@academix-admin/selection-viewer 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -32,6 +32,33 @@ var getStyles = (id) => `
32
32
  width: 100%;
33
33
  }
34
34
 
35
+ /*
36
+ * The close button, with a target a thumb can find.
37
+ *
38
+ * It sat at right: 0, top: 8 with no padding at all, so the icon was flush against the sheet's
39
+ * edge and the only thing that could be tapped was the glyph itself \u2014 a target well under half
40
+ * what a finger needs, in the corner of the screen where a thumb is least accurate. Inset by 4px
41
+ * and padded out to 44px square, so the icon still reads as sitting in the corner while the
42
+ * hittable area reaches the edges.
43
+ *
44
+ * The cancelButton.style prop is still spread last at the call site, so a consumer that was
45
+ * overriding any of this keeps overriding it. (No backticks in here: this whole block lives
46
+ * inside a template literal, and one would end the string.)
47
+ */
48
+ #${id} .selection-viewer-cancel {
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ min-width: 44px;
53
+ min-height: 44px;
54
+ padding: 10px;
55
+ border: none;
56
+ background-color: transparent;
57
+ color: inherit;
58
+ cursor: pointer;
59
+ -webkit-tap-highlight-color: transparent;
60
+ }
61
+
35
62
  #${id} .selection-viewer-drag-handle {
36
63
  height: 5px;
37
64
  border-radius: 3px;
@@ -72,11 +99,20 @@ var getStyles = (id) => `
72
99
  width: 100%;
73
100
  }
74
101
 
102
+ /*
103
+ * The rows, set in from the edges like everything else in the sheet.
104
+ *
105
+ * The title and the search box have carried a 16px margin from the start; the content had none, so
106
+ * a list of cards ran flush into the sides of the screen while the search box above it did not.
107
+ * The layoutProp.contentPadding option overrides it for a consumer that wants its rows edge to
108
+ * edge. (No backticks: this block is inside a template literal.)
109
+ */
75
110
  #${id} .selection-viewer-content {
76
111
  overflow-y: auto;
77
112
  -webkit-overflow-scrolling: touch;
78
113
  flex: 1;
79
114
  min-height: 0;
115
+ box-sizing: border-box;
80
116
  }
81
117
 
82
118
  #${id} .selection-viewer-content.vertical {
@@ -292,7 +328,6 @@ var SelectionViewer = ({
292
328
  [reportAggregate, unreportAggregate]
293
329
  );
294
330
  const reportedAggregate = reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : null;
295
- const isComposed = reportedAggregate !== null;
296
331
  const selectionState = selectionStateProp !== "initial" ? selectionStateProp : reportedAggregate ?? "initial";
297
332
  React.useEffect(() => {
298
333
  if (typeof window === "undefined" || !window.visualViewport) return;
@@ -459,12 +494,12 @@ var SelectionViewer = ({
459
494
  cancelButton?.position === "left" && /* @__PURE__ */ jsxRuntime.jsx(
460
495
  "button",
461
496
  {
497
+ "aria-label": cancelButton.ariaLabel || "Close",
498
+ className: "selection-viewer-cancel",
462
499
  style: {
463
500
  position: "absolute",
464
- left: "0px",
465
- top: "8px",
466
- border: "none",
467
- backgroundColor: "transparent",
501
+ left: "4px",
502
+ top: "4px",
468
503
  ...cancelButton.style
469
504
  },
470
505
  onClick: cancelButton.onClick || onClose,
@@ -485,12 +520,12 @@ var SelectionViewer = ({
485
520
  cancelButton?.position === "right" && /* @__PURE__ */ jsxRuntime.jsx(
486
521
  "button",
487
522
  {
523
+ "aria-label": cancelButton.ariaLabel || "Close",
524
+ className: "selection-viewer-cancel",
488
525
  style: {
489
526
  position: "absolute",
490
- right: "0px",
491
- top: "8px",
492
- border: "none",
493
- backgroundColor: "transparent",
527
+ right: "4px",
528
+ top: "4px",
494
529
  ...cancelButton.style
495
530
  },
496
531
  onClick: cancelButton.onClick || onClose,
@@ -564,7 +599,16 @@ var SelectionViewer = ({
564
599
  onScroll: onPaginate ? handleScroll : void 0,
565
600
  style: {
566
601
  paddingTop: isSearchFocused ? layoutProp?.gapBetweenSearchAndContent : "0",
567
- paddingBottom: keyboardHeight > 0 ? `${keyboardHeight + 16}px` : "16px"
602
+ paddingBottom: keyboardHeight > 0 ? `${keyboardHeight + 16}px` : "16px",
603
+ /*
604
+ * Set in from the edges, like everything else in the sheet.
605
+ *
606
+ * The title and the search box have carried 16px from the start and the content had
607
+ * none, so a list of rows ran flush into the sides of the screen under a search box
608
+ * that did not. Overridable for rows that genuinely want the full width.
609
+ */
610
+ paddingLeft: layoutProp?.contentPadding ?? "16px",
611
+ paddingRight: layoutProp?.contentPadding ?? "16px"
568
612
  },
569
613
  children: React__default.default.Children.count(children) > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
570
614
  children,
@@ -579,7 +623,7 @@ var SelectionViewer = ({
579
623
  children: loadingProp?.view
580
624
  }
581
625
  ),
582
- isComposed && selectionState === "empty" && /* @__PURE__ */ jsxRuntime.jsx(
626
+ selectionState === "empty" && /* @__PURE__ */ jsxRuntime.jsx(
583
627
  "div",
584
628
  {
585
629
  className: "selection-viewer-no-results",
@@ -590,7 +634,7 @@ var SelectionViewer = ({
590
634
  children: noResultProp?.view || /* @__PURE__ */ jsxRuntime.jsx("div", { className: "selection-viewer-default-no-results", children: noResultProp?.text || "No results found" })
591
635
  }
592
636
  ),
593
- isComposed && selectionState === "error" && /* @__PURE__ */ jsxRuntime.jsx(
637
+ selectionState === "error" && /* @__PURE__ */ jsxRuntime.jsx(
594
638
  "div",
595
639
  {
596
640
  className: "selection-viewer-error",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SelectionViewer.tsx","../src/Row.tsx","../src/Column.tsx"],"names":["React","useEffect","useState","useRef","useCallback","useMemo","jsx","jsxs","Sheet","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\r\nimport { Sheet } from \"@academix-admin/modal-sheet\";\r\n\r\n// ==================== Aggregation (Row/Column) ====================\r\n// Independent from @academix-admin/search-viewer's equivalent (Library Charter: packages stay\r\n// mutually independent) — same shape, duplicated intentionally rather than shared.\r\n\r\ntype AggregateReporter = {\r\n report: (id: string, state: SelectionState) => void;\r\n unreport: (id: string) => void;\r\n};\r\n\r\n/** A `Row` reports its own `state` into the nearest `Column` through this. */\r\nconst RowAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\n/** `Column` reports its own aggregated state up through this — `SelectionViewer` provides it and\r\n * merges whatever's reported into its own selectionState resolution, with zero extra wiring. */\r\nconst SelectionViewerAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\nfunction computeAggregateState(states: SelectionState[]): SelectionState {\r\n if (states.length === 0) return \"initial\";\r\n if (states.some((s) => s === \"data\")) return \"data\";\r\n if (states.some((s) => s === \"loading\")) return \"loading\";\r\n if (states.every((s) => s === \"empty\")) return \"empty\";\r\n if (states.some((s) => s === \"error\")) return \"error\";\r\n return \"initial\";\r\n}\r\n\r\n// ==================== Types ====================\r\ntype Padding = {\r\n l: string;\r\n r: string;\r\n t: string;\r\n b: string;\r\n};\r\n\r\ntype SnapPoint = number;\r\n\r\ntype SelectionState = \"loading\" | \"empty\" | \"error\" | \"data\" | \"initial\";\r\n\r\n\r\ntype TitleProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n containerClass?: string;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype SearchProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n background?: string;\r\n prefixIcon?: React.ReactNode;\r\n suffixIcon?: React.ReactNode;\r\n clearIcon?: React.ReactNode;\r\n backIcon?: React.ReactNode;\r\n prefixGap?: string;\r\n suffixGap?: string;\r\n padding?: Padding;\r\n autoFocus?: boolean;\r\n inputStyle?: React.CSSProperties;\r\n containerStyle?: React.CSSProperties;\r\n onChange?: (value: string) => void;\r\n onFocus?: () => void;\r\n onBlur?: () => void;\r\n};\r\n\r\ntype LoadingProps = {\r\n view: React.ReactNode;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype NoResultProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype ErrorProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype CancelButtonProps = {\r\n text?: string;\r\n view: React.ReactNode;\r\n position?: \"left\" | \"right\";\r\n style?: React.CSSProperties;\r\n onClick?: () => void;\r\n};\r\n\r\ntype LayoutProps = {\r\n gapBetweenHandleAndTitle?: string;\r\n gapBetweenTitleAndSearch?: string;\r\n gapBetweenSearchAndContent?: string;\r\n backgroundColor?: string;\r\n handleColor?: string;\r\n handleWidth?: string;\r\n fullScreenSearchBackground?: string;\r\n fullScreenSearchHeaderStyle?: React.CSSProperties;\r\n maxWidth?: string;\r\n};\r\n\r\ntype SelectionViewerProps = {\r\n id?: string;\r\n isOpen: boolean;\r\n backDrop?: boolean;\r\n onClose: () => void;\r\n titleProp: TitleProps;\r\n searchProp?: SearchProps;\r\n loadingProp?: LoadingProps;\r\n noResultProp?: NoResultProps;\r\n errorProp?: ErrorProps;\r\n cancelButton?: CancelButtonProps;\r\n layoutProp?: LayoutProps;\r\n childrenDirection?: \"vertical\" | \"horizontal\";\r\n children?: React.ReactNode;\r\n onPaginate?: () => boolean | Promise<boolean>;\r\n snapPoints?: SnapPoint[];\r\n initialSnap?: number;\r\n unmountOnClose?: boolean;\r\n zIndex?: number;\r\n /**\r\n * Accessible name for the sheet, announced when it opens.\r\n *\r\n * A modal with no name is announced simply as \"dialog\", which tells a screen-reader user that\r\n * something has taken over the screen and nothing at all about what.\r\n */\r\n ariaLabel?: string;\r\n maxHeight?: string;\r\n minHeight?: string;\r\n selectionState?: SelectionState;\r\n closeThreshold?: number;\r\n};\r\n\r\n// ==================== Styles ====================\r\nconst getStyles = (id: string) => `\r\n#${id} .selection-viewer-header {\r\n padding: 0px;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-drag-handle {\r\n height: 5px;\r\n border-radius: 3px;\r\n margin-top: 16px;\r\n}\r\n\r\n#${id} .selection-viewer-container {\r\n display: flex;\r\n align-items: flex-start;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-title {\r\n margin: 0px;\r\n font-size: 18px;\r\n font-weight: 600;\r\n padding: 0px 16px 0px 16px;\r\n word-break: break-word; /* break long words */\r\n white-space: normal; /* allow wrapping */\r\n}\r\n\r\n#${id} .selection-viewer-search {\r\n display: flex;\r\n align-items: center;\r\n margin: 16px 16px 4px 16px;\r\n border-radius: 12px;\r\n box-sizing: border-box;\r\n border: 1px solid rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n#${id} .selection-viewer-search-input {\r\n flex: 1;\r\n border: none;\r\n background: transparent;\r\n padding: 12px 8px;\r\n outline: none;\r\n font-size: 16px !important;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-content {\r\n overflow-y: auto;\r\n -webkit-overflow-scrolling: touch;\r\n flex: 1;\r\n min-height: 0;\r\n}\r\n\r\n#${id} .selection-viewer-content.vertical {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n#${id} .selection-viewer-content.horizontal {\r\n display: flex;\r\n flex-direction: row;\r\n gap: 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n}\r\n\r\n#${id} .selection-viewer-no-results,\r\n#${id} .selection-viewer-error,\r\n#${id} .selection-viewer-loading {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n min-height: 120px;\r\n}\r\n\r\n#${id} .selection-viewer-default-no-results {\r\n color: #666;\r\n font-size: 14px;\r\n}\r\n\r\n#${id} .selection-viewer-default-error {\r\n color: red;\r\n font-size: 14px;\r\n}\r\n\r\n/* Full screen search mode */\r\n#${id} .selection-viewer-fullscreen-search {\r\n// position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n z-index: 10;\r\n// padding-top: env(safe-area-inset-top);\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-right: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-left: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n/* React Modal Sheet overrides */\r\n#${id} .react-modal-sheet-container {\r\n max-width: 500px;\r\n margin: 0 auto;\r\n border-top-left-radius: 16px;\r\n border-top-right-radius: 16px;\r\n}\r\n\r\n#${id} .react-modal-sheet-backdrop {\r\n background-color: rgba(0, 0, 0, 0.5) !important;\r\n pointer-events: auto !important;\r\n}\r\n\r\n#${id} .react-modal-sheet-content {\r\n padding: 0 0px 0px 0px;\r\n height: 100%;\r\n}\r\n\r\n\r\n/* Mobile full-width behavior */\r\n@media (max-width: 500px) {\r\n #${id} .react-modal-sheet-container {\r\n max-width: 100%;\r\n border-radius: 0;\r\n }\r\n}\r\n\r\n/* Prevent iOS zooming */\r\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\r\n #${id} .selection-viewer-search-input {\r\n font-size: 16px !important;\r\n }\r\n}\r\n`;\r\n\r\n// ==================== Hook to inject CSS per instance ====================\r\nconst useInjectStyles = (id: string) => {\r\n useEffect(() => {\r\n const styleId = `selection-viewer-styles-${id}`;\r\n let styleTag = document.getElementById(styleId) as HTMLStyleElement | null;\r\n\r\n if (!styleTag) {\r\n styleTag = document.createElement(\"style\");\r\n styleTag.id = styleId;\r\n styleTag.innerHTML = getStyles(id);\r\n document.head.appendChild(styleTag);\r\n }\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (styleTag && document.head.contains(styleTag)) {\r\n document.head.removeChild(styleTag);\r\n }\r\n };\r\n }, [id]);\r\n};\r\n\r\n// ==================== Component ====================\r\n/**\r\n * Escape closes the viewer, and Tab stays inside it.\r\n *\r\n * The viewer covers the screen, so what is behind it is not available — but nothing said so to the\r\n * keyboard. Tab walked out of the option list into the page underneath, where a person was\r\n * operating controls they could not see, and Escape did nothing at all, which is the one key\r\n * everybody reaches for to get out of a picker.\r\n *\r\n * Deliberately a private copy rather than an import from a sibling package: every library here\r\n * stands alone, and a shared helper between two of them is a dependency the consumer did not ask\r\n * for. Takes the container's `id` rather than a ref, because the sheet element belongs to the\r\n * underlying modal-sheet component; looking it up when a key is pressed finds it however that\r\n * component chooses to mount it. Focusables are re-queried on every Tab, since the option list\r\n * changes as the consumer filters it and a list captured on open is a list of dead elements.\r\n */\r\nconst useModalKeys = (isOpen: boolean, onClose: () => void, containerId: string) => {\r\n useEffect(() => {\r\n if (!isOpen || typeof document === \"undefined\") return;\r\n\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n onClose();\r\n return;\r\n }\r\n if (e.key !== \"Tab\") return;\r\n\r\n const focusable = document.getElementById(containerId)?.querySelectorAll<HTMLElement>(\r\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]),' +\r\n ' textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\r\n );\r\n if (!focusable || focusable.length === 0) return;\r\n\r\n const first = focusable[0];\r\n const last = focusable[focusable.length - 1];\r\n\r\n if (e.shiftKey && document.activeElement === first) {\r\n e.preventDefault();\r\n last.focus();\r\n } else if (!e.shiftKey && document.activeElement === last) {\r\n e.preventDefault();\r\n first.focus();\r\n }\r\n };\r\n\r\n document.addEventListener(\"keydown\", onKeyDown);\r\n return () => document.removeEventListener(\"keydown\", onKeyDown);\r\n }, [isOpen, onClose, containerId]);\r\n};\r\n\r\nconst SelectionViewer: React.FC<SelectionViewerProps> = ({\r\n id: providedId,\r\n isOpen,\r\n backDrop = true,\r\n onClose,\r\n titleProp,\r\n searchProp,\r\n loadingProp,\r\n noResultProp,\r\n errorProp,\r\n cancelButton,\r\n layoutProp,\r\n childrenDirection = \"vertical\",\r\n children,\r\n onPaginate,\r\n snapPoints = [0, 1],\r\n initialSnap = 1,\r\n unmountOnClose = true,\r\n zIndex = 1000,\r\n ariaLabel,\r\n maxHeight = \"90dvh\",\r\n minHeight = \"65dvh\",\r\n selectionState: selectionStateProp = \"initial\",\r\n closeThreshold = 0.2,\r\n}) => {\r\n const [id] = useState(() => providedId || `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n const [searchValue, setSearchValue] = useState(\"\");\r\n const [isSearchFocused, setIsSearchFocused] = useState(false);\r\n const [keyboardHeight, setKeyboardHeight] = useState(0);\r\n const [inputKey, setInputKey] = useState(0);\r\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false);\r\n const isPaginating = useRef(false);\r\n const searchInputRef = useRef<HTMLInputElement>(null);\r\n const sheetRef = useRef<any>(null);\r\n const headerRef = useRef<HTMLDivElement>(null);\r\n\r\n useInjectStyles(id);\r\n // Escape closes the viewer and Tab stays inside it — see useModalKeys.\r\n useModalKeys(isOpen, onClose, id);\r\n\r\n // Descendant sections (a Column, or anything else) can report a cumulative state up through this —\r\n // starts empty, so a plain SelectionViewer with no Row/Column children behaves exactly as before.\r\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\r\n const reportAggregate = useCallback((reporterId: string, state: SelectionState) => {\r\n setReportedStates((prev) => {\r\n const next = new Map(prev);\r\n next.set(reporterId, state);\r\n return next;\r\n });\r\n }, []);\r\n const unreportAggregate = useCallback((reporterId: string) => {\r\n setReportedStates((prev) => {\r\n if (!prev.has(reporterId)) return prev;\r\n const next = new Map(prev);\r\n next.delete(reporterId);\r\n return next;\r\n });\r\n }, []);\r\n const aggregateReporterValue = useMemo(\r\n () => ({ report: reportAggregate, unreport: unreportAggregate }),\r\n [reportAggregate, unreportAggregate]\r\n );\r\n const reportedAggregate =\r\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : null;\r\n const isComposed = reportedAggregate !== null;\r\n\r\n // Precedence: an explicit `selectionState` prop always wins (matches today's exact behaviour for\r\n // any consumer not using Row/Column) -> then a reported Column aggregate, if one exists -> \"initial\".\r\n const selectionState =\r\n selectionStateProp !== \"initial\" ? selectionStateProp : reportedAggregate ?? \"initial\";\r\n\r\n // Track keyboard height\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || !window.visualViewport) return;\r\n\r\n const handleResize = () => {\r\n const vp = window.visualViewport!;\r\n const kbHeight = window.innerHeight - vp.height;\r\n setKeyboardHeight(kbHeight > 0 ? kbHeight : 0);\r\n };\r\n\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n window.visualViewport.addEventListener('scroll', handleResize);\r\n\r\n return () => {\r\n window.visualViewport?.removeEventListener('resize', handleResize);\r\n window.visualViewport?.removeEventListener('scroll', handleResize);\r\n };\r\n }, []);\r\n\r\n // Auto-focus on search\r\n useEffect(() => {\r\n if (!isOpen) {\r\n searchInputRef.current?.blur();\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n setShouldAutoFocus(false);\r\n return;\r\n }\r\n }, [isOpen, searchProp?.autoFocus]);\r\n\r\n const handleOpenEnd = useCallback(() => {\r\n if (searchProp?.autoFocus && searchInputRef.current) {\r\n setInputKey(prev => prev + 1);\r\n setShouldAutoFocus(true);\r\n searchInputRef.current.focus();\r\n searchInputRef.current.click();\r\n }\r\n }, [searchProp?.autoFocus]);\r\n\r\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const value = e.target.value;\r\n setSearchValue(value);\r\n searchProp?.onChange?.(value);\r\n };\r\n\r\n const handleSearchFocus = () => {\r\n setIsSearchFocused(true);\r\n searchProp?.onFocus?.();\r\n requestAnimationFrame(() => {\r\n searchInputRef.current?.focus();\r\n });\r\n };\r\n\r\n const handleSearchBlur = () => {\r\n searchProp?.onBlur?.();\r\n };\r\n\r\n const handleBackFromSearch = () => {\r\n setIsSearchFocused(false);\r\n if (searchInputRef.current) {\r\n searchInputRef.current.blur();\r\n }\r\n };\r\n\r\n const clearSearch = () => {\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n if (searchInputRef.current) {\r\n searchInputRef.current.focus();\r\n }\r\n };\r\n\r\n const handleScroll = useCallback(\r\n async (e: React.UIEvent<HTMLDivElement>) => {\r\n if (isPaginating.current || !onPaginate) return;\r\n\r\n const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;\r\n const isNearBottom = scrollHeight - scrollTop <= clientHeight * 1.2;\r\n\r\n if (isNearBottom) {\r\n isPaginating.current = true;\r\n const hasMore = await onPaginate();\r\n if (!hasMore) {\r\n isPaginating.current = false;\r\n } else {\r\n setTimeout(() => {\r\n isPaginating.current = false;\r\n }, 500);\r\n }\r\n }\r\n },\r\n [onPaginate]\r\n );\r\n\r\n if (!isOpen && unmountOnClose) return null;\r\n\r\n return (\r\n <SelectionViewerAggregateContext.Provider value={aggregateReporterValue}>\r\n <Sheet\r\n ref={sheetRef}\r\n isOpen={isOpen}\r\n onClose={onClose}\r\n detent=\"content\"\r\n style={{ zIndex }}\r\n maxHeight={maxHeight}\r\n onOpenEnd={handleOpenEnd}\r\n >\r\n <Sheet.Container\r\n id={id}\r\n // Announced as a modal dialog. Without this a screen reader reads the sheet as one more\r\n // region of the page and gives no indication that what is behind it is unavailable — and\r\n // an automated check for an open dialog finds nothing at all.\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-label={ariaLabel}\r\n style={{\r\n maxHeight: maxHeight,\r\n minHeight: isSearchFocused ? \"100dvh\" : minHeight,\r\n maxWidth: layoutProp?.maxWidth ?? '800px',\r\n margin: \"0 auto\",\r\n width: \"100%\",\r\n left: 0,\r\n right: 0,\r\n paddingBottom: \"calc(0px + env(safe-area-inset-bottom))\",\r\n background: isSearchFocused\r\n ? layoutProp?.fullScreenSearchBackground || layoutProp?.backgroundColor\r\n : layoutProp?.backgroundColor,\r\n borderTopLeftRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n borderTopRightRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n }}\r\n >\r\n {isSearchFocused ? (\r\n <Sheet.Header>\r\n <div\r\n className=\"selection-viewer-fullscreen-search\"\r\n style={layoutProp?.fullScreenSearchHeaderStyle}\r\n >\r\n <div className=\"selection-viewer-search\" style={{\r\n ...searchProp?.containerStyle,\r\n background: searchProp?.background,\r\n padding: searchProp?.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"16px\"\r\n }}>\r\n <button\r\n className=\"selection-viewer-search-back-button\"\r\n onClick={handleBackFromSearch}\r\n aria-label=\"Exit search mode\"\r\n >\r\n {searchProp?.backIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M15 18L9 12L15 6\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp?.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp?.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp?.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n >\r\n {searchProp?.clearIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </Sheet.Header>\r\n ) : (\r\n <Sheet.Header>\r\n <div className=\"selection-viewer-header\">\r\n {/* Cancel button left */}\r\n {cancelButton?.position === \"left\" && (\r\n <button\r\n style={{\r\n position: \"absolute\",\r\n left: \"0px\",\r\n top: \"8px\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Drag handle */}\r\n {!isSearchFocused && (\r\n <div\r\n className=\"selection-viewer-drag-handle\"\r\n style={{\r\n background: layoutProp?.handleColor || \"#ccc\",\r\n width: layoutProp?.handleWidth || \"40px\",\r\n marginBottom: layoutProp?.gapBetweenHandleAndTitle || \"12px\",\r\n }}\r\n />\r\n )}\r\n\r\n {/* Cancel button right */}\r\n {cancelButton?.position === \"right\" && (\r\n <button\r\n style={{\r\n position: \"absolute\",\r\n right: \"0px\",\r\n top: \"8px\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Title */}\r\n <div className={titleProp.containerClass || \"selection-viewer-container\"}>\r\n <h2\r\n id={`${id}-title`}\r\n className={titleProp.className || \"selection-viewer-title\"}\r\n style={{\r\n marginBottom: layoutProp?.gapBetweenTitleAndSearch || \"8px\",\r\n color: titleProp?.textColor || 'black',\r\n ...titleProp.style\r\n }}\r\n >\r\n {titleProp.text}\r\n </h2>\r\n </div>\r\n </div>\r\n\r\n {/* Search */}\r\n {searchProp && (\r\n <div\r\n className=\"selection-viewer-search\"\r\n style={{\r\n background: searchProp.background,\r\n padding: searchProp.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"8px 16px\",\r\n marginBottom: layoutProp?.gapBetweenSearchAndContent,\r\n ...searchProp.containerStyle\r\n }}\r\n >\r\n {searchProp.prefixIcon && (\r\n <span style={{ marginRight: searchProp.prefixGap || \"8px\" }}>\r\n {searchProp.prefixIcon}\r\n </span>\r\n )}\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n style={{ marginLeft: searchProp.suffixGap || \"8px\" }}\r\n >\r\n {searchProp.clearIcon || searchProp.suffixIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n {!searchValue && searchProp.suffixIcon && (\r\n <span style={{ marginLeft: searchProp.suffixGap || \"8px\" }}>\r\n {searchProp.suffixIcon}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n </Sheet.Header>\r\n )}\r\n\r\n <Sheet.Content>\r\n <div\r\n className={`selection-viewer-content ${childrenDirection}`}\r\n onScroll={onPaginate ? handleScroll : undefined}\r\n style={{\r\n paddingTop: isSearchFocused ? layoutProp?.gapBetweenSearchAndContent : '0',\r\n paddingBottom: keyboardHeight > 0\r\n ? `${keyboardHeight + 16}px`\r\n : '16px',\r\n }}\r\n >\r\n {/* Show children first, then loading at bottom */}\r\n {React.Children.count(children) > 0 ? (\r\n <>\r\n {children}\r\n {selectionState === \"loading\" && (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n )}\r\n {/* Composed mode: a Column/Row descendant reports its own state, which can only ever be\r\n \"empty\"/\"error\" here since the child count > 0 branch is unconditional on a literal\r\n <Column> being present. Layer the outer view alongside the (visually empty) children\r\n rather than replacing them — a Column/Row must stay mounted to keep reporting. */}\r\n {isComposed && selectionState === \"empty\" && (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n {isComposed && selectionState === \"error\" && (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </>\r\n ) : (selectionState === \"empty\" || (React.Children.count(children) <= 0 && (selectionState != \"loading\" && selectionState != \"error\"))) ? (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : selectionState === \"loading\" ? (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n ) : (selectionState === \"error\") ? (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : null}\r\n </div>\r\n </Sheet.Content>\r\n </Sheet.Container>\r\n <Sheet.Backdrop onTap={backDrop ? onClose : undefined} />\r\n </Sheet>\r\n </SelectionViewerAggregateContext.Provider>\r\n );\r\n};\r\n\r\n// ==================== Controller Hook ====================\r\ntype Operation = {\r\n open: () => void;\r\n close: () => void;\r\n toggle: () => void;\r\n setSelectionState: (val: SelectionState) => void;\r\n};\r\n\r\nconst useSelectionController = (initialSelectionState?: SelectionState): [\r\n string,\r\n Operation,\r\n boolean,\r\n SelectionState\r\n] => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [selectionState, setSelectionState] = useState(initialSelectionState || 'initial');\r\n const [selectionId] = useState(() => `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n\r\n const operations = useMemo<Operation>(() => ({\r\n open: () => setIsOpen(true),\r\n close: () => setIsOpen(false),\r\n toggle: () => setIsOpen((prev) => !prev),\r\n setSelectionState\r\n }), [setSelectionState]);\r\n\r\n return [selectionId, operations, isOpen, selectionState];\r\n};\r\n\r\nexport { SelectionViewer, useSelectionController, RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState };\r\nexport type {\r\n SelectionViewerProps,\r\n SelectionState,\r\n TitleProps,\r\n SearchProps,\r\n LoadingProps,\r\n NoResultProps,\r\n ErrorProps,\r\n CancelButtonProps,\r\n LayoutProps,\r\n Padding,\r\n SnapPoint,\r\n AggregateReporter,\r\n};\r\nexport default SelectionViewer;\r\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { RowAggregateContext } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type RowProps = {\n id?: string;\n /** Consumer-owned — SelectionViewer has never owned fetch/filter state, so unlike\n * search-viewer's Row this isn't internally computed. Mirrors how `selectionState`\n * is already a prop on SelectionViewer itself today. Defaults to \"data\": if you\n * render children without wiring this, we assume what you rendered IS the data. */\n state?: SelectionState;\n /** Called when this Row is scrolled horizontally near its end. Return (or resolve to)\n * `true` if more data may follow (keeps the pagination trigger armed), `false` once\n * there's nothing left to fetch — mirrors SelectionViewer's own `onPaginate` contract. */\n onPaginate?: () => boolean | Promise<boolean>;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A horizontally-scrolling, independently-paginating section — the Row/Column\n * equivalent for `SelectionViewer`. No shared code with `@academix-admin/search-viewer`'s\n * Row (Library Charter: packages stay mutually independent) — this one has no\n * query/debounce/cache engine of its own since `SelectionViewer` never had one either;\n * the consumer owns fetching/filtering and just tells this Row what `state` it's in. */\nfunction Row({ id: providedId, state = \"data\", onPaginate, className, style, children }: RowProps) {\n const aggregateReporter = React.useContext(RowAggregateContext);\n const [rowId] = useState(() => providedId || `row-${Math.random().toString(36).substring(2, 11)}`);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const isPaginating = useRef(false);\n\n const handleScroll = useCallback(async () => {\n const el = containerRef.current;\n if (!el || isPaginating.current || !onPaginate) return;\n\n // Same \"near the end\" threshold as SelectionViewer's own vertical pagination trigger, adapted\n // to horizontal scroll metrics since a Row scrolls sideways.\n const { scrollLeft, scrollWidth, clientWidth } = el;\n if (scrollWidth - scrollLeft > clientWidth * 1.2) return;\n\n isPaginating.current = true;\n const hasMore = await onPaginate();\n if (!hasMore) {\n isPaginating.current = false;\n } else {\n setTimeout(() => {\n isPaginating.current = false;\n }, 500);\n }\n }, [onPaginate]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el || !onPaginate) return;\n el.addEventListener(\"scroll\", handleScroll);\n return () => el.removeEventListener(\"scroll\", handleScroll);\n }, [handleScroll, onPaginate]);\n\n useEffect(() => {\n aggregateReporter?.report(rowId, state);\n return () => aggregateReporter?.unreport(rowId);\n }, [aggregateReporter, rowId, state]);\n\n return (\n <div\n ref={containerRef}\n className={className ? `selection-viewer-row ${className}` : \"selection-viewer-row\"}\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n gap: \"8px\",\n overflowX: \"auto\",\n overflowY: \"hidden\",\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n\nRow.displayName = \"Row\";\n\nexport { Row };\n","import React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type ColumnProps = {\n id?: string;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A vertical arrangement of `Row`s (or other content) — the explicit, composable\n * equivalent of today's flat `children` list. Its default layout is deliberately\n * identical to the existing `.selection-viewer-content.vertical` rendering\n * (`flex-direction: column, gap: 8px`), so today's flat usage is, unchanged, \"an\n * implicit Column with no Rows.\"\n *\n * Provides the `RowAggregateContext` its `Row` children report into, computes ONE\n * cumulative state from everything reported, and is itself a reporter one level up:\n * nested inside another `Column` it reports through that Column's `RowAggregateContext`\n * (behaving like a Row); at the top level it reports through `SelectionViewerAggregateContext`,\n * which `SelectionViewer` provides — this drives the outer sheet's loading/empty/error\n * views automatically with zero manual wiring, and lets Columns nest arbitrarily deep. */\nfunction Column({ id: providedId, className, style, children }: ColumnProps) {\n const [columnId] = useState(\n () => providedId || `column-${Math.random().toString(36).substring(2, 11)}`\n );\n\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\n const report = useCallback((id: string, state: SelectionState) => {\n setReportedStates((prev) => {\n const next = new Map(prev);\n next.set(id, state);\n return next;\n });\n }, []);\n const unreport = useCallback((id: string) => {\n setReportedStates((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n const rowAggregateValue = useMemo(() => ({ report, unreport }), [report, unreport]);\n\n const aggregateState =\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : \"initial\";\n\n const parentRowAggregate = React.useContext(RowAggregateContext);\n const selectionViewerAggregate = React.useContext(SelectionViewerAggregateContext);\n const upstreamReporter = parentRowAggregate ?? selectionViewerAggregate;\n\n useEffect(() => {\n if (!upstreamReporter) return;\n upstreamReporter.report(columnId, aggregateState);\n return () => upstreamReporter.unreport(columnId);\n }, [upstreamReporter, columnId, aggregateState]);\n\n return (\n <RowAggregateContext.Provider value={rowAggregateValue}>\n <div\n className={className ? `selection-viewer-column ${className}` : \"selection-viewer-column\"}\n style={{ display: \"flex\", flexDirection: \"column\", gap: \"8px\", ...style }}\n >\n {children}\n </div>\n </RowAggregateContext.Provider>\n );\n}\n\nColumn.displayName = \"Column\";\n\nexport { Column };\n"]}
1
+ {"version":3,"sources":["../src/SelectionViewer.tsx","../src/Row.tsx","../src/Column.tsx"],"names":["React","useEffect","useState","useRef","useCallback","useMemo","jsx","jsxs","Sheet","Fragment"],"mappings":"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","file":"index.cjs","sourcesContent":["import React, { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\r\nimport { Sheet } from \"@academix-admin/modal-sheet\";\r\n\r\n// ==================== Aggregation (Row/Column) ====================\r\n// Independent from @academix-admin/search-viewer's equivalent (Library Charter: packages stay\r\n// mutually independent) — same shape, duplicated intentionally rather than shared.\r\n\r\ntype AggregateReporter = {\r\n report: (id: string, state: SelectionState) => void;\r\n unreport: (id: string) => void;\r\n};\r\n\r\n/** A `Row` reports its own `state` into the nearest `Column` through this. */\r\nconst RowAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\n/** `Column` reports its own aggregated state up through this — `SelectionViewer` provides it and\r\n * merges whatever's reported into its own selectionState resolution, with zero extra wiring. */\r\nconst SelectionViewerAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\nfunction computeAggregateState(states: SelectionState[]): SelectionState {\r\n if (states.length === 0) return \"initial\";\r\n if (states.some((s) => s === \"data\")) return \"data\";\r\n if (states.some((s) => s === \"loading\")) return \"loading\";\r\n if (states.every((s) => s === \"empty\")) return \"empty\";\r\n if (states.some((s) => s === \"error\")) return \"error\";\r\n return \"initial\";\r\n}\r\n\r\n// ==================== Types ====================\r\ntype Padding = {\r\n l: string;\r\n r: string;\r\n t: string;\r\n b: string;\r\n};\r\n\r\ntype SnapPoint = number;\r\n\r\ntype SelectionState = \"loading\" | \"empty\" | \"error\" | \"data\" | \"initial\";\r\n\r\n\r\ntype TitleProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n containerClass?: string;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype SearchProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n background?: string;\r\n prefixIcon?: React.ReactNode;\r\n suffixIcon?: React.ReactNode;\r\n clearIcon?: React.ReactNode;\r\n backIcon?: React.ReactNode;\r\n prefixGap?: string;\r\n suffixGap?: string;\r\n padding?: Padding;\r\n autoFocus?: boolean;\r\n inputStyle?: React.CSSProperties;\r\n containerStyle?: React.CSSProperties;\r\n onChange?: (value: string) => void;\r\n onFocus?: () => void;\r\n onBlur?: () => void;\r\n};\r\n\r\ntype LoadingProps = {\r\n view: React.ReactNode;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype NoResultProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype ErrorProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype CancelButtonProps = {\r\n text?: string;\r\n view: React.ReactNode;\r\n position?: \"left\" | \"right\";\r\n style?: React.CSSProperties;\r\n onClick?: () => void;\r\n /**\r\n * What a screen reader calls it. Defaults to \"Close\".\r\n *\r\n * A button whose only content is an icon has no accessible name at all, so it was announced as\r\n * just \"button\" — the one control that dismisses the sheet, and nothing said so.\r\n */\r\n ariaLabel?: string;\r\n};\r\n\r\ntype LayoutProps = {\r\n gapBetweenHandleAndTitle?: string;\r\n gapBetweenTitleAndSearch?: string;\r\n gapBetweenSearchAndContent?: string;\r\n /**\r\n * How far the rows are set in from the sides. Defaults to `16px`, matching the search box.\r\n *\r\n * The content had no inset while everything above it had 16px, so a list ran flush into the\r\n * sides of the screen under a search box that did not. Pass `0px` for rows that should reach\r\n * the edges.\r\n */\r\n contentPadding?: string;\r\n backgroundColor?: string;\r\n handleColor?: string;\r\n handleWidth?: string;\r\n fullScreenSearchBackground?: string;\r\n fullScreenSearchHeaderStyle?: React.CSSProperties;\r\n maxWidth?: string;\r\n};\r\n\r\ntype SelectionViewerProps = {\r\n id?: string;\r\n isOpen: boolean;\r\n backDrop?: boolean;\r\n onClose: () => void;\r\n titleProp: TitleProps;\r\n searchProp?: SearchProps;\r\n loadingProp?: LoadingProps;\r\n noResultProp?: NoResultProps;\r\n errorProp?: ErrorProps;\r\n cancelButton?: CancelButtonProps;\r\n layoutProp?: LayoutProps;\r\n childrenDirection?: \"vertical\" | \"horizontal\";\r\n children?: React.ReactNode;\r\n onPaginate?: () => boolean | Promise<boolean>;\r\n snapPoints?: SnapPoint[];\r\n initialSnap?: number;\r\n unmountOnClose?: boolean;\r\n zIndex?: number;\r\n /**\r\n * Accessible name for the sheet, announced when it opens.\r\n *\r\n * A modal with no name is announced simply as \"dialog\", which tells a screen-reader user that\r\n * something has taken over the screen and nothing at all about what.\r\n */\r\n ariaLabel?: string;\r\n maxHeight?: string;\r\n minHeight?: string;\r\n selectionState?: SelectionState;\r\n closeThreshold?: number;\r\n};\r\n\r\n// ==================== Styles ====================\r\nconst getStyles = (id: string) => `\r\n#${id} .selection-viewer-header {\r\n padding: 0px;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n/*\r\n * The close button, with a target a thumb can find.\r\n *\r\n * It sat at right: 0, top: 8 with no padding at all, so the icon was flush against the sheet's\r\n * edge and the only thing that could be tapped was the glyph itself — a target well under half\r\n * what a finger needs, in the corner of the screen where a thumb is least accurate. Inset by 4px\r\n * and padded out to 44px square, so the icon still reads as sitting in the corner while the\r\n * hittable area reaches the edges.\r\n *\r\n * The cancelButton.style prop is still spread last at the call site, so a consumer that was\r\n * overriding any of this keeps overriding it. (No backticks in here: this whole block lives\r\n * inside a template literal, and one would end the string.)\r\n */\r\n#${id} .selection-viewer-cancel {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 44px;\r\n min-height: 44px;\r\n padding: 10px;\r\n border: none;\r\n background-color: transparent;\r\n color: inherit;\r\n cursor: pointer;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n#${id} .selection-viewer-drag-handle {\r\n height: 5px;\r\n border-radius: 3px;\r\n margin-top: 16px;\r\n}\r\n\r\n#${id} .selection-viewer-container {\r\n display: flex;\r\n align-items: flex-start;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-title {\r\n margin: 0px;\r\n font-size: 18px;\r\n font-weight: 600;\r\n padding: 0px 16px 0px 16px;\r\n word-break: break-word; /* break long words */\r\n white-space: normal; /* allow wrapping */\r\n}\r\n\r\n#${id} .selection-viewer-search {\r\n display: flex;\r\n align-items: center;\r\n margin: 16px 16px 4px 16px;\r\n border-radius: 12px;\r\n box-sizing: border-box;\r\n border: 1px solid rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n#${id} .selection-viewer-search-input {\r\n flex: 1;\r\n border: none;\r\n background: transparent;\r\n padding: 12px 8px;\r\n outline: none;\r\n font-size: 16px !important;\r\n width: 100%;\r\n}\r\n\r\n/*\r\n * The rows, set in from the edges like everything else in the sheet.\r\n *\r\n * The title and the search box have carried a 16px margin from the start; the content had none, so\r\n * a list of cards ran flush into the sides of the screen while the search box above it did not.\r\n * The layoutProp.contentPadding option overrides it for a consumer that wants its rows edge to\r\n * edge. (No backticks: this block is inside a template literal.)\r\n */\r\n#${id} .selection-viewer-content {\r\n overflow-y: auto;\r\n -webkit-overflow-scrolling: touch;\r\n flex: 1;\r\n min-height: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#${id} .selection-viewer-content.vertical {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n#${id} .selection-viewer-content.horizontal {\r\n display: flex;\r\n flex-direction: row;\r\n gap: 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n}\r\n\r\n#${id} .selection-viewer-no-results,\r\n#${id} .selection-viewer-error,\r\n#${id} .selection-viewer-loading {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n min-height: 120px;\r\n}\r\n\r\n#${id} .selection-viewer-default-no-results {\r\n color: #666;\r\n font-size: 14px;\r\n}\r\n\r\n#${id} .selection-viewer-default-error {\r\n color: red;\r\n font-size: 14px;\r\n}\r\n\r\n/* Full screen search mode */\r\n#${id} .selection-viewer-fullscreen-search {\r\n// position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n z-index: 10;\r\n// padding-top: env(safe-area-inset-top);\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-right: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-left: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n/* React Modal Sheet overrides */\r\n#${id} .react-modal-sheet-container {\r\n max-width: 500px;\r\n margin: 0 auto;\r\n border-top-left-radius: 16px;\r\n border-top-right-radius: 16px;\r\n}\r\n\r\n#${id} .react-modal-sheet-backdrop {\r\n background-color: rgba(0, 0, 0, 0.5) !important;\r\n pointer-events: auto !important;\r\n}\r\n\r\n#${id} .react-modal-sheet-content {\r\n padding: 0 0px 0px 0px;\r\n height: 100%;\r\n}\r\n\r\n\r\n/* Mobile full-width behavior */\r\n@media (max-width: 500px) {\r\n #${id} .react-modal-sheet-container {\r\n max-width: 100%;\r\n border-radius: 0;\r\n }\r\n}\r\n\r\n/* Prevent iOS zooming */\r\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\r\n #${id} .selection-viewer-search-input {\r\n font-size: 16px !important;\r\n }\r\n}\r\n`;\r\n\r\n// ==================== Hook to inject CSS per instance ====================\r\nconst useInjectStyles = (id: string) => {\r\n useEffect(() => {\r\n const styleId = `selection-viewer-styles-${id}`;\r\n let styleTag = document.getElementById(styleId) as HTMLStyleElement | null;\r\n\r\n if (!styleTag) {\r\n styleTag = document.createElement(\"style\");\r\n styleTag.id = styleId;\r\n styleTag.innerHTML = getStyles(id);\r\n document.head.appendChild(styleTag);\r\n }\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (styleTag && document.head.contains(styleTag)) {\r\n document.head.removeChild(styleTag);\r\n }\r\n };\r\n }, [id]);\r\n};\r\n\r\n// ==================== Component ====================\r\n/**\r\n * Escape closes the viewer, and Tab stays inside it.\r\n *\r\n * The viewer covers the screen, so what is behind it is not available — but nothing said so to the\r\n * keyboard. Tab walked out of the option list into the page underneath, where a person was\r\n * operating controls they could not see, and Escape did nothing at all, which is the one key\r\n * everybody reaches for to get out of a picker.\r\n *\r\n * Deliberately a private copy rather than an import from a sibling package: every library here\r\n * stands alone, and a shared helper between two of them is a dependency the consumer did not ask\r\n * for. Takes the container's `id` rather than a ref, because the sheet element belongs to the\r\n * underlying modal-sheet component; looking it up when a key is pressed finds it however that\r\n * component chooses to mount it. Focusables are re-queried on every Tab, since the option list\r\n * changes as the consumer filters it and a list captured on open is a list of dead elements.\r\n */\r\nconst useModalKeys = (isOpen: boolean, onClose: () => void, containerId: string) => {\r\n useEffect(() => {\r\n if (!isOpen || typeof document === \"undefined\") return;\r\n\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n onClose();\r\n return;\r\n }\r\n if (e.key !== \"Tab\") return;\r\n\r\n const focusable = document.getElementById(containerId)?.querySelectorAll<HTMLElement>(\r\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]),' +\r\n ' textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\r\n );\r\n if (!focusable || focusable.length === 0) return;\r\n\r\n const first = focusable[0];\r\n const last = focusable[focusable.length - 1];\r\n\r\n if (e.shiftKey && document.activeElement === first) {\r\n e.preventDefault();\r\n last.focus();\r\n } else if (!e.shiftKey && document.activeElement === last) {\r\n e.preventDefault();\r\n first.focus();\r\n }\r\n };\r\n\r\n document.addEventListener(\"keydown\", onKeyDown);\r\n return () => document.removeEventListener(\"keydown\", onKeyDown);\r\n }, [isOpen, onClose, containerId]);\r\n};\r\n\r\nconst SelectionViewer: React.FC<SelectionViewerProps> = ({\r\n id: providedId,\r\n isOpen,\r\n backDrop = true,\r\n onClose,\r\n titleProp,\r\n searchProp,\r\n loadingProp,\r\n noResultProp,\r\n errorProp,\r\n cancelButton,\r\n layoutProp,\r\n childrenDirection = \"vertical\",\r\n children,\r\n onPaginate,\r\n snapPoints = [0, 1],\r\n initialSnap = 1,\r\n unmountOnClose = true,\r\n zIndex = 1000,\r\n ariaLabel,\r\n maxHeight = \"90dvh\",\r\n minHeight = \"65dvh\",\r\n selectionState: selectionStateProp = \"initial\",\r\n closeThreshold = 0.2,\r\n}) => {\r\n const [id] = useState(() => providedId || `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n const [searchValue, setSearchValue] = useState(\"\");\r\n const [isSearchFocused, setIsSearchFocused] = useState(false);\r\n const [keyboardHeight, setKeyboardHeight] = useState(0);\r\n const [inputKey, setInputKey] = useState(0);\r\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false);\r\n const isPaginating = useRef(false);\r\n const searchInputRef = useRef<HTMLInputElement>(null);\r\n const sheetRef = useRef<any>(null);\r\n const headerRef = useRef<HTMLDivElement>(null);\r\n\r\n useInjectStyles(id);\r\n // Escape closes the viewer and Tab stays inside it — see useModalKeys.\r\n useModalKeys(isOpen, onClose, id);\r\n\r\n // Descendant sections (a Column, or anything else) can report a cumulative state up through this —\r\n // starts empty, so a plain SelectionViewer with no Row/Column children behaves exactly as before.\r\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\r\n const reportAggregate = useCallback((reporterId: string, state: SelectionState) => {\r\n setReportedStates((prev) => {\r\n const next = new Map(prev);\r\n next.set(reporterId, state);\r\n return next;\r\n });\r\n }, []);\r\n const unreportAggregate = useCallback((reporterId: string) => {\r\n setReportedStates((prev) => {\r\n if (!prev.has(reporterId)) return prev;\r\n const next = new Map(prev);\r\n next.delete(reporterId);\r\n return next;\r\n });\r\n }, []);\r\n const aggregateReporterValue = useMemo(\r\n () => ({ report: reportAggregate, unreport: unreportAggregate }),\r\n [reportAggregate, unreportAggregate]\r\n );\r\n const reportedAggregate =\r\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : null;\r\n const isComposed = reportedAggregate !== null;\r\n\r\n // Precedence: an explicit `selectionState` prop always wins (matches today's exact behaviour for\r\n // any consumer not using Row/Column) -> then a reported Column aggregate, if one exists -> \"initial\".\r\n const selectionState =\r\n selectionStateProp !== \"initial\" ? selectionStateProp : reportedAggregate ?? \"initial\";\r\n\r\n // Track keyboard height\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || !window.visualViewport) return;\r\n\r\n const handleResize = () => {\r\n const vp = window.visualViewport!;\r\n const kbHeight = window.innerHeight - vp.height;\r\n setKeyboardHeight(kbHeight > 0 ? kbHeight : 0);\r\n };\r\n\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n window.visualViewport.addEventListener('scroll', handleResize);\r\n\r\n return () => {\r\n window.visualViewport?.removeEventListener('resize', handleResize);\r\n window.visualViewport?.removeEventListener('scroll', handleResize);\r\n };\r\n }, []);\r\n\r\n // Auto-focus on search\r\n useEffect(() => {\r\n if (!isOpen) {\r\n searchInputRef.current?.blur();\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n setShouldAutoFocus(false);\r\n return;\r\n }\r\n }, [isOpen, searchProp?.autoFocus]);\r\n\r\n const handleOpenEnd = useCallback(() => {\r\n if (searchProp?.autoFocus && searchInputRef.current) {\r\n setInputKey(prev => prev + 1);\r\n setShouldAutoFocus(true);\r\n searchInputRef.current.focus();\r\n searchInputRef.current.click();\r\n }\r\n }, [searchProp?.autoFocus]);\r\n\r\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const value = e.target.value;\r\n setSearchValue(value);\r\n searchProp?.onChange?.(value);\r\n };\r\n\r\n const handleSearchFocus = () => {\r\n setIsSearchFocused(true);\r\n searchProp?.onFocus?.();\r\n requestAnimationFrame(() => {\r\n searchInputRef.current?.focus();\r\n });\r\n };\r\n\r\n const handleSearchBlur = () => {\r\n searchProp?.onBlur?.();\r\n };\r\n\r\n const handleBackFromSearch = () => {\r\n setIsSearchFocused(false);\r\n if (searchInputRef.current) {\r\n searchInputRef.current.blur();\r\n }\r\n };\r\n\r\n const clearSearch = () => {\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n if (searchInputRef.current) {\r\n searchInputRef.current.focus();\r\n }\r\n };\r\n\r\n const handleScroll = useCallback(\r\n async (e: React.UIEvent<HTMLDivElement>) => {\r\n if (isPaginating.current || !onPaginate) return;\r\n\r\n const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;\r\n const isNearBottom = scrollHeight - scrollTop <= clientHeight * 1.2;\r\n\r\n if (isNearBottom) {\r\n isPaginating.current = true;\r\n const hasMore = await onPaginate();\r\n if (!hasMore) {\r\n isPaginating.current = false;\r\n } else {\r\n setTimeout(() => {\r\n isPaginating.current = false;\r\n }, 500);\r\n }\r\n }\r\n },\r\n [onPaginate]\r\n );\r\n\r\n if (!isOpen && unmountOnClose) return null;\r\n\r\n return (\r\n <SelectionViewerAggregateContext.Provider value={aggregateReporterValue}>\r\n <Sheet\r\n ref={sheetRef}\r\n isOpen={isOpen}\r\n onClose={onClose}\r\n detent=\"content\"\r\n style={{ zIndex }}\r\n maxHeight={maxHeight}\r\n onOpenEnd={handleOpenEnd}\r\n >\r\n <Sheet.Container\r\n id={id}\r\n // Announced as a modal dialog. Without this a screen reader reads the sheet as one more\r\n // region of the page and gives no indication that what is behind it is unavailable — and\r\n // an automated check for an open dialog finds nothing at all.\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-label={ariaLabel}\r\n style={{\r\n maxHeight: maxHeight,\r\n minHeight: isSearchFocused ? \"100dvh\" : minHeight,\r\n maxWidth: layoutProp?.maxWidth ?? '800px',\r\n margin: \"0 auto\",\r\n width: \"100%\",\r\n left: 0,\r\n right: 0,\r\n paddingBottom: \"calc(0px + env(safe-area-inset-bottom))\",\r\n background: isSearchFocused\r\n ? layoutProp?.fullScreenSearchBackground || layoutProp?.backgroundColor\r\n : layoutProp?.backgroundColor,\r\n borderTopLeftRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n borderTopRightRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n }}\r\n >\r\n {isSearchFocused ? (\r\n <Sheet.Header>\r\n <div\r\n className=\"selection-viewer-fullscreen-search\"\r\n style={layoutProp?.fullScreenSearchHeaderStyle}\r\n >\r\n <div className=\"selection-viewer-search\" style={{\r\n ...searchProp?.containerStyle,\r\n background: searchProp?.background,\r\n padding: searchProp?.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"16px\"\r\n }}>\r\n <button\r\n className=\"selection-viewer-search-back-button\"\r\n onClick={handleBackFromSearch}\r\n aria-label=\"Exit search mode\"\r\n >\r\n {searchProp?.backIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M15 18L9 12L15 6\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp?.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp?.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp?.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n >\r\n {searchProp?.clearIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </Sheet.Header>\r\n ) : (\r\n <Sheet.Header>\r\n <div className=\"selection-viewer-header\">\r\n {/* Cancel button left */}\r\n {cancelButton?.position === \"left\" && (\r\n <button\r\n aria-label={cancelButton.ariaLabel || \"Close\"}\r\n className=\"selection-viewer-cancel\"\r\n style={{\r\n position: \"absolute\",\r\n left: \"4px\",\r\n top: \"4px\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Drag handle */}\r\n {!isSearchFocused && (\r\n <div\r\n className=\"selection-viewer-drag-handle\"\r\n style={{\r\n background: layoutProp?.handleColor || \"#ccc\",\r\n width: layoutProp?.handleWidth || \"40px\",\r\n marginBottom: layoutProp?.gapBetweenHandleAndTitle || \"12px\",\r\n }}\r\n />\r\n )}\r\n\r\n {/* Cancel button right */}\r\n {cancelButton?.position === \"right\" && (\r\n <button\r\n aria-label={cancelButton.ariaLabel || \"Close\"}\r\n className=\"selection-viewer-cancel\"\r\n style={{\r\n position: \"absolute\",\r\n right: \"4px\",\r\n top: \"4px\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Title */}\r\n <div className={titleProp.containerClass || \"selection-viewer-container\"}>\r\n <h2\r\n id={`${id}-title`}\r\n className={titleProp.className || \"selection-viewer-title\"}\r\n style={{\r\n marginBottom: layoutProp?.gapBetweenTitleAndSearch || \"8px\",\r\n color: titleProp?.textColor || 'black',\r\n ...titleProp.style\r\n }}\r\n >\r\n {titleProp.text}\r\n </h2>\r\n </div>\r\n </div>\r\n\r\n {/* Search */}\r\n {searchProp && (\r\n <div\r\n className=\"selection-viewer-search\"\r\n style={{\r\n background: searchProp.background,\r\n padding: searchProp.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"8px 16px\",\r\n marginBottom: layoutProp?.gapBetweenSearchAndContent,\r\n ...searchProp.containerStyle\r\n }}\r\n >\r\n {searchProp.prefixIcon && (\r\n <span style={{ marginRight: searchProp.prefixGap || \"8px\" }}>\r\n {searchProp.prefixIcon}\r\n </span>\r\n )}\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n style={{ marginLeft: searchProp.suffixGap || \"8px\" }}\r\n >\r\n {searchProp.clearIcon || searchProp.suffixIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n {!searchValue && searchProp.suffixIcon && (\r\n <span style={{ marginLeft: searchProp.suffixGap || \"8px\" }}>\r\n {searchProp.suffixIcon}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n </Sheet.Header>\r\n )}\r\n\r\n <Sheet.Content>\r\n <div\r\n className={`selection-viewer-content ${childrenDirection}`}\r\n onScroll={onPaginate ? handleScroll : undefined}\r\n style={{\r\n paddingTop: isSearchFocused ? layoutProp?.gapBetweenSearchAndContent : '0',\r\n paddingBottom: keyboardHeight > 0\r\n ? `${keyboardHeight + 16}px`\r\n : '16px',\r\n /*\r\n * Set in from the edges, like everything else in the sheet.\r\n *\r\n * The title and the search box have carried 16px from the start and the content had\r\n * none, so a list of rows ran flush into the sides of the screen under a search box\r\n * that did not. Overridable for rows that genuinely want the full width.\r\n */\r\n paddingLeft: layoutProp?.contentPadding ?? '16px',\r\n paddingRight: layoutProp?.contentPadding ?? '16px',\r\n }}\r\n >\r\n {/* Show children first, then loading at bottom */}\r\n {React.Children.count(children) > 0 ? (\r\n <>\r\n {children}\r\n {selectionState === \"loading\" && (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n )}\r\n {/*\r\n Shown ALONGSIDE the children, not instead of them.\r\n\r\n This was guarded on composed mode — a Column/Row descendant reporting its own\r\n state — on the reasoning that only a composed sheet can have children and be\r\n empty at the same time. That is not true of the commonest arrangement there is:\r\n a consumer that wraps its rows in a single container. `React.Children.count` is\r\n then 1 whether the container holds fifty rows or none, so the empty branch below\r\n never ran and the sheet showed a blank white screen — at the exact moment\r\n somebody had searched for something that is not there, which is when the empty\r\n state is the only useful thing on screen.\r\n\r\n Layered rather than substituted, for the reason the composed case already had:\r\n a child that reports its own state must stay mounted to go on reporting. A\r\n consumer whose `selectionState` says \"empty\" is asserting there is nothing to\r\n show, so drawing its own view beside visually-empty children is what it asked\r\n for.\r\n */}\r\n {selectionState === \"empty\" && (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n {selectionState === \"error\" && (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </>\r\n ) : (selectionState === \"empty\" || (React.Children.count(children) <= 0 && (selectionState != \"loading\" && selectionState != \"error\"))) ? (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : selectionState === \"loading\" ? (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n ) : (selectionState === \"error\") ? (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : null}\r\n </div>\r\n </Sheet.Content>\r\n </Sheet.Container>\r\n <Sheet.Backdrop onTap={backDrop ? onClose : undefined} />\r\n </Sheet>\r\n </SelectionViewerAggregateContext.Provider>\r\n );\r\n};\r\n\r\n// ==================== Controller Hook ====================\r\ntype Operation = {\r\n open: () => void;\r\n close: () => void;\r\n toggle: () => void;\r\n setSelectionState: (val: SelectionState) => void;\r\n};\r\n\r\nconst useSelectionController = (initialSelectionState?: SelectionState): [\r\n string,\r\n Operation,\r\n boolean,\r\n SelectionState\r\n] => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [selectionState, setSelectionState] = useState(initialSelectionState || 'initial');\r\n const [selectionId] = useState(() => `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n\r\n const operations = useMemo<Operation>(() => ({\r\n open: () => setIsOpen(true),\r\n close: () => setIsOpen(false),\r\n toggle: () => setIsOpen((prev) => !prev),\r\n setSelectionState\r\n }), [setSelectionState]);\r\n\r\n return [selectionId, operations, isOpen, selectionState];\r\n};\r\n\r\nexport { SelectionViewer, useSelectionController, RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState };\r\nexport type {\r\n SelectionViewerProps,\r\n SelectionState,\r\n TitleProps,\r\n SearchProps,\r\n LoadingProps,\r\n NoResultProps,\r\n ErrorProps,\r\n CancelButtonProps,\r\n LayoutProps,\r\n Padding,\r\n SnapPoint,\r\n AggregateReporter,\r\n};\r\nexport default SelectionViewer;\r\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { RowAggregateContext } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type RowProps = {\n id?: string;\n /** Consumer-owned — SelectionViewer has never owned fetch/filter state, so unlike\n * search-viewer's Row this isn't internally computed. Mirrors how `selectionState`\n * is already a prop on SelectionViewer itself today. Defaults to \"data\": if you\n * render children without wiring this, we assume what you rendered IS the data. */\n state?: SelectionState;\n /** Called when this Row is scrolled horizontally near its end. Return (or resolve to)\n * `true` if more data may follow (keeps the pagination trigger armed), `false` once\n * there's nothing left to fetch — mirrors SelectionViewer's own `onPaginate` contract. */\n onPaginate?: () => boolean | Promise<boolean>;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A horizontally-scrolling, independently-paginating section — the Row/Column\n * equivalent for `SelectionViewer`. No shared code with `@academix-admin/search-viewer`'s\n * Row (Library Charter: packages stay mutually independent) — this one has no\n * query/debounce/cache engine of its own since `SelectionViewer` never had one either;\n * the consumer owns fetching/filtering and just tells this Row what `state` it's in. */\nfunction Row({ id: providedId, state = \"data\", onPaginate, className, style, children }: RowProps) {\n const aggregateReporter = React.useContext(RowAggregateContext);\n const [rowId] = useState(() => providedId || `row-${Math.random().toString(36).substring(2, 11)}`);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const isPaginating = useRef(false);\n\n const handleScroll = useCallback(async () => {\n const el = containerRef.current;\n if (!el || isPaginating.current || !onPaginate) return;\n\n // Same \"near the end\" threshold as SelectionViewer's own vertical pagination trigger, adapted\n // to horizontal scroll metrics since a Row scrolls sideways.\n const { scrollLeft, scrollWidth, clientWidth } = el;\n if (scrollWidth - scrollLeft > clientWidth * 1.2) return;\n\n isPaginating.current = true;\n const hasMore = await onPaginate();\n if (!hasMore) {\n isPaginating.current = false;\n } else {\n setTimeout(() => {\n isPaginating.current = false;\n }, 500);\n }\n }, [onPaginate]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el || !onPaginate) return;\n el.addEventListener(\"scroll\", handleScroll);\n return () => el.removeEventListener(\"scroll\", handleScroll);\n }, [handleScroll, onPaginate]);\n\n useEffect(() => {\n aggregateReporter?.report(rowId, state);\n return () => aggregateReporter?.unreport(rowId);\n }, [aggregateReporter, rowId, state]);\n\n return (\n <div\n ref={containerRef}\n className={className ? `selection-viewer-row ${className}` : \"selection-viewer-row\"}\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n gap: \"8px\",\n overflowX: \"auto\",\n overflowY: \"hidden\",\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n\nRow.displayName = \"Row\";\n\nexport { Row };\n","import React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type ColumnProps = {\n id?: string;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A vertical arrangement of `Row`s (or other content) — the explicit, composable\n * equivalent of today's flat `children` list. Its default layout is deliberately\n * identical to the existing `.selection-viewer-content.vertical` rendering\n * (`flex-direction: column, gap: 8px`), so today's flat usage is, unchanged, \"an\n * implicit Column with no Rows.\"\n *\n * Provides the `RowAggregateContext` its `Row` children report into, computes ONE\n * cumulative state from everything reported, and is itself a reporter one level up:\n * nested inside another `Column` it reports through that Column's `RowAggregateContext`\n * (behaving like a Row); at the top level it reports through `SelectionViewerAggregateContext`,\n * which `SelectionViewer` provides — this drives the outer sheet's loading/empty/error\n * views automatically with zero manual wiring, and lets Columns nest arbitrarily deep. */\nfunction Column({ id: providedId, className, style, children }: ColumnProps) {\n const [columnId] = useState(\n () => providedId || `column-${Math.random().toString(36).substring(2, 11)}`\n );\n\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\n const report = useCallback((id: string, state: SelectionState) => {\n setReportedStates((prev) => {\n const next = new Map(prev);\n next.set(id, state);\n return next;\n });\n }, []);\n const unreport = useCallback((id: string) => {\n setReportedStates((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n const rowAggregateValue = useMemo(() => ({ report, unreport }), [report, unreport]);\n\n const aggregateState =\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : \"initial\";\n\n const parentRowAggregate = React.useContext(RowAggregateContext);\n const selectionViewerAggregate = React.useContext(SelectionViewerAggregateContext);\n const upstreamReporter = parentRowAggregate ?? selectionViewerAggregate;\n\n useEffect(() => {\n if (!upstreamReporter) return;\n upstreamReporter.report(columnId, aggregateState);\n return () => upstreamReporter.unreport(columnId);\n }, [upstreamReporter, columnId, aggregateState]);\n\n return (\n <RowAggregateContext.Provider value={rowAggregateValue}>\n <div\n className={className ? `selection-viewer-column ${className}` : \"selection-viewer-column\"}\n style={{ display: \"flex\", flexDirection: \"column\", gap: \"8px\", ...style }}\n >\n {children}\n </div>\n </RowAggregateContext.Provider>\n );\n}\n\nColumn.displayName = \"Column\";\n\nexport { Column };\n"]}
package/dist/index.d.cts CHANGED
@@ -67,11 +67,26 @@ type CancelButtonProps = {
67
67
  position?: "left" | "right";
68
68
  style?: React.CSSProperties;
69
69
  onClick?: () => void;
70
+ /**
71
+ * What a screen reader calls it. Defaults to "Close".
72
+ *
73
+ * A button whose only content is an icon has no accessible name at all, so it was announced as
74
+ * just "button" — the one control that dismisses the sheet, and nothing said so.
75
+ */
76
+ ariaLabel?: string;
70
77
  };
71
78
  type LayoutProps = {
72
79
  gapBetweenHandleAndTitle?: string;
73
80
  gapBetweenTitleAndSearch?: string;
74
81
  gapBetweenSearchAndContent?: string;
82
+ /**
83
+ * How far the rows are set in from the sides. Defaults to `16px`, matching the search box.
84
+ *
85
+ * The content had no inset while everything above it had 16px, so a list ran flush into the
86
+ * sides of the screen under a search box that did not. Pass `0px` for rows that should reach
87
+ * the edges.
88
+ */
89
+ contentPadding?: string;
75
90
  backgroundColor?: string;
76
91
  handleColor?: string;
77
92
  handleWidth?: string;
package/dist/index.d.ts CHANGED
@@ -67,11 +67,26 @@ type CancelButtonProps = {
67
67
  position?: "left" | "right";
68
68
  style?: React.CSSProperties;
69
69
  onClick?: () => void;
70
+ /**
71
+ * What a screen reader calls it. Defaults to "Close".
72
+ *
73
+ * A button whose only content is an icon has no accessible name at all, so it was announced as
74
+ * just "button" — the one control that dismisses the sheet, and nothing said so.
75
+ */
76
+ ariaLabel?: string;
70
77
  };
71
78
  type LayoutProps = {
72
79
  gapBetweenHandleAndTitle?: string;
73
80
  gapBetweenTitleAndSearch?: string;
74
81
  gapBetweenSearchAndContent?: string;
82
+ /**
83
+ * How far the rows are set in from the sides. Defaults to `16px`, matching the search box.
84
+ *
85
+ * The content had no inset while everything above it had 16px, so a list ran flush into the
86
+ * sides of the screen under a search box that did not. Pass `0px` for rows that should reach
87
+ * the edges.
88
+ */
89
+ contentPadding?: string;
75
90
  backgroundColor?: string;
76
91
  handleColor?: string;
77
92
  handleWidth?: string;
package/dist/index.js CHANGED
@@ -24,6 +24,33 @@ var getStyles = (id) => `
24
24
  width: 100%;
25
25
  }
26
26
 
27
+ /*
28
+ * The close button, with a target a thumb can find.
29
+ *
30
+ * It sat at right: 0, top: 8 with no padding at all, so the icon was flush against the sheet's
31
+ * edge and the only thing that could be tapped was the glyph itself \u2014 a target well under half
32
+ * what a finger needs, in the corner of the screen where a thumb is least accurate. Inset by 4px
33
+ * and padded out to 44px square, so the icon still reads as sitting in the corner while the
34
+ * hittable area reaches the edges.
35
+ *
36
+ * The cancelButton.style prop is still spread last at the call site, so a consumer that was
37
+ * overriding any of this keeps overriding it. (No backticks in here: this whole block lives
38
+ * inside a template literal, and one would end the string.)
39
+ */
40
+ #${id} .selection-viewer-cancel {
41
+ display: inline-flex;
42
+ align-items: center;
43
+ justify-content: center;
44
+ min-width: 44px;
45
+ min-height: 44px;
46
+ padding: 10px;
47
+ border: none;
48
+ background-color: transparent;
49
+ color: inherit;
50
+ cursor: pointer;
51
+ -webkit-tap-highlight-color: transparent;
52
+ }
53
+
27
54
  #${id} .selection-viewer-drag-handle {
28
55
  height: 5px;
29
56
  border-radius: 3px;
@@ -64,11 +91,20 @@ var getStyles = (id) => `
64
91
  width: 100%;
65
92
  }
66
93
 
94
+ /*
95
+ * The rows, set in from the edges like everything else in the sheet.
96
+ *
97
+ * The title and the search box have carried a 16px margin from the start; the content had none, so
98
+ * a list of cards ran flush into the sides of the screen while the search box above it did not.
99
+ * The layoutProp.contentPadding option overrides it for a consumer that wants its rows edge to
100
+ * edge. (No backticks: this block is inside a template literal.)
101
+ */
67
102
  #${id} .selection-viewer-content {
68
103
  overflow-y: auto;
69
104
  -webkit-overflow-scrolling: touch;
70
105
  flex: 1;
71
106
  min-height: 0;
107
+ box-sizing: border-box;
72
108
  }
73
109
 
74
110
  #${id} .selection-viewer-content.vertical {
@@ -284,7 +320,6 @@ var SelectionViewer = ({
284
320
  [reportAggregate, unreportAggregate]
285
321
  );
286
322
  const reportedAggregate = reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : null;
287
- const isComposed = reportedAggregate !== null;
288
323
  const selectionState = selectionStateProp !== "initial" ? selectionStateProp : reportedAggregate ?? "initial";
289
324
  useEffect(() => {
290
325
  if (typeof window === "undefined" || !window.visualViewport) return;
@@ -451,12 +486,12 @@ var SelectionViewer = ({
451
486
  cancelButton?.position === "left" && /* @__PURE__ */ jsx(
452
487
  "button",
453
488
  {
489
+ "aria-label": cancelButton.ariaLabel || "Close",
490
+ className: "selection-viewer-cancel",
454
491
  style: {
455
492
  position: "absolute",
456
- left: "0px",
457
- top: "8px",
458
- border: "none",
459
- backgroundColor: "transparent",
493
+ left: "4px",
494
+ top: "4px",
460
495
  ...cancelButton.style
461
496
  },
462
497
  onClick: cancelButton.onClick || onClose,
@@ -477,12 +512,12 @@ var SelectionViewer = ({
477
512
  cancelButton?.position === "right" && /* @__PURE__ */ jsx(
478
513
  "button",
479
514
  {
515
+ "aria-label": cancelButton.ariaLabel || "Close",
516
+ className: "selection-viewer-cancel",
480
517
  style: {
481
518
  position: "absolute",
482
- right: "0px",
483
- top: "8px",
484
- border: "none",
485
- backgroundColor: "transparent",
519
+ right: "4px",
520
+ top: "4px",
486
521
  ...cancelButton.style
487
522
  },
488
523
  onClick: cancelButton.onClick || onClose,
@@ -556,7 +591,16 @@ var SelectionViewer = ({
556
591
  onScroll: onPaginate ? handleScroll : void 0,
557
592
  style: {
558
593
  paddingTop: isSearchFocused ? layoutProp?.gapBetweenSearchAndContent : "0",
559
- paddingBottom: keyboardHeight > 0 ? `${keyboardHeight + 16}px` : "16px"
594
+ paddingBottom: keyboardHeight > 0 ? `${keyboardHeight + 16}px` : "16px",
595
+ /*
596
+ * Set in from the edges, like everything else in the sheet.
597
+ *
598
+ * The title and the search box have carried 16px from the start and the content had
599
+ * none, so a list of rows ran flush into the sides of the screen under a search box
600
+ * that did not. Overridable for rows that genuinely want the full width.
601
+ */
602
+ paddingLeft: layoutProp?.contentPadding ?? "16px",
603
+ paddingRight: layoutProp?.contentPadding ?? "16px"
560
604
  },
561
605
  children: React.Children.count(children) > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
562
606
  children,
@@ -571,7 +615,7 @@ var SelectionViewer = ({
571
615
  children: loadingProp?.view
572
616
  }
573
617
  ),
574
- isComposed && selectionState === "empty" && /* @__PURE__ */ jsx(
618
+ selectionState === "empty" && /* @__PURE__ */ jsx(
575
619
  "div",
576
620
  {
577
621
  className: "selection-viewer-no-results",
@@ -582,7 +626,7 @@ var SelectionViewer = ({
582
626
  children: noResultProp?.view || /* @__PURE__ */ jsx("div", { className: "selection-viewer-default-no-results", children: noResultProp?.text || "No results found" })
583
627
  }
584
628
  ),
585
- isComposed && selectionState === "error" && /* @__PURE__ */ jsx(
629
+ selectionState === "error" && /* @__PURE__ */ jsx(
586
630
  "div",
587
631
  {
588
632
  className: "selection-viewer-error",
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SelectionViewer.tsx","../src/Row.tsx","../src/Column.tsx"],"names":["React","useState","useRef","useCallback","useEffect","jsx","useMemo"],"mappings":";;;;;AAaA,IAAM,mBAAA,GAAsB,KAAA,CAAM,aAAA,CAAwC,IAAI;AAI9E,IAAM,+BAAA,GAAkC,KAAA,CAAM,aAAA,CAAwC,IAAI;AAE1F,SAAS,sBAAsB,MAAA,EAA0C;AACvE,EAAA,IAAI,MAAA,CAAO,MAAA,KAAW,CAAA,EAAG,OAAO,SAAA;AAChC,EAAA,IAAI,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,KAAM,MAAM,GAAG,OAAO,MAAA;AAC7C,EAAA,IAAI,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,KAAM,SAAS,GAAG,OAAO,SAAA;AAChD,EAAA,IAAI,OAAO,KAAA,CAAM,CAAC,MAAM,CAAA,KAAM,OAAO,GAAG,OAAO,OAAA;AAC/C,EAAA,IAAI,OAAO,IAAA,CAAK,CAAC,MAAM,CAAA,KAAM,OAAO,GAAG,OAAO,OAAA;AAC9C,EAAA,OAAO,SAAA;AACT;AAoHA,IAAM,SAAA,GAAY,CAAC,EAAA,KAAe;AAAA,CAAA,EAC/B,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EASF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAMF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAMF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EASF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EASF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAUF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAOF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAMF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAQF,EAAE,CAAA;AAAA,CAAA,EACF,EAAE,CAAA;AAAA,CAAA,EACF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAOF,EAAE,CAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAKF,EAAE,CAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,CAAA,EAMF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAUF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAYF,EAAE,CAAA;AAAA;AAAA;;AAAA,CAAA,EAIF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAYF,EAAE,CAAA;AAAA;AAAA;;AAAA;AAAA,CAAA,EAKF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAOF,EAAE,CAAA;AAAA;AAAA;AAAA;;AAAA,CAAA,EAKF,EAAE,CAAA;AAAA;AAAA;AAAA;;;AAAA;AAAA;AAAA,GAAA,EAQA,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,GAAA,EAQF,EAAE,CAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAOP,IAAM,eAAA,GAAkB,CAAC,EAAA,KAAe;AACtC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,OAAA,GAAU,2BAA2B,EAAE,CAAA,CAAA;AAC7C,IAAA,IAAI,QAAA,GAAW,QAAA,CAAS,cAAA,CAAe,OAAO,CAAA;AAE9C,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,QAAA,GAAW,QAAA,CAAS,cAAc,OAAO,CAAA;AACzC,MAAA,QAAA,CAAS,EAAA,GAAK,OAAA;AACd,MAAA,QAAA,CAAS,SAAA,GAAY,UAAU,EAAE,CAAA;AACjC,MAAA,QAAA,CAAS,IAAA,CAAK,YAAY,QAAQ,CAAA;AAAA,IACpC;AAGA,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,QAAA,IAAY,QAAA,CAAS,IAAA,CAAK,QAAA,CAAS,QAAQ,CAAA,EAAG;AAChD,QAAA,QAAA,CAAS,IAAA,CAAK,YAAY,QAAQ,CAAA;AAAA,MACpC;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,EAAE,CAAC,CAAA;AACT,CAAA;AAkBA,IAAM,YAAA,GAAe,CAAC,MAAA,EAAiB,OAAA,EAAqB,WAAA,KAAwB;AAClF,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,IAAU,OAAO,QAAA,KAAa,WAAA,EAAa;AAEhD,IAAA,MAAM,SAAA,GAAY,CAAC,CAAA,KAAqB;AACtC,MAAA,IAAI,CAAA,CAAE,QAAQ,QAAA,EAAU;AACtB,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,OAAA,EAAQ;AACR,QAAA;AAAA,MACF;AACA,MAAA,IAAI,CAAA,CAAE,QAAQ,KAAA,EAAO;AAErB,MAAA,MAAM,SAAA,GAAY,QAAA,CAAS,cAAA,CAAe,WAAW,CAAA,EAAG,gBAAA;AAAA,QACtD;AAAA,OAEF;AACA,MAAA,IAAI,CAAC,SAAA,IAAa,SAAA,CAAU,MAAA,KAAW,CAAA,EAAG;AAE1C,MAAA,MAAM,KAAA,GAAQ,UAAU,CAAC,CAAA;AACzB,MAAA,MAAM,IAAA,GAAO,SAAA,CAAU,SAAA,CAAU,MAAA,GAAS,CAAC,CAAA;AAE3C,MAAA,IAAI,CAAA,CAAE,QAAA,IAAY,QAAA,CAAS,aAAA,KAAkB,KAAA,EAAO;AAClD,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,IAAA,CAAK,KAAA,EAAM;AAAA,MACb,WAAW,CAAC,CAAA,CAAE,QAAA,IAAY,QAAA,CAAS,kBAAkB,IAAA,EAAM;AACzD,QAAA,CAAA,CAAE,cAAA,EAAe;AACjB,QAAA,KAAA,CAAM,KAAA,EAAM;AAAA,MACd;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC9C,IAAA,OAAO,MAAM,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,SAAS,CAAA;AAAA,EAChE,CAAA,EAAG,CAAC,MAAA,EAAQ,OAAA,EAAS,WAAW,CAAC,CAAA;AACnC,CAAA;AAEA,IAAM,kBAAkD,CAAC;AAAA,EACvD,EAAA,EAAI,UAAA;AAAA,EACJ,MAAA;AAAA,EACA,QAAA,GAAW,IAAA;AAAA,EACX,OAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,iBAAA,GAAoB,UAAA;AAAA,EACpB,QAAA;AAAA,EACA,UAAA;AAAA,EACA,UAAA,GAAa,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,EAClB,WAAA,GAAc,CAAA;AAAA,EACd,cAAA,GAAiB,IAAA;AAAA,EACjB,MAAA,GAAS,GAAA;AAAA,EACT,SAAA;AAAA,EACA,SAAA,GAAY,OAAA;AAAA,EACZ,SAAA,GAAY,OAAA;AAAA,EACZ,gBAAgB,kBAAA,GAAqB,SAAA;AAAA,EACrC,cAAA,GAAiB;AACnB,CAAA,KAAM;AACJ,EAAA,MAAM,CAAC,EAAE,CAAA,GAAI,QAAA,CAAS,MAAM,cAAc,CAAA,UAAA,EAAa,IAAA,CAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAA,EAAG,EAAE,CAAC,CAAA,CAAE,CAAA;AACpG,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,EAAE,CAAA;AACjD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5D,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAAS,CAAC,CAAA;AACtD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,CAAC,CAAA;AAC1C,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAAS,KAAK,CAAA;AAC5D,EAAA,MAAM,YAAA,GAAe,OAAO,KAAK,CAAA;AACjC,EAAA,MAAM,cAAA,GAAiB,OAAyB,IAAI,CAAA;AACpD,EAAA,MAAM,QAAA,GAAW,OAAY,IAAI,CAAA;AACjC,EAAkB,OAAuB,IAAI;AAE7C,EAAA,eAAA,CAAgB,EAAE,CAAA;AAElB,EAAA,YAAA,CAAa,MAAA,EAAQ,SAAS,EAAE,CAAA;AAIhC,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,IAAI,QAAA,iBAAsC,IAAI,KAAK,CAAA;AAC3F,EAAA,MAAM,eAAA,GAAkB,WAAA,CAAY,CAAC,UAAA,EAAoB,KAAA,KAA0B;AACjF,IAAA,iBAAA,CAAkB,CAAC,IAAA,KAAS;AAC1B,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,MAAA,IAAA,CAAK,GAAA,CAAI,YAAY,KAAK,CAAA;AAC1B,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,MAAM,iBAAA,GAAoB,WAAA,CAAY,CAAC,UAAA,KAAuB;AAC5D,IAAA,iBAAA,CAAkB,CAAC,IAAA,KAAS;AAC1B,MAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,UAAU,GAAG,OAAO,IAAA;AAClC,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,MAAA,IAAA,CAAK,OAAO,UAAU,CAAA;AACtB,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,MAAM,sBAAA,GAAyB,OAAA;AAAA,IAC7B,OAAO,EAAE,MAAA,EAAQ,eAAA,EAAiB,UAAU,iBAAA,EAAkB,CAAA;AAAA,IAC9D,CAAC,iBAAiB,iBAAiB;AAAA,GACrC;AACA,EAAA,MAAM,iBAAA,GACJ,cAAA,CAAe,IAAA,GAAO,CAAA,GAAI,qBAAA,CAAsB,KAAA,CAAM,IAAA,CAAK,cAAA,CAAe,MAAA,EAAQ,CAAC,CAAA,GAAI,IAAA;AACzF,EAAA,MAAM,aAAa,iBAAA,KAAsB,IAAA;AAIzC,EAAA,MAAM,cAAA,GACJ,kBAAA,KAAuB,SAAA,GAAY,kBAAA,GAAqB,iBAAA,IAAqB,SAAA;AAG/E,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,OAAO,cAAA,EAAgB;AAE7D,IAAA,MAAM,eAAe,MAAM;AACzB,MAAA,MAAM,KAAK,MAAA,CAAO,cAAA;AAClB,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,WAAA,GAAc,EAAA,CAAG,MAAA;AACzC,MAAA,iBAAA,CAAkB,QAAA,GAAW,CAAA,GAAI,QAAA,GAAW,CAAC,CAAA;AAAA,IAC/C,CAAA;AAEA,IAAA,MAAA,CAAO,cAAA,CAAe,gBAAA,CAAiB,QAAA,EAAU,YAAY,CAAA;AAC7D,IAAA,MAAA,CAAO,cAAA,CAAe,gBAAA,CAAiB,QAAA,EAAU,YAAY,CAAA;AAE7D,IAAA,OAAO,MAAM;AACX,MAAA,MAAA,CAAO,cAAA,EAAgB,mBAAA,CAAoB,QAAA,EAAU,YAAY,CAAA;AACjE,MAAA,MAAA,CAAO,cAAA,EAAgB,mBAAA,CAAoB,QAAA,EAAU,YAAY,CAAA;AAAA,IACnE,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAGL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,cAAA,CAAe,SAAS,IAAA,EAAK;AAC7B,MAAA,cAAA,CAAe,EAAE,CAAA;AACjB,MAAA,UAAA,EAAY,WAAW,EAAE,CAAA;AACzB,MAAA,kBAAA,CAAmB,KAAK,CAAA;AACxB,MAAA;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,EAAQ,UAAA,EAAY,SAAS,CAAC,CAAA;AAElC,EAAA,MAAM,aAAA,GAAgB,YAAY,MAAM;AACtC,IAAA,IAAI,UAAA,EAAY,SAAA,IAAa,cAAA,CAAe,OAAA,EAAS;AACnD,MAAA,WAAA,CAAY,CAAA,IAAA,KAAQ,OAAO,CAAC,CAAA;AAC5B,MAAA,kBAAA,CAAmB,IAAI,CAAA;AACvB,MAAA,cAAA,CAAe,QAAQ,KAAA,EAAM;AAC7B,MAAA,cAAA,CAAe,QAAQ,KAAA,EAAM;AAAA,IAC/B;AAAA,EACF,CAAA,EAAG,CAAC,UAAA,EAAY,SAAS,CAAC,CAAA;AAE1B,EAAA,MAAM,kBAAA,GAAqB,CAAC,CAAA,KAA2C;AACrE,IAAA,MAAM,KAAA,GAAQ,EAAE,MAAA,CAAO,KAAA;AACvB,IAAA,cAAA,CAAe,KAAK,CAAA;AACpB,IAAA,UAAA,EAAY,WAAW,KAAK,CAAA;AAAA,EAC9B,CAAA;AAEA,EAAA,MAAM,oBAAoB,MAAM;AAC9B,IAAA,kBAAA,CAAmB,IAAI,CAAA;AACvB,IAAA,UAAA,EAAY,OAAA,IAAU;AACtB,IAAA,qBAAA,CAAsB,MAAM;AAC1B,MAAA,cAAA,CAAe,SAAS,KAAA,EAAM;AAAA,IAChC,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,mBAAmB,MAAM;AAC7B,IAAA,UAAA,EAAY,MAAA,IAAS;AAAA,EACvB,CAAA;AAEA,EAAA,MAAM,uBAAuB,MAAM;AACjC,IAAA,kBAAA,CAAmB,KAAK,CAAA;AACxB,IAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,MAAA,cAAA,CAAe,QAAQ,IAAA,EAAK;AAAA,IAC9B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,cAAA,CAAe,EAAE,CAAA;AACjB,IAAA,UAAA,EAAY,WAAW,EAAE,CAAA;AACzB,IAAA,IAAI,eAAe,OAAA,EAAS;AAC1B,MAAA,cAAA,CAAe,QAAQ,KAAA,EAAM;AAAA,IAC/B;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,YAAA,GAAe,WAAA;AAAA,IACnB,OAAO,CAAA,KAAqC;AAC1C,MAAA,IAAI,YAAA,CAAa,OAAA,IAAW,CAAC,UAAA,EAAY;AAEzC,MAAA,MAAM,EAAE,SAAA,EAAW,YAAA,EAAc,YAAA,KAAiB,CAAA,CAAE,aAAA;AACpD,MAAA,MAAM,YAAA,GAAe,YAAA,GAAe,SAAA,IAAa,YAAA,GAAe,GAAA;AAEhE,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,YAAA,CAAa,OAAA,GAAU,IAAA;AACvB,QAAA,MAAM,OAAA,GAAU,MAAM,UAAA,EAAW;AACjC,QAAA,IAAI,CAAC,OAAA,EAAS;AACZ,UAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AAAA,QACzB,CAAA,MAAO;AACL,UAAA,UAAA,CAAW,MAAM;AACf,YAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AAAA,UACzB,GAAG,GAAG,CAAA;AAAA,QACR;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA,CAAC,UAAU;AAAA,GACb;AAEA,EAAA,IAAI,CAAC,MAAA,IAAU,cAAA,EAAgB,OAAO,IAAA;AAEtC,EAAA,uBACE,GAAA,CAAC,+BAAA,CAAgC,QAAA,EAAhC,EAAyC,OAAO,sBAAA,EACjD,QAAA,kBAAA,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,QAAA;AAAA,MACL,MAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA,EAAO,SAAA;AAAA,MACP,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,MAChB,SAAA;AAAA,MACA,SAAA,EAAW,aAAA;AAAA,MAEX,QAAA,EAAA;AAAA,wBAAA,IAAA;AAAA,UAAC,KAAA,CAAM,SAAA;AAAA,UAAN;AAAA,YACC,EAAA;AAAA,YAIA,IAAA,EAAK,QAAA;AAAA,YACL,YAAA,EAAW,MAAA;AAAA,YACX,YAAA,EAAY,SAAA;AAAA,YACZ,KAAA,EAAO;AAAA,cACL,SAAA;AAAA,cACA,SAAA,EAAW,kBAAkB,QAAA,GAAW,SAAA;AAAA,cACxC,QAAA,EAAU,YAAY,QAAA,IAAY,OAAA;AAAA,cAClC,MAAA,EAAQ,QAAA;AAAA,cACR,KAAA,EAAO,MAAA;AAAA,cACP,IAAA,EAAM,CAAA;AAAA,cACN,KAAA,EAAO,CAAA;AAAA,cACP,aAAA,EAAe,yCAAA;AAAA,cACf,YAAY,eAAA,GACR,UAAA,EAAY,0BAAA,IAA8B,UAAA,EAAY,kBACtD,UAAA,EAAY,eAAA;AAAA,cAChB,mBAAA,EAAqB,kBAAkB,KAAA,GAAQ,MAAA;AAAA,cAC/C,oBAAA,EAAsB,kBAAkB,KAAA,GAAQ;AAAA,aAClD;AAAA,YAEC,QAAA,EAAA;AAAA,cAAA,eAAA,mBACC,GAAA,CAAC,KAAA,CAAM,MAAA,EAAN,EACC,QAAA,kBAAA,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAU,oCAAA;AAAA,kBACV,OAAO,UAAA,EAAY,2BAAA;AAAA,kBAEnB,QAAA,kBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EAA0B,KAAA,EAAO;AAAA,oBAC9C,GAAG,UAAA,EAAY,cAAA;AAAA,oBACf,YAAY,UAAA,EAAY,UAAA;AAAA,oBACxB,SAAS,UAAA,EAAY,OAAA,GACjB,GAAG,UAAA,CAAW,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,UAAA,CAAW,QAAQ,CAAC,CAAA,CAAA,EAAI,WAAW,OAAA,CAAQ,CAAC,IAAI,UAAA,CAAW,OAAA,CAAQ,CAAC,CAAA,CAAA,GAC/F;AAAA,mBACN,EACE,QAAA,EAAA;AAAA,oCAAA,GAAA;AAAA,sBAAC,QAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,qCAAA;AAAA,wBACV,OAAA,EAAS,oBAAA;AAAA,wBACT,YAAA,EAAW,kBAAA;AAAA,wBAEV,QAAA,EAAA,UAAA,EAAY,QAAA,oBACX,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,kBAAA,EAAmB,MAAA,EAAQ,UAAA,EAAY,SAAA,IAAa,cAAA,EAAgB,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAC3I;AAAA;AAAA,qBAEJ;AAAA,oCAEA,GAAA;AAAA,sBAAC,OAAA;AAAA,sBAAA;AAAA,wBAEC,GAAA,EAAK,cAAA;AAAA,wBACL,IAAA,EAAK,MAAA;AAAA,wBACL,aAAa,UAAA,EAAY,IAAA;AAAA,wBACzB,KAAA,EAAO,WAAA;AAAA,wBACP,QAAA,EAAU,kBAAA;AAAA,wBACV,SAAA,EAAW,YAAY,SAAA,IAAa,+BAAA;AAAA,wBACpC,KAAA,EAAO;AAAA,0BACL,OAAO,UAAA,EAAY,SAAA;AAAA,0BACnB,GAAG,UAAA,EAAY;AAAA,yBACjB;AAAA,wBACA,OAAA,EAAS,iBAAA;AAAA,wBACT,MAAA,EAAQ,gBAAA;AAAA,wBACR,SAAA,EAAW;AAAA,uBAAA;AAAA,sBAbN;AAAA,qBAcP;AAAA,oBAEC,WAAA,oBACC,GAAA;AAAA,sBAAC,QAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,sCAAA;AAAA,wBACV,OAAA,EAAS,WAAA;AAAA,wBACT,YAAA,EAAW,cAAA;AAAA,wBAEV,QAAA,EAAA,UAAA,EAAY,SAAA,oBACX,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,sBAAA,EAAuB,MAAA,EAAQ,UAAA,EAAY,SAAA,IAAa,cAAA,EAAgB,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EAC/I;AAAA;AAAA;AAEJ,mBAAA,EAEJ;AAAA;AAAA,eACF,EACF,CAAA,mBAEA,IAAA,CAAC,KAAA,CAAM,QAAN,EACC,QAAA,EAAA;AAAA,gCAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EAEZ,QAAA,EAAA;AAAA,kBAAA,YAAA,EAAc,aAAa,MAAA,oBAC1B,GAAA;AAAA,oBAAC,QAAA;AAAA,oBAAA;AAAA,sBACC,KAAA,EAAO;AAAA,wBACL,QAAA,EAAU,UAAA;AAAA,wBACV,IAAA,EAAM,KAAA;AAAA,wBACN,GAAA,EAAK,KAAA;AAAA,wBACL,MAAA,EAAQ,MAAA;AAAA,wBACR,eAAA,EAAiB,aAAA;AAAA,wBACjB,GAAG,YAAA,CAAa;AAAA,uBAClB;AAAA,sBACA,OAAA,EAAS,aAAa,OAAA,IAAW,OAAA;AAAA,sBAEhC,QAAA,EAAA,YAAA,CAAa,IAAA,IAAQ,YAAA,CAAa,IAAA,IAAQ;AAAA;AAAA,mBAC7C;AAAA,kBAID,CAAC,eAAA,oBACA,GAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,8BAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,UAAA,EAAY,YAAY,WAAA,IAAe,MAAA;AAAA,wBACvC,KAAA,EAAO,YAAY,WAAA,IAAe,MAAA;AAAA,wBAClC,YAAA,EAAc,YAAY,wBAAA,IAA4B;AAAA;AACxD;AAAA,mBACF;AAAA,kBAID,YAAA,EAAc,aAAa,OAAA,oBAC1B,GAAA;AAAA,oBAAC,QAAA;AAAA,oBAAA;AAAA,sBACC,KAAA,EAAO;AAAA,wBACL,QAAA,EAAU,UAAA;AAAA,wBACV,KAAA,EAAO,KAAA;AAAA,wBACP,GAAA,EAAK,KAAA;AAAA,wBACL,MAAA,EAAQ,MAAA;AAAA,wBACR,eAAA,EAAiB,aAAA;AAAA,wBACjB,GAAG,YAAA,CAAa;AAAA,uBAClB;AAAA,sBACA,OAAA,EAAS,aAAa,OAAA,IAAW,OAAA;AAAA,sBAEhC,QAAA,EAAA,YAAA,CAAa,IAAA,IAAQ,YAAA,CAAa,IAAA,IAAQ;AAAA;AAAA,mBAC7C;AAAA,kCAIF,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,SAAA,CAAU,kBAAkB,4BAAA,EAC1C,QAAA,kBAAA,GAAA;AAAA,oBAAC,IAAA;AAAA,oBAAA;AAAA,sBACC,EAAA,EAAI,GAAG,EAAE,CAAA,MAAA,CAAA;AAAA,sBACT,SAAA,EAAW,UAAU,SAAA,IAAa,wBAAA;AAAA,sBAClC,KAAA,EAAO;AAAA,wBACL,YAAA,EAAc,YAAY,wBAAA,IAA4B,KAAA;AAAA,wBACtD,KAAA,EAAO,WAAW,SAAA,IAAa,OAAA;AAAA,wBAC/B,GAAG,SAAA,CAAU;AAAA,uBACf;AAAA,sBAEC,QAAA,EAAA,SAAA,CAAU;AAAA;AAAA,mBACb,EACF;AAAA,iBAAA,EACF,CAAA;AAAA,gBAGC,UAAA,oBACC,IAAA;AAAA,kBAAC,KAAA;AAAA,kBAAA;AAAA,oBACC,SAAA,EAAU,yBAAA;AAAA,oBACV,KAAA,EAAO;AAAA,sBACL,YAAY,UAAA,CAAW,UAAA;AAAA,sBACvB,SAAS,UAAA,CAAW,OAAA,GAChB,GAAG,UAAA,CAAW,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,UAAA,CAAW,QAAQ,CAAC,CAAA,CAAA,EAAI,WAAW,OAAA,CAAQ,CAAC,IAAI,UAAA,CAAW,OAAA,CAAQ,CAAC,CAAA,CAAA,GAC/F,UAAA;AAAA,sBACJ,cAAc,UAAA,EAAY,0BAAA;AAAA,sBAC1B,GAAG,UAAA,CAAW;AAAA,qBAChB;AAAA,oBAEC,QAAA,EAAA;AAAA,sBAAA,UAAA,CAAW,UAAA,oBACV,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAO,EAAE,WAAA,EAAa,UAAA,CAAW,SAAA,IAAa,KAAA,EAAM,EACvD,QAAA,EAAA,UAAA,CAAW,UAAA,EACd,CAAA;AAAA,sCAEF,GAAA;AAAA,wBAAC,OAAA;AAAA,wBAAA;AAAA,0BAEC,GAAA,EAAK,cAAA;AAAA,0BACL,IAAA,EAAK,MAAA;AAAA,0BACL,aAAa,UAAA,CAAW,IAAA;AAAA,0BACxB,KAAA,EAAO,WAAA;AAAA,0BACP,QAAA,EAAU,kBAAA;AAAA,0BACV,SAAA,EAAW,WAAW,SAAA,IAAa,+BAAA;AAAA,0BACnC,KAAA,EAAO;AAAA,4BACL,OAAO,UAAA,EAAY,SAAA;AAAA,4BACnB,GAAG,UAAA,CAAW;AAAA,2BAChB;AAAA,0BACA,OAAA,EAAS,iBAAA;AAAA,0BACT,MAAA,EAAQ,gBAAA;AAAA,0BACR,SAAA,EAAW;AAAA,yBAAA;AAAA,wBAbN;AAAA,uBAcP;AAAA,sBACC,WAAA,oBACC,GAAA;AAAA,wBAAC,QAAA;AAAA,wBAAA;AAAA,0BACC,SAAA,EAAU,sCAAA;AAAA,0BACV,OAAA,EAAS,WAAA;AAAA,0BACT,YAAA,EAAW,cAAA;AAAA,0BACX,KAAA,EAAO,EAAE,UAAA,EAAY,UAAA,CAAW,aAAa,KAAA,EAAM;AAAA,0BAElD,QAAA,EAAA,UAAA,CAAW,SAAA,IAAa,UAAA,CAAW,UAAA,oBAClC,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,IAAA,EAAK,MAAA,EAAO,IAAA,EAAK,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,KAAA,EAAM,4BAAA,EAChE,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,sBAAA,EAAuB,MAAA,EAAO,cAAA,EAAe,WAAA,EAAY,GAAA,EAAI,aAAA,EAAc,OAAA,EAAQ,cAAA,EAAe,OAAA,EAAQ,CAAA,EACpH;AAAA;AAAA,uBAEJ;AAAA,sBAED,CAAC,WAAA,IAAe,UAAA,CAAW,UAAA,wBACzB,MAAA,EAAA,EAAK,KAAA,EAAO,EAAE,UAAA,EAAY,UAAA,CAAW,SAAA,IAAa,KAAA,EAAM,EACtD,qBAAW,UAAA,EACd;AAAA;AAAA;AAAA;AAEJ,eAAA,EAEJ,CAAA;AAAA,8BAGF,GAAA,CAAC,KAAA,CAAM,OAAA,EAAN,EACC,QAAA,kBAAA,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,SAAA,EAAW,4BAA4B,iBAAiB,CAAA,CAAA;AAAA,kBACxD,QAAA,EAAU,aAAa,YAAA,GAAe,MAAA;AAAA,kBACtC,KAAA,EAAO;AAAA,oBACL,UAAA,EAAY,eAAA,GAAkB,UAAA,EAAY,0BAAA,GAA6B,GAAA;AAAA,oBACvE,eAAe,cAAA,GAAiB,CAAA,GAC5B,CAAA,EAAG,cAAA,GAAiB,EAAE,CAAA,EAAA,CAAA,GACtB;AAAA,mBACN;AAAA,kBAGC,gBAAM,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAA,GAAI,oBAChC,IAAA,CAAA,QAAA,EAAA,EACG,QAAA,EAAA;AAAA,oBAAA,QAAA;AAAA,oBACA,mBAAmB,SAAA,oBAClB,GAAA;AAAA,sBAAC,KAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,0BAAA;AAAA,wBACV,KAAA,EAAO;AAAA,0BACL,SAAS,WAAA,EAAa,OAAA,GAClB,GAAG,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,WAAA,CAAY,QAAQ,CAAC,CAAA,CAAA,EAAI,YAAY,OAAA,CAAQ,CAAC,IAAI,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAA,CAAA,GACnG,MAAA;AAAA,0BACJ,GAAG,WAAA,EAAa;AAAA,yBAClB;AAAA,wBAEC,QAAA,EAAA,WAAA,EAAa;AAAA;AAAA,qBAChB;AAAA,oBAMD,UAAA,IAAc,mBAAmB,OAAA,oBAChC,GAAA;AAAA,sBAAC,KAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,6BAAA;AAAA,wBACV,KAAA,EAAO;AAAA,0BACL,SAAS,YAAA,EAAc,OAAA,GACnB,GAAG,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,YAAA,CAAa,QAAQ,CAAC,CAAA,CAAA,EAAI,aAAa,OAAA,CAAQ,CAAC,IAAI,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,CAAA,GACvG,MAAA;AAAA,0BACJ,GAAG,YAAA,EAAc;AAAA,yBACnB;AAAA,wBAEC,QAAA,EAAA,YAAA,EAAc,wBACb,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qCAAA,EACZ,QAAA,EAAA,YAAA,EAAc,QAAQ,kBAAA,EACzB;AAAA;AAAA,qBAEJ;AAAA,oBAED,UAAA,IAAc,mBAAmB,OAAA,oBAChC,GAAA;AAAA,sBAAC,KAAA;AAAA,sBAAA;AAAA,wBACC,SAAA,EAAU,wBAAA;AAAA,wBACV,KAAA,EAAO;AAAA,0BACL,SAAS,SAAA,EAAW,OAAA,GAChB,GAAG,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,SAAA,CAAU,QAAQ,CAAC,CAAA,CAAA,EAAI,UAAU,OAAA,CAAQ,CAAC,IAAI,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,CAAA,GAC3F,MAAA;AAAA,0BACJ,GAAG,SAAA,EAAW;AAAA,yBAChB;AAAA,wBAEC,QAAA,EAAA,SAAA,EAAW,wBACV,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gCAAA,EACZ,QAAA,EAAA,SAAA,EAAW,QAAQ,kBAAA,EACtB;AAAA;AAAA;AAEJ,mBAAA,EAEJ,CAAA,GACG,cAAA,KAAmB,OAAA,IAAY,KAAA,CAAM,QAAA,CAAS,KAAA,CAAM,QAAQ,CAAA,IAAK,CAAA,KAAM,cAAA,IAAkB,SAAA,IAAa,cAAA,IAAkB,OAAA,CAAA,mBAC3H,GAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,6BAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,SAAS,YAAA,EAAc,OAAA,GACnB,GAAG,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,YAAA,CAAa,QAAQ,CAAC,CAAA,CAAA,EAAI,aAAa,OAAA,CAAQ,CAAC,IAAI,YAAA,CAAa,OAAA,CAAQ,CAAC,CAAA,CAAA,GACvG,MAAA;AAAA,wBACJ,GAAG,YAAA,EAAc;AAAA,uBACnB;AAAA,sBAEC,QAAA,EAAA,YAAA,EAAc,wBACb,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,qCAAA,EACZ,QAAA,EAAA,YAAA,EAAc,QAAQ,kBAAA,EACzB;AAAA;AAAA,mBAEJ,GACE,mBAAmB,SAAA,mBACrB,GAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,0BAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,SAAS,WAAA,EAAa,OAAA,GAClB,GAAG,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,WAAA,CAAY,QAAQ,CAAC,CAAA,CAAA,EAAI,YAAY,OAAA,CAAQ,CAAC,IAAI,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAA,CAAA,GACnG,MAAA;AAAA,wBACJ,GAAG,WAAA,EAAa;AAAA,uBAClB;AAAA,sBAEC,QAAA,EAAA,WAAA,EAAa;AAAA;AAAA,mBAChB,GACG,mBAAmB,OAAA,mBACtB,GAAA;AAAA,oBAAC,KAAA;AAAA,oBAAA;AAAA,sBACC,SAAA,EAAU,wBAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,SAAS,SAAA,EAAW,OAAA,GAChB,GAAG,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,CAAA,EAAI,SAAA,CAAU,QAAQ,CAAC,CAAA,CAAA,EAAI,UAAU,OAAA,CAAQ,CAAC,IAAI,SAAA,CAAU,OAAA,CAAQ,CAAC,CAAA,CAAA,GAC3F,MAAA;AAAA,wBACJ,GAAG,SAAA,EAAW;AAAA,uBAChB;AAAA,sBAEC,QAAA,EAAA,SAAA,EAAW,wBACV,GAAA,CAAC,KAAA,EAAA,EAAI,WAAU,gCAAA,EACZ,QAAA,EAAA,SAAA,EAAW,QAAQ,kBAAA,EACtB;AAAA;AAAA,mBAEJ,GACE;AAAA;AAAA,eACN,EACF;AAAA;AAAA;AAAA,SACF;AAAA,4BACC,KAAA,CAAM,QAAA,EAAN,EAAe,KAAA,EAAO,QAAA,GAAW,UAAU,MAAA,EAAW;AAAA;AAAA;AAAA,GACzD,EACA,CAAA;AAEJ,CAAA;AAUA,IAAM,sBAAA,GAAyB,CAAC,qBAAA,KAK3B;AACH,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAS,KAAK,CAAA;AAC1C,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,QAAA,CAAS,yBAAyB,SAAS,CAAA;AACvF,EAAA,MAAM,CAAC,WAAW,CAAA,GAAI,QAAA,CAAS,MAAM,aAAa,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,CAAA,EAAG,EAAE,CAAC,CAAA,CAAE,CAAA;AAE/F,EAAA,MAAM,UAAA,GAAa,QAAmB,OAAO;AAAA,IAC3C,IAAA,EAAM,MAAM,SAAA,CAAU,IAAI,CAAA;AAAA,IAC1B,KAAA,EAAO,MAAM,SAAA,CAAU,KAAK,CAAA;AAAA,IAC5B,QAAQ,MAAM,SAAA,CAAU,CAAC,IAAA,KAAS,CAAC,IAAI,CAAA;AAAA,IACvC;AAAA,GACF,CAAA,EAAI,CAAC,iBAAiB,CAAC,CAAA;AAEvB,EAAA,OAAO,CAAC,WAAA,EAAa,UAAA,EAAY,MAAA,EAAQ,cAAc,CAAA;AACzD;AAiBA,IAAO,uBAAA,GAAQ;ACz4Bf,SAAS,GAAA,CAAI,EAAE,EAAA,EAAI,UAAA,EAAY,KAAA,GAAQ,QAAQ,UAAA,EAAY,SAAA,EAAW,KAAA,EAAO,QAAA,EAAS,EAAa;AACjG,EAAA,MAAM,iBAAA,GAAoBA,KAAAA,CAAM,UAAA,CAAW,mBAAmB,CAAA;AAC9D,EAAA,MAAM,CAAC,KAAK,CAAA,GAAIC,QAAAA,CAAS,MAAM,cAAc,CAAA,IAAA,EAAO,IAAA,CAAK,MAAA,EAAO,CAAE,SAAS,EAAE,CAAA,CAAE,UAAU,CAAA,EAAG,EAAE,CAAC,CAAA,CAAE,CAAA;AACjG,EAAA,MAAM,YAAA,GAAeC,OAA8B,IAAI,CAAA;AACvD,EAAA,MAAM,YAAA,GAAeA,OAAO,KAAK,CAAA;AAEjC,EAAA,MAAM,YAAA,GAAeC,YAAY,YAAY;AAC3C,IAAA,MAAM,KAAK,YAAA,CAAa,OAAA;AACxB,IAAA,IAAI,CAAC,EAAA,IAAM,YAAA,CAAa,OAAA,IAAW,CAAC,UAAA,EAAY;AAIhD,IAAA,MAAM,EAAE,UAAA,EAAY,WAAA,EAAa,WAAA,EAAY,GAAI,EAAA;AACjD,IAAA,IAAI,WAAA,GAAc,UAAA,GAAa,WAAA,GAAc,GAAA,EAAK;AAElD,IAAA,YAAA,CAAa,OAAA,GAAU,IAAA;AACvB,IAAA,MAAM,OAAA,GAAU,MAAM,UAAA,EAAW;AACjC,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AAAA,IACzB,CAAA,MAAO;AACL,MAAA,UAAA,CAAW,MAAM;AACf,QAAA,YAAA,CAAa,OAAA,GAAU,KAAA;AAAA,MACzB,GAAG,GAAG,CAAA;AAAA,IACR;AAAA,EACF,CAAA,EAAG,CAAC,UAAU,CAAC,CAAA;AAEf,EAAAC,UAAU,MAAM;AACd,IAAA,MAAM,KAAK,YAAA,CAAa,OAAA;AACxB,IAAA,IAAI,CAAC,EAAA,IAAM,CAAC,UAAA,EAAY;AACxB,IAAA,EAAA,CAAG,gBAAA,CAAiB,UAAU,YAAY,CAAA;AAC1C,IAAA,OAAO,MAAM,EAAA,CAAG,mBAAA,CAAoB,QAAA,EAAU,YAAY,CAAA;AAAA,EAC5D,CAAA,EAAG,CAAC,YAAA,EAAc,UAAU,CAAC,CAAA;AAE7B,EAAAA,UAAU,MAAM;AACd,IAAA,iBAAA,EAAmB,MAAA,CAAO,OAAO,KAAK,CAAA;AACtC,IAAA,OAAO,MAAM,iBAAA,EAAmB,QAAA,CAAS,KAAK,CAAA;AAAA,EAChD,CAAA,EAAG,CAAC,iBAAA,EAAmB,KAAA,EAAO,KAAK,CAAC,CAAA;AAEpC,EAAA,uBACEC,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,GAAA,EAAK,YAAA;AAAA,MACL,SAAA,EAAW,SAAA,GAAY,CAAA,qBAAA,EAAwB,SAAS,CAAA,CAAA,GAAK,sBAAA;AAAA,MAC7D,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,KAAA;AAAA,QACf,GAAA,EAAK,KAAA;AAAA,QACL,SAAA,EAAW,MAAA;AAAA,QACX,SAAA,EAAW,QAAA;AAAA,QACX,GAAG;AAAA,OACL;AAAA,MAEC;AAAA;AAAA,GACH;AAEJ;AAEA,GAAA,CAAI,WAAA,GAAc,KAAA;AC1DlB,SAAS,OAAO,EAAE,EAAA,EAAI,YAAY,SAAA,EAAW,KAAA,EAAO,UAAS,EAAgB;AAC3E,EAAA,MAAM,CAAC,QAAQ,CAAA,GAAIJ,QAAAA;AAAA,IACjB,MAAM,UAAA,IAAc,CAAA,OAAA,EAAU,IAAA,CAAK,MAAA,EAAO,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAA,CAAU,CAAA,EAAG,EAAE,CAAC,CAAA;AAAA,GAC3E;AAEA,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,IAAIA,QAAAA,iBAAsC,IAAI,KAAK,CAAA;AAC3F,EAAA,MAAM,MAAA,GAASE,WAAAA,CAAY,CAAC,EAAA,EAAY,KAAA,KAA0B;AAChE,IAAA,iBAAA,CAAkB,CAAC,IAAA,KAAS;AAC1B,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,MAAA,IAAA,CAAK,GAAA,CAAI,IAAI,KAAK,CAAA;AAClB,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,MAAM,QAAA,GAAWA,WAAAA,CAAY,CAAC,EAAA,KAAe;AAC3C,IAAA,iBAAA,CAAkB,CAAC,IAAA,KAAS;AAC1B,MAAA,IAAI,CAAC,IAAA,CAAK,GAAA,CAAI,EAAE,GAAG,OAAO,IAAA;AAC1B,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,IAAI,CAAA;AACzB,MAAA,IAAA,CAAK,OAAO,EAAE,CAAA;AACd,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,MAAM,iBAAA,GAAoBG,OAAAA,CAAQ,OAAO,EAAE,MAAA,EAAQ,UAAS,CAAA,EAAI,CAAC,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAElF,EAAA,MAAM,cAAA,GACJ,cAAA,CAAe,IAAA,GAAO,CAAA,GAAI,qBAAA,CAAsB,KAAA,CAAM,IAAA,CAAK,cAAA,CAAe,MAAA,EAAQ,CAAC,CAAA,GAAI,SAAA;AAEzF,EAAA,MAAM,kBAAA,GAAqBN,KAAAA,CAAM,UAAA,CAAW,mBAAmB,CAAA;AAC/D,EAAA,MAAM,wBAAA,GAA2BA,KAAAA,CAAM,UAAA,CAAW,+BAA+B,CAAA;AACjF,EAAA,MAAM,mBAAmB,kBAAA,IAAsB,wBAAA;AAE/C,EAAAI,UAAU,MAAM;AACd,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACvB,IAAA,gBAAA,CAAiB,MAAA,CAAO,UAAU,cAAc,CAAA;AAChD,IAAA,OAAO,MAAM,gBAAA,CAAiB,QAAA,CAAS,QAAQ,CAAA;AAAA,EACjD,CAAA,EAAG,CAAC,gBAAA,EAAkB,QAAA,EAAU,cAAc,CAAC,CAAA;AAE/C,EAAA,uBACEC,GAAAA,CAAC,mBAAA,CAAoB,UAApB,EAA6B,KAAA,EAAO,mBACnC,QAAA,kBAAAA,GAAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAW,SAAA,GAAY,CAAA,wBAAA,EAA2B,SAAS,CAAA,CAAA,GAAK,yBAAA;AAAA,MAChE,KAAA,EAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,eAAe,QAAA,EAAU,GAAA,EAAK,KAAA,EAAO,GAAG,KAAA,EAAM;AAAA,MAEvE;AAAA;AAAA,GACH,EACF,CAAA;AAEJ;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"index.js","sourcesContent":["import React, { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\r\nimport { Sheet } from \"@academix-admin/modal-sheet\";\r\n\r\n// ==================== Aggregation (Row/Column) ====================\r\n// Independent from @academix-admin/search-viewer's equivalent (Library Charter: packages stay\r\n// mutually independent) — same shape, duplicated intentionally rather than shared.\r\n\r\ntype AggregateReporter = {\r\n report: (id: string, state: SelectionState) => void;\r\n unreport: (id: string) => void;\r\n};\r\n\r\n/** A `Row` reports its own `state` into the nearest `Column` through this. */\r\nconst RowAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\n/** `Column` reports its own aggregated state up through this — `SelectionViewer` provides it and\r\n * merges whatever's reported into its own selectionState resolution, with zero extra wiring. */\r\nconst SelectionViewerAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\nfunction computeAggregateState(states: SelectionState[]): SelectionState {\r\n if (states.length === 0) return \"initial\";\r\n if (states.some((s) => s === \"data\")) return \"data\";\r\n if (states.some((s) => s === \"loading\")) return \"loading\";\r\n if (states.every((s) => s === \"empty\")) return \"empty\";\r\n if (states.some((s) => s === \"error\")) return \"error\";\r\n return \"initial\";\r\n}\r\n\r\n// ==================== Types ====================\r\ntype Padding = {\r\n l: string;\r\n r: string;\r\n t: string;\r\n b: string;\r\n};\r\n\r\ntype SnapPoint = number;\r\n\r\ntype SelectionState = \"loading\" | \"empty\" | \"error\" | \"data\" | \"initial\";\r\n\r\n\r\ntype TitleProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n containerClass?: string;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype SearchProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n background?: string;\r\n prefixIcon?: React.ReactNode;\r\n suffixIcon?: React.ReactNode;\r\n clearIcon?: React.ReactNode;\r\n backIcon?: React.ReactNode;\r\n prefixGap?: string;\r\n suffixGap?: string;\r\n padding?: Padding;\r\n autoFocus?: boolean;\r\n inputStyle?: React.CSSProperties;\r\n containerStyle?: React.CSSProperties;\r\n onChange?: (value: string) => void;\r\n onFocus?: () => void;\r\n onBlur?: () => void;\r\n};\r\n\r\ntype LoadingProps = {\r\n view: React.ReactNode;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype NoResultProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype ErrorProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype CancelButtonProps = {\r\n text?: string;\r\n view: React.ReactNode;\r\n position?: \"left\" | \"right\";\r\n style?: React.CSSProperties;\r\n onClick?: () => void;\r\n};\r\n\r\ntype LayoutProps = {\r\n gapBetweenHandleAndTitle?: string;\r\n gapBetweenTitleAndSearch?: string;\r\n gapBetweenSearchAndContent?: string;\r\n backgroundColor?: string;\r\n handleColor?: string;\r\n handleWidth?: string;\r\n fullScreenSearchBackground?: string;\r\n fullScreenSearchHeaderStyle?: React.CSSProperties;\r\n maxWidth?: string;\r\n};\r\n\r\ntype SelectionViewerProps = {\r\n id?: string;\r\n isOpen: boolean;\r\n backDrop?: boolean;\r\n onClose: () => void;\r\n titleProp: TitleProps;\r\n searchProp?: SearchProps;\r\n loadingProp?: LoadingProps;\r\n noResultProp?: NoResultProps;\r\n errorProp?: ErrorProps;\r\n cancelButton?: CancelButtonProps;\r\n layoutProp?: LayoutProps;\r\n childrenDirection?: \"vertical\" | \"horizontal\";\r\n children?: React.ReactNode;\r\n onPaginate?: () => boolean | Promise<boolean>;\r\n snapPoints?: SnapPoint[];\r\n initialSnap?: number;\r\n unmountOnClose?: boolean;\r\n zIndex?: number;\r\n /**\r\n * Accessible name for the sheet, announced when it opens.\r\n *\r\n * A modal with no name is announced simply as \"dialog\", which tells a screen-reader user that\r\n * something has taken over the screen and nothing at all about what.\r\n */\r\n ariaLabel?: string;\r\n maxHeight?: string;\r\n minHeight?: string;\r\n selectionState?: SelectionState;\r\n closeThreshold?: number;\r\n};\r\n\r\n// ==================== Styles ====================\r\nconst getStyles = (id: string) => `\r\n#${id} .selection-viewer-header {\r\n padding: 0px;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-drag-handle {\r\n height: 5px;\r\n border-radius: 3px;\r\n margin-top: 16px;\r\n}\r\n\r\n#${id} .selection-viewer-container {\r\n display: flex;\r\n align-items: flex-start;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-title {\r\n margin: 0px;\r\n font-size: 18px;\r\n font-weight: 600;\r\n padding: 0px 16px 0px 16px;\r\n word-break: break-word; /* break long words */\r\n white-space: normal; /* allow wrapping */\r\n}\r\n\r\n#${id} .selection-viewer-search {\r\n display: flex;\r\n align-items: center;\r\n margin: 16px 16px 4px 16px;\r\n border-radius: 12px;\r\n box-sizing: border-box;\r\n border: 1px solid rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n#${id} .selection-viewer-search-input {\r\n flex: 1;\r\n border: none;\r\n background: transparent;\r\n padding: 12px 8px;\r\n outline: none;\r\n font-size: 16px !important;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-content {\r\n overflow-y: auto;\r\n -webkit-overflow-scrolling: touch;\r\n flex: 1;\r\n min-height: 0;\r\n}\r\n\r\n#${id} .selection-viewer-content.vertical {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n#${id} .selection-viewer-content.horizontal {\r\n display: flex;\r\n flex-direction: row;\r\n gap: 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n}\r\n\r\n#${id} .selection-viewer-no-results,\r\n#${id} .selection-viewer-error,\r\n#${id} .selection-viewer-loading {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n min-height: 120px;\r\n}\r\n\r\n#${id} .selection-viewer-default-no-results {\r\n color: #666;\r\n font-size: 14px;\r\n}\r\n\r\n#${id} .selection-viewer-default-error {\r\n color: red;\r\n font-size: 14px;\r\n}\r\n\r\n/* Full screen search mode */\r\n#${id} .selection-viewer-fullscreen-search {\r\n// position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n z-index: 10;\r\n// padding-top: env(safe-area-inset-top);\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-right: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-left: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n/* React Modal Sheet overrides */\r\n#${id} .react-modal-sheet-container {\r\n max-width: 500px;\r\n margin: 0 auto;\r\n border-top-left-radius: 16px;\r\n border-top-right-radius: 16px;\r\n}\r\n\r\n#${id} .react-modal-sheet-backdrop {\r\n background-color: rgba(0, 0, 0, 0.5) !important;\r\n pointer-events: auto !important;\r\n}\r\n\r\n#${id} .react-modal-sheet-content {\r\n padding: 0 0px 0px 0px;\r\n height: 100%;\r\n}\r\n\r\n\r\n/* Mobile full-width behavior */\r\n@media (max-width: 500px) {\r\n #${id} .react-modal-sheet-container {\r\n max-width: 100%;\r\n border-radius: 0;\r\n }\r\n}\r\n\r\n/* Prevent iOS zooming */\r\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\r\n #${id} .selection-viewer-search-input {\r\n font-size: 16px !important;\r\n }\r\n}\r\n`;\r\n\r\n// ==================== Hook to inject CSS per instance ====================\r\nconst useInjectStyles = (id: string) => {\r\n useEffect(() => {\r\n const styleId = `selection-viewer-styles-${id}`;\r\n let styleTag = document.getElementById(styleId) as HTMLStyleElement | null;\r\n\r\n if (!styleTag) {\r\n styleTag = document.createElement(\"style\");\r\n styleTag.id = styleId;\r\n styleTag.innerHTML = getStyles(id);\r\n document.head.appendChild(styleTag);\r\n }\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (styleTag && document.head.contains(styleTag)) {\r\n document.head.removeChild(styleTag);\r\n }\r\n };\r\n }, [id]);\r\n};\r\n\r\n// ==================== Component ====================\r\n/**\r\n * Escape closes the viewer, and Tab stays inside it.\r\n *\r\n * The viewer covers the screen, so what is behind it is not available — but nothing said so to the\r\n * keyboard. Tab walked out of the option list into the page underneath, where a person was\r\n * operating controls they could not see, and Escape did nothing at all, which is the one key\r\n * everybody reaches for to get out of a picker.\r\n *\r\n * Deliberately a private copy rather than an import from a sibling package: every library here\r\n * stands alone, and a shared helper between two of them is a dependency the consumer did not ask\r\n * for. Takes the container's `id` rather than a ref, because the sheet element belongs to the\r\n * underlying modal-sheet component; looking it up when a key is pressed finds it however that\r\n * component chooses to mount it. Focusables are re-queried on every Tab, since the option list\r\n * changes as the consumer filters it and a list captured on open is a list of dead elements.\r\n */\r\nconst useModalKeys = (isOpen: boolean, onClose: () => void, containerId: string) => {\r\n useEffect(() => {\r\n if (!isOpen || typeof document === \"undefined\") return;\r\n\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n onClose();\r\n return;\r\n }\r\n if (e.key !== \"Tab\") return;\r\n\r\n const focusable = document.getElementById(containerId)?.querySelectorAll<HTMLElement>(\r\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]),' +\r\n ' textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\r\n );\r\n if (!focusable || focusable.length === 0) return;\r\n\r\n const first = focusable[0];\r\n const last = focusable[focusable.length - 1];\r\n\r\n if (e.shiftKey && document.activeElement === first) {\r\n e.preventDefault();\r\n last.focus();\r\n } else if (!e.shiftKey && document.activeElement === last) {\r\n e.preventDefault();\r\n first.focus();\r\n }\r\n };\r\n\r\n document.addEventListener(\"keydown\", onKeyDown);\r\n return () => document.removeEventListener(\"keydown\", onKeyDown);\r\n }, [isOpen, onClose, containerId]);\r\n};\r\n\r\nconst SelectionViewer: React.FC<SelectionViewerProps> = ({\r\n id: providedId,\r\n isOpen,\r\n backDrop = true,\r\n onClose,\r\n titleProp,\r\n searchProp,\r\n loadingProp,\r\n noResultProp,\r\n errorProp,\r\n cancelButton,\r\n layoutProp,\r\n childrenDirection = \"vertical\",\r\n children,\r\n onPaginate,\r\n snapPoints = [0, 1],\r\n initialSnap = 1,\r\n unmountOnClose = true,\r\n zIndex = 1000,\r\n ariaLabel,\r\n maxHeight = \"90dvh\",\r\n minHeight = \"65dvh\",\r\n selectionState: selectionStateProp = \"initial\",\r\n closeThreshold = 0.2,\r\n}) => {\r\n const [id] = useState(() => providedId || `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n const [searchValue, setSearchValue] = useState(\"\");\r\n const [isSearchFocused, setIsSearchFocused] = useState(false);\r\n const [keyboardHeight, setKeyboardHeight] = useState(0);\r\n const [inputKey, setInputKey] = useState(0);\r\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false);\r\n const isPaginating = useRef(false);\r\n const searchInputRef = useRef<HTMLInputElement>(null);\r\n const sheetRef = useRef<any>(null);\r\n const headerRef = useRef<HTMLDivElement>(null);\r\n\r\n useInjectStyles(id);\r\n // Escape closes the viewer and Tab stays inside it — see useModalKeys.\r\n useModalKeys(isOpen, onClose, id);\r\n\r\n // Descendant sections (a Column, or anything else) can report a cumulative state up through this —\r\n // starts empty, so a plain SelectionViewer with no Row/Column children behaves exactly as before.\r\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\r\n const reportAggregate = useCallback((reporterId: string, state: SelectionState) => {\r\n setReportedStates((prev) => {\r\n const next = new Map(prev);\r\n next.set(reporterId, state);\r\n return next;\r\n });\r\n }, []);\r\n const unreportAggregate = useCallback((reporterId: string) => {\r\n setReportedStates((prev) => {\r\n if (!prev.has(reporterId)) return prev;\r\n const next = new Map(prev);\r\n next.delete(reporterId);\r\n return next;\r\n });\r\n }, []);\r\n const aggregateReporterValue = useMemo(\r\n () => ({ report: reportAggregate, unreport: unreportAggregate }),\r\n [reportAggregate, unreportAggregate]\r\n );\r\n const reportedAggregate =\r\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : null;\r\n const isComposed = reportedAggregate !== null;\r\n\r\n // Precedence: an explicit `selectionState` prop always wins (matches today's exact behaviour for\r\n // any consumer not using Row/Column) -> then a reported Column aggregate, if one exists -> \"initial\".\r\n const selectionState =\r\n selectionStateProp !== \"initial\" ? selectionStateProp : reportedAggregate ?? \"initial\";\r\n\r\n // Track keyboard height\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || !window.visualViewport) return;\r\n\r\n const handleResize = () => {\r\n const vp = window.visualViewport!;\r\n const kbHeight = window.innerHeight - vp.height;\r\n setKeyboardHeight(kbHeight > 0 ? kbHeight : 0);\r\n };\r\n\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n window.visualViewport.addEventListener('scroll', handleResize);\r\n\r\n return () => {\r\n window.visualViewport?.removeEventListener('resize', handleResize);\r\n window.visualViewport?.removeEventListener('scroll', handleResize);\r\n };\r\n }, []);\r\n\r\n // Auto-focus on search\r\n useEffect(() => {\r\n if (!isOpen) {\r\n searchInputRef.current?.blur();\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n setShouldAutoFocus(false);\r\n return;\r\n }\r\n }, [isOpen, searchProp?.autoFocus]);\r\n\r\n const handleOpenEnd = useCallback(() => {\r\n if (searchProp?.autoFocus && searchInputRef.current) {\r\n setInputKey(prev => prev + 1);\r\n setShouldAutoFocus(true);\r\n searchInputRef.current.focus();\r\n searchInputRef.current.click();\r\n }\r\n }, [searchProp?.autoFocus]);\r\n\r\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const value = e.target.value;\r\n setSearchValue(value);\r\n searchProp?.onChange?.(value);\r\n };\r\n\r\n const handleSearchFocus = () => {\r\n setIsSearchFocused(true);\r\n searchProp?.onFocus?.();\r\n requestAnimationFrame(() => {\r\n searchInputRef.current?.focus();\r\n });\r\n };\r\n\r\n const handleSearchBlur = () => {\r\n searchProp?.onBlur?.();\r\n };\r\n\r\n const handleBackFromSearch = () => {\r\n setIsSearchFocused(false);\r\n if (searchInputRef.current) {\r\n searchInputRef.current.blur();\r\n }\r\n };\r\n\r\n const clearSearch = () => {\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n if (searchInputRef.current) {\r\n searchInputRef.current.focus();\r\n }\r\n };\r\n\r\n const handleScroll = useCallback(\r\n async (e: React.UIEvent<HTMLDivElement>) => {\r\n if (isPaginating.current || !onPaginate) return;\r\n\r\n const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;\r\n const isNearBottom = scrollHeight - scrollTop <= clientHeight * 1.2;\r\n\r\n if (isNearBottom) {\r\n isPaginating.current = true;\r\n const hasMore = await onPaginate();\r\n if (!hasMore) {\r\n isPaginating.current = false;\r\n } else {\r\n setTimeout(() => {\r\n isPaginating.current = false;\r\n }, 500);\r\n }\r\n }\r\n },\r\n [onPaginate]\r\n );\r\n\r\n if (!isOpen && unmountOnClose) return null;\r\n\r\n return (\r\n <SelectionViewerAggregateContext.Provider value={aggregateReporterValue}>\r\n <Sheet\r\n ref={sheetRef}\r\n isOpen={isOpen}\r\n onClose={onClose}\r\n detent=\"content\"\r\n style={{ zIndex }}\r\n maxHeight={maxHeight}\r\n onOpenEnd={handleOpenEnd}\r\n >\r\n <Sheet.Container\r\n id={id}\r\n // Announced as a modal dialog. Without this a screen reader reads the sheet as one more\r\n // region of the page and gives no indication that what is behind it is unavailable — and\r\n // an automated check for an open dialog finds nothing at all.\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-label={ariaLabel}\r\n style={{\r\n maxHeight: maxHeight,\r\n minHeight: isSearchFocused ? \"100dvh\" : minHeight,\r\n maxWidth: layoutProp?.maxWidth ?? '800px',\r\n margin: \"0 auto\",\r\n width: \"100%\",\r\n left: 0,\r\n right: 0,\r\n paddingBottom: \"calc(0px + env(safe-area-inset-bottom))\",\r\n background: isSearchFocused\r\n ? layoutProp?.fullScreenSearchBackground || layoutProp?.backgroundColor\r\n : layoutProp?.backgroundColor,\r\n borderTopLeftRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n borderTopRightRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n }}\r\n >\r\n {isSearchFocused ? (\r\n <Sheet.Header>\r\n <div\r\n className=\"selection-viewer-fullscreen-search\"\r\n style={layoutProp?.fullScreenSearchHeaderStyle}\r\n >\r\n <div className=\"selection-viewer-search\" style={{\r\n ...searchProp?.containerStyle,\r\n background: searchProp?.background,\r\n padding: searchProp?.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"16px\"\r\n }}>\r\n <button\r\n className=\"selection-viewer-search-back-button\"\r\n onClick={handleBackFromSearch}\r\n aria-label=\"Exit search mode\"\r\n >\r\n {searchProp?.backIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M15 18L9 12L15 6\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp?.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp?.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp?.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n >\r\n {searchProp?.clearIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </Sheet.Header>\r\n ) : (\r\n <Sheet.Header>\r\n <div className=\"selection-viewer-header\">\r\n {/* Cancel button left */}\r\n {cancelButton?.position === \"left\" && (\r\n <button\r\n style={{\r\n position: \"absolute\",\r\n left: \"0px\",\r\n top: \"8px\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Drag handle */}\r\n {!isSearchFocused && (\r\n <div\r\n className=\"selection-viewer-drag-handle\"\r\n style={{\r\n background: layoutProp?.handleColor || \"#ccc\",\r\n width: layoutProp?.handleWidth || \"40px\",\r\n marginBottom: layoutProp?.gapBetweenHandleAndTitle || \"12px\",\r\n }}\r\n />\r\n )}\r\n\r\n {/* Cancel button right */}\r\n {cancelButton?.position === \"right\" && (\r\n <button\r\n style={{\r\n position: \"absolute\",\r\n right: \"0px\",\r\n top: \"8px\",\r\n border: \"none\",\r\n backgroundColor: \"transparent\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Title */}\r\n <div className={titleProp.containerClass || \"selection-viewer-container\"}>\r\n <h2\r\n id={`${id}-title`}\r\n className={titleProp.className || \"selection-viewer-title\"}\r\n style={{\r\n marginBottom: layoutProp?.gapBetweenTitleAndSearch || \"8px\",\r\n color: titleProp?.textColor || 'black',\r\n ...titleProp.style\r\n }}\r\n >\r\n {titleProp.text}\r\n </h2>\r\n </div>\r\n </div>\r\n\r\n {/* Search */}\r\n {searchProp && (\r\n <div\r\n className=\"selection-viewer-search\"\r\n style={{\r\n background: searchProp.background,\r\n padding: searchProp.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"8px 16px\",\r\n marginBottom: layoutProp?.gapBetweenSearchAndContent,\r\n ...searchProp.containerStyle\r\n }}\r\n >\r\n {searchProp.prefixIcon && (\r\n <span style={{ marginRight: searchProp.prefixGap || \"8px\" }}>\r\n {searchProp.prefixIcon}\r\n </span>\r\n )}\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n style={{ marginLeft: searchProp.suffixGap || \"8px\" }}\r\n >\r\n {searchProp.clearIcon || searchProp.suffixIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n {!searchValue && searchProp.suffixIcon && (\r\n <span style={{ marginLeft: searchProp.suffixGap || \"8px\" }}>\r\n {searchProp.suffixIcon}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n </Sheet.Header>\r\n )}\r\n\r\n <Sheet.Content>\r\n <div\r\n className={`selection-viewer-content ${childrenDirection}`}\r\n onScroll={onPaginate ? handleScroll : undefined}\r\n style={{\r\n paddingTop: isSearchFocused ? layoutProp?.gapBetweenSearchAndContent : '0',\r\n paddingBottom: keyboardHeight > 0\r\n ? `${keyboardHeight + 16}px`\r\n : '16px',\r\n }}\r\n >\r\n {/* Show children first, then loading at bottom */}\r\n {React.Children.count(children) > 0 ? (\r\n <>\r\n {children}\r\n {selectionState === \"loading\" && (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n )}\r\n {/* Composed mode: a Column/Row descendant reports its own state, which can only ever be\r\n \"empty\"/\"error\" here since the child count > 0 branch is unconditional on a literal\r\n <Column> being present. Layer the outer view alongside the (visually empty) children\r\n rather than replacing them — a Column/Row must stay mounted to keep reporting. */}\r\n {isComposed && selectionState === \"empty\" && (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n {isComposed && selectionState === \"error\" && (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </>\r\n ) : (selectionState === \"empty\" || (React.Children.count(children) <= 0 && (selectionState != \"loading\" && selectionState != \"error\"))) ? (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : selectionState === \"loading\" ? (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n ) : (selectionState === \"error\") ? (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : null}\r\n </div>\r\n </Sheet.Content>\r\n </Sheet.Container>\r\n <Sheet.Backdrop onTap={backDrop ? onClose : undefined} />\r\n </Sheet>\r\n </SelectionViewerAggregateContext.Provider>\r\n );\r\n};\r\n\r\n// ==================== Controller Hook ====================\r\ntype Operation = {\r\n open: () => void;\r\n close: () => void;\r\n toggle: () => void;\r\n setSelectionState: (val: SelectionState) => void;\r\n};\r\n\r\nconst useSelectionController = (initialSelectionState?: SelectionState): [\r\n string,\r\n Operation,\r\n boolean,\r\n SelectionState\r\n] => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [selectionState, setSelectionState] = useState(initialSelectionState || 'initial');\r\n const [selectionId] = useState(() => `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n\r\n const operations = useMemo<Operation>(() => ({\r\n open: () => setIsOpen(true),\r\n close: () => setIsOpen(false),\r\n toggle: () => setIsOpen((prev) => !prev),\r\n setSelectionState\r\n }), [setSelectionState]);\r\n\r\n return [selectionId, operations, isOpen, selectionState];\r\n};\r\n\r\nexport { SelectionViewer, useSelectionController, RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState };\r\nexport type {\r\n SelectionViewerProps,\r\n SelectionState,\r\n TitleProps,\r\n SearchProps,\r\n LoadingProps,\r\n NoResultProps,\r\n ErrorProps,\r\n CancelButtonProps,\r\n LayoutProps,\r\n Padding,\r\n SnapPoint,\r\n AggregateReporter,\r\n};\r\nexport default SelectionViewer;\r\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { RowAggregateContext } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type RowProps = {\n id?: string;\n /** Consumer-owned — SelectionViewer has never owned fetch/filter state, so unlike\n * search-viewer's Row this isn't internally computed. Mirrors how `selectionState`\n * is already a prop on SelectionViewer itself today. Defaults to \"data\": if you\n * render children without wiring this, we assume what you rendered IS the data. */\n state?: SelectionState;\n /** Called when this Row is scrolled horizontally near its end. Return (or resolve to)\n * `true` if more data may follow (keeps the pagination trigger armed), `false` once\n * there's nothing left to fetch — mirrors SelectionViewer's own `onPaginate` contract. */\n onPaginate?: () => boolean | Promise<boolean>;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A horizontally-scrolling, independently-paginating section — the Row/Column\n * equivalent for `SelectionViewer`. No shared code with `@academix-admin/search-viewer`'s\n * Row (Library Charter: packages stay mutually independent) — this one has no\n * query/debounce/cache engine of its own since `SelectionViewer` never had one either;\n * the consumer owns fetching/filtering and just tells this Row what `state` it's in. */\nfunction Row({ id: providedId, state = \"data\", onPaginate, className, style, children }: RowProps) {\n const aggregateReporter = React.useContext(RowAggregateContext);\n const [rowId] = useState(() => providedId || `row-${Math.random().toString(36).substring(2, 11)}`);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const isPaginating = useRef(false);\n\n const handleScroll = useCallback(async () => {\n const el = containerRef.current;\n if (!el || isPaginating.current || !onPaginate) return;\n\n // Same \"near the end\" threshold as SelectionViewer's own vertical pagination trigger, adapted\n // to horizontal scroll metrics since a Row scrolls sideways.\n const { scrollLeft, scrollWidth, clientWidth } = el;\n if (scrollWidth - scrollLeft > clientWidth * 1.2) return;\n\n isPaginating.current = true;\n const hasMore = await onPaginate();\n if (!hasMore) {\n isPaginating.current = false;\n } else {\n setTimeout(() => {\n isPaginating.current = false;\n }, 500);\n }\n }, [onPaginate]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el || !onPaginate) return;\n el.addEventListener(\"scroll\", handleScroll);\n return () => el.removeEventListener(\"scroll\", handleScroll);\n }, [handleScroll, onPaginate]);\n\n useEffect(() => {\n aggregateReporter?.report(rowId, state);\n return () => aggregateReporter?.unreport(rowId);\n }, [aggregateReporter, rowId, state]);\n\n return (\n <div\n ref={containerRef}\n className={className ? `selection-viewer-row ${className}` : \"selection-viewer-row\"}\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n gap: \"8px\",\n overflowX: \"auto\",\n overflowY: \"hidden\",\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n\nRow.displayName = \"Row\";\n\nexport { Row };\n","import React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type ColumnProps = {\n id?: string;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A vertical arrangement of `Row`s (or other content) — the explicit, composable\n * equivalent of today's flat `children` list. Its default layout is deliberately\n * identical to the existing `.selection-viewer-content.vertical` rendering\n * (`flex-direction: column, gap: 8px`), so today's flat usage is, unchanged, \"an\n * implicit Column with no Rows.\"\n *\n * Provides the `RowAggregateContext` its `Row` children report into, computes ONE\n * cumulative state from everything reported, and is itself a reporter one level up:\n * nested inside another `Column` it reports through that Column's `RowAggregateContext`\n * (behaving like a Row); at the top level it reports through `SelectionViewerAggregateContext`,\n * which `SelectionViewer` provides — this drives the outer sheet's loading/empty/error\n * views automatically with zero manual wiring, and lets Columns nest arbitrarily deep. */\nfunction Column({ id: providedId, className, style, children }: ColumnProps) {\n const [columnId] = useState(\n () => providedId || `column-${Math.random().toString(36).substring(2, 11)}`\n );\n\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\n const report = useCallback((id: string, state: SelectionState) => {\n setReportedStates((prev) => {\n const next = new Map(prev);\n next.set(id, state);\n return next;\n });\n }, []);\n const unreport = useCallback((id: string) => {\n setReportedStates((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n const rowAggregateValue = useMemo(() => ({ report, unreport }), [report, unreport]);\n\n const aggregateState =\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : \"initial\";\n\n const parentRowAggregate = React.useContext(RowAggregateContext);\n const selectionViewerAggregate = React.useContext(SelectionViewerAggregateContext);\n const upstreamReporter = parentRowAggregate ?? selectionViewerAggregate;\n\n useEffect(() => {\n if (!upstreamReporter) return;\n upstreamReporter.report(columnId, aggregateState);\n return () => upstreamReporter.unreport(columnId);\n }, [upstreamReporter, columnId, aggregateState]);\n\n return (\n <RowAggregateContext.Provider value={rowAggregateValue}>\n <div\n className={className ? `selection-viewer-column ${className}` : \"selection-viewer-column\"}\n style={{ display: \"flex\", flexDirection: \"column\", gap: \"8px\", ...style }}\n >\n {children}\n </div>\n </RowAggregateContext.Provider>\n );\n}\n\nColumn.displayName = \"Column\";\n\nexport { Column };\n"]}
1
+ {"version":3,"sources":["../src/SelectionViewer.tsx","../src/Row.tsx","../src/Column.tsx"],"names":["React","useState","useRef","useCallback","useEffect","jsx","useMemo"],"mappings":"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","file":"index.js","sourcesContent":["import React, { useState, useEffect, useCallback, useRef, useMemo } from \"react\";\r\nimport { Sheet } from \"@academix-admin/modal-sheet\";\r\n\r\n// ==================== Aggregation (Row/Column) ====================\r\n// Independent from @academix-admin/search-viewer's equivalent (Library Charter: packages stay\r\n// mutually independent) — same shape, duplicated intentionally rather than shared.\r\n\r\ntype AggregateReporter = {\r\n report: (id: string, state: SelectionState) => void;\r\n unreport: (id: string) => void;\r\n};\r\n\r\n/** A `Row` reports its own `state` into the nearest `Column` through this. */\r\nconst RowAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\n/** `Column` reports its own aggregated state up through this — `SelectionViewer` provides it and\r\n * merges whatever's reported into its own selectionState resolution, with zero extra wiring. */\r\nconst SelectionViewerAggregateContext = React.createContext<AggregateReporter | null>(null);\r\n\r\nfunction computeAggregateState(states: SelectionState[]): SelectionState {\r\n if (states.length === 0) return \"initial\";\r\n if (states.some((s) => s === \"data\")) return \"data\";\r\n if (states.some((s) => s === \"loading\")) return \"loading\";\r\n if (states.every((s) => s === \"empty\")) return \"empty\";\r\n if (states.some((s) => s === \"error\")) return \"error\";\r\n return \"initial\";\r\n}\r\n\r\n// ==================== Types ====================\r\ntype Padding = {\r\n l: string;\r\n r: string;\r\n t: string;\r\n b: string;\r\n};\r\n\r\ntype SnapPoint = number;\r\n\r\ntype SelectionState = \"loading\" | \"empty\" | \"error\" | \"data\" | \"initial\";\r\n\r\n\r\ntype TitleProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n containerClass?: string;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype SearchProps = {\r\n text: string;\r\n textColor: string;\r\n className?: string;\r\n background?: string;\r\n prefixIcon?: React.ReactNode;\r\n suffixIcon?: React.ReactNode;\r\n clearIcon?: React.ReactNode;\r\n backIcon?: React.ReactNode;\r\n prefixGap?: string;\r\n suffixGap?: string;\r\n padding?: Padding;\r\n autoFocus?: boolean;\r\n inputStyle?: React.CSSProperties;\r\n containerStyle?: React.CSSProperties;\r\n onChange?: (value: string) => void;\r\n onFocus?: () => void;\r\n onBlur?: () => void;\r\n};\r\n\r\ntype LoadingProps = {\r\n view: React.ReactNode;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype NoResultProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype ErrorProps = {\r\n view: React.ReactNode;\r\n text?: string;\r\n padding?: Padding;\r\n style?: React.CSSProperties;\r\n};\r\n\r\ntype CancelButtonProps = {\r\n text?: string;\r\n view: React.ReactNode;\r\n position?: \"left\" | \"right\";\r\n style?: React.CSSProperties;\r\n onClick?: () => void;\r\n /**\r\n * What a screen reader calls it. Defaults to \"Close\".\r\n *\r\n * A button whose only content is an icon has no accessible name at all, so it was announced as\r\n * just \"button\" — the one control that dismisses the sheet, and nothing said so.\r\n */\r\n ariaLabel?: string;\r\n};\r\n\r\ntype LayoutProps = {\r\n gapBetweenHandleAndTitle?: string;\r\n gapBetweenTitleAndSearch?: string;\r\n gapBetweenSearchAndContent?: string;\r\n /**\r\n * How far the rows are set in from the sides. Defaults to `16px`, matching the search box.\r\n *\r\n * The content had no inset while everything above it had 16px, so a list ran flush into the\r\n * sides of the screen under a search box that did not. Pass `0px` for rows that should reach\r\n * the edges.\r\n */\r\n contentPadding?: string;\r\n backgroundColor?: string;\r\n handleColor?: string;\r\n handleWidth?: string;\r\n fullScreenSearchBackground?: string;\r\n fullScreenSearchHeaderStyle?: React.CSSProperties;\r\n maxWidth?: string;\r\n};\r\n\r\ntype SelectionViewerProps = {\r\n id?: string;\r\n isOpen: boolean;\r\n backDrop?: boolean;\r\n onClose: () => void;\r\n titleProp: TitleProps;\r\n searchProp?: SearchProps;\r\n loadingProp?: LoadingProps;\r\n noResultProp?: NoResultProps;\r\n errorProp?: ErrorProps;\r\n cancelButton?: CancelButtonProps;\r\n layoutProp?: LayoutProps;\r\n childrenDirection?: \"vertical\" | \"horizontal\";\r\n children?: React.ReactNode;\r\n onPaginate?: () => boolean | Promise<boolean>;\r\n snapPoints?: SnapPoint[];\r\n initialSnap?: number;\r\n unmountOnClose?: boolean;\r\n zIndex?: number;\r\n /**\r\n * Accessible name for the sheet, announced when it opens.\r\n *\r\n * A modal with no name is announced simply as \"dialog\", which tells a screen-reader user that\r\n * something has taken over the screen and nothing at all about what.\r\n */\r\n ariaLabel?: string;\r\n maxHeight?: string;\r\n minHeight?: string;\r\n selectionState?: SelectionState;\r\n closeThreshold?: number;\r\n};\r\n\r\n// ==================== Styles ====================\r\nconst getStyles = (id: string) => `\r\n#${id} .selection-viewer-header {\r\n padding: 0px;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n position: relative;\r\n width: 100%;\r\n}\r\n\r\n/*\r\n * The close button, with a target a thumb can find.\r\n *\r\n * It sat at right: 0, top: 8 with no padding at all, so the icon was flush against the sheet's\r\n * edge and the only thing that could be tapped was the glyph itself — a target well under half\r\n * what a finger needs, in the corner of the screen where a thumb is least accurate. Inset by 4px\r\n * and padded out to 44px square, so the icon still reads as sitting in the corner while the\r\n * hittable area reaches the edges.\r\n *\r\n * The cancelButton.style prop is still spread last at the call site, so a consumer that was\r\n * overriding any of this keeps overriding it. (No backticks in here: this whole block lives\r\n * inside a template literal, and one would end the string.)\r\n */\r\n#${id} .selection-viewer-cancel {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 44px;\r\n min-height: 44px;\r\n padding: 10px;\r\n border: none;\r\n background-color: transparent;\r\n color: inherit;\r\n cursor: pointer;\r\n -webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n#${id} .selection-viewer-drag-handle {\r\n height: 5px;\r\n border-radius: 3px;\r\n margin-top: 16px;\r\n}\r\n\r\n#${id} .selection-viewer-container {\r\n display: flex;\r\n align-items: flex-start;\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-title {\r\n margin: 0px;\r\n font-size: 18px;\r\n font-weight: 600;\r\n padding: 0px 16px 0px 16px;\r\n word-break: break-word; /* break long words */\r\n white-space: normal; /* allow wrapping */\r\n}\r\n\r\n#${id} .selection-viewer-search {\r\n display: flex;\r\n align-items: center;\r\n margin: 16px 16px 4px 16px;\r\n border-radius: 12px;\r\n box-sizing: border-box;\r\n border: 1px solid rgba(0, 0, 0, 0.1);\r\n}\r\n\r\n#${id} .selection-viewer-search-input {\r\n flex: 1;\r\n border: none;\r\n background: transparent;\r\n padding: 12px 8px;\r\n outline: none;\r\n font-size: 16px !important;\r\n width: 100%;\r\n}\r\n\r\n/*\r\n * The rows, set in from the edges like everything else in the sheet.\r\n *\r\n * The title and the search box have carried a 16px margin from the start; the content had none, so\r\n * a list of cards ran flush into the sides of the screen while the search box above it did not.\r\n * The layoutProp.contentPadding option overrides it for a consumer that wants its rows edge to\r\n * edge. (No backticks: this block is inside a template literal.)\r\n */\r\n#${id} .selection-viewer-content {\r\n overflow-y: auto;\r\n -webkit-overflow-scrolling: touch;\r\n flex: 1;\r\n min-height: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#${id} .selection-viewer-content.vertical {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 8px;\r\n}\r\n\r\n#${id} .selection-viewer-content.horizontal {\r\n display: flex;\r\n flex-direction: row;\r\n gap: 8px;\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n}\r\n\r\n#${id} .selection-viewer-no-results,\r\n#${id} .selection-viewer-error,\r\n#${id} .selection-viewer-loading {\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n min-height: 120px;\r\n}\r\n\r\n#${id} .selection-viewer-default-no-results {\r\n color: #666;\r\n font-size: 14px;\r\n}\r\n\r\n#${id} .selection-viewer-default-error {\r\n color: red;\r\n font-size: 14px;\r\n}\r\n\r\n/* Full screen search mode */\r\n#${id} .selection-viewer-fullscreen-search {\r\n// position: fixed;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n z-index: 10;\r\n// padding-top: env(safe-area-inset-top);\r\n width: 100%;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-right: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-back-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button {\r\n background: none;\r\n border: none;\r\n padding: 8px;\r\n margin-left: 4px;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n cursor: pointer;\r\n transition: opacity 0.2s;\r\n}\r\n\r\n#${id} .selection-viewer-search-clear-button:hover {\r\n opacity: 0.7;\r\n}\r\n\r\n/* React Modal Sheet overrides */\r\n#${id} .react-modal-sheet-container {\r\n max-width: 500px;\r\n margin: 0 auto;\r\n border-top-left-radius: 16px;\r\n border-top-right-radius: 16px;\r\n}\r\n\r\n#${id} .react-modal-sheet-backdrop {\r\n background-color: rgba(0, 0, 0, 0.5) !important;\r\n pointer-events: auto !important;\r\n}\r\n\r\n#${id} .react-modal-sheet-content {\r\n padding: 0 0px 0px 0px;\r\n height: 100%;\r\n}\r\n\r\n\r\n/* Mobile full-width behavior */\r\n@media (max-width: 500px) {\r\n #${id} .react-modal-sheet-container {\r\n max-width: 100%;\r\n border-radius: 0;\r\n }\r\n}\r\n\r\n/* Prevent iOS zooming */\r\n@media screen and (-webkit-min-device-pixel-ratio: 0) {\r\n #${id} .selection-viewer-search-input {\r\n font-size: 16px !important;\r\n }\r\n}\r\n`;\r\n\r\n// ==================== Hook to inject CSS per instance ====================\r\nconst useInjectStyles = (id: string) => {\r\n useEffect(() => {\r\n const styleId = `selection-viewer-styles-${id}`;\r\n let styleTag = document.getElementById(styleId) as HTMLStyleElement | null;\r\n\r\n if (!styleTag) {\r\n styleTag = document.createElement(\"style\");\r\n styleTag.id = styleId;\r\n styleTag.innerHTML = getStyles(id);\r\n document.head.appendChild(styleTag);\r\n }\r\n\r\n // Cleanup on unmount\r\n return () => {\r\n if (styleTag && document.head.contains(styleTag)) {\r\n document.head.removeChild(styleTag);\r\n }\r\n };\r\n }, [id]);\r\n};\r\n\r\n// ==================== Component ====================\r\n/**\r\n * Escape closes the viewer, and Tab stays inside it.\r\n *\r\n * The viewer covers the screen, so what is behind it is not available — but nothing said so to the\r\n * keyboard. Tab walked out of the option list into the page underneath, where a person was\r\n * operating controls they could not see, and Escape did nothing at all, which is the one key\r\n * everybody reaches for to get out of a picker.\r\n *\r\n * Deliberately a private copy rather than an import from a sibling package: every library here\r\n * stands alone, and a shared helper between two of them is a dependency the consumer did not ask\r\n * for. Takes the container's `id` rather than a ref, because the sheet element belongs to the\r\n * underlying modal-sheet component; looking it up when a key is pressed finds it however that\r\n * component chooses to mount it. Focusables are re-queried on every Tab, since the option list\r\n * changes as the consumer filters it and a list captured on open is a list of dead elements.\r\n */\r\nconst useModalKeys = (isOpen: boolean, onClose: () => void, containerId: string) => {\r\n useEffect(() => {\r\n if (!isOpen || typeof document === \"undefined\") return;\r\n\r\n const onKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n onClose();\r\n return;\r\n }\r\n if (e.key !== \"Tab\") return;\r\n\r\n const focusable = document.getElementById(containerId)?.querySelectorAll<HTMLElement>(\r\n 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]),' +\r\n ' textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])',\r\n );\r\n if (!focusable || focusable.length === 0) return;\r\n\r\n const first = focusable[0];\r\n const last = focusable[focusable.length - 1];\r\n\r\n if (e.shiftKey && document.activeElement === first) {\r\n e.preventDefault();\r\n last.focus();\r\n } else if (!e.shiftKey && document.activeElement === last) {\r\n e.preventDefault();\r\n first.focus();\r\n }\r\n };\r\n\r\n document.addEventListener(\"keydown\", onKeyDown);\r\n return () => document.removeEventListener(\"keydown\", onKeyDown);\r\n }, [isOpen, onClose, containerId]);\r\n};\r\n\r\nconst SelectionViewer: React.FC<SelectionViewerProps> = ({\r\n id: providedId,\r\n isOpen,\r\n backDrop = true,\r\n onClose,\r\n titleProp,\r\n searchProp,\r\n loadingProp,\r\n noResultProp,\r\n errorProp,\r\n cancelButton,\r\n layoutProp,\r\n childrenDirection = \"vertical\",\r\n children,\r\n onPaginate,\r\n snapPoints = [0, 1],\r\n initialSnap = 1,\r\n unmountOnClose = true,\r\n zIndex = 1000,\r\n ariaLabel,\r\n maxHeight = \"90dvh\",\r\n minHeight = \"65dvh\",\r\n selectionState: selectionStateProp = \"initial\",\r\n closeThreshold = 0.2,\r\n}) => {\r\n const [id] = useState(() => providedId || `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n const [searchValue, setSearchValue] = useState(\"\");\r\n const [isSearchFocused, setIsSearchFocused] = useState(false);\r\n const [keyboardHeight, setKeyboardHeight] = useState(0);\r\n const [inputKey, setInputKey] = useState(0);\r\n const [shouldAutoFocus, setShouldAutoFocus] = useState(false);\r\n const isPaginating = useRef(false);\r\n const searchInputRef = useRef<HTMLInputElement>(null);\r\n const sheetRef = useRef<any>(null);\r\n const headerRef = useRef<HTMLDivElement>(null);\r\n\r\n useInjectStyles(id);\r\n // Escape closes the viewer and Tab stays inside it — see useModalKeys.\r\n useModalKeys(isOpen, onClose, id);\r\n\r\n // Descendant sections (a Column, or anything else) can report a cumulative state up through this —\r\n // starts empty, so a plain SelectionViewer with no Row/Column children behaves exactly as before.\r\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\r\n const reportAggregate = useCallback((reporterId: string, state: SelectionState) => {\r\n setReportedStates((prev) => {\r\n const next = new Map(prev);\r\n next.set(reporterId, state);\r\n return next;\r\n });\r\n }, []);\r\n const unreportAggregate = useCallback((reporterId: string) => {\r\n setReportedStates((prev) => {\r\n if (!prev.has(reporterId)) return prev;\r\n const next = new Map(prev);\r\n next.delete(reporterId);\r\n return next;\r\n });\r\n }, []);\r\n const aggregateReporterValue = useMemo(\r\n () => ({ report: reportAggregate, unreport: unreportAggregate }),\r\n [reportAggregate, unreportAggregate]\r\n );\r\n const reportedAggregate =\r\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : null;\r\n const isComposed = reportedAggregate !== null;\r\n\r\n // Precedence: an explicit `selectionState` prop always wins (matches today's exact behaviour for\r\n // any consumer not using Row/Column) -> then a reported Column aggregate, if one exists -> \"initial\".\r\n const selectionState =\r\n selectionStateProp !== \"initial\" ? selectionStateProp : reportedAggregate ?? \"initial\";\r\n\r\n // Track keyboard height\r\n useEffect(() => {\r\n if (typeof window === 'undefined' || !window.visualViewport) return;\r\n\r\n const handleResize = () => {\r\n const vp = window.visualViewport!;\r\n const kbHeight = window.innerHeight - vp.height;\r\n setKeyboardHeight(kbHeight > 0 ? kbHeight : 0);\r\n };\r\n\r\n window.visualViewport.addEventListener('resize', handleResize);\r\n window.visualViewport.addEventListener('scroll', handleResize);\r\n\r\n return () => {\r\n window.visualViewport?.removeEventListener('resize', handleResize);\r\n window.visualViewport?.removeEventListener('scroll', handleResize);\r\n };\r\n }, []);\r\n\r\n // Auto-focus on search\r\n useEffect(() => {\r\n if (!isOpen) {\r\n searchInputRef.current?.blur();\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n setShouldAutoFocus(false);\r\n return;\r\n }\r\n }, [isOpen, searchProp?.autoFocus]);\r\n\r\n const handleOpenEnd = useCallback(() => {\r\n if (searchProp?.autoFocus && searchInputRef.current) {\r\n setInputKey(prev => prev + 1);\r\n setShouldAutoFocus(true);\r\n searchInputRef.current.focus();\r\n searchInputRef.current.click();\r\n }\r\n }, [searchProp?.autoFocus]);\r\n\r\n const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {\r\n const value = e.target.value;\r\n setSearchValue(value);\r\n searchProp?.onChange?.(value);\r\n };\r\n\r\n const handleSearchFocus = () => {\r\n setIsSearchFocused(true);\r\n searchProp?.onFocus?.();\r\n requestAnimationFrame(() => {\r\n searchInputRef.current?.focus();\r\n });\r\n };\r\n\r\n const handleSearchBlur = () => {\r\n searchProp?.onBlur?.();\r\n };\r\n\r\n const handleBackFromSearch = () => {\r\n setIsSearchFocused(false);\r\n if (searchInputRef.current) {\r\n searchInputRef.current.blur();\r\n }\r\n };\r\n\r\n const clearSearch = () => {\r\n setSearchValue(\"\");\r\n searchProp?.onChange?.(\"\");\r\n if (searchInputRef.current) {\r\n searchInputRef.current.focus();\r\n }\r\n };\r\n\r\n const handleScroll = useCallback(\r\n async (e: React.UIEvent<HTMLDivElement>) => {\r\n if (isPaginating.current || !onPaginate) return;\r\n\r\n const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;\r\n const isNearBottom = scrollHeight - scrollTop <= clientHeight * 1.2;\r\n\r\n if (isNearBottom) {\r\n isPaginating.current = true;\r\n const hasMore = await onPaginate();\r\n if (!hasMore) {\r\n isPaginating.current = false;\r\n } else {\r\n setTimeout(() => {\r\n isPaginating.current = false;\r\n }, 500);\r\n }\r\n }\r\n },\r\n [onPaginate]\r\n );\r\n\r\n if (!isOpen && unmountOnClose) return null;\r\n\r\n return (\r\n <SelectionViewerAggregateContext.Provider value={aggregateReporterValue}>\r\n <Sheet\r\n ref={sheetRef}\r\n isOpen={isOpen}\r\n onClose={onClose}\r\n detent=\"content\"\r\n style={{ zIndex }}\r\n maxHeight={maxHeight}\r\n onOpenEnd={handleOpenEnd}\r\n >\r\n <Sheet.Container\r\n id={id}\r\n // Announced as a modal dialog. Without this a screen reader reads the sheet as one more\r\n // region of the page and gives no indication that what is behind it is unavailable — and\r\n // an automated check for an open dialog finds nothing at all.\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-label={ariaLabel}\r\n style={{\r\n maxHeight: maxHeight,\r\n minHeight: isSearchFocused ? \"100dvh\" : minHeight,\r\n maxWidth: layoutProp?.maxWidth ?? '800px',\r\n margin: \"0 auto\",\r\n width: \"100%\",\r\n left: 0,\r\n right: 0,\r\n paddingBottom: \"calc(0px + env(safe-area-inset-bottom))\",\r\n background: isSearchFocused\r\n ? layoutProp?.fullScreenSearchBackground || layoutProp?.backgroundColor\r\n : layoutProp?.backgroundColor,\r\n borderTopLeftRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n borderTopRightRadius: isSearchFocused ? \"0px\" : \"16px\",\r\n }}\r\n >\r\n {isSearchFocused ? (\r\n <Sheet.Header>\r\n <div\r\n className=\"selection-viewer-fullscreen-search\"\r\n style={layoutProp?.fullScreenSearchHeaderStyle}\r\n >\r\n <div className=\"selection-viewer-search\" style={{\r\n ...searchProp?.containerStyle,\r\n background: searchProp?.background,\r\n padding: searchProp?.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"16px\"\r\n }}>\r\n <button\r\n className=\"selection-viewer-search-back-button\"\r\n onClick={handleBackFromSearch}\r\n aria-label=\"Exit search mode\"\r\n >\r\n {searchProp?.backIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M15 18L9 12L15 6\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp?.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp?.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp?.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n >\r\n {searchProp?.clearIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke={searchProp?.textColor || 'currentColor'} strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n </div>\r\n </Sheet.Header>\r\n ) : (\r\n <Sheet.Header>\r\n <div className=\"selection-viewer-header\">\r\n {/* Cancel button left */}\r\n {cancelButton?.position === \"left\" && (\r\n <button\r\n aria-label={cancelButton.ariaLabel || \"Close\"}\r\n className=\"selection-viewer-cancel\"\r\n style={{\r\n position: \"absolute\",\r\n left: \"4px\",\r\n top: \"4px\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Drag handle */}\r\n {!isSearchFocused && (\r\n <div\r\n className=\"selection-viewer-drag-handle\"\r\n style={{\r\n background: layoutProp?.handleColor || \"#ccc\",\r\n width: layoutProp?.handleWidth || \"40px\",\r\n marginBottom: layoutProp?.gapBetweenHandleAndTitle || \"12px\",\r\n }}\r\n />\r\n )}\r\n\r\n {/* Cancel button right */}\r\n {cancelButton?.position === \"right\" && (\r\n <button\r\n aria-label={cancelButton.ariaLabel || \"Close\"}\r\n className=\"selection-viewer-cancel\"\r\n style={{\r\n position: \"absolute\",\r\n right: \"4px\",\r\n top: \"4px\",\r\n ...cancelButton.style\r\n }}\r\n onClick={cancelButton.onClick || onClose}\r\n >\r\n {cancelButton.view || cancelButton.text || \"Cancel\"}\r\n </button>\r\n )}\r\n\r\n {/* Title */}\r\n <div className={titleProp.containerClass || \"selection-viewer-container\"}>\r\n <h2\r\n id={`${id}-title`}\r\n className={titleProp.className || \"selection-viewer-title\"}\r\n style={{\r\n marginBottom: layoutProp?.gapBetweenTitleAndSearch || \"8px\",\r\n color: titleProp?.textColor || 'black',\r\n ...titleProp.style\r\n }}\r\n >\r\n {titleProp.text}\r\n </h2>\r\n </div>\r\n </div>\r\n\r\n {/* Search */}\r\n {searchProp && (\r\n <div\r\n className=\"selection-viewer-search\"\r\n style={{\r\n background: searchProp.background,\r\n padding: searchProp.padding\r\n ? `${searchProp.padding.t} ${searchProp.padding.r} ${searchProp.padding.b} ${searchProp.padding.l}`\r\n : \"8px 16px\",\r\n marginBottom: layoutProp?.gapBetweenSearchAndContent,\r\n ...searchProp.containerStyle\r\n }}\r\n >\r\n {searchProp.prefixIcon && (\r\n <span style={{ marginRight: searchProp.prefixGap || \"8px\" }}>\r\n {searchProp.prefixIcon}\r\n </span>\r\n )}\r\n <input\r\n key={inputKey}\r\n ref={searchInputRef}\r\n type=\"text\"\r\n placeholder={searchProp.text}\r\n value={searchValue}\r\n onChange={handleSearchChange}\r\n className={searchProp.className || \"selection-viewer-search-input\"}\r\n style={{\r\n color: searchProp?.textColor,\r\n ...searchProp.inputStyle\r\n }}\r\n onFocus={handleSearchFocus}\r\n onBlur={handleSearchBlur}\r\n autoFocus={shouldAutoFocus}\r\n />\r\n {searchValue && (\r\n <button\r\n className=\"selection-viewer-search-clear-button\"\r\n onClick={clearSearch}\r\n aria-label=\"Clear search\"\r\n style={{ marginLeft: searchProp.suffixGap || \"8px\" }}\r\n >\r\n {searchProp.clearIcon || searchProp.suffixIcon || (\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path d=\"M18 6L6 18M6 6L18 18\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\r\n </svg>\r\n )}\r\n </button>\r\n )}\r\n {!searchValue && searchProp.suffixIcon && (\r\n <span style={{ marginLeft: searchProp.suffixGap || \"8px\" }}>\r\n {searchProp.suffixIcon}\r\n </span>\r\n )}\r\n </div>\r\n )}\r\n </Sheet.Header>\r\n )}\r\n\r\n <Sheet.Content>\r\n <div\r\n className={`selection-viewer-content ${childrenDirection}`}\r\n onScroll={onPaginate ? handleScroll : undefined}\r\n style={{\r\n paddingTop: isSearchFocused ? layoutProp?.gapBetweenSearchAndContent : '0',\r\n paddingBottom: keyboardHeight > 0\r\n ? `${keyboardHeight + 16}px`\r\n : '16px',\r\n /*\r\n * Set in from the edges, like everything else in the sheet.\r\n *\r\n * The title and the search box have carried 16px from the start and the content had\r\n * none, so a list of rows ran flush into the sides of the screen under a search box\r\n * that did not. Overridable for rows that genuinely want the full width.\r\n */\r\n paddingLeft: layoutProp?.contentPadding ?? '16px',\r\n paddingRight: layoutProp?.contentPadding ?? '16px',\r\n }}\r\n >\r\n {/* Show children first, then loading at bottom */}\r\n {React.Children.count(children) > 0 ? (\r\n <>\r\n {children}\r\n {selectionState === \"loading\" && (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n )}\r\n {/*\r\n Shown ALONGSIDE the children, not instead of them.\r\n\r\n This was guarded on composed mode — a Column/Row descendant reporting its own\r\n state — on the reasoning that only a composed sheet can have children and be\r\n empty at the same time. That is not true of the commonest arrangement there is:\r\n a consumer that wraps its rows in a single container. `React.Children.count` is\r\n then 1 whether the container holds fifty rows or none, so the empty branch below\r\n never ran and the sheet showed a blank white screen — at the exact moment\r\n somebody had searched for something that is not there, which is when the empty\r\n state is the only useful thing on screen.\r\n\r\n Layered rather than substituted, for the reason the composed case already had:\r\n a child that reports its own state must stay mounted to go on reporting. A\r\n consumer whose `selectionState` says \"empty\" is asserting there is nothing to\r\n show, so drawing its own view beside visually-empty children is what it asked\r\n for.\r\n */}\r\n {selectionState === \"empty\" && (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n {selectionState === \"error\" && (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n </>\r\n ) : (selectionState === \"empty\" || (React.Children.count(children) <= 0 && (selectionState != \"loading\" && selectionState != \"error\"))) ? (\r\n <div\r\n className=\"selection-viewer-no-results\"\r\n style={{\r\n padding: noResultProp?.padding\r\n ? `${noResultProp.padding.t} ${noResultProp.padding.r} ${noResultProp.padding.b} ${noResultProp.padding.l}`\r\n : \"16px\",\r\n ...noResultProp?.style\r\n }}\r\n >\r\n {noResultProp?.view || (\r\n <div className=\"selection-viewer-default-no-results\">\r\n {noResultProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : selectionState === \"loading\" ? (\r\n <div\r\n className=\"selection-viewer-loading\"\r\n style={{\r\n padding: loadingProp?.padding\r\n ? `${loadingProp.padding.t} ${loadingProp.padding.r} ${loadingProp.padding.b} ${loadingProp.padding.l}`\r\n : \"16px\",\r\n ...loadingProp?.style\r\n }}\r\n >\r\n {loadingProp?.view}\r\n </div>\r\n ) : (selectionState === \"error\") ? (\r\n <div\r\n className=\"selection-viewer-error\"\r\n style={{\r\n padding: errorProp?.padding\r\n ? `${errorProp.padding.t} ${errorProp.padding.r} ${errorProp.padding.b} ${errorProp.padding.l}`\r\n : \"16px\",\r\n ...errorProp?.style\r\n }}\r\n >\r\n {errorProp?.view || (\r\n <div className=\"selection-viewer-default-error\">\r\n {errorProp?.text || \"No results found\"}\r\n </div>\r\n )}\r\n </div>\r\n ) : null}\r\n </div>\r\n </Sheet.Content>\r\n </Sheet.Container>\r\n <Sheet.Backdrop onTap={backDrop ? onClose : undefined} />\r\n </Sheet>\r\n </SelectionViewerAggregateContext.Provider>\r\n );\r\n};\r\n\r\n// ==================== Controller Hook ====================\r\ntype Operation = {\r\n open: () => void;\r\n close: () => void;\r\n toggle: () => void;\r\n setSelectionState: (val: SelectionState) => void;\r\n};\r\n\r\nconst useSelectionController = (initialSelectionState?: SelectionState): [\r\n string,\r\n Operation,\r\n boolean,\r\n SelectionState\r\n] => {\r\n const [isOpen, setIsOpen] = useState(false);\r\n const [selectionState, setSelectionState] = useState(initialSelectionState || 'initial');\r\n const [selectionId] = useState(() => `selection-${Math.random().toString(36).substring(2, 11)}`);\r\n\r\n const operations = useMemo<Operation>(() => ({\r\n open: () => setIsOpen(true),\r\n close: () => setIsOpen(false),\r\n toggle: () => setIsOpen((prev) => !prev),\r\n setSelectionState\r\n }), [setSelectionState]);\r\n\r\n return [selectionId, operations, isOpen, selectionState];\r\n};\r\n\r\nexport { SelectionViewer, useSelectionController, RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState };\r\nexport type {\r\n SelectionViewerProps,\r\n SelectionState,\r\n TitleProps,\r\n SearchProps,\r\n LoadingProps,\r\n NoResultProps,\r\n ErrorProps,\r\n CancelButtonProps,\r\n LayoutProps,\r\n Padding,\r\n SnapPoint,\r\n AggregateReporter,\r\n};\r\nexport default SelectionViewer;\r\n","import React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { RowAggregateContext } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type RowProps = {\n id?: string;\n /** Consumer-owned — SelectionViewer has never owned fetch/filter state, so unlike\n * search-viewer's Row this isn't internally computed. Mirrors how `selectionState`\n * is already a prop on SelectionViewer itself today. Defaults to \"data\": if you\n * render children without wiring this, we assume what you rendered IS the data. */\n state?: SelectionState;\n /** Called when this Row is scrolled horizontally near its end. Return (or resolve to)\n * `true` if more data may follow (keeps the pagination trigger armed), `false` once\n * there's nothing left to fetch — mirrors SelectionViewer's own `onPaginate` contract. */\n onPaginate?: () => boolean | Promise<boolean>;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A horizontally-scrolling, independently-paginating section — the Row/Column\n * equivalent for `SelectionViewer`. No shared code with `@academix-admin/search-viewer`'s\n * Row (Library Charter: packages stay mutually independent) — this one has no\n * query/debounce/cache engine of its own since `SelectionViewer` never had one either;\n * the consumer owns fetching/filtering and just tells this Row what `state` it's in. */\nfunction Row({ id: providedId, state = \"data\", onPaginate, className, style, children }: RowProps) {\n const aggregateReporter = React.useContext(RowAggregateContext);\n const [rowId] = useState(() => providedId || `row-${Math.random().toString(36).substring(2, 11)}`);\n const containerRef = useRef<HTMLDivElement | null>(null);\n const isPaginating = useRef(false);\n\n const handleScroll = useCallback(async () => {\n const el = containerRef.current;\n if (!el || isPaginating.current || !onPaginate) return;\n\n // Same \"near the end\" threshold as SelectionViewer's own vertical pagination trigger, adapted\n // to horizontal scroll metrics since a Row scrolls sideways.\n const { scrollLeft, scrollWidth, clientWidth } = el;\n if (scrollWidth - scrollLeft > clientWidth * 1.2) return;\n\n isPaginating.current = true;\n const hasMore = await onPaginate();\n if (!hasMore) {\n isPaginating.current = false;\n } else {\n setTimeout(() => {\n isPaginating.current = false;\n }, 500);\n }\n }, [onPaginate]);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el || !onPaginate) return;\n el.addEventListener(\"scroll\", handleScroll);\n return () => el.removeEventListener(\"scroll\", handleScroll);\n }, [handleScroll, onPaginate]);\n\n useEffect(() => {\n aggregateReporter?.report(rowId, state);\n return () => aggregateReporter?.unreport(rowId);\n }, [aggregateReporter, rowId, state]);\n\n return (\n <div\n ref={containerRef}\n className={className ? `selection-viewer-row ${className}` : \"selection-viewer-row\"}\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n gap: \"8px\",\n overflowX: \"auto\",\n overflowY: \"hidden\",\n ...style,\n }}\n >\n {children}\n </div>\n );\n}\n\nRow.displayName = \"Row\";\n\nexport { Row };\n","import React, { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { RowAggregateContext, SelectionViewerAggregateContext, computeAggregateState } from \"./SelectionViewer\";\nimport type { SelectionState } from \"./SelectionViewer\";\n\nexport type ColumnProps = {\n id?: string;\n className?: string;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n};\n\n/** A vertical arrangement of `Row`s (or other content) — the explicit, composable\n * equivalent of today's flat `children` list. Its default layout is deliberately\n * identical to the existing `.selection-viewer-content.vertical` rendering\n * (`flex-direction: column, gap: 8px`), so today's flat usage is, unchanged, \"an\n * implicit Column with no Rows.\"\n *\n * Provides the `RowAggregateContext` its `Row` children report into, computes ONE\n * cumulative state from everything reported, and is itself a reporter one level up:\n * nested inside another `Column` it reports through that Column's `RowAggregateContext`\n * (behaving like a Row); at the top level it reports through `SelectionViewerAggregateContext`,\n * which `SelectionViewer` provides — this drives the outer sheet's loading/empty/error\n * views automatically with zero manual wiring, and lets Columns nest arbitrarily deep. */\nfunction Column({ id: providedId, className, style, children }: ColumnProps) {\n const [columnId] = useState(\n () => providedId || `column-${Math.random().toString(36).substring(2, 11)}`\n );\n\n const [reportedStates, setReportedStates] = useState<Map<string, SelectionState>>(new Map());\n const report = useCallback((id: string, state: SelectionState) => {\n setReportedStates((prev) => {\n const next = new Map(prev);\n next.set(id, state);\n return next;\n });\n }, []);\n const unreport = useCallback((id: string) => {\n setReportedStates((prev) => {\n if (!prev.has(id)) return prev;\n const next = new Map(prev);\n next.delete(id);\n return next;\n });\n }, []);\n const rowAggregateValue = useMemo(() => ({ report, unreport }), [report, unreport]);\n\n const aggregateState =\n reportedStates.size > 0 ? computeAggregateState(Array.from(reportedStates.values())) : \"initial\";\n\n const parentRowAggregate = React.useContext(RowAggregateContext);\n const selectionViewerAggregate = React.useContext(SelectionViewerAggregateContext);\n const upstreamReporter = parentRowAggregate ?? selectionViewerAggregate;\n\n useEffect(() => {\n if (!upstreamReporter) return;\n upstreamReporter.report(columnId, aggregateState);\n return () => upstreamReporter.unreport(columnId);\n }, [upstreamReporter, columnId, aggregateState]);\n\n return (\n <RowAggregateContext.Provider value={rowAggregateValue}>\n <div\n className={className ? `selection-viewer-column ${className}` : \"selection-viewer-column\"}\n style={{ display: \"flex\", flexDirection: \"column\", gap: \"8px\", ...style }}\n >\n {children}\n </div>\n </RowAggregateContext.Provider>\n );\n}\n\nColumn.displayName = \"Column\";\n\nexport { Column };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@academix-admin/selection-viewer",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "description": "Imperative React selection sheet \u2014 search + pick from a list \u2014 with a controller hook, built on @academix-admin/modal-sheet.",
5
5
  "keywords": [
6
6
  "react",