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