/ src / context / accessibility-layout.ts
accessibility-layout.ts
 1  import { getContext, setContext } from 'svelte';
 2  
 3  import type { Shelf } from '@jet-app/app-store/api/models';
 4  import { isAccessibilityHeaderShelf } from '~/components/jet/shelf/AccessibilityHeaderShelf.svelte';
 5  import { isAccessibilityFeaturesShelf } from '~/components/jet/shelf/AccessibilityFeaturesShelf.svelte';
 6  import { isAccessibilityDeveloperLinkShelf } from '~/components/jet/shelf/AccessibilityDeveloperLinkShelf.svelte';
 7  
 8  /**
 9   * Describes the layout configuration for accessibility shelves
10   */
11  interface AccessibilityLayoutConfiguration {
12      withBottomPadding: boolean;
13  }
14  
15  const ACCESSIBILITY_LAYOUT_FALLBACK: AccessibilityLayoutConfiguration =
16      Object.freeze({
17          withBottomPadding: false,
18      });
19  
20  type AccessibilityLayoutStore = WeakMap<
21      Shelf,
22      AccessibilityLayoutConfiguration
23  >;
24  type AccessibilityLayoutStoreContext = AccessibilityLayoutStore | undefined;
25  
26  const ACCESSIBILITY_LAYOUT_CONTEXT_ID = 'accessibility-layout-context';
27  
28  /**
29   * Check if a shelf is accessibility-related
30   */
31  function isAccessibilityRelated(shelf: Shelf): boolean {
32      return (
33          shelf.contentType === 'accessibilityParagraph' ||
34          shelf.contentType === 'accessibilityFeatures'
35      );
36  }
37  
38  /**
39   * Check if a shelf is one of the target accessibility shelves
40   */
41  function isTargetAccessibilityShelf(shelf: Shelf): boolean {
42      return (
43          isAccessibilityHeaderShelf(shelf) ||
44          isAccessibilityFeaturesShelf(shelf) ||
45          isAccessibilityDeveloperLinkShelf(shelf)
46      );
47  }
48  
49  /**
50   * Store the {@linkcode AccessibilityLayoutConfiguration} for each accessibility shelf
51   * in "context", so it can be retrieved at the shelf-component level
52   *
53   * This determines bottom padding based on whether the next shelf is accessibility-related
54   */
55  export function setAccessibilityLayoutContext(page: { shelves: Shelf[] }) {
56      const store: AccessibilityLayoutStore = new WeakMap();
57  
58      for (let i = 0; i < page.shelves.length; i++) {
59          const shelf = page.shelves[i];
60  
61          // Only process target accessibility shelves
62          if (!isTargetAccessibilityShelf(shelf)) {
63              continue;
64          }
65  
66          // Check if the next shelf is accessibility-related
67          const nextShelf = page.shelves[i + 1];
68          const hasAccessibilityNext =
69              nextShelf && isAccessibilityRelated(nextShelf);
70  
71          store.set(shelf, {
72              withBottomPadding: !hasAccessibilityNext,
73          });
74      }
75  
76      setContext<AccessibilityLayoutStoreContext>(
77          ACCESSIBILITY_LAYOUT_CONTEXT_ID,
78          store,
79      );
80  }
81  
82  /**
83   * Retrieve the {@linkcode AccessibilityLayoutConfiguration} for a given accessibility shelf
84   */
85  export function getAccessibilityLayoutConfiguration(
86      shelf: Shelf,
87  ): AccessibilityLayoutConfiguration {
88      const accessibilityLayout = getContext<AccessibilityLayoutStoreContext>(
89          ACCESSIBILITY_LAYOUT_CONTEXT_ID,
90      );
91  
92      return accessibilityLayout?.get(shelf) ?? ACCESSIBILITY_LAYOUT_FALLBACK;
93  }