/ src / components / ShelfItemLayout.svelte
ShelfItemLayout.svelte
  1  <!--
  2  @component
  3  Renders a set of `Shelf` items in either a horizontal shelf
  4  or a grid, depending on the `shelf` configuration
  5  
  6  Note: when configuring the `gridType` property, a single value will be used
  7  for both the shelf-based or grid-based item layouts. If two different grid types
  8  are needed instead, `gridTypeForShelf` and `gridTypeForGrid` are needed instead;
  9  these properties cannot be used alongside the general-purpose `gridType`.
 10  -->
 11  <script lang="ts" generics="Item">
 12      import type { Shelf } from '@jet-app/app-store/api/models';
 13  
 14      import type { GridType } from '@amp/web-app-components/src/components/Shelf/types';
 15  
 16      import type { XOR } from '~/utils/types';
 17      import HorizontalShelf from '~/components/jet/shelf/HorizontalShelf.svelte';
 18      import Grid from '~/components/Grid.svelte';
 19  
 20      /**
 21       * The sub-set of {@linkcode Shelf} that is necesary to render this component
 22       */
 23      interface RequiredShelf
 24          extends Pick<Shelf, 'rowsPerColumn' | 'isHorizontal'> {
 25          items: Item[];
 26      }
 27  
 28      interface $$Slots {
 29          default: {
 30              item: Item;
 31          };
 32      }
 33  
 34      /**
 35       * Represents the `gridType` properties of this component
 36       *
 37       * Either a `gridType` that will be used for both the shelf or grid
 38       * layouts can be provided, OR specific properties for the grid type
 39       * for the shelf and grid respectively; this `XOR` here prevents
 40       * these approachs from being mixed-and-matched.
 41       */
 42      type GeneralOrIndividualGridType = XOR<
 43          {
 44              gridType: GridType;
 45          },
 46          {
 47              gridTypeForGrid: GridType;
 48              gridTypeForShelf: GridType;
 49          }
 50      >;
 51  
 52      type $$Props = GeneralOrIndividualGridType & {
 53          shelf: RequiredShelf;
 54          rowsPerColumnOverride?: number | null;
 55      };
 56  
 57      /**
 58       * The shelf to render items for
 59       */
 60      export let shelf: RequiredShelf;
 61  
 62      /**
 63       * An optional override of the shelfs `rowsPerColumn` property
 64       */
 65      export let rowsPerColumnOverride: number | null = null;
 66  
 67      /**
 68       * Determine the grid type configuration for the shelf or grid layouts
 69       * based on the mutually-exclusive properties of {@linkcode GeneralOrIndividualGridType}
 70       */
 71      function extractGridTypes(props: $$Props) {
 72          if (typeof props.gridType === 'string') {
 73              return {
 74                  gridTypeForShelf: props.gridType,
 75                  gridTypeForGrid: props.gridType,
 76              };
 77          } else {
 78              return props;
 79          }
 80      }
 81  
 82      $: ({ gridTypeForShelf, gridTypeForGrid } = extractGridTypes(
 83          $$props as $$Props,
 84      ));
 85  
 86      $: isHorizontal = shelf.isHorizontal;
 87      $: gridRows = rowsPerColumnOverride ?? shelf.rowsPerColumn ?? undefined;
 88  </script>
 89  
 90  {#if isHorizontal}
 91      <HorizontalShelf
 92          items={shelf.items}
 93          {gridRows}
 94          gridType={gridTypeForShelf}
 95          let:item
 96      >
 97          <slot {item} />
 98      </HorizontalShelf>
 99  {:else}
100      <Grid items={shelf.items} gridType={gridTypeForGrid} let:item>
101          <slot {item} />
102      </Grid>
103  {/if}