Merge pull request #382 from reuters-graphics/mf-horiz-scroller
Edits to documentation and demos
This commit is contained in:
commit
74d6de2ff7
9 changed files with 336 additions and 348 deletions
|
|
@ -2,195 +2,142 @@ import { Meta } from '@storybook/blocks';
|
||||||
|
|
||||||
import * as HorizontalScrollerStories from './HorizontalScroller.stories.svelte';
|
import * as HorizontalScrollerStories from './HorizontalScroller.stories.svelte';
|
||||||
|
|
||||||
import IllustratorScreenshot from './assets/illustrator.png';
|
import IllustratorScreenshot from './assets/illustrator.jpg';
|
||||||
|
|
||||||
<Meta of={HorizontalScrollerStories} />
|
<Meta of={HorizontalScrollerStories} />
|
||||||
|
|
||||||
# HorizontalScroller
|
# HorizontalScroller
|
||||||
|
|
||||||
The `HorizontalScroller` component is helpful in making horizontal scrolling sections that respond to vertical scroll input. It is flexible in a way that it can horizontally scroll any children content wider than 100vw from one end to the other.
|
The `HorizontalScroller` component creates a horizontal scrolling section that scrolls through any child content wider than `100vw`.
|
||||||
|
|
||||||
To scroll any DOM layout wider than the viewport, wrap the content inside the `HorizontalScroller` component. The component will take care of the rest.
|
To use `HorizontalScroller`, wrap it around the content that you want to horizontally scroll through. The scroll length is controlled by the height of the `HorizontalScroller` container, which is set by the prop `height`. `height` defaults to `200lvh`, but you can adjust this to any valid CSS height value such as `1200px` or `400lvh`.
|
||||||
|
|
||||||
## Basic demo
|
The child content inside the `HorizontalScroller` must be wider than `100vw` so that there is overflow to horizontal scroll through. By default, only the top `100lvh` of the child content is visible. You can use CSS `transform: translate()` on the child content to adjust its vertical positioning within the visible area.
|
||||||
|
|
||||||
To use the `HorizontalScroller` component, import it and provide the children content to scroll. The scroll height defaults to `200lvh`, but you can adjust this to any valid CSS height value such as `1200px` or `200lvh` with the `height` prop.
|
|
||||||
|
|
||||||
> 💡TIP: Use `lvh` or `svh` units instead of `vh` unit for the height, as [these units](https://www.w3.org/TR/css-values-4/#large-viewport-size) are more reliable on mobile or other devices where elements such as the address bar toggle between being shown and hidden.
|
> 💡TIP: Use `lvh` or `svh` units instead of `vh` unit for the height, as [these units](https://www.w3.org/TR/css-values-4/#large-viewport-size) are more reliable on mobile or other devices where elements such as the address bar toggle between being shown and hidden.
|
||||||
|
|
||||||
[Demo](?path=/story/components-graphics-horizontalscroller--demo)
|
> 💡TIP: Set the `showDebugInfo` prop to `true` to visualise the scroll progress and other useful information.
|
||||||
|
|
||||||
|
See the full list of available props under the `Controls` tab in the [demo](?path=/story/components-graphics-horizontalscroller--demo).
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { HorizontalScroller } from '@reuters-graphics/graphics-components';
|
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- Optionally set `height` to adjust scroll height -->
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
<HorizontalScroller height="400lvh">
|
<Block width="fluid">
|
||||||
<div style="width: 200vw; height: 100lvh;">
|
<!-- Optionally set `height` prop to adjust scroll length. Defaults to `200lvh` -->
|
||||||
<!-- Content wider than 100vw -->
|
<HorizontalScroller>
|
||||||
<!-- Only the top 100lvh will be visible -->
|
<!-- Child content wider than 100vw. Only the top 100lvh is visible. -->
|
||||||
<img
|
<div style="width: 400vw; height: 100lvh;">
|
||||||
src="path/to/wide-image.jpg"
|
<img
|
||||||
alt="alt text"
|
src="my-wide-image.jpg"
|
||||||
style="width: 100%; height: 100%; object-fit: cover; padding: 0; margin: 0;"
|
alt="alt text"
|
||||||
/>
|
style="width: 100%; height: 100%; object-fit: cover; padding: 0; margin: 0;"
|
||||||
</div>
|
/>
|
||||||
</HorizontalScroller>
|
</div>
|
||||||
|
</HorizontalScroller>
|
||||||
|
</Block>
|
||||||
```
|
```
|
||||||
|
|
||||||
## With stops
|
## Controlling scroll behaviour with stops and easing
|
||||||
|
|
||||||
The `HorizontalScroller` also allows you to define a set of points to stop or slow down the scrolling at specific intervals using the `stops` prop. This is useful for creating step-based horizontal scrolling experiences.
|
The `HorizontalScroller` allows you to control the horizontal scroll behaviour and pacing with various props.
|
||||||
|
|
||||||
The `scrubbed` prop can be used to define whether the scrolling experience should be smooth or tied directly to the scroll position. Setting `scrubbed` to `true` will make the horizontal scroll position directly correspond to the vertical scroll position, while setting it to `false` will create a smooth scrolling effect.
|
**`stops`:**
|
||||||
|
|
||||||
If `scrubbed` is set to `false` and `stops` are defined, the scroller will transition smoothly to the next stop when the `Mapped Progress` reaches the midpoint between the two stops. The transition speed is controlled by the `duration` prop (in milliseconds) and the `easing` prop (which accepts any easing function from `svelte/easing` or a custom function based on signature `(t: number) => number`).
|
`stops` is an optional prop that accepts an array of numbers between `0` and `1`. At these points, which corresponds to the scroll `progress` values, the scrolling stops or slows down. This is useful for adding custom pauses based on progress.
|
||||||
|
|
||||||
If `scrubbed` is set to `true` and `stops` are defined, all the stops are traversed at equal distance but based on the easing function provided.
|
For example, as shown in the demo below, if you define `stops` as `[0.2, 0.5, 0.9]`, the scrolling will pause or slow down at these `progress` values as the user scrolls through the `HorizontalScroller` section.
|
||||||
|
|
||||||
Use `showDebugInfo` prop to visualize the scroll progress and other useful debug information. The `Progress` indicates the vertical progress with values in the range 0...1 indicating the content being locked or a user-fed value to control the horizontal scroll position. The `Mapped Progress` value indicates the vertical progress mapped to mappedStart and mappedEnd values. By default these are 0 and 1 respectively. Finally, the `Eased Progress` value indicates the horizontal scroll progress after applying stops and easing (if any). `Eased Progress` accurately reflects the transition of horizontal scroll position.
|
**`scrubbed`:**
|
||||||
|
|
||||||
Feel free to toggle `scrubbed` prop here to see the difference.
|
The `scrubbed` prop controls whether the scrolling is tied exactly to the scroll position (`scrubbed: true`) or is smoothed out (`scrubbed: false`). This prop defaults to `true`.
|
||||||
|
|
||||||
[Demo](?path=/story/components-graphics-horizontalscroller--demo)
|
If `scrubbed` is set to `false` and `stops` are defined, the scrolling transitions smoothly between the stop values.
|
||||||
|
|
||||||
|
**`easing`** and **`duration`**:
|
||||||
|
|
||||||
|
`easing` accepts any easing function from `svelte/easing` or a custom easing function, while `duration` sets the time, in milliseconds, for each transition between stops.
|
||||||
|
|
||||||
|
So, if the stops are at irregular intervals — for example, `[0.2, 0.9]` — the scroll to the first stop will be much quicker than the scroll to the second stop since the distance to travel is different but the duration of the transition is the same.
|
||||||
|
|
||||||
|
By default, `duration` is set to `400` milliseconds.
|
||||||
|
|
||||||
|
[Demo](?path=/story/components-graphics-horizontalscroller--with-stops)
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { HorizontalScroller } from '@reuters-graphics/graphics-components';
|
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||||
import { quartInOut } from 'svelte/easing';
|
import { quartInOut } from 'svelte/easing';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<HorizontalScroller
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
height="200lvh"
|
<Block width="fluid">
|
||||||
stops={[0.2, 0.5, 0.6, 0.7]}
|
<HorizontalScroller
|
||||||
duration={400}
|
stops={[0.2, 0.5, 0.9]}
|
||||||
scrubbed={false}
|
duration={400}
|
||||||
easing={quartInOut}
|
scrubbed={false}
|
||||||
showDebugInfo
|
easing={quartInOut}
|
||||||
direction="right"
|
showDebugInfo={true}
|
||||||
>
|
>
|
||||||
<div style="width: 200vw; height: 100lvh;">
|
<!-- Child content wider than 100vw. Only the top 100lvh is visible. -->
|
||||||
<!-- Content wider than 100vw -->
|
<div style="width: 200vw; height: 100lvh;">
|
||||||
<!-- Only the top 100lvh will be visible -->
|
<img
|
||||||
<img
|
src="my-wide-image.jpg"
|
||||||
src="path/to/wide-image.jpg"
|
alt="alt text"
|
||||||
alt="alt text"
|
style="width: 100%; height: 100%; object-fit: cover; padding: 0; margin: 0;"
|
||||||
style="width: 100%; height: 100%; object-fit: cover; padding: 0; margin: 0;"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
</HorizontalScroller>
|
||||||
</HorizontalScroller>
|
</Block>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Extended boundary
|
## Extended boundaries
|
||||||
|
|
||||||
`HorizontalScroller` also provides `mappedStart` and `mappedEnd` props to extend the horizontal scroll boundaries beyond the default 0 to 1 range. This is useful when you want to create an overscroll effect or have more control over the horizontal scroll range. By default these values are set to 0 and 1 respectively.
|
`HorizontalScroller` has `mappedStart` and `mappedEnd` props, which extend the horizontal scroll boundaries beyond the default 0 to 1 range. This is useful when you want to create an overscroll effect or have more control over the horizontal scroll range. By default, these values are set to 0 and 1 respectively.
|
||||||
|
|
||||||
[Demo](?path=/story/components-graphics-horizontalscroller--extended-boundary)
|
If using custom `mappedStart` and `mappedEnd` values, you must also set `stops` values that are within the mapped range.
|
||||||
|
|
||||||
|
> 💡TIP: In the debugging info box, `Progress` indicates the raw scroll progress value between `0` and `1`. `Mapped Progress` indicates the vertical progress mapped to `mappedStart` and `mappedEnd`. If they are not set, `Mapped Progress` is bound between 0 and 1 and matches `Progress`. `Eased Progress` indicates the scroll progress with any stops and easing applied. `Eased Progress` is what reflects the actual transition of the horizontal scroll position.
|
||||||
|
|
||||||
|
[Demo](?path=/story/components-graphics-horizontalscroller--extended-boundaries)
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { HorizontalScroller } from '@reuters-graphics/graphics-components';
|
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||||
import { quartInOut } from 'svelte/easing';
|
import { quartInOut } from 'svelte/easing';
|
||||||
</script>
|
</script>
|
||||||
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
<HorizontalScroller
|
<Block width="fluid">
|
||||||
height="200lvh"
|
<HorizontalScroller
|
||||||
mappedStart={-0.5}
|
mappedStart={-0.5}
|
||||||
mappedEnd={1.5}
|
mappedEnd={1.5}
|
||||||
stops={[0, 1]}
|
stops={[0, 1]}
|
||||||
scrubbed={true}
|
showDebugInfo={true}
|
||||||
easing={quartInOut}
|
easing={quartInOut}
|
||||||
direction="right"
|
>
|
||||||
showDebugInfo
|
<!-- Child content wider than 100vw. Only the top 100lvh is visible. -->
|
||||||
>
|
<div style="width: 200vw; height: 100lvh;">
|
||||||
<div style="width: 200vw; height: 100lvh;">
|
<img
|
||||||
<!-- Content wider than 100vw -->
|
src="my-wide-image.jpg"
|
||||||
<!-- Only the top 100lvh will be visible -->
|
alt="alt text"
|
||||||
<img
|
style="width: 100%; height: 100%; object-fit: cover; padding: 0; margin: 0;"
|
||||||
src="path/to/wide-image.jpg"
|
|
||||||
alt="alt text"
|
|
||||||
style="width: 100%; height: 100%; object-fit: cover; padding: 0; margin: 0;"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</HorizontalScroller>
|
|
||||||
```
|
|
||||||
|
|
||||||
## With custom child components
|
|
||||||
|
|
||||||
You can create a horizontal stack of any components and pass it as children to the `HorizontalScroller`. Here's an example of using `DatawrapperChart`, `Headline` and ai2svelte components inside the scroller.
|
|
||||||
|
|
||||||
[Demo](?path=/story/components-graphics-horizontalscroller--custom-children)
|
|
||||||
|
|
||||||
```svelte
|
|
||||||
<script lang="ts">
|
|
||||||
import {
|
|
||||||
Block,
|
|
||||||
DatawrapperChart,
|
|
||||||
Headline,
|
|
||||||
HorizontalScroller,
|
|
||||||
} from '@reuters-graphics/graphics-components';
|
|
||||||
import AiChart from './ai2svelte/ai-chart.svelte';
|
|
||||||
import { quartInOut } from 'svelte/easing';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<HorizontalScroller
|
|
||||||
height="200lvh"
|
|
||||||
stops={[0.2, 0.5, 0.6, 0.7]}
|
|
||||||
duration={400}
|
|
||||||
scrubbed={false}
|
|
||||||
easing={quartInOut}
|
|
||||||
direction="right"
|
|
||||||
showDebugInfo
|
|
||||||
>
|
|
||||||
<div id="horizontal-stack">
|
|
||||||
<div style="width: 100vw;">
|
|
||||||
<DatawrapperChart
|
|
||||||
title="Global abortion access"
|
|
||||||
ariaLabel="map"
|
|
||||||
id="abortion-rights-map"
|
|
||||||
src="https://graphics.reuters.com/USA-ABORTION/lgpdwggnwvo/media-embed.html"
|
|
||||||
frameTitle=""
|
|
||||||
scrolling="no"
|
|
||||||
textWidth="normal"
|
|
||||||
width="wider"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 100vw;">
|
</HorizontalScroller>
|
||||||
<Headline
|
</Block>
|
||||||
hed="Reuters Graphics Interactive"
|
|
||||||
dek="The beginning of a beautiful page"
|
|
||||||
section="World News"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div style="width: 100vw;">
|
|
||||||
<Block width="normal">
|
|
||||||
<AiChart />
|
|
||||||
</Block>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</HorizontalScroller>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
#horizontal-stack {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-around;
|
|
||||||
gap: 10vw;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## With ai2svelte components
|
## With ai2svelte components
|
||||||
|
|
||||||
With ai2svelte v1.0.3 onwards, you can export your ai2svelte graphic with a wider-than-viewport layout and use it directly inside the `HorizontalScroller` component to create horizontal scrolling graphics.
|
With [ai2svelte](https://reuters-graphics.github.io/ai2svelte/) v1.0.3 onwards, you can export your ai2svelte graphic with a wider-than-viewport layout and use it directly inside `HorizontalScroller` to create horizontally scrolling graphics.
|
||||||
|
|
||||||
To do that, follow these steps:
|
To do that, follow these steps:
|
||||||
|
|
||||||
1. In Illustrator, rename your artboard with a tag indicating breakpoint width for that artboard to be visible on page. For example, to make the XL artboard visible on viewports wider than 1200px, rename the artboard to `xl:1200`. You can have more than one artboard with different breakpoint widths.
|
1. In Illustrator, rename your artboard with the breakpoint at which you want that artboard to be visible on the page. For example, to make the XL artboard visible on viewports wider than 1200px, rename it to `xl:1200`. You can have multiple artboards with different breakpoints.
|
||||||
2. In ai2svelte settings, set these properties and run ai2svelte to export the component.
|
2. Add these properties to the ai2svelte settings and run the script to export the component.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
include_resizer_css: false
|
include_resizer_css: false
|
||||||
|
|
@ -207,35 +154,50 @@ allow_overflow: true
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { HorizontalScroller } from '@reuters-graphics/graphics-components';
|
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||||
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
||||||
import { sineInOut } from 'svelte/easing';
|
|
||||||
// If using with the graphics kit
|
// If using with the graphics kit
|
||||||
import { assets } from '$app/paths';
|
import { assets } from '$app/paths';
|
||||||
|
|
||||||
|
// Optional easing function
|
||||||
|
import { sineInOut } from 'svelte/easing';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<HorizontalScroller
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
width="fluid"
|
<Block width="fluid">
|
||||||
height="800lvh"
|
<HorizontalScroller
|
||||||
direction="right"
|
height="800lvh"
|
||||||
easing={sineInOut}
|
easing={sineInOut}
|
||||||
showDebugInfo
|
showDebugInfo
|
||||||
>
|
>
|
||||||
<AiGraphic assetsPath={assets} />
|
<AiGraphic assetsPath={assets} />
|
||||||
</HorizontalScroller>
|
</HorizontalScroller>
|
||||||
|
</Block>
|
||||||
```
|
```
|
||||||
|
|
||||||
## With ai2svelte components (advanced)
|
## With ai2svelte components: advanced
|
||||||
|
|
||||||
Binding the `progress` can be useful to even transition tagged content inside the ai2svelte graphic as part of the horizontal scrolling experience. For example, caption boxes exported as `htext` tagged layers can be animated to fade in/out or move in/out of view based on the scroll progress. Or one could even use tagged `png` layers to create parallax effects.
|
You can use the bound prop `progress` to create advanced interactivity with an ai2svelte graphic.
|
||||||
|
|
||||||
|
The demo below has 2 advanced interactions: fade in/out of caption boxes based on scroll position and parallax movement of a `png` layer.
|
||||||
|
|
||||||
|
### Captions fading in/out
|
||||||
|
|
||||||
|
Caption boxes are exported as `htext` [tagged layers](https://reuters-graphics.github.io/ai2svelte/users/tagged-layers/) in ai2svelte. In this example, we use the `handleScroll()` function to check the position of each caption box relative to the viewport width and set its opacity to `1` (visible) or `0` (hidden) based on whether the caption box is within the `threshold` of the viewport.
|
||||||
|
|
||||||
|
### Parallax effect with png layer
|
||||||
|
|
||||||
|
This demo has a tagged `png` [layer](https://reuters-graphics.github.io/ai2svelte/users/tagged-layers/), which contains the foreground overlay image. The `handleScroll()` function uses the bound `progress` value to calculate a horizontal translation for the `png` layer, creating a parallax effect as the user scrolls through the `HorizontalScroller`.
|
||||||
|
|
||||||
[Demo](?path=/story/components-graphics-horizontalscroller--scrollable-ai-2-svelte-advanced)
|
[Demo](?path=/story/components-graphics-horizontalscroller--scrollable-ai-2-svelte-advanced)
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { HorizontalScroller } from '@reuters-graphics/graphics-components';
|
import { HorizontalScroller, Block } from '@reuters-graphics/graphics-components';
|
||||||
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
||||||
import { sineInOut } from 'svelte/easing';
|
import { sineInOut } from 'svelte/easing';
|
||||||
|
|
||||||
// If using with the graphics kit
|
// If using with the graphics kit
|
||||||
import { assets } from '$app/paths';
|
import { assets } from '$app/paths';
|
||||||
|
|
||||||
|
|
@ -247,14 +209,13 @@ Binding the `progress` can be useful to even transition tagged content inside th
|
||||||
let screenWidth: number = $state(0);
|
let screenWidth: number = $state(0);
|
||||||
|
|
||||||
function handleScroll() {
|
function handleScroll() {
|
||||||
// to create the parallax movement
|
// Create a parallax movement for the foreground png layer
|
||||||
if (pngLayer) {
|
if (pngLayer) {
|
||||||
pngLayer.style.transform = `translateX(${map(progress, 0, 1, -400, 400)}px)`;
|
pngLayer.style.transform = `translateX(${map(progress, 0, 1, -400, 400)}px)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each caption, checks if position of the caption < 80vw
|
// For each caption, checks if position of the caption is below the threshold.
|
||||||
// if it is, show it
|
// If it is, show it. If not, hide it
|
||||||
// if not, hide it
|
|
||||||
if (captions?.length) {
|
if (captions?.length) {
|
||||||
captions.forEach((caption) => {
|
captions.forEach((caption) => {
|
||||||
let captionWidth = caption.getBoundingClientRect().width;
|
let captionWidth = caption.getBoundingClientRect().width;
|
||||||
|
|
@ -276,8 +237,7 @@ Binding the `progress` can be useful to even transition tagged content inside th
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// refetch new captions and png image
|
// Refetch new captions and png image every time the artboard changes
|
||||||
// every time the artboard changes
|
|
||||||
function onArtboardChange(artboard: HTMLElement) {
|
function onArtboardChange(artboard: HTMLElement) {
|
||||||
pngLayer = artboard.querySelector('.g-png-layer-overlay');
|
pngLayer = artboard.querySelector('.g-png-layer-overlay');
|
||||||
captions = Array.from(artboard.querySelectorAll('.g-captions'));
|
captions = Array.from(artboard.querySelectorAll('.g-captions'));
|
||||||
|
|
@ -291,16 +251,31 @@ Binding the `progress` can be useful to even transition tagged content inside th
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<HorizontalScroller
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
width="fluid"
|
<Block width="fluid">
|
||||||
height="800lvh"
|
<HorizontalScroller
|
||||||
direction="right"
|
height="800lvh"
|
||||||
bind:progress
|
bind:progress
|
||||||
easing={sineInOut}
|
easing={sineInOut}
|
||||||
showDebugInfo
|
showDebugInfo={true}
|
||||||
>
|
>
|
||||||
<AiGraphic assetsPath={assets} {onArtboardChange} />
|
<AiGraphic assetsPath={assets} {onArtboardChange}
|
||||||
</HorizontalScroller>
|
taggedText={{
|
||||||
|
htext: {
|
||||||
|
captions: {
|
||||||
|
caption1:
|
||||||
|
'<div class="scroller-caption"><strong>Caption 1!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
|
caption2:
|
||||||
|
'<div class="scroller-caption"><strong>Caption 2!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
|
caption3:
|
||||||
|
'<div class="scroller-caption"><strong>Caption 3!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
|
caption4:
|
||||||
|
'<div class="scroller-caption"><strong>Caption 4!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}} />
|
||||||
|
</HorizontalScroller>
|
||||||
|
</Block>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
:global(.scroller-caption) {
|
:global(.scroller-caption) {
|
||||||
|
|
@ -313,58 +288,106 @@ Binding the `progress` can be useful to even transition tagged content inside th
|
||||||
</style>
|
</style>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## With custom child components
|
||||||
|
|
||||||
|
You can create a custom horizontal layout with any component and pass it as a child to the `HorizontalScroller`. Here's an example with `DatawrapperChart`, `Headline` and ai2svelte components laid out in a horizontal scroll.
|
||||||
|
|
||||||
|
[Demo](?path=/story/components-graphics-horizontalscroller--custom-children)
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script lang="ts">
|
||||||
|
import {
|
||||||
|
Block,
|
||||||
|
DatawrapperChart,
|
||||||
|
Headline,
|
||||||
|
HorizontalScroller,
|
||||||
|
} from '@reuters-graphics/graphics-components';
|
||||||
|
import AiChart from './ai2svelte/ai-chart.svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
|
<Block width="fluid">
|
||||||
|
<HorizontalScroller>
|
||||||
|
<div id="horizontal-stack">
|
||||||
|
<div style="width: 100vw;">
|
||||||
|
<DatawrapperChart
|
||||||
|
title="Global abortion access"
|
||||||
|
ariaLabel="map"
|
||||||
|
id="abortion-rights-map"
|
||||||
|
src="https://graphics.reuters.com/USA-ABORTION/lgpdwggnwvo/media-embed.html"
|
||||||
|
frameTitle=""
|
||||||
|
scrolling="no"
|
||||||
|
textWidth="normal"
|
||||||
|
width="wider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100vw;">
|
||||||
|
<Headline
|
||||||
|
hed="Reuters Graphics Interactive"
|
||||||
|
dek="The beginning of a beautiful page"
|
||||||
|
section="World News"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100vw;">
|
||||||
|
<Block width="normal">
|
||||||
|
<AiChart />
|
||||||
|
</Block>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</HorizontalScroller>
|
||||||
|
</Block>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#horizontal-stack {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
gap: 10vw;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
## With ScrollerBase
|
## With ScrollerBase
|
||||||
|
|
||||||
You can also integrate HorizontalScroller with `ScrollerBase` for a horizontal scroll with vertical captions experience.
|
You can also integrate HorizontalScroller with `ScrollerBase` for a horizontal scroll with vertical captions.
|
||||||
|
|
||||||
[Demo](?path=/story/components-graphics-horizontalscroller--scrollable-ai-2-svelte)
|
When using `HorizontalScroller` with `ScrollerBase` or other scrollers, you must:
|
||||||
|
- Create a `progress` state variable and bind it to both `ScrollerBase` and `HorizontalScroller`
|
||||||
|
- Set `HorizontalScroller`'s `height` to `100lvh`
|
||||||
|
- Set `handleScroll` to `false`
|
||||||
|
|
||||||
|
[Demo](?path=/story/components-graphics-horizontalscroller--with-scroller-base)
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {
|
import {
|
||||||
HorizontalScroller,
|
HorizontalScroller,
|
||||||
ScrollerBase,
|
ScrollerBase,
|
||||||
|
Block
|
||||||
} from '@reuters-graphics/graphics-components';
|
} from '@reuters-graphics/graphics-components';
|
||||||
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
import AiGraphic from './ai2svelte/ai-graphic.svelte';
|
||||||
import { circInOut } from 'svelte/easing';
|
import { circInOut } from 'svelte/easing';
|
||||||
import { circInOut } from 'svelte/easing';
|
|
||||||
|
|
||||||
// Optional: Bind your own variables to use them in your code.
|
// Optional: Bind your own variables to use them in your code.
|
||||||
let count = $state(1);
|
|
||||||
let index = $state(0);
|
|
||||||
let offset = $state(0);
|
|
||||||
let progress = $state(0);
|
let progress = $state(0);
|
||||||
let top = $state(0);
|
|
||||||
let threshold = $state(0.5);
|
|
||||||
let bottom = $state(1);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ScrollerBase
|
<ScrollerBase bind:progress query="div.step-foreground-container">
|
||||||
{top}
|
|
||||||
{threshold}
|
|
||||||
{bottom}
|
|
||||||
bind:count
|
|
||||||
bind:index
|
|
||||||
bind:offset
|
|
||||||
bind:progress
|
|
||||||
query="div.step-foreground-container"
|
|
||||||
>
|
|
||||||
{#snippet backgroundSnippet()}
|
{#snippet backgroundSnippet()}
|
||||||
<!-- Make sure to set height to `100lvh` -->
|
<!-- Wrap `HorizontalScroller` in a fluid container for a full bleed experience -->
|
||||||
<!-- and handleScroll to false to avoid scroll conflicts -->
|
<Block width="fluid">
|
||||||
<HorizontalScroller
|
<HorizontalScroller
|
||||||
width="fluid"
|
bind:progress
|
||||||
height="100lvh"
|
height="100lvh"
|
||||||
direction="right"
|
handleScroll={false}
|
||||||
bind:progress
|
showDebugInfo={true}
|
||||||
scrubbed
|
>
|
||||||
stops={[0.5]}
|
<AiGraphic />
|
||||||
handleScroll={false}
|
</HorizontalScroller>
|
||||||
easing={circInOut}
|
</Block>
|
||||||
showDebugInfo
|
|
||||||
>
|
|
||||||
<Demo />
|
|
||||||
</HorizontalScroller>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet foregroundSnippet()}
|
{#snippet foregroundSnippet()}
|
||||||
<!-- Add custom foreground HTML or component -->
|
<!-- Add custom foreground HTML or component -->
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
<script module lang="ts">
|
<script module lang="ts">
|
||||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
import HorizontalScroller from './HorizontalScroller.svelte';
|
|
||||||
import { quartInOut } from 'svelte/easing';
|
import { quartInOut } from 'svelte/easing';
|
||||||
|
|
||||||
|
import HorizontalScroller from './HorizontalScroller.svelte';
|
||||||
import DemoComponent from './demo/Demo.svelte';
|
import DemoComponent from './demo/Demo.svelte';
|
||||||
import DemoSnippetBlock from './demo/DemoSnippet.svelte';
|
import DemoSnippetBlock from './demo/DemoSnippet.svelte';
|
||||||
import CustomChildrenBlock from './demo/CustomChildrenSnippet.svelte';
|
import CustomChildrenBlock from './demo/CustomChildrenSnippet.svelte';
|
||||||
import ScrollableGraphic from './demo/ScrollableGraphic.svelte';
|
import ScrollableGraphic from './demo/ScrollableGraphic.svelte';
|
||||||
import AdvancedScrollableGraphic from './demo/AdvancedScrollableGraphic.svelte';
|
import AdvancedScrollableGraphic from './demo/AdvancedScrollableGraphic.svelte';
|
||||||
import WithScrollerBaseComponent from './demo/withScrollerBase.svelte';
|
import WithScrollerBaseComponent from './demo/withScrollerBase.svelte';
|
||||||
import Block from '../Block/Block.svelte';
|
|
||||||
|
|
||||||
const { Story } = defineMeta({
|
const { Story } = defineMeta({
|
||||||
title: 'Components/Graphics/HorizontalScroller',
|
title: 'Components/Graphics/HorizontalScroller',
|
||||||
|
|
@ -19,85 +19,40 @@
|
||||||
let width: number = $state(0);
|
let width: number = $state(0);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:window bind:innerWidth={width} />
|
<svelte:window bind:innerWidth={width} />
|
||||||
|
|
||||||
{#snippet DemoSnippet()}
|
<Story name="Demo">
|
||||||
<DemoSnippetBlock />
|
<DemoComponent>
|
||||||
{/snippet}
|
<DemoSnippetBlock />
|
||||||
|
</DemoComponent>
|
||||||
{#snippet CustomChildrenSnippet()}
|
|
||||||
<CustomChildrenBlock />
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
<Story
|
|
||||||
name="Demo"
|
|
||||||
args={{
|
|
||||||
children: DemoSnippet,
|
|
||||||
height: '200lvh',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#snippet children(args)}
|
|
||||||
<DemoComponent {...args}></DemoComponent>
|
|
||||||
{/snippet}
|
|
||||||
</Story>
|
</Story>
|
||||||
|
|
||||||
<Story
|
<Story name="With stops and easing" exportName="WithStops">
|
||||||
name="With stops"
|
<DemoComponent
|
||||||
args={{
|
stops={[0.2, 0.5, 0.9]}
|
||||||
children: DemoSnippet,
|
duration={400}
|
||||||
height: '200lvh',
|
toggleScrub={true}
|
||||||
stops: [0.2, 0.5, 0.6, 0.7],
|
easing={quartInOut}
|
||||||
duration: 400,
|
>
|
||||||
scrubbed: true,
|
<DemoSnippetBlock />
|
||||||
easing: quartInOut,
|
</DemoComponent>
|
||||||
showDebugInfo: true,
|
|
||||||
direction: 'left',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#snippet children(args)}
|
|
||||||
<Block width="fluid">
|
|
||||||
<DemoComponent {...args}></DemoComponent>
|
|
||||||
</Block>
|
|
||||||
{/snippet}
|
|
||||||
</Story>
|
</Story>
|
||||||
|
|
||||||
<Story
|
<Story name="Extended boundaries">
|
||||||
name="Extended boundary"
|
<DemoComponent
|
||||||
args={{
|
mappedStart={-0.5}
|
||||||
children: DemoSnippet,
|
mappedEnd={1.5}
|
||||||
height: '200lvh',
|
easing={quartInOut}
|
||||||
mappedStart: -0.5,
|
stops={[0, 1]}
|
||||||
mappedEnd: 1.5,
|
>
|
||||||
showDebugInfo: true,
|
<DemoSnippetBlock />
|
||||||
scrubbed: true,
|
</DemoComponent>
|
||||||
stops: [0, 1],
|
|
||||||
easing: quartInOut,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#snippet children(args)}
|
|
||||||
<DemoComponent {...args}></DemoComponent>
|
|
||||||
{/snippet}
|
|
||||||
</Story>
|
</Story>
|
||||||
|
|
||||||
<Story
|
<Story name="Custom children">
|
||||||
name="Custom children"
|
<DemoComponent>
|
||||||
args={{
|
<CustomChildrenBlock />
|
||||||
children: CustomChildrenSnippet,
|
</DemoComponent>
|
||||||
height: '200lvh',
|
|
||||||
stops: [0.5],
|
|
||||||
duration: 400,
|
|
||||||
scrubbed: false,
|
|
||||||
easing: quartInOut,
|
|
||||||
showDebugInfo: true,
|
|
||||||
direction: 'right',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{#snippet children(args)}
|
|
||||||
<DemoComponent {...args}></DemoComponent>
|
|
||||||
{/snippet}
|
|
||||||
</Story>
|
</Story>
|
||||||
|
|
||||||
<Story name="Scrollable ai2svelte">
|
<Story name="Scrollable ai2svelte">
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount, type Snippet } from 'svelte';
|
import { onMount, type Snippet } from 'svelte';
|
||||||
import { Tween } from 'svelte/motion';
|
import { Tween } from 'svelte/motion';
|
||||||
import type { Action } from 'svelte/action';
|
|
||||||
import { clamp, map } from './utils/index';
|
import { clamp, map } from './utils/index';
|
||||||
|
import type { Action } from 'svelte/action';
|
||||||
|
|
||||||
import Debug from './Debug.svelte';
|
import Debug from './Debug.svelte';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -210,7 +211,7 @@
|
||||||
|
|
||||||
<div
|
<div
|
||||||
{id}
|
{id}
|
||||||
class={`horizontal-scroller-container ${cls}`}
|
class="horizontal-scroller-container {cls}"
|
||||||
style="height: {height};"
|
style="height: {height};"
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
bind:clientHeight={containerHeight}
|
bind:clientHeight={containerHeight}
|
||||||
|
|
|
||||||
BIN
src/components/HorizontalScroller/assets/illustrator.jpg
Normal file
BIN
src/components/HorizontalScroller/assets/illustrator.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 250 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 MiB |
|
|
@ -1,6 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Demo from './graphic/ai2svelte/demo.svelte';
|
import Demo from './graphic/ai2svelte/demo.svelte';
|
||||||
import BodyText from '../../BodyText/BodyText.svelte';
|
import BodyText from '../../BodyText/BodyText.svelte';
|
||||||
|
import Block from '../../Block/Block.svelte';
|
||||||
|
|
||||||
import HorizontalScroller from '../HorizontalScroller.svelte';
|
import HorizontalScroller from '../HorizontalScroller.svelte';
|
||||||
import { map } from '../utils/index';
|
import { map } from '../utils/index';
|
||||||
import { sineInOut } from 'svelte/easing';
|
import { sineInOut } from 'svelte/easing';
|
||||||
|
|
@ -57,32 +59,33 @@
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
<HorizontalScroller
|
<Block width="fluid">
|
||||||
height="800lvh"
|
<HorizontalScroller
|
||||||
direction="right"
|
height="800lvh"
|
||||||
bind:progress
|
bind:progress
|
||||||
easing={sineInOut}
|
easing={sineInOut}
|
||||||
showDebugInfo
|
showDebugInfo
|
||||||
>
|
>
|
||||||
<Demo
|
<Demo
|
||||||
{onArtboardChange}
|
{onArtboardChange}
|
||||||
debugTaggedText
|
debugTaggedText
|
||||||
taggedText={{
|
taggedText={{
|
||||||
htext: {
|
htext: {
|
||||||
captions: {
|
captions: {
|
||||||
caption1:
|
caption1:
|
||||||
'<div class="scroller-caption"><strong>Destruction!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
'<div class="scroller-caption"><strong>Caption 1!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
caption2:
|
caption2:
|
||||||
'<div class="scroller-caption"><strong>Destruction!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
'<div class="scroller-caption"><strong>Caption 2!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
caption3:
|
caption3:
|
||||||
'<div class="scroller-caption"><strong>Destruction!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
'<div class="scroller-caption"><strong>Caption 3!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
caption4:
|
caption4:
|
||||||
'<div class="scroller-caption"><strong>Destruction!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
'<div class="scroller-caption"><strong>Caption 4!</strong><br/>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</div>',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
</HorizontalScroller>
|
||||||
</HorizontalScroller>
|
</Block>
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,42 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import ScrollerHorizontal from '../HorizontalScroller.svelte';
|
import HorizontalScroller from '../HorizontalScroller.svelte';
|
||||||
import BodyText from '../../BodyText/BodyText.svelte';
|
import BodyText from '../../BodyText/BodyText.svelte';
|
||||||
|
import Block from '../../Block/Block.svelte';
|
||||||
|
|
||||||
let { ...args } = $props();
|
let { ...args } = $props();
|
||||||
|
|
||||||
const foobarText: string =
|
const foobarText: string =
|
||||||
'In the mystical land of Foobaristan, the legendary hero Foo set out on an epic quest to find his missing semicolon, only to discover that Bar had accidentally used it as a bookmark inside a JSON file. Naturally, the entire kingdom crashed immediately. As the villagers panicked, Foo and Bar tried to fix the situation by turning everything off and on again, but all that did was anger the ancient deity known as “The Build System,” which now demanded three sacrifices: a clean cache, a fresh node_modules folder, and someone’s weekend. And thus began the saga nobody asked for, yet every developer somehow relates to.';
|
'In the mystical land of Foobaristan, the legendary hero Foo set out on an epic quest to find his missing semicolon, only to discover that Bar had accidentally used it as a bookmark inside a JSON file. Naturally, the entire kingdom crashed immediately. As the villagers panicked, Foo and Bar tried to fix the situation by turning everything off and on again, but all that did was anger the ancient deity known as “The Build System,” which now demanded three sacrifices: a clean cache, a fresh node_modules folder, and someone’s weekend. And thus began the saga nobody asked for, yet every developer somehow relates to.';
|
||||||
|
|
||||||
|
// For the `scrubbed` demo
|
||||||
|
let scrubbed: boolean = $state(true);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
<ScrollerHorizontal {...args} />
|
{#if args.toggleScrub}
|
||||||
|
<Block>
|
||||||
|
<button onclick={() => (scrubbed = !scrubbed)}>
|
||||||
|
Toggle scrubbed: {scrubbed}
|
||||||
|
</button>
|
||||||
|
</Block>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<Block width="fluid">
|
||||||
|
<HorizontalScroller showDebugInfo={true} {...args} {scrubbed} />
|
||||||
|
</Block>
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: 'Geist Mono', monospace;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: block;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Demo from './graphic/ai2svelte/demo.svelte';
|
import Demo from './graphic/ai2svelte/demo.svelte';
|
||||||
import BodyText from '../../BodyText/BodyText.svelte';
|
import BodyText from '../../BodyText/BodyText.svelte';
|
||||||
|
import Block from '../../Block/Block.svelte';
|
||||||
import HorizontalScroller from '../HorizontalScroller.svelte';
|
import HorizontalScroller from '../HorizontalScroller.svelte';
|
||||||
import { sineInOut } from 'svelte/easing';
|
import { sineInOut } from 'svelte/easing';
|
||||||
|
|
||||||
|
|
@ -10,15 +11,11 @@
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
<HorizontalScroller
|
<Block width="fluid">
|
||||||
height="800lvh"
|
<HorizontalScroller height="800lvh" easing={sineInOut}>
|
||||||
direction="right"
|
<Demo />
|
||||||
easing={sineInOut}
|
</HorizontalScroller>
|
||||||
showDebugInfo
|
</Block>
|
||||||
>
|
|
||||||
<Demo />
|
|
||||||
</HorizontalScroller>
|
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,31 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Demo from './graphic/ai2svelte/demo.svelte';
|
import Demo from './graphic/ai2svelte/demo.svelte';
|
||||||
import BodyText from '../../BodyText/BodyText.svelte';
|
import BodyText from '../../BodyText/BodyText.svelte';
|
||||||
|
import Block from '../../Block/Block.svelte';
|
||||||
import HorizontalScroller from '../HorizontalScroller.svelte';
|
import HorizontalScroller from '../HorizontalScroller.svelte';
|
||||||
import ScrollerBase from '../../ScrollerBase/ScrollerBase.svelte';
|
import ScrollerBase from '../../ScrollerBase/ScrollerBase.svelte';
|
||||||
import { circInOut } from 'svelte/easing';
|
|
||||||
|
|
||||||
const foobarText: string =
|
const foobarText: string =
|
||||||
'In the mystical land of Foobaristan, the legendary hero Foo set out on an epic quest to find his missing semicolon, only to discover that Bar had accidentally used it as a bookmark inside a JSON file. Naturally, the entire kingdom crashed immediately. As the villagers panicked, Foo and Bar tried to fix the situation by turning everything off and on again, but all that did was anger the ancient deity known as “The Build System,” which now demanded three sacrifices: a clean cache, a fresh node_modules folder, and someone’s weekend. And thus began the saga nobody asked for, yet every developer somehow relates to.';
|
'In the mystical land of Foobaristan, the legendary hero Foo set out on an epic quest to find his missing semicolon, only to discover that Bar had accidentally used it as a bookmark inside a JSON file. Naturally, the entire kingdom crashed immediately. As the villagers panicked, Foo and Bar tried to fix the situation by turning everything off and on again, but all that did was anger the ancient deity known as “The Build System,” which now demanded three sacrifices: a clean cache, a fresh node_modules folder, and someone’s weekend. And thus began the saga nobody asked for, yet every developer somehow relates to.';
|
||||||
|
|
||||||
// Optional: Bind your own variables to use them in your code.
|
// Optional: Bind your own variables to use them in your code.
|
||||||
let count = $state(1);
|
|
||||||
let index = $state(0);
|
|
||||||
let offset = $state(0);
|
|
||||||
let progress = $state(0);
|
let progress = $state(0);
|
||||||
let top = $state(0);
|
|
||||||
let threshold = $state(0.5);
|
|
||||||
let bottom = $state(1);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<BodyText text={foobarText} />
|
<BodyText text={foobarText} />
|
||||||
|
|
||||||
<ScrollerBase
|
<ScrollerBase bind:progress query="div.step-foreground-container">
|
||||||
{top}
|
|
||||||
{threshold}
|
|
||||||
{bottom}
|
|
||||||
bind:count
|
|
||||||
bind:index
|
|
||||||
bind:offset
|
|
||||||
bind:progress
|
|
||||||
query="div.step-foreground-container"
|
|
||||||
>
|
|
||||||
{#snippet backgroundSnippet()}
|
{#snippet backgroundSnippet()}
|
||||||
<!-- Add custom background HTML or component -->
|
<Block width="fluid">
|
||||||
<HorizontalScroller
|
<HorizontalScroller
|
||||||
height="100lvh"
|
bind:progress
|
||||||
direction="right"
|
height="100lvh"
|
||||||
bind:progress
|
handleScroll={false}
|
||||||
scrubbed
|
showDebugInfo
|
||||||
stops={[0.5]}
|
>
|
||||||
handleScroll={false}
|
<Demo />
|
||||||
easing={circInOut}
|
</HorizontalScroller>
|
||||||
showDebugInfo
|
</Block>
|
||||||
>
|
|
||||||
<Demo />
|
|
||||||
</HorizontalScroller>
|
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet foregroundSnippet()}
|
{#snippet foregroundSnippet()}
|
||||||
<!-- Add custom foreground HTML or component -->
|
<!-- Add custom foreground HTML or component -->
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue