@nori-ui/core 1.1.0 → 1.3.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 (58) hide show
  1. package/dist/chunk-2PESUXE3.js +3 -0
  2. package/dist/chunk-2PESUXE3.js.map +1 -0
  3. package/dist/{chunk-WDNDTSNX.js → chunk-4I37QSEM.js} +3 -3
  4. package/dist/{chunk-WDNDTSNX.js.map → chunk-4I37QSEM.js.map} +1 -1
  5. package/dist/chunk-H7MFAFV4.js +303 -0
  6. package/dist/chunk-H7MFAFV4.js.map +1 -0
  7. package/dist/chunk-KCLWPSV5.js +134 -0
  8. package/dist/chunk-KCLWPSV5.js.map +1 -0
  9. package/dist/{chunk-7D2BHQ6M.js → chunk-L5X4SYJ4.js} +3 -3
  10. package/dist/chunk-L5X4SYJ4.js.map +1 -0
  11. package/dist/{chunk-Y4ZRSW35.js → chunk-OCHEPOOO.js} +3 -3
  12. package/dist/{chunk-Y4ZRSW35.js.map → chunk-OCHEPOOO.js.map} +1 -1
  13. package/dist/{chunk-VMAGFYHG.js → chunk-SJZTETUT.js} +3 -3
  14. package/dist/{chunk-VMAGFYHG.js.map → chunk-SJZTETUT.js.map} +1 -1
  15. package/dist/chunk-XXBN6CIK.js +343 -0
  16. package/dist/chunk-XXBN6CIK.js.map +1 -0
  17. package/dist/chunk-ZPUYNM37.js +3 -0
  18. package/dist/chunk-ZPUYNM37.js.map +1 -0
  19. package/dist/client.cjs +747 -0
  20. package/dist/client.cjs.map +1 -1
  21. package/dist/client.d.cts +4 -1
  22. package/dist/client.d.ts +4 -1
  23. package/dist/client.js +24 -19
  24. package/dist/client.js.map +1 -1
  25. package/dist/components/Accordion/index.js +2 -2
  26. package/dist/components/Breadcrumb/index.cjs.map +1 -1
  27. package/dist/components/Breadcrumb/index.js +3 -2
  28. package/dist/components/ContextMenu/index.cjs +1150 -0
  29. package/dist/components/ContextMenu/index.cjs.map +1 -0
  30. package/dist/components/ContextMenu/index.d.cts +38 -0
  31. package/dist/components/ContextMenu/index.d.ts +38 -0
  32. package/dist/components/ContextMenu/index.js +10 -0
  33. package/dist/components/ContextMenu/index.js.map +1 -0
  34. package/dist/components/DatePicker/index.cjs +3875 -0
  35. package/dist/components/DatePicker/index.cjs.map +1 -0
  36. package/dist/components/DatePicker/index.d.cts +58 -0
  37. package/dist/components/DatePicker/index.d.ts +58 -0
  38. package/dist/components/DatePicker/index.js +15 -0
  39. package/dist/components/DatePicker/index.js.map +1 -0
  40. package/dist/components/DropdownMenu/index.cjs +1032 -0
  41. package/dist/components/DropdownMenu/index.cjs.map +1 -0
  42. package/dist/components/DropdownMenu/index.d.cts +97 -0
  43. package/dist/components/DropdownMenu/index.d.ts +97 -0
  44. package/dist/components/DropdownMenu/index.js +10 -0
  45. package/dist/components/DropdownMenu/index.js.map +1 -0
  46. package/dist/components/Popover/index.cjs +1 -0
  47. package/dist/components/Popover/index.cjs.map +1 -1
  48. package/dist/components/Popover/index.d.cts +22 -1
  49. package/dist/components/Popover/index.d.ts +22 -1
  50. package/dist/components/Popover/index.js +2 -1
  51. package/dist/components/Switch/index.js +2 -2
  52. package/dist/index.cjs +747 -0
  53. package/dist/index.cjs.map +1 -1
  54. package/dist/index.d.cts +4 -1
  55. package/dist/index.d.ts +4 -1
  56. package/dist/index.js +23 -18
  57. package/package.json +1 -1
  58. package/dist/chunk-7D2BHQ6M.js.map +0 -1
@@ -0,0 +1,1032 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var reactNative = require('react-native');
5
+ var jsxRuntime = require('nativewind/jsx-runtime');
6
+
7
+ var __defProp = Object.defineProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+
10
+ // src/slot/compose-refs.ts
11
+ function composeRefs(...refs) {
12
+ return (node) => {
13
+ for (const ref of refs) {
14
+ if (ref == null) {
15
+ continue;
16
+ }
17
+ if (typeof ref === "function") {
18
+ ref(node);
19
+ } else {
20
+ ref.current = node;
21
+ }
22
+ }
23
+ };
24
+ }
25
+ __name(composeRefs, "composeRefs");
26
+ var Slot = react.forwardRef(/* @__PURE__ */ __name(function Slot2(props, forwardedRef) {
27
+ const { children, ...slotProps } = props;
28
+ if (!react.isValidElement(children)) {
29
+ return null;
30
+ }
31
+ const child = react.Children.only(children);
32
+ const merged = mergeProps(slotProps, child.props);
33
+ const childRef = child.ref;
34
+ if (forwardedRef || childRef) {
35
+ merged.ref = composeRefs(forwardedRef, childRef);
36
+ }
37
+ return react.cloneElement(child, merged);
38
+ }, "Slot"));
39
+ Slot.displayName = "Slot";
40
+ function mergeProps(outer, inner) {
41
+ const merged = { ...outer };
42
+ for (const key of Object.keys(inner)) {
43
+ const outerValue = outer[key];
44
+ const innerValue = inner[key];
45
+ if (key === "className" || key === "class") {
46
+ merged[key] = joinClass(outerValue, innerValue);
47
+ continue;
48
+ }
49
+ if (key === "style") {
50
+ merged[key] = {
51
+ ...outerValue,
52
+ ...innerValue
53
+ };
54
+ continue;
55
+ }
56
+ if (isEventHandler(key, outerValue, innerValue)) {
57
+ merged[key] = composeHandlers(outerValue, innerValue);
58
+ continue;
59
+ }
60
+ merged[key] = innerValue;
61
+ }
62
+ return merged;
63
+ }
64
+ __name(mergeProps, "mergeProps");
65
+ function joinClass(outer, inner) {
66
+ const a = typeof outer === "string" ? outer : "";
67
+ const b = typeof inner === "string" ? inner : "";
68
+ const joined = [a, b].filter(Boolean).join(" ");
69
+ return joined.length > 0 ? joined : void 0;
70
+ }
71
+ __name(joinClass, "joinClass");
72
+ function isEventHandler(key, outer, inner) {
73
+ if (!key.startsWith("on") || key.length < 3) {
74
+ return false;
75
+ }
76
+ if (key[2] !== key[2]?.toUpperCase()) {
77
+ return false;
78
+ }
79
+ return typeof outer === "function" && typeof inner === "function";
80
+ }
81
+ __name(isEventHandler, "isEventHandler");
82
+ function composeHandlers(outer, inner) {
83
+ return (...args) => {
84
+ outer(...args);
85
+ inner(...args);
86
+ };
87
+ }
88
+ __name(composeHandlers, "composeHandlers");
89
+
90
+ // src/theme/px.ts
91
+ function px(value) {
92
+ if (typeof value === "number") {
93
+ return value;
94
+ }
95
+ const n = Number.parseFloat(value);
96
+ return Number.isFinite(n) ? n : 0;
97
+ }
98
+ __name(px, "px");
99
+
100
+ // ../tokens/build/theme.ts
101
+ var theme = {
102
+ color: {
103
+ danger: "#ef4444",
104
+ info: "#3b82f6",
105
+ neutral: {
106
+ "100": "#f4f4f5",
107
+ "200": "#e4e4e7",
108
+ "300": "#d4d4d8",
109
+ "400": "#a1a1aa",
110
+ "50": "#fafafa",
111
+ "500": "#71717a",
112
+ "600": "#52525b",
113
+ "700": "#3f3f46",
114
+ "800": "#27272a",
115
+ "900": "#18181b"
116
+ },
117
+ primary: {
118
+ "100": "#ccfbf1",
119
+ "200": "#99f6e4",
120
+ "300": "#5eead4",
121
+ "400": "#2dd4bf",
122
+ "50": "#f0fdfa",
123
+ "500": "#14b8a6",
124
+ "600": "#0d9488",
125
+ "700": "#0f766e",
126
+ "800": "#115e59",
127
+ "900": "#134e4a"
128
+ },
129
+ success: "#22c55e",
130
+ warning: "#f59e0b"
131
+ },
132
+ fontFamily: {
133
+ body: "system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
134
+ display: "ui-serif, Georgia, 'Times New Roman', serif",
135
+ mono: "ui-monospace, 'SF Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace"
136
+ },
137
+ fontSize: {
138
+ "2xl": "24px",
139
+ "3xl": "30px",
140
+ "4xl": "36px",
141
+ lg: "18px",
142
+ md: "16px",
143
+ sm: "14px",
144
+ xl: "20px",
145
+ xs: "12px"
146
+ },
147
+ fontWeight: {
148
+ bold: "700",
149
+ medium: "500",
150
+ regular: "400",
151
+ semibold: "600"
152
+ },
153
+ lineHeight: {
154
+ normal: "1.4",
155
+ relaxed: "1.6",
156
+ tight: "1.2"
157
+ },
158
+ radius: {
159
+ "2xl": "16px",
160
+ full: "9999px",
161
+ lg: "8px",
162
+ md: "6px",
163
+ none: "0px",
164
+ sm: "4px",
165
+ xl: "12px"
166
+ },
167
+ semantic: {
168
+ background: {
169
+ default: "#fafafa",
170
+ elevated: "#ffffff",
171
+ subtle: "#f4f4f5"
172
+ },
173
+ border: {
174
+ default: "#e4e4e7",
175
+ strong: "#d4d4d8"
176
+ },
177
+ interactive: {
178
+ destructive: "#ef4444",
179
+ primary: "#0d9488",
180
+ primaryHover: "#0f766e",
181
+ primaryPressed: "#115e59"
182
+ },
183
+ text: {
184
+ default: "#18181b",
185
+ inverted: "#fafafa",
186
+ muted: "#52525b"
187
+ }
188
+ },
189
+ shadow: {
190
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
191
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
192
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)"
193
+ },
194
+ spacing: {
195
+ "0": "0px",
196
+ "1": "4px",
197
+ "10": "40px",
198
+ "12": "48px",
199
+ "16": "64px",
200
+ "2": "8px",
201
+ "20": "80px",
202
+ "24": "96px",
203
+ "3": "12px",
204
+ "4": "16px",
205
+ "5": "20px",
206
+ "6": "24px",
207
+ "8": "32px"
208
+ }
209
+ };
210
+ var themeDark = {
211
+ color: {
212
+ danger: "#ef4444",
213
+ info: "#3b82f6",
214
+ neutral: {
215
+ "100": "#f4f4f5",
216
+ "200": "#e4e4e7",
217
+ "300": "#d4d4d8",
218
+ "400": "#a1a1aa",
219
+ "50": "#fafafa",
220
+ "500": "#71717a",
221
+ "600": "#52525b",
222
+ "700": "#3f3f46",
223
+ "800": "#27272a",
224
+ "900": "#18181b"
225
+ },
226
+ primary: {
227
+ "100": "#ccfbf1",
228
+ "200": "#99f6e4",
229
+ "300": "#5eead4",
230
+ "400": "#2dd4bf",
231
+ "50": "#f0fdfa",
232
+ "500": "#14b8a6",
233
+ "600": "#0d9488",
234
+ "700": "#0f766e",
235
+ "800": "#115e59",
236
+ "900": "#134e4a"
237
+ },
238
+ success: "#22c55e",
239
+ warning: "#f59e0b"
240
+ },
241
+ fontFamily: {
242
+ body: "system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
243
+ display: "ui-serif, Georgia, 'Times New Roman', serif",
244
+ mono: "ui-monospace, 'SF Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace"
245
+ },
246
+ fontSize: {
247
+ "2xl": "24px",
248
+ "3xl": "30px",
249
+ "4xl": "36px",
250
+ lg: "18px",
251
+ md: "16px",
252
+ sm: "14px",
253
+ xl: "20px",
254
+ xs: "12px"
255
+ },
256
+ fontWeight: {
257
+ bold: "700",
258
+ medium: "500",
259
+ regular: "400",
260
+ semibold: "600"
261
+ },
262
+ lineHeight: {
263
+ normal: "1.4",
264
+ relaxed: "1.6",
265
+ tight: "1.2"
266
+ },
267
+ radius: {
268
+ "2xl": "16px",
269
+ full: "9999px",
270
+ lg: "8px",
271
+ md: "6px",
272
+ none: "0px",
273
+ sm: "4px",
274
+ xl: "12px"
275
+ },
276
+ semantic: {
277
+ background: {
278
+ default: "#18181b",
279
+ elevated: "#3f3f46",
280
+ subtle: "#27272a"
281
+ },
282
+ border: {
283
+ default: "#3f3f46",
284
+ strong: "#52525b"
285
+ },
286
+ interactive: {
287
+ destructive: "#ef4444",
288
+ primary: "#2dd4bf",
289
+ primaryHover: "#5eead4",
290
+ primaryPressed: "#99f6e4"
291
+ },
292
+ text: {
293
+ default: "#fafafa",
294
+ inverted: "#18181b",
295
+ muted: "#a1a1aa"
296
+ }
297
+ },
298
+ shadow: {
299
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
300
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
301
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)"
302
+ },
303
+ spacing: {
304
+ "0": "0px",
305
+ "1": "4px",
306
+ "10": "40px",
307
+ "12": "48px",
308
+ "16": "64px",
309
+ "2": "8px",
310
+ "20": "80px",
311
+ "24": "96px",
312
+ "3": "12px",
313
+ "4": "16px",
314
+ "5": "20px",
315
+ "6": "24px",
316
+ "8": "32px"
317
+ }
318
+ };
319
+ var defaultTheme = {
320
+ light: theme,
321
+ dark: themeDark
322
+ };
323
+ var ThemeContext = react.createContext(defaultTheme);
324
+ ThemeContext.displayName = "ThemeContext";
325
+ var ColorSchemeOverrideContext = react.createContext(null);
326
+ ColorSchemeOverrideContext.displayName = "ColorSchemeOverrideContext";
327
+ var isWeb = reactNative.Platform.OS === "web";
328
+ function readWebScheme() {
329
+ if (typeof document === "undefined") {
330
+ return "light";
331
+ }
332
+ const root = document.documentElement;
333
+ if (root.classList.contains("dark")) {
334
+ return "dark";
335
+ }
336
+ if (root.getAttribute("data-theme") === "dark") {
337
+ return "dark";
338
+ }
339
+ return "light";
340
+ }
341
+ __name(readWebScheme, "readWebScheme");
342
+ function useColorScheme() {
343
+ const override = react.useContext(ColorSchemeOverrideContext);
344
+ const [scheme, setScheme] = react.useState(() => {
345
+ if (isWeb) {
346
+ return readWebScheme();
347
+ }
348
+ return reactNative.Appearance.getColorScheme() ?? "light";
349
+ });
350
+ react.useEffect(() => {
351
+ if (isWeb) {
352
+ const root = document.documentElement;
353
+ const update = /* @__PURE__ */ __name(() => setScheme(readWebScheme()), "update");
354
+ const observer = new MutationObserver(update);
355
+ observer.observe(root, { attributes: true, attributeFilter: ["class", "data-theme"] });
356
+ update();
357
+ return () => observer.disconnect();
358
+ }
359
+ const sub = reactNative.Appearance.addChangeListener(({ colorScheme }) => {
360
+ setScheme(colorScheme ?? "light");
361
+ });
362
+ return () => sub.remove();
363
+ }, []);
364
+ return override ?? scheme;
365
+ }
366
+ __name(useColorScheme, "useColorScheme");
367
+
368
+ // src/theme/use-theme-colors.ts
369
+ function useThemeColors() {
370
+ const scheme = useColorScheme();
371
+ const themePair = react.useContext(ThemeContext);
372
+ return scheme === "dark" ? themePair.dark : themePair.light;
373
+ }
374
+ __name(useThemeColors, "useThemeColors");
375
+
376
+ // src/utils/cn.ts
377
+ function cn(...inputs) {
378
+ const out = [];
379
+ for (const input of inputs) {
380
+ append(out, input);
381
+ }
382
+ return out.join(" ");
383
+ }
384
+ __name(cn, "cn");
385
+ function append(out, input) {
386
+ if (!input) {
387
+ return;
388
+ }
389
+ if (typeof input === "string") {
390
+ if (input.length > 0) {
391
+ out.push(input);
392
+ }
393
+ return;
394
+ }
395
+ if (typeof input === "number") {
396
+ return;
397
+ }
398
+ if (Array.isArray(input)) {
399
+ for (const inner of input) {
400
+ append(out, inner);
401
+ }
402
+ return;
403
+ }
404
+ if (typeof input === "object") {
405
+ for (const key of Object.keys(input)) {
406
+ if (input[key]) {
407
+ out.push(key);
408
+ }
409
+ }
410
+ }
411
+ }
412
+ __name(append, "append");
413
+ var PopoverContext = react.createContext(null);
414
+ var usePopoverContext = /* @__PURE__ */ __name((label) => {
415
+ const ctx = react.useContext(PopoverContext);
416
+ if (!ctx) {
417
+ throw new Error(`<${label}> must be rendered inside a <Popover>.`);
418
+ }
419
+ return ctx;
420
+ }, "usePopoverContext");
421
+ var PopoverRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
422
+ const [inner, setInner] = react.useState(defaultOpen);
423
+ const isControlled = open !== void 0;
424
+ const current = isControlled ? open : inner;
425
+ const setOpen = react.useCallback(
426
+ (next) => {
427
+ if (!isControlled) {
428
+ setInner(next);
429
+ }
430
+ onOpenChange?.(next);
431
+ },
432
+ [isControlled, onOpenChange]
433
+ );
434
+ const baseId = react.useId();
435
+ const triggerRef = react.useRef(null);
436
+ const contentRef = react.useRef(null);
437
+ const [triggerRect, setTriggerRect] = react.useState(null);
438
+ const measureTrigger = react.useCallback(() => {
439
+ const node = triggerRef.current;
440
+ if (!node || typeof node.getBoundingClientRect !== "function") {
441
+ return;
442
+ }
443
+ const rect = node.getBoundingClientRect();
444
+ setTriggerRect({ top: rect.top, left: rect.left, width: rect.width, height: rect.height });
445
+ }, []);
446
+ const ctxValue = {
447
+ open: current,
448
+ setOpen,
449
+ contentId: `${baseId}-content`,
450
+ triggerRef,
451
+ contentRef,
452
+ triggerRect,
453
+ measureTrigger
454
+ };
455
+ return /* @__PURE__ */ jsxRuntime.jsx(PopoverContext.Provider, { value: ctxValue, children });
456
+ }, "PopoverRoot");
457
+ var PopoverTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
458
+ const ctx = usePopoverContext("PopoverTrigger");
459
+ const onPress = react.useCallback(() => {
460
+ ctx.measureTrigger();
461
+ ctx.setOpen(!ctx.open);
462
+ }, [ctx]);
463
+ if (asChild && react.isValidElement(children)) {
464
+ const child = children;
465
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
466
+ existing?.(event);
467
+ ctx.measureTrigger();
468
+ ctx.setOpen(!ctx.open);
469
+ }, "fire");
470
+ return /* @__PURE__ */ jsxRuntime.jsx(
471
+ Slot,
472
+ {
473
+ ref: (node) => {
474
+ ctx.triggerRef.current = node;
475
+ },
476
+ onClick: fire(child.props.onClick),
477
+ onPress: fire(child.props.onPress),
478
+ "aria-haspopup": "dialog",
479
+ "aria-expanded": ctx.open,
480
+ "aria-controls": ctx.contentId,
481
+ ...testID !== void 0 ? { "data-testid": testID } : {},
482
+ ...className !== void 0 ? { className } : {},
483
+ children: child
484
+ }
485
+ );
486
+ }
487
+ return /* @__PURE__ */ jsxRuntime.jsx(
488
+ reactNative.Pressable,
489
+ {
490
+ ref: (node) => {
491
+ ctx.triggerRef.current = node;
492
+ },
493
+ onPress,
494
+ ...{
495
+ "aria-haspopup": "dialog",
496
+ "aria-expanded": ctx.open,
497
+ "aria-controls": ctx.contentId
498
+ },
499
+ ...testID !== void 0 ? { testID } : {},
500
+ ...className !== void 0 ? { className } : {},
501
+ children: wrapStringChildren(children)
502
+ }
503
+ );
504
+ }, "PopoverTrigger");
505
+ function wrapStringChildren(children) {
506
+ if (typeof children === "string" || typeof children === "number") {
507
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
508
+ }
509
+ return children;
510
+ }
511
+ __name(wrapStringChildren, "wrapStringChildren");
512
+ var GAP = 4;
513
+ var MIN_WIDTH = 200;
514
+ var VIEWPORT_MARGIN = 8;
515
+ function computePosition(rect, side, align, contentSize) {
516
+ const cw = contentSize?.width ?? MIN_WIDTH;
517
+ const ch = contentSize?.height ?? 0;
518
+ let top = 0;
519
+ let left = 0;
520
+ switch (side) {
521
+ case "top":
522
+ top = rect.top - GAP - ch;
523
+ break;
524
+ case "bottom":
525
+ top = rect.top + rect.height + GAP;
526
+ break;
527
+ case "left":
528
+ left = rect.left - GAP - cw;
529
+ break;
530
+ case "right":
531
+ left = rect.left + rect.width + GAP;
532
+ break;
533
+ }
534
+ if (side === "top" || side === "bottom") {
535
+ switch (align) {
536
+ case "start":
537
+ left = rect.left;
538
+ break;
539
+ case "center":
540
+ left = rect.left + rect.width / 2 - cw / 2;
541
+ break;
542
+ case "end":
543
+ left = rect.left + rect.width - cw;
544
+ break;
545
+ }
546
+ } else {
547
+ switch (align) {
548
+ case "start":
549
+ top = rect.top;
550
+ break;
551
+ case "center":
552
+ top = rect.top + rect.height / 2 - ch / 2;
553
+ break;
554
+ case "end":
555
+ top = rect.top + rect.height - ch;
556
+ break;
557
+ }
558
+ }
559
+ return { top, left };
560
+ }
561
+ __name(computePosition, "computePosition");
562
+ var PopoverContent = /* @__PURE__ */ __name(({
563
+ side = "bottom",
564
+ align = "center",
565
+ children,
566
+ className,
567
+ testID,
568
+ ...rest
569
+ }) => {
570
+ const ctx = usePopoverContext("PopoverContent");
571
+ const colors = useThemeColors();
572
+ const ariaLabel = rest["aria-label"];
573
+ const [contentSize, setContentSize] = react.useState(null);
574
+ react.useEffect(() => {
575
+ if (!ctx.open) {
576
+ return;
577
+ }
578
+ if (reactNative.Platform.OS !== "web") {
579
+ return;
580
+ }
581
+ if (typeof document === "undefined") {
582
+ return;
583
+ }
584
+ ctx.measureTrigger();
585
+ const onDocMouseDown = /* @__PURE__ */ __name((event) => {
586
+ const target = event.target;
587
+ const trigger = ctx.triggerRef.current;
588
+ const content2 = ctx.contentRef.current;
589
+ if (trigger?.contains(target)) {
590
+ return;
591
+ }
592
+ if (content2?.contains(target)) {
593
+ return;
594
+ }
595
+ ctx.setOpen(false);
596
+ }, "onDocMouseDown");
597
+ const onKeyDown = /* @__PURE__ */ __name((event) => {
598
+ if (event.key === "Escape") {
599
+ event.preventDefault();
600
+ ctx.setOpen(false);
601
+ }
602
+ }, "onKeyDown");
603
+ const onResize = /* @__PURE__ */ __name(() => ctx.measureTrigger(), "onResize");
604
+ const onScroll = /* @__PURE__ */ __name(() => ctx.measureTrigger(), "onScroll");
605
+ document.addEventListener("mousedown", onDocMouseDown);
606
+ document.addEventListener("keydown", onKeyDown);
607
+ window.addEventListener("resize", onResize);
608
+ window.addEventListener("scroll", onScroll, true);
609
+ return () => {
610
+ document.removeEventListener("mousedown", onDocMouseDown);
611
+ document.removeEventListener("keydown", onKeyDown);
612
+ window.removeEventListener("resize", onResize);
613
+ window.removeEventListener("scroll", onScroll, true);
614
+ };
615
+ }, [ctx.open, ctx.measureTrigger, ctx.setOpen, ctx.triggerRef, ctx.contentRef]);
616
+ react.useEffect(() => {
617
+ if (!ctx.open) {
618
+ setContentSize(null);
619
+ }
620
+ }, [ctx.open]);
621
+ if (!ctx.open) {
622
+ return null;
623
+ }
624
+ const position = ctx.triggerRect ? computePosition(ctx.triggerRect, side, align, contentSize) : null;
625
+ const viewportWidth = reactNative.Dimensions.get("window").width;
626
+ const maxContentWidth = Math.max(MIN_WIDTH, viewportWidth - VIEWPORT_MARGIN * 2);
627
+ const contentBaseStyle = {
628
+ minWidth: MIN_WIDTH,
629
+ maxWidth: maxContentWidth,
630
+ borderRadius: px(colors.radius.lg),
631
+ borderWidth: 1,
632
+ borderColor: colors.semantic.border.default,
633
+ backgroundColor: colors.semantic.background.elevated,
634
+ padding: px(colors.spacing["4"]),
635
+ ...reactNative.Platform.OS === "web" ? {
636
+ boxShadow: "0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)",
637
+ // Subtle scale-in. Skipped on native (do nothing fancy there).
638
+ transition: "opacity 120ms ease-out, transform 120ms ease-out",
639
+ transform: "scale(1)",
640
+ opacity: 1
641
+ } : { elevation: 8 }
642
+ };
643
+ const measuredWidth = contentSize?.width ?? maxContentWidth;
644
+ const clampedLeft = position ? Math.min(
645
+ Math.max(VIEWPORT_MARGIN, position.left),
646
+ Math.max(VIEWPORT_MARGIN, viewportWidth - measuredWidth - VIEWPORT_MARGIN)
647
+ ) : 0;
648
+ const positionedStyle = reactNative.Platform.OS === "web" ? position ? {
649
+ position: "fixed",
650
+ top: position.top,
651
+ left: clampedLeft,
652
+ zIndex: 50
653
+ } : {
654
+ // Trigger not yet measured — render off-screen for a
655
+ // frame to avoid a flash at (0,0).
656
+ position: "fixed",
657
+ top: -9999,
658
+ left: -9999,
659
+ zIndex: 50
660
+ } : {};
661
+ const content = /* @__PURE__ */ jsxRuntime.jsx(
662
+ reactNative.View,
663
+ {
664
+ ref: (node) => {
665
+ ctx.contentRef.current = node;
666
+ if (reactNative.Platform.OS !== "web") {
667
+ return;
668
+ }
669
+ if (!node) {
670
+ return;
671
+ }
672
+ if (typeof node.getBoundingClientRect !== "function") {
673
+ return;
674
+ }
675
+ const rect = node.getBoundingClientRect();
676
+ if (!contentSize || contentSize.width !== rect.width || contentSize.height !== rect.height) {
677
+ setContentSize({ width: rect.width, height: rect.height });
678
+ }
679
+ },
680
+ ...{
681
+ role: "dialog",
682
+ id: ctx.contentId,
683
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel, accessibilityLabel: ariaLabel } : {}
684
+ },
685
+ ...testID !== void 0 ? { testID } : {},
686
+ className: cn(
687
+ "rounded-lg border border-semantic-border-default bg-semantic-background-elevated",
688
+ className
689
+ ),
690
+ style: [contentBaseStyle, positionedStyle],
691
+ children
692
+ }
693
+ );
694
+ if (reactNative.Platform.OS === "web") {
695
+ return content;
696
+ }
697
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Modal, { visible: ctx.open, transparent: true, animationType: "fade", onRequestClose: () => ctx.setOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(
698
+ reactNative.Pressable,
699
+ {
700
+ accessibilityRole: "none",
701
+ "aria-hidden": true,
702
+ onPress: () => ctx.setOpen(false),
703
+ style: {
704
+ position: "absolute",
705
+ top: 0,
706
+ left: 0,
707
+ right: 0,
708
+ bottom: 0,
709
+ backgroundColor: "transparent"
710
+ },
711
+ children: /* @__PURE__ */ jsxRuntime.jsx(
712
+ reactNative.Pressable,
713
+ {
714
+ onPress: (event) => event.stopPropagation?.(),
715
+ style: {
716
+ position: "absolute",
717
+ top: ctx.triggerRect ? side === "top" ? Math.max(VIEWPORT_MARGIN, ctx.triggerRect.top - GAP - 80) : ctx.triggerRect.top + ctx.triggerRect.height + GAP : 80,
718
+ // Clamp horizontally so a wide popover near the
719
+ // right edge can still grow leftward without
720
+ // overflowing the screen.
721
+ left: ctx.triggerRect ? Math.min(
722
+ Math.max(VIEWPORT_MARGIN, ctx.triggerRect.left),
723
+ Math.max(VIEWPORT_MARGIN, viewportWidth - measuredWidth - VIEWPORT_MARGIN)
724
+ ) : VIEWPORT_MARGIN * 2
725
+ },
726
+ children: content
727
+ }
728
+ )
729
+ }
730
+ ) });
731
+ }, "PopoverContent");
732
+ var Popover = Object.assign(PopoverRoot, {
733
+ Trigger: PopoverTrigger,
734
+ Content: PopoverContent
735
+ });
736
+ var MenuContext = react.createContext(null);
737
+ var MenuContextProvider = /* @__PURE__ */ __name(({
738
+ open,
739
+ toggle,
740
+ close,
741
+ children
742
+ }) => /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, toggle: toggle ?? close, close }, children }), "MenuContextProvider");
743
+ function useMenuContext(caller) {
744
+ const ctx = react.useContext(MenuContext);
745
+ if (!ctx) {
746
+ throw new Error(`<${caller}> must be rendered inside a <DropdownMenu> or <ContextMenu>.`);
747
+ }
748
+ return ctx;
749
+ }
750
+ __name(useMenuContext, "useMenuContext");
751
+ var MenuContent = /* @__PURE__ */ __name(({
752
+ children,
753
+ className,
754
+ testID,
755
+ side = "bottom",
756
+ align = "start",
757
+ "aria-label": ariaLabel
758
+ }) => {
759
+ const colors = useThemeColors();
760
+ const containerRef = react.useRef(null);
761
+ react.useEffect(() => {
762
+ if (reactNative.Platform.OS !== "web") {
763
+ return;
764
+ }
765
+ if (typeof document === "undefined") {
766
+ return;
767
+ }
768
+ const container = containerRef.current;
769
+ if (!container) {
770
+ return;
771
+ }
772
+ const getItems = /* @__PURE__ */ __name(() => Array.from(container.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')), "getItems");
773
+ const onKeyDown = /* @__PURE__ */ __name((e) => {
774
+ const items = getItems();
775
+ if (items.length === 0) {
776
+ return;
777
+ }
778
+ const focused = document.activeElement;
779
+ const idx = focused ? items.indexOf(focused) : -1;
780
+ switch (e.key) {
781
+ case "ArrowDown":
782
+ e.preventDefault();
783
+ items[idx < items.length - 1 ? idx + 1 : 0]?.focus();
784
+ break;
785
+ case "ArrowUp":
786
+ e.preventDefault();
787
+ items[idx > 0 ? idx - 1 : items.length - 1]?.focus();
788
+ break;
789
+ case "Home":
790
+ e.preventDefault();
791
+ items[0]?.focus();
792
+ break;
793
+ case "End":
794
+ e.preventDefault();
795
+ items[items.length - 1]?.focus();
796
+ break;
797
+ }
798
+ }, "onKeyDown");
799
+ container.addEventListener("keydown", onKeyDown);
800
+ return () => container.removeEventListener("keydown", onKeyDown);
801
+ });
802
+ return /* @__PURE__ */ jsxRuntime.jsx(
803
+ Popover.Content,
804
+ {
805
+ side,
806
+ align,
807
+ ...testID !== void 0 ? { testID } : {},
808
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
809
+ ...className !== void 0 ? { className } : {},
810
+ children: /* @__PURE__ */ jsxRuntime.jsx(
811
+ reactNative.View,
812
+ {
813
+ ref: containerRef,
814
+ ...{
815
+ role: "menu",
816
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {}
817
+ },
818
+ style: {
819
+ minWidth: 160,
820
+ paddingVertical: px(colors.spacing["1"]),
821
+ margin: -px(colors.spacing["4"]),
822
+ borderRadius: px(colors.radius.lg),
823
+ overflow: "hidden"
824
+ },
825
+ children
826
+ }
827
+ )
828
+ }
829
+ );
830
+ }, "MenuContent");
831
+ MenuContent.displayName = "MenuContent";
832
+ var MenuItem = /* @__PURE__ */ __name(({
833
+ onSelect,
834
+ disabled = false,
835
+ destructive = false,
836
+ icon,
837
+ shortcut,
838
+ children,
839
+ className,
840
+ testID
841
+ }) => {
842
+ const colors = useThemeColors();
843
+ const menu = useMenuContext("MenuItem");
844
+ const handlePress = react.useCallback(() => {
845
+ if (disabled) {
846
+ return;
847
+ }
848
+ onSelect?.();
849
+ menu.close();
850
+ }, [disabled, onSelect, menu]);
851
+ const textColor = destructive ? colors.color.danger : disabled ? colors.semantic.text.muted : colors.semantic.text.default;
852
+ return /* @__PURE__ */ jsxRuntime.jsxs(
853
+ reactNative.Pressable,
854
+ {
855
+ onPress: handlePress,
856
+ disabled,
857
+ ...{
858
+ role: "menuitem",
859
+ "aria-disabled": disabled ? "true" : void 0,
860
+ tabIndex: disabled ? -1 : 0,
861
+ onKeyDown: /* @__PURE__ */ __name((e) => {
862
+ if (e.key === "Enter" || e.key === " ") {
863
+ e.preventDefault();
864
+ handlePress();
865
+ }
866
+ }, "onKeyDown")
867
+ },
868
+ ...testID !== void 0 ? { testID } : {},
869
+ className: cn("flex-row items-center gap-2 px-3 py-2", className),
870
+ style: { opacity: disabled ? 0.4 : 1 },
871
+ accessibilityRole: "menuitem",
872
+ accessibilityState: { disabled },
873
+ children: [
874
+ icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
875
+ /* @__PURE__ */ jsxRuntime.jsx(
876
+ reactNative.Text,
877
+ {
878
+ style: {
879
+ flex: 1,
880
+ fontFamily: colors.fontFamily.body,
881
+ fontSize: px(colors.fontSize.sm),
882
+ color: textColor
883
+ },
884
+ children
885
+ }
886
+ ),
887
+ shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
888
+ reactNative.Text,
889
+ {
890
+ ...{ "aria-hidden": "true" },
891
+ style: {
892
+ fontFamily: colors.fontFamily.body,
893
+ fontSize: px(colors.fontSize.xs),
894
+ color: colors.semantic.text.muted
895
+ },
896
+ children: shortcut
897
+ }
898
+ )
899
+ ]
900
+ }
901
+ );
902
+ }, "MenuItem");
903
+ MenuItem.displayName = "MenuItem";
904
+ var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
905
+ const colors = useThemeColors();
906
+ return /* @__PURE__ */ jsxRuntime.jsx(
907
+ reactNative.View,
908
+ {
909
+ ...{ role: "separator" },
910
+ accessibilityRole: "none",
911
+ ...testID !== void 0 ? { testID } : {},
912
+ className: cn("mx-1 my-1", className),
913
+ style: {
914
+ height: 1,
915
+ marginVertical: 4,
916
+ marginHorizontal: 4,
917
+ backgroundColor: colors.semantic.border.default
918
+ }
919
+ }
920
+ );
921
+ }, "MenuSeparator");
922
+ MenuSeparator.displayName = "MenuSeparator";
923
+ var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
924
+ const colors = useThemeColors();
925
+ return /* @__PURE__ */ jsxRuntime.jsx(
926
+ reactNative.View,
927
+ {
928
+ ...{ role: "presentation" },
929
+ ...testID !== void 0 ? { testID } : {},
930
+ className: cn("px-3 pt-2 pb-1", className),
931
+ children: /* @__PURE__ */ jsxRuntime.jsx(
932
+ reactNative.Text,
933
+ {
934
+ style: {
935
+ fontFamily: colors.fontFamily.body,
936
+ fontSize: px(colors.fontSize.xs),
937
+ color: colors.semantic.text.muted,
938
+ textTransform: "uppercase",
939
+ letterSpacing: 0.6,
940
+ fontWeight: "600"
941
+ },
942
+ children
943
+ }
944
+ )
945
+ }
946
+ );
947
+ }, "MenuLabel");
948
+ MenuLabel.displayName = "MenuLabel";
949
+ var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
950
+ const [inner, setInner] = react.useState(defaultOpen);
951
+ const isControlled = open !== void 0;
952
+ const current = isControlled ? open : inner;
953
+ const setOpen = react.useCallback(
954
+ (next) => {
955
+ if (!isControlled) {
956
+ setInner(next);
957
+ }
958
+ onOpenChange?.(next);
959
+ },
960
+ [isControlled, onOpenChange]
961
+ );
962
+ const toggle = react.useCallback(() => setOpen(!current), [setOpen, current]);
963
+ const close = react.useCallback(() => setOpen(false), [setOpen]);
964
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: current, toggle, close, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
965
+ }, "DropdownMenuRoot");
966
+ var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
967
+ const menu = useMenuContext("DropdownMenu.Trigger");
968
+ const popover = usePopoverContext("DropdownMenu.Trigger");
969
+ const onPress = react.useCallback(() => {
970
+ popover.measureTrigger();
971
+ popover.setOpen(!popover.open);
972
+ }, [popover]);
973
+ if (react.isValidElement(children)) {
974
+ const child = children;
975
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
976
+ existing?.(event);
977
+ popover.measureTrigger();
978
+ popover.setOpen(!popover.open);
979
+ }, "fire");
980
+ return /* @__PURE__ */ jsxRuntime.jsx(
981
+ Slot,
982
+ {
983
+ ref: (node) => {
984
+ popover.triggerRef.current = node;
985
+ },
986
+ onClick: fire(child.props.onClick),
987
+ onPress: fire(child.props.onPress),
988
+ ...{
989
+ "aria-haspopup": "menu",
990
+ "aria-expanded": menu.open,
991
+ "aria-controls": popover.contentId
992
+ },
993
+ ...testID !== void 0 ? { "data-testid": testID } : {},
994
+ ...className !== void 0 ? { className } : {},
995
+ children: child
996
+ }
997
+ );
998
+ }
999
+ return /* @__PURE__ */ jsxRuntime.jsx(
1000
+ reactNative.Pressable,
1001
+ {
1002
+ ref: (node) => {
1003
+ popover.triggerRef.current = node;
1004
+ },
1005
+ onPress,
1006
+ ...{
1007
+ "aria-haspopup": "menu",
1008
+ "aria-expanded": menu.open,
1009
+ "aria-controls": popover.contentId
1010
+ },
1011
+ ...testID !== void 0 ? { testID } : {},
1012
+ ...className !== void 0 ? { className } : {},
1013
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
1014
+ }
1015
+ );
1016
+ }, "DropdownMenuTrigger");
1017
+ var DropdownMenuContent = /* @__PURE__ */ __name((props) => /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }), "DropdownMenuContent");
1018
+ var DropdownMenu = Object.assign(DropdownMenuRoot, {
1019
+ Trigger: DropdownMenuTrigger,
1020
+ Content: DropdownMenuContent,
1021
+ Item: MenuItem,
1022
+ Separator: MenuSeparator,
1023
+ Label: MenuLabel
1024
+ });
1025
+
1026
+ exports.DropdownMenu = DropdownMenu;
1027
+ exports.MenuContent = MenuContent;
1028
+ exports.MenuItem = MenuItem;
1029
+ exports.MenuLabel = MenuLabel;
1030
+ exports.MenuSeparator = MenuSeparator;
1031
+ //# sourceMappingURL=index.cjs.map
1032
+ //# sourceMappingURL=index.cjs.map