@zyncat/ui 0.9.1 → 0.11.0

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.
Files changed (59) hide show
  1. package/dist/alert.js +1 -1
  2. package/dist/{chunk-EQ32F2QJ.js → chunk-62P3KD57.js} +5 -5
  3. package/dist/chunk-62P3KD57.js.map +1 -0
  4. package/dist/{chunk-45XJ75GZ.js → chunk-AIQXS2XY.js} +5 -5
  5. package/dist/{chunk-45XJ75GZ.js.map → chunk-AIQXS2XY.js.map} +1 -1
  6. package/dist/{chunk-GLT5IKQY.js → chunk-AMFGY56I.js} +10 -6
  7. package/dist/chunk-AMFGY56I.js.map +1 -0
  8. package/dist/{chunk-LDC3RIYA.js → chunk-DKVUPFQR.js} +3 -3
  9. package/dist/{chunk-LDC3RIYA.js.map → chunk-DKVUPFQR.js.map} +1 -1
  10. package/dist/{chunk-356HZMT4.js → chunk-NGTA34V2.js} +23 -20
  11. package/dist/chunk-NGTA34V2.js.map +1 -0
  12. package/dist/{chunk-GY7JOPUQ.js → chunk-U4MHX3KH.js} +7 -16
  13. package/dist/chunk-U4MHX3KH.js.map +1 -0
  14. package/dist/{chunk-FLO4A6BI.js → chunk-WFHRAKN3.js} +54 -52
  15. package/dist/chunk-WFHRAKN3.js.map +1 -0
  16. package/dist/{chunk-W5YM2FV4.js → chunk-XJQQQJAO.js} +10 -7
  17. package/dist/chunk-XJQQQJAO.js.map +1 -0
  18. package/dist/date-field.js +5 -5
  19. package/dist/date-range-field.js +7 -7
  20. package/dist/datetime-field.js +5 -5
  21. package/dist/dialog.css +3 -0
  22. package/dist/dialog.d.ts +4 -1
  23. package/dist/dialog.js +8 -6
  24. package/dist/dialog.js.map +1 -1
  25. package/dist/mcp.js +1 -4
  26. package/dist/modal.css +9 -0
  27. package/dist/modal.d.ts +35 -0
  28. package/dist/modal.js +63 -0
  29. package/dist/modal.js.map +1 -0
  30. package/dist/multi-select.js +4 -4
  31. package/dist/overlay.css +3 -0
  32. package/dist/popover.d.ts +10 -3
  33. package/dist/popover.js +5 -5
  34. package/dist/select.js +4 -4
  35. package/dist/sheet.d.ts +4 -1
  36. package/dist/sheet.js +5 -5
  37. package/dist/tag.js +1 -1
  38. package/dist/toast.js +1 -1
  39. package/dist/tooltip.js +1 -1
  40. package/llms.txt +28 -5
  41. package/package.json +7 -2
  42. package/src/components/composites/dialog/Dialog.tsx +30 -23
  43. package/src/components/composites/dialog/dialog.css +3 -0
  44. package/src/components/composites/modal/Modal.tsx +95 -0
  45. package/src/components/composites/modal/modal.css +9 -0
  46. package/src/components/composites/popover/Popover.tsx +12 -3
  47. package/src/components/composites/sheet/Sheet.tsx +10 -1
  48. package/src/components/internal/overlay/layer.tsx +4 -14
  49. package/src/components/internal/overlay/modal.tsx +45 -36
  50. package/src/components/internal/overlay/overlay.css +3 -0
  51. package/src/components/internal/overlay/position.ts +8 -3
  52. package/src/mcp/server.ts +1 -4
  53. package/src/motion/presence.tsx +29 -19
  54. package/dist/chunk-356HZMT4.js.map +0 -1
  55. package/dist/chunk-EQ32F2QJ.js.map +0 -1
  56. package/dist/chunk-FLO4A6BI.js.map +0 -1
  57. package/dist/chunk-GLT5IKQY.js.map +0 -1
  58. package/dist/chunk-GY7JOPUQ.js.map +0 -1
  59. package/dist/chunk-W5YM2FV4.js.map +0 -1
@@ -11,49 +11,51 @@ import { cx } from '../utils/cx';
11
11
 
12
12
  const SM = UIMotion;
13
13
 
14
- let ovLocks = 0;
15
- let ovSavedOverflow = '';
16
- let ovSavedPad = '';
17
- function useScrollLock() {
18
- useEffect(() => {
19
- if (++ovLocks === 1) {
20
- const body = document.body;
21
- const gutter = window.innerWidth - document.documentElement.clientWidth;
22
- ovSavedOverflow = body.style.overflow;
23
- ovSavedPad = body.style.paddingRight;
24
- body.style.overflow = 'hidden';
25
- if (gutter > 0) body.style.paddingRight = (parseFloat(getComputedStyle(body).paddingRight) || 0) + gutter + 'px';
26
- }
27
- return () => {
28
- if (--ovLocks === 0) {
29
- document.body.style.overflow = ovSavedOverflow;
30
- document.body.style.paddingRight = ovSavedPad;
31
- }
32
- };
33
- }, []);
14
+ interface OvScopeLock {
15
+ depth: number;
16
+ overflow: string;
17
+ paddingRight: string;
18
+ inerted: HTMLElement[];
19
+ }
20
+
21
+ const ovScopeLocks = new Map<HTMLElement, OvScopeLock>();
22
+
23
+ function ovGutter(scope: HTMLElement, cs: CSSStyleDeclaration): number {
24
+ if (scope === document.body) return window.innerWidth - document.documentElement.clientWidth;
25
+ return scope.offsetWidth - scope.clientWidth - parseFloat(cs.borderLeftWidth) - parseFloat(cs.borderRightWidth);
34
26
  }
35
27
 
36
- let ovInertCount = 0;
37
- const ovInerted = new Set<HTMLElement>();
38
- function useInertOutside() {
28
+ function useScopeLock(container?: HTMLElement | null) {
39
29
  useEffect(() => {
40
- if (++ovInertCount === 1) {
41
- for (const el of Array.from(document.body.children) as HTMLElement[]) {
30
+ const scope = container ?? document.body;
31
+ const lock: OvScopeLock = ovScopeLocks.get(scope) ?? {
32
+ depth: 0,
33
+ overflow: scope.style.overflow,
34
+ paddingRight: scope.style.paddingRight,
35
+ inerted: [],
36
+ };
37
+ ovScopeLocks.set(scope, lock);
38
+
39
+ if (++lock.depth === 1) {
40
+ const cs = getComputedStyle(scope);
41
+ const gutter = ovGutter(scope, cs);
42
+ scope.style.overflow = 'hidden';
43
+ if (gutter > 0) scope.style.paddingRight = (parseFloat(cs.paddingRight) || 0) + gutter + 'px';
44
+ for (const el of Array.from(scope.children) as HTMLElement[]) {
42
45
  if (el.hasAttribute('data-overlay-root') || el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.inert)
43
46
  continue;
44
47
  el.inert = true;
45
- ovInerted.add(el);
48
+ lock.inerted.push(el);
46
49
  }
47
50
  }
48
51
  return () => {
49
- if (--ovInertCount === 0) {
50
- ovInerted.forEach((el) => {
51
- el.inert = false;
52
- });
53
- ovInerted.clear();
54
- }
52
+ if (--lock.depth > 0) return;
53
+ scope.style.overflow = lock.overflow;
54
+ scope.style.paddingRight = lock.paddingRight;
55
+ for (const el of lock.inerted) el.inert = false;
56
+ ovScopeLocks.delete(scope);
55
57
  };
56
- }, []);
58
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
57
59
  }
58
60
 
59
61
  const ovScrimTiming = {
@@ -92,8 +94,10 @@ export function ModalShell({
92
94
  panelId,
93
95
  dismissible,
94
96
  requestClose,
97
+ container,
95
98
  panelRef: externalPanelRef = null,
96
99
  panelProps = {},
100
+ layerProps = {},
97
101
  animate: animateSpec,
98
102
  exit,
99
103
  children,
@@ -103,8 +107,10 @@ export function ModalShell({
103
107
  panelId: string;
104
108
  dismissible: boolean;
105
109
  requestClose: () => void;
110
+ container?: HTMLElement | null;
106
111
  panelRef?: RefObject<HTMLElement> | null;
107
112
  panelProps?: Record<string, any>;
113
+ layerProps?: Record<string, any>;
108
114
  children: ReactNode;
109
115
  } & MotionSpecs) {
110
116
  const layerRef = useRef<HTMLDivElement>(null);
@@ -120,12 +126,15 @@ export function ModalShell({
120
126
  };
121
127
 
122
128
  useMotion(layerRef, { animate: withScrim('open', animateSpec), exit: withScrim('close', exit) });
123
- useScrollLock();
124
- useInertOutside();
129
+ useScopeLock(container);
125
130
  useReturnFocus(layerRef);
126
131
  useFocusTrap({ panelRef, entry });
127
132
  return (
128
- <div ref={layerRef} className={'overlay-layer ' + layerClass}>
133
+ <div
134
+ {...layerProps}
135
+ ref={layerRef}
136
+ className={cx('overlay-layer', container && 'overlay-layer--scoped', layerClass, layerProps.className)}
137
+ >
129
138
  <OverlayScrim dismissible={dismissible} onPress={requestClose} scrimRef={scrimRef} />
130
139
  <div
131
140
  id={panelId}
@@ -8,6 +8,9 @@
8
8
  inset: 0;
9
9
  display: grid;
10
10
  }
11
+ .overlay-layer--scoped {
12
+ position: absolute;
13
+ }
11
14
  .overlay-scrim {
12
15
  position: absolute;
13
16
  inset: 0;
@@ -3,18 +3,23 @@
3
3
  import { useLayoutEffect, type RefObject } from 'react';
4
4
  import { tokenPx } from '../utils/token-px';
5
5
 
6
+ export interface VirtualAnchor {
7
+ getBoundingClientRect(): DOMRect;
8
+ }
9
+
6
10
  interface UseAnchorPositionProps {
7
11
  side: 'top' | 'bottom' | 'left' | 'right';
8
12
  align: 'start' | 'center' | 'end';
9
13
  arrow: boolean;
14
+ anchor?: VirtualAnchor | null;
10
15
  triggerRef: RefObject<HTMLElement>;
11
16
  panelRef: RefObject<HTMLElement>;
12
17
  }
13
18
 
14
- export function useAnchorPosition({ side, align, arrow, triggerRef, panelRef }: UseAnchorPositionProps) {
19
+ export function useAnchorPosition({ side, align, arrow, anchor, triggerRef, panelRef }: UseAnchorPositionProps) {
15
20
  useLayoutEffect(() => {
16
21
  const place = () => {
17
- const t = triggerRef.current;
22
+ const t = anchor ?? triggerRef.current;
18
23
  const p = panelRef.current;
19
24
  if (!t || !p) return;
20
25
 
@@ -99,5 +104,5 @@ export function useAnchorPosition({ side, align, arrow, triggerRef, panelRef }:
99
104
  window.removeEventListener('resize', place);
100
105
  ro.disconnect();
101
106
  };
102
- }, [side, align, arrow]); // eslint-disable-line react-hooks/exhaustive-deps
107
+ }, [side, align, arrow, anchor]); // eslint-disable-line react-hooks/exhaustive-deps
103
108
  }
package/src/mcp/server.ts CHANGED
@@ -39,9 +39,7 @@ interface Db {
39
39
  const SECTION_RE = /^=+\s+(.+?)\s*$/;
40
40
  const HEADING_RE = /^([A-Za-z][\w /]*?) - @zyncat\/ui\/([a-z][a-z0-9-]*)\b.*$/;
41
41
 
42
- let cached: Db | null = null;
43
42
  function db(): Db {
44
- if (cached) return cached;
45
43
  const root = findRoot();
46
44
  const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'));
47
45
  const subpaths = Object.entries(pkg.exports ?? {})
@@ -84,8 +82,7 @@ function db(): Db {
84
82
  }
85
83
  while (preamble.length && !preamble[preamble.length - 1].trim()) preamble.pop();
86
84
 
87
- cached = { root, version: String(pkg.version ?? '0'), subpaths, preamble, sections, entries };
88
- return cached;
85
+ return { root, version: String(pkg.version ?? '0'), subpaths, preamble, sections, entries };
89
86
  }
90
87
 
91
88
  const norm = (s: string) =>
@@ -6,7 +6,6 @@ import {
6
6
  createElement,
7
7
  isValidElement,
8
8
  useEffect,
9
- useLayoutEffect,
10
9
  useRef,
11
10
  useState,
12
11
  type ReactElement,
@@ -20,6 +19,13 @@ interface Entry {
20
19
  exiting: boolean;
21
20
  }
22
21
 
22
+ type Claims = Map<string, Set<object>>;
23
+
24
+ interface Tracked {
25
+ shown: Entry[];
26
+ signature: string;
27
+ }
28
+
23
29
  function toEntries(children: ReactNode): Entry[] {
24
30
  const out: Entry[] = [];
25
31
  Children.forEach(children, (child, index) => {
@@ -28,6 +34,17 @@ function toEntries(children: ReactNode): Entry[] {
28
34
  return out;
29
35
  }
30
36
 
37
+ function withExiting(previous: Entry[], incoming: Entry[], claims: Claims): Entry[] {
38
+ const live = new Set(incoming.map((entry) => entry.key));
39
+ const merged: Entry[] = incoming.map((entry) => ({ ...entry }));
40
+ previous.forEach((entry, index) => {
41
+ if (live.has(entry.key)) return;
42
+ if (!claims.get(entry.key)?.size) return;
43
+ merged.splice(index, 0, entry.exiting ? entry : { ...entry, exiting: true });
44
+ });
45
+ return merged;
46
+ }
47
+
31
48
  export interface PresenceProps {
32
49
  /** Keyed children. A child animates out only if it renders a `<Motion>` carrying `exit`. */
33
50
  children?: ReactNode;
@@ -42,17 +59,23 @@ export interface PresenceProps {
42
59
  export function Presence({ children, initial = true, mode = 'sync', onExitComplete }: PresenceProps) {
43
60
  const incoming = toEntries(children);
44
61
  const signature = incoming.map((entry) => entry.key).join('|');
45
- const [shown, setShown] = useState<Entry[]>(incoming);
62
+ const claims = useRef<Claims>(new Map());
63
+ const [tracked, setTracked] = useState<Tracked>({ shown: incoming, signature });
46
64
  const bornAtMount = useRef(new Set(incoming.map((entry) => entry.key)));
47
65
  const wasExiting = useRef(false);
48
66
  const complete = useRef(onExitComplete);
49
67
  complete.current = onExitComplete;
50
- const claims = useRef(new Map<string, Set<object>>());
68
+
69
+ let shown = tracked.shown;
70
+ if (tracked.signature !== signature) {
71
+ shown = withExiting(tracked.shown, incoming, claims.current);
72
+ setTracked({ shown, signature });
73
+ }
51
74
 
52
75
  const drop = (key: string) =>
53
- setShown((previous) => {
54
- const next = previous.filter((entry) => entry.key !== key || !entry.exiting);
55
- return next.length === previous.length ? previous : next;
76
+ setTracked((previous) => {
77
+ const next = previous.shown.filter((entry) => entry.key !== key || !entry.exiting);
78
+ return next.length === previous.shown.length ? previous : { ...previous, shown: next };
56
79
  });
57
80
 
58
81
  const claimExit = (key: string) => (): (() => void) => {
@@ -71,19 +94,6 @@ export function Presence({ children, initial = true, mode = 'sync', onExitComple
71
94
  };
72
95
  };
73
96
 
74
- useLayoutEffect(() => {
75
- setShown((previous) => {
76
- const live = new Set(incoming.map((entry) => entry.key));
77
- const merged: Entry[] = incoming.map((entry) => ({ ...entry }));
78
- previous.forEach((entry, index) => {
79
- if (live.has(entry.key)) return;
80
- if (!claims.current.get(entry.key)?.size) return;
81
- merged.splice(index, 0, entry.exiting ? entry : { ...entry, exiting: true });
82
- });
83
- return merged;
84
- });
85
- }, [signature]); // eslint-disable-line react-hooks/exhaustive-deps
86
-
87
97
  const leaving = shown.some((entry) => entry.exiting);
88
98
 
89
99
  useEffect(() => {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/motion/presence.tsx"],"names":[],"mappings":";;;AAsBA,SAAS,UAAU,QAAA,EAA8B;AAC/C,EAAA,MAAM,MAAe,EAAC;AACtB,EAAA,QAAA,CAAS,OAAA,CAAQ,QAAA,EAAU,CAAC,KAAA,EAAO,KAAA,KAAU;AAC3C,IAAA,IAAI,eAAe,KAAK,CAAA,EAAG,GAAA,CAAI,IAAA,CAAK,EAAE,GAAA,EAAK,MAAA,CAAO,KAAA,CAAM,GAAA,IAAO,KAAK,CAAA,EAAG,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,OAAO,CAAA;AAAA,EACtG,CAAC,CAAA;AACD,EAAA,OAAO,GAAA;AACT;AAaO,SAAS,QAAA,CAAS,EAAE,QAAA,EAAU,OAAA,GAAU,MAAM,IAAA,GAAO,MAAA,EAAQ,gBAAe,EAAkB;AACnG,EAAA,MAAM,QAAA,GAAW,UAAU,QAAQ,CAAA;AACnC,EAAA,MAAM,SAAA,GAAY,SAAS,GAAA,CAAI,CAAC,UAAU,KAAA,CAAM,GAAG,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAC7D,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAkB,QAAQ,CAAA;AACpD,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,IAAI,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,CAAC,KAAA,KAAU,KAAA,CAAM,GAAG,CAAC,CAAC,CAAA;AACtE,EAAA,MAAM,UAAA,GAAa,OAAO,KAAK,CAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,OAAO,cAAc,CAAA;AACtC,EAAA,QAAA,CAAS,OAAA,GAAU,cAAA;AACnB,EAAA,MAAM,MAAA,GAAS,MAAA,iBAAO,IAAI,GAAA,EAA0B,CAAA;AAEpD,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KACZ,QAAA,CAAS,CAAC,QAAA,KAAa;AACrB,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,MAAA,CAAO,CAAC,KAAA,KAAU,MAAM,GAAA,KAAQ,GAAA,IAAO,CAAC,KAAA,CAAM,OAAO,CAAA;AAC3E,IAAA,OAAO,IAAA,CAAK,MAAA,KAAW,QAAA,CAAS,MAAA,GAAS,QAAA,GAAW,IAAA;AAAA,EACtD,CAAC,CAAA;AAEH,EAAA,MAAM,SAAA,GAAY,CAAC,GAAA,KAAgB,MAAoB;AACrD,IAAA,IAAI,MAAA,GAAS,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA;AACnC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAA,uBAAa,GAAA,EAAY;AACzB,MAAA,MAAA,CAAO,OAAA,CAAQ,GAAA,CAAI,GAAA,EAAK,MAAM,CAAA;AAAA,IAChC;AACA,IAAA,MAAM,QAAQ,EAAC;AACf,IAAA,MAAM,IAAA,GAAO,MAAA;AACb,IAAA,IAAA,CAAK,IAAI,KAAK,CAAA;AACd,IAAA,OAAO,MAAM;AACX,MAAA,IAAI,CAAC,IAAA,CAAK,MAAA,CAAO,KAAK,CAAA,IAAK,KAAK,IAAA,EAAM;AACtC,MAAA,IAAI,MAAA,CAAO,QAAQ,GAAA,CAAI,GAAG,MAAM,IAAA,EAAM,MAAA,CAAO,OAAA,CAAQ,MAAA,CAAO,GAAG,CAAA;AAC/D,MAAA,IAAA,CAAK,GAAG,CAAA;AAAA,IACV,CAAA;AAAA,EACF,CAAA;AAEA,EAAA,eAAA,CAAgB,MAAM;AACpB,IAAA,QAAA,CAAS,CAAC,QAAA,KAAa;AACrB,MAAA,MAAM,IAAA,GAAO,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAC,KAAA,KAAU,KAAA,CAAM,GAAG,CAAC,CAAA;AACvD,MAAA,MAAM,MAAA,GAAkB,SAAS,GAAA,CAAI,CAAC,WAAW,EAAE,GAAG,OAAM,CAAE,CAAA;AAC9D,MAAA,QAAA,CAAS,OAAA,CAAQ,CAAC,KAAA,EAAO,KAAA,KAAU;AACjC,QAAA,IAAI,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,GAAG,CAAA,EAAG;AACzB,QAAA,IAAI,CAAC,MAAA,CAAO,OAAA,CAAQ,IAAI,KAAA,CAAM,GAAG,GAAG,IAAA,EAAM;AAC1C,QAAA,MAAA,CAAO,MAAA,CAAO,KAAA,EAAO,CAAA,EAAG,KAAA,CAAM,OAAA,GAAU,KAAA,GAAQ,EAAE,GAAG,KAAA,EAAO,OAAA,EAAS,IAAA,EAAM,CAAA;AAAA,MAC7E,CAAC,CAAA;AACD,MAAA,OAAO,MAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,MAAM,UAAU,KAAA,CAAM,IAAA,CAAK,CAAC,KAAA,KAAU,MAAM,OAAO,CAAA;AAEnD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,UAAA,CAAW,OAAA,IAAW,CAAC,OAAA,WAAkB,OAAA,IAAU;AACvD,IAAA,UAAA,CAAW,OAAA,GAAU,OAAA;AAAA,EACvB,CAAA,EAAG,CAAC,OAAO,CAAC,CAAA;AAEZ,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,QAAA,CAAS,GAAA,CAAI,CAAC,KAAA,KAAU,CAAC,KAAA,CAAM,GAAA,EAAK,KAAA,CAAM,IAAI,CAAC,CAAC,CAAA;AACtE,EAAA,MAAM,OAAA,GAAU,IAAA,KAAS,MAAA,IAAU,OAAA,GAAU,KAAA,CAAM,OAAO,CAAC,KAAA,KAAU,KAAA,CAAM,OAAO,CAAA,GAAI,KAAA;AAEtF,EAAA,OAAO,aAAA;AAAA,IACL,QAAA;AAAA,IACA,IAAA;AAAA,IACA,OAAA,CAAQ,GAAA;AAAA,MAAI,CAAC,KAAA,KACX,aAAA;AAAA,QACE,eAAA,CAAgB,QAAA;AAAA,QAChB;AAAA,UACE,KAAK,KAAA,CAAM,GAAA;AAAA,UACX,KAAA,EAAO;AAAA,YACL,SAAA,EAAW,CAAC,KAAA,CAAM,OAAA;AAAA,YAClB,SAAS,OAAA,IAAW,CAAC,YAAY,OAAA,CAAQ,GAAA,CAAI,MAAM,GAAG,CAAA;AAAA,YACtD,SAAA,EAAW,SAAA,CAAU,KAAA,CAAM,GAAG;AAAA;AAChC,SACF;AAAA,QACA,KAAA,CAAM,GAAA,CAAI,KAAA,CAAM,GAAG,KAAK,KAAA,CAAM;AAAA;AAChC;AACF,GACF;AACF","file":"chunk-356HZMT4.js","sourcesContent":["'use client';\n\nimport {\n Children,\n Fragment,\n createElement,\n isValidElement,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { PresenceContext } from './presence-context';\n\ninterface Entry {\n key: string;\n node: ReactElement;\n exiting: boolean;\n}\n\nfunction toEntries(children: ReactNode): Entry[] {\n const out: Entry[] = [];\n Children.forEach(children, (child, index) => {\n if (isValidElement(child)) out.push({ key: String(child.key ?? index), node: child, exiting: false });\n });\n return out;\n}\n\nexport interface PresenceProps {\n /** Keyed children. A child animates out only if it renders a `<Motion>` carrying `exit`. */\n children?: ReactNode;\n /** Let children present on the first paint play their `animate`. @default true */\n initial?: boolean;\n /** `wait` holds entering children back until the outgoing ones have left. @default 'sync' */\n mode?: 'sync' | 'wait';\n /** Fires once the last exiting child has been removed. */\n onExitComplete?: () => void;\n}\n\nexport function Presence({ children, initial = true, mode = 'sync', onExitComplete }: PresenceProps) {\n const incoming = toEntries(children);\n const signature = incoming.map((entry) => entry.key).join('|');\n const [shown, setShown] = useState<Entry[]>(incoming);\n const bornAtMount = useRef(new Set(incoming.map((entry) => entry.key)));\n const wasExiting = useRef(false);\n const complete = useRef(onExitComplete);\n complete.current = onExitComplete;\n const claims = useRef(new Map<string, Set<object>>());\n\n const drop = (key: string) =>\n setShown((previous) => {\n const next = previous.filter((entry) => entry.key !== key || !entry.exiting);\n return next.length === previous.length ? previous : next;\n });\n\n const claimExit = (key: string) => (): (() => void) => {\n let tokens = claims.current.get(key);\n if (!tokens) {\n tokens = new Set<object>();\n claims.current.set(key, tokens);\n }\n const token = {};\n const held = tokens;\n held.add(token);\n return () => {\n if (!held.delete(token) || held.size) return;\n if (claims.current.get(key) === held) claims.current.delete(key);\n drop(key);\n };\n };\n\n useLayoutEffect(() => {\n setShown((previous) => {\n const live = new Set(incoming.map((entry) => entry.key));\n const merged: Entry[] = incoming.map((entry) => ({ ...entry }));\n previous.forEach((entry, index) => {\n if (live.has(entry.key)) return;\n if (!claims.current.get(entry.key)?.size) return;\n merged.splice(index, 0, entry.exiting ? entry : { ...entry, exiting: true });\n });\n return merged;\n });\n }, [signature]); // eslint-disable-line react-hooks/exhaustive-deps\n\n const leaving = shown.some((entry) => entry.exiting);\n\n useEffect(() => {\n if (wasExiting.current && !leaving) complete.current?.();\n wasExiting.current = leaving;\n }, [leaving]);\n\n const fresh = new Map(incoming.map((entry) => [entry.key, entry.node]));\n const visible = mode === 'wait' && leaving ? shown.filter((entry) => entry.exiting) : shown;\n\n return createElement(\n Fragment,\n null,\n visible.map((entry) =>\n createElement(\n PresenceContext.Provider,\n {\n key: entry.key,\n value: {\n isPresent: !entry.exiting,\n initial: initial || !bornAtMount.current.has(entry.key),\n claimExit: claimExit(entry.key),\n },\n },\n fresh.get(entry.key) ?? entry.node,\n ),\n ),\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/internal/overlay/position.ts"],"names":[],"mappings":"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","file":"chunk-EQ32F2QJ.js","sourcesContent":["'use client';\n\nimport { useLayoutEffect, type RefObject } from 'react';\nimport { tokenPx } from '../utils/token-px';\n\ninterface UseAnchorPositionProps {\n side: 'top' | 'bottom' | 'left' | 'right';\n align: 'start' | 'center' | 'end';\n arrow: boolean;\n triggerRef: RefObject<HTMLElement>;\n panelRef: RefObject<HTMLElement>;\n}\n\nexport function useAnchorPosition({ side, align, arrow, triggerRef, panelRef }: UseAnchorPositionProps) {\n useLayoutEffect(() => {\n const place = () => {\n const t = triggerRef.current;\n const p = panelRef.current;\n if (!t || !p) return;\n\n const r = t.getBoundingClientRect();\n const pw = p.offsetWidth;\n const ph = p.offsetHeight;\n\n const edge = tokenPx('--space-2');\n\n const gap = arrow ? tokenPx('--space-2') + 3 : 0;\n\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n\n const room: Record<string, number> = { top: r.top, bottom: vh - r.bottom, left: r.left, right: vw - r.right };\n\n const opposite: Record<string, 'top' | 'bottom' | 'left' | 'right'> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n };\n\n const vertical = side === 'top' || side === 'bottom';\n\n let s = side;\n if (room[s] < (vertical ? ph : pw) + gap && room[opposite[s]] > room[s]) {\n s = opposite[s];\n }\n\n let x: number;\n let y: number;\n\n if (vertical) {\n y = s === 'top' ? r.top - ph - gap : r.bottom + gap;\n\n x = align === 'start' ? r.left : align === 'end' ? r.right - pw : r.left + (r.width - pw) / 2;\n\n x = Math.min(Math.max(x, edge), vw - pw - edge);\n\n y = Math.max(Math.min(y, vh - ph - edge), edge);\n } else {\n x = s === 'left' ? r.left - pw - gap : r.right + gap;\n\n y = align === 'start' ? r.top : align === 'end' ? r.bottom - ph : r.top + (r.height - ph) / 2;\n\n y = Math.min(Math.max(y, edge), vh - ph - edge);\n x = Math.max(Math.min(x, vw - pw - edge), edge);\n }\n\n p.style.left = Math.round(x) + 'px';\n p.style.top = Math.round(y) + 'px';\n\n p.setAttribute('data-side', s);\n p.setAttribute('data-align', align);\n\n if (arrow) {\n if (vertical) {\n p.style.setProperty(\n '--overlay-arrow-x',\n Math.round(Math.min(Math.max(r.left + r.width / 2 - x, 12), pw - 12)) + 'px',\n );\n } else {\n p.style.setProperty(\n '--overlay-arrow-y',\n Math.round(Math.min(Math.max(r.top + r.height / 2 - y, 12), ph - 12)) + 'px',\n );\n }\n }\n };\n\n place();\n\n window.addEventListener('scroll', place, true);\n window.addEventListener('resize', place);\n\n const ro = new ResizeObserver(place);\n ro.observe(panelRef.current!);\n\n return () => {\n window.removeEventListener('scroll', place, true);\n window.removeEventListener('resize', place);\n ro.disconnect();\n };\n }, [side, align, arrow]); // eslint-disable-line react-hooks/exhaustive-deps\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/internal/overlay/modal.tsx"],"names":[],"mappings":"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","file":"chunk-FLO4A6BI.js","sourcesContent":["'use client';\n\nimport './overlay.css';\nimport { useEffect, useRef, type ReactNode, type RefObject } from 'react';\nimport { animate, type Layer, type Playback } from '../../../engine';\nimport { useMotion, run, type MotionSpec, type MotionSpecs } from '../../../motion/use-motion';\nimport { UIMotion } from '../../../tokens/motion-tokens';\nimport { useOverlayEntry } from './layer';\nimport { useReturnFocus, useFocusTrap } from './focus';\nimport { cx } from '../utils/cx';\n\nconst SM = UIMotion;\n\nlet ovLocks = 0;\nlet ovSavedOverflow = '';\nlet ovSavedPad = '';\nfunction useScrollLock() {\n useEffect(() => {\n if (++ovLocks === 1) {\n const body = document.body;\n const gutter = window.innerWidth - document.documentElement.clientWidth;\n ovSavedOverflow = body.style.overflow;\n ovSavedPad = body.style.paddingRight;\n body.style.overflow = 'hidden';\n if (gutter > 0) body.style.paddingRight = (parseFloat(getComputedStyle(body).paddingRight) || 0) + gutter + 'px';\n }\n return () => {\n if (--ovLocks === 0) {\n document.body.style.overflow = ovSavedOverflow;\n document.body.style.paddingRight = ovSavedPad;\n }\n };\n }, []);\n}\n\nlet ovInertCount = 0;\nconst ovInerted = new Set<HTMLElement>();\nfunction useInertOutside() {\n useEffect(() => {\n if (++ovInertCount === 1) {\n for (const el of Array.from(document.body.children) as HTMLElement[]) {\n if (el.hasAttribute('data-overlay-root') || el.tagName === 'SCRIPT' || el.tagName === 'STYLE' || el.inert)\n continue;\n el.inert = true;\n ovInerted.add(el);\n }\n }\n return () => {\n if (--ovInertCount === 0) {\n ovInerted.forEach((el) => {\n el.inert = false;\n });\n ovInerted.clear();\n }\n };\n }, []);\n}\n\nconst ovScrimTiming = {\n open: { duration: SM.dur.slow, ease: SM.ease.entrance },\n close: { duration: SM.dur.base, ease: SM.ease.standard },\n};\n\nfunction OverlayScrim({\n dismissible,\n onPress,\n scrimRef,\n}: {\n dismissible: boolean;\n onPress: () => void;\n scrimRef: RefObject<HTMLDivElement | null>;\n}) {\n const down = useRef(false);\n return (\n <div\n ref={scrimRef}\n className=\"overlay-scrim\"\n aria-hidden=\"true\"\n onPointerDown={(e) => {\n down.current = e.target === e.currentTarget;\n }}\n onClick={(e) => {\n if (dismissible && down.current && e.target === e.currentTarget) onPress();\n }}\n ></div>\n );\n}\n\nexport function ModalShell({\n layerClass,\n panelClass,\n panelId,\n dismissible,\n requestClose,\n panelRef: externalPanelRef = null,\n panelProps = {},\n animate: animateSpec,\n exit,\n children,\n}: {\n layerClass: string;\n panelClass: string;\n panelId: string;\n dismissible: boolean;\n requestClose: () => void;\n panelRef?: RefObject<HTMLElement> | null;\n panelProps?: Record<string, any>;\n children: ReactNode;\n} & MotionSpecs) {\n const layerRef = useRef<HTMLDivElement>(null);\n const scrimRef = useRef<HTMLDivElement>(null);\n const internalPanelRef = useRef<HTMLElement>(null);\n const panelRef = externalPanelRef || internalPanelRef;\n const entry = useOverlayEntry({ nodeRef: layerRef, dismissible, requestClose });\n\n const withScrim = (dir: 'open' | 'close', panelSpec: MotionSpec | undefined) => (): Playback[] => {\n const fade: Layer = { opacity: dir === 'open' ? [0, 1] : [0], timing: ovScrimTiming[dir] };\n const plays = scrimRef.current ? [animate(scrimRef.current, fade)] : [];\n return panelRef.current ? plays.concat(run(panelSpec, panelRef.current)) : plays;\n };\n\n useMotion(layerRef, { animate: withScrim('open', animateSpec), exit: withScrim('close', exit) });\n useScrollLock();\n useInertOutside();\n useReturnFocus(layerRef);\n useFocusTrap({ panelRef, entry });\n return (\n <div ref={layerRef} className={'overlay-layer ' + layerClass}>\n <OverlayScrim dismissible={dismissible} onPress={requestClose} scrimRef={scrimRef} />\n <div\n id={panelId}\n tabIndex={-1}\n {...panelProps}\n ref={panelRef as RefObject<HTMLDivElement>}\n className={cx('overlay-panel', panelClass, panelProps.className)}\n >\n {children}\n </div>\n </div>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/composites/sheet/use-sheet-drag.ts","../src/components/composites/sheet/Sheet.tsx"],"names":["animate","useRef"],"mappings":"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","file":"chunk-GLT5IKQY.js","sourcesContent":["'use client';\n\nimport { useEffect, useRef, type PointerEvent as ReactPointerEvent, type RefObject } from 'react';\nimport { animate, startDrag, type PanInfo } from '../../../engine';\nimport { UIMotion } from '../../../tokens/motion-tokens';\n\nconst SM = UIMotion;\n\nconst DISMISS_RATIO = 0.4;\nconst DISMISS_VELOCITY = 500;\nconst INTENT_PX = 4;\nconst STRETCH_MAX = 0.06;\n\nfunction findScrollable(node: EventTarget | null, stop: HTMLElement | null): HTMLElement | null {\n let el = node instanceof Element ? node : null;\n while (el && el !== stop) {\n const s = getComputedStyle(el);\n if (\n /(auto|scroll)/.test(s.overflowY + s.overflowX) &&\n (el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth)\n )\n return el as HTMLElement;\n el = el.parentElement;\n }\n return null;\n}\n\nfunction sheetScrim(panel: HTMLElement | null): HTMLElement | null {\n return panel?.parentElement?.querySelector<HTMLElement>('.overlay-scrim') ?? null;\n}\n\nexport function sheetSpan(panel: HTMLElement, side: 'right' | 'bottom'): number {\n return side === 'bottom' ? panel.offsetHeight : panel.offsetWidth;\n}\n\nexport function useSheetDrag({\n side,\n panelRef,\n enabled,\n requestClose,\n}: {\n side: 'right' | 'bottom';\n panelRef: RefObject<HTMLElement>;\n enabled: boolean;\n requestClose: () => void;\n}) {\n const axis = side === 'bottom' ? 'y' : 'x';\n const savedUserSelect = useRef<string | null>(null);\n\n function suspendSelection() {\n const sel = window.getSelection();\n if (sel) sel.removeAllRanges();\n savedUserSelect.current = document.body.style.userSelect;\n document.body.style.userSelect = 'none';\n }\n function restoreSelection() {\n if (savedUserSelect.current === null) return;\n document.body.style.userSelect = savedUserSelect.current;\n savedUserSelect.current = null;\n }\n useEffect(() => restoreSelection, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n function paint(el: HTMLElement, travel: number, stretch: number) {\n const span = sheetSpan(el, side);\n el.style.translate = axis === 'y' ? `0px ${travel}px` : `${travel}px 0px`;\n el.style.scale = axis === 'y' ? `1 ${stretch}` : `${stretch} 1`;\n const scrim = sheetScrim(el);\n if (scrim) scrim.style.opacity = String(1 - Math.min(Math.max(travel / span, 0), 1));\n }\n\n function onPointerDown(e: ReactPointerEvent) {\n if (e.button !== 0) return;\n const startX = e.clientX,\n startY = e.clientY;\n const scrollable = findScrollable(e.target, panelRef.current);\n\n const onMove = (ev: PointerEvent) => {\n const dx = ev.clientX - startX,\n dy = ev.clientY - startY;\n if (Math.max(Math.abs(dx), Math.abs(dy)) < INTENT_PX) return;\n cleanup();\n const along = axis === 'y' ? dy : dx;\n const cross = axis === 'y' ? dx : dy;\n if (Math.abs(along) <= Math.abs(cross)) return;\n if (scrollable) {\n if (along < 0) return;\n if (axis === 'y' ? scrollable.scrollTop > 0 : scrollable.scrollLeft > 0) return;\n }\n suspendSelection();\n startDrag(ev, { onMove: onDrag, onEnd: onDragEnd });\n };\n\n const cleanup = () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', cleanup);\n window.removeEventListener('pointercancel', cleanup);\n };\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', cleanup);\n window.addEventListener('pointercancel', cleanup);\n }\n\n function onDrag(info: PanInfo) {\n const el = panelRef.current;\n if (!el) return;\n const o = info.offset[axis];\n const span = sheetSpan(el, side);\n paint(el, Math.max(o, 0), o < 0 ? 1 + Math.min(-o / span, 1) * STRETCH_MAX : 1);\n }\n\n function onDragEnd(info: PanInfo) {\n restoreSelection();\n const el = panelRef.current;\n if (!el) return;\n const span = sheetSpan(el, side);\n if (info.offset[axis] > span * DISMISS_RATIO || info.velocity[axis] > DISMISS_VELOCITY) {\n requestClose();\n return;\n }\n animate(el, { x: [0], y: [0], scale: [[1, 1]], timing: SM.t.settle });\n const scrim = sheetScrim(el);\n if (scrim) animate(scrim, { opacity: [1], timing: SM.t.settle });\n }\n\n return enabled ? { onPointerDown } : {};\n}\n","'use client';\n\nimport './sheet.css';\nimport { Fragment, useId, useRef, type HTMLAttributes, type ReactElement, type ReactNode } from 'react';\nimport { animate, type Layer } from '../../../engine';\nimport { Presence } from '../../../motion/presence';\nimport type { MotionSpecs } from '../../../motion/use-motion';\nimport { resolveMotionTiming } from '../../../motion/motion-timing';\nimport type { DisableableAnimation } from '../../../motion/timing';\nimport { useControllable } from '../../internal/hooks/use-controllable';\nimport { ovCloneTrigger, OverlayPortal } from '../../internal/overlay/layer';\nimport { ModalShell } from '../../internal/overlay/modal';\nimport { useSheetDrag, sheetSpan } from './use-sheet-drag';\nimport type { DataAttributes } from '../../../dom-props';\n\nconst SHEET_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'base', ease: 'exit' },\n} as const;\n\nexport interface SheetProps {\n /** Controlled open state. Omit to stay uncontrolled. */\n open?: boolean;\n /** Initial state when uncontrolled. Default false. */\n defaultOpen?: boolean;\n /** Fires whenever the open state changes. Pair with `open` for controlled use. */\n onOpenChange?: (open: boolean) => void;\n\n /** Cloned to open the sheet on click. */\n trigger?: ReactElement | null;\n\n /** Edge the sheet slides in from. Default 'right'. */\n side?: 'right' | 'bottom';\n\n /** Scrim/Esc dismissal + drag-to-edge. Default true. */\n dismissible?: boolean;\n\n /** Base id for the panel; drives the trigger's `aria-controls`. Auto-generated when omitted. */\n id?: string;\n /** Standard attributes (className, style, data-*, ...) forwarded to the sheet panel. */\n htmlProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;\n /** Open/close timing - motion tokens only, or `null` to disable. @default open 'slow'/'entrance', close 'base'/'exit' */\n animation?: DisableableAnimation;\n /** The ENTIRE surface - paint AND semantics. Drive dismissal with `open`/`onOpenChange`. */\n children: ReactNode;\n}\n\nfunction sheetSlide(slot: HTMLElement, side: 'right' | 'bottom', at: number[]): Layer {\n const frames = at.map((ratio) => ratio * sheetSpan(slot, side));\n return side === 'bottom' ? { y: frames } : { x: frames };\n}\n\nfunction SheetShell({\n side,\n panelId,\n dismissible,\n requestClose,\n htmlProps,\n animate,\n exit,\n children,\n}: {\n side: 'right' | 'bottom';\n panelId: string;\n dismissible: boolean;\n requestClose: () => void;\n htmlProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;\n children: ReactNode;\n} & MotionSpecs) {\n const panelRef = useRef<HTMLElement>(null);\n const dragProps = useSheetDrag({ side, panelRef, enabled: dismissible, requestClose });\n return (\n <ModalShell\n animate={animate}\n exit={exit}\n layerClass={'overlay-layer--sheet-' + side}\n panelClass={'overlay-panel--sheet-' + side}\n panelId={panelId}\n dismissible={dismissible}\n requestClose={requestClose}\n panelRef={panelRef}\n panelProps={{ ...htmlProps, ...dragProps }}\n >\n {children}\n </ModalShell>\n );\n}\n\nexport function Sheet({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n trigger = null,\n side = 'right',\n dismissible = true,\n id,\n htmlProps,\n animation,\n children,\n}: SheetProps) {\n const [open, setOpen] = useControllable(controlledOpen, defaultOpen, onOpenChange);\n const triggerRef = useRef<HTMLElement>(null);\n const autoId = useId();\n const panelId = id || 'sheet-' + autoId;\n const close = () => setOpen(false);\n const timings = resolveMotionTiming(animation, SHEET_TIMING);\n\n return (\n <Fragment>\n {ovCloneTrigger(trigger, { open, onPress: () => setOpen(true), panelId, haspopup: 'dialog', triggerRef })}\n <OverlayPortal>\n <Presence>\n {open && (\n <SheetShell\n key=\"sheet\"\n animate={(slot) => {\n const play = animate(slot, { ...sheetSlide(slot, side, [1, 0]), timing: timings.open });\n play.finished.then(() => play.stop());\n return play;\n }}\n exit={(slot) => animate(slot, { ...sheetSlide(slot, side, [1]), timing: timings.close })}\n side={side}\n panelId={panelId}\n dismissible={dismissible}\n requestClose={close}\n htmlProps={htmlProps}\n >\n {children}\n </SheetShell>\n )}\n </Presence>\n </OverlayPortal>\n </Fragment>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/internal/overlay/layer.tsx"],"names":[],"mappings":"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","file":"chunk-GY7JOPUQ.js","sourcesContent":["'use client';\n\nimport {\n cloneElement,\n useEffect,\n useLayoutEffect,\n useRef,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefObject,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\ninterface OverlayEntry {\n contains: (t: EventTarget | null) => boolean;\n isDismissible: () => boolean;\n requestClose: () => void;\n _dismissible?: boolean;\n _close?: () => void;\n}\n\nconst ovStack: OverlayEntry[] = [];\n\nfunction ovOnDocKeyDown(e: KeyboardEvent) {\n if (e.key !== 'Escape' || e.defaultPrevented || ovStack.length === 0) return;\n const top = ovStack[ovStack.length - 1];\n if (!top.isDismissible()) return;\n e.preventDefault();\n top.requestClose();\n}\n\nfunction ovIsTop(entry: OverlayEntry) {\n return ovStack[ovStack.length - 1] === entry;\n}\n\nfunction ovInOverlayAbove(entry: OverlayEntry, target: EventTarget | null) {\n const i = ovStack.indexOf(entry);\n return i >= 0 && ovStack.slice(i + 1).some((e) => e.contains(target));\n}\n\nfunction useOverlayEntry({\n nodeRef,\n dismissible,\n requestClose,\n}: {\n nodeRef: RefObject<HTMLElement>;\n dismissible: boolean;\n requestClose: () => void;\n}): OverlayEntry {\n const ref = useRef<OverlayEntry>(null);\n if (!ref.current) {\n ref.current = {\n contains: (t) => Boolean(nodeRef.current && nodeRef.current.contains(t as Node)),\n isDismissible: () => ref.current._dismissible,\n requestClose: () => ref.current._close(),\n };\n }\n ref.current._dismissible = dismissible;\n ref.current._close = requestClose;\n\n useLayoutEffect(() => {\n const entry = ref.current;\n if (ovStack.length === 0) document.addEventListener('keydown', ovOnDocKeyDown);\n ovStack.push(entry);\n if (nodeRef.current) nodeRef.current.style.zIndex = 'calc(var(--layer-overlay) + ' + (ovStack.length - 1) + ')';\n return () => {\n const i = ovStack.indexOf(entry);\n if (i >= 0) ovStack.splice(i, 1);\n if (ovStack.length === 0) document.removeEventListener('keydown', ovOnDocKeyDown);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n return ref.current;\n}\n\nfunction useOutsidePress({\n entry,\n refs,\n enabled,\n onPress,\n}: {\n entry: OverlayEntry;\n refs: RefObject<HTMLElement>[];\n enabled: boolean;\n onPress: () => void;\n}) {\n const latest = useRef<{ enabled: boolean; onPress: () => void }>(null);\n latest.current = { enabled, onPress };\n useEffect(() => {\n const onDown = (e: PointerEvent) => {\n if (!latest.current.enabled) return;\n const t = e.target;\n if (refs.some((r) => r.current && r.current.contains(t as Node))) return;\n if (ovInOverlayAbove(entry, t)) return;\n latest.current.onPress();\n };\n document.addEventListener('pointerdown', onDown, true);\n return () => document.removeEventListener('pointerdown', onDown, true);\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n}\n\nfunction ovCloneTrigger(\n trigger: ReactElement | null,\n {\n open,\n onPress,\n panelId,\n haspopup,\n triggerRef,\n }: { open: boolean; onPress: () => void; panelId: string; haspopup: string; triggerRef: RefObject<HTMLElement> },\n): ReactElement | null {\n if (!trigger) return null;\n const own = trigger.props as { onClick?: (...args: unknown[]) => void };\n const ownRef = (trigger as ReactElement & { ref?: Ref<HTMLElement> }).ref;\n return cloneElement(trigger, {\n 'aria-haspopup': haspopup,\n 'aria-expanded': open,\n 'aria-controls': open ? panelId : undefined,\n onClick: (...args: unknown[]) => {\n own.onClick?.(...args);\n onPress();\n },\n ref: (node: HTMLElement | null) => {\n triggerRef.current = node;\n if (typeof ownRef === 'function') ownRef(node);\n else if (ownRef) ownRef.current = node;\n },\n } as Partial<typeof trigger.props>);\n}\n\nfunction OverlayPortal({ children }: { children: ReactNode }) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n if (typeof document !== 'undefined' && !hostRef.current) {\n hostRef.current = document.createElement('div');\n hostRef.current.setAttribute('data-overlay-root', '');\n }\n useLayoutEffect(() => {\n const el = hostRef.current;\n if (!el) return;\n document.body.appendChild(el);\n return () => el.remove();\n }, []);\n if (!hostRef.current) return null;\n return createPortal(children, hostRef.current);\n}\n\nexport { ovIsTop, ovInOverlayAbove, useOverlayEntry, useOutsidePress, ovCloneTrigger, OverlayPortal };\nexport type { OverlayEntry };\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/composites/popover/Popover.tsx"],"names":[],"mappings":"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","file":"chunk-W5YM2FV4.js","sourcesContent":["'use client';\n\nimport './popover.css';\nimport { Fragment, useId, useRef, type HTMLAttributes, type ReactElement, type ReactNode, type RefObject } from 'react';\nimport { Presence } from '../../../motion/presence';\nimport { useMotion, type MotionSpecs } from '../../../motion/use-motion';\nimport { resolveMotionTiming } from '../../../motion/motion-timing';\nimport type { DisableableAnimation } from '../../../motion/timing';\nimport { useControllable } from '../../internal/hooks/use-controllable';\nimport { ovCloneTrigger, useOverlayEntry, useOutsidePress, OverlayPortal } from '../../internal/overlay/layer';\nimport { useReturnFocus } from '../../internal/overlay/focus';\nimport { useAnchorPosition } from '../../internal/overlay/position';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nconst POPOVER_TIMING = {\n open: { duration: 'base', ease: 'entrance' },\n close: { duration: 'fast', ease: 'exit' },\n} as const;\n\nexport interface PopoverProps {\n /** Controlled open state. Omit to stay uncontrolled. */\n open?: boolean;\n /** Initial state when uncontrolled. Default false. */\n defaultOpen?: boolean;\n /** Fires whenever the open state changes. Pair with `open` for controlled use. */\n onOpenChange?: (open: boolean) => void;\n\n /** Cloned to toggle the panel; required as the anchor. */\n trigger?: ReactElement | null;\n\n /** Preferred side; flips to the opposite side when cramped. Default 'bottom'. */\n side?: 'top' | 'bottom' | 'left' | 'right';\n /** Cross-axis alignment against the trigger. Default 'start'. */\n align?: 'start' | 'center' | 'end';\n /** Caret tracking the trigger center. Default false. */\n arrow?: boolean;\n\n /** Esc + outside-press dismissal. Default true. */\n dismissible?: boolean;\n\n /** Base id for the panel; drives the trigger's `aria-controls`. Auto-generated when omitted. */\n id?: string;\n /** Standard attributes (className, style, data-*, ...) forwarded to the popover panel. */\n htmlProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;\n /** Open/close timing - motion tokens only, or `null` to disable. @default open 'base'/'entrance', close 'fast'/'exit' */\n animation?: DisableableAnimation;\n /** The ENTIRE surface - paint AND semantics. Drive dismissal with `open`/`onOpenChange`. */\n children: ReactNode;\n}\n\nfunction PopoverPanel({\n panelId,\n side,\n align,\n arrow,\n dismissible,\n requestClose,\n triggerRef,\n htmlProps,\n animate,\n exit,\n children,\n}: {\n panelId: string;\n side: 'top' | 'bottom' | 'left' | 'right';\n align: 'start' | 'center' | 'end';\n arrow: boolean;\n dismissible: boolean;\n requestClose: () => void;\n triggerRef: RefObject<HTMLElement>;\n htmlProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;\n children: ReactNode;\n} & MotionSpecs) {\n const panelRef = useRef<HTMLElement>(null);\n const entry = useOverlayEntry({ nodeRef: panelRef, dismissible, requestClose });\n useMotion(panelRef, { animate, exit });\n useReturnFocus(panelRef);\n useAnchorPosition({ side, align, arrow, triggerRef, panelRef });\n useOutsidePress({ entry, refs: [triggerRef, panelRef], enabled: dismissible, onPress: requestClose });\n return (\n <div\n {...htmlProps}\n id={panelId}\n ref={panelRef as RefObject<HTMLDivElement>}\n className={cx('overlay-popover', htmlProps?.className)}\n >\n {arrow && <span className=\"overlay-popover__arrow\" aria-hidden=\"true\"></span>}\n {children}\n </div>\n );\n}\n\nexport function Popover({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n trigger = null,\n side = 'bottom',\n align = 'start',\n arrow = false,\n dismissible = true,\n id,\n htmlProps,\n animation,\n children,\n}: PopoverProps) {\n const [open, setOpen] = useControllable(controlledOpen, defaultOpen, onOpenChange);\n const triggerRef = useRef<HTMLElement>(null);\n const autoId = useId();\n const panelId = id || 'popover-' + autoId;\n const close = () => setOpen(false);\n const timings = resolveMotionTiming(animation, POPOVER_TIMING);\n\n return (\n <Fragment>\n {ovCloneTrigger(trigger, { open, onPress: () => setOpen(!open), panelId, haspopup: 'true', triggerRef })}\n <OverlayPortal>\n <Presence>\n {open && (\n <PopoverPanel\n key=\"panel\"\n animate={{ opacity: [0, 1], scale: [0.96, 1], timing: timings.open }}\n exit={{ opacity: [0], scale: [0.96], timing: timings.close }}\n panelId={panelId}\n side={side}\n align={align}\n arrow={arrow}\n dismissible={dismissible}\n requestClose={close}\n triggerRef={triggerRef}\n htmlProps={htmlProps}\n >\n {children}\n </PopoverPanel>\n )}\n </Presence>\n </OverlayPortal>\n </Fragment>\n );\n}\n"]}