import { Meta } from '@storybook/blocks';

import * as LottieStories from './Lottie.stories.svelte';
import CompositionMarkerImage from './assets/marker.jpg?url';

<Meta of={LottieStories} />

# Lottie

The `Lottie` component uses the [dotLottie-web](https://developers.lottiefiles.com/docs/dotlottie-player/dotlottie-web/) library to render Lottie animations.

## How to prepare Lottie files

[LottieFiles](https://lottiefiles.com/) is the official platform for creating and editing Lottie animations. The free version of LottieFiles has limited features, so [Bodymovin](https://exchange.adobe.com/apps/cc/12557/bodymovin) remains a popular, free way to export Lottie animations as JSON files. 

[dotLottie](https://dotlottie.io/) is another common format for Lottie files. This format bundles the Lottie JSON file and any associated assets, such as images and fonts, into a single compressed file with the extension `.lottie`.

This `Lottie` component is flexible and supports both `dotLottie` and JSON Lottie files. For best performance it is recommended that you convert your Lottie JSON file into a `.zip` file by following these steps:

1. Export your Lottie animation as a JSON file using [Bodymovin](https://exchange.adobe.com/apps/cc/12557/bodymovin) or another Lottie exporter.
2. Use the [LottieFiles converter](https://lottiefiles.com/tools/lottie-to-dotlottie) to convert the JSON file into a `.lottie` file. 
3. Change the file extension to `.zip` from `.lottie`. This ensures full compatibility with the Reuters graphics publisher while maintaining the benefits of dotLottie format's compression and optimisation.

## Basic demo

To use the `Lottie` component, import it and provide the Lottie animation source. The height of the container defaults to `100lvh`, but you can adjust this to any valid CSS height value such as `1200px` or `200lvh` with the `height` prop.

**Use `lvh` or `svh` units instead of `vh`** as [these units](https://www.w3.org/TR/css-values-4/#large-viewport-size) are more reliable on mobile and other devices where elements such as the address bar appear and disappear and affect the height.

If importing the Lottie file directly into a Svelte component, make sure to append **?url** to the import statement (see example below). This ensures that the file is treated as a URL.

> 💡TIP: Set `showDebugInfo` prop to `true` to display information about the component state.

[Demo](?path=/story/components-graphics-scrollerlottie--demo)


```svelte
<script lang="ts">
  import { Lottie } from '@reuters-graphics/graphics-components';

  // Import Lottie file
  import MyLottie from './lottie/my-lottie.zip?url'; // Append **?url** to the file path
</script>

<Lottie src={MyLottie} autoplay={true} showDebugInfo={true} />
```

## Using with ArchieML

If you are using `Lottie` with ArchieML, store your Lottie zip file in the `src/statics/lottie/` folder.

With the graphics kit, you'll likely get your text and prop values from an ArchieML doc...

```yaml
# ArchieML doc
[blocks]
  type: lottie

  # Lottie file stored in `src/statics/lottie/` folder
  src: lottie/LottieFile.zip
  autoplay: true
  loop: true
  showDebugInfo: true
[]
```

... which you'll parse out of a ArchieML block object before passing to the `Lottie` component.

```svelte
<script lang="ts">
  import { Lottie } from '@reuters-graphics/graphics-components';

  // Graphics kit only
  import { assets } from '$app/paths'; // 👈 If using in the graphics kit...
  import { truthy } from '$utils/propValidators'; // 👈 If using in the graphics kit...
</script>

{#each content.blocks as block}
  <!-- Inside the content.blocks for loop... -->
  {#if block.type == 'lottie'}
    <Lottie
      src={`${assets}/${block.src}`}
      autoplay={truthy(block.autoplay)}
      loop={truthy(block.loop)}
      showDebugInfo={truthy(block.showDebugInfo)}
    />
  {/if}
{/each}
```

## Playing a segment

 The `Lottie` component can play a specific segment of the Lottie animation using the `segment` prop. The `segment` prop expects an array of two numbers representing the start and end frames of the segment.

[Demo](?path=/story/components-graphics-scrollerlottie--segment)

With the graphics kit, you'll likely get your text and prop values from an ArchieML doc...

```yaml
# ArchieML doc
[blocks]
  type: lottie
  showDebugInfo: true
  loop: true

  # Optionally, set playback speed
  speed: 0.5

  # Lottie file stored in `src/statics/lottie/` folder
  src: lottie/LottieFile.zip
  [.segment]
    start: 0
    end: 20
  []
[]
```

... which you'll parse out of a ArchieML block object before passing to the `Lottie` component.

```svelte
<script lang="ts">
  import { Lottie } from '@reuters-graphics/graphics-components';

  // Graphics kit only
  import { assets } from '$app/paths'; // 👈 If using in the graphics kit...
  import { truthy } from '$utils/propValidators'; // 👈 If using in the graphics kit...
</script>

{#each content.blocks as block}
  <!-- Inside the content.blocks for loop... -->
  {#if block.type == 'lottie'}
    <Lottie
      src={`${assets}/${block.src}`}
      segment={[parseInt(block.segment.start), parseInt(block.segment.end)]}
      showDebugInfo={truthy(block.showDebugInfo)}
      loop={truthy(block.loop)}
      speed={parseInt(block.speed)}
    />
  {/if}
{/each}
```

## Markers

 The `Lottie` component can also play a specific portion of the Lottie animation using markers set in [AfterEffects](https://helpx.adobe.com/in/after-effects/using/layer-markers-composition-markers.html).

The list of available markers, which can be passed into the `marker` prop, can be found in the debug info box that appears when `showDebugInfo` is set to `true`.

When setting markers in AfterEffects, ensure that the **Comment** section of the Composition Marker contains only the name of your marker:

<img src={CompositionMarkerImage} alt="Composition Marker Dialog" />

[Demo](?path=/story/components-graphics-scrollerlottie--marker)

```svelte
<script lang="ts">
  import { Lottie } from '@reuters-graphics/graphics-components';

  // Import Lottie file
  import MyLottie from './lottie/my-lottie.zip?url'; // Append **?url** to the file path
</script>

<Lottie src={MyLottie} marker="myMarker"
/>
```

## Switching themes

[Lottie Creator](https://lottiefiles.com/theming) allows you to define multiple colour themes for your animation. You can switch between these themes using the `theme` prop.

Available themes can be found in the debug info when the `showDebugInfo` prop is set to `true`.

You can set multiple themes and switch between them dynamically -- for example, based on the `progress` of the animation.

[Demo](?path=/story/components-graphics-scrollerlottie--themes)

```svelte
<script lang="ts">
  import { Lottie } from '@reuters-graphics/graphics-components';
  import MyLottie from './lottie/my-lottie.zip?url';

  // Set a bindable `progress` variable to pass into `<Lottie />`
  let progress = $state(0);
</script>

<Lottie
  src={MyLottie}
  bind:progress
  themeId={progress < 0.33 ? 'water'
  : progress < 0.66 ? 'air'
  : 'earth'}
  autoplay
  showDebugInfo
/>
```

## Using with `ScrollerBase`

The `Lottie` component can be used with the `ScrollerBase` component to create a more complex scrolling experience. `ScrollerBase` provides a scrollable container sets the `Lottie` component as a background.

```svelte
<script lang="ts">
  import { Lottie, ScrollerBase } from '@reuters-graphics/graphics-components';
  import MyLottie from './lottie/my-lottie.zip?url';

  // Pass `progress` as `videoPercentage` to Lottie
  let progress = $state(0);
</script>

<ScrollerBase bind:progress query="div.step-foreground-container">
  {#snippet backgroundSnippet()}
    <!-- Pass bindable prop `progress` as `progress` -->
      <Lottie src={MyLottie} {progress} showDebugInfo />
  {/snippet}
  {#snippet foregroundSnippet()}
    <div class="step-foreground-container">
      <h3 class="text-center">Step 1</h3>
    </div>
    <div class="step-foreground-container">
      <h3 class="text-center">Step 2</h3>
    </div>
    <div class="step-foreground-container">
      <h3 class="text-center">Step 3</h3>
    </div>
  {/snippet}
</ScrollerBase>

<style lang="scss">
  .step-foreground-container {
    height: 100lvh;
    width: 50%;
    margin: 0 auto;

    h3 {
      background-color: antiquewhite;
      text-align: center;
    }
  }
</style>
```

## With foregrounds

The `Lottie` component can also be used with the `LottieForeground` component to display foreground elements at specific times in the animation.

[Demo](?path=/story/components-graphics-scrollerlottie--with-foregrounds).

```svelte
<script lang="ts">
  import { Lottie, ScrollerBase } from '@reuters-graphics/graphics-components';
  import MyLottie from './lottie/my-lottie.zip?url';
</script>

  <Lottie src={MyLottie} autoplay >
  
    <!-- Foreground 1: Headline component as foreground -->
    <LottieForeground
      startFrame={0}
      endFrame={50}
      position="center center"
      backgroundColour="rgba(0, 0, 0)"
    >
      <div class="headline-container">
        <Theme base="dark">
          <Headline
            hed="Headline"
            dek="This is an example of using a Svelte component as the foreground."
            authors={['Jane Doe', 'John Doe']}
          />
        </Theme>
      </div>
    </LottieForeground>

    <!-- Foreground 2: Text only -->
     <LottieForeground
      startFrame={50}
      endFrame={100}
      text="Foreground caption between frames 50 and 100."
      position="bottom center"
      backgroundColour="rgba(0, 0, 0)"
      width="wide"
    />
  </Lottie>
```
### Using with ArchieML
With the graphics kit, you'll likely get your text and prop values from an ArchieML doc...

```yaml
# ArchieML doc
[blocks]
  type: lottie

  # Lottie file stored in `src/statics/lottie/` folder
  src: lottie/LottieFile.zip

  # Array of foregrounds
  [.foregrounds]

    # Foreground 1: Headline component
    startFrame: 0 # When in the animation to start showing the foreground
    endFrame: 50 # When to stop showing the foreground

    # Set foreground type
    type: component

    # Set props to pass into `LottieForeground`
    {.foregroundProps}
      componentName: Headline
      hed: Headline
      dek: Some deck text
      [.authors]
        * Jane Doe
        * John Smith
      []
    {}

  # Foreground 2: Text only
    startFrame: 50  
    endFrame: 100  

    # Set foreground type
    type: text

    # If the foreground type is `text`, set text prop here
    {.foregroundProps}
      text: Some text for the foreground
    {}

[]
```

... which you'll parse out of a ArchieML block object before passing to the `Lottie` component.

```svelte
<script lang="ts">
  import {
    Lottie,
    LottieForeground,
  } from '@reuters-graphics/graphics-components';
  import { assets } from '$app/paths';

 // Make an object of components to use as foregrounds
  const Components = $state({
    Headline,
  });
</script>

{#each content.blocks as block}
  <!-- Inside the content.blocks for loop... -->
  {#if block.type == 'lottie'}
    <Lottie src={`${assets}/${block.src}`} >
      {#each block.foregrounds as foreground}
        {#if foreground.type == 'text'}
          <LottieForeground
            startFrame={parseInt(foreground.startFrame)}
            endFrame={parseInt(foreground.endFrame)}
            text={foreground.foregroundProps.text}
          />
        {:else if foreground.type == 'component'}
          {@const Component =
            Components[foreground.foregroundProps.componentName]}
          <LottieForeground
            startFrame={parseInt(foreground.startFrame)}
            endFrame={parseInt(foreground.endFrame)}
          >
            <Component {...foreground.foregroundProps} />
          </LottieForeground>
        {/if}
      {/each}
    </Lottie>
  {/if}
{/each}
```
