OTTODesign System

Code

Cinema

Storybook group: Components · Sidebar path: Components/Cinema · Extracted 28.09.2026

Version Tag Status API
v1 <oc-cinema-v1> Stable, allowed for generation CinemaV1

Overview (v1)

Source: ./src/components/cinema/v1/Overview.mdx

Cinema

The cinema component provides a way to display multiple items in a horizontal slide. This component is useful in cases where visual space is limited, and you want to present a series of related content (e.g., images or cards) that the user can navigate through.

Default variation

Story Default:

<oc-cinema-v1 oc-aria-label="cinema of placeholders">
  <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 1</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 2</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 3</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 4</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 5</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 6</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 7</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 8</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 9</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 10</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 11</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 12</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 13</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 14</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 15</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 16</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 17</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 18</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 19</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 20</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 21</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 22</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 23</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 24</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 25</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 26</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 27</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 28</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 29</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 30</oc-placeholder-v1>
</oc-cinema-v1>

Configuration

The cinema component is configurable, allowing you to tailor its features and appearance to your specific needs. To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the cinema component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.

Info

See the Cinema UX documentation for detailed user experience guidelines.

Accessibility

The cinema component comes with a set of built-in accessibility features to ensure a seamless experience for all users.

Provide an ARIA label

To make the cinema recognizable for screen readers, use the oc-aria-label attribute to provide clear and descriptive context information. See the general accessibility documentation for guidance on using oc-aria-label, including how it works with link and masked link behavior.

Alternatively, you can surround the component with a <section> (or role="region") element with an ARIA label.

<section aria-label="My cinema section">
  <oc-cinema>
    <!-- Cinema items here -->
  </oc-cinema>
</section>

Events

The cinema component provides events for checking the item visibility and the stage scroll state.

Item visibility changed

The oc-item-visibility-changed event triggers, whenever the stage is scrolled and new items enter the viewport. The event returns an object that provides an array with all items that are currently visible on the page, their respective index positions in the collection, the scroll direction of the cinema stage, whether it is currently scrolling or not and the source that triggered the scroll:

myCinema.addEventListener("oc-item-visibility-changed", (event) => {
  event.detail; // Returns: { { visibleItems: {elements: HTMLElement[]; indices: number[] }, scrollDirection: "left | right", stageIsScrolling: boolean, scrollSource: "arrows" | "pagination-dots" | "move-method" | "swipe" }
});

For more information on tracking the visibility state of the component itself, see the visibility tracking documentation.

Stage scroll

The oc-stage-scroll event triggers when the stage is being scrolled. It returns the boolean isScrolling that reflects the current state as well as the source that initiated the scroll:

myCinema.addEventListener("oc-stage-scroll", (event) => {
  event.detail; // Returns: { isScrolling: boolean, source: "arrows" | "pagination-dots" | "move-method" | "swipe" }
});
Stage scroll completed

The oc-stage-scroll-completed event triggers when the stage scroll has been completed. It returns an object that provides an array with all items that are currently visible on the page, their respective index positions in the collection, the scroll direction of the cinema stage and the source that triggered the scroll:

myCinema.addEventListener("oc-stage-scroll-completed", (event) => {
  event.detail; // Returns: { { visibleItems: {elements: HTMLElement[]; indices: number[] }, scrollDirection: "left | right", scrollSource: "arrows" | "pagination-dots" | "move-method" | "swipe" }
});

Sources that initiate the scroll can be:

  • arrows - When the user interacts via the visual buttons.
  • pagination-dots - When the user interacts via the additional pagination-dots.
  • move-method - When the stage is being scrolled programmatically.
  • swipe - When the user interacts via swipe gestures on smartphones or laptop touchpads.

Configuration (v1)

Source: ./src/components/cinema/v1/Configuration.mdx

Cinema configuration

Configure the cinema component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

Story Default:

<oc-cinema-v1 oc-aria-label="cinema of placeholders">
  <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 1</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 2</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 3</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 4</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 5</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 6</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 7</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 8</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 9</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 10</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 11</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 12</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 13</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 14</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 15</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 16</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 17</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 18</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 19</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 20</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 21</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 22</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 23</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 24</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 25</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 26</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 27</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 28</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 29</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 30</oc-placeholder-v1>
</oc-cinema-v1>

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

API v1

Source: ./src/components/cinema/v1/CinemaV1.API.g.mdx

Cinema v1 API

API: <oc-cinema-v1> (CinemaV1)

The Cinema component provides a way to display multiple items in a horizontal slide. This component is useful in cases where visual space is limited, and you want to present a series of related content (e.g., images or cards) that the user can navigate through.

The Cinema component supports navigation through arrow buttons. The position of these buttons can be customized. It also supports ARIA labels for accessibility.

Attributes / properties
Attribute Type Default Required Description
resizing "none" | "stretch" | "cut" | "stretch-cut" "stretch-cut" no Specifies the resizing behavior of the items in the cinema. The resizing behavior determines - none Items are not resized. - stretch Items are stretched to fill the available space. - cut Items are cut off when they overflow. - stretch-cut Items are stretched to fill the available space, and cut off when they overflow.
cut string "0.5" no Sets the cut percentage of the items.

Used when the resizing property is set to cut or stretch-cut.
pagination-dots boolean false no Whether Pagination Dots should be visible. Pagination dots provide a visual indication of the number of items in the cinema, and which item is currently being viewed.
hide-skip-link boolean false no Hides the skip link that allows users to skip the carousel content. Set to true to hide the skip link.
items-per-page string no Sets the desired amount of items per page
gap string "16px" no Sets the gap between items.
stage-spacing string "16px" no Sets the spacing on the outer sides of the stage.
arrow-button-position string "50%" no Specifies the custom position of the arrow buttons. This can be any valid CSS value for the top property. The arrow buttons are used to navigate through the items in the cinema.
item-visibility-threshold number[] no The custom threshold used for tracking the visibility of the items
visible-items HTMLElement[] no The amount of current visible items.
oc-aria-label string no Sets the ARIA label of the cinema section. This label is used by screen readers to provide context to users with visual impairments. The label should describe the overall content or purpose of the cinema.

Providing an ARIA label can also be done by adding a surrounding <section> (or role="region") element with an ARIA label.
Slots
Slot Required Description
default yes Defines the main content of the cinema. This slot should contain a series of items (e.g., images or cards) that you want to present in a cinema format.
Events
Event Detail type Description
oc-item-visibility-changed CustomEvent<ScrollEventDetail> Scrolling the cinema triggers the oc-item-visibility-changed event. The event returns an object that provides an array with all items that are currently visible on the page, their respective index positions in the collection, and the scroll direction of the cinema stage
oc-stage-scroll CustomEvent<ScrollEventDetail> Scrolling the cinema triggers the oc-stage-scroll event. The event returns a boolean of the current state as well as the source that initiated the scroll.
oc-stage-scroll-completed CustomEvent<ScrollEventDetail> Dispatched after stage scroll initiated by user or programmatically has completed. Meaning there is no scrolling of the stage within a defined timeout. The event returns an object that provides an array with all items that are currently visible on the page, their respective index positions in the collection, and the scroll direction of the cinema stage. The event also returns the source that initiated the scroll.
oc-property-change OcCinemaV1Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
Methods
  • moveTo: (index: number, options?: { source?: "arrows" | "pagination-dots" | undefined; reducedMotion?: boolean | undefined; } | undefined) => void

    Scrolls cinema elements to the specified page index. The index corresponds to the pages calculated based on the container width and item sizes.

    Parameters:

    • index: number - The index of the page that should be scrolled to.
    • options: { source?: "arrows" | "pagination-dots" | undefined; reducedMotion?: boolean | undefined; } | undefined - Optional scroll behavior settings.

    Returns: void

    Example:

    const cinema = document.querySelector("oc-cinema-v1");
    cinema.moveTo(2, { reducedMotion: true, source: "pagination-dots" });
    
CSS custom properties
Custom property Default Description
--arrow-button-position 50% Sets the position of the arrow buttons.
--cut 0.5 Sets the cut percentage of the items.

Used when the resizing property is set to cut or stretch-cut.
--gap 16px Sets the gap between items.
--items-per-page Sets the desired amount of items per page Works only when resizing-mode is set to stretch-cut or cut
--stage-spacing 16px Sets the spacing on the outer sides of the stage.

Variations (v1)

Source: ./src/components/cinema/v1/Variations.mdx

Variations

Listed below are the most common variations of the cinema component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-cinema-variations--default · tags: components, cinema, v1

The default configuration with resizing set to stretch-cut.

<oc-cinema-v1 oc-aria-label="cinema of placeholders">
  <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 1</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 2</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 3</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 4</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 5</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 6</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 7</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 8</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 9</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 10</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 11</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 12</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 13</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 14</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 15</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 16</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 17</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 18</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 19</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 20</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 21</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 22</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 23</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 24</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 25</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 26</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 27</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 28</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 29</oc-placeholder-v1>
        
        <oc-placeholder-v1 interactive="true" style="width: 205px">ITEM 30</oc-placeholder-v1>
</oc-cinema-v1>

3 Items

Story: components-cinema-variations--three-items · tags: components, cinema, v1

The configuration with 3 items. The resizing is set to none. The items are not resized.

Args: defaultSlot=(see snippet), resizing=none

<oc-cinema-v1 oc-aria-label="cinema of placeholders" resizing="none">
  <oc-placeholder-v1  style="width: 100px" interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1  style="width: 100px"   interactive="true">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1   style="width: 100px"  interactive="true">ITEM 3</oc-placeholder-v1>
</oc-cinema-v1>

Stretch-Items

Story: components-cinema-variations--stretch-items · tags: components, cinema, v1

The configuration with 3 items. The resizing is set to stretch. The items are stretched to fill the available space.

Args: defaultSlot=(see snippet), resizing=stretch

<oc-cinema-v1 oc-aria-label="cinema of placeholders" resizing="stretch">
  <oc-placeholder-v1   interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 3</oc-placeholder-v1>
</oc-cinema-v1>

Different Item-Widths

Story: components-cinema-variations--different-item-widths · tags: components, cinema, v1

The configuration with items of different widths. The resizing is set to stretch.

Args: defaultSlot=(see snippet), resizing=stretch

<oc-cinema-v1 oc-aria-label="cinema of placeholders" resizing="stretch">
  <oc-placeholder-v1  interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true"  style="width: 85%">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>

Custom items per page

Story: components-cinema-variations--custom-items-per-page · tags: components, cinema, v1

The configuration with a set number of items per page.

Args: defaultSlot=(see snippet), items-per-page=7

<oc-cinema-v1 oc-aria-label="cinema of placeholders" items-per-page="7">
  <oc-placeholder-v1  interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1  interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>

Demo: Custom stage spacing

Story: components-cinema-variations--demo-custom-stage-spacing · tags: components, cinema, v1

Demo showcasing on how stage-spacing can be customized.

<div style="border: 2px dashed lightgray; padding: 16px 0">
  <oc-cinema-v1>
    <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
    <oc-placeholder-v1 interactive="true">ITEM 2</oc-placeholder-v1>
    <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  </oc-cinema-v1>
</div>

<div style="display: flex; flex-direction: column; gap: 16px;  margin-top: 32px;">
  <div style="display: flex; gap: 16px; align-items: center;">
    <label for="stage-spacing-slider">Stage Spacing</label>
    <input
      type="range"
      name="stage-spacing-slider"
      id="stage-spacing-slider"
      min="0"
      max="64"
      value="16"
    />
    <span id="stage-spacing-slider-value">16px</span>
  </div>
</div>

<script>
  (() => {
    const cinema = document.querySelector("oc-cinema-v1");
    const stageSpacingSlider = document.getElementById("stage-spacing-slider");
    const stageSpacingSliderValue = document.getElementById("stage-spacing-slider-value");

    stageSpacingSlider.addEventListener("input", (event) => {
      const value = event.target.value + "px";
      cinema.style.setProperty("--stage-spacing", value);
      stageSpacingSliderValue.textContent = value;
    });
  })();
</script>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: Custom stage spacing",
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    chromatic: {
      hideInChromatic: true,
      disableSnapshot: true
    },
    controls: {
      disabled: true
    }
  },
  render: () => {
    return html`
      <div style="border: 2px dashed lightgray; padding: 16px 0">
        <oc-cinema-v1>
          <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
          <oc-placeholder-v1 interactive="true">ITEM 2</oc-placeholder-v1>
          <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        </oc-cinema-v1>
      </div>

      <div style="display: flex; flex-direction: column; gap: 16px;  margin-top: 32px;">
        <div style="display: flex; gap: 16px; align-items: center;">
          <label for="stage-spacing-slider">Stage Spacing</label>
          <input
            type="range"
            name="stage-spacing-slider"
            id="stage-spacing-slider"
            min="0"
            max="64"
            value="16"
          />
          <span id="stage-spacing-slider-value">16px</span>
        </div>
      </div>

      <script>
        (() => {
          const cinema = document.querySelector("oc-cinema-v1");
          const stageSpacingSlider = document.getElementById("stage-spacing-slider");
          const stageSpacingSliderValue = document.getElementById("stage-spacing-slider-value");

          stageSpacingSlider.addEventListener("input", (event) => {
            const value = event.target.value + "px";
            cinema.style.setProperty("--stage-spacing", value);
            stageSpacingSliderValue.textContent = value;
          });
        })();
      </script>
    `;
  }
}

Demo: Move-Method

Story: components-cinema-variations--demo-move-method · tags: components, cinema, v1

Demo showcasing the movement of the stage programmatically.

Args: defaultSlot=(see snippet), pagination-dots=true

<!-- The component-->
<oc-cinema-v1 oc-aria-label="cinema of placeholders" pagination-dots><oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    </oc-cinema-v1>

<br />
<br />
<p>
  <oc-button-v1 size="50"> Move stage to page 5 </oc-button-v1>
  <br />
  <br />
  <textarea
    style="width: 100%; height: 4rem; resize:none; font-family: Monospace; border:0;"
    aria-label="example"
    disabled
  >
  const moveMyCinema = (myCinema) => {
    myCinema.moveTo(5);
  }
  </textarea>
</p>
<br />
<br />
<p>
  <oc-button-v1 size="50"> Move stage to page 5 (reduced motion)</oc-button-v1>
  <br />
  <br />
  <textarea
    style="width: 100%; height: 4rem; resize:none; font-family: Monospace; border:0;"
    aria-label="example"
    disabled
  >
  const moveMyCinema = (myCinema) => {
    myCinema.moveTo(5, { reducedMotion: true });
  }
  </textarea>
</p>

<script>
  (() => {
    const [moveStage, moveStageReducedMotion] = document.getElementsByTagName("oc-button-v1");

    moveStage.addEventListener("click", () => {
      document.querySelector("oc-cinema-v1").moveTo(5);
    });

    moveStageReducedMotion.addEventListener("click", () => {
      document.querySelector("oc-cinema-v1").moveTo(5, { reducedMotion: true });
    });
  })();
</script>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: Move-Method",
  parameters: {
    chromatic: {
      hideInChromatic: true,
      disableSnapshot: true
    }
  },
  args: {
    defaultSlot: `<oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    <oc-placeholder-v1  variant="image" width="100%" height="100%" style="height: 300px" interactive="true"></oc-placeholder-v1>
    `,
    "pagination-dots": true
  },
  render: ({
    defaultSlot,
    ...props
  }) => {
    return html`
      <!-- The component-->
      <oc-cinema-v1 ${spread(props)}>${unsafeHTML(defaultSlot)}</oc-cinema-v1>

      <br />
      <br />
      <p>
        <oc-button-v1 size="50"> Move stage to page 5 </oc-button-v1>
        <br />
        <br />
        <textarea
          style="width: 100%; height: 4rem; resize:none; font-family: Monospace; border:0;"
          aria-label="example"
          disabled
        >
        const moveMyCinema = (myCinema) => {
          myCinema.moveTo(5);
        }
        </textarea>
      </p>
      <br />
      <br />
      <p>
        <oc-button-v1 size="50"> Move stage to page 5 (reduced motion)</oc-button-v1>
        <br />
        <br />
        <textarea
          style="width: 100%; height: 4rem; resize:none; font-family: Monospace; border:0;"
          aria-label="example"
          disabled
        >
        const moveMyCinema = (myCinema) => {
          myCinema.moveTo(5, { reducedMotion: true });
        }
        </textarea>
      </p>

      <script>
        (() => {
          const [moveStage, moveStageReducedMotion] = document.getElementsByTagName("oc-button-v1");

          moveStage.addEventListener("click", () => {
            document.querySelector("oc-cinema-v1").moveTo(5);
          });

          moveStageReducedMotion.addEventListener("click", () => {
            document.querySelector("oc-cinema-v1").moveTo(5, { reducedMotion: true });
          });
        })();
      </script>
    `;
  }
}

Demo: Multiple Cinemas

Story: components-cinema-variations--demo-multiple-cinemas · tags: components, cinema, v1

The configuration with items of different widths. The resizing is set to stretch.

<h1>List of Cinemas</h1>

<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>

<oc-cinema-v1
  id="cinema-1"
  pagination-dots
  item-visibility-threshold="[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]"
>
  <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>
<div style="margin-top: 32px"></div>
<oc-cinema-v1 id="cinema-2" pagination-dots item-visibility-threshold="[0.4, 0.8]">
  <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>
<div style="margin-top: 32px"></div>

<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>

<oc-cinema-v1 id="cinema-3" pagination-dots item-visibility-threshold="[0.3, 0.6, 0.9]">
  <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>
<div style="margin-top: 32px"></div>
<oc-cinema-v1 id="cinema-4" pagination-dots>
  <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>
<p>
  This cinema element has special tracking attributes (starting with <code>data-tr-v1</code>),
  which configure the tracking engine to observe the element by utilizing the provided
  threshold values. The element will be tracked when it becomes visible by at least 50% (as
  configured). And then tracking engin will first emit an event
  <code>tr-become-visible</code> containing the tracking trigger. and then if the event is not
  canceled, it will submit the default tracking method <code>submitMiniAction</code> to the
  tracking library (bct).
</p>
<p>
  you can make the submission visible in the console by enabling the tracking debug mode and
  providing a fake implementation (since bct is not enabled in storybook)
</p>
<pre><code>
  otto.tracking.submitMiniAction.assignFunction(console.log);
  o_global.debug.activate("nexus.otto.tracking", "debug");
</code></pre>
<oc-cinema-v1
  id="cinema-5"
  pagination-dots
  data-tr-v1
  data-tr-v1-tr-become-visible.observer='{ "threshold": 0.5 }'
  data-tr-v1-tr-become-visible.updates='[{ "featureId": "foo-barid", "status": "works" }]'
>
  <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>

<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>
<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>
<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>
<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>
<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>
<oc-cinema-v1 id="cinema-6" pagination-dots item-visibility-threshold="[0.5]">
  <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
  <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
</oc-cinema-v1>

<p>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
  maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
  repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
  laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
  itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
  optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
  necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
  exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
  dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
  atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
  maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
  eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
  laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
  Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
  reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
  dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
  qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
  placeat facilis facere quia doloribus.
</p>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: Multiple Cinemas",
  parameters: {
    controls: {
      disabled: true
    },
    chromatic: {
      hideInChromatic: true,
      disableSnapshot: true
    }
  },
  render: () => {
    return html`
      <h1>List of Cinemas</h1>

      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>

      <oc-cinema-v1
        id="cinema-1"
        pagination-dots
        item-visibility-threshold="[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]"
      >
        <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
      </oc-cinema-v1>
      <div style="margin-top: 32px"></div>
      <oc-cinema-v1 id="cinema-2" pagination-dots item-visibility-threshold="[0.4, 0.8]">
        <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
      </oc-cinema-v1>
      <div style="margin-top: 32px"></div>

      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>

      <oc-cinema-v1 id="cinema-3" pagination-dots item-visibility-threshold="[0.3, 0.6, 0.9]">
        <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
      </oc-cinema-v1>
      <div style="margin-top: 32px"></div>
      <oc-cinema-v1 id="cinema-4" pagination-dots>
        <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
      </oc-cinema-v1>
      <p>
        This cinema element has special tracking attributes (starting with <code>data-tr-v1</code>),
        which configure the tracking engine to observe the element by utilizing the provided
        threshold values. The element will be tracked when it becomes visible by at least 50% (as
        configured). And then tracking engin will first emit an event
        <code>tr-become-visible</code> containing the tracking trigger. and then if the event is not
        canceled, it will submit the default tracking method <code>submitMiniAction</code> to the
        tracking library (bct).
      </p>
      <p>
        you can make the submission visible in the console by enabling the tracking debug mode and
        providing a fake implementation (since bct is not enabled in storybook)
      </p>
      <pre><code>
        otto.tracking.submitMiniAction.assignFunction(console.log);
        o_global.debug.activate("nexus.otto.tracking", "debug");
      </code></pre>
      <oc-cinema-v1
        id="cinema-5"
        pagination-dots
        data-tr-v1
        data-tr-v1-tr-become-visible.observer='{ "threshold": 0.5 }'
        data-tr-v1-tr-become-visible.updates='[{ "featureId": "foo-barid", "status": "works" }]'
      >
        <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
      </oc-cinema-v1>

      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>
      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>
      <oc-cinema-v1 id="cinema-6" pagination-dots item-visibility-threshold="[0.5]">
        <oc-placeholder-v1 interactive="true">ITEM 1</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 1500px">ITEM 2</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 3</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 4</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true" style="width: 100px">ITEM 5</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 6</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 7</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 8</oc-placeholder-v1>
        <oc-placeholder-v1 interactive="true">ITEM 9</oc-placeholder-v1>
      </oc-cinema-v1>

      <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Officiis facilis nobis nisi odit
        maiores libero assumenda repudiandae. Repudiandae sapiente odit id. Voluptas dolores
        repellendus sit corrupti ab dolor distinctio, expedita id quod suscipit. Saepe culpa libero
        laborum vel quos illum officia, fuga corporis dolor excepturi! Excepturi, nobis. Pariatur
        itaque voluptas tenetur qui aut eveniet, aliquam numquam quia distinctio dolor ducimus quod
        optio quam soluta expedita eligendi quae, ipsa culpa. Praesentium autem impedit,
        necessitatibus quos porro cupiditate ipsam eveniet nisi illo. Sequi molestias magnam
        exercitationem repudiandae maiores dolor itaque earum necessitatibus facere. Officiis
        dolorem, hic modi, maxime sint sapiente, libero quas impedit earum quibusdam rerum minus
        atque doloribus! Accusamus impedit rerum ea pariatur sunt ex iure consequatur! Quisquam
        maiores doloremque, sit vero, sint a ullam eum possimus dicta voluptatem numquam sequi
        eveniet dolorem recusandae ratione odio! Sint reprehenderit earum quas fugit dolorum
        laudantium maiores officiis necessitatibus harum? Exercitationem provident dolores soluta.
        Rerum minus hic asperiores nesciunt, error quae blanditiis expedita ducimus facere provident
        reprehenderit, ex autem tempore praesentium? Culpa blanditiis repellendus earum qui? Atque
        dolorem, impedit dignissimos non pariatur blanditiis porro nisi doloribus? Fugit recusandae
        qui dignissimos, natus architecto sapiente sunt laudantium tenetur temporibus iste totam
        placeat facilis facere quia doloribus.
      </p>
    `;
  }
}

Demo: Device Type Detection

Story: components-cinema-variations--demo-device-type-detection · tags: components, cinema, v1

Demo showing the detected device type and how it affects the cinema navigation arrows. On touch-only devices, arrows are hidden. On hybrid and desktop devices, arrows are shown.

<p>
  <strong>Detected device type:</strong> ${deviceType}<br />
  <code
    >isTouchable: ${pt.isTouchable} · isHybrid: ${pt.isHybrid} · isMouse: ${pt.isMouse}</code
  >
</p>
<p>
  On <strong>touch-only</strong> devices, navigation arrows are hidden (users swipe
  natively).<br />
  On <strong>hybrid</strong> and <strong>desktop/mouse</strong> devices, navigation arrows are
  visible.
</p>
<oc-cinema-v1 pagination-dots>
  ${unsafeHTML(Array.from(Array(8), (_, i) => `<oc-placeholder-v1 interactive="true" style="width: 205px">ITEM ${i + 1}</oc-placeholder-v1>`).join(""))}
</oc-cinema-v1>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Demo: Device Type Detection",
  parameters: {
    controls: {
      disabled: true
    },
    chromatic: {
      hideInChromatic: true,
      disableSnapshot: true
    }
  },
  render: () => {
    const pt = pointerType.get();
    let deviceType: string;
    if (pt.isHybrid) {
      deviceType = "Hybrid (touch + pointer)";
    } else if (pt.isTouchable) {
      deviceType = "Touch only";
    } else {
      deviceType = "Mouse / Desktop";
    }
    return html`
      <p>
        <strong>Detected device type:</strong> ${deviceType}<br />
        <code
          >isTouchable: ${pt.isTouchable} · isHybrid: ${pt.isHybrid} · isMouse: ${pt.isMouse}</code
        >
      </p>
      <p>
        On <strong>touch-only</strong> devices, navigation arrows are hidden (users swipe
        natively).<br />
        On <strong>hybrid</strong> and <strong>desktop/mouse</strong> devices, navigation arrows are
        visible.
      </p>
      <oc-cinema-v1 pagination-dots>
        ${unsafeHTML(Array.from(Array(8), (_, i) => `<oc-placeholder-v1 interactive="true" style="width: 205px">ITEM ${i + 1}</oc-placeholder-v1>`).join(""))}
      </oc-cinema-v1>
    `;
  }
}

Interaction tests (CinemaV1.interactions.stories.ts)

Interaction test stories (automated tests, not usage patterns).

Move Cinema

Story: components-cinema-interaction-tests--move-cinema · tags: components, cinema, v1, interactions, play-fn

Args: pagination-dots=true, defaultSlot=(see snippet)

<oc-cinema-v1 style="width: 800px" pagination-dots>
  <div tabindex="0" style="background: lightcyan">
              Content
            </div>
          <div tabindex="0" style="background: lightcyan">
              Content
            </div>
          <div tabindex="0" style="background: lightcyan">
              Content
            </div>
          <div tabindex="0" style="background: lightcyan">
              Content
            </div>
          <div tabindex="0" style="background: lightcyan">
              Content
            </div>
          <div tabindex="0" style="background: lightcyan">
              Content
            </div>
          
</oc-cinema-v1>
Story source (TypeScript, verbatim from Storybook)
{
  args: {
    "pagination-dots": true,
    defaultSlot: `${new Array(6).fill(`<div tabindex="0" style="background: lightcyan">
              Content
            </div>
          `).join("")}`
  },
  parameters: {
    chromatic: {
      disableSnapshot: true
    }
  },
  render(args) {
    const {
      defaultSlot,
      ...props
    } = args;
    return html` <oc-cinema-v1 style="width: 800px" ${spread(props)}>
      ${unsafeHTML(defaultSlot)}
    </oc-cinema-v1>`;
  },
  play: async ({
    canvasElement
  }) => {
    await macrotasks(10);
    const {
      paginationDots,
      stageElement,
      prevButton,
      nextButton
    } = getSutElements(canvasElement);
    await waitFor("initial", async () => {
      await expect(stageElement.scrollLeft, "scrollLeft should be correct").toBe(0);
      await expect(prevButton, "previous button should not be visible").not.toBeVisible();
      await expect(nextButton, "next button should be visible").toBeVisible();
      await expect(toVisibleArray(paginationDots), "pagination dots should be correct").toEqual([1, 0, 0]);
    });

    // Perform scroll to the right
    await click(nextButton);
    await waitFor("scrolled to right", async () => {
      await expect(prevButton, "previous button should be visible").toBeVisible();
      await expect(nextButton, "next button should be visible").toBeVisible();
      await expect(toVisibleArray(paginationDots), "pagination dots should be correct").toEqual([0, 1, 0]);
    });

    // Perform scroll to the right
    await click(nextButton);
    await waitFor("scrolled to right", async () => {
      await expect(prevButton, "previous button should be visible").toBeVisible();
      await expect(nextButton, "next button should not be visible").not.toBeVisible();
      await expect(toVisibleArray(paginationDots), "pagination dots should be correct").toEqual([0, 0, 1]);
    });

    // Perform scroll to the left
    await click(prevButton);
    await waitFor("scrolled to left", async () => {
      await expect(prevButton, "previous button should be visible").toBeVisible();
      await expect(nextButton, "next button should be visible").toBeVisible();
      await expect(toVisibleArray(paginationDots), "pagination dots should be correct").toEqual([0, 1, 0]);
    });

    // Perform scroll to the left
    await click(prevButton);
    await waitFor("scrolled to left", async () => {
      await expect(prevButton, "previous button should not be visible").not.toBeVisible();
      await expect(nextButton, "next button should be visible").toBeVisible();
      await expect(toVisibleArray(paginationDots), "pagination dots should be correct").toEqual([1, 0, 0]);
    });
  }
}

Move Cinema Without Resizing

Story: components-cinema-interaction-tests--move-cinema-without-resizing · tags: components, cinema, v1, interactions

Args: resizing=none, pagination-dots=true, defaultSlot=(see snippet)

Story source (TypeScript, verbatim from Storybook)
MoveCinemaWithoutResizingStories.MoveCinemaWithoutResizing

Asynchronous Content

Story: components-cinema-interaction-tests--asynchronous-content · tags: components, cinema, v1, interactions, play-fn

<oc-cinema-v1 pagination-dots style="width: 500px"></oc-cinema-v1>
Story source (TypeScript, verbatim from Storybook)
{
  render() {
    return html` <oc-cinema-v1 pagination-dots style="width: 500px"></oc-cinema-v1>`;
  },
  play: async ({
    canvasElement
  }) => {
    await macrotasks(10);
    const {
      cinemaElement
    } = getSutElements(canvasElement);
    const item = document.createElement("div");
    item.innerHTML = "Content";
    item.tabIndex = 0;
    const items = Array.from({
      length: 20
    }).map(() => item.cloneNode(true) as HTMLElement);

    // eslint-disable-next-line no-restricted-syntax
    for (const i of items) {
      cinemaElement.append(i);
      // eslint-disable-next-line no-await-in-loop
      await macrotasks(1);
    }
    const paginationDots = Array.from(cinemaElement.shadowRoot!.querySelectorAll(".paginationdots__item"));
    await expect(paginationDots.length, "pagination dots should be rendered").toBe(20);
    await expect(paginationDots[0].classList.contains("paginationdots__item--selected"), "first pagination dot should be selected").toBeTruthy();
    await expect(paginationDots.slice(1).some(e => e.classList.contains("paginationdots__item--selected")), "other pagination dots should not be selected").toBeFalsy();
  }
}

Pagination With Different Sizes

Story: components-cinema-interaction-tests--pagination-with-different-sizes · tags: components, cinema, v1, interactions, play-fn

<div tabindex="0" style="background: lightcyan; width: ${w}px">
  ${i + 1}. ${w}px
</div>
Story source (TypeScript, verbatim from Storybook)
{
  render() {
    const items = (widthes: number[]) => {
      return widthes.map((w, i) => html`<div tabindex="0" style="background: lightcyan; width: ${w}px">
            ${i + 1}. ${w}px
          </div>`);
    };
    return html`
      <div data-testid="cinema1">
        <h3>Gap=default</h3>
        <oc-cinema-v1 pagination-dots style="width: 500px" resizing="none">
          ${items([124, 157, 131, 219, 84, 92, 317, 160, 142])}
        </oc-cinema-v1>
      </div>

      <div data-testid="cinema2">
        <h3>Gap=50px perfect fit 3 items</h3>
        <oc-cinema-v1 pagination-dots style="width: 466px" resizing="none" gap="50px">
          ${items([100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100])}
        </oc-cinema-v1>
      </div>

      <div data-testid="cinema3">
        <h3>Gap=50px perfect fit 1 item</h3>
        <oc-cinema-v1 pagination-dots style="width: 466px" resizing="none" gap="50px">
          ${items([400, 400, 400])}
        </oc-cinema-v1>
      </div>

      <style>
        div > oc-cinema-v1 {
          background: lightcoral;
        }
      </style>
    `;
  },
  play: async ({
    canvasElement
  }) => {
    await macrotasks(10);
    const sut1 = getSutElements(canvasElement.querySelector('[data-testid="cinema1"]')!);
    sut1.prevButton.style.display = "none"; // hide buttons for better debugging
    sut1.nextButton.style.display = "none"; // hide buttons for better debugging

    const sut2 = getSutElements(canvasElement.querySelector('[data-testid="cinema2"]')!);
    sut2.prevButton.style.display = "none"; // hide buttons for better debugging
    sut2.nextButton.style.display = "none"; // hide buttons for better debugging

    const sut3 = getSutElements(canvasElement.querySelector('[data-testid="cinema3"]')!);
    sut3.prevButton.style.display = "none"; // hide buttons for better debugging
    sut3.nextButton.style.display = "none"; // hide buttons for better debugging

    // TEST CINEMA 1
    await expect(sut1.paginationDots.length).toBe(4);
    await expect(sut1.stageElement.scrollLeft).toBe(0);
    await click(sut1.paginationDots[1]);
    await waitFor("cinema 1 page 2", async () => {
      await expect(sut1.stageElement.scrollLeft).toBeGreaterThanOrEqual(439);
      await expect(sut1.stageElement.scrollLeft).toBeLessThanOrEqual(440);
    });
    await click(sut1.paginationDots[2]);
    await waitFor("cinema 1 page 3", async () => {
      await expect(sut1.stageElement.scrollLeft).toBeGreaterThanOrEqual(827);
      await expect(sut1.stageElement.scrollLeft).toBeLessThanOrEqual(828);
    });
    await click(sut1.paginationDots[3]);
    await waitFor("cinema 1 page 4", async () => {
      await expect(sut1.stageElement.scrollLeft === 1086 || sut1.stageElement.scrollLeft === 1070).toBeTruthy();
    });

    // TEST CINEMA 2
    await expect(sut2.paginationDots.length).toBe(6);
    await expect(sut2.stageElement.scrollLeft).toBe(0);
    await click(sut2.paginationDots[1]);
    await waitFor("cinema 2 page 2", async () => {
      await expect([416, 433].includes(sut2.stageElement.scrollLeft)).toBeTruthy();
    });
    await click(sut2.paginationDots[2]);
    await waitFor("cinema 2 page 3", async () => {
      await expect(sut2.stageElement.scrollLeft).toBe(883);
    });
    await click(sut2.paginationDots[3]);
    await waitFor("cinema 2 page 4", async () => {
      await expect(sut2.stageElement.scrollLeft).toBe(1333);
    });

    // TEST CINEMA 3
    await expect(sut3.paginationDots.length).toBe(3);
    await expect(sut3.stageElement.scrollLeft).toBe(0);
    await click(sut3.paginationDots[1]);
    await waitFor("cinema 3 page 2", async () => {
      await expect(sut3.stageElement.scrollLeft).toBe(433);
    });
    await click(sut3.paginationDots[2]);
    await waitFor("cinema 3 page 3", async () => {
      await expect([850, 866].includes(sut3.stageElement.scrollLeft)).toBeTruthy();
    });
  }
}