@nori-ui/core 1.7.0 → 1.9.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 (63) hide show
  1. package/dist/chunk-BOMPFNM4.js +165 -0
  2. package/dist/chunk-BOMPFNM4.js.map +1 -0
  3. package/dist/chunk-BVLOX4A3.js +256 -0
  4. package/dist/chunk-BVLOX4A3.js.map +1 -0
  5. package/dist/{chunk-PLQPBMG2.js → chunk-BXZGCOKT.js} +2 -2
  6. package/dist/{chunk-PLQPBMG2.js.map → chunk-BXZGCOKT.js.map} +1 -1
  7. package/dist/{chunk-RI4Y2C5U.js → chunk-KLK7OMFT.js} +3 -3
  8. package/dist/{chunk-RI4Y2C5U.js.map → chunk-KLK7OMFT.js.map} +1 -1
  9. package/dist/chunk-OHWRTHGL.js +495 -0
  10. package/dist/chunk-OHWRTHGL.js.map +1 -0
  11. package/dist/{chunk-V5QSMDZL.js → chunk-QB6RH6UU.js} +3 -3
  12. package/dist/{chunk-V5QSMDZL.js.map → chunk-QB6RH6UU.js.map} +1 -1
  13. package/dist/chunk-S763GTIZ.js +350 -0
  14. package/dist/chunk-S763GTIZ.js.map +1 -0
  15. package/dist/chunk-UJRVWGK7.js +3 -0
  16. package/dist/chunk-UJRVWGK7.js.map +1 -0
  17. package/dist/chunk-VFUV6XJR.js +257 -0
  18. package/dist/chunk-VFUV6XJR.js.map +1 -0
  19. package/dist/client.cjs +2860 -1386
  20. package/dist/client.cjs.map +1 -1
  21. package/dist/client.d.cts +5 -0
  22. package/dist/client.d.ts +5 -0
  23. package/dist/client.js +23 -17
  24. package/dist/client.js.map +1 -1
  25. package/dist/components/Accordion/index.js +2 -2
  26. package/dist/components/Carousel/index.cjs +297 -0
  27. package/dist/components/Carousel/index.cjs.map +1 -0
  28. package/dist/components/Carousel/index.d.cts +67 -0
  29. package/dist/components/Carousel/index.d.ts +67 -0
  30. package/dist/components/Carousel/index.js +5 -0
  31. package/dist/components/Carousel/index.js.map +1 -0
  32. package/dist/components/Command/index.cjs +1371 -0
  33. package/dist/components/Command/index.cjs.map +1 -0
  34. package/dist/components/Command/index.d.cts +89 -0
  35. package/dist/components/Command/index.d.ts +89 -0
  36. package/dist/components/Command/index.js +11 -0
  37. package/dist/components/Command/index.js.map +1 -0
  38. package/dist/components/Dialog/index.js +2 -1
  39. package/dist/components/HoverCard/index.cjs +894 -0
  40. package/dist/components/HoverCard/index.cjs.map +1 -0
  41. package/dist/components/HoverCard/index.d.cts +66 -0
  42. package/dist/components/HoverCard/index.d.ts +66 -0
  43. package/dist/components/HoverCard/index.js +9 -0
  44. package/dist/components/HoverCard/index.js.map +1 -0
  45. package/dist/components/InputOTP/index.cjs +580 -0
  46. package/dist/components/InputOTP/index.cjs.map +1 -0
  47. package/dist/components/InputOTP/index.d.cts +49 -0
  48. package/dist/components/InputOTP/index.d.ts +49 -0
  49. package/dist/components/InputOTP/index.js +7 -0
  50. package/dist/components/InputOTP/index.js.map +1 -0
  51. package/dist/components/Sidebar/index.cjs +675 -0
  52. package/dist/components/Sidebar/index.cjs.map +1 -0
  53. package/dist/components/Sidebar/index.d.cts +109 -0
  54. package/dist/components/Sidebar/index.d.ts +109 -0
  55. package/dist/components/Sidebar/index.js +7 -0
  56. package/dist/components/Sidebar/index.js.map +1 -0
  57. package/dist/components/Switch/index.js +2 -2
  58. package/dist/index.cjs +2860 -1386
  59. package/dist/index.cjs.map +1 -1
  60. package/dist/index.d.cts +5 -0
  61. package/dist/index.d.ts +5 -0
  62. package/dist/index.js +23 -17
  63. package/package.json +1 -1
package/dist/client.cjs CHANGED
@@ -6519,6 +6519,254 @@ var Card = Object.assign(CardRoot, {
6519
6519
  Content: CardContent,
6520
6520
  Footer: CardFooter
6521
6521
  });
6522
+ var CarouselContext = React.createContext(null);
6523
+ function useCarouselContext(caller) {
6524
+ const ctx = React.useContext(CarouselContext);
6525
+ if (!ctx) {
6526
+ throw new Error(`<${caller}> must be rendered inside <Carousel>.`);
6527
+ }
6528
+ return ctx;
6529
+ }
6530
+ __name(useCarouselContext, "useCarouselContext");
6531
+ var CarouselRoot = /* @__PURE__ */ __name(({
6532
+ index: controlledIndex,
6533
+ defaultIndex = 0,
6534
+ onIndexChange,
6535
+ loop = false,
6536
+ orientation = "horizontal",
6537
+ children,
6538
+ className,
6539
+ testID
6540
+ }) => {
6541
+ const [inner, setInner] = React.useState(defaultIndex);
6542
+ const isControlled = controlledIndex !== void 0;
6543
+ const index = isControlled ? controlledIndex : inner;
6544
+ const [count, setCount] = React.useState(0);
6545
+ const listRef = React.useRef(null);
6546
+ const id = React.useId();
6547
+ const setIndex = React.useCallback(
6548
+ (next2) => {
6549
+ if (!isControlled) {
6550
+ setInner(next2);
6551
+ }
6552
+ onIndexChange?.(next2);
6553
+ },
6554
+ [isControlled, onIndexChange]
6555
+ );
6556
+ const scrollTo = React.useCallback(
6557
+ (idx) => {
6558
+ const list = listRef.current;
6559
+ if (!list) {
6560
+ return;
6561
+ }
6562
+ const item = list.children[idx];
6563
+ if (!item) {
6564
+ return;
6565
+ }
6566
+ item.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "nearest" });
6567
+ setIndex(idx);
6568
+ },
6569
+ [setIndex]
6570
+ );
6571
+ const next = React.useCallback(() => {
6572
+ if (count === 0) {
6573
+ return;
6574
+ }
6575
+ if (index < count - 1) {
6576
+ scrollTo(index + 1);
6577
+ } else if (loop) {
6578
+ scrollTo(0);
6579
+ }
6580
+ }, [index, count, loop, scrollTo]);
6581
+ const prev = React.useCallback(() => {
6582
+ if (count === 0) {
6583
+ return;
6584
+ }
6585
+ if (index > 0) {
6586
+ scrollTo(index - 1);
6587
+ } else if (loop) {
6588
+ scrollTo(count - 1);
6589
+ }
6590
+ }, [index, count, loop, scrollTo]);
6591
+ React.useEffect(() => {
6592
+ const list = listRef.current;
6593
+ if (!list) {
6594
+ return;
6595
+ }
6596
+ const handleScroll = /* @__PURE__ */ __name(() => {
6597
+ const { scrollLeft, scrollTop, offsetWidth, offsetHeight } = list;
6598
+ const pos = orientation === "horizontal" ? scrollLeft : scrollTop;
6599
+ const size = orientation === "horizontal" ? offsetWidth : offsetHeight;
6600
+ if (size === 0) {
6601
+ return;
6602
+ }
6603
+ const newIdx = Math.round(pos / size);
6604
+ if (newIdx !== index) {
6605
+ setIndex(newIdx);
6606
+ }
6607
+ }, "handleScroll");
6608
+ list.addEventListener("scroll", handleScroll, { passive: true });
6609
+ return () => list.removeEventListener("scroll", handleScroll);
6610
+ }, [orientation, index, setIndex]);
6611
+ return /* @__PURE__ */ jsxRuntime.jsx(
6612
+ CarouselContext.Provider,
6613
+ {
6614
+ value: { index, count, loop, orientation, scrollTo, next, prev, listRef, setCount, id },
6615
+ children: /* @__PURE__ */ jsxRuntime.jsx(
6616
+ "section",
6617
+ {
6618
+ "aria-label": testID ?? "Carousel",
6619
+ className: cn("relative overflow-hidden", className),
6620
+ "data-testid": testID,
6621
+ children
6622
+ }
6623
+ )
6624
+ }
6625
+ );
6626
+ }, "CarouselRoot");
6627
+ var CarouselContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
6628
+ const ctx = useCarouselContext("Carousel.Content");
6629
+ const childCount = React.Children.count(children);
6630
+ React.useEffect(() => {
6631
+ ctx.setCount(childCount);
6632
+ }, [childCount, ctx.setCount]);
6633
+ const isHorizontal = ctx.orientation === "horizontal";
6634
+ return /* @__PURE__ */ jsxRuntime.jsx(
6635
+ "div",
6636
+ {
6637
+ ref: ctx.listRef,
6638
+ "data-testid": testID,
6639
+ className: cn(
6640
+ "flex",
6641
+ isHorizontal ? "flex-row overflow-x-auto overflow-y-hidden" : "flex-col overflow-y-auto overflow-x-hidden",
6642
+ className
6643
+ ),
6644
+ style: {
6645
+ scrollSnapType: isHorizontal ? "x mandatory" : "y mandatory",
6646
+ scrollBehavior: "smooth",
6647
+ WebkitOverflowScrolling: "touch",
6648
+ // Hide scrollbar
6649
+ scrollbarWidth: "none",
6650
+ msOverflowStyle: "none"
6651
+ },
6652
+ children
6653
+ }
6654
+ );
6655
+ }, "CarouselContent");
6656
+ var CarouselItem = /* @__PURE__ */ __name(({ children, className, testID }) => {
6657
+ const ctx = useCarouselContext("Carousel.Item");
6658
+ const isHorizontal = ctx.orientation === "horizontal";
6659
+ return /* @__PURE__ */ jsxRuntime.jsx(
6660
+ "div",
6661
+ {
6662
+ "data-testid": testID,
6663
+ className: cn("shrink-0", isHorizontal ? "w-full" : "h-full", className),
6664
+ style: {
6665
+ scrollSnapAlign: "start",
6666
+ minWidth: isHorizontal ? "100%" : void 0,
6667
+ minHeight: !isHorizontal ? "100%" : void 0
6668
+ },
6669
+ children
6670
+ }
6671
+ );
6672
+ }, "CarouselItem");
6673
+ var CarouselPrevious = /* @__PURE__ */ __name(({ className, testID, children }) => {
6674
+ const ctx = useCarouselContext("Carousel.Previous");
6675
+ const disabled = !ctx.loop && ctx.index === 0;
6676
+ return /* @__PURE__ */ jsxRuntime.jsx(
6677
+ "button",
6678
+ {
6679
+ type: "button",
6680
+ "aria-label": "Previous slide",
6681
+ disabled,
6682
+ "data-testid": testID,
6683
+ onClick: ctx.prev,
6684
+ className: cn(
6685
+ "absolute left-2 top-1/2 z-10 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full bg-white/80 shadow hover:bg-white disabled:opacity-40",
6686
+ className
6687
+ ),
6688
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(
6689
+ "svg",
6690
+ {
6691
+ viewBox: "0 0 24 24",
6692
+ fill: "none",
6693
+ stroke: "currentColor",
6694
+ strokeWidth: 2,
6695
+ className: "h-4 w-4",
6696
+ "aria-hidden": "true",
6697
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 18l-6-6 6-6", strokeLinecap: "round", strokeLinejoin: "round" })
6698
+ }
6699
+ )
6700
+ }
6701
+ );
6702
+ }, "CarouselPrevious");
6703
+ var CarouselNext = /* @__PURE__ */ __name(({ className, testID, children }) => {
6704
+ const ctx = useCarouselContext("Carousel.Next");
6705
+ const disabled = !ctx.loop && ctx.index >= ctx.count - 1;
6706
+ return /* @__PURE__ */ jsxRuntime.jsx(
6707
+ "button",
6708
+ {
6709
+ type: "button",
6710
+ "aria-label": "Next slide",
6711
+ disabled,
6712
+ "data-testid": testID,
6713
+ onClick: ctx.next,
6714
+ className: cn(
6715
+ "absolute right-2 top-1/2 z-10 flex h-8 w-8 -translate-y-1/2 items-center justify-center rounded-full bg-white/80 shadow hover:bg-white disabled:opacity-40",
6716
+ className
6717
+ ),
6718
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(
6719
+ "svg",
6720
+ {
6721
+ viewBox: "0 0 24 24",
6722
+ fill: "none",
6723
+ stroke: "currentColor",
6724
+ strokeWidth: 2,
6725
+ className: "h-4 w-4",
6726
+ "aria-hidden": "true",
6727
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 18l6-6-6-6", strokeLinecap: "round", strokeLinejoin: "round" })
6728
+ }
6729
+ )
6730
+ }
6731
+ );
6732
+ }, "CarouselNext");
6733
+ var CarouselDots = /* @__PURE__ */ __name(({ className, testID }) => {
6734
+ const ctx = useCarouselContext("Carousel.Dots");
6735
+ if (ctx.count === 0) {
6736
+ return null;
6737
+ }
6738
+ return /* @__PURE__ */ jsxRuntime.jsx(
6739
+ "div",
6740
+ {
6741
+ role: "tablist",
6742
+ "aria-label": "Slide navigation",
6743
+ "data-testid": testID,
6744
+ className: cn("absolute bottom-3 left-0 right-0 flex items-center justify-center gap-1.5", className),
6745
+ children: Array.from({ length: ctx.count }, (_, i) => /* @__PURE__ */ jsxRuntime.jsx(
6746
+ "button",
6747
+ {
6748
+ type: "button",
6749
+ role: "tab",
6750
+ "aria-selected": i === ctx.index,
6751
+ "aria-label": `Go to slide ${i + 1}`,
6752
+ onClick: () => ctx.scrollTo(i),
6753
+ className: cn(
6754
+ "h-1.5 w-1.5 rounded-full transition-all",
6755
+ i === ctx.index ? "w-3 bg-white" : "bg-white/50 hover:bg-white/75"
6756
+ )
6757
+ },
6758
+ i
6759
+ ))
6760
+ }
6761
+ );
6762
+ }, "CarouselDots");
6763
+ var Carousel = Object.assign(CarouselRoot, {
6764
+ Content: CarouselContent,
6765
+ Item: CarouselItem,
6766
+ Previous: CarouselPrevious,
6767
+ Next: CarouselNext,
6768
+ Dots: CarouselDots
6769
+ });
6522
6770
  var ROW_LAYOUT_BASE = { flexDirection: "row", alignItems: "center" };
6523
6771
  var BOX_LAYOUT_BASE = {
6524
6772
  // 20×20 box — component-density literal — not from theme
@@ -6843,1198 +7091,1198 @@ var Collapsible = Object.assign(CollapsibleRoot, {
6843
7091
  var Combobox = /* @__PURE__ */ __name((props) => {
6844
7092
  return /* @__PURE__ */ jsxRuntime.jsx(Select, { searchable: true, ...props });
6845
7093
  }, "Combobox");
6846
- var MenuContext = React.createContext(null);
6847
- var MenuContextProvider = /* @__PURE__ */ __name(({
6848
- open,
6849
- toggle,
6850
- close,
6851
- children
6852
- }) => /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, toggle: toggle ?? close, close }, children }), "MenuContextProvider");
6853
- function useMenuContext(caller) {
6854
- const ctx = React.useContext(MenuContext);
7094
+ var DialogContext = React.createContext(null);
7095
+ var useDialogContext = /* @__PURE__ */ __name((label) => {
7096
+ const ctx = React.useContext(DialogContext);
6855
7097
  if (!ctx) {
6856
- throw new Error(`<${caller}> must be rendered inside a <DropdownMenu> or <ContextMenu>.`);
7098
+ throw new Error(`<${label}> must be rendered inside a <Dialog>.`);
6857
7099
  }
6858
7100
  return ctx;
7101
+ }, "useDialogContext");
7102
+ var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7103
+ const [inner, setInner] = React.useState(defaultOpen);
7104
+ const isControlled = open !== void 0;
7105
+ const current = isControlled ? open : inner;
7106
+ const setOpen = React.useCallback(
7107
+ (next) => {
7108
+ if (!isControlled) {
7109
+ setInner(next);
7110
+ }
7111
+ onOpenChange?.(next);
7112
+ },
7113
+ [isControlled, onOpenChange]
7114
+ );
7115
+ const baseId = React.useId();
7116
+ const triggerRef = React.useRef(null);
7117
+ const ctxValue = {
7118
+ open: current,
7119
+ setOpen,
7120
+ titleId: `${baseId}-title`,
7121
+ descriptionId: `${baseId}-description`,
7122
+ triggerRef
7123
+ };
7124
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: ctxValue, children });
7125
+ }, "DialogRoot");
7126
+ var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
7127
+ const ctx = useDialogContext("DialogTrigger");
7128
+ const onPress = React.useCallback(() => ctx.setOpen(true), [ctx]);
7129
+ if (asChild && React.isValidElement(children)) {
7130
+ const child = children;
7131
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
7132
+ existing?.(event);
7133
+ ctx.setOpen(true);
7134
+ }, "fire");
7135
+ return /* @__PURE__ */ jsxRuntime.jsx(
7136
+ Slot,
7137
+ {
7138
+ ref: (node) => {
7139
+ ctx.triggerRef.current = node;
7140
+ },
7141
+ onClick: fire(child.props.onClick),
7142
+ onPress: fire(child.props.onPress),
7143
+ ...testID !== void 0 ? { "data-testid": testID } : {},
7144
+ ...className !== void 0 ? { className } : {},
7145
+ children: child
7146
+ }
7147
+ );
7148
+ }
7149
+ return /* @__PURE__ */ jsxRuntime.jsx(
7150
+ reactNative.Pressable,
7151
+ {
7152
+ ref: (node) => {
7153
+ ctx.triggerRef.current = node;
7154
+ },
7155
+ onPress,
7156
+ ...testID !== void 0 ? { testID } : {},
7157
+ ...className !== void 0 ? { className } : {},
7158
+ children: wrapStringChildren4(children)
7159
+ }
7160
+ );
7161
+ }, "DialogTrigger");
7162
+ function wrapStringChildren4(children) {
7163
+ if (typeof children === "string" || typeof children === "number") {
7164
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
7165
+ }
7166
+ return children;
6859
7167
  }
6860
- __name(useMenuContext, "useMenuContext");
6861
- var MenuContent = /* @__PURE__ */ __name(({
6862
- children,
6863
- className,
6864
- testID,
6865
- side = "bottom",
6866
- align = "start",
6867
- "aria-label": ariaLabel
6868
- }) => {
7168
+ __name(wrapStringChildren4, "wrapStringChildren");
7169
+ var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.24)";
7170
+ var BLUR_AMOUNT2 = 4;
7171
+ var OVERLAY_LAYOUT_BASE2 = {
7172
+ position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
7173
+ top: 0,
7174
+ left: 0,
7175
+ right: 0,
7176
+ bottom: 0,
7177
+ alignItems: "center",
7178
+ justifyContent: "center",
7179
+ // On native the BlurBackdrop sibling renders BEHIND this overlay and
7180
+ // already provides dim + frosted-glass via expo-blur's `tint`/`intensity`.
7181
+ // Painting SCRIM_COLOR on top would mask the blur entirely (the user
7182
+ // sees only a flat tint), so the overlay stays transparent and the
7183
+ // BlurView is the dominant visual on native.
7184
+ ...reactNative.Platform.OS === "web" ? { zIndex: 50 } : { backgroundColor: "transparent" }
7185
+ };
7186
+ var CONTENT_LAYOUT_BASE3 = {
7187
+ width: "100%",
7188
+ maxWidth: 480,
7189
+ // component-density literal — not from theme
7190
+ ...reactNative.Platform.OS === "web" ? {
7191
+ boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
7192
+ } : { elevation: 24 }
7193
+ };
7194
+ var FOCUSABLE_SELECTOR2 = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
7195
+ var DialogContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
7196
+ const ctx = useDialogContext("DialogContent");
6869
7197
  const colors = useThemeColors();
6870
- const containerRef = React.useRef(null);
7198
+ const scheme = useColorScheme();
7199
+ const contentRef = React.useRef(null);
7200
+ const overlayStyle = {
7201
+ ...OVERLAY_LAYOUT_BASE2,
7202
+ padding: px(colors.spacing["4"])
7203
+ };
7204
+ const contentStyle = {
7205
+ ...CONTENT_LAYOUT_BASE3,
7206
+ borderRadius: px(colors.radius.xl),
7207
+ padding: px(colors.spacing["6"]),
7208
+ gap: px(colors.spacing["3"])
7209
+ };
7210
+ const [entered, setEntered] = React.useState(false);
6871
7211
  React.useEffect(() => {
6872
7212
  if (reactNative.Platform.OS !== "web") {
7213
+ setEntered(true);
6873
7214
  return;
6874
7215
  }
6875
- if (typeof document === "undefined") {
7216
+ if (!ctx.open) {
7217
+ setEntered(false);
6876
7218
  return;
6877
7219
  }
6878
- const container = containerRef.current;
6879
- if (!container) {
7220
+ const id = requestAnimationFrame(() => setEntered(true));
7221
+ return () => cancelAnimationFrame(id);
7222
+ }, [ctx.open]);
7223
+ const enterStyle = reactNative.Platform.OS === "web" ? {
7224
+ opacity: entered ? 1 : 0,
7225
+ transform: [{ scale: entered ? 1 : 0.96 }],
7226
+ transitionProperty: "opacity, transform",
7227
+ transitionDuration: "150ms",
7228
+ transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)"
7229
+ } : {};
7230
+ const overlayDomRef = React.useRef(null);
7231
+ React.useEffect(() => {
7232
+ if (reactNative.Platform.OS !== "web") {
6880
7233
  return;
6881
7234
  }
6882
- const getItems = /* @__PURE__ */ __name(() => Array.from(container.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')), "getItems");
6883
- const onKeyDown = /* @__PURE__ */ __name((e) => {
6884
- const items = getItems();
6885
- if (items.length === 0) {
6886
- return;
6887
- }
6888
- const focused = document.activeElement;
6889
- const idx = focused ? items.indexOf(focused) : -1;
6890
- switch (e.key) {
6891
- case "ArrowDown":
6892
- e.preventDefault();
6893
- items[idx < items.length - 1 ? idx + 1 : 0]?.focus();
6894
- break;
6895
- case "ArrowUp":
6896
- e.preventDefault();
6897
- items[idx > 0 ? idx - 1 : items.length - 1]?.focus();
6898
- break;
6899
- case "Home":
6900
- e.preventDefault();
6901
- items[0]?.focus();
6902
- break;
6903
- case "End":
6904
- e.preventDefault();
6905
- items[items.length - 1]?.focus();
6906
- break;
6907
- }
6908
- }, "onKeyDown");
6909
- container.addEventListener("keydown", onKeyDown);
6910
- return () => container.removeEventListener("keydown", onKeyDown);
6911
- });
6912
- return /* @__PURE__ */ jsxRuntime.jsx(
6913
- Popover.Content,
6914
- {
6915
- side,
6916
- align,
6917
- ...testID !== void 0 ? { testID } : {},
6918
- ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
6919
- ...className !== void 0 ? { className } : {},
6920
- children: /* @__PURE__ */ jsxRuntime.jsx(
6921
- reactNative.View,
6922
- {
6923
- ref: containerRef,
6924
- ...{
6925
- role: "menu",
6926
- ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {}
6927
- },
6928
- style: {
6929
- minWidth: 160,
6930
- paddingVertical: px(colors.spacing["1"]),
6931
- margin: -px(colors.spacing["4"]),
6932
- borderRadius: px(colors.radius.lg),
6933
- overflow: "hidden"
6934
- },
6935
- children
6936
- }
6937
- )
7235
+ const node = overlayDomRef.current;
7236
+ if (!node) {
7237
+ return;
6938
7238
  }
6939
- );
6940
- }, "MenuContent");
6941
- MenuContent.displayName = "MenuContent";
6942
- var MenuItem = /* @__PURE__ */ __name(({
6943
- onSelect,
6944
- disabled = false,
6945
- destructive = false,
6946
- icon,
6947
- shortcut,
6948
- children,
6949
- className,
6950
- testID
6951
- }) => {
6952
- const colors = useThemeColors();
6953
- const menu = useMenuContext("MenuItem");
6954
- const handlePress = React.useCallback(() => {
6955
- if (disabled) {
7239
+ node.style.transitionProperty = "background-color, backdrop-filter, -webkit-backdrop-filter";
7240
+ node.style.transitionDuration = "150ms, 200ms, 200ms";
7241
+ node.style.transitionTimingFunction = "ease-out";
7242
+ if (entered) {
7243
+ node.style.backgroundColor = SCRIM_COLOR2;
7244
+ node.style.backdropFilter = `blur(${BLUR_AMOUNT2}px)`;
7245
+ node.style.setProperty("-webkit-backdrop-filter", `blur(${BLUR_AMOUNT2}px)`);
7246
+ } else {
7247
+ node.style.backgroundColor = "rgba(0, 0, 0, 0)";
7248
+ node.style.backdropFilter = "blur(0px)";
7249
+ node.style.setProperty("-webkit-backdrop-filter", "blur(0px)");
7250
+ }
7251
+ }, [entered]);
7252
+ React.useEffect(() => {
7253
+ if (!ctx.open) {
6956
7254
  return;
6957
7255
  }
6958
- onSelect?.();
6959
- menu.close();
6960
- }, [disabled, onSelect, menu]);
6961
- const textColor = destructive ? colors.color.danger : disabled ? colors.semantic.text.muted : colors.semantic.text.default;
7256
+ if (reactNative.Platform.OS !== "web") {
7257
+ return;
7258
+ }
7259
+ if (typeof document === "undefined") {
7260
+ return;
7261
+ }
7262
+ const previouslyFocused = document.activeElement;
7263
+ const prevBodyOverflow = document.body.style.overflow;
7264
+ document.body.style.overflow = "hidden";
7265
+ const focusFirst = /* @__PURE__ */ __name(() => {
7266
+ const node = contentRef.current;
7267
+ if (!node) {
7268
+ return;
7269
+ }
7270
+ const focusable = node.querySelectorAll(FOCUSABLE_SELECTOR2);
7271
+ const first = focusable[0];
7272
+ if (first) {
7273
+ first.focus();
7274
+ } else {
7275
+ node.setAttribute("tabindex", "-1");
7276
+ node.focus();
7277
+ }
7278
+ }, "focusFirst");
7279
+ focusFirst();
7280
+ const onKeyDown = /* @__PURE__ */ __name((event) => {
7281
+ if (event.key === "Escape") {
7282
+ event.preventDefault();
7283
+ ctx.setOpen(false);
7284
+ return;
7285
+ }
7286
+ if (event.key !== "Tab") {
7287
+ return;
7288
+ }
7289
+ const node = contentRef.current;
7290
+ if (!node) {
7291
+ return;
7292
+ }
7293
+ const focusable = Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR2)).filter(
7294
+ (el) => el.offsetParent !== null || el === document.activeElement
7295
+ );
7296
+ if (focusable.length === 0) {
7297
+ event.preventDefault();
7298
+ return;
7299
+ }
7300
+ const first = focusable[0];
7301
+ const last = focusable[focusable.length - 1];
7302
+ if (!first || !last) {
7303
+ return;
7304
+ }
7305
+ if (event.shiftKey) {
7306
+ if (document.activeElement === first || !node.contains(document.activeElement)) {
7307
+ event.preventDefault();
7308
+ last.focus();
7309
+ }
7310
+ } else if (document.activeElement === last) {
7311
+ event.preventDefault();
7312
+ first.focus();
7313
+ }
7314
+ }, "onKeyDown");
7315
+ document.addEventListener("keydown", onKeyDown);
7316
+ return () => {
7317
+ document.removeEventListener("keydown", onKeyDown);
7318
+ document.body.style.overflow = prevBodyOverflow;
7319
+ const restoreTo = ctx.triggerRef.current ?? previouslyFocused;
7320
+ restoreTo?.focus?.();
7321
+ };
7322
+ }, [ctx.open, ctx.setOpen, ctx.triggerRef]);
7323
+ const onOverlayPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
6962
7324
  return /* @__PURE__ */ jsxRuntime.jsxs(
6963
- reactNative.Pressable,
7325
+ reactNative.Modal,
6964
7326
  {
6965
- onPress: handlePress,
6966
- disabled,
6967
- ...{
6968
- role: "menuitem",
6969
- "aria-disabled": disabled ? "true" : void 0,
6970
- tabIndex: disabled ? -1 : 0,
6971
- onKeyDown: /* @__PURE__ */ __name((e) => {
6972
- if (e.key === "Enter" || e.key === " ") {
6973
- e.preventDefault();
6974
- handlePress();
6975
- }
6976
- }, "onKeyDown")
6977
- },
6978
- ...testID !== void 0 ? { testID } : {},
6979
- className: cn("flex-row items-center gap-2 px-3 py-2", className),
6980
- style: { opacity: disabled ? 0.4 : 1 },
6981
- accessibilityRole: "menuitem",
6982
- accessibilityState: { disabled },
7327
+ visible: ctx.open,
7328
+ transparent: true,
7329
+ animationType: reactNative.Platform.OS === "web" ? "none" : "fade",
7330
+ onRequestClose: () => ctx.setOpen(false),
6983
7331
  children: [
6984
- icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
7332
+ /* @__PURE__ */ jsxRuntime.jsx(BlurBackdrop, { intensity: 60, tint: scheme === "dark" ? "dark" : "light", style: reactNative.StyleSheet.absoluteFill }),
6985
7333
  /* @__PURE__ */ jsxRuntime.jsx(
6986
- reactNative.Text,
6987
- {
6988
- style: {
6989
- flex: 1,
6990
- fontFamily: colors.fontFamily.body,
6991
- fontSize: px(colors.fontSize.sm),
6992
- color: textColor
6993
- },
6994
- children
6995
- }
6996
- ),
6997
- shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
6998
- reactNative.Text,
7334
+ reactNative.Pressable,
6999
7335
  {
7000
- ...{ "aria-hidden": "true" },
7001
- style: {
7002
- fontFamily: colors.fontFamily.body,
7003
- fontSize: px(colors.fontSize.xs),
7004
- color: colors.semantic.text.muted
7336
+ accessibilityRole: "none",
7337
+ "aria-hidden": true,
7338
+ ref: (node) => {
7339
+ overlayDomRef.current = node;
7005
7340
  },
7006
- children: shortcut
7341
+ style: overlayStyle,
7342
+ onPress: onOverlayPress,
7343
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7344
+ reactNative.Pressable,
7345
+ {
7346
+ onPress: (event) => event.stopPropagation?.(),
7347
+ ref: (node) => {
7348
+ contentRef.current = node;
7349
+ },
7350
+ role: "dialog",
7351
+ accessibilityRole: "none",
7352
+ "aria-modal": true,
7353
+ "aria-labelledby": ctx.titleId,
7354
+ "aria-describedby": ctx.descriptionId,
7355
+ ...testID !== void 0 ? { testID } : {},
7356
+ className: cn("w-full max-w-md rounded-xl bg-semantic-background-elevated p-6 gap-3", className),
7357
+ style: [contentStyle, { backgroundColor: colors.semantic.background.elevated }, enterStyle],
7358
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7359
+ reactNative.View,
7360
+ {
7361
+ className: "flex-col gap-1.5",
7362
+ style: { flexDirection: "column", gap: px(colors.spacing["2"]) - 2 },
7363
+ children
7364
+ }
7365
+ )
7366
+ }
7367
+ )
7007
7368
  }
7008
7369
  )
7009
7370
  ]
7010
7371
  }
7011
7372
  );
7012
- }, "MenuItem");
7013
- MenuItem.displayName = "MenuItem";
7014
- var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
7373
+ }, "DialogContent");
7374
+ var DialogTitle = /* @__PURE__ */ __name(({ children, className }) => {
7375
+ const ctx = useDialogContext("DialogTitle");
7015
7376
  const colors = useThemeColors();
7016
7377
  return /* @__PURE__ */ jsxRuntime.jsx(
7017
- reactNative.View,
7378
+ reactNative.Text,
7018
7379
  {
7019
- ...{ role: "separator" },
7020
- accessibilityRole: "none",
7021
- ...testID !== void 0 ? { testID } : {},
7022
- className: cn("mx-1 my-1", className),
7380
+ nativeID: ctx.titleId,
7381
+ id: ctx.titleId,
7382
+ role: "heading",
7383
+ "aria-level": 2,
7384
+ className: cn("text-lg font-semibold text-semantic-text-default", className),
7023
7385
  style: {
7024
- height: 1,
7025
- marginVertical: 4,
7026
- marginHorizontal: 4,
7027
- backgroundColor: colors.semantic.border.default
7028
- }
7029
- }
7030
- );
7031
- }, "MenuSeparator");
7032
- MenuSeparator.displayName = "MenuSeparator";
7033
- var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
7386
+ color: colors.semantic.text.default,
7387
+ fontFamily: colors.fontFamily.display,
7388
+ fontSize: px(colors.fontSize.lg),
7389
+ fontWeight: colors.fontWeight.semibold
7390
+ },
7391
+ children
7392
+ }
7393
+ );
7394
+ }, "DialogTitle");
7395
+ var DialogDescription = /* @__PURE__ */ __name(({ children, className }) => {
7396
+ const ctx = useDialogContext("DialogDescription");
7034
7397
  const colors = useThemeColors();
7035
7398
  return /* @__PURE__ */ jsxRuntime.jsx(
7036
- reactNative.View,
7399
+ reactNative.Text,
7037
7400
  {
7038
- ...{ role: "presentation" },
7039
- ...testID !== void 0 ? { testID } : {},
7040
- className: cn("px-3 pt-2 pb-1", className),
7041
- children: /* @__PURE__ */ jsxRuntime.jsx(
7042
- reactNative.Text,
7043
- {
7044
- style: {
7045
- fontFamily: colors.fontFamily.body,
7046
- fontSize: px(colors.fontSize.xs),
7047
- color: colors.semantic.text.muted,
7048
- textTransform: "uppercase",
7049
- letterSpacing: 0.6,
7050
- fontWeight: "600"
7051
- },
7052
- children
7053
- }
7054
- )
7401
+ nativeID: ctx.descriptionId,
7402
+ id: ctx.descriptionId,
7403
+ className: cn("text-sm text-semantic-text-muted", className),
7404
+ style: {
7405
+ color: colors.semantic.text.muted,
7406
+ fontFamily: colors.fontFamily.body,
7407
+ fontSize: px(colors.fontSize.sm),
7408
+ lineHeight: px(colors.fontSize.sm) * Number(colors.lineHeight.normal)
7409
+ },
7410
+ children
7055
7411
  }
7056
7412
  );
7057
- }, "MenuLabel");
7058
- MenuLabel.displayName = "MenuLabel";
7059
- var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7060
- const [inner, setInner] = React.useState(defaultOpen);
7061
- const isControlled = open !== void 0;
7062
- const current = isControlled ? open : inner;
7063
- const setOpen = React.useCallback(
7064
- (next) => {
7065
- if (!isControlled) {
7066
- setInner(next);
7067
- }
7068
- onOpenChange?.(next);
7069
- },
7070
- [isControlled, onOpenChange]
7071
- );
7072
- const toggle = React.useCallback(() => setOpen(!current), [setOpen, current]);
7073
- const close = React.useCallback(() => setOpen(false), [setOpen]);
7074
- return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: current, toggle, close, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
7075
- }, "DropdownMenuRoot");
7076
- var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7077
- const menu = useMenuContext("DropdownMenu.Trigger");
7078
- const popover = usePopoverContext("DropdownMenu.Trigger");
7079
- const onPress = React.useCallback(() => {
7080
- popover.measureTrigger();
7081
- popover.setOpen(!popover.open);
7082
- }, [popover]);
7083
- if (React.isValidElement(children)) {
7413
+ }, "DialogDescription");
7414
+ var DialogClose = /* @__PURE__ */ __name(({
7415
+ asChild = true,
7416
+ children,
7417
+ className,
7418
+ testID,
7419
+ accessibilityLabel = "Close"
7420
+ }) => {
7421
+ const ctx = useDialogContext("DialogClose");
7422
+ const colors = useThemeColors();
7423
+ const onPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
7424
+ if (asChild && React.isValidElement(children)) {
7084
7425
  const child = children;
7085
7426
  const fire = /* @__PURE__ */ __name((existing) => (event) => {
7086
7427
  existing?.(event);
7087
- popover.measureTrigger();
7088
- popover.setOpen(!popover.open);
7428
+ ctx.setOpen(false);
7089
7429
  }, "fire");
7090
7430
  return /* @__PURE__ */ jsxRuntime.jsx(
7091
7431
  Slot,
7092
7432
  {
7093
- ref: (node) => {
7094
- popover.triggerRef.current = node;
7095
- },
7096
7433
  onClick: fire(child.props.onClick),
7097
7434
  onPress: fire(child.props.onPress),
7098
- ...{
7099
- "aria-haspopup": "menu",
7100
- "aria-expanded": menu.open,
7101
- "aria-controls": popover.contentId
7102
- },
7103
7435
  ...testID !== void 0 ? { "data-testid": testID } : {},
7104
7436
  ...className !== void 0 ? { className } : {},
7105
7437
  children: child
7106
7438
  }
7107
7439
  );
7108
7440
  }
7441
+ if (children !== void 0) {
7442
+ return /* @__PURE__ */ jsxRuntime.jsx(
7443
+ reactNative.Pressable,
7444
+ {
7445
+ onPress,
7446
+ role: "button",
7447
+ accessibilityRole: "button",
7448
+ accessibilityLabel,
7449
+ "aria-label": accessibilityLabel,
7450
+ ...testID !== void 0 ? { testID } : {},
7451
+ ...className !== void 0 ? { className } : {},
7452
+ children: wrapStringChildren4(children)
7453
+ }
7454
+ );
7455
+ }
7109
7456
  return /* @__PURE__ */ jsxRuntime.jsx(
7110
7457
  reactNative.Pressable,
7111
7458
  {
7112
- ref: (node) => {
7113
- popover.triggerRef.current = node;
7114
- },
7115
7459
  onPress,
7116
- ...{
7117
- "aria-haspopup": "menu",
7118
- "aria-expanded": menu.open,
7119
- "aria-controls": popover.contentId
7120
- },
7460
+ role: "button",
7461
+ accessibilityRole: "button",
7462
+ accessibilityLabel,
7463
+ "aria-label": accessibilityLabel,
7121
7464
  ...testID !== void 0 ? { testID } : {},
7122
- ...className !== void 0 ? { className } : {},
7123
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7465
+ className: cn("absolute right-3 top-3 w-8 h-8 items-center justify-center rounded-md", className),
7466
+ style: {
7467
+ position: "absolute",
7468
+ right: px(colors.spacing["3"]),
7469
+ top: px(colors.spacing["3"]),
7470
+ // 32×32 close hit target — component-density literal — not from theme
7471
+ width: 32,
7472
+ height: 32,
7473
+ alignItems: "center",
7474
+ justifyContent: "center",
7475
+ borderRadius: px(colors.radius.md)
7476
+ },
7477
+ children: /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.close, { size: 18, color: colors.semantic.text.muted })
7124
7478
  }
7125
7479
  );
7126
- }, "DropdownMenuTrigger");
7127
- var DropdownMenuContent = /* @__PURE__ */ __name((props) => /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }), "DropdownMenuContent");
7128
- var DropdownMenu = Object.assign(DropdownMenuRoot, {
7129
- Trigger: DropdownMenuTrigger,
7130
- Content: DropdownMenuContent,
7131
- Item: MenuItem,
7132
- Separator: MenuSeparator,
7133
- Label: MenuLabel
7480
+ }, "DialogClose");
7481
+ var DialogFooter = /* @__PURE__ */ __name(({ children, className }) => {
7482
+ const colors = useThemeColors();
7483
+ return /* @__PURE__ */ jsxRuntime.jsx(
7484
+ reactNative.View,
7485
+ {
7486
+ className: cn("mt-4 flex-row items-center justify-end gap-2", className),
7487
+ style: {
7488
+ marginTop: px(colors.spacing["4"]),
7489
+ flexDirection: "row",
7490
+ alignItems: "center",
7491
+ justifyContent: "flex-end",
7492
+ gap: px(colors.spacing["2"])
7493
+ },
7494
+ children
7495
+ }
7496
+ );
7497
+ }, "DialogFooter");
7498
+ var Dialog = Object.assign(DialogRoot, {
7499
+ Trigger: DialogTrigger,
7500
+ Content: DialogContent,
7501
+ Title: DialogTitle,
7502
+ Description: DialogDescription,
7503
+ Footer: DialogFooter,
7504
+ Close: DialogClose
7134
7505
  });
7135
- var ContextMenuCtx = React.createContext(null);
7136
- var useContextMenuCtx = /* @__PURE__ */ __name(() => {
7137
- const ctx = React.useContext(ContextMenuCtx);
7506
+ var CommandContext = React.createContext(null);
7507
+ function useCommandContext(caller) {
7508
+ const ctx = React.useContext(CommandContext);
7138
7509
  if (!ctx) {
7139
- throw new Error("ContextMenu compound parts must be rendered inside a <ContextMenu>.");
7510
+ throw new Error(`<${caller}> must be rendered inside <Command>.`);
7140
7511
  }
7141
7512
  return ctx;
7142
- }, "useContextMenuCtx");
7143
- var ContextMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7513
+ }
7514
+ __name(useCommandContext, "useCommandContext");
7515
+ var CommandRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7144
7516
  const [inner, setInner] = React.useState(defaultOpen);
7145
7517
  const isControlled = open !== void 0;
7146
7518
  const current = isControlled ? open : inner;
7519
+ const [query, setQuery] = React.useState("");
7147
7520
  const setOpen = React.useCallback(
7148
7521
  (next) => {
7149
7522
  if (!isControlled) {
7150
7523
  setInner(next);
7151
7524
  }
7525
+ if (!next) {
7526
+ setQuery("");
7527
+ }
7152
7528
  onOpenChange?.(next);
7153
7529
  },
7154
7530
  [isControlled, onOpenChange]
7155
7531
  );
7156
- return /* @__PURE__ */ jsxRuntime.jsx(ContextMenuCtx.Provider, { value: { open: current, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
7157
- }, "ContextMenuRoot");
7158
- var ContextMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7159
- const ctx = useContextMenuCtx();
7160
- const popover = usePopoverContext("ContextMenu.Trigger");
7161
- const openMenu = React.useCallback(() => {
7162
- popover.measureTrigger();
7163
- ctx.setOpen(true);
7164
- }, [ctx, popover]);
7532
+ React.useEffect(() => {
7533
+ if (reactNative.Platform.OS !== "web") {
7534
+ return;
7535
+ }
7536
+ const handler = /* @__PURE__ */ __name((e) => {
7537
+ if ((e.metaKey || e.ctrlKey) && e.key === "k") {
7538
+ e.preventDefault();
7539
+ setOpen(!current);
7540
+ }
7541
+ }, "handler");
7542
+ window.addEventListener("keydown", handler);
7543
+ return () => window.removeEventListener("keydown", handler);
7544
+ }, [current, setOpen]);
7545
+ const ctxValue = {
7546
+ open: current,
7547
+ setOpen,
7548
+ query,
7549
+ setQuery
7550
+ };
7551
+ return /* @__PURE__ */ jsxRuntime.jsx(CommandContext.Provider, { value: ctxValue, children });
7552
+ }, "CommandRoot");
7553
+ var CommandTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7554
+ const ctx = useCommandContext("Command.Trigger");
7555
+ const open = /* @__PURE__ */ __name(() => ctx.setOpen(true), "open");
7165
7556
  if (reactNative.Platform.OS === "web") {
7166
7557
  if (React.isValidElement(children)) {
7167
7558
  const child = children;
7168
- const existing = child.props.onContextMenu;
7169
- return /* @__PURE__ */ jsxRuntime.jsx(
7170
- Slot,
7171
- {
7172
- ref: (node) => {
7173
- popover.triggerRef.current = node;
7174
- },
7175
- onContextMenu: (e) => {
7176
- e.preventDefault();
7177
- existing?.(e);
7178
- openMenu();
7179
- },
7180
- ...{
7181
- "aria-haspopup": "menu",
7182
- "aria-expanded": ctx.open,
7183
- "aria-controls": popover.contentId
7184
- },
7185
- ...testID !== void 0 ? { "data-testid": testID } : {},
7186
- ...className !== void 0 ? { className } : {},
7187
- children: child
7188
- }
7189
- );
7190
- }
7191
- return /* @__PURE__ */ jsxRuntime.jsx(
7192
- reactNative.Pressable,
7193
- {
7194
- ref: (node) => {
7195
- popover.triggerRef.current = node;
7196
- },
7197
- ...{
7198
- onContextMenu: /* @__PURE__ */ __name((e) => {
7199
- e.preventDefault();
7200
- openMenu();
7201
- }, "onContextMenu"),
7202
- "aria-haspopup": "menu",
7203
- "aria-expanded": ctx.open,
7204
- "aria-controls": popover.contentId
7205
- },
7206
- ...testID !== void 0 ? { testID } : {},
7207
- ...className !== void 0 ? { className } : {},
7208
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7559
+ const existingOnClick = child.props.onClick;
7560
+ const existingOnPress = child.props.onPress;
7561
+ const fire = /* @__PURE__ */ __name((e) => {
7562
+ existingOnClick?.(e);
7563
+ existingOnPress?.(e);
7564
+ open();
7565
+ }, "fire");
7566
+ const extraProps = {
7567
+ onClick: fire,
7568
+ "aria-haspopup": "dialog",
7569
+ "aria-expanded": ctx.open ? "true" : "false"
7570
+ };
7571
+ if (existingOnPress !== void 0) {
7572
+ extraProps.onPress = fire;
7209
7573
  }
7210
- );
7211
- }
7212
- if (React.isValidElement(children)) {
7213
- const child = children;
7214
- const existing = child.props.onLongPress;
7574
+ return React.cloneElement(child, extraProps);
7575
+ }
7215
7576
  return /* @__PURE__ */ jsxRuntime.jsx(
7216
- Slot,
7577
+ "button",
7217
7578
  {
7218
- ref: (node) => {
7219
- popover.triggerRef.current = node;
7220
- },
7221
- onLongPress: (e) => {
7222
- existing?.(e);
7223
- openMenu();
7224
- },
7225
- accessibilityRole: "button",
7226
- ...testID !== void 0 ? { testID } : {},
7227
- ...className !== void 0 ? { className } : {},
7228
- children: child
7579
+ type: "button",
7580
+ "data-testid": testID,
7581
+ className: cn("nori-command-trigger", className),
7582
+ "aria-haspopup": "dialog",
7583
+ "aria-expanded": ctx.open,
7584
+ onClick: open,
7585
+ children
7586
+ }
7587
+ );
7588
+ }
7589
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { testID, onPress: open, accessibilityRole: "button", children });
7590
+ }, "CommandTrigger");
7591
+ var CommandDialogInner = /* @__PURE__ */ __name(({
7592
+ placeholder = "Type a command or search\u2026",
7593
+ children,
7594
+ className,
7595
+ testID
7596
+ }) => {
7597
+ const ctx = useCommandContext("Command.Dialog");
7598
+ const colors = useThemeColors();
7599
+ const inputRef = React.useRef(null);
7600
+ React.useEffect(() => {
7601
+ if (!ctx.open) {
7602
+ return;
7603
+ }
7604
+ if (reactNative.Platform.OS !== "web") {
7605
+ return;
7606
+ }
7607
+ const id = setTimeout(() => inputRef.current?.focus(), 50);
7608
+ return () => clearTimeout(id);
7609
+ }, [ctx.open]);
7610
+ const contentProps = testID !== void 0 ? { testID, className: cn("nori-command-dialog", className) } : { className: cn("nori-command-dialog", className) };
7611
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: ctx.open, onOpenChange: ctx.setOpen, children: /* @__PURE__ */ jsxRuntime.jsx(Dialog.Content, { ...contentProps, children: reactNative.Platform.OS === "web" ? /* @__PURE__ */ jsxRuntime.jsxs(
7612
+ "div",
7613
+ {
7614
+ style: {
7615
+ maxHeight: "80vh",
7616
+ display: "flex",
7617
+ flexDirection: "column",
7618
+ overflow: "hidden",
7619
+ minWidth: 360
7620
+ },
7621
+ children: [
7622
+ /* @__PURE__ */ jsxRuntime.jsxs(
7623
+ "div",
7624
+ {
7625
+ style: {
7626
+ padding: `${colors.spacing["3"]}px ${colors.spacing["4"]}px`,
7627
+ borderBottom: `1px solid ${colors.semantic.border.default}`,
7628
+ display: "flex",
7629
+ alignItems: "center",
7630
+ gap: colors.spacing["2"]
7631
+ },
7632
+ children: [
7633
+ /* @__PURE__ */ jsxRuntime.jsx(
7634
+ "svg",
7635
+ {
7636
+ width: "16",
7637
+ height: "16",
7638
+ viewBox: "0 0 16 16",
7639
+ fill: "none",
7640
+ "aria-hidden": "true",
7641
+ style: { color: colors.semantic.text.muted, flexShrink: 0 },
7642
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7643
+ "path",
7644
+ {
7645
+ d: "M6.5 11a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM14 14l-3-3",
7646
+ stroke: "currentColor",
7647
+ strokeWidth: "1.5",
7648
+ strokeLinecap: "round",
7649
+ strokeLinejoin: "round"
7650
+ }
7651
+ )
7652
+ }
7653
+ ),
7654
+ /* @__PURE__ */ jsxRuntime.jsx(
7655
+ "input",
7656
+ {
7657
+ ref: inputRef,
7658
+ type: "text",
7659
+ role: "combobox",
7660
+ "aria-expanded": true,
7661
+ "aria-autocomplete": "list",
7662
+ autoComplete: "off",
7663
+ spellCheck: false,
7664
+ placeholder,
7665
+ value: ctx.query,
7666
+ onChange: (e) => ctx.setQuery(e.target.value),
7667
+ style: {
7668
+ flex: 1,
7669
+ fontSize: 15,
7670
+ background: "transparent",
7671
+ border: "none",
7672
+ outline: "none",
7673
+ color: colors.semantic.text.default,
7674
+ width: "100%"
7675
+ }
7676
+ }
7677
+ )
7678
+ ]
7679
+ }
7680
+ ),
7681
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", style: { overflowY: "auto", flex: 1, maxHeight: 400 }, children })
7682
+ ]
7683
+ }
7684
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1 }, children: [
7685
+ /* @__PURE__ */ jsxRuntime.jsx(
7686
+ reactNative.TextInput,
7687
+ {
7688
+ placeholder,
7689
+ placeholderTextColor: colors.semantic.text.muted,
7690
+ value: ctx.query,
7691
+ onChangeText: ctx.setQuery,
7692
+ autoFocus: ctx.open,
7693
+ style: {
7694
+ fontSize: 15,
7695
+ color: colors.semantic.text.default,
7696
+ paddingHorizontal: px(colors.spacing["4"]),
7697
+ paddingVertical: px(colors.spacing["3"]),
7698
+ borderBottomWidth: 1,
7699
+ borderBottomColor: colors.semantic.border.default
7700
+ }
7701
+ }
7702
+ ),
7703
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { style: { maxHeight: 400 }, children })
7704
+ ] }) }) });
7705
+ }, "CommandDialogInner");
7706
+ var CommandEmpty = /* @__PURE__ */ __name(({ children, className, testID }) => {
7707
+ const colors = useThemeColors();
7708
+ if (reactNative.Platform.OS === "web") {
7709
+ return /* @__PURE__ */ jsxRuntime.jsx(
7710
+ "div",
7711
+ {
7712
+ "data-testid": testID,
7713
+ role: "status",
7714
+ "aria-live": "polite",
7715
+ className: cn("nori-command-empty", className),
7716
+ style: {
7717
+ paddingTop: colors.spacing["6"],
7718
+ paddingBottom: colors.spacing["6"],
7719
+ paddingLeft: colors.spacing["4"],
7720
+ paddingRight: colors.spacing["4"],
7721
+ textAlign: "center",
7722
+ color: colors.semantic.text.muted,
7723
+ fontSize: 14
7724
+ },
7725
+ children
7229
7726
  }
7230
7727
  );
7231
7728
  }
7232
7729
  return /* @__PURE__ */ jsxRuntime.jsx(
7233
- reactNative.Pressable,
7730
+ reactNative.View,
7234
7731
  {
7235
- ref: (node) => {
7236
- popover.triggerRef.current = node;
7732
+ testID,
7733
+ style: {
7734
+ paddingVertical: px(colors.spacing["6"]),
7735
+ paddingHorizontal: px(colors.spacing["4"]),
7736
+ alignItems: "center"
7237
7737
  },
7238
- onLongPress: openMenu,
7239
- ...testID !== void 0 ? { testID } : {},
7240
- ...className !== void 0 ? { className } : {},
7241
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7738
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.semantic.text.muted, fontSize: 14 }, children: typeof children === "string" ? children : "No results found." })
7242
7739
  }
7243
7740
  );
7244
- }, "ContextMenuTrigger");
7245
- var ContextMenuContent = /* @__PURE__ */ __name((props) => {
7246
- const ctx = useContextMenuCtx();
7247
- const close = React.useCallback(() => ctx.setOpen(false), [ctx]);
7248
- return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: ctx.open, close, children: /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }) });
7249
- }, "ContextMenuContent");
7250
- var ContextMenu = Object.assign(ContextMenuRoot, {
7251
- Trigger: ContextMenuTrigger,
7252
- Content: ContextMenuContent,
7253
- Item: MenuItem,
7254
- Separator: MenuSeparator,
7255
- Label: MenuLabel
7256
- });
7257
- var range = /* @__PURE__ */ __name((from, to) => {
7258
- if (to < from) {
7259
- return [];
7741
+ }, "CommandEmpty");
7742
+ var CommandGroup = /* @__PURE__ */ __name(({ heading, children, className, testID }) => {
7743
+ const ctx = useCommandContext("Command.Group");
7744
+ const groupId = React.useId();
7745
+ const colors = useThemeColors();
7746
+ const visibleCount = countVisibleItems(children, ctx.query);
7747
+ if (visibleCount === 0) {
7748
+ return null;
7260
7749
  }
7261
- const out = new Array(to - from + 1);
7262
- for (let i = 0; i < out.length; i += 1) {
7263
- out[i] = from + i;
7750
+ if (reactNative.Platform.OS === "web") {
7751
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7752
+ "section",
7753
+ {
7754
+ "data-testid": testID,
7755
+ "aria-labelledby": heading ? `${groupId}-heading` : void 0,
7756
+ className: cn("nori-command-group", className),
7757
+ children: [
7758
+ heading && /* @__PURE__ */ jsxRuntime.jsx(
7759
+ "div",
7760
+ {
7761
+ id: `${groupId}-heading`,
7762
+ style: {
7763
+ padding: `${colors.spacing["2"]}px ${colors.spacing["4"]}px ${colors.spacing["1"]}px`,
7764
+ fontSize: 11,
7765
+ fontWeight: 600,
7766
+ letterSpacing: "0.05em",
7767
+ textTransform: "uppercase",
7768
+ color: colors.semantic.text.muted
7769
+ },
7770
+ children: heading
7771
+ }
7772
+ ),
7773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingBottom: colors.spacing["2"] }, children })
7774
+ ]
7775
+ }
7776
+ );
7264
7777
  }
7265
- return out;
7266
- }, "range");
7267
- function usePagination(args) {
7268
- const {
7269
- page: controlledPage,
7270
- defaultPage = 1,
7271
- pageCount,
7272
- siblingCount = 1,
7273
- boundaryCount = 1,
7274
- showFirstLast = false,
7275
- showPrevNext = true,
7276
- onPageChange
7277
- } = args;
7278
- const isControlled = controlledPage !== void 0;
7279
- const [uncontrolledPage, setUncontrolledPage] = React.useState(defaultPage);
7280
- const onChangeRef = React.useRef(onPageChange);
7281
- onChangeRef.current = onPageChange;
7282
- const safePageCount = Math.max(1, Math.floor(pageCount));
7283
- const rawPage = isControlled ? controlledPage : uncontrolledPage;
7284
- const currentPage = Math.min(Math.max(1, Math.floor(rawPage)), safePageCount);
7285
- const goToPage = React.useCallback(
7286
- (next2) => {
7287
- const clamped = Math.min(Math.max(1, Math.floor(next2)), Math.max(1, Math.floor(pageCount)));
7288
- if (!isControlled) {
7289
- setUncontrolledPage(clamped);
7778
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { testID, children: [
7779
+ heading && /* @__PURE__ */ jsxRuntime.jsx(
7780
+ reactNative.View,
7781
+ {
7782
+ style: {
7783
+ paddingHorizontal: px(colors.spacing["4"]),
7784
+ paddingTop: px(colors.spacing["2"]),
7785
+ paddingBottom: px(colors.spacing["1"])
7786
+ },
7787
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7788
+ reactNative.Text,
7789
+ {
7790
+ style: {
7791
+ fontSize: 11,
7792
+ fontWeight: "600",
7793
+ textTransform: "uppercase",
7794
+ color: colors.semantic.text.muted,
7795
+ letterSpacing: 0.5
7796
+ },
7797
+ children: heading
7798
+ }
7799
+ )
7290
7800
  }
7291
- onChangeRef.current?.(clamped);
7292
- },
7293
- [isControlled, pageCount]
7294
- );
7295
- const prev = React.useCallback(() => goToPage(currentPage - 1), [goToPage, currentPage]);
7296
- const next = React.useCallback(() => goToPage(currentPage + 1), [goToPage, currentPage]);
7297
- const first = React.useCallback(() => goToPage(1), [goToPage]);
7298
- const last = React.useCallback(() => goToPage(safePageCount), [goToPage, safePageCount]);
7299
- const pages = React.useMemo(() => {
7300
- const items = [];
7301
- const safeSibling = Math.max(0, Math.floor(siblingCount));
7302
- const safeBoundary = Math.max(0, Math.floor(boundaryCount));
7303
- if (showFirstLast) {
7304
- items.push({ type: "first", disabled: currentPage <= 1 });
7305
- }
7306
- if (showPrevNext) {
7307
- items.push({ type: "prev", disabled: currentPage <= 1 });
7801
+ ),
7802
+ children
7803
+ ] });
7804
+ }, "CommandGroup");
7805
+ var CommandItem = /* @__PURE__ */ __name(({ onSelect, disabled = false, children, className, testID }) => {
7806
+ const ctx = useCommandContext("Command.Item");
7807
+ const colors = useThemeColors();
7808
+ const text = extractText(children);
7809
+ const visible = matchesQuery(text, ctx.query);
7810
+ if (!visible) {
7811
+ return null;
7812
+ }
7813
+ const handleSelect = /* @__PURE__ */ __name(() => {
7814
+ if (disabled) {
7815
+ return;
7308
7816
  }
7309
- const startPages = range(1, Math.min(safeBoundary, safePageCount));
7310
- const endPages = range(Math.max(safePageCount - safeBoundary + 1, safeBoundary + 1), safePageCount);
7311
- const siblingsStart = Math.max(
7312
- Math.min(currentPage - safeSibling, safePageCount - safeBoundary - safeSibling * 2 - 1),
7313
- safeBoundary + 2
7314
- );
7315
- const siblingsEnd = Math.min(
7316
- Math.max(currentPage + safeSibling, safeBoundary + safeSibling * 2 + 2),
7317
- endPages.length > 0 ? endPages[0] - 2 : safePageCount - 1
7817
+ onSelect?.();
7818
+ ctx.setOpen(false);
7819
+ }, "handleSelect");
7820
+ if (reactNative.Platform.OS === "web") {
7821
+ return /* @__PURE__ */ jsxRuntime.jsx(
7822
+ "div",
7823
+ {
7824
+ "data-testid": testID,
7825
+ role: "option",
7826
+ "aria-selected": "false",
7827
+ "aria-disabled": disabled,
7828
+ tabIndex: disabled ? -1 : 0,
7829
+ className: cn("nori-command-item", className),
7830
+ onClick: handleSelect,
7831
+ onKeyDown: (e) => {
7832
+ if (e.key === "Enter") {
7833
+ e.preventDefault();
7834
+ handleSelect();
7835
+ }
7836
+ },
7837
+ onMouseEnter: (e) => {
7838
+ if (!disabled) {
7839
+ e.currentTarget.style.background = `${colors.semantic.interactive.primary}14`;
7840
+ }
7841
+ },
7842
+ onMouseLeave: (e) => {
7843
+ e.currentTarget.style.background = "transparent";
7844
+ },
7845
+ onFocus: (e) => {
7846
+ if (!disabled) {
7847
+ e.currentTarget.style.background = `${colors.semantic.interactive.primary}14`;
7848
+ }
7849
+ },
7850
+ onBlur: (e) => {
7851
+ e.currentTarget.style.background = "transparent";
7852
+ },
7853
+ style: {
7854
+ display: "flex",
7855
+ alignItems: "center",
7856
+ justifyContent: "space-between",
7857
+ padding: `${colors.spacing["2"]}px ${colors.spacing["4"]}px`,
7858
+ cursor: disabled ? "not-allowed" : "pointer",
7859
+ opacity: disabled ? 0.5 : 1,
7860
+ fontSize: 14,
7861
+ color: colors.semantic.text.default,
7862
+ borderRadius: colors.radius.sm,
7863
+ margin: `0 ${colors.spacing["1"]}px`,
7864
+ outline: "none"
7865
+ },
7866
+ children
7867
+ }
7318
7868
  );
7319
- const middle = [];
7320
- if (siblingsStart > safeBoundary + 2) {
7321
- middle.push("ellipsis");
7322
- } else if (safeBoundary + 1 < safePageCount - safeBoundary) {
7323
- middle.push(safeBoundary + 1);
7869
+ }
7870
+ return /* @__PURE__ */ jsxRuntime.jsx(
7871
+ reactNative.Pressable,
7872
+ {
7873
+ testID,
7874
+ onPress: handleSelect,
7875
+ disabled,
7876
+ accessibilityRole: "button",
7877
+ style: ({ pressed }) => ({
7878
+ flexDirection: "row",
7879
+ alignItems: "center",
7880
+ justifyContent: "space-between",
7881
+ paddingHorizontal: px(colors.spacing["4"]),
7882
+ paddingVertical: px(colors.spacing["3"]),
7883
+ opacity: disabled ? 0.5 : pressed ? 0.7 : 1
7884
+ }),
7885
+ children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14, color: colors.semantic.text.default }, children }) : children
7324
7886
  }
7325
- for (const p of range(siblingsStart, siblingsEnd)) {
7326
- middle.push(p);
7887
+ );
7888
+ }, "CommandItem");
7889
+ var CommandShortcut = /* @__PURE__ */ __name(({ children, className }) => {
7890
+ const colors = useThemeColors();
7891
+ if (reactNative.Platform.OS === "web") {
7892
+ return /* @__PURE__ */ jsxRuntime.jsx(
7893
+ "span",
7894
+ {
7895
+ "aria-hidden": "true",
7896
+ className: cn("nori-command-shortcut", className),
7897
+ style: {
7898
+ marginLeft: "auto",
7899
+ fontSize: 12,
7900
+ color: colors.semantic.text.muted,
7901
+ letterSpacing: "0.05em",
7902
+ opacity: 0.7
7903
+ },
7904
+ children
7905
+ }
7906
+ );
7907
+ }
7908
+ return /* @__PURE__ */ jsxRuntime.jsx(
7909
+ reactNative.Text,
7910
+ {
7911
+ style: {
7912
+ fontSize: 12,
7913
+ color: colors.semantic.text.muted,
7914
+ opacity: 0.7
7915
+ },
7916
+ children: typeof children === "string" ? children : null
7327
7917
  }
7328
- if (siblingsEnd < safePageCount - safeBoundary - 1) {
7329
- middle.push("ellipsis");
7330
- } else if (safePageCount - safeBoundary > safeBoundary) {
7331
- middle.push(safePageCount - safeBoundary);
7918
+ );
7919
+ }, "CommandShortcut");
7920
+ function extractText(node) {
7921
+ if (typeof node === "string" || typeof node === "number") {
7922
+ return String(node);
7923
+ }
7924
+ if (Array.isArray(node)) {
7925
+ return node.map(extractText).join(" ");
7926
+ }
7927
+ if (React.isValidElement(node)) {
7928
+ const el = node;
7929
+ return extractText(el.props.children);
7930
+ }
7931
+ return "";
7932
+ }
7933
+ __name(extractText, "extractText");
7934
+ function matchesQuery(text, query) {
7935
+ if (!query.trim()) {
7936
+ return true;
7937
+ }
7938
+ return text.toLowerCase().includes(query.toLowerCase().trim());
7939
+ }
7940
+ __name(matchesQuery, "matchesQuery");
7941
+ function countVisibleItems(children, query) {
7942
+ let count = 0;
7943
+ React.Children.forEach(children, (child) => {
7944
+ if (!React.isValidElement(child)) {
7945
+ return;
7332
7946
  }
7333
- const seen = /* @__PURE__ */ new Set();
7334
- const pushPage = /* @__PURE__ */ __name((n) => {
7335
- if (n < 1 || n > safePageCount || seen.has(n)) {
7336
- return;
7947
+ const props = child.props;
7948
+ if ("onSelect" in props || !("heading" in props)) {
7949
+ const text = extractText(props.children);
7950
+ if (matchesQuery(text, query)) {
7951
+ count++;
7337
7952
  }
7338
- seen.add(n);
7339
- items.push({ type: "page", page: n, selected: n === currentPage });
7340
- }, "pushPage");
7341
- for (const n of startPages) {
7342
- pushPage(n);
7343
- }
7344
- for (const m of middle) {
7345
- if (m === "ellipsis") {
7346
- items.push({ type: "ellipsis" });
7347
- } else {
7348
- pushPage(m);
7349
- }
7350
- }
7351
- for (const n of endPages) {
7352
- pushPage(n);
7353
- }
7354
- if (showPrevNext) {
7355
- items.push({ type: "next", disabled: currentPage >= safePageCount });
7356
- }
7357
- if (showFirstLast) {
7358
- items.push({ type: "last", disabled: currentPage >= safePageCount });
7359
7953
  }
7360
- return items;
7361
- }, [currentPage, safePageCount, siblingCount, boundaryCount, showFirstLast, showPrevNext]);
7362
- return {
7363
- page: currentPage,
7364
- pages,
7365
- canPrev: currentPage > 1,
7366
- canNext: currentPage < safePageCount,
7367
- goToPage,
7368
- prev,
7369
- next,
7370
- first,
7371
- last
7372
- };
7373
- }
7374
- __name(usePagination, "usePagination");
7375
- var TableContext = React.createContext({
7376
- striped: false,
7377
- compact: false,
7378
- bordered: false,
7379
- rowIndex: 0,
7380
- setRowIndex: /* @__PURE__ */ __name(() => {
7381
- }, "setRowIndex")
7382
- });
7383
- function buildTableCompound(parts) {
7384
- return Object.assign(parts.Root, {
7385
- Header: parts.Header,
7386
- Body: parts.Body,
7387
- Footer: parts.Footer,
7388
- Row: parts.Row,
7389
- HeaderCell: parts.HeaderCell,
7390
- Cell: parts.Cell,
7391
- Caption: parts.Caption
7392
7954
  });
7955
+ return count;
7393
7956
  }
7394
- __name(buildTableCompound, "buildTableCompound");
7395
- var TableRoot = /* @__PURE__ */ __name(({ striped = false, compact = false, bordered = false, children, className, testID }) => {
7396
- const [rowIndex, setRowIndex] = React.useState(0);
7397
- const ctxValue = {
7398
- striped,
7399
- compact,
7400
- bordered,
7401
- rowIndex,
7402
- setRowIndex
7403
- };
7404
- return /* @__PURE__ */ jsxRuntime.jsx(TableContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx(
7405
- "table",
7406
- {
7407
- className: cn(
7408
- "w-full caption-bottom text-sm",
7409
- bordered && "border border-semantic-border-default",
7410
- className
7411
- ),
7412
- ...testID !== void 0 ? { "data-testid": testID } : {},
7413
- children
7414
- }
7415
- ) }) });
7416
- }, "TableRoot");
7417
- var TableHeader = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7418
- "thead",
7419
- {
7420
- className: cn("[&_tr]:border-b [&_tr]:border-semantic-border-default", className),
7421
- ...testID !== void 0 ? { "data-testid": testID } : {},
7422
- children
7423
- }
7424
- ), "TableHeader");
7425
- var TableBody = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7426
- "tbody",
7427
- {
7428
- className: cn("[&_tr:last-child]:border-0", className),
7429
- ...testID !== void 0 ? { "data-testid": testID } : {},
7430
- children
7431
- }
7432
- ), "TableBody");
7433
- var TableFooter = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7434
- "tfoot",
7435
- {
7436
- className: cn("border-t border-semantic-border-default font-medium", className),
7437
- ...testID !== void 0 ? { "data-testid": testID } : {},
7438
- children
7439
- }
7440
- ), "TableFooter");
7441
- var TableRow = /* @__PURE__ */ __name(({ selected = false, onPress, children, className, testID }) => {
7442
- const colors = useThemeColors();
7443
- const handleClick = React.useCallback(() => {
7444
- onPress?.();
7445
- }, [onPress]);
7446
- return /* @__PURE__ */ jsxRuntime.jsx(
7447
- "tr",
7448
- {
7449
- className: cn(
7450
- "border-b border-semantic-border-default transition-colors",
7451
- onPress && "cursor-pointer hover:bg-semantic-background-subtle",
7452
- selected && "bg-semantic-background-subtle",
7453
- className
7454
- ),
7455
- style: selected ? { backgroundColor: colors.semantic.background.subtle } : void 0,
7456
- onClick: onPress ? handleClick : void 0,
7457
- ...testID !== void 0 ? { "data-testid": testID } : {},
7458
- children
7459
- }
7460
- );
7461
- }, "TableRow");
7462
- var TableHeaderCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7463
- "th",
7464
- {
7465
- className: cn(
7466
- "h-10 px-4 font-medium text-semantic-text-secondary",
7467
- align === "right" && "text-right",
7468
- align === "center" && "text-center",
7469
- align === "left" && "text-left",
7470
- className
7471
- ),
7472
- colSpan,
7473
- ...testID !== void 0 ? { "data-testid": testID } : {},
7474
- children
7475
- }
7476
- ), "TableHeaderCell");
7477
- var TableCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7478
- "td",
7479
- {
7480
- className: cn(
7481
- "p-4 align-middle",
7482
- align === "right" && "text-right",
7483
- align === "center" && "text-center",
7484
- align === "left" && "text-left",
7485
- className
7486
- ),
7487
- colSpan,
7488
- ...testID !== void 0 ? { "data-testid": testID } : {},
7489
- children
7490
- }
7491
- ), "TableCell");
7492
- var TableCaption = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7493
- "caption",
7494
- {
7495
- className: cn("mt-4 text-sm text-semantic-text-secondary", className),
7496
- ...testID !== void 0 ? { "data-testid": testID } : {},
7497
- children
7498
- }
7499
- ), "TableCaption");
7500
- var Table = buildTableCompound({
7501
- Root: TableRoot,
7502
- Header: TableHeader,
7503
- Body: TableBody,
7504
- Footer: TableFooter,
7505
- Row: TableRow,
7506
- HeaderCell: TableHeaderCell,
7507
- Cell: TableCell,
7508
- Caption: TableCaption
7509
- });
7510
- function sortData(data, sort) {
7511
- if (!sort) {
7512
- return data;
7513
- }
7514
- const key = sort.id;
7515
- return [...data].sort((a, b) => {
7516
- const av = a[key];
7517
- const bv = b[key];
7518
- if (av == null && bv == null) {
7519
- return 0;
7957
+ __name(countVisibleItems, "countVisibleItems");
7958
+ var CommandDialogWrapper = /* @__PURE__ */ __name((props) => {
7959
+ const ctx = useCommandContext("Command.Dialog");
7960
+ const { children, ...rest } = props;
7961
+ let anyVisible = false;
7962
+ let emptyNode = null;
7963
+ React.Children.forEach(children, (child) => {
7964
+ if (!React.isValidElement(child)) {
7965
+ return;
7520
7966
  }
7521
- if (av == null) {
7522
- return 1;
7967
+ const childProps = child.props;
7968
+ if (!("heading" in childProps) && !("onSelect" in childProps) && !("icon" in childProps)) {
7969
+ emptyNode = child;
7970
+ return;
7523
7971
  }
7524
- if (bv == null) {
7525
- return -1;
7972
+ const groupChildren = childProps.children;
7973
+ const count = countVisibleItems(groupChildren, ctx.query);
7974
+ if (count > 0) {
7975
+ anyVisible = true;
7526
7976
  }
7527
- const cmp2 = av < bv ? -1 : av > bv ? 1 : 0;
7528
- return sort.direction === "asc" ? cmp2 : -cmp2;
7529
7977
  });
7530
- }
7531
- __name(sortData, "sortData");
7532
- function SortIndicator({ direction }) {
7533
- if (direction === void 0) {
7534
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4, opacity: 0.3 }, children: "\u21C5" });
7978
+ return /* @__PURE__ */ jsxRuntime.jsx(CommandDialogInner, { ...rest, children: anyVisible ? children : emptyNode ?? /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No results found." }) });
7979
+ }, "CommandDialogWrapper");
7980
+ var Command = Object.assign(CommandRoot, {
7981
+ Trigger: CommandTrigger,
7982
+ Dialog: CommandDialogWrapper,
7983
+ Empty: CommandEmpty,
7984
+ Group: CommandGroup,
7985
+ Item: CommandItem,
7986
+ Shortcut: CommandShortcut
7987
+ });
7988
+ var MenuContext = React.createContext(null);
7989
+ var MenuContextProvider = /* @__PURE__ */ __name(({
7990
+ open,
7991
+ toggle,
7992
+ close,
7993
+ children
7994
+ }) => /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, toggle: toggle ?? close, close }, children }), "MenuContextProvider");
7995
+ function useMenuContext(caller) {
7996
+ const ctx = React.useContext(MenuContext);
7997
+ if (!ctx) {
7998
+ throw new Error(`<${caller}> must be rendered inside a <DropdownMenu> or <ContextMenu>.`);
7535
7999
  }
7536
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4 }, children: direction === "asc" ? "\u2191" : "\u2193" });
8000
+ return ctx;
7537
8001
  }
7538
- __name(SortIndicator, "SortIndicator");
7539
- function DataTable({
7540
- data,
7541
- columns,
7542
- pageSize = 10,
7543
- defaultSort,
7544
- onRowPress,
7545
- emptyState,
7546
- striped,
7547
- compact,
7548
- bordered,
8002
+ __name(useMenuContext, "useMenuContext");
8003
+ var MenuContent = /* @__PURE__ */ __name(({
8004
+ children,
8005
+ className,
7549
8006
  testID,
7550
- className
7551
- }) {
7552
- const [sort, setSort] = React.useState(defaultSort ?? null);
7553
- const sorted = React.useMemo(() => sortData(data, sort), [data, sort]);
7554
- const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));
7555
- const { page, goToPage, canPrev, canNext } = usePagination({ pageCount, defaultPage: 1 });
7556
- const pageSlice = React.useMemo(() => {
7557
- const start = (page - 1) * pageSize;
7558
- return sorted.slice(start, start + pageSize);
7559
- }, [sorted, page, pageSize]);
7560
- const handleSort = /* @__PURE__ */ __name((colId) => {
7561
- setSort((prev) => {
7562
- if (prev?.id !== colId) {
7563
- goToPage(1);
7564
- return { id: colId, direction: "asc" };
8007
+ side = "bottom",
8008
+ align = "start",
8009
+ "aria-label": ariaLabel
8010
+ }) => {
8011
+ const colors = useThemeColors();
8012
+ const containerRef = React.useRef(null);
8013
+ React.useEffect(() => {
8014
+ if (reactNative.Platform.OS !== "web") {
8015
+ return;
8016
+ }
8017
+ if (typeof document === "undefined") {
8018
+ return;
8019
+ }
8020
+ const container = containerRef.current;
8021
+ if (!container) {
8022
+ return;
8023
+ }
8024
+ const getItems = /* @__PURE__ */ __name(() => Array.from(container.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')), "getItems");
8025
+ const onKeyDown = /* @__PURE__ */ __name((e) => {
8026
+ const items = getItems();
8027
+ if (items.length === 0) {
8028
+ return;
7565
8029
  }
7566
- if (prev.direction === "asc") {
7567
- return { id: colId, direction: "desc" };
8030
+ const focused = document.activeElement;
8031
+ const idx = focused ? items.indexOf(focused) : -1;
8032
+ switch (e.key) {
8033
+ case "ArrowDown":
8034
+ e.preventDefault();
8035
+ items[idx < items.length - 1 ? idx + 1 : 0]?.focus();
8036
+ break;
8037
+ case "ArrowUp":
8038
+ e.preventDefault();
8039
+ items[idx > 0 ? idx - 1 : items.length - 1]?.focus();
8040
+ break;
8041
+ case "Home":
8042
+ e.preventDefault();
8043
+ items[0]?.focus();
8044
+ break;
8045
+ case "End":
8046
+ e.preventDefault();
8047
+ items[items.length - 1]?.focus();
8048
+ break;
7568
8049
  }
7569
- goToPage(1);
7570
- return null;
7571
- });
7572
- }, "handleSort");
7573
- const tableProps = {};
7574
- if (striped !== void 0) {
7575
- tableProps.striped = striped;
7576
- }
7577
- if (compact !== void 0) {
7578
- tableProps.compact = compact;
7579
- }
7580
- if (bordered !== void 0) {
7581
- tableProps.bordered = bordered;
7582
- }
7583
- if (testID !== void 0) {
7584
- tableProps.testID = testID;
7585
- }
7586
- if (className !== void 0) {
7587
- tableProps.className = className;
7588
- }
7589
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { width: "100%" }, children: [
7590
- /* @__PURE__ */ jsxRuntime.jsxs(Table, { ...tableProps, children: [
7591
- /* @__PURE__ */ jsxRuntime.jsx(Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: columns.map((col) => {
7592
- const align = col.align;
7593
- return /* @__PURE__ */ jsxRuntime.jsx(Table.HeaderCell, { ...align !== void 0 ? { align } : {}, children: col.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
7594
- reactNative.Pressable,
7595
- {
7596
- accessibilityRole: "button",
7597
- accessibilityLabel: `Sort by ${col.id}`,
7598
- "aria-label": `Sort by ${col.id}`,
7599
- onPress: () => handleSort(col.id),
7600
- style: { flexDirection: "row", alignItems: "center" },
7601
- children: [
7602
- typeof col.header === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children: col.header }) : col.header,
7603
- /* @__PURE__ */ jsxRuntime.jsx(
7604
- SortIndicator,
7605
- {
7606
- ...sort?.id === col.id ? { direction: sort.direction } : {}
7607
- }
7608
- )
7609
- ]
7610
- }
7611
- ) : col.header }, col.id);
7612
- }) }) }),
7613
- /* @__PURE__ */ jsxRuntime.jsx(Table.Body, { children: pageSlice.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Cell, { colSpan: columns.length, children: /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: emptyState ?? "No data" }) }) }) : pageSlice.map((row, i) => /* @__PURE__ */ jsxRuntime.jsx(
7614
- Table.Row,
8050
+ }, "onKeyDown");
8051
+ container.addEventListener("keydown", onKeyDown);
8052
+ return () => container.removeEventListener("keydown", onKeyDown);
8053
+ });
8054
+ return /* @__PURE__ */ jsxRuntime.jsx(
8055
+ Popover.Content,
8056
+ {
8057
+ side,
8058
+ align,
8059
+ ...testID !== void 0 ? { testID } : {},
8060
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
8061
+ ...className !== void 0 ? { className } : {},
8062
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8063
+ reactNative.View,
7615
8064
  {
7616
- ...onRowPress !== void 0 ? { onPress: /* @__PURE__ */ __name(() => onRowPress(row), "onPress") } : {},
7617
- children: columns.map((col) => {
7618
- const colAlign = col.align;
7619
- return /* @__PURE__ */ jsxRuntime.jsx(
7620
- Table.Cell,
7621
- {
7622
- ...colAlign !== void 0 ? { align: colAlign } : {},
7623
- children: col.cell(row)
7624
- },
7625
- col.id
7626
- );
7627
- })
7628
- },
7629
- i
7630
- )) })
7631
- ] }),
7632
- pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(
7633
- PaginationControls,
7634
- {
7635
- page,
7636
- pageCount,
7637
- canPrev,
7638
- canNext,
7639
- goToPage
7640
- }
7641
- )
7642
- ] });
7643
- }
7644
- __name(DataTable, "DataTable");
7645
- function EmptyState({ children }) {
7646
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { paddingVertical: 32, alignItems: "center" }, children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: "#888", fontSize: 14 }, children }) : children });
7647
- }
7648
- __name(EmptyState, "EmptyState");
7649
- function PaginationControls({
7650
- page,
7651
- pageCount,
7652
- canPrev,
7653
- canNext,
7654
- goToPage
7655
- }) {
8065
+ ref: containerRef,
8066
+ ...{
8067
+ role: "menu",
8068
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {}
8069
+ },
8070
+ style: {
8071
+ minWidth: 160,
8072
+ paddingVertical: px(colors.spacing["1"]),
8073
+ margin: -px(colors.spacing["4"]),
8074
+ borderRadius: px(colors.radius.lg),
8075
+ overflow: "hidden"
8076
+ },
8077
+ children
8078
+ }
8079
+ )
8080
+ }
8081
+ );
8082
+ }, "MenuContent");
8083
+ MenuContent.displayName = "MenuContent";
8084
+ var MenuItem = /* @__PURE__ */ __name(({
8085
+ onSelect,
8086
+ disabled = false,
8087
+ destructive = false,
8088
+ icon,
8089
+ shortcut,
8090
+ children,
8091
+ className,
8092
+ testID
8093
+ }) => {
8094
+ const colors = useThemeColors();
8095
+ const menu = useMenuContext("MenuItem");
8096
+ const handlePress = React.useCallback(() => {
8097
+ if (disabled) {
8098
+ return;
8099
+ }
8100
+ onSelect?.();
8101
+ menu.close();
8102
+ }, [disabled, onSelect, menu]);
8103
+ const textColor = destructive ? colors.color.danger : disabled ? colors.semantic.text.muted : colors.semantic.text.default;
7656
8104
  return /* @__PURE__ */ jsxRuntime.jsxs(
7657
- reactNative.View,
8105
+ reactNative.Pressable,
7658
8106
  {
7659
- style: {
7660
- flexDirection: "row",
7661
- justifyContent: "flex-end",
7662
- alignItems: "center",
7663
- paddingVertical: 8,
7664
- gap: 8
8107
+ onPress: handlePress,
8108
+ disabled,
8109
+ ...{
8110
+ role: "menuitem",
8111
+ "aria-disabled": disabled ? "true" : void 0,
8112
+ tabIndex: disabled ? -1 : 0,
8113
+ onKeyDown: /* @__PURE__ */ __name((e) => {
8114
+ if (e.key === "Enter" || e.key === " ") {
8115
+ e.preventDefault();
8116
+ handlePress();
8117
+ }
8118
+ }, "onKeyDown")
7665
8119
  },
8120
+ ...testID !== void 0 ? { testID } : {},
8121
+ className: cn("flex-row items-center gap-2 px-3 py-2", className),
8122
+ style: { opacity: disabled ? 0.4 : 1 },
8123
+ accessibilityRole: "menuitem",
8124
+ accessibilityState: { disabled },
7666
8125
  children: [
8126
+ icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
7667
8127
  /* @__PURE__ */ jsxRuntime.jsx(
7668
- reactNative.Pressable,
8128
+ reactNative.Text,
7669
8129
  {
7670
- onPress: canPrev ? () => goToPage(page - 1) : void 0,
7671
- accessibilityRole: "button",
7672
- accessibilityLabel: "Previous page",
7673
- "aria-label": "Previous page",
7674
- "aria-disabled": !canPrev,
7675
- style: { opacity: canPrev ? 1 : 0.4, paddingHorizontal: 8 },
7676
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "\u2039 Prev" })
8130
+ style: {
8131
+ flex: 1,
8132
+ fontFamily: colors.fontFamily.body,
8133
+ fontSize: px(colors.fontSize.sm),
8134
+ color: textColor
8135
+ },
8136
+ children
7677
8137
  }
7678
8138
  ),
7679
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: { fontSize: 14 }, "aria-live": "polite", children: [
7680
- page,
7681
- " / ",
7682
- pageCount
7683
- ] }),
7684
- /* @__PURE__ */ jsxRuntime.jsx(
7685
- reactNative.Pressable,
8139
+ shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
8140
+ reactNative.Text,
7686
8141
  {
7687
- onPress: canNext ? () => goToPage(page + 1) : void 0,
7688
- accessibilityRole: "button",
7689
- accessibilityLabel: "Next page",
7690
- "aria-label": "Next page",
7691
- "aria-disabled": !canNext,
7692
- style: { opacity: canNext ? 1 : 0.4, paddingHorizontal: 8 },
7693
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "Next \u203A" })
8142
+ ...{ "aria-hidden": "true" },
8143
+ style: {
8144
+ fontFamily: colors.fontFamily.body,
8145
+ fontSize: px(colors.fontSize.xs),
8146
+ color: colors.semantic.text.muted
8147
+ },
8148
+ children: shortcut
7694
8149
  }
7695
8150
  )
7696
8151
  ]
7697
8152
  }
7698
8153
  );
7699
- }
7700
- __name(PaginationControls, "PaginationControls");
7701
- function formatDate(date$1, locale) {
7702
- try {
7703
- return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date$1.toDate(date.getLocalTimeZone()));
7704
- } catch {
7705
- return `${date$1.year}-${String(date$1.month).padStart(2, "0")}-${String(date$1.day).padStart(2, "0")}`;
7706
- }
7707
- }
7708
- __name(formatDate, "formatDate");
7709
- function CalendarIcon({ size = 16, color = "currentColor" }) {
8154
+ }, "MenuItem");
8155
+ MenuItem.displayName = "MenuItem";
8156
+ var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
7710
8157
  const colors = useThemeColors();
7711
- if (reactNative.Platform.OS === "web") {
7712
- return /* @__PURE__ */ jsxRuntime.jsx(
7713
- "svg",
7714
- {
7715
- width: size,
7716
- height: size,
7717
- viewBox: "0 0 24 24",
7718
- fill: "none",
7719
- stroke: color,
7720
- strokeWidth: "2",
7721
- strokeLinecap: "round",
7722
- strokeLinejoin: "round",
7723
- "aria-hidden": "true",
7724
- children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" })
7725
- }
7726
- );
7727
- }
7728
- const resolvedColor = color === "currentColor" ? colors.semantic.text.muted : color;
7729
8158
  return /* @__PURE__ */ jsxRuntime.jsx(
7730
- reactNative.Text,
8159
+ reactNative.View,
7731
8160
  {
7732
- accessibilityElementsHidden: true,
7733
- importantForAccessibility: "no-hide-descendants",
7734
- style: { fontSize: size, lineHeight: size, color: resolvedColor },
7735
- children: "\u{1F4C5}"
8161
+ ...{ role: "separator" },
8162
+ accessibilityRole: "none",
8163
+ ...testID !== void 0 ? { testID } : {},
8164
+ className: cn("mx-1 my-1", className),
8165
+ style: {
8166
+ height: 1,
8167
+ marginVertical: 4,
8168
+ marginHorizontal: 4,
8169
+ backgroundColor: colors.semantic.border.default
8170
+ }
7736
8171
  }
7737
8172
  );
7738
- }
7739
- __name(CalendarIcon, "CalendarIcon");
7740
- function buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek) {
7741
- const out = {};
7742
- if (minValue !== void 0) {
7743
- out.minValue = minValue;
7744
- }
7745
- if (maxValue !== void 0) {
7746
- out.maxValue = maxValue;
7747
- }
7748
- if (isDateUnavailable !== void 0) {
7749
- out.isDateUnavailable = isDateUnavailable;
7750
- }
7751
- if (firstDayOfWeek !== void 0) {
7752
- out.firstDayOfWeek = firstDayOfWeek;
7753
- }
7754
- return out;
7755
- }
7756
- __name(buildCalendarOptional, "buildCalendarOptional");
7757
- function buildTriggerAriaProps(ariaProps) {
7758
- const out = {};
7759
- if (ariaProps["aria-labelledby"] !== void 0) {
7760
- out["aria-labelledby"] = ariaProps["aria-labelledby"];
7761
- }
7762
- if (ariaProps["aria-describedby"] !== void 0) {
7763
- out["aria-describedby"] = ariaProps["aria-describedby"];
7764
- }
7765
- if (ariaProps["aria-invalid"] !== void 0) {
7766
- out["aria-invalid"] = ariaProps["aria-invalid"];
7767
- }
7768
- if (ariaProps["aria-required"] !== void 0) {
7769
- out["aria-required"] = ariaProps["aria-required"];
7770
- }
7771
- return out;
7772
- }
7773
- __name(buildTriggerAriaProps, "buildTriggerAriaProps");
7774
- var DatePickerRoot = /* @__PURE__ */ __name(({
7775
- value,
7776
- defaultValue: defaultValue2,
7777
- onChange,
7778
- locale: localeProp,
7779
- minValue,
7780
- maxValue,
7781
- isDateUnavailable,
7782
- firstDayOfWeek,
7783
- placeholder,
7784
- disabled = false,
7785
- id,
7786
- name: _name,
7787
- className,
7788
- testID,
7789
- ...ariaProps
7790
- }) => {
7791
- const providerLocale = useLocale();
7792
- const locale = localeProp ?? providerLocale;
7793
- const [open, setOpen] = React.useState(false);
7794
- const isControlled = value !== void 0;
7795
- const [inner, setInner] = React.useState(defaultValue2 ?? null);
7796
- const current = isControlled ? value ?? null : inner;
7797
- const handleChange = React.useCallback(
7798
- (date) => {
7799
- if (!isControlled) {
7800
- setInner(date);
7801
- }
7802
- onChange?.(date);
7803
- setOpen(false);
7804
- },
7805
- [isControlled, onChange]
8173
+ }, "MenuSeparator");
8174
+ MenuSeparator.displayName = "MenuSeparator";
8175
+ var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
8176
+ const colors = useThemeColors();
8177
+ return /* @__PURE__ */ jsxRuntime.jsx(
8178
+ reactNative.View,
8179
+ {
8180
+ ...{ role: "presentation" },
8181
+ ...testID !== void 0 ? { testID } : {},
8182
+ className: cn("px-3 pt-2 pb-1", className),
8183
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8184
+ reactNative.Text,
8185
+ {
8186
+ style: {
8187
+ fontFamily: colors.fontFamily.body,
8188
+ fontSize: px(colors.fontSize.xs),
8189
+ color: colors.semantic.text.muted,
8190
+ textTransform: "uppercase",
8191
+ letterSpacing: 0.6,
8192
+ fontWeight: "600"
8193
+ },
8194
+ children
8195
+ }
8196
+ )
8197
+ }
7806
8198
  );
7807
- const handleOpenChange = React.useCallback(
8199
+ }, "MenuLabel");
8200
+ MenuLabel.displayName = "MenuLabel";
8201
+ var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8202
+ const [inner, setInner] = React.useState(defaultOpen);
8203
+ const isControlled = open !== void 0;
8204
+ const current = isControlled ? open : inner;
8205
+ const setOpen = React.useCallback(
7808
8206
  (next) => {
7809
- if (!disabled) {
7810
- setOpen(next);
8207
+ if (!isControlled) {
8208
+ setInner(next);
7811
8209
  }
8210
+ onOpenChange?.(next);
7812
8211
  },
7813
- [disabled]
8212
+ [isControlled, onOpenChange]
7814
8213
  );
7815
- const displayValue = current ? formatDate(current, locale) : null;
7816
- const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
7817
- const triggerAriaProps = buildTriggerAriaProps(ariaProps);
7818
- const colors = useThemeColors();
7819
- const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
7820
- const pressableStyle = {
7821
- flexDirection: "row",
7822
- alignItems: "center",
7823
- borderWidth: 1,
7824
- borderRadius: px(colors.radius.md),
7825
- paddingHorizontal: px(colors.spacing["3"]),
7826
- paddingVertical: px(colors.spacing["2"]),
7827
- backgroundColor: colors.semantic.background.elevated,
7828
- borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
7829
- opacity: disabled ? 0.6 : 1
7830
- };
7831
- const textStyle = {
7832
- flex: 1,
7833
- fontFamily: colors.fontFamily.body,
7834
- fontSize: px(colors.fontSize.md),
7835
- color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
7836
- };
7837
- const triggerExtraProps = {
7838
- role: "combobox",
7839
- accessibilityRole: "button",
7840
- "aria-haspopup": "dialog",
7841
- "aria-expanded": open,
7842
- ...triggerAriaProps
7843
- };
7844
- if (id !== void 0) {
7845
- triggerExtraProps.id = id;
7846
- triggerExtraProps.nativeID = id;
7847
- }
7848
- if (testID !== void 0) {
7849
- triggerExtraProps.testID = testID;
7850
- }
7851
- if (hasError) {
7852
- triggerExtraProps["aria-invalid"] = true;
7853
- }
7854
- if (ariaProps["aria-required"]) {
7855
- triggerExtraProps["aria-required"] = true;
7856
- }
7857
- if (disabled) {
7858
- triggerExtraProps["aria-disabled"] = true;
7859
- }
7860
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
7861
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
7862
- reactNative.Pressable,
7863
- {
7864
- onPress: disabled ? void 0 : () => setOpen(!open),
7865
- disabled,
7866
- className: cn(
7867
- "flex-row items-center rounded-md border px-3 py-2",
7868
- hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
7869
- disabled ? "opacity-60" : void 0,
7870
- className
7871
- ),
7872
- style: pressableStyle,
7873
- ...triggerExtraProps,
7874
- children: [
7875
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
7876
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
7877
- ]
7878
- }
7879
- ) }),
7880
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
7881
- Calendar,
8214
+ const toggle = React.useCallback(() => setOpen(!current), [setOpen, current]);
8215
+ const close = React.useCallback(() => setOpen(false), [setOpen]);
8216
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: current, toggle, close, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
8217
+ }, "DropdownMenuRoot");
8218
+ var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
8219
+ const menu = useMenuContext("DropdownMenu.Trigger");
8220
+ const popover = usePopoverContext("DropdownMenu.Trigger");
8221
+ const onPress = React.useCallback(() => {
8222
+ popover.measureTrigger();
8223
+ popover.setOpen(!popover.open);
8224
+ }, [popover]);
8225
+ if (React.isValidElement(children)) {
8226
+ const child = children;
8227
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
8228
+ existing?.(event);
8229
+ popover.measureTrigger();
8230
+ popover.setOpen(!popover.open);
8231
+ }, "fire");
8232
+ return /* @__PURE__ */ jsxRuntime.jsx(
8233
+ Slot,
7882
8234
  {
7883
- mode: "single",
7884
- value: current,
7885
- onChange: (date) => {
7886
- handleChange(date);
8235
+ ref: (node) => {
8236
+ popover.triggerRef.current = node;
7887
8237
  },
7888
- locale,
7889
- ...calendarOptional
8238
+ onClick: fire(child.props.onClick),
8239
+ onPress: fire(child.props.onPress),
8240
+ ...{
8241
+ "aria-haspopup": "menu",
8242
+ "aria-expanded": menu.open,
8243
+ "aria-controls": popover.contentId
8244
+ },
8245
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8246
+ ...className !== void 0 ? { className } : {},
8247
+ children: child
7890
8248
  }
7891
- ) })
7892
- ] });
7893
- }, "DatePickerRoot");
7894
- var DatePickerRange = /* @__PURE__ */ __name(({
7895
- value,
7896
- defaultValue: defaultValue2,
7897
- onChange,
7898
- locale: localeProp,
7899
- minValue,
7900
- maxValue,
7901
- isDateUnavailable,
7902
- firstDayOfWeek,
7903
- placeholder,
7904
- disabled = false,
7905
- id,
7906
- name: _name,
7907
- className,
7908
- testID,
7909
- ...ariaProps
7910
- }) => {
7911
- const providerLocale = useLocale();
7912
- const locale = localeProp ?? providerLocale;
7913
- const [open, setOpen] = React.useState(false);
7914
- const isControlled = value !== void 0;
7915
- const [inner, setInner] = React.useState(defaultValue2 ?? { start: null, end: null });
7916
- const current = isControlled ? value ?? { start: null, end: null } : inner;
7917
- const calendarValue = current.start !== null ? { start: current.start, end: current.end } : null;
7918
- const handleChange = React.useCallback(
7919
- (calRange) => {
7920
- const next = {
7921
- start: calRange?.start ?? null,
7922
- end: calRange?.end ?? null
7923
- };
7924
- if (!isControlled) {
7925
- setInner(next);
7926
- }
7927
- onChange?.(next);
7928
- if (next.start !== null && next.end !== null) {
7929
- setOpen(false);
7930
- }
7931
- },
7932
- [isControlled, onChange]
7933
- );
7934
- const handleOpenChange = React.useCallback(
7935
- (next) => {
7936
- if (!disabled) {
7937
- setOpen(next);
7938
- }
7939
- },
7940
- [disabled]
7941
- );
7942
- let displayValue = null;
7943
- if (current.start !== null) {
7944
- const startStr = formatDate(current.start, locale);
7945
- const endStr = current.end !== null ? formatDate(current.end, locale) : "";
7946
- displayValue = `${startStr} \u2013 ${endStr}`;
7947
- }
7948
- const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
7949
- const triggerAriaProps = buildTriggerAriaProps(ariaProps);
7950
- const colors = useThemeColors();
7951
- const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
7952
- const pressableStyle = {
7953
- flexDirection: "row",
7954
- alignItems: "center",
7955
- borderWidth: 1,
7956
- borderRadius: px(colors.radius.md),
7957
- paddingHorizontal: px(colors.spacing["3"]),
7958
- paddingVertical: px(colors.spacing["2"]),
7959
- backgroundColor: colors.semantic.background.elevated,
7960
- borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
7961
- opacity: disabled ? 0.6 : 1
7962
- };
7963
- const textStyle = {
7964
- flex: 1,
7965
- fontFamily: colors.fontFamily.body,
7966
- fontSize: px(colors.fontSize.md),
7967
- color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
7968
- };
7969
- const triggerExtraProps = {
7970
- role: "combobox",
7971
- accessibilityRole: "button",
7972
- "aria-haspopup": "dialog",
7973
- "aria-expanded": open,
7974
- ...triggerAriaProps
7975
- };
7976
- if (id !== void 0) {
7977
- triggerExtraProps.id = id;
7978
- triggerExtraProps.nativeID = id;
7979
- }
7980
- if (testID !== void 0) {
7981
- triggerExtraProps.testID = testID;
7982
- }
7983
- if (hasError) {
7984
- triggerExtraProps["aria-invalid"] = true;
7985
- }
7986
- if (ariaProps["aria-required"]) {
7987
- triggerExtraProps["aria-required"] = true;
7988
- }
7989
- if (disabled) {
7990
- triggerExtraProps["aria-disabled"] = true;
8249
+ );
7991
8250
  }
7992
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
7993
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
7994
- reactNative.Pressable,
7995
- {
7996
- onPress: disabled ? void 0 : () => setOpen(!open),
7997
- disabled,
7998
- className: cn(
7999
- "flex-row items-center rounded-md border px-3 py-2",
8000
- hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
8001
- disabled ? "opacity-60" : void 0,
8002
- className
8003
- ),
8004
- style: pressableStyle,
8005
- ...triggerExtraProps,
8006
- children: [
8007
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
8008
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
8009
- ]
8010
- }
8011
- ) }),
8012
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date range picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
8013
- Calendar,
8014
- {
8015
- mode: "range",
8016
- value: calendarValue,
8017
- onChange: (range2) => {
8018
- handleChange(range2);
8019
- },
8020
- locale,
8021
- ...calendarOptional
8022
- }
8023
- ) })
8024
- ] });
8025
- }, "DatePickerRange");
8026
- var DatePicker = Object.assign(DatePickerRoot, {
8027
- Range: DatePickerRange
8251
+ return /* @__PURE__ */ jsxRuntime.jsx(
8252
+ reactNative.Pressable,
8253
+ {
8254
+ ref: (node) => {
8255
+ popover.triggerRef.current = node;
8256
+ },
8257
+ onPress,
8258
+ ...{
8259
+ "aria-haspopup": "menu",
8260
+ "aria-expanded": menu.open,
8261
+ "aria-controls": popover.contentId
8262
+ },
8263
+ ...testID !== void 0 ? { testID } : {},
8264
+ ...className !== void 0 ? { className } : {},
8265
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8266
+ }
8267
+ );
8268
+ }, "DropdownMenuTrigger");
8269
+ var DropdownMenuContent = /* @__PURE__ */ __name((props) => /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }), "DropdownMenuContent");
8270
+ var DropdownMenu = Object.assign(DropdownMenuRoot, {
8271
+ Trigger: DropdownMenuTrigger,
8272
+ Content: DropdownMenuContent,
8273
+ Item: MenuItem,
8274
+ Separator: MenuSeparator,
8275
+ Label: MenuLabel
8028
8276
  });
8029
- var DialogContext = React.createContext(null);
8030
- var useDialogContext = /* @__PURE__ */ __name((label) => {
8031
- const ctx = React.useContext(DialogContext);
8277
+ var ContextMenuCtx = React.createContext(null);
8278
+ var useContextMenuCtx = /* @__PURE__ */ __name(() => {
8279
+ const ctx = React.useContext(ContextMenuCtx);
8032
8280
  if (!ctx) {
8033
- throw new Error(`<${label}> must be rendered inside a <Dialog>.`);
8281
+ throw new Error("ContextMenu compound parts must be rendered inside a <ContextMenu>.");
8034
8282
  }
8035
8283
  return ctx;
8036
- }, "useDialogContext");
8037
- var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8284
+ }, "useContextMenuCtx");
8285
+ var ContextMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8038
8286
  const [inner, setInner] = React.useState(defaultOpen);
8039
8287
  const isControlled = open !== void 0;
8040
8288
  const current = isControlled ? open : inner;
@@ -8047,35 +8295,77 @@ var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChan
8047
8295
  },
8048
8296
  [isControlled, onOpenChange]
8049
8297
  );
8050
- const baseId = React.useId();
8051
- const triggerRef = React.useRef(null);
8052
- const ctxValue = {
8053
- open: current,
8054
- setOpen,
8055
- titleId: `${baseId}-title`,
8056
- descriptionId: `${baseId}-description`,
8057
- triggerRef
8058
- };
8059
- return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: ctxValue, children });
8060
- }, "DialogRoot");
8061
- var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
8062
- const ctx = useDialogContext("DialogTrigger");
8063
- const onPress = React.useCallback(() => ctx.setOpen(true), [ctx]);
8064
- if (asChild && React.isValidElement(children)) {
8298
+ return /* @__PURE__ */ jsxRuntime.jsx(ContextMenuCtx.Provider, { value: { open: current, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
8299
+ }, "ContextMenuRoot");
8300
+ var ContextMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
8301
+ const ctx = useContextMenuCtx();
8302
+ const popover = usePopoverContext("ContextMenu.Trigger");
8303
+ const openMenu = React.useCallback(() => {
8304
+ popover.measureTrigger();
8305
+ ctx.setOpen(true);
8306
+ }, [ctx, popover]);
8307
+ if (reactNative.Platform.OS === "web") {
8308
+ if (React.isValidElement(children)) {
8309
+ const child = children;
8310
+ const existing = child.props.onContextMenu;
8311
+ return /* @__PURE__ */ jsxRuntime.jsx(
8312
+ Slot,
8313
+ {
8314
+ ref: (node) => {
8315
+ popover.triggerRef.current = node;
8316
+ },
8317
+ onContextMenu: (e) => {
8318
+ e.preventDefault();
8319
+ existing?.(e);
8320
+ openMenu();
8321
+ },
8322
+ ...{
8323
+ "aria-haspopup": "menu",
8324
+ "aria-expanded": ctx.open,
8325
+ "aria-controls": popover.contentId
8326
+ },
8327
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8328
+ ...className !== void 0 ? { className } : {},
8329
+ children: child
8330
+ }
8331
+ );
8332
+ }
8333
+ return /* @__PURE__ */ jsxRuntime.jsx(
8334
+ reactNative.Pressable,
8335
+ {
8336
+ ref: (node) => {
8337
+ popover.triggerRef.current = node;
8338
+ },
8339
+ ...{
8340
+ onContextMenu: /* @__PURE__ */ __name((e) => {
8341
+ e.preventDefault();
8342
+ openMenu();
8343
+ }, "onContextMenu"),
8344
+ "aria-haspopup": "menu",
8345
+ "aria-expanded": ctx.open,
8346
+ "aria-controls": popover.contentId
8347
+ },
8348
+ ...testID !== void 0 ? { testID } : {},
8349
+ ...className !== void 0 ? { className } : {},
8350
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8351
+ }
8352
+ );
8353
+ }
8354
+ if (React.isValidElement(children)) {
8065
8355
  const child = children;
8066
- const fire = /* @__PURE__ */ __name((existing) => (event) => {
8067
- existing?.(event);
8068
- ctx.setOpen(true);
8069
- }, "fire");
8356
+ const existing = child.props.onLongPress;
8070
8357
  return /* @__PURE__ */ jsxRuntime.jsx(
8071
8358
  Slot,
8072
8359
  {
8073
8360
  ref: (node) => {
8074
- ctx.triggerRef.current = node;
8361
+ popover.triggerRef.current = node;
8075
8362
  },
8076
- onClick: fire(child.props.onClick),
8077
- onPress: fire(child.props.onPress),
8078
- ...testID !== void 0 ? { "data-testid": testID } : {},
8363
+ onLongPress: (e) => {
8364
+ existing?.(e);
8365
+ openMenu();
8366
+ },
8367
+ accessibilityRole: "button",
8368
+ ...testID !== void 0 ? { testID } : {},
8079
8369
  ...className !== void 0 ? { className } : {},
8080
8370
  children: child
8081
8371
  }
@@ -8085,358 +8375,798 @@ var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, classNam
8085
8375
  reactNative.Pressable,
8086
8376
  {
8087
8377
  ref: (node) => {
8088
- ctx.triggerRef.current = node;
8378
+ popover.triggerRef.current = node;
8089
8379
  },
8090
- onPress,
8380
+ onLongPress: openMenu,
8091
8381
  ...testID !== void 0 ? { testID } : {},
8092
8382
  ...className !== void 0 ? { className } : {},
8093
- children: wrapStringChildren4(children)
8383
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8094
8384
  }
8095
8385
  );
8096
- }, "DialogTrigger");
8097
- function wrapStringChildren4(children) {
8098
- if (typeof children === "string" || typeof children === "number") {
8099
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
8100
- }
8101
- return children;
8102
- }
8103
- __name(wrapStringChildren4, "wrapStringChildren");
8104
- var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.24)";
8105
- var BLUR_AMOUNT2 = 4;
8106
- var OVERLAY_LAYOUT_BASE2 = {
8107
- position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
8108
- top: 0,
8109
- left: 0,
8110
- right: 0,
8111
- bottom: 0,
8112
- alignItems: "center",
8113
- justifyContent: "center",
8114
- // On native the BlurBackdrop sibling renders BEHIND this overlay and
8115
- // already provides dim + frosted-glass via expo-blur's `tint`/`intensity`.
8116
- // Painting SCRIM_COLOR on top would mask the blur entirely (the user
8117
- // sees only a flat tint), so the overlay stays transparent and the
8118
- // BlurView is the dominant visual on native.
8119
- ...reactNative.Platform.OS === "web" ? { zIndex: 50 } : { backgroundColor: "transparent" }
8120
- };
8121
- var CONTENT_LAYOUT_BASE3 = {
8122
- width: "100%",
8123
- maxWidth: 480,
8124
- // component-density literal — not from theme
8125
- ...reactNative.Platform.OS === "web" ? {
8126
- boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
8127
- } : { elevation: 24 }
8128
- };
8129
- var FOCUSABLE_SELECTOR2 = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
8130
- var DialogContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
8131
- const ctx = useDialogContext("DialogContent");
8132
- const colors = useThemeColors();
8133
- const scheme = useColorScheme();
8134
- const contentRef = React.useRef(null);
8135
- const overlayStyle = {
8136
- ...OVERLAY_LAYOUT_BASE2,
8137
- padding: px(colors.spacing["4"])
8138
- };
8139
- const contentStyle = {
8140
- ...CONTENT_LAYOUT_BASE3,
8141
- borderRadius: px(colors.radius.xl),
8142
- padding: px(colors.spacing["6"]),
8143
- gap: px(colors.spacing["3"])
8144
- };
8145
- const [entered, setEntered] = React.useState(false);
8146
- React.useEffect(() => {
8147
- if (reactNative.Platform.OS !== "web") {
8148
- setEntered(true);
8149
- return;
8150
- }
8151
- if (!ctx.open) {
8152
- setEntered(false);
8153
- return;
8154
- }
8155
- const id = requestAnimationFrame(() => setEntered(true));
8156
- return () => cancelAnimationFrame(id);
8157
- }, [ctx.open]);
8158
- const enterStyle = reactNative.Platform.OS === "web" ? {
8159
- opacity: entered ? 1 : 0,
8160
- transform: [{ scale: entered ? 1 : 0.96 }],
8161
- transitionProperty: "opacity, transform",
8162
- transitionDuration: "150ms",
8163
- transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)"
8164
- } : {};
8165
- const overlayDomRef = React.useRef(null);
8166
- React.useEffect(() => {
8167
- if (reactNative.Platform.OS !== "web") {
8168
- return;
8169
- }
8170
- const node = overlayDomRef.current;
8171
- if (!node) {
8172
- return;
8386
+ }, "ContextMenuTrigger");
8387
+ var ContextMenuContent = /* @__PURE__ */ __name((props) => {
8388
+ const ctx = useContextMenuCtx();
8389
+ const close = React.useCallback(() => ctx.setOpen(false), [ctx]);
8390
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: ctx.open, close, children: /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }) });
8391
+ }, "ContextMenuContent");
8392
+ var ContextMenu = Object.assign(ContextMenuRoot, {
8393
+ Trigger: ContextMenuTrigger,
8394
+ Content: ContextMenuContent,
8395
+ Item: MenuItem,
8396
+ Separator: MenuSeparator,
8397
+ Label: MenuLabel
8398
+ });
8399
+ var range = /* @__PURE__ */ __name((from, to) => {
8400
+ if (to < from) {
8401
+ return [];
8402
+ }
8403
+ const out = new Array(to - from + 1);
8404
+ for (let i = 0; i < out.length; i += 1) {
8405
+ out[i] = from + i;
8406
+ }
8407
+ return out;
8408
+ }, "range");
8409
+ function usePagination(args) {
8410
+ const {
8411
+ page: controlledPage,
8412
+ defaultPage = 1,
8413
+ pageCount,
8414
+ siblingCount = 1,
8415
+ boundaryCount = 1,
8416
+ showFirstLast = false,
8417
+ showPrevNext = true,
8418
+ onPageChange
8419
+ } = args;
8420
+ const isControlled = controlledPage !== void 0;
8421
+ const [uncontrolledPage, setUncontrolledPage] = React.useState(defaultPage);
8422
+ const onChangeRef = React.useRef(onPageChange);
8423
+ onChangeRef.current = onPageChange;
8424
+ const safePageCount = Math.max(1, Math.floor(pageCount));
8425
+ const rawPage = isControlled ? controlledPage : uncontrolledPage;
8426
+ const currentPage = Math.min(Math.max(1, Math.floor(rawPage)), safePageCount);
8427
+ const goToPage = React.useCallback(
8428
+ (next2) => {
8429
+ const clamped = Math.min(Math.max(1, Math.floor(next2)), Math.max(1, Math.floor(pageCount)));
8430
+ if (!isControlled) {
8431
+ setUncontrolledPage(clamped);
8432
+ }
8433
+ onChangeRef.current?.(clamped);
8434
+ },
8435
+ [isControlled, pageCount]
8436
+ );
8437
+ const prev = React.useCallback(() => goToPage(currentPage - 1), [goToPage, currentPage]);
8438
+ const next = React.useCallback(() => goToPage(currentPage + 1), [goToPage, currentPage]);
8439
+ const first = React.useCallback(() => goToPage(1), [goToPage]);
8440
+ const last = React.useCallback(() => goToPage(safePageCount), [goToPage, safePageCount]);
8441
+ const pages = React.useMemo(() => {
8442
+ const items = [];
8443
+ const safeSibling = Math.max(0, Math.floor(siblingCount));
8444
+ const safeBoundary = Math.max(0, Math.floor(boundaryCount));
8445
+ if (showFirstLast) {
8446
+ items.push({ type: "first", disabled: currentPage <= 1 });
8173
8447
  }
8174
- node.style.transitionProperty = "background-color, backdrop-filter, -webkit-backdrop-filter";
8175
- node.style.transitionDuration = "150ms, 200ms, 200ms";
8176
- node.style.transitionTimingFunction = "ease-out";
8177
- if (entered) {
8178
- node.style.backgroundColor = SCRIM_COLOR2;
8179
- node.style.backdropFilter = `blur(${BLUR_AMOUNT2}px)`;
8180
- node.style.setProperty("-webkit-backdrop-filter", `blur(${BLUR_AMOUNT2}px)`);
8181
- } else {
8182
- node.style.backgroundColor = "rgba(0, 0, 0, 0)";
8183
- node.style.backdropFilter = "blur(0px)";
8184
- node.style.setProperty("-webkit-backdrop-filter", "blur(0px)");
8448
+ if (showPrevNext) {
8449
+ items.push({ type: "prev", disabled: currentPage <= 1 });
8185
8450
  }
8186
- }, [entered]);
8187
- React.useEffect(() => {
8188
- if (!ctx.open) {
8189
- return;
8451
+ const startPages = range(1, Math.min(safeBoundary, safePageCount));
8452
+ const endPages = range(Math.max(safePageCount - safeBoundary + 1, safeBoundary + 1), safePageCount);
8453
+ const siblingsStart = Math.max(
8454
+ Math.min(currentPage - safeSibling, safePageCount - safeBoundary - safeSibling * 2 - 1),
8455
+ safeBoundary + 2
8456
+ );
8457
+ const siblingsEnd = Math.min(
8458
+ Math.max(currentPage + safeSibling, safeBoundary + safeSibling * 2 + 2),
8459
+ endPages.length > 0 ? endPages[0] - 2 : safePageCount - 1
8460
+ );
8461
+ const middle = [];
8462
+ if (siblingsStart > safeBoundary + 2) {
8463
+ middle.push("ellipsis");
8464
+ } else if (safeBoundary + 1 < safePageCount - safeBoundary) {
8465
+ middle.push(safeBoundary + 1);
8190
8466
  }
8191
- if (reactNative.Platform.OS !== "web") {
8192
- return;
8467
+ for (const p of range(siblingsStart, siblingsEnd)) {
8468
+ middle.push(p);
8193
8469
  }
8194
- if (typeof document === "undefined") {
8195
- return;
8470
+ if (siblingsEnd < safePageCount - safeBoundary - 1) {
8471
+ middle.push("ellipsis");
8472
+ } else if (safePageCount - safeBoundary > safeBoundary) {
8473
+ middle.push(safePageCount - safeBoundary);
8196
8474
  }
8197
- const previouslyFocused = document.activeElement;
8198
- const prevBodyOverflow = document.body.style.overflow;
8199
- document.body.style.overflow = "hidden";
8200
- const focusFirst = /* @__PURE__ */ __name(() => {
8201
- const node = contentRef.current;
8202
- if (!node) {
8475
+ const seen = /* @__PURE__ */ new Set();
8476
+ const pushPage = /* @__PURE__ */ __name((n) => {
8477
+ if (n < 1 || n > safePageCount || seen.has(n)) {
8203
8478
  return;
8204
8479
  }
8205
- const focusable = node.querySelectorAll(FOCUSABLE_SELECTOR2);
8206
- const first = focusable[0];
8207
- if (first) {
8208
- first.focus();
8480
+ seen.add(n);
8481
+ items.push({ type: "page", page: n, selected: n === currentPage });
8482
+ }, "pushPage");
8483
+ for (const n of startPages) {
8484
+ pushPage(n);
8485
+ }
8486
+ for (const m of middle) {
8487
+ if (m === "ellipsis") {
8488
+ items.push({ type: "ellipsis" });
8209
8489
  } else {
8210
- node.setAttribute("tabindex", "-1");
8211
- node.focus();
8212
- }
8213
- }, "focusFirst");
8214
- focusFirst();
8215
- const onKeyDown = /* @__PURE__ */ __name((event) => {
8216
- if (event.key === "Escape") {
8217
- event.preventDefault();
8218
- ctx.setOpen(false);
8219
- return;
8220
- }
8221
- if (event.key !== "Tab") {
8222
- return;
8223
- }
8224
- const node = contentRef.current;
8225
- if (!node) {
8226
- return;
8490
+ pushPage(m);
8227
8491
  }
8228
- const focusable = Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR2)).filter(
8229
- (el) => el.offsetParent !== null || el === document.activeElement
8230
- );
8231
- if (focusable.length === 0) {
8232
- event.preventDefault();
8233
- return;
8492
+ }
8493
+ for (const n of endPages) {
8494
+ pushPage(n);
8495
+ }
8496
+ if (showPrevNext) {
8497
+ items.push({ type: "next", disabled: currentPage >= safePageCount });
8498
+ }
8499
+ if (showFirstLast) {
8500
+ items.push({ type: "last", disabled: currentPage >= safePageCount });
8501
+ }
8502
+ return items;
8503
+ }, [currentPage, safePageCount, siblingCount, boundaryCount, showFirstLast, showPrevNext]);
8504
+ return {
8505
+ page: currentPage,
8506
+ pages,
8507
+ canPrev: currentPage > 1,
8508
+ canNext: currentPage < safePageCount,
8509
+ goToPage,
8510
+ prev,
8511
+ next,
8512
+ first,
8513
+ last
8514
+ };
8515
+ }
8516
+ __name(usePagination, "usePagination");
8517
+ var TableContext = React.createContext({
8518
+ striped: false,
8519
+ compact: false,
8520
+ bordered: false,
8521
+ rowIndex: 0,
8522
+ setRowIndex: /* @__PURE__ */ __name(() => {
8523
+ }, "setRowIndex")
8524
+ });
8525
+ function buildTableCompound(parts) {
8526
+ return Object.assign(parts.Root, {
8527
+ Header: parts.Header,
8528
+ Body: parts.Body,
8529
+ Footer: parts.Footer,
8530
+ Row: parts.Row,
8531
+ HeaderCell: parts.HeaderCell,
8532
+ Cell: parts.Cell,
8533
+ Caption: parts.Caption
8534
+ });
8535
+ }
8536
+ __name(buildTableCompound, "buildTableCompound");
8537
+ var TableRoot = /* @__PURE__ */ __name(({ striped = false, compact = false, bordered = false, children, className, testID }) => {
8538
+ const [rowIndex, setRowIndex] = React.useState(0);
8539
+ const ctxValue = {
8540
+ striped,
8541
+ compact,
8542
+ bordered,
8543
+ rowIndex,
8544
+ setRowIndex
8545
+ };
8546
+ return /* @__PURE__ */ jsxRuntime.jsx(TableContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx(
8547
+ "table",
8548
+ {
8549
+ className: cn(
8550
+ "w-full caption-bottom text-sm",
8551
+ bordered && "border border-semantic-border-default",
8552
+ className
8553
+ ),
8554
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8555
+ children
8556
+ }
8557
+ ) }) });
8558
+ }, "TableRoot");
8559
+ var TableHeader = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8560
+ "thead",
8561
+ {
8562
+ className: cn("[&_tr]:border-b [&_tr]:border-semantic-border-default", className),
8563
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8564
+ children
8565
+ }
8566
+ ), "TableHeader");
8567
+ var TableBody = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8568
+ "tbody",
8569
+ {
8570
+ className: cn("[&_tr:last-child]:border-0", className),
8571
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8572
+ children
8573
+ }
8574
+ ), "TableBody");
8575
+ var TableFooter = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8576
+ "tfoot",
8577
+ {
8578
+ className: cn("border-t border-semantic-border-default font-medium", className),
8579
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8580
+ children
8581
+ }
8582
+ ), "TableFooter");
8583
+ var TableRow = /* @__PURE__ */ __name(({ selected = false, onPress, children, className, testID }) => {
8584
+ const colors = useThemeColors();
8585
+ const handleClick = React.useCallback(() => {
8586
+ onPress?.();
8587
+ }, [onPress]);
8588
+ return /* @__PURE__ */ jsxRuntime.jsx(
8589
+ "tr",
8590
+ {
8591
+ className: cn(
8592
+ "border-b border-semantic-border-default transition-colors",
8593
+ onPress && "cursor-pointer hover:bg-semantic-background-subtle",
8594
+ selected && "bg-semantic-background-subtle",
8595
+ className
8596
+ ),
8597
+ style: selected ? { backgroundColor: colors.semantic.background.subtle } : void 0,
8598
+ onClick: onPress ? handleClick : void 0,
8599
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8600
+ children
8601
+ }
8602
+ );
8603
+ }, "TableRow");
8604
+ var TableHeaderCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8605
+ "th",
8606
+ {
8607
+ className: cn(
8608
+ "h-10 px-4 font-medium text-semantic-text-secondary",
8609
+ align === "right" && "text-right",
8610
+ align === "center" && "text-center",
8611
+ align === "left" && "text-left",
8612
+ className
8613
+ ),
8614
+ colSpan,
8615
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8616
+ children
8617
+ }
8618
+ ), "TableHeaderCell");
8619
+ var TableCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8620
+ "td",
8621
+ {
8622
+ className: cn(
8623
+ "p-4 align-middle",
8624
+ align === "right" && "text-right",
8625
+ align === "center" && "text-center",
8626
+ align === "left" && "text-left",
8627
+ className
8628
+ ),
8629
+ colSpan,
8630
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8631
+ children
8632
+ }
8633
+ ), "TableCell");
8634
+ var TableCaption = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8635
+ "caption",
8636
+ {
8637
+ className: cn("mt-4 text-sm text-semantic-text-secondary", className),
8638
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8639
+ children
8640
+ }
8641
+ ), "TableCaption");
8642
+ var Table = buildTableCompound({
8643
+ Root: TableRoot,
8644
+ Header: TableHeader,
8645
+ Body: TableBody,
8646
+ Footer: TableFooter,
8647
+ Row: TableRow,
8648
+ HeaderCell: TableHeaderCell,
8649
+ Cell: TableCell,
8650
+ Caption: TableCaption
8651
+ });
8652
+ function sortData(data, sort) {
8653
+ if (!sort) {
8654
+ return data;
8655
+ }
8656
+ const key = sort.id;
8657
+ return [...data].sort((a, b) => {
8658
+ const av = a[key];
8659
+ const bv = b[key];
8660
+ if (av == null && bv == null) {
8661
+ return 0;
8662
+ }
8663
+ if (av == null) {
8664
+ return 1;
8665
+ }
8666
+ if (bv == null) {
8667
+ return -1;
8668
+ }
8669
+ const cmp2 = av < bv ? -1 : av > bv ? 1 : 0;
8670
+ return sort.direction === "asc" ? cmp2 : -cmp2;
8671
+ });
8672
+ }
8673
+ __name(sortData, "sortData");
8674
+ function SortIndicator({ direction }) {
8675
+ if (direction === void 0) {
8676
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4, opacity: 0.3 }, children: "\u21C5" });
8677
+ }
8678
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4 }, children: direction === "asc" ? "\u2191" : "\u2193" });
8679
+ }
8680
+ __name(SortIndicator, "SortIndicator");
8681
+ function DataTable({
8682
+ data,
8683
+ columns,
8684
+ pageSize = 10,
8685
+ defaultSort,
8686
+ onRowPress,
8687
+ emptyState,
8688
+ striped,
8689
+ compact,
8690
+ bordered,
8691
+ testID,
8692
+ className
8693
+ }) {
8694
+ const [sort, setSort] = React.useState(defaultSort ?? null);
8695
+ const sorted = React.useMemo(() => sortData(data, sort), [data, sort]);
8696
+ const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));
8697
+ const { page, goToPage, canPrev, canNext } = usePagination({ pageCount, defaultPage: 1 });
8698
+ const pageSlice = React.useMemo(() => {
8699
+ const start = (page - 1) * pageSize;
8700
+ return sorted.slice(start, start + pageSize);
8701
+ }, [sorted, page, pageSize]);
8702
+ const handleSort = /* @__PURE__ */ __name((colId) => {
8703
+ setSort((prev) => {
8704
+ if (prev?.id !== colId) {
8705
+ goToPage(1);
8706
+ return { id: colId, direction: "asc" };
8234
8707
  }
8235
- const first = focusable[0];
8236
- const last = focusable[focusable.length - 1];
8237
- if (!first || !last) {
8238
- return;
8708
+ if (prev.direction === "asc") {
8709
+ return { id: colId, direction: "desc" };
8239
8710
  }
8240
- if (event.shiftKey) {
8241
- if (document.activeElement === first || !node.contains(document.activeElement)) {
8242
- event.preventDefault();
8243
- last.focus();
8244
- }
8245
- } else if (document.activeElement === last) {
8246
- event.preventDefault();
8247
- first.focus();
8711
+ goToPage(1);
8712
+ return null;
8713
+ });
8714
+ }, "handleSort");
8715
+ const tableProps = {};
8716
+ if (striped !== void 0) {
8717
+ tableProps.striped = striped;
8718
+ }
8719
+ if (compact !== void 0) {
8720
+ tableProps.compact = compact;
8721
+ }
8722
+ if (bordered !== void 0) {
8723
+ tableProps.bordered = bordered;
8724
+ }
8725
+ if (testID !== void 0) {
8726
+ tableProps.testID = testID;
8727
+ }
8728
+ if (className !== void 0) {
8729
+ tableProps.className = className;
8730
+ }
8731
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { width: "100%" }, children: [
8732
+ /* @__PURE__ */ jsxRuntime.jsxs(Table, { ...tableProps, children: [
8733
+ /* @__PURE__ */ jsxRuntime.jsx(Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: columns.map((col) => {
8734
+ const align = col.align;
8735
+ return /* @__PURE__ */ jsxRuntime.jsx(Table.HeaderCell, { ...align !== void 0 ? { align } : {}, children: col.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
8736
+ reactNative.Pressable,
8737
+ {
8738
+ accessibilityRole: "button",
8739
+ accessibilityLabel: `Sort by ${col.id}`,
8740
+ "aria-label": `Sort by ${col.id}`,
8741
+ onPress: () => handleSort(col.id),
8742
+ style: { flexDirection: "row", alignItems: "center" },
8743
+ children: [
8744
+ typeof col.header === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children: col.header }) : col.header,
8745
+ /* @__PURE__ */ jsxRuntime.jsx(
8746
+ SortIndicator,
8747
+ {
8748
+ ...sort?.id === col.id ? { direction: sort.direction } : {}
8749
+ }
8750
+ )
8751
+ ]
8752
+ }
8753
+ ) : col.header }, col.id);
8754
+ }) }) }),
8755
+ /* @__PURE__ */ jsxRuntime.jsx(Table.Body, { children: pageSlice.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Cell, { colSpan: columns.length, children: /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: emptyState ?? "No data" }) }) }) : pageSlice.map((row, i) => /* @__PURE__ */ jsxRuntime.jsx(
8756
+ Table.Row,
8757
+ {
8758
+ ...onRowPress !== void 0 ? { onPress: /* @__PURE__ */ __name(() => onRowPress(row), "onPress") } : {},
8759
+ children: columns.map((col) => {
8760
+ const colAlign = col.align;
8761
+ return /* @__PURE__ */ jsxRuntime.jsx(
8762
+ Table.Cell,
8763
+ {
8764
+ ...colAlign !== void 0 ? { align: colAlign } : {},
8765
+ children: col.cell(row)
8766
+ },
8767
+ col.id
8768
+ );
8769
+ })
8770
+ },
8771
+ i
8772
+ )) })
8773
+ ] }),
8774
+ pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(
8775
+ PaginationControls,
8776
+ {
8777
+ page,
8778
+ pageCount,
8779
+ canPrev,
8780
+ canNext,
8781
+ goToPage
8248
8782
  }
8249
- }, "onKeyDown");
8250
- document.addEventListener("keydown", onKeyDown);
8251
- return () => {
8252
- document.removeEventListener("keydown", onKeyDown);
8253
- document.body.style.overflow = prevBodyOverflow;
8254
- const restoreTo = ctx.triggerRef.current ?? previouslyFocused;
8255
- restoreTo?.focus?.();
8256
- };
8257
- }, [ctx.open, ctx.setOpen, ctx.triggerRef]);
8258
- const onOverlayPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
8783
+ )
8784
+ ] });
8785
+ }
8786
+ __name(DataTable, "DataTable");
8787
+ function EmptyState({ children }) {
8788
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { paddingVertical: 32, alignItems: "center" }, children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: "#888", fontSize: 14 }, children }) : children });
8789
+ }
8790
+ __name(EmptyState, "EmptyState");
8791
+ function PaginationControls({
8792
+ page,
8793
+ pageCount,
8794
+ canPrev,
8795
+ canNext,
8796
+ goToPage
8797
+ }) {
8259
8798
  return /* @__PURE__ */ jsxRuntime.jsxs(
8260
- reactNative.Modal,
8799
+ reactNative.View,
8261
8800
  {
8262
- visible: ctx.open,
8263
- transparent: true,
8264
- animationType: reactNative.Platform.OS === "web" ? "none" : "fade",
8265
- onRequestClose: () => ctx.setOpen(false),
8801
+ style: {
8802
+ flexDirection: "row",
8803
+ justifyContent: "flex-end",
8804
+ alignItems: "center",
8805
+ paddingVertical: 8,
8806
+ gap: 8
8807
+ },
8266
8808
  children: [
8267
- /* @__PURE__ */ jsxRuntime.jsx(BlurBackdrop, { intensity: 60, tint: scheme === "dark" ? "dark" : "light", style: reactNative.StyleSheet.absoluteFill }),
8268
8809
  /* @__PURE__ */ jsxRuntime.jsx(
8269
8810
  reactNative.Pressable,
8270
8811
  {
8271
- accessibilityRole: "none",
8272
- "aria-hidden": true,
8273
- ref: (node) => {
8274
- overlayDomRef.current = node;
8275
- },
8276
- style: overlayStyle,
8277
- onPress: onOverlayPress,
8278
- children: /* @__PURE__ */ jsxRuntime.jsx(
8279
- reactNative.Pressable,
8280
- {
8281
- onPress: (event) => event.stopPropagation?.(),
8282
- ref: (node) => {
8283
- contentRef.current = node;
8284
- },
8285
- role: "dialog",
8286
- accessibilityRole: "none",
8287
- "aria-modal": true,
8288
- "aria-labelledby": ctx.titleId,
8289
- "aria-describedby": ctx.descriptionId,
8290
- ...testID !== void 0 ? { testID } : {},
8291
- className: cn("w-full max-w-md rounded-xl bg-semantic-background-elevated p-6 gap-3", className),
8292
- style: [contentStyle, { backgroundColor: colors.semantic.background.elevated }, enterStyle],
8293
- children: /* @__PURE__ */ jsxRuntime.jsx(
8294
- reactNative.View,
8295
- {
8296
- className: "flex-col gap-1.5",
8297
- style: { flexDirection: "column", gap: px(colors.spacing["2"]) - 2 },
8298
- children
8299
- }
8300
- )
8301
- }
8302
- )
8812
+ onPress: canPrev ? () => goToPage(page - 1) : void 0,
8813
+ accessibilityRole: "button",
8814
+ accessibilityLabel: "Previous page",
8815
+ "aria-label": "Previous page",
8816
+ "aria-disabled": !canPrev,
8817
+ style: { opacity: canPrev ? 1 : 0.4, paddingHorizontal: 8 },
8818
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "\u2039 Prev" })
8303
8819
  }
8304
- )
8305
- ]
8306
- }
8307
- );
8308
- }, "DialogContent");
8309
- var DialogTitle = /* @__PURE__ */ __name(({ children, className }) => {
8310
- const ctx = useDialogContext("DialogTitle");
8311
- const colors = useThemeColors();
8312
- return /* @__PURE__ */ jsxRuntime.jsx(
8313
- reactNative.Text,
8314
- {
8315
- nativeID: ctx.titleId,
8316
- id: ctx.titleId,
8317
- role: "heading",
8318
- "aria-level": 2,
8319
- className: cn("text-lg font-semibold text-semantic-text-default", className),
8320
- style: {
8321
- color: colors.semantic.text.default,
8322
- fontFamily: colors.fontFamily.display,
8323
- fontSize: px(colors.fontSize.lg),
8324
- fontWeight: colors.fontWeight.semibold
8325
- },
8326
- children
8820
+ ),
8821
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: { fontSize: 14 }, "aria-live": "polite", children: [
8822
+ page,
8823
+ " / ",
8824
+ pageCount
8825
+ ] }),
8826
+ /* @__PURE__ */ jsxRuntime.jsx(
8827
+ reactNative.Pressable,
8828
+ {
8829
+ onPress: canNext ? () => goToPage(page + 1) : void 0,
8830
+ accessibilityRole: "button",
8831
+ accessibilityLabel: "Next page",
8832
+ "aria-label": "Next page",
8833
+ "aria-disabled": !canNext,
8834
+ style: { opacity: canNext ? 1 : 0.4, paddingHorizontal: 8 },
8835
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "Next \u203A" })
8836
+ }
8837
+ )
8838
+ ]
8327
8839
  }
8328
8840
  );
8329
- }, "DialogTitle");
8330
- var DialogDescription = /* @__PURE__ */ __name(({ children, className }) => {
8331
- const ctx = useDialogContext("DialogDescription");
8841
+ }
8842
+ __name(PaginationControls, "PaginationControls");
8843
+ function formatDate(date$1, locale) {
8844
+ try {
8845
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date$1.toDate(date.getLocalTimeZone()));
8846
+ } catch {
8847
+ return `${date$1.year}-${String(date$1.month).padStart(2, "0")}-${String(date$1.day).padStart(2, "0")}`;
8848
+ }
8849
+ }
8850
+ __name(formatDate, "formatDate");
8851
+ function CalendarIcon({ size = 16, color = "currentColor" }) {
8332
8852
  const colors = useThemeColors();
8853
+ if (reactNative.Platform.OS === "web") {
8854
+ return /* @__PURE__ */ jsxRuntime.jsx(
8855
+ "svg",
8856
+ {
8857
+ width: size,
8858
+ height: size,
8859
+ viewBox: "0 0 24 24",
8860
+ fill: "none",
8861
+ stroke: color,
8862
+ strokeWidth: "2",
8863
+ strokeLinecap: "round",
8864
+ strokeLinejoin: "round",
8865
+ "aria-hidden": "true",
8866
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" })
8867
+ }
8868
+ );
8869
+ }
8870
+ const resolvedColor = color === "currentColor" ? colors.semantic.text.muted : color;
8333
8871
  return /* @__PURE__ */ jsxRuntime.jsx(
8334
8872
  reactNative.Text,
8335
8873
  {
8336
- nativeID: ctx.descriptionId,
8337
- id: ctx.descriptionId,
8338
- className: cn("text-sm text-semantic-text-muted", className),
8339
- style: {
8340
- color: colors.semantic.text.muted,
8341
- fontFamily: colors.fontFamily.body,
8342
- fontSize: px(colors.fontSize.sm),
8343
- lineHeight: px(colors.fontSize.sm) * Number(colors.lineHeight.normal)
8344
- },
8345
- children
8874
+ accessibilityElementsHidden: true,
8875
+ importantForAccessibility: "no-hide-descendants",
8876
+ style: { fontSize: size, lineHeight: size, color: resolvedColor },
8877
+ children: "\u{1F4C5}"
8346
8878
  }
8347
8879
  );
8348
- }, "DialogDescription");
8349
- var DialogClose = /* @__PURE__ */ __name(({
8350
- asChild = true,
8351
- children,
8880
+ }
8881
+ __name(CalendarIcon, "CalendarIcon");
8882
+ function buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek) {
8883
+ const out = {};
8884
+ if (minValue !== void 0) {
8885
+ out.minValue = minValue;
8886
+ }
8887
+ if (maxValue !== void 0) {
8888
+ out.maxValue = maxValue;
8889
+ }
8890
+ if (isDateUnavailable !== void 0) {
8891
+ out.isDateUnavailable = isDateUnavailable;
8892
+ }
8893
+ if (firstDayOfWeek !== void 0) {
8894
+ out.firstDayOfWeek = firstDayOfWeek;
8895
+ }
8896
+ return out;
8897
+ }
8898
+ __name(buildCalendarOptional, "buildCalendarOptional");
8899
+ function buildTriggerAriaProps(ariaProps) {
8900
+ const out = {};
8901
+ if (ariaProps["aria-labelledby"] !== void 0) {
8902
+ out["aria-labelledby"] = ariaProps["aria-labelledby"];
8903
+ }
8904
+ if (ariaProps["aria-describedby"] !== void 0) {
8905
+ out["aria-describedby"] = ariaProps["aria-describedby"];
8906
+ }
8907
+ if (ariaProps["aria-invalid"] !== void 0) {
8908
+ out["aria-invalid"] = ariaProps["aria-invalid"];
8909
+ }
8910
+ if (ariaProps["aria-required"] !== void 0) {
8911
+ out["aria-required"] = ariaProps["aria-required"];
8912
+ }
8913
+ return out;
8914
+ }
8915
+ __name(buildTriggerAriaProps, "buildTriggerAriaProps");
8916
+ var DatePickerRoot = /* @__PURE__ */ __name(({
8917
+ value,
8918
+ defaultValue: defaultValue2,
8919
+ onChange,
8920
+ locale: localeProp,
8921
+ minValue,
8922
+ maxValue,
8923
+ isDateUnavailable,
8924
+ firstDayOfWeek,
8925
+ placeholder,
8926
+ disabled = false,
8927
+ id,
8928
+ name: _name,
8352
8929
  className,
8353
8930
  testID,
8354
- accessibilityLabel = "Close"
8931
+ ...ariaProps
8355
8932
  }) => {
8356
- const ctx = useDialogContext("DialogClose");
8933
+ const providerLocale = useLocale();
8934
+ const locale = localeProp ?? providerLocale;
8935
+ const [open, setOpen] = React.useState(false);
8936
+ const isControlled = value !== void 0;
8937
+ const [inner, setInner] = React.useState(defaultValue2 ?? null);
8938
+ const current = isControlled ? value ?? null : inner;
8939
+ const handleChange = React.useCallback(
8940
+ (date) => {
8941
+ if (!isControlled) {
8942
+ setInner(date);
8943
+ }
8944
+ onChange?.(date);
8945
+ setOpen(false);
8946
+ },
8947
+ [isControlled, onChange]
8948
+ );
8949
+ const handleOpenChange = React.useCallback(
8950
+ (next) => {
8951
+ if (!disabled) {
8952
+ setOpen(next);
8953
+ }
8954
+ },
8955
+ [disabled]
8956
+ );
8957
+ const displayValue = current ? formatDate(current, locale) : null;
8958
+ const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8959
+ const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8357
8960
  const colors = useThemeColors();
8358
- const onPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
8359
- if (asChild && React.isValidElement(children)) {
8360
- const child = children;
8361
- const fire = /* @__PURE__ */ __name((existing) => (event) => {
8362
- existing?.(event);
8363
- ctx.setOpen(false);
8364
- }, "fire");
8365
- return /* @__PURE__ */ jsxRuntime.jsx(
8366
- Slot,
8961
+ const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
8962
+ const pressableStyle = {
8963
+ flexDirection: "row",
8964
+ alignItems: "center",
8965
+ borderWidth: 1,
8966
+ borderRadius: px(colors.radius.md),
8967
+ paddingHorizontal: px(colors.spacing["3"]),
8968
+ paddingVertical: px(colors.spacing["2"]),
8969
+ backgroundColor: colors.semantic.background.elevated,
8970
+ borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
8971
+ opacity: disabled ? 0.6 : 1
8972
+ };
8973
+ const textStyle = {
8974
+ flex: 1,
8975
+ fontFamily: colors.fontFamily.body,
8976
+ fontSize: px(colors.fontSize.md),
8977
+ color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
8978
+ };
8979
+ const triggerExtraProps = {
8980
+ role: "combobox",
8981
+ accessibilityRole: "button",
8982
+ "aria-haspopup": "dialog",
8983
+ "aria-expanded": open,
8984
+ ...triggerAriaProps
8985
+ };
8986
+ if (id !== void 0) {
8987
+ triggerExtraProps.id = id;
8988
+ triggerExtraProps.nativeID = id;
8989
+ }
8990
+ if (testID !== void 0) {
8991
+ triggerExtraProps.testID = testID;
8992
+ }
8993
+ if (hasError) {
8994
+ triggerExtraProps["aria-invalid"] = true;
8995
+ }
8996
+ if (ariaProps["aria-required"]) {
8997
+ triggerExtraProps["aria-required"] = true;
8998
+ }
8999
+ if (disabled) {
9000
+ triggerExtraProps["aria-disabled"] = true;
9001
+ }
9002
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
9003
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
9004
+ reactNative.Pressable,
8367
9005
  {
8368
- onClick: fire(child.props.onClick),
8369
- onPress: fire(child.props.onPress),
8370
- ...testID !== void 0 ? { "data-testid": testID } : {},
8371
- ...className !== void 0 ? { className } : {},
8372
- children: child
9006
+ onPress: disabled ? void 0 : () => setOpen(!open),
9007
+ disabled,
9008
+ className: cn(
9009
+ "flex-row items-center rounded-md border px-3 py-2",
9010
+ hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
9011
+ disabled ? "opacity-60" : void 0,
9012
+ className
9013
+ ),
9014
+ style: pressableStyle,
9015
+ ...triggerExtraProps,
9016
+ children: [
9017
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
9018
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
9019
+ ]
9020
+ }
9021
+ ) }),
9022
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
9023
+ Calendar,
9024
+ {
9025
+ mode: "single",
9026
+ value: current,
9027
+ onChange: (date) => {
9028
+ handleChange(date);
9029
+ },
9030
+ locale,
9031
+ ...calendarOptional
9032
+ }
9033
+ ) })
9034
+ ] });
9035
+ }, "DatePickerRoot");
9036
+ var DatePickerRange = /* @__PURE__ */ __name(({
9037
+ value,
9038
+ defaultValue: defaultValue2,
9039
+ onChange,
9040
+ locale: localeProp,
9041
+ minValue,
9042
+ maxValue,
9043
+ isDateUnavailable,
9044
+ firstDayOfWeek,
9045
+ placeholder,
9046
+ disabled = false,
9047
+ id,
9048
+ name: _name,
9049
+ className,
9050
+ testID,
9051
+ ...ariaProps
9052
+ }) => {
9053
+ const providerLocale = useLocale();
9054
+ const locale = localeProp ?? providerLocale;
9055
+ const [open, setOpen] = React.useState(false);
9056
+ const isControlled = value !== void 0;
9057
+ const [inner, setInner] = React.useState(defaultValue2 ?? { start: null, end: null });
9058
+ const current = isControlled ? value ?? { start: null, end: null } : inner;
9059
+ const calendarValue = current.start !== null ? { start: current.start, end: current.end } : null;
9060
+ const handleChange = React.useCallback(
9061
+ (calRange) => {
9062
+ const next = {
9063
+ start: calRange?.start ?? null,
9064
+ end: calRange?.end ?? null
9065
+ };
9066
+ if (!isControlled) {
9067
+ setInner(next);
8373
9068
  }
8374
- );
9069
+ onChange?.(next);
9070
+ if (next.start !== null && next.end !== null) {
9071
+ setOpen(false);
9072
+ }
9073
+ },
9074
+ [isControlled, onChange]
9075
+ );
9076
+ const handleOpenChange = React.useCallback(
9077
+ (next) => {
9078
+ if (!disabled) {
9079
+ setOpen(next);
9080
+ }
9081
+ },
9082
+ [disabled]
9083
+ );
9084
+ let displayValue = null;
9085
+ if (current.start !== null) {
9086
+ const startStr = formatDate(current.start, locale);
9087
+ const endStr = current.end !== null ? formatDate(current.end, locale) : "";
9088
+ displayValue = `${startStr} \u2013 ${endStr}`;
8375
9089
  }
8376
- if (children !== void 0) {
8377
- return /* @__PURE__ */ jsxRuntime.jsx(
9090
+ const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
9091
+ const triggerAriaProps = buildTriggerAriaProps(ariaProps);
9092
+ const colors = useThemeColors();
9093
+ const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
9094
+ const pressableStyle = {
9095
+ flexDirection: "row",
9096
+ alignItems: "center",
9097
+ borderWidth: 1,
9098
+ borderRadius: px(colors.radius.md),
9099
+ paddingHorizontal: px(colors.spacing["3"]),
9100
+ paddingVertical: px(colors.spacing["2"]),
9101
+ backgroundColor: colors.semantic.background.elevated,
9102
+ borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
9103
+ opacity: disabled ? 0.6 : 1
9104
+ };
9105
+ const textStyle = {
9106
+ flex: 1,
9107
+ fontFamily: colors.fontFamily.body,
9108
+ fontSize: px(colors.fontSize.md),
9109
+ color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
9110
+ };
9111
+ const triggerExtraProps = {
9112
+ role: "combobox",
9113
+ accessibilityRole: "button",
9114
+ "aria-haspopup": "dialog",
9115
+ "aria-expanded": open,
9116
+ ...triggerAriaProps
9117
+ };
9118
+ if (id !== void 0) {
9119
+ triggerExtraProps.id = id;
9120
+ triggerExtraProps.nativeID = id;
9121
+ }
9122
+ if (testID !== void 0) {
9123
+ triggerExtraProps.testID = testID;
9124
+ }
9125
+ if (hasError) {
9126
+ triggerExtraProps["aria-invalid"] = true;
9127
+ }
9128
+ if (ariaProps["aria-required"]) {
9129
+ triggerExtraProps["aria-required"] = true;
9130
+ }
9131
+ if (disabled) {
9132
+ triggerExtraProps["aria-disabled"] = true;
9133
+ }
9134
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
9135
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
8378
9136
  reactNative.Pressable,
8379
9137
  {
8380
- onPress,
8381
- role: "button",
8382
- accessibilityRole: "button",
8383
- accessibilityLabel,
8384
- "aria-label": accessibilityLabel,
8385
- ...testID !== void 0 ? { testID } : {},
8386
- ...className !== void 0 ? { className } : {},
8387
- children: wrapStringChildren4(children)
9138
+ onPress: disabled ? void 0 : () => setOpen(!open),
9139
+ disabled,
9140
+ className: cn(
9141
+ "flex-row items-center rounded-md border px-3 py-2",
9142
+ hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
9143
+ disabled ? "opacity-60" : void 0,
9144
+ className
9145
+ ),
9146
+ style: pressableStyle,
9147
+ ...triggerExtraProps,
9148
+ children: [
9149
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
9150
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
9151
+ ]
8388
9152
  }
8389
- );
8390
- }
8391
- return /* @__PURE__ */ jsxRuntime.jsx(
8392
- reactNative.Pressable,
8393
- {
8394
- onPress,
8395
- role: "button",
8396
- accessibilityRole: "button",
8397
- accessibilityLabel,
8398
- "aria-label": accessibilityLabel,
8399
- ...testID !== void 0 ? { testID } : {},
8400
- className: cn("absolute right-3 top-3 w-8 h-8 items-center justify-center rounded-md", className),
8401
- style: {
8402
- position: "absolute",
8403
- right: px(colors.spacing["3"]),
8404
- top: px(colors.spacing["3"]),
8405
- // 32×32 close hit target — component-density literal — not from theme
8406
- width: 32,
8407
- height: 32,
8408
- alignItems: "center",
8409
- justifyContent: "center",
8410
- borderRadius: px(colors.radius.md)
8411
- },
8412
- children: /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.close, { size: 18, color: colors.semantic.text.muted })
8413
- }
8414
- );
8415
- }, "DialogClose");
8416
- var DialogFooter = /* @__PURE__ */ __name(({ children, className }) => {
8417
- const colors = useThemeColors();
8418
- return /* @__PURE__ */ jsxRuntime.jsx(
8419
- reactNative.View,
8420
- {
8421
- className: cn("mt-4 flex-row items-center justify-end gap-2", className),
8422
- style: {
8423
- marginTop: px(colors.spacing["4"]),
8424
- flexDirection: "row",
8425
- alignItems: "center",
8426
- justifyContent: "flex-end",
8427
- gap: px(colors.spacing["2"])
8428
- },
8429
- children
8430
- }
8431
- );
8432
- }, "DialogFooter");
8433
- var Dialog = Object.assign(DialogRoot, {
8434
- Trigger: DialogTrigger,
8435
- Content: DialogContent,
8436
- Title: DialogTitle,
8437
- Description: DialogDescription,
8438
- Footer: DialogFooter,
8439
- Close: DialogClose
9153
+ ) }),
9154
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date range picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
9155
+ Calendar,
9156
+ {
9157
+ mode: "range",
9158
+ value: calendarValue,
9159
+ onChange: (range2) => {
9160
+ handleChange(range2);
9161
+ },
9162
+ locale,
9163
+ ...calendarOptional
9164
+ }
9165
+ ) })
9166
+ ] });
9167
+ }, "DatePickerRange");
9168
+ var DatePicker = Object.assign(DatePickerRoot, {
9169
+ Range: DatePickerRange
8440
9170
  });
8441
9171
  var Empty = /* @__PURE__ */ __name(({ icon, title, description, action, className, testID }) => {
8442
9172
  const colors = useThemeColors();
@@ -9395,9 +10125,164 @@ function withAlpha(color, alpha) {
9395
10125
  const b = Number.parseInt(expanded.slice(5, 7), 16);
9396
10126
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
9397
10127
  }
9398
- return color;
9399
- }
9400
- __name(withAlpha, "withAlpha");
10128
+ return color;
10129
+ }
10130
+ __name(withAlpha, "withAlpha");
10131
+ var HoverCardContext = React.createContext(null);
10132
+ function useHoverCardContext(caller) {
10133
+ const ctx = React.useContext(HoverCardContext);
10134
+ if (!ctx) {
10135
+ throw new Error(`<${caller}> must be rendered inside <HoverCard>.`);
10136
+ }
10137
+ return ctx;
10138
+ }
10139
+ __name(useHoverCardContext, "useHoverCardContext");
10140
+ var DEFAULT_OPEN_DELAY = 300;
10141
+ var DEFAULT_CLOSE_DELAY = 200;
10142
+ var HoverCardRoot = /* @__PURE__ */ __name(({
10143
+ open: controlledOpen,
10144
+ defaultOpen = false,
10145
+ onOpenChange,
10146
+ openDelay = DEFAULT_OPEN_DELAY,
10147
+ closeDelay = DEFAULT_CLOSE_DELAY,
10148
+ children
10149
+ }) => {
10150
+ const [inner, setInner] = React.useState(defaultOpen);
10151
+ const isControlled = controlledOpen !== void 0;
10152
+ const open = isControlled ? controlledOpen : inner;
10153
+ const id = React.useId();
10154
+ const setOpen = React.useCallback(
10155
+ (next) => {
10156
+ if (!isControlled) {
10157
+ setInner(next);
10158
+ }
10159
+ onOpenChange?.(next);
10160
+ },
10161
+ [isControlled, onOpenChange]
10162
+ );
10163
+ const openTimer = React.useRef(null);
10164
+ const closeTimer = React.useRef(null);
10165
+ const cancelTimers = React.useCallback(() => {
10166
+ if (openTimer.current) {
10167
+ clearTimeout(openTimer.current);
10168
+ openTimer.current = null;
10169
+ }
10170
+ if (closeTimer.current) {
10171
+ clearTimeout(closeTimer.current);
10172
+ closeTimer.current = null;
10173
+ }
10174
+ }, []);
10175
+ const requestOpen = React.useCallback(() => {
10176
+ if (closeTimer.current) {
10177
+ clearTimeout(closeTimer.current);
10178
+ closeTimer.current = null;
10179
+ }
10180
+ if (openTimer.current) {
10181
+ return;
10182
+ }
10183
+ if (openDelay <= 0) {
10184
+ setOpen(true);
10185
+ return;
10186
+ }
10187
+ openTimer.current = setTimeout(() => {
10188
+ openTimer.current = null;
10189
+ setOpen(true);
10190
+ }, openDelay);
10191
+ }, [openDelay, setOpen]);
10192
+ const requestClose = React.useCallback(() => {
10193
+ if (openTimer.current) {
10194
+ clearTimeout(openTimer.current);
10195
+ openTimer.current = null;
10196
+ }
10197
+ if (closeTimer.current) {
10198
+ return;
10199
+ }
10200
+ if (closeDelay <= 0) {
10201
+ setOpen(false);
10202
+ return;
10203
+ }
10204
+ closeTimer.current = setTimeout(() => {
10205
+ closeTimer.current = null;
10206
+ setOpen(false);
10207
+ }, closeDelay);
10208
+ }, [closeDelay, setOpen]);
10209
+ React.useEffect(() => () => cancelTimers(), [cancelTimers]);
10210
+ return /* @__PURE__ */ jsxRuntime.jsx(
10211
+ HoverCardContext.Provider,
10212
+ {
10213
+ value: { open, requestOpen, requestClose, cancelTimers, contentId: `hc-content-${id}` },
10214
+ children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open, onOpenChange: setOpen, children })
10215
+ }
10216
+ );
10217
+ }, "HoverCardRoot");
10218
+ var HoverCardTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
10219
+ const ctx = useHoverCardContext("HoverCard.Trigger");
10220
+ const handleMouseEnter = React.useCallback(() => {
10221
+ ctx.cancelTimers();
10222
+ ctx.requestOpen();
10223
+ }, [ctx]);
10224
+ const handleMouseLeave = React.useCallback(() => {
10225
+ ctx.requestClose();
10226
+ }, [ctx]);
10227
+ const handlers = {
10228
+ onMouseEnter: handleMouseEnter,
10229
+ onMouseLeave: handleMouseLeave,
10230
+ "aria-haspopup": "dialog",
10231
+ "aria-expanded": ctx.open
10232
+ };
10233
+ if (asChild && React.isValidElement(children)) {
10234
+ const child = children;
10235
+ const compose = /* @__PURE__ */ __name((existing, next) => (event) => {
10236
+ existing?.(event);
10237
+ next(event);
10238
+ }, "compose");
10239
+ return /* @__PURE__ */ jsxRuntime.jsx(
10240
+ Slot,
10241
+ {
10242
+ ...handlers,
10243
+ onMouseEnter: compose(child.props.onMouseEnter, handleMouseEnter),
10244
+ onMouseLeave: compose(child.props.onMouseLeave, handleMouseLeave),
10245
+ ...className !== void 0 ? { className } : {},
10246
+ ...testID !== void 0 ? { "data-testid": testID } : {},
10247
+ children: child
10248
+ }
10249
+ );
10250
+ }
10251
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { ...handlers, className, ...testID !== void 0 ? { "data-testid": testID } : {}, children });
10252
+ }, "HoverCardTrigger");
10253
+ var HoverCardContent = /* @__PURE__ */ __name(({ side = "bottom", align = "start", children, className, testID }) => {
10254
+ const ctx = useHoverCardContext("HoverCard.Content");
10255
+ const handleMouseEnter = React.useCallback(() => {
10256
+ ctx.cancelTimers();
10257
+ }, [ctx]);
10258
+ const handleMouseLeave = React.useCallback(() => {
10259
+ ctx.requestClose();
10260
+ }, [ctx]);
10261
+ return /* @__PURE__ */ jsxRuntime.jsx(
10262
+ Popover.Content,
10263
+ {
10264
+ side,
10265
+ align,
10266
+ ...className !== void 0 ? { className } : {},
10267
+ ...testID !== void 0 ? { testID } : {},
10268
+ children: /* @__PURE__ */ jsxRuntime.jsx(
10269
+ "div",
10270
+ {
10271
+ id: ctx.contentId,
10272
+ role: "dialog",
10273
+ "aria-label": "Hover card",
10274
+ onMouseEnter: handleMouseEnter,
10275
+ onMouseLeave: handleMouseLeave,
10276
+ children
10277
+ }
10278
+ )
10279
+ }
10280
+ );
10281
+ }, "HoverCardContent");
10282
+ var HoverCard = Object.assign(HoverCardRoot, {
10283
+ Trigger: HoverCardTrigger,
10284
+ Content: HoverCardContent
10285
+ });
9401
10286
  var ALIGN_CLASS = {
9402
10287
  start: "items-start",
9403
10288
  center: "items-center",
@@ -9770,6 +10655,250 @@ var InputGroup = Object.assign(InputGroupRoot, {
9770
10655
  Addon: InputGroupAddon,
9771
10656
  Input: InputGroupInput
9772
10657
  });
10658
+ function isAllowed(char, pattern) {
10659
+ if (pattern === "numeric") {
10660
+ return /^\d$/.test(char);
10661
+ }
10662
+ return /^[a-zA-Z0-9]$/.test(char);
10663
+ }
10664
+ __name(isAllowed, "isAllowed");
10665
+ function filterValue(value, pattern, length) {
10666
+ return value.split("").filter((c) => isAllowed(c, pattern)).slice(0, length).join("");
10667
+ }
10668
+ __name(filterValue, "filterValue");
10669
+ var InputOTP = /* @__PURE__ */ __name(({
10670
+ value = "",
10671
+ onChange,
10672
+ onComplete,
10673
+ length = 6,
10674
+ placeholder = "\xB7",
10675
+ pattern = "numeric",
10676
+ disabled = false,
10677
+ autoFocus = false,
10678
+ id,
10679
+ name,
10680
+ "aria-label": ariaLabel = "One-time code",
10681
+ "aria-labelledby": ariaLabelledBy,
10682
+ "aria-describedby": ariaDescribedBy,
10683
+ "aria-invalid": ariaInvalid,
10684
+ className,
10685
+ testID
10686
+ }) => {
10687
+ const colors = useThemeColors();
10688
+ const [cells, setCells] = React.useState(() => {
10689
+ const filtered = filterValue(value, pattern, length);
10690
+ return Array.from({ length }, (_, i) => filtered[i] ?? "");
10691
+ });
10692
+ const prevValue = React.useRef(value);
10693
+ React.useEffect(() => {
10694
+ if (value !== prevValue.current) {
10695
+ prevValue.current = value;
10696
+ const filtered = filterValue(value, pattern, length);
10697
+ setCells(Array.from({ length }, (_, i) => filtered[i] ?? ""));
10698
+ }
10699
+ }, [value, pattern, length]);
10700
+ const inputRefs = React.useRef([]);
10701
+ const focusCell = React.useCallback(
10702
+ (idx) => {
10703
+ if (idx >= 0 && idx < length) {
10704
+ inputRefs.current[idx]?.focus();
10705
+ }
10706
+ },
10707
+ [length]
10708
+ );
10709
+ const updateCells = React.useCallback(
10710
+ (next) => {
10711
+ setCells(next);
10712
+ const joined = next.join("");
10713
+ onChange?.(joined);
10714
+ if (joined.length === length && !next.includes("")) {
10715
+ onComplete?.(joined);
10716
+ }
10717
+ },
10718
+ [onChange, onComplete, length]
10719
+ );
10720
+ const onContainerPaste = React.useCallback(
10721
+ (e) => {
10722
+ e.preventDefault();
10723
+ const text = e.clipboardData.getData("text/plain") ?? "";
10724
+ const filtered = filterValue(text, pattern, length);
10725
+ const next = Array.from({ length }, (_, i) => filtered[i] ?? "");
10726
+ updateCells(next);
10727
+ const nextEmpty = next.indexOf("");
10728
+ focusCell(nextEmpty === -1 ? length - 1 : nextEmpty);
10729
+ },
10730
+ [pattern, length, updateCells, focusCell]
10731
+ );
10732
+ const handleChangeText = React.useCallback(
10733
+ (text, idx) => {
10734
+ if (text.length > 1) {
10735
+ const filtered = filterValue(text, pattern, length);
10736
+ const next2 = Array.from({ length }, (_, i) => filtered[i] ?? "");
10737
+ updateCells(next2);
10738
+ const nextEmpty = next2.indexOf("");
10739
+ focusCell(nextEmpty === -1 ? length - 1 : nextEmpty);
10740
+ return;
10741
+ }
10742
+ const char = text.slice(-1);
10743
+ if (char && !isAllowed(char, pattern)) {
10744
+ return;
10745
+ }
10746
+ const next = [...cells];
10747
+ next[idx] = char;
10748
+ updateCells(next);
10749
+ if (char) {
10750
+ focusCell(idx + 1);
10751
+ }
10752
+ },
10753
+ [cells, pattern, length, updateCells, focusCell]
10754
+ );
10755
+ const handleWebKeyDown = React.useCallback(
10756
+ (e, idx) => {
10757
+ if (e.key === "Backspace") {
10758
+ if (cells[idx] !== "") {
10759
+ const next = [...cells];
10760
+ next[idx] = "";
10761
+ updateCells(next);
10762
+ } else {
10763
+ focusCell(idx - 1);
10764
+ }
10765
+ e.preventDefault();
10766
+ } else if (e.key === "ArrowLeft") {
10767
+ focusCell(idx - 1);
10768
+ e.preventDefault();
10769
+ } else if (e.key === "ArrowRight") {
10770
+ focusCell(idx + 1);
10771
+ e.preventDefault();
10772
+ } else if (e.key.length === 1 && isAllowed(e.key, pattern)) {
10773
+ const next = [...cells];
10774
+ next[idx] = e.key;
10775
+ updateCells(next);
10776
+ focusCell(idx + 1);
10777
+ e.preventDefault();
10778
+ }
10779
+ },
10780
+ [cells, pattern, focusCell, updateCells]
10781
+ );
10782
+ const handleNativeKeyPress = React.useCallback(
10783
+ (e, idx) => {
10784
+ if (e.nativeEvent.key === "Backspace") {
10785
+ if (cells[idx] !== "") {
10786
+ const next = [...cells];
10787
+ next[idx] = "";
10788
+ updateCells(next);
10789
+ } else {
10790
+ focusCell(idx - 1);
10791
+ }
10792
+ }
10793
+ },
10794
+ [cells, focusCell, updateCells]
10795
+ );
10796
+ const cellStyle = [
10797
+ styles2.cell,
10798
+ {
10799
+ width: px(48),
10800
+ height: px(56),
10801
+ borderRadius: px(colors.radius.md),
10802
+ borderColor: colors.semantic.border.default,
10803
+ backgroundColor: colors.semantic.background.elevated,
10804
+ color: colors.semantic.text.default,
10805
+ fontSize: px(colors.fontSize.xl),
10806
+ fontFamily: colors.fontFamily.body
10807
+ },
10808
+ disabled ? styles2.disabled : null,
10809
+ ariaInvalid === true || ariaInvalid === "true" ? { borderColor: colors.color.danger } : null
10810
+ ];
10811
+ const isWeb3 = reactNative.Platform.OS === "web";
10812
+ const containerProps = isWeb3 ? {
10813
+ onPaste: onContainerPaste,
10814
+ role: "group",
10815
+ "aria-label": ariaLabel,
10816
+ "aria-labelledby": ariaLabelledBy,
10817
+ "aria-describedby": ariaDescribedBy
10818
+ } : {};
10819
+ return /* @__PURE__ */ jsxRuntime.jsxs(
10820
+ reactNative.View,
10821
+ {
10822
+ testID,
10823
+ ...isWeb3 ? {} : { accessible: true, accessibilityLabel: ariaLabel },
10824
+ ...containerProps,
10825
+ className: cn("flex-row items-center gap-2", className),
10826
+ style: styles2.container,
10827
+ children: [
10828
+ Array.from({ length }, (_, idx) => {
10829
+ const cellValue = cells[idx] ?? "";
10830
+ const cellRef = /* @__PURE__ */ __name((el) => {
10831
+ inputRefs.current[idx] = el;
10832
+ }, "cellRef");
10833
+ const webProps = isWeb3 ? {
10834
+ onKeyDown: /* @__PURE__ */ __name((e) => handleWebKeyDown(e, idx), "onKeyDown"),
10835
+ // id only on the first cell
10836
+ ...idx === 0 && id ? { id, nativeID: id } : {},
10837
+ ...idx === 0 && name ? { name } : {},
10838
+ ...idx === 0 && ariaLabelledBy ? { "aria-labelledby": ariaLabelledBy } : {},
10839
+ ...idx === 0 && ariaDescribedBy ? { "aria-describedby": ariaDescribedBy } : {},
10840
+ ...idx === 0 && ariaInvalid !== void 0 ? { "aria-invalid": ariaInvalid } : {},
10841
+ inputMode: pattern === "numeric" ? "numeric" : "text"
10842
+ } : {};
10843
+ const nativeOnlyProps = isWeb3 ? {} : {
10844
+ keyboardType: pattern === "numeric" ? "number-pad" : "default",
10845
+ textAlign: "center",
10846
+ selectTextOnFocus: true,
10847
+ onKeyPress: /* @__PURE__ */ __name((e) => handleNativeKeyPress(e, idx), "onKeyPress")
10848
+ };
10849
+ return /* @__PURE__ */ jsxRuntime.jsx(
10850
+ reactNative.TextInput,
10851
+ {
10852
+ ref: cellRef,
10853
+ value: cellValue,
10854
+ placeholder: placeholder,
10855
+ maxLength: 1,
10856
+ editable: !disabled,
10857
+ autoFocus: autoFocus && idx === 0,
10858
+ testID: testID ? `${testID}-cell-${idx}` : void 0,
10859
+ onChangeText: (text) => handleChangeText(text, idx),
10860
+ accessibilityLabel: `Digit ${idx + 1} of ${length}`,
10861
+ ...nativeOnlyProps,
10862
+ ...webProps,
10863
+ style: cellStyle
10864
+ },
10865
+ idx
10866
+ );
10867
+ }),
10868
+ isWeb3 && name ? /* @__PURE__ */ jsxRuntime.jsx(
10869
+ reactNative.TextInput,
10870
+ {
10871
+ style: styles2.hidden,
10872
+ value: cells.join(""),
10873
+ "aria-hidden": true,
10874
+ tabIndex: -1,
10875
+ ...{ name }
10876
+ }
10877
+ ) : null
10878
+ ]
10879
+ }
10880
+ );
10881
+ }, "InputOTP");
10882
+ var styles2 = reactNative.StyleSheet.create({
10883
+ container: {
10884
+ flexDirection: "row",
10885
+ alignItems: "center",
10886
+ gap: 8
10887
+ },
10888
+ cell: {
10889
+ borderWidth: 1,
10890
+ textAlign: "center"
10891
+ },
10892
+ disabled: {
10893
+ opacity: 0.6
10894
+ },
10895
+ hidden: {
10896
+ position: "absolute",
10897
+ width: 0,
10898
+ height: 0,
10899
+ opacity: 0
10900
+ }
10901
+ });
9773
10902
  var Item = /* @__PURE__ */ __name(({
9774
10903
  leading,
9775
10904
  title,
@@ -11869,6 +12998,344 @@ function translateOffscreen(side) {
11869
12998
  }
11870
12999
  }
11871
13000
  __name(translateOffscreen, "translateOffscreen");
13001
+ var SidebarContext = React.createContext(null);
13002
+ function useSidebarContext(caller) {
13003
+ const ctx = React.useContext(SidebarContext);
13004
+ if (!ctx) {
13005
+ throw new Error(`<${caller}> must be rendered inside <Sidebar>.`);
13006
+ }
13007
+ return ctx;
13008
+ }
13009
+ __name(useSidebarContext, "useSidebarContext");
13010
+ var EXPANDED_WIDTH = 240;
13011
+ var COLLAPSED_WIDTH = 56;
13012
+ var SidebarRoot = /* @__PURE__ */ __name(({
13013
+ collapsed,
13014
+ defaultCollapsed = false,
13015
+ onCollapsedChange,
13016
+ side = "left",
13017
+ variant = "standard",
13018
+ children,
13019
+ className,
13020
+ testID
13021
+ }) => {
13022
+ const [inner, setInner] = React.useState(defaultCollapsed);
13023
+ const isControlled = collapsed !== void 0;
13024
+ const current = isControlled ? collapsed : inner;
13025
+ const navId = React.useId();
13026
+ const colors = useThemeColors();
13027
+ const setCollapsed = React.useCallback(
13028
+ (next) => {
13029
+ if (!isControlled) {
13030
+ setInner(next);
13031
+ }
13032
+ onCollapsedChange?.(next);
13033
+ },
13034
+ [isControlled, onCollapsedChange]
13035
+ );
13036
+ const toggleCollapsed = React.useCallback(() => {
13037
+ setCollapsed(!current);
13038
+ }, [current, setCollapsed]);
13039
+ const ctxValue = {
13040
+ collapsed: current,
13041
+ setCollapsed,
13042
+ toggleCollapsed,
13043
+ navId
13044
+ };
13045
+ const width = current ? COLLAPSED_WIDTH : EXPANDED_WIDTH;
13046
+ const containerStyle = reactNative.Platform.OS === "web" ? {
13047
+ position: "fixed",
13048
+ top: 0,
13049
+ bottom: 0,
13050
+ [side]: 0,
13051
+ width,
13052
+ transitionProperty: "width",
13053
+ transitionDuration: "200ms",
13054
+ transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)",
13055
+ display: "flex",
13056
+ flexDirection: "column",
13057
+ overflow: "hidden",
13058
+ zIndex: 40
13059
+ } : {
13060
+ width,
13061
+ flexDirection: "column",
13062
+ overflow: "hidden"
13063
+ };
13064
+ const variantStyle = reactNative.Platform.OS === "web" ? variant === "floating" ? {
13065
+ margin: 8,
13066
+ borderRadius: colors.radius.lg,
13067
+ top: 8,
13068
+ bottom: 8,
13069
+ height: "auto"
13070
+ } : variant === "inset" ? {
13071
+ boxShadow: "4px 0 16px rgba(0,0,0,0.08)"
13072
+ } : {} : {};
13073
+ const rootStyle = {
13074
+ ...containerStyle,
13075
+ ...variantStyle,
13076
+ backgroundColor: colors.semantic.background.elevated,
13077
+ borderRightWidth: variant !== "floating" ? 1 : 0,
13078
+ borderRightColor: colors.semantic.border.default
13079
+ };
13080
+ if (reactNative.Platform.OS === "web") {
13081
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx(
13082
+ "nav",
13083
+ {
13084
+ id: navId,
13085
+ "aria-label": "Sidebar",
13086
+ "data-collapsed": current,
13087
+ "data-side": side,
13088
+ "data-variant": variant,
13089
+ "data-testid": testID,
13090
+ className: cn(
13091
+ "nori-sidebar flex flex-col overflow-hidden transition-[width] duration-200",
13092
+ className
13093
+ ),
13094
+ style: rootStyle,
13095
+ children
13096
+ }
13097
+ ) });
13098
+ }
13099
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: rootStyle, testID, accessibilityRole: "menu", accessibilityLabel: "Sidebar", children }) });
13100
+ }, "SidebarRoot");
13101
+ var SidebarHeader = /* @__PURE__ */ __name(({ children, className, testID }) => {
13102
+ const colors = useThemeColors();
13103
+ const style = {
13104
+ padding: px(colors.spacing["4"]),
13105
+ borderBottomWidth: 1,
13106
+ borderBottomColor: colors.semantic.border.default,
13107
+ flexDirection: "row",
13108
+ alignItems: "center",
13109
+ gap: px(colors.spacing["2"]),
13110
+ overflow: "hidden"
13111
+ };
13112
+ if (reactNative.Platform.OS === "web") {
13113
+ return /* @__PURE__ */ jsxRuntime.jsx(
13114
+ "div",
13115
+ {
13116
+ "data-testid": testID,
13117
+ className: cn("nori-sidebar-header", className),
13118
+ style,
13119
+ children
13120
+ }
13121
+ );
13122
+ }
13123
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13124
+ }, "SidebarHeader");
13125
+ var SidebarContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
13126
+ const style = { flex: 1, overflow: "hidden" };
13127
+ if (reactNative.Platform.OS === "web") {
13128
+ return /* @__PURE__ */ jsxRuntime.jsx(
13129
+ "div",
13130
+ {
13131
+ "data-testid": testID,
13132
+ className: cn("nori-sidebar-content", className),
13133
+ style: { flex: 1, overflowY: "auto", overflowX: "hidden" },
13134
+ children
13135
+ }
13136
+ );
13137
+ }
13138
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { style, testID, contentContainerStyle: { flexGrow: 1 }, children });
13139
+ }, "SidebarContent");
13140
+ var SidebarFooter = /* @__PURE__ */ __name(({ children, className, testID }) => {
13141
+ const colors = useThemeColors();
13142
+ const style = {
13143
+ padding: px(colors.spacing["4"]),
13144
+ borderTopWidth: 1,
13145
+ borderTopColor: colors.semantic.border.default,
13146
+ overflow: "hidden"
13147
+ };
13148
+ if (reactNative.Platform.OS === "web") {
13149
+ return /* @__PURE__ */ jsxRuntime.jsx(
13150
+ "div",
13151
+ {
13152
+ "data-testid": testID,
13153
+ className: cn("nori-sidebar-footer", className),
13154
+ style,
13155
+ children
13156
+ }
13157
+ );
13158
+ }
13159
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13160
+ }, "SidebarFooter");
13161
+ var SidebarGroup = /* @__PURE__ */ __name(({ children, className, testID }) => {
13162
+ const colors = useThemeColors();
13163
+ const style = {
13164
+ paddingTop: px(colors.spacing["2"]),
13165
+ paddingBottom: px(colors.spacing["2"])
13166
+ };
13167
+ if (reactNative.Platform.OS === "web") {
13168
+ return /* @__PURE__ */ jsxRuntime.jsx(
13169
+ "div",
13170
+ {
13171
+ "data-testid": testID,
13172
+ className: cn("nori-sidebar-group", className),
13173
+ style,
13174
+ children
13175
+ }
13176
+ );
13177
+ }
13178
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13179
+ }, "SidebarGroup");
13180
+ var SidebarGroupLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
13181
+ const ctx = useSidebarContext("Sidebar.GroupLabel");
13182
+ const colors = useThemeColors();
13183
+ if (ctx.collapsed) {
13184
+ return null;
13185
+ }
13186
+ const style = {
13187
+ paddingHorizontal: px(colors.spacing["4"]),
13188
+ paddingVertical: px(colors.spacing["1"])
13189
+ };
13190
+ const textStyle = {
13191
+ fontSize: 11,
13192
+ fontWeight: "600",
13193
+ letterSpacing: 0.5,
13194
+ textTransform: "uppercase",
13195
+ color: colors.semantic.text.muted
13196
+ };
13197
+ if (reactNative.Platform.OS === "web") {
13198
+ return /* @__PURE__ */ jsxRuntime.jsx(
13199
+ "div",
13200
+ {
13201
+ "data-testid": testID,
13202
+ className: cn("nori-sidebar-group-label", className),
13203
+ style,
13204
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: textStyle, children })
13205
+ }
13206
+ );
13207
+ }
13208
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, children }) });
13209
+ }, "SidebarGroupLabel");
13210
+ var SidebarMenu = /* @__PURE__ */ __name(({ children, className, testID }) => {
13211
+ const colors = useThemeColors();
13212
+ const style = {
13213
+ paddingHorizontal: px(colors.spacing["2"]),
13214
+ gap: px(colors.spacing["1"])
13215
+ };
13216
+ if (reactNative.Platform.OS === "web") {
13217
+ return /* @__PURE__ */ jsxRuntime.jsx(
13218
+ "ul",
13219
+ {
13220
+ "data-testid": testID,
13221
+ className: cn("nori-sidebar-menu", className),
13222
+ style: {
13223
+ ...style,
13224
+ listStyle: "none",
13225
+ margin: 0,
13226
+ padding: `0 ${colors.spacing["2"]}px`
13227
+ },
13228
+ children
13229
+ }
13230
+ );
13231
+ }
13232
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13233
+ }, "SidebarMenu");
13234
+ var SidebarMenuItem = /* @__PURE__ */ __name(({
13235
+ icon,
13236
+ active = false,
13237
+ disabled = false,
13238
+ onPress,
13239
+ children,
13240
+ className,
13241
+ testID
13242
+ }) => {
13243
+ const ctx = useSidebarContext("Sidebar.MenuItem");
13244
+ const colors = useThemeColors();
13245
+ const itemStyle = {
13246
+ flexDirection: "row",
13247
+ alignItems: "center",
13248
+ borderRadius: px(colors.radius.md),
13249
+ paddingHorizontal: px(colors.spacing["3"]),
13250
+ paddingVertical: px(colors.spacing["2"]),
13251
+ gap: px(colors.spacing["3"]),
13252
+ opacity: disabled ? 0.5 : 1,
13253
+ ...ctx.collapsed ? { justifyContent: "center", paddingHorizontal: px(colors.spacing["2"]) } : {}
13254
+ };
13255
+ const activeBg = colors.semantic.interactive.primary;
13256
+ const labelStr = typeof children === "string" ? children : void 0;
13257
+ const labelTextStyle = {
13258
+ fontSize: 14,
13259
+ fontWeight: active ? "600" : "400",
13260
+ color: active ? colors.semantic.text.default : colors.semantic.text.muted,
13261
+ flex: 1
13262
+ };
13263
+ if (reactNative.Platform.OS === "web") {
13264
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { style: { listStyle: "none" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
13265
+ "button",
13266
+ {
13267
+ type: "button",
13268
+ "data-testid": testID,
13269
+ "aria-current": active ? "page" : void 0,
13270
+ "aria-disabled": disabled,
13271
+ title: ctx.collapsed && labelStr ? labelStr : void 0,
13272
+ disabled,
13273
+ onClick: disabled ? void 0 : onPress,
13274
+ className: cn("nori-sidebar-menu-item", className),
13275
+ style: {
13276
+ display: "flex",
13277
+ alignItems: "center",
13278
+ gap: colors.spacing["3"],
13279
+ width: "100%",
13280
+ textAlign: "left",
13281
+ border: "none",
13282
+ cursor: disabled ? "not-allowed" : "pointer",
13283
+ borderRadius: colors.radius.md,
13284
+ padding: ctx.collapsed ? `${colors.spacing["2"]}px` : `${colors.spacing["2"]}px ${colors.spacing["3"]}px`,
13285
+ justifyContent: ctx.collapsed ? "center" : "flex-start",
13286
+ background: active ? `${activeBg}1a` : "transparent",
13287
+ opacity: disabled ? 0.5 : 1
13288
+ },
13289
+ children: [
13290
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nori-sidebar-menu-item-icon", "aria-hidden": "true", children: icon }),
13291
+ !ctx.collapsed && /* @__PURE__ */ jsxRuntime.jsx(
13292
+ "span",
13293
+ {
13294
+ style: {
13295
+ fontSize: 14,
13296
+ fontWeight: active ? 600 : 400,
13297
+ color: active ? colors.semantic.text.default : colors.semantic.text.muted,
13298
+ flex: 1,
13299
+ overflow: "hidden",
13300
+ whiteSpace: "nowrap",
13301
+ textOverflow: "ellipsis"
13302
+ },
13303
+ children
13304
+ }
13305
+ )
13306
+ ]
13307
+ }
13308
+ ) });
13309
+ }
13310
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13311
+ reactNative.Pressable,
13312
+ {
13313
+ testID,
13314
+ onPress: disabled ? void 0 : onPress,
13315
+ disabled,
13316
+ accessibilityRole: "menuitem",
13317
+ accessibilityState: { selected: active, disabled },
13318
+ style: ({ pressed }) => [
13319
+ itemStyle,
13320
+ active ? { backgroundColor: `${activeBg}1a` } : {},
13321
+ pressed && { opacity: 0.7 }
13322
+ ],
13323
+ children: [
13324
+ icon && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { children: icon }),
13325
+ !ctx.collapsed && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: labelTextStyle, numberOfLines: 1, children })
13326
+ ]
13327
+ }
13328
+ );
13329
+ }, "SidebarMenuItem");
13330
+ var Sidebar = Object.assign(SidebarRoot, {
13331
+ Header: SidebarHeader,
13332
+ Content: SidebarContent,
13333
+ Footer: SidebarFooter,
13334
+ Group: SidebarGroup,
13335
+ GroupLabel: SidebarGroupLabel,
13336
+ Menu: SidebarMenu,
13337
+ MenuItem: SidebarMenuItem
13338
+ });
11872
13339
  var PULSE_DURATION_MS = 900;
11873
13340
  var PULSE_MIN = 0.55;
11874
13341
  var PULSE_MAX = 1;
@@ -14235,9 +15702,11 @@ exports.Button = Button;
14235
15702
  exports.ButtonGroup = ButtonGroup;
14236
15703
  exports.Calendar = Calendar;
14237
15704
  exports.Card = Card;
15705
+ exports.Carousel = Carousel;
14238
15706
  exports.Checkbox = Checkbox;
14239
15707
  exports.Collapsible = Collapsible;
14240
15708
  exports.Combobox = Combobox;
15709
+ exports.Command = Command;
14241
15710
  exports.ContextMenu = ContextMenu;
14242
15711
  exports.DataTable = DataTable;
14243
15712
  exports.DatePicker = DatePicker;
@@ -14248,9 +15717,11 @@ exports.Empty = Empty;
14248
15717
  exports.Field = Field;
14249
15718
  exports.FloatButton = FloatButton;
14250
15719
  exports.HStack = HStack;
15720
+ exports.HoverCard = HoverCard;
14251
15721
  exports.I18nProvider = I18nProvider;
14252
15722
  exports.Icon = Icon;
14253
15723
  exports.InputGroup = InputGroup;
15724
+ exports.InputOTP = InputOTP;
14254
15725
  exports.Item = Item;
14255
15726
  exports.Kbd = Kbd;
14256
15727
  exports.Label = Label;
@@ -14278,6 +15749,7 @@ exports.SheetHeader = SheetHeader;
14278
15749
  exports.SheetPanel = SheetPanel;
14279
15750
  exports.SheetTitle = SheetTitle;
14280
15751
  exports.SheetTrigger = SheetTrigger;
15752
+ exports.Sidebar = Sidebar;
14281
15753
  exports.Skeleton = Skeleton;
14282
15754
  exports.Slider = Slider;
14283
15755
  exports.SliderGestureProvider = SliderGestureProvider;
@@ -14313,10 +15785,12 @@ exports.themeDark = themeDark;
14313
15785
  exports.toast = toast2;
14314
15786
  exports.useCalendarCaption = useCalendarCaption;
14315
15787
  exports.useColorScheme = useColorScheme;
15788
+ exports.useCommandContext = useCommandContext;
14316
15789
  exports.useLocale = useLocale;
14317
15790
  exports.usePagination = usePagination;
14318
15791
  exports.usePopoverContext = usePopoverContext;
14319
15792
  exports.useSemanticIcon = useSemanticIcon;
15793
+ exports.useSidebarContext = useSidebarContext;
14320
15794
  exports.useSliderInteractionActive = useSliderInteractionActive;
14321
15795
  exports.useTheme = useTheme;
14322
15796
  exports.useThemeColors = useThemeColors;