@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
@@ -1,5 +1,5 @@
1
- 'use client';import { useReturnFocus, useFocusTrap } from './chunk-LDC3RIYA.js';
2
- import { useOverlayEntry } from './chunk-GY7JOPUQ.js';
1
+ 'use client';import { useReturnFocus, useFocusTrap } from './chunk-DKVUPFQR.js';
2
+ import { useOverlayEntry } from './chunk-U4MHX3KH.js';
3
3
  import { useMotion, run } from './chunk-XWUWYSCT.js';
4
4
  import { animate } from './chunk-YGCVWGUG.js';
5
5
  import { UIMotion } from './chunk-S5ZTZANS.js';
@@ -9,46 +9,39 @@ import { useRef, useEffect } from 'react';
9
9
  import { jsxs, jsx } from 'react/jsx-runtime';
10
10
 
11
11
  var SM = UIMotion;
12
- var ovLocks = 0;
13
- var ovSavedOverflow = "";
14
- var ovSavedPad = "";
15
- function useScrollLock() {
16
- useEffect(() => {
17
- if (++ovLocks === 1) {
18
- const body = document.body;
19
- const gutter = window.innerWidth - document.documentElement.clientWidth;
20
- ovSavedOverflow = body.style.overflow;
21
- ovSavedPad = body.style.paddingRight;
22
- body.style.overflow = "hidden";
23
- if (gutter > 0) body.style.paddingRight = (parseFloat(getComputedStyle(body).paddingRight) || 0) + gutter + "px";
24
- }
25
- return () => {
26
- if (--ovLocks === 0) {
27
- document.body.style.overflow = ovSavedOverflow;
28
- document.body.style.paddingRight = ovSavedPad;
29
- }
30
- };
31
- }, []);
12
+ var ovScopeLocks = /* @__PURE__ */ new Map();
13
+ function ovGutter(scope, cs) {
14
+ if (scope === document.body) return window.innerWidth - document.documentElement.clientWidth;
15
+ return scope.offsetWidth - scope.clientWidth - parseFloat(cs.borderLeftWidth) - parseFloat(cs.borderRightWidth);
32
16
  }
33
- var ovInertCount = 0;
34
- var ovInerted = /* @__PURE__ */ new Set();
35
- function useInertOutside() {
17
+ function useScopeLock(container) {
36
18
  useEffect(() => {
37
- if (++ovInertCount === 1) {
38
- for (const el of Array.from(document.body.children)) {
19
+ const scope = container ?? document.body;
20
+ const lock = ovScopeLocks.get(scope) ?? {
21
+ depth: 0,
22
+ overflow: scope.style.overflow,
23
+ paddingRight: scope.style.paddingRight,
24
+ inerted: []
25
+ };
26
+ ovScopeLocks.set(scope, lock);
27
+ if (++lock.depth === 1) {
28
+ const cs = getComputedStyle(scope);
29
+ const gutter = ovGutter(scope, cs);
30
+ scope.style.overflow = "hidden";
31
+ if (gutter > 0) scope.style.paddingRight = (parseFloat(cs.paddingRight) || 0) + gutter + "px";
32
+ for (const el of Array.from(scope.children)) {
39
33
  if (el.hasAttribute("data-overlay-root") || el.tagName === "SCRIPT" || el.tagName === "STYLE" || el.inert)
40
34
  continue;
41
35
  el.inert = true;
42
- ovInerted.add(el);
36
+ lock.inerted.push(el);
43
37
  }
44
38
  }
45
39
  return () => {
46
- if (--ovInertCount === 0) {
47
- ovInerted.forEach((el) => {
48
- el.inert = false;
49
- });
50
- ovInerted.clear();
51
- }
40
+ if (--lock.depth > 0) return;
41
+ scope.style.overflow = lock.overflow;
42
+ scope.style.paddingRight = lock.paddingRight;
43
+ for (const el of lock.inerted) el.inert = false;
44
+ ovScopeLocks.delete(scope);
52
45
  };
53
46
  }, []);
54
47
  }
@@ -83,8 +76,10 @@ function ModalShell({
83
76
  panelId,
84
77
  dismissible,
85
78
  requestClose,
79
+ container,
86
80
  panelRef: externalPanelRef = null,
87
81
  panelProps = {},
82
+ layerProps = {},
88
83
  animate: animateSpec,
89
84
  exit,
90
85
  children
@@ -100,26 +95,33 @@ function ModalShell({
100
95
  return panelRef.current ? plays.concat(run(panelSpec, panelRef.current)) : plays;
101
96
  };
102
97
  useMotion(layerRef, { animate: withScrim("open", animateSpec), exit: withScrim("close", exit) });
103
- useScrollLock();
104
- useInertOutside();
98
+ useScopeLock(container);
105
99
  useReturnFocus(layerRef);
106
100
  useFocusTrap({ panelRef, entry });
107
- return /* @__PURE__ */ jsxs("div", { ref: layerRef, className: "overlay-layer " + layerClass, children: [
108
- /* @__PURE__ */ jsx(OverlayScrim, { dismissible, onPress: requestClose, scrimRef }),
109
- /* @__PURE__ */ jsx(
110
- "div",
111
- {
112
- id: panelId,
113
- tabIndex: -1,
114
- ...panelProps,
115
- ref: panelRef,
116
- className: cx("overlay-panel", panelClass, panelProps.className),
117
- children
118
- }
119
- )
120
- ] });
101
+ return /* @__PURE__ */ jsxs(
102
+ "div",
103
+ {
104
+ ...layerProps,
105
+ ref: layerRef,
106
+ className: cx("overlay-layer", container && "overlay-layer--scoped", layerClass, layerProps.className),
107
+ children: [
108
+ /* @__PURE__ */ jsx(OverlayScrim, { dismissible, onPress: requestClose, scrimRef }),
109
+ /* @__PURE__ */ jsx(
110
+ "div",
111
+ {
112
+ id: panelId,
113
+ tabIndex: -1,
114
+ ...panelProps,
115
+ ref: panelRef,
116
+ className: cx("overlay-panel", panelClass, panelProps.className),
117
+ children
118
+ }
119
+ )
120
+ ]
121
+ }
122
+ );
121
123
  }
122
124
 
123
125
  export { ModalShell };
124
- //# sourceMappingURL=chunk-FLO4A6BI.js.map
125
- //# sourceMappingURL=chunk-FLO4A6BI.js.map
126
+ //# sourceMappingURL=chunk-WFHRAKN3.js.map
127
+ //# sourceMappingURL=chunk-WFHRAKN3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/internal/overlay/modal.tsx"],"names":[],"mappings":"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","file":"chunk-WFHRAKN3.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\ninterface OvScopeLock {\n depth: number;\n overflow: string;\n paddingRight: string;\n inerted: HTMLElement[];\n}\n\nconst ovScopeLocks = new Map<HTMLElement, OvScopeLock>();\n\nfunction ovGutter(scope: HTMLElement, cs: CSSStyleDeclaration): number {\n if (scope === document.body) return window.innerWidth - document.documentElement.clientWidth;\n return scope.offsetWidth - scope.clientWidth - parseFloat(cs.borderLeftWidth) - parseFloat(cs.borderRightWidth);\n}\n\nfunction useScopeLock(container?: HTMLElement | null) {\n useEffect(() => {\n const scope = container ?? document.body;\n const lock: OvScopeLock = ovScopeLocks.get(scope) ?? {\n depth: 0,\n overflow: scope.style.overflow,\n paddingRight: scope.style.paddingRight,\n inerted: [],\n };\n ovScopeLocks.set(scope, lock);\n\n if (++lock.depth === 1) {\n const cs = getComputedStyle(scope);\n const gutter = ovGutter(scope, cs);\n scope.style.overflow = 'hidden';\n if (gutter > 0) scope.style.paddingRight = (parseFloat(cs.paddingRight) || 0) + gutter + 'px';\n for (const el of Array.from(scope.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 lock.inerted.push(el);\n }\n }\n return () => {\n if (--lock.depth > 0) return;\n scope.style.overflow = lock.overflow;\n scope.style.paddingRight = lock.paddingRight;\n for (const el of lock.inerted) el.inert = false;\n ovScopeLocks.delete(scope);\n };\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\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 container,\n panelRef: externalPanelRef = null,\n panelProps = {},\n layerProps = {},\n animate: animateSpec,\n exit,\n children,\n}: {\n layerClass: string;\n panelClass: string;\n panelId: string;\n dismissible: boolean;\n requestClose: () => void;\n container?: HTMLElement | null;\n panelRef?: RefObject<HTMLElement> | null;\n panelProps?: Record<string, any>;\n layerProps?: 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 useScopeLock(container);\n useReturnFocus(layerRef);\n useFocusTrap({ panelRef, entry });\n return (\n <div\n {...layerProps}\n ref={layerRef}\n className={cx('overlay-layer', container && 'overlay-layer--scoped', layerClass, layerProps.className)}\n >\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,8 +1,8 @@
1
- 'use client';import { useAnchorPosition } from './chunk-EQ32F2QJ.js';
2
- import { useReturnFocus } from './chunk-LDC3RIYA.js';
3
- import { ovCloneTrigger, OverlayPortal, useOverlayEntry, useOutsidePress } from './chunk-GY7JOPUQ.js';
1
+ 'use client';import { useAnchorPosition } from './chunk-62P3KD57.js';
2
+ import { useReturnFocus } from './chunk-DKVUPFQR.js';
3
+ import { ovCloneTrigger, OverlayPortal, useOverlayEntry, useOutsidePress } from './chunk-U4MHX3KH.js';
4
4
  import { resolveMotionTiming } from './chunk-NEF5XAHG.js';
5
- import { Presence } from './chunk-356HZMT4.js';
5
+ import { Presence } from './chunk-NGTA34V2.js';
6
6
  import { useMotion } from './chunk-XWUWYSCT.js';
7
7
  import { useControllable } from './chunk-MMRIQNEN.js';
8
8
  import { cx } from './chunk-QGNC7LH5.js';
@@ -21,6 +21,7 @@ function PopoverPanel({
21
21
  arrow,
22
22
  dismissible,
23
23
  requestClose,
24
+ anchor,
24
25
  triggerRef,
25
26
  htmlProps,
26
27
  animate,
@@ -31,7 +32,7 @@ function PopoverPanel({
31
32
  const entry = useOverlayEntry({ nodeRef: panelRef, dismissible, requestClose });
32
33
  useMotion(panelRef, { animate, exit });
33
34
  useReturnFocus(panelRef);
34
- useAnchorPosition({ side, align, arrow, triggerRef, panelRef });
35
+ useAnchorPosition({ side, align, arrow, anchor, triggerRef, panelRef });
35
36
  useOutsidePress({ entry, refs: [triggerRef, panelRef], enabled: dismissible, onPress: requestClose });
36
37
  return /* @__PURE__ */ jsxs(
37
38
  "div",
@@ -52,6 +53,7 @@ function Popover({
52
53
  defaultOpen = false,
53
54
  onOpenChange,
54
55
  trigger = null,
56
+ anchor = null,
55
57
  side = "bottom",
56
58
  align = "start",
57
59
  arrow = false,
@@ -80,6 +82,7 @@ function Popover({
80
82
  arrow,
81
83
  dismissible,
82
84
  requestClose: close,
85
+ anchor,
83
86
  triggerRef,
84
87
  htmlProps,
85
88
  children
@@ -90,5 +93,5 @@ function Popover({
90
93
  }
91
94
 
92
95
  export { Popover };
93
- //# sourceMappingURL=chunk-W5YM2FV4.js.map
94
- //# sourceMappingURL=chunk-W5YM2FV4.js.map
96
+ //# sourceMappingURL=chunk-XJQQQJAO.js.map
97
+ //# sourceMappingURL=chunk-XJQQQJAO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/composites/popover/Popover.tsx"],"names":[],"mappings":"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","file":"chunk-XJQQQJAO.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, type VirtualAnchor } from '../../internal/overlay/position';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nexport type { VirtualAnchor };\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, and used as the anchor unless `anchor` is set. */\n trigger?: ReactElement | null;\n /** Anchor to an arbitrary rect instead of the trigger - any `{ getBoundingClientRect() }`, which an element also satisfies.\n * Drive `open` yourself; pass a new object to re-place a moving anchor. */\n anchor?: VirtualAnchor | 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 anchor,\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 anchor?: VirtualAnchor | null;\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, anchor, 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 anchor = 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 anchor={anchor}\n triggerRef={triggerRef}\n htmlProps={htmlProps}\n >\n {children}\n </PopoverPanel>\n )}\n </Presence>\n </OverlayPortal>\n </Fragment>\n );\n}\n"]}
@@ -1,14 +1,14 @@
1
1
  'use client';import { DtpPanel } from './chunk-Y7AJQVWJ.js';
2
2
  import './chunk-TCUCYFT7.js';
3
+ import { Popover } from './chunk-XJQQQJAO.js';
4
+ import './chunk-62P3KD57.js';
3
5
  import { FieldTrigger, displayDay, FieldShell } from './chunk-YGGCQNNU.js';
4
- import { Popover } from './chunk-W5YM2FV4.js';
5
- import './chunk-EQ32F2QJ.js';
6
- import './chunk-LDC3RIYA.js';
7
- import './chunk-GY7JOPUQ.js';
6
+ import './chunk-DKVUPFQR.js';
7
+ import './chunk-U4MHX3KH.js';
8
8
  import './chunk-UE63OOVG.js';
9
9
  import './chunk-WM5J5TDI.js';
10
10
  import './chunk-NEF5XAHG.js';
11
- import './chunk-356HZMT4.js';
11
+ import './chunk-NGTA34V2.js';
12
12
  import './chunk-2QWJ6FAX.js';
13
13
  import './chunk-XWUWYSCT.js';
14
14
  import './chunk-YGCVWGUG.js';
@@ -1,15 +1,15 @@
1
- 'use client';import { Sheet } from './chunk-GLT5IKQY.js';
1
+ 'use client';import { Sheet } from './chunk-AMFGY56I.js';
2
2
  import { useDayFocus } from './chunk-TCUCYFT7.js';
3
+ import { Popover } from './chunk-XJQQQJAO.js';
4
+ import './chunk-62P3KD57.js';
3
5
  import { FieldShell, FieldTrigger, parse, today, tzLabel, MONTHS, pad, toKey, add, grid, DOW, col, within } from './chunk-YGGCQNNU.js';
4
- import './chunk-FLO4A6BI.js';
5
- import { Popover } from './chunk-W5YM2FV4.js';
6
- import './chunk-EQ32F2QJ.js';
7
- import './chunk-LDC3RIYA.js';
8
- import './chunk-GY7JOPUQ.js';
6
+ import './chunk-WFHRAKN3.js';
7
+ import './chunk-DKVUPFQR.js';
8
+ import './chunk-U4MHX3KH.js';
9
9
  import './chunk-UE63OOVG.js';
10
10
  import { useGlide, GlidePill } from './chunk-WM5J5TDI.js';
11
11
  import './chunk-NEF5XAHG.js';
12
- import './chunk-356HZMT4.js';
12
+ import './chunk-NGTA34V2.js';
13
13
  import { Motion } from './chunk-2QWJ6FAX.js';
14
14
  import './chunk-XWUWYSCT.js';
15
15
  import './chunk-YGCVWGUG.js';
@@ -1,15 +1,15 @@
1
1
  'use client';import { DtpPanel } from './chunk-Y7AJQVWJ.js';
2
2
  import './chunk-TCUCYFT7.js';
3
+ import { Popover } from './chunk-XJQQQJAO.js';
4
+ import './chunk-62P3KD57.js';
3
5
  import { TimeSegments, disp12 } from './chunk-64UU4LGU.js';
4
6
  import { displayDay, FieldShell, FieldTrigger, pad } from './chunk-YGGCQNNU.js';
5
- import { Popover } from './chunk-W5YM2FV4.js';
6
- import './chunk-EQ32F2QJ.js';
7
- import './chunk-LDC3RIYA.js';
8
- import './chunk-GY7JOPUQ.js';
7
+ import './chunk-DKVUPFQR.js';
8
+ import './chunk-U4MHX3KH.js';
9
9
  import './chunk-UE63OOVG.js';
10
10
  import './chunk-WM5J5TDI.js';
11
11
  import './chunk-NEF5XAHG.js';
12
- import './chunk-356HZMT4.js';
12
+ import './chunk-NGTA34V2.js';
13
13
  import './chunk-2QWJ6FAX.js';
14
14
  import './chunk-XWUWYSCT.js';
15
15
  import './chunk-YGCVWGUG.js';
package/dist/dialog.css CHANGED
@@ -136,6 +136,9 @@
136
136
  color: var(--text-body);
137
137
  font: var(--type-body);
138
138
  }
139
+ .dialog__body:first-child {
140
+ padding-top: var(--space-5);
141
+ }
139
142
  .dialog:has(.dialog__icon) .dialog__body {
140
143
  padding-left: calc(var(--space-5) + 2.25rem + var(--space-3));
141
144
  }
package/dist/dialog.d.ts CHANGED
@@ -25,6 +25,9 @@ interface DialogProps {
25
25
  icon?: ReactNode;
26
26
  /** Close button + backdrop/Esc dismissal. Default true. */
27
27
  dismissible?: boolean;
28
+ /** Center inside this element instead of the viewport - it must be positioned (`position: relative` or similar).
29
+ * Scrim, scroll lock and inert scope to it; the rest of the page stays interactive. */
30
+ container?: HTMLElement | null;
28
31
  /** Action row - a node, or a render fn `(close) => node` so uncontrolled dialogs can dismiss. */
29
32
  footer?: ReactNode | ((close: () => void) => ReactNode);
30
33
  /** Dialog body - scrolls when tall; its scroll edges flag the header lift + footer divider. */
@@ -37,6 +40,6 @@ interface DialogProps {
37
40
  /** Open/close timing - motion tokens only, or `null` to disable. @default open 'slow'/'entrance', close 'base'/'standard' */
38
41
  animation?: DisableableAnimation;
39
42
  }
40
- declare function Dialog({ open: controlledOpen, defaultOpen, onOpenChange, trigger, title, description, size, tone, icon, dismissible, footer, children, id, htmlProps, animation, }: DialogProps): react.JSX.Element;
43
+ declare function Dialog({ open: controlledOpen, defaultOpen, onOpenChange, trigger, title, description, size, tone, icon, dismissible, container, footer, children, id, htmlProps, animation, }: DialogProps): react.JSX.Element;
41
44
 
42
45
  export { Dialog, type DialogProps };
package/dist/dialog.js CHANGED
@@ -1,9 +1,9 @@
1
1
  'use client';import { useScrollEdges } from './chunk-BIDVNLJO.js';
2
- import { ModalShell } from './chunk-FLO4A6BI.js';
3
- import './chunk-LDC3RIYA.js';
4
- import { ovCloneTrigger, OverlayPortal } from './chunk-GY7JOPUQ.js';
2
+ import { ModalShell } from './chunk-WFHRAKN3.js';
3
+ import './chunk-DKVUPFQR.js';
4
+ import { ovCloneTrigger, OverlayPortal } from './chunk-U4MHX3KH.js';
5
5
  import { resolveMotionTiming } from './chunk-NEF5XAHG.js';
6
- import { Presence } from './chunk-356HZMT4.js';
6
+ import { Presence } from './chunk-NGTA34V2.js';
7
7
  import './chunk-XWUWYSCT.js';
8
8
  import './chunk-YGCVWGUG.js';
9
9
  import { IconSlot } from './chunk-2ERBBFZS.js';
@@ -52,7 +52,7 @@ function DialogSurface({
52
52
  "aria-labelledby": title ? titleId : void 0,
53
53
  "aria-describedby": description ? descId : void 0,
54
54
  children: [
55
- /* @__PURE__ */ jsxs("header", { className: "dialog__header", children: [
55
+ (icon || title || description || dismissible) && /* @__PURE__ */ jsxs("header", { className: "dialog__header", children: [
56
56
  icon && /* @__PURE__ */ jsx("span", { className: "dialog__icon", children: /* @__PURE__ */ jsx(IconSlot, { size: "md", children: icon }) }),
57
57
  /* @__PURE__ */ jsxs("div", { className: "dialog__heading", children: [
58
58
  title && /* @__PURE__ */ jsx("h2", { className: "dialog__title", id: titleId, children: title }),
@@ -77,6 +77,7 @@ function Dialog({
77
77
  tone = "default",
78
78
  icon = null,
79
79
  dismissible = true,
80
+ container = null,
80
81
  footer = null,
81
82
  children,
82
83
  id,
@@ -91,7 +92,7 @@ function Dialog({
91
92
  const timings = resolveMotionTiming(animation, DIALOG_TIMING);
92
93
  return /* @__PURE__ */ jsxs(Fragment, { children: [
93
94
  ovCloneTrigger(trigger, { open, onPress: () => setOpen(true), panelId, haspopup: "dialog", triggerRef }),
94
- /* @__PURE__ */ jsx(OverlayPortal, { children: /* @__PURE__ */ jsx(Presence, { children: open && /* @__PURE__ */ jsx(
95
+ /* @__PURE__ */ jsx(OverlayPortal, { container, children: /* @__PURE__ */ jsx(Presence, { children: open && /* @__PURE__ */ jsx(
95
96
  ModalShell,
96
97
  {
97
98
  animate: { y: [6, 0], scale: [0.98, 1], opacity: [0, 1], timing: timings.open },
@@ -100,6 +101,7 @@ function Dialog({
100
101
  panelClass: "overlay-panel--dialog",
101
102
  panelId,
102
103
  dismissible,
104
+ container,
103
105
  requestClose: close,
104
106
  children: /* @__PURE__ */ jsx(
105
107
  DialogSurface,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/composites/dialog/Dialog.tsx"],"names":[],"mappings":"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","file":"dialog.js","sourcesContent":["'use client';\n\nimport './dialog.css';\nimport { Fragment, useId, useRef, type HTMLAttributes, type ReactElement, type ReactNode } from 'react';\nimport { Presence } from '../../../motion/presence';\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 { Icon } from '../../internal/icon/Icon';\nimport { IconSlot } from '../../internal/icon/IconSlot';\nimport { useScrollEdges } from '../../internal/hooks/use-scroll-edges';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nconst DIALOG_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'base', ease: 'standard' },\n} as const;\n\nexport interface DialogProps {\n /** Controlled open state. Omit for uncontrolled (use defaultOpen + trigger). */\n open?: boolean;\n /** Initial open 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 /** Optional element cloned to open the dialog on click (uncontrolled ergonomics). */\n trigger?: ReactElement | null;\n /** Header title - rendered as the `<h2>` and wired to `aria-labelledby`. */\n title?: ReactNode;\n /** Subtext under the title - wired to `aria-describedby`. @default null */\n description?: ReactNode;\n /** Panel width. @default 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** 'danger' tints the header icon badge + is the convention for destructive confirms. */\n tone?: 'default' | 'danger';\n /** Your own icon node for the header badge (alert dialogs). */\n icon?: ReactNode;\n /** Close button + backdrop/Esc dismissal. Default true. */\n dismissible?: boolean;\n /** Action row - a node, or a render fn `(close) => node` so uncontrolled dialogs can dismiss. */\n footer?: ReactNode | ((close: () => void) => ReactNode);\n /** Dialog body - scrolls when tall; its scroll edges flag the header lift + footer divider. */\n children?: ReactNode;\n /** Base id for the panel; drives the trigger's `aria-controls` and the title/desc aria ids.\n * Auto-generated when omitted. */\n id?: string;\n /** Standard attributes (className, style, data-*, ...) forwarded to the dialog `<section>`. */\n htmlProps?: HTMLAttributes<HTMLElement> & DataAttributes;\n /** Open/close timing - motion tokens only, or `null` to disable. @default open 'slow'/'entrance', close 'base'/'standard' */\n animation?: DisableableAnimation;\n}\n\ninterface DialogSurfaceProps {\n panelId: string;\n size: 'sm' | 'md' | 'lg';\n tone: 'default' | 'danger';\n icon: ReactNode;\n title: ReactNode;\n description: ReactNode;\n dismissible: boolean;\n footerContent: ReactNode;\n requestClose: () => void;\n htmlProps?: HTMLAttributes<HTMLElement> & DataAttributes;\n children?: ReactNode;\n}\n\nfunction DialogSurface({\n panelId,\n size,\n tone,\n icon,\n title,\n description,\n dismissible,\n footerContent,\n requestClose,\n htmlProps,\n children,\n}: DialogSurfaceProps) {\n const bodyRef = useRef<HTMLDivElement>(null);\n const titleId = panelId + '-title';\n const descId = panelId + '-desc';\n\n useScrollEdges(bodyRef, (edges, el) => {\n el.toggleAttribute('data-scroll-top', edges.top);\n el.toggleAttribute('data-scroll-bottom', edges.bottom);\n });\n\n return (\n <section\n {...htmlProps}\n className={cx('dialog', htmlProps?.className)}\n role=\"dialog\"\n aria-modal=\"true\"\n data-size={size === 'md' ? undefined : size}\n data-tone={tone === 'default' ? undefined : tone}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={description ? descId : undefined}\n >\n <header className=\"dialog__header\">\n {icon && (\n <span className=\"dialog__icon\">\n <IconSlot size=\"md\">{icon}</IconSlot>\n </span>\n )}\n <div className=\"dialog__heading\">\n {title && (\n <h2 className=\"dialog__title\" id={titleId}>\n {title}\n </h2>\n )}\n {description && (\n <p className=\"dialog__desc\" id={descId}>\n {description}\n </p>\n )}\n </div>\n {dismissible && (\n <button type=\"button\" className=\"dialog__close\" aria-label=\"Close dialog\" onClick={requestClose}>\n <Icon name=\"x\" size=\"sm\" weight=\"bold\" />\n </button>\n )}\n </header>\n\n <div className=\"dialog__body\" ref={bodyRef}>\n {children}\n </div>\n\n {footerContent && <footer className=\"dialog__footer\">{footerContent}</footer>}\n </section>\n );\n}\n\nexport function Dialog({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n trigger = null,\n title,\n description = null,\n size = 'md',\n tone = 'default',\n icon = null,\n dismissible = true,\n footer = null,\n children,\n id,\n htmlProps,\n animation,\n}: DialogProps) {\n const autoId = useId();\n const panelId = id || 'dialog-' + autoId;\n const [open, setOpen] = useControllable(controlledOpen, defaultOpen, onOpenChange);\n const triggerRef = useRef<HTMLElement>(null);\n const close = () => setOpen(false);\n\n const timings = resolveMotionTiming(animation, DIALOG_TIMING);\n\n return (\n <Fragment>\n {ovCloneTrigger(trigger, { open, onPress: () => setOpen(true), panelId, haspopup: 'dialog', triggerRef })}\n <OverlayPortal>\n <Presence>\n {open && (\n <ModalShell\n key=\"dialog\"\n animate={{ y: [6, 0], scale: [0.98, 1], opacity: [0, 1], timing: timings.open }}\n exit={{ y: [6], scale: [0.98], opacity: [0], timing: timings.close }}\n layerClass=\"overlay-layer--dialog\"\n panelClass=\"overlay-panel--dialog\"\n panelId={panelId}\n dismissible={dismissible}\n requestClose={close}\n >\n <DialogSurface\n panelId={panelId}\n size={size}\n tone={tone}\n icon={icon}\n title={title}\n description={description}\n dismissible={dismissible}\n footerContent={typeof footer === 'function' ? footer(close) : footer}\n requestClose={close}\n htmlProps={htmlProps}\n >\n {children}\n </DialogSurface>\n </ModalShell>\n )}\n </Presence>\n </OverlayPortal>\n </Fragment>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/components/composites/dialog/Dialog.tsx"],"names":[],"mappings":"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","file":"dialog.js","sourcesContent":["'use client';\n\nimport './dialog.css';\nimport { Fragment, useId, useRef, type HTMLAttributes, type ReactElement, type ReactNode } from 'react';\nimport { Presence } from '../../../motion/presence';\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 { Icon } from '../../internal/icon/Icon';\nimport { IconSlot } from '../../internal/icon/IconSlot';\nimport { useScrollEdges } from '../../internal/hooks/use-scroll-edges';\nimport type { DataAttributes } from '../../../dom-props';\nimport { cx } from '../../internal/utils/cx';\n\nconst DIALOG_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'base', ease: 'standard' },\n} as const;\n\nexport interface DialogProps {\n /** Controlled open state. Omit for uncontrolled (use defaultOpen + trigger). */\n open?: boolean;\n /** Initial open 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 /** Optional element cloned to open the dialog on click (uncontrolled ergonomics). */\n trigger?: ReactElement | null;\n /** Header title - rendered as the `<h2>` and wired to `aria-labelledby`. */\n title?: ReactNode;\n /** Subtext under the title - wired to `aria-describedby`. @default null */\n description?: ReactNode;\n /** Panel width. @default 'md' */\n size?: 'sm' | 'md' | 'lg';\n /** 'danger' tints the header icon badge + is the convention for destructive confirms. */\n tone?: 'default' | 'danger';\n /** Your own icon node for the header badge (alert dialogs). */\n icon?: ReactNode;\n /** Close button + backdrop/Esc dismissal. Default true. */\n dismissible?: boolean;\n /** Center inside this element instead of the viewport - it must be positioned (`position: relative` or similar).\n * Scrim, scroll lock and inert scope to it; the rest of the page stays interactive. */\n container?: HTMLElement | null;\n /** Action row - a node, or a render fn `(close) => node` so uncontrolled dialogs can dismiss. */\n footer?: ReactNode | ((close: () => void) => ReactNode);\n /** Dialog body - scrolls when tall; its scroll edges flag the header lift + footer divider. */\n children?: ReactNode;\n /** Base id for the panel; drives the trigger's `aria-controls` and the title/desc aria ids.\n * Auto-generated when omitted. */\n id?: string;\n /** Standard attributes (className, style, data-*, ...) forwarded to the dialog `<section>`. */\n htmlProps?: HTMLAttributes<HTMLElement> & DataAttributes;\n /** Open/close timing - motion tokens only, or `null` to disable. @default open 'slow'/'entrance', close 'base'/'standard' */\n animation?: DisableableAnimation;\n}\n\ninterface DialogSurfaceProps {\n panelId: string;\n size: 'sm' | 'md' | 'lg';\n tone: 'default' | 'danger';\n icon: ReactNode;\n title: ReactNode;\n description: ReactNode;\n dismissible: boolean;\n footerContent: ReactNode;\n requestClose: () => void;\n htmlProps?: HTMLAttributes<HTMLElement> & DataAttributes;\n children?: ReactNode;\n}\n\nfunction DialogSurface({\n panelId,\n size,\n tone,\n icon,\n title,\n description,\n dismissible,\n footerContent,\n requestClose,\n htmlProps,\n children,\n}: DialogSurfaceProps) {\n const bodyRef = useRef<HTMLDivElement>(null);\n const titleId = panelId + '-title';\n const descId = panelId + '-desc';\n\n useScrollEdges(bodyRef, (edges, el) => {\n el.toggleAttribute('data-scroll-top', edges.top);\n el.toggleAttribute('data-scroll-bottom', edges.bottom);\n });\n\n return (\n <section\n {...htmlProps}\n className={cx('dialog', htmlProps?.className)}\n role=\"dialog\"\n aria-modal=\"true\"\n data-size={size === 'md' ? undefined : size}\n data-tone={tone === 'default' ? undefined : tone}\n aria-labelledby={title ? titleId : undefined}\n aria-describedby={description ? descId : undefined}\n >\n {(icon || title || description || dismissible) && (\n <header className=\"dialog__header\">\n {icon && (\n <span className=\"dialog__icon\">\n <IconSlot size=\"md\">{icon}</IconSlot>\n </span>\n )}\n <div className=\"dialog__heading\">\n {title && (\n <h2 className=\"dialog__title\" id={titleId}>\n {title}\n </h2>\n )}\n {description && (\n <p className=\"dialog__desc\" id={descId}>\n {description}\n </p>\n )}\n </div>\n {dismissible && (\n <button type=\"button\" className=\"dialog__close\" aria-label=\"Close dialog\" onClick={requestClose}>\n <Icon name=\"x\" size=\"sm\" weight=\"bold\" />\n </button>\n )}\n </header>\n )}\n\n <div className=\"dialog__body\" ref={bodyRef}>\n {children}\n </div>\n\n {footerContent && <footer className=\"dialog__footer\">{footerContent}</footer>}\n </section>\n );\n}\n\nexport function Dialog({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n trigger = null,\n title,\n description = null,\n size = 'md',\n tone = 'default',\n icon = null,\n dismissible = true,\n container = null,\n footer = null,\n children,\n id,\n htmlProps,\n animation,\n}: DialogProps) {\n const autoId = useId();\n const panelId = id || 'dialog-' + autoId;\n const [open, setOpen] = useControllable(controlledOpen, defaultOpen, onOpenChange);\n const triggerRef = useRef<HTMLElement>(null);\n const close = () => setOpen(false);\n\n const timings = resolveMotionTiming(animation, DIALOG_TIMING);\n\n return (\n <Fragment>\n {ovCloneTrigger(trigger, { open, onPress: () => setOpen(true), panelId, haspopup: 'dialog', triggerRef })}\n <OverlayPortal container={container}>\n <Presence>\n {open && (\n <ModalShell\n key=\"dialog\"\n animate={{ y: [6, 0], scale: [0.98, 1], opacity: [0, 1], timing: timings.open }}\n exit={{ y: [6], scale: [0.98], opacity: [0], timing: timings.close }}\n layerClass=\"overlay-layer--dialog\"\n panelClass=\"overlay-panel--dialog\"\n panelId={panelId}\n dismissible={dismissible}\n container={container}\n requestClose={close}\n >\n <DialogSurface\n panelId={panelId}\n size={size}\n tone={tone}\n icon={icon}\n title={title}\n description={description}\n dismissible={dismissible}\n footerContent={typeof footer === 'function' ? footer(close) : footer}\n requestClose={close}\n htmlProps={htmlProps}\n >\n {children}\n </DialogSurface>\n </ModalShell>\n )}\n </Presence>\n </OverlayPortal>\n </Fragment>\n );\n}\n"]}
package/dist/mcp.js CHANGED
@@ -21,9 +21,7 @@ function findRoot() {
21
21
  }
22
22
  var SECTION_RE = /^=+\s+(.+?)\s*$/;
23
23
  var HEADING_RE = /^([A-Za-z][\w /]*?) - @zyncat\/ui\/([a-z][a-z0-9-]*)\b.*$/;
24
- var cached = null;
25
24
  function db() {
26
- if (cached) return cached;
27
25
  const root = findRoot();
28
26
  const pkg = JSON.parse(readFileSync(join(root, "package.json"), "utf8"));
29
27
  const subpaths = Object.entries(pkg.exports ?? {}).filter(([, v]) => typeof v === "object" && v !== null && "types" in v).map(([k]) => k.replace(/^\.\//, ""));
@@ -62,8 +60,7 @@ function db() {
62
60
  while (s.body.length && !s.body[0].trim()) s.body.shift();
63
61
  }
64
62
  while (preamble.length && !preamble[preamble.length - 1].trim()) preamble.pop();
65
- cached = { root, version: String(pkg.version ?? "0"), subpaths, preamble, sections, entries };
66
- return cached;
63
+ return { root, version: String(pkg.version ?? "0"), subpaths, preamble, sections, entries };
67
64
  }
68
65
  var norm = (s) => s.toLowerCase().replace(/^@zyncat\/ui\//, "").replace(/[^a-z0-9]/g, "");
69
66
  function resolveSubpath(input) {
package/dist/modal.css ADDED
@@ -0,0 +1,9 @@
1
+ /* modal.css - the unpainted modal surface: the shell layer centers the panel and
2
+ constrains it to the layer box. Everything else is the consumer's paint. */
3
+ .overlay-layer--modal {
4
+ place-items: center;
5
+ }
6
+ .overlay-panel--modal {
7
+ max-width: 100%;
8
+ max-height: 100%;
9
+ }
@@ -0,0 +1,35 @@
1
+ import * as react from 'react';
2
+ import { ReactElement, HTMLAttributes, ReactNode } from 'react';
3
+ import { D as DisableableAnimation } from './timing-7JA_zQHP.js';
4
+ import { D as DataAttributes } from './dom-props-C0jrllBw.js';
5
+ import './motion-scale-Canq4stZ.js';
6
+
7
+ interface ModalProps {
8
+ /** Controlled open state. Omit to stay uncontrolled. */
9
+ open?: boolean;
10
+ /** Initial state when uncontrolled. Default false. */
11
+ defaultOpen?: boolean;
12
+ /** Fires whenever the open state changes. Pair with `open` for controlled use. */
13
+ onOpenChange?: (open: boolean) => void;
14
+ /** Cloned to open the modal on click. */
15
+ trigger?: ReactElement | null;
16
+ /** Scrim/Esc dismissal. Default true. */
17
+ dismissible?: boolean;
18
+ /** Mount inside this element instead of the viewport - it must be positioned (`position: relative` or similar).
19
+ * Scrim, scroll lock and inert scope to it; the rest of the page stays interactive. */
20
+ container?: HTMLElement | null;
21
+ /** Base id for the panel; drives the trigger's `aria-controls`. Auto-generated when omitted. */
22
+ id?: string;
23
+ /** Standard attributes (className, style, data-*, ...) forwarded to the panel - this is where your paint goes.
24
+ * Centered by default; `width: 100%; height: 100%` makes it full-bleed. */
25
+ htmlProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;
26
+ /** Standard attributes forwarded to the layer behind the panel - set `--bg-overlay` here to retint the scrim. */
27
+ layerProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;
28
+ /** Open/close timing - motion tokens only, or `null` to disable. @default open 'slow'/'entrance', close 'base'/'standard' */
29
+ animation?: DisableableAnimation;
30
+ /** The ENTIRE surface - paint AND semantics (`role="dialog"`, a label). Nothing is painted for you. */
31
+ children: ReactNode;
32
+ }
33
+ declare function Modal({ open: controlledOpen, defaultOpen, onOpenChange, trigger, dismissible, container, id, htmlProps, layerProps, animation, children, }: ModalProps): react.JSX.Element;
34
+
35
+ export { Modal, type ModalProps };
package/dist/modal.js ADDED
@@ -0,0 +1,63 @@
1
+ 'use client';import { ModalShell } from './chunk-WFHRAKN3.js';
2
+ import './chunk-DKVUPFQR.js';
3
+ import { ovCloneTrigger, OverlayPortal } from './chunk-U4MHX3KH.js';
4
+ import { resolveMotionTiming } from './chunk-NEF5XAHG.js';
5
+ import { Presence } from './chunk-NGTA34V2.js';
6
+ import './chunk-XWUWYSCT.js';
7
+ import './chunk-YGCVWGUG.js';
8
+ import { useControllable } from './chunk-MMRIQNEN.js';
9
+ import './chunk-S5ZTZANS.js';
10
+ import './chunk-VTJTGVZZ.js';
11
+ import './chunk-QGNC7LH5.js';
12
+ import './modal.css';
13
+ import { useRef, useId, Fragment } from 'react';
14
+ import { jsxs, jsx } from 'react/jsx-runtime';
15
+
16
+ var MODAL_TIMING = {
17
+ open: { duration: "slow", ease: "entrance" },
18
+ close: { duration: "base", ease: "standard" }
19
+ };
20
+ function Modal({
21
+ open: controlledOpen,
22
+ defaultOpen = false,
23
+ onOpenChange,
24
+ trigger = null,
25
+ dismissible = true,
26
+ container = null,
27
+ id,
28
+ htmlProps,
29
+ layerProps,
30
+ animation,
31
+ children
32
+ }) {
33
+ const [open, setOpen] = useControllable(controlledOpen, defaultOpen, onOpenChange);
34
+ const triggerRef = useRef(null);
35
+ const autoId = useId();
36
+ const panelId = id || "modal-" + autoId;
37
+ const close = () => setOpen(false);
38
+ const timings = resolveMotionTiming(animation, MODAL_TIMING);
39
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
40
+ ovCloneTrigger(trigger, { open, onPress: () => setOpen(true), panelId, haspopup: "dialog", triggerRef }),
41
+ /* @__PURE__ */ jsx(OverlayPortal, { container, children: /* @__PURE__ */ jsx(Presence, { children: open && /* @__PURE__ */ jsx(
42
+ ModalShell,
43
+ {
44
+ animate: { opacity: [0, 1], scale: [0.98, 1], timing: timings.open },
45
+ exit: { opacity: [0], scale: [0.98], timing: timings.close },
46
+ layerClass: "overlay-layer--modal",
47
+ panelClass: "overlay-panel--modal",
48
+ panelId,
49
+ dismissible,
50
+ container,
51
+ requestClose: close,
52
+ panelProps: htmlProps,
53
+ layerProps,
54
+ children
55
+ },
56
+ "modal"
57
+ ) }) })
58
+ ] });
59
+ }
60
+
61
+ export { Modal };
62
+ //# sourceMappingURL=modal.js.map
63
+ //# sourceMappingURL=modal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/composites/modal/Modal.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;AAYA,IAAM,YAAA,GAAe;AAAA,EACnB,IAAA,EAAM,EAAE,QAAA,EAAU,MAAA,EAAQ,MAAM,UAAA,EAAW;AAAA,EAC3C,KAAA,EAAO,EAAE,QAAA,EAAU,MAAA,EAAQ,MAAM,UAAA;AACnC,CAAA;AAiCO,SAAS,KAAA,CAAM;AAAA,EACpB,IAAA,EAAM,cAAA;AAAA,EACN,WAAA,GAAc,KAAA;AAAA,EACd,YAAA;AAAA,EACA,OAAA,GAAU,IAAA;AAAA,EACV,WAAA,GAAc,IAAA;AAAA,EACd,SAAA,GAAY,IAAA;AAAA,EACZ,EAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAe;AACb,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,IAAI,eAAA,CAAgB,cAAA,EAAgB,aAAa,YAAY,CAAA;AACjF,EAAA,MAAM,UAAA,GAAa,OAAoB,IAAI,CAAA;AAC3C,EAAA,MAAM,SAAS,KAAA,EAAM;AACrB,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,GAAW,MAAA;AACjC,EAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,KAAK,CAAA;AACjC,EAAA,MAAM,OAAA,GAAU,mBAAA,CAAoB,SAAA,EAAW,YAAY,CAAA;AAE3D,EAAA,4BACG,QAAA,EAAA,EACE,QAAA,EAAA;AAAA,IAAA,cAAA,CAAe,OAAA,EAAS,EAAE,IAAA,EAAM,OAAA,EAAS,MAAM,OAAA,CAAQ,IAAI,CAAA,EAAG,OAAA,EAAS,QAAA,EAAU,QAAA,EAAU,UAAA,EAAY,CAAA;AAAA,oBACxG,GAAA,CAAC,aAAA,EAAA,EAAc,SAAA,EACb,QAAA,kBAAA,GAAA,CAAC,YACE,QAAA,EAAA,IAAA,oBACC,GAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QAEC,OAAA,EAAS,EAAE,OAAA,EAAS,CAAC,GAAG,CAAC,CAAA,EAAG,KAAA,EAAO,CAAC,IAAA,EAAM,CAAC,CAAA,EAAG,MAAA,EAAQ,QAAQ,IAAA,EAAK;AAAA,QACnE,IAAA,EAAM,EAAE,OAAA,EAAS,CAAC,CAAC,CAAA,EAAG,KAAA,EAAO,CAAC,IAAI,CAAA,EAAG,MAAA,EAAQ,OAAA,CAAQ,KAAA,EAAM;AAAA,QAC3D,UAAA,EAAW,sBAAA;AAAA,QACX,UAAA,EAAW,sBAAA;AAAA,QACX,OAAA;AAAA,QACA,WAAA;AAAA,QACA,SAAA;AAAA,QACA,YAAA,EAAc,KAAA;AAAA,QACd,UAAA,EAAY,SAAA;AAAA,QACZ,UAAA;AAAA,QAEC;AAAA,OAAA;AAAA,MAZG;AAAA,OAeV,CAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"modal.js","sourcesContent":["'use client';\n\nimport './modal.css';\nimport { Fragment, useId, useRef, type HTMLAttributes, type ReactElement, type ReactNode } from 'react';\nimport { Presence } from '../../../motion/presence';\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 type { DataAttributes } from '../../../dom-props';\n\nconst MODAL_TIMING = {\n open: { duration: 'slow', ease: 'entrance' },\n close: { duration: 'base', ease: 'standard' },\n} as const;\n\nexport interface ModalProps {\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 modal on click. */\n trigger?: ReactElement | null;\n\n /** Scrim/Esc dismissal. Default true. */\n dismissible?: boolean;\n\n /** Mount inside this element instead of the viewport - it must be positioned (`position: relative` or similar).\n * Scrim, scroll lock and inert scope to it; the rest of the page stays interactive. */\n container?: HTMLElement | null;\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 panel - this is where your paint goes.\n * Centered by default; `width: 100%; height: 100%` makes it full-bleed. */\n htmlProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;\n /** Standard attributes forwarded to the layer behind the panel - set `--bg-overlay` here to retint the scrim. */\n layerProps?: HTMLAttributes<HTMLDivElement> & DataAttributes;\n /** Open/close timing - motion tokens only, or `null` to disable. @default open 'slow'/'entrance', close 'base'/'standard' */\n animation?: DisableableAnimation;\n /** The ENTIRE surface - paint AND semantics (`role=\"dialog\"`, a label). Nothing is painted for you. */\n children: ReactNode;\n}\n\nexport function Modal({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n trigger = null,\n dismissible = true,\n container = null,\n id,\n htmlProps,\n layerProps,\n animation,\n children,\n}: ModalProps) {\n const [open, setOpen] = useControllable(controlledOpen, defaultOpen, onOpenChange);\n const triggerRef = useRef<HTMLElement>(null);\n const autoId = useId();\n const panelId = id || 'modal-' + autoId;\n const close = () => setOpen(false);\n const timings = resolveMotionTiming(animation, MODAL_TIMING);\n\n return (\n <Fragment>\n {ovCloneTrigger(trigger, { open, onPress: () => setOpen(true), panelId, haspopup: 'dialog', triggerRef })}\n <OverlayPortal container={container}>\n <Presence>\n {open && (\n <ModalShell\n key=\"modal\"\n animate={{ opacity: [0, 1], scale: [0.98, 1], timing: timings.open }}\n exit={{ opacity: [0], scale: [0.98], timing: timings.close }}\n layerClass=\"overlay-layer--modal\"\n panelClass=\"overlay-panel--modal\"\n panelId={panelId}\n dismissible={dismissible}\n container={container}\n requestClose={close}\n panelProps={htmlProps}\n layerProps={layerProps}\n >\n {children}\n </ModalShell>\n )}\n </Presence>\n </OverlayPortal>\n </Fragment>\n );\n}\n"]}
@@ -1,10 +1,10 @@
1
- 'use client';import { useListbox, SelectTrigger, ListboxPanel } from './chunk-45XJ75GZ.js';
2
- import './chunk-EQ32F2QJ.js';
3
- import './chunk-GY7JOPUQ.js';
1
+ 'use client';import { useListbox, SelectTrigger, ListboxPanel } from './chunk-AIQXS2XY.js';
2
+ import './chunk-62P3KD57.js';
3
+ import './chunk-U4MHX3KH.js';
4
4
  import './chunk-UE63OOVG.js';
5
5
  import './chunk-WM5J5TDI.js';
6
6
  import './chunk-NEF5XAHG.js';
7
- import './chunk-356HZMT4.js';
7
+ import './chunk-NGTA34V2.js';
8
8
  import './chunk-XWUWYSCT.js';
9
9
  import './chunk-YGCVWGUG.js';
10
10
  import './chunk-2ERBBFZS.js';
package/dist/overlay.css CHANGED
@@ -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;