@nori-ui/core 1.8.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 (39) hide show
  1. package/dist/{chunk-PLQPBMG2.js → chunk-BXZGCOKT.js} +2 -2
  2. package/dist/{chunk-PLQPBMG2.js.map → chunk-BXZGCOKT.js.map} +1 -1
  3. package/dist/{chunk-RI4Y2C5U.js → chunk-KLK7OMFT.js} +3 -3
  4. package/dist/{chunk-RI4Y2C5U.js.map → chunk-KLK7OMFT.js.map} +1 -1
  5. package/dist/chunk-OHWRTHGL.js +495 -0
  6. package/dist/chunk-OHWRTHGL.js.map +1 -0
  7. package/dist/{chunk-V5QSMDZL.js → chunk-QB6RH6UU.js} +3 -3
  8. package/dist/{chunk-V5QSMDZL.js.map → chunk-QB6RH6UU.js.map} +1 -1
  9. package/dist/chunk-S763GTIZ.js +350 -0
  10. package/dist/chunk-S763GTIZ.js.map +1 -0
  11. package/dist/chunk-UJRVWGK7.js +3 -0
  12. package/dist/chunk-UJRVWGK7.js.map +1 -0
  13. package/dist/client.cjs +2248 -1424
  14. package/dist/client.cjs.map +1 -1
  15. package/dist/client.d.cts +2 -0
  16. package/dist/client.d.ts +2 -0
  17. package/dist/client.js +13 -10
  18. package/dist/client.js.map +1 -1
  19. package/dist/components/Accordion/index.js +2 -2
  20. package/dist/components/Command/index.cjs +1371 -0
  21. package/dist/components/Command/index.cjs.map +1 -0
  22. package/dist/components/Command/index.d.cts +89 -0
  23. package/dist/components/Command/index.d.ts +89 -0
  24. package/dist/components/Command/index.js +11 -0
  25. package/dist/components/Command/index.js.map +1 -0
  26. package/dist/components/Dialog/index.js +2 -1
  27. package/dist/components/Sidebar/index.cjs +675 -0
  28. package/dist/components/Sidebar/index.cjs.map +1 -0
  29. package/dist/components/Sidebar/index.d.cts +109 -0
  30. package/dist/components/Sidebar/index.d.ts +109 -0
  31. package/dist/components/Sidebar/index.js +7 -0
  32. package/dist/components/Sidebar/index.js.map +1 -0
  33. package/dist/components/Switch/index.js +2 -2
  34. package/dist/index.cjs +2248 -1424
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +2 -0
  37. package/dist/index.d.ts +2 -0
  38. package/dist/index.js +13 -10
  39. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -7070,220 +7070,15 @@ var Collapsible = Object.assign(CollapsibleRoot, {
7070
7070
  var Combobox = /* @__PURE__ */ __name((props) => {
7071
7071
  return /* @__PURE__ */ jsxRuntime.jsx(Select, { searchable: true, ...props });
7072
7072
  }, "Combobox");
7073
- var MenuContext = React.createContext(null);
7074
- var MenuContextProvider = /* @__PURE__ */ __name(({
7075
- open,
7076
- toggle,
7077
- close,
7078
- children
7079
- }) => /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, toggle: toggle ?? close, close }, children }), "MenuContextProvider");
7080
- function useMenuContext(caller) {
7081
- const ctx = React.useContext(MenuContext);
7073
+ var DialogContext = React.createContext(null);
7074
+ var useDialogContext = /* @__PURE__ */ __name((label) => {
7075
+ const ctx = React.useContext(DialogContext);
7082
7076
  if (!ctx) {
7083
- throw new Error(`<${caller}> must be rendered inside a <DropdownMenu> or <ContextMenu>.`);
7077
+ throw new Error(`<${label}> must be rendered inside a <Dialog>.`);
7084
7078
  }
7085
7079
  return ctx;
7086
- }
7087
- __name(useMenuContext, "useMenuContext");
7088
- var MenuContent = /* @__PURE__ */ __name(({
7089
- children,
7090
- className,
7091
- testID,
7092
- side = "bottom",
7093
- align = "start",
7094
- "aria-label": ariaLabel
7095
- }) => {
7096
- const colors = useThemeColors();
7097
- const containerRef = React.useRef(null);
7098
- React.useEffect(() => {
7099
- if (reactNative.Platform.OS !== "web") {
7100
- return;
7101
- }
7102
- if (typeof document === "undefined") {
7103
- return;
7104
- }
7105
- const container = containerRef.current;
7106
- if (!container) {
7107
- return;
7108
- }
7109
- const getItems = /* @__PURE__ */ __name(() => Array.from(container.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')), "getItems");
7110
- const onKeyDown = /* @__PURE__ */ __name((e) => {
7111
- const items = getItems();
7112
- if (items.length === 0) {
7113
- return;
7114
- }
7115
- const focused = document.activeElement;
7116
- const idx = focused ? items.indexOf(focused) : -1;
7117
- switch (e.key) {
7118
- case "ArrowDown":
7119
- e.preventDefault();
7120
- items[idx < items.length - 1 ? idx + 1 : 0]?.focus();
7121
- break;
7122
- case "ArrowUp":
7123
- e.preventDefault();
7124
- items[idx > 0 ? idx - 1 : items.length - 1]?.focus();
7125
- break;
7126
- case "Home":
7127
- e.preventDefault();
7128
- items[0]?.focus();
7129
- break;
7130
- case "End":
7131
- e.preventDefault();
7132
- items[items.length - 1]?.focus();
7133
- break;
7134
- }
7135
- }, "onKeyDown");
7136
- container.addEventListener("keydown", onKeyDown);
7137
- return () => container.removeEventListener("keydown", onKeyDown);
7138
- });
7139
- return /* @__PURE__ */ jsxRuntime.jsx(
7140
- Popover.Content,
7141
- {
7142
- side,
7143
- align,
7144
- ...testID !== void 0 ? { testID } : {},
7145
- ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
7146
- ...className !== void 0 ? { className } : {},
7147
- children: /* @__PURE__ */ jsxRuntime.jsx(
7148
- reactNative.View,
7149
- {
7150
- ref: containerRef,
7151
- ...{
7152
- role: "menu",
7153
- ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {}
7154
- },
7155
- style: {
7156
- minWidth: 160,
7157
- paddingVertical: px(colors.spacing["1"]),
7158
- margin: -px(colors.spacing["4"]),
7159
- borderRadius: px(colors.radius.lg),
7160
- overflow: "hidden"
7161
- },
7162
- children
7163
- }
7164
- )
7165
- }
7166
- );
7167
- }, "MenuContent");
7168
- MenuContent.displayName = "MenuContent";
7169
- var MenuItem = /* @__PURE__ */ __name(({
7170
- onSelect,
7171
- disabled = false,
7172
- destructive = false,
7173
- icon,
7174
- shortcut,
7175
- children,
7176
- className,
7177
- testID
7178
- }) => {
7179
- const colors = useThemeColors();
7180
- const menu = useMenuContext("MenuItem");
7181
- const handlePress = React.useCallback(() => {
7182
- if (disabled) {
7183
- return;
7184
- }
7185
- onSelect?.();
7186
- menu.close();
7187
- }, [disabled, onSelect, menu]);
7188
- const textColor = destructive ? colors.color.danger : disabled ? colors.semantic.text.muted : colors.semantic.text.default;
7189
- return /* @__PURE__ */ jsxRuntime.jsxs(
7190
- reactNative.Pressable,
7191
- {
7192
- onPress: handlePress,
7193
- disabled,
7194
- ...{
7195
- role: "menuitem",
7196
- "aria-disabled": disabled ? "true" : void 0,
7197
- tabIndex: disabled ? -1 : 0,
7198
- onKeyDown: /* @__PURE__ */ __name((e) => {
7199
- if (e.key === "Enter" || e.key === " ") {
7200
- e.preventDefault();
7201
- handlePress();
7202
- }
7203
- }, "onKeyDown")
7204
- },
7205
- ...testID !== void 0 ? { testID } : {},
7206
- className: cn("flex-row items-center gap-2 px-3 py-2", className),
7207
- style: { opacity: disabled ? 0.4 : 1 },
7208
- accessibilityRole: "menuitem",
7209
- accessibilityState: { disabled },
7210
- children: [
7211
- icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
7212
- /* @__PURE__ */ jsxRuntime.jsx(
7213
- reactNative.Text,
7214
- {
7215
- style: {
7216
- flex: 1,
7217
- fontFamily: colors.fontFamily.body,
7218
- fontSize: px(colors.fontSize.sm),
7219
- color: textColor
7220
- },
7221
- children
7222
- }
7223
- ),
7224
- shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
7225
- reactNative.Text,
7226
- {
7227
- ...{ "aria-hidden": "true" },
7228
- style: {
7229
- fontFamily: colors.fontFamily.body,
7230
- fontSize: px(colors.fontSize.xs),
7231
- color: colors.semantic.text.muted
7232
- },
7233
- children: shortcut
7234
- }
7235
- )
7236
- ]
7237
- }
7238
- );
7239
- }, "MenuItem");
7240
- MenuItem.displayName = "MenuItem";
7241
- var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
7242
- const colors = useThemeColors();
7243
- return /* @__PURE__ */ jsxRuntime.jsx(
7244
- reactNative.View,
7245
- {
7246
- ...{ role: "separator" },
7247
- accessibilityRole: "none",
7248
- ...testID !== void 0 ? { testID } : {},
7249
- className: cn("mx-1 my-1", className),
7250
- style: {
7251
- height: 1,
7252
- marginVertical: 4,
7253
- marginHorizontal: 4,
7254
- backgroundColor: colors.semantic.border.default
7255
- }
7256
- }
7257
- );
7258
- }, "MenuSeparator");
7259
- MenuSeparator.displayName = "MenuSeparator";
7260
- var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
7261
- const colors = useThemeColors();
7262
- return /* @__PURE__ */ jsxRuntime.jsx(
7263
- reactNative.View,
7264
- {
7265
- ...{ role: "presentation" },
7266
- ...testID !== void 0 ? { testID } : {},
7267
- className: cn("px-3 pt-2 pb-1", className),
7268
- children: /* @__PURE__ */ jsxRuntime.jsx(
7269
- reactNative.Text,
7270
- {
7271
- style: {
7272
- fontFamily: colors.fontFamily.body,
7273
- fontSize: px(colors.fontSize.xs),
7274
- color: colors.semantic.text.muted,
7275
- textTransform: "uppercase",
7276
- letterSpacing: 0.6,
7277
- fontWeight: "600"
7278
- },
7279
- children
7280
- }
7281
- )
7282
- }
7283
- );
7284
- }, "MenuLabel");
7285
- MenuLabel.displayName = "MenuLabel";
7286
- var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7080
+ }, "useDialogContext");
7081
+ var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7287
7082
  const [inner, setInner] = React.useState(defaultOpen);
7288
7083
  const isControlled = open !== void 0;
7289
7084
  const current = isControlled ? open : inner;
@@ -7296,37 +7091,34 @@ var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOp
7296
7091
  },
7297
7092
  [isControlled, onOpenChange]
7298
7093
  );
7299
- const toggle = React.useCallback(() => setOpen(!current), [setOpen, current]);
7300
- const close = React.useCallback(() => setOpen(false), [setOpen]);
7301
- return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: current, toggle, close, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
7302
- }, "DropdownMenuRoot");
7303
- var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7304
- const menu = useMenuContext("DropdownMenu.Trigger");
7305
- const popover = usePopoverContext("DropdownMenu.Trigger");
7306
- const onPress = React.useCallback(() => {
7307
- popover.measureTrigger();
7308
- popover.setOpen(!popover.open);
7309
- }, [popover]);
7310
- if (React.isValidElement(children)) {
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)) {
7311
7109
  const child = children;
7312
7110
  const fire = /* @__PURE__ */ __name((existing) => (event) => {
7313
7111
  existing?.(event);
7314
- popover.measureTrigger();
7315
- popover.setOpen(!popover.open);
7112
+ ctx.setOpen(true);
7316
7113
  }, "fire");
7317
7114
  return /* @__PURE__ */ jsxRuntime.jsx(
7318
7115
  Slot,
7319
7116
  {
7320
7117
  ref: (node) => {
7321
- popover.triggerRef.current = node;
7118
+ ctx.triggerRef.current = node;
7322
7119
  },
7323
7120
  onClick: fire(child.props.onClick),
7324
7121
  onPress: fire(child.props.onPress),
7325
- ...{
7326
- "aria-haspopup": "menu",
7327
- "aria-expanded": menu.open,
7328
- "aria-controls": popover.contentId
7329
- },
7330
7122
  ...testID !== void 0 ? { "data-testid": testID } : {},
7331
7123
  ...className !== void 0 ? { className } : {},
7332
7124
  children: child
@@ -7337,972 +7129,1222 @@ var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID
7337
7129
  reactNative.Pressable,
7338
7130
  {
7339
7131
  ref: (node) => {
7340
- popover.triggerRef.current = node;
7132
+ ctx.triggerRef.current = node;
7341
7133
  },
7342
7134
  onPress,
7343
- ...{
7344
- "aria-haspopup": "menu",
7345
- "aria-expanded": menu.open,
7346
- "aria-controls": popover.contentId
7347
- },
7348
7135
  ...testID !== void 0 ? { testID } : {},
7349
7136
  ...className !== void 0 ? { className } : {},
7350
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7137
+ children: wrapStringChildren4(children)
7351
7138
  }
7352
7139
  );
7353
- }, "DropdownMenuTrigger");
7354
- var DropdownMenuContent = /* @__PURE__ */ __name((props) => /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }), "DropdownMenuContent");
7355
- var DropdownMenu = Object.assign(DropdownMenuRoot, {
7356
- Trigger: DropdownMenuTrigger,
7357
- Content: DropdownMenuContent,
7358
- Item: MenuItem,
7359
- Separator: MenuSeparator,
7360
- Label: MenuLabel
7361
- });
7362
- var ContextMenuCtx = React.createContext(null);
7363
- var useContextMenuCtx = /* @__PURE__ */ __name(() => {
7364
- const ctx = React.useContext(ContextMenuCtx);
7365
- if (!ctx) {
7366
- throw new Error("ContextMenu compound parts must be rendered inside a <ContextMenu>.");
7140
+ }, "DialogTrigger");
7141
+ function wrapStringChildren4(children) {
7142
+ if (typeof children === "string" || typeof children === "number") {
7143
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
7367
7144
  }
7368
- return ctx;
7369
- }, "useContextMenuCtx");
7370
- var ContextMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7371
- const [inner, setInner] = React.useState(defaultOpen);
7372
- const isControlled = open !== void 0;
7373
- const current = isControlled ? open : inner;
7374
- const setOpen = React.useCallback(
7375
- (next) => {
7376
- if (!isControlled) {
7377
- setInner(next);
7145
+ return children;
7146
+ }
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");
7176
+ const colors = useThemeColors();
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);
7190
+ React.useEffect(() => {
7191
+ if (reactNative.Platform.OS !== "web") {
7192
+ setEntered(true);
7193
+ return;
7194
+ }
7195
+ if (!ctx.open) {
7196
+ setEntered(false);
7197
+ return;
7198
+ }
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") {
7212
+ return;
7213
+ }
7214
+ const node = overlayDomRef.current;
7215
+ if (!node) {
7216
+ return;
7217
+ }
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) {
7233
+ return;
7234
+ }
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;
7378
7248
  }
7379
- onOpenChange?.(next);
7380
- },
7381
- [isControlled, onOpenChange]
7382
- );
7383
- return /* @__PURE__ */ jsxRuntime.jsx(ContextMenuCtx.Provider, { value: { open: current, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
7384
- }, "ContextMenuRoot");
7385
- var ContextMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7386
- const ctx = useContextMenuCtx();
7387
- const popover = usePopoverContext("ContextMenu.Trigger");
7388
- const openMenu = React.useCallback(() => {
7389
- popover.measureTrigger();
7390
- ctx.setOpen(true);
7391
- }, [ctx, popover]);
7392
- if (reactNative.Platform.OS === "web") {
7393
- if (React.isValidElement(children)) {
7394
- const child = children;
7395
- const existing = child.props.onContextMenu;
7396
- return /* @__PURE__ */ jsxRuntime.jsx(
7397
- Slot,
7398
- {
7399
- ref: (node) => {
7400
- popover.triggerRef.current = node;
7401
- },
7402
- onContextMenu: (e) => {
7403
- e.preventDefault();
7404
- existing?.(e);
7405
- openMenu();
7406
- },
7407
- ...{
7408
- "aria-haspopup": "menu",
7409
- "aria-expanded": ctx.open,
7410
- "aria-controls": popover.contentId
7411
- },
7412
- ...testID !== void 0 ? { "data-testid": testID } : {},
7413
- ...className !== void 0 ? { className } : {},
7414
- children: child
7415
- }
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
7416
7274
  );
7417
- }
7418
- return /* @__PURE__ */ jsxRuntime.jsx(
7419
- reactNative.Pressable,
7420
- {
7421
- ref: (node) => {
7422
- popover.triggerRef.current = node;
7423
- },
7424
- ...{
7425
- onContextMenu: /* @__PURE__ */ __name((e) => {
7426
- e.preventDefault();
7427
- openMenu();
7428
- }, "onContextMenu"),
7429
- "aria-haspopup": "menu",
7430
- "aria-expanded": ctx.open,
7431
- "aria-controls": popover.contentId
7432
- },
7433
- ...testID !== void 0 ? { testID } : {},
7434
- ...className !== void 0 ? { className } : {},
7435
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7275
+ if (focusable.length === 0) {
7276
+ event.preventDefault();
7277
+ return;
7436
7278
  }
7437
- );
7438
- }
7439
- if (React.isValidElement(children)) {
7440
- const child = children;
7441
- const existing = child.props.onLongPress;
7442
- return /* @__PURE__ */ jsxRuntime.jsx(
7443
- Slot,
7444
- {
7445
- ref: (node) => {
7446
- popover.triggerRef.current = node;
7447
- },
7448
- onLongPress: (e) => {
7449
- existing?.(e);
7450
- openMenu();
7451
- },
7452
- accessibilityRole: "button",
7453
- ...testID !== void 0 ? { testID } : {},
7454
- ...className !== void 0 ? { className } : {},
7455
- children: child
7279
+ const first = focusable[0];
7280
+ const last = focusable[focusable.length - 1];
7281
+ if (!first || !last) {
7282
+ return;
7456
7283
  }
7457
- );
7458
- }
7459
- return /* @__PURE__ */ jsxRuntime.jsx(
7460
- reactNative.Pressable,
7461
- {
7462
- ref: (node) => {
7463
- popover.triggerRef.current = node;
7464
- },
7465
- onLongPress: openMenu,
7466
- ...testID !== void 0 ? { testID } : {},
7467
- ...className !== void 0 ? { className } : {},
7468
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7469
- }
7470
- );
7471
- }, "ContextMenuTrigger");
7472
- var ContextMenuContent = /* @__PURE__ */ __name((props) => {
7473
- const ctx = useContextMenuCtx();
7474
- const close = React.useCallback(() => ctx.setOpen(false), [ctx]);
7475
- return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: ctx.open, close, children: /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }) });
7476
- }, "ContextMenuContent");
7477
- var ContextMenu = Object.assign(ContextMenuRoot, {
7478
- Trigger: ContextMenuTrigger,
7479
- Content: ContextMenuContent,
7480
- Item: MenuItem,
7481
- Separator: MenuSeparator,
7482
- Label: MenuLabel
7483
- });
7484
- var range = /* @__PURE__ */ __name((from, to) => {
7485
- if (to < from) {
7486
- return [];
7487
- }
7488
- const out = new Array(to - from + 1);
7489
- for (let i = 0; i < out.length; i += 1) {
7490
- out[i] = from + i;
7491
- }
7492
- return out;
7493
- }, "range");
7494
- function usePagination(args) {
7495
- const {
7496
- page: controlledPage,
7497
- defaultPage = 1,
7498
- pageCount,
7499
- siblingCount = 1,
7500
- boundaryCount = 1,
7501
- showFirstLast = false,
7502
- showPrevNext = true,
7503
- onPageChange
7504
- } = args;
7505
- const isControlled = controlledPage !== void 0;
7506
- const [uncontrolledPage, setUncontrolledPage] = React.useState(defaultPage);
7507
- const onChangeRef = React.useRef(onPageChange);
7508
- onChangeRef.current = onPageChange;
7509
- const safePageCount = Math.max(1, Math.floor(pageCount));
7510
- const rawPage = isControlled ? controlledPage : uncontrolledPage;
7511
- const currentPage = Math.min(Math.max(1, Math.floor(rawPage)), safePageCount);
7512
- const goToPage = React.useCallback(
7513
- (next2) => {
7514
- const clamped = Math.min(Math.max(1, Math.floor(next2)), Math.max(1, Math.floor(pageCount)));
7515
- if (!isControlled) {
7516
- setUncontrolledPage(clamped);
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();
7517
7292
  }
7518
- onChangeRef.current?.(clamped);
7519
- },
7520
- [isControlled, pageCount]
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]);
7303
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7304
+ reactNative.Modal,
7305
+ {
7306
+ visible: ctx.open,
7307
+ transparent: true,
7308
+ animationType: reactNative.Platform.OS === "web" ? "none" : "fade",
7309
+ onRequestClose: () => ctx.setOpen(false),
7310
+ children: [
7311
+ /* @__PURE__ */ jsxRuntime.jsx(BlurBackdrop, { intensity: 60, tint: scheme === "dark" ? "dark" : "light", style: reactNative.StyleSheet.absoluteFill }),
7312
+ /* @__PURE__ */ jsxRuntime.jsx(
7313
+ reactNative.Pressable,
7314
+ {
7315
+ accessibilityRole: "none",
7316
+ "aria-hidden": true,
7317
+ ref: (node) => {
7318
+ overlayDomRef.current = node;
7319
+ },
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
+ )
7347
+ }
7348
+ )
7349
+ ]
7350
+ }
7521
7351
  );
7522
- const prev = React.useCallback(() => goToPage(currentPage - 1), [goToPage, currentPage]);
7523
- const next = React.useCallback(() => goToPage(currentPage + 1), [goToPage, currentPage]);
7524
- const first = React.useCallback(() => goToPage(1), [goToPage]);
7525
- const last = React.useCallback(() => goToPage(safePageCount), [goToPage, safePageCount]);
7526
- const pages = React.useMemo(() => {
7527
- const items = [];
7528
- const safeSibling = Math.max(0, Math.floor(siblingCount));
7529
- const safeBoundary = Math.max(0, Math.floor(boundaryCount));
7530
- if (showFirstLast) {
7531
- items.push({ type: "first", disabled: currentPage <= 1 });
7352
+ }, "DialogContent");
7353
+ var DialogTitle = /* @__PURE__ */ __name(({ children, className }) => {
7354
+ const ctx = useDialogContext("DialogTitle");
7355
+ const colors = useThemeColors();
7356
+ return /* @__PURE__ */ jsxRuntime.jsx(
7357
+ reactNative.Text,
7358
+ {
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),
7364
+ style: {
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
7532
7371
  }
7533
- if (showPrevNext) {
7534
- items.push({ type: "prev", disabled: currentPage <= 1 });
7372
+ );
7373
+ }, "DialogTitle");
7374
+ var DialogDescription = /* @__PURE__ */ __name(({ children, className }) => {
7375
+ const ctx = useDialogContext("DialogDescription");
7376
+ const colors = useThemeColors();
7377
+ return /* @__PURE__ */ jsxRuntime.jsx(
7378
+ reactNative.Text,
7379
+ {
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
7535
7390
  }
7536
- const startPages = range(1, Math.min(safeBoundary, safePageCount));
7537
- const endPages = range(Math.max(safePageCount - safeBoundary + 1, safeBoundary + 1), safePageCount);
7538
- const siblingsStart = Math.max(
7539
- Math.min(currentPage - safeSibling, safePageCount - safeBoundary - safeSibling * 2 - 1),
7540
- safeBoundary + 2
7391
+ );
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)) {
7404
+ const child = children;
7405
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
7406
+ existing?.(event);
7407
+ ctx.setOpen(false);
7408
+ }, "fire");
7409
+ return /* @__PURE__ */ jsxRuntime.jsx(
7410
+ Slot,
7411
+ {
7412
+ onClick: fire(child.props.onClick),
7413
+ onPress: fire(child.props.onPress),
7414
+ ...testID !== void 0 ? { "data-testid": testID } : {},
7415
+ ...className !== void 0 ? { className } : {},
7416
+ children: child
7417
+ }
7541
7418
  );
7542
- const siblingsEnd = Math.min(
7543
- Math.max(currentPage + safeSibling, safeBoundary + safeSibling * 2 + 2),
7544
- endPages.length > 0 ? endPages[0] - 2 : safePageCount - 1
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
+ }
7545
7433
  );
7546
- const middle = [];
7547
- if (siblingsStart > safeBoundary + 2) {
7548
- middle.push("ellipsis");
7549
- } else if (safeBoundary + 1 < safePageCount - safeBoundary) {
7550
- middle.push(safeBoundary + 1);
7551
- }
7552
- for (const p of range(siblingsStart, siblingsEnd)) {
7553
- middle.push(p);
7554
- }
7555
- if (siblingsEnd < safePageCount - safeBoundary - 1) {
7556
- middle.push("ellipsis");
7557
- } else if (safePageCount - safeBoundary > safeBoundary) {
7558
- middle.push(safePageCount - safeBoundary);
7434
+ }
7435
+ return /* @__PURE__ */ jsxRuntime.jsx(
7436
+ reactNative.Pressable,
7437
+ {
7438
+ onPress,
7439
+ role: "button",
7440
+ accessibilityRole: "button",
7441
+ accessibilityLabel,
7442
+ "aria-label": accessibilityLabel,
7443
+ ...testID !== void 0 ? { testID } : {},
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 })
7559
7457
  }
7560
- const seen = /* @__PURE__ */ new Set();
7561
- const pushPage = /* @__PURE__ */ __name((n) => {
7562
- if (n < 1 || n > safePageCount || seen.has(n)) {
7563
- return;
7564
- }
7565
- seen.add(n);
7566
- items.push({ type: "page", page: n, selected: n === currentPage });
7567
- }, "pushPage");
7568
- for (const n of startPages) {
7569
- pushPage(n);
7458
+ );
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
7570
7474
  }
7571
- for (const m of middle) {
7572
- if (m === "ellipsis") {
7573
- items.push({ type: "ellipsis" });
7574
- } else {
7575
- pushPage(m);
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
7484
+ });
7485
+ var CommandContext = React.createContext(null);
7486
+ function useCommandContext(caller) {
7487
+ const ctx = React.useContext(CommandContext);
7488
+ if (!ctx) {
7489
+ throw new Error(`<${caller}> must be rendered inside <Command>.`);
7490
+ }
7491
+ return ctx;
7492
+ }
7493
+ __name(useCommandContext, "useCommandContext");
7494
+ var CommandRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7495
+ const [inner, setInner] = React.useState(defaultOpen);
7496
+ const isControlled = open !== void 0;
7497
+ const current = isControlled ? open : inner;
7498
+ const [query, setQuery] = React.useState("");
7499
+ const setOpen = React.useCallback(
7500
+ (next) => {
7501
+ if (!isControlled) {
7502
+ setInner(next);
7576
7503
  }
7504
+ if (!next) {
7505
+ setQuery("");
7506
+ }
7507
+ onOpenChange?.(next);
7508
+ },
7509
+ [isControlled, onOpenChange]
7510
+ );
7511
+ React.useEffect(() => {
7512
+ if (reactNative.Platform.OS !== "web") {
7513
+ return;
7577
7514
  }
7578
- for (const n of endPages) {
7579
- pushPage(n);
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");
7535
+ if (reactNative.Platform.OS === "web") {
7536
+ if (React.isValidElement(children)) {
7537
+ const child = 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;
7552
+ }
7553
+ return React.cloneElement(child, extraProps);
7580
7554
  }
7581
- if (showPrevNext) {
7582
- items.push({ type: "next", disabled: currentPage >= safePageCount });
7555
+ return /* @__PURE__ */ jsxRuntime.jsx(
7556
+ "button",
7557
+ {
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;
7583
7582
  }
7584
- if (showFirstLast) {
7585
- items.push({ type: "last", disabled: currentPage >= safePageCount });
7583
+ if (reactNative.Platform.OS !== "web") {
7584
+ return;
7586
7585
  }
7587
- return items;
7588
- }, [currentPage, safePageCount, siblingCount, boundaryCount, showFirstLast, showPrevNext]);
7589
- return {
7590
- page: currentPage,
7591
- pages,
7592
- canPrev: currentPage > 1,
7593
- canNext: currentPage < safePageCount,
7594
- goToPage,
7595
- prev,
7596
- next,
7597
- first,
7598
- last
7599
- };
7600
- }
7601
- __name(usePagination, "usePagination");
7602
- var TableContext = React.createContext({
7603
- striped: false,
7604
- compact: false,
7605
- bordered: false,
7606
- rowIndex: 0,
7607
- setRowIndex: /* @__PURE__ */ __name(() => {
7608
- }, "setRowIndex")
7609
- });
7610
- function buildTableCompound(parts) {
7611
- return Object.assign(parts.Root, {
7612
- Header: parts.Header,
7613
- Body: parts.Body,
7614
- Footer: parts.Footer,
7615
- Row: parts.Row,
7616
- HeaderCell: parts.HeaderCell,
7617
- Cell: parts.Cell,
7618
- Caption: parts.Caption
7619
- });
7620
- }
7621
- __name(buildTableCompound, "buildTableCompound");
7622
- var TableRoot = /* @__PURE__ */ __name(({ striped = false, compact = false, bordered = false, children, className, testID }) => {
7623
- const [rowIndex, setRowIndex] = React.useState(0);
7624
- const ctxValue = {
7625
- striped,
7626
- compact,
7627
- bordered,
7628
- rowIndex,
7629
- setRowIndex
7630
- };
7631
- return /* @__PURE__ */ jsxRuntime.jsx(TableContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx(
7632
- "table",
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",
7633
7592
  {
7634
- className: cn(
7635
- "w-full caption-bottom text-sm",
7636
- bordered && "border border-semantic-border-default",
7637
- className
7638
- ),
7639
- ...testID !== void 0 ? { "data-testid": testID } : {},
7640
- children
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
+ ]
7641
7662
  }
7642
- ) }) });
7643
- }, "TableRoot");
7644
- var TableHeader = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7645
- "thead",
7646
- {
7647
- className: cn("[&_tr]:border-b [&_tr]:border-semantic-border-default", className),
7648
- ...testID !== void 0 ? { "data-testid": testID } : {},
7649
- children
7650
- }
7651
- ), "TableHeader");
7652
- var TableBody = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7653
- "tbody",
7654
- {
7655
- className: cn("[&_tr:last-child]:border-0", className),
7656
- ...testID !== void 0 ? { "data-testid": testID } : {},
7657
- children
7658
- }
7659
- ), "TableBody");
7660
- var TableFooter = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7661
- "tfoot",
7662
- {
7663
- className: cn("border-t border-semantic-border-default font-medium", className),
7664
- ...testID !== void 0 ? { "data-testid": testID } : {},
7665
- children
7666
- }
7667
- ), "TableFooter");
7668
- var TableRow = /* @__PURE__ */ __name(({ selected = false, onPress, children, className, testID }) => {
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 }) => {
7669
7686
  const colors = useThemeColors();
7670
- const handleClick = React.useCallback(() => {
7671
- onPress?.();
7672
- }, [onPress]);
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
7705
+ }
7706
+ );
7707
+ }
7673
7708
  return /* @__PURE__ */ jsxRuntime.jsx(
7674
- "tr",
7709
+ reactNative.View,
7675
7710
  {
7676
- className: cn(
7677
- "border-b border-semantic-border-default transition-colors",
7678
- onPress && "cursor-pointer hover:bg-semantic-background-subtle",
7679
- selected && "bg-semantic-background-subtle",
7680
- className
7681
- ),
7682
- style: selected ? { backgroundColor: colors.semantic.background.subtle } : void 0,
7683
- onClick: onPress ? handleClick : void 0,
7684
- ...testID !== void 0 ? { "data-testid": testID } : {},
7685
- children
7711
+ testID,
7712
+ style: {
7713
+ paddingVertical: px(colors.spacing["6"]),
7714
+ paddingHorizontal: px(colors.spacing["4"]),
7715
+ alignItems: "center"
7716
+ },
7717
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.semantic.text.muted, fontSize: 14 }, children: typeof children === "string" ? children : "No results found." })
7686
7718
  }
7687
7719
  );
7688
- }, "TableRow");
7689
- var TableHeaderCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7690
- "th",
7691
- {
7692
- className: cn(
7693
- "h-10 px-4 font-medium text-semantic-text-secondary",
7694
- align === "right" && "text-right",
7695
- align === "center" && "text-center",
7696
- align === "left" && "text-left",
7697
- className
7698
- ),
7699
- colSpan,
7700
- ...testID !== void 0 ? { "data-testid": testID } : {},
7701
- children
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;
7702
7728
  }
7703
- ), "TableHeaderCell");
7704
- var TableCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7705
- "td",
7706
- {
7707
- className: cn(
7708
- "p-4 align-middle",
7709
- align === "right" && "text-right",
7710
- align === "center" && "text-center",
7711
- align === "left" && "text-left",
7712
- className
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
+ );
7756
+ }
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
+ )
7779
+ }
7713
7780
  ),
7714
- colSpan,
7715
- ...testID !== void 0 ? { "data-testid": testID } : {},
7716
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;
7717
7791
  }
7718
- ), "TableCell");
7719
- var TableCaption = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7720
- "caption",
7721
- {
7722
- className: cn("mt-4 text-sm text-semantic-text-secondary", className),
7723
- ...testID !== void 0 ? { "data-testid": testID } : {},
7724
- children
7792
+ const handleSelect = /* @__PURE__ */ __name(() => {
7793
+ if (disabled) {
7794
+ return;
7795
+ }
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
+ }
7847
+ );
7725
7848
  }
7726
- ), "TableCaption");
7727
- var Table = buildTableCompound({
7728
- Root: TableRoot,
7729
- Header: TableHeader,
7730
- Body: TableBody,
7731
- Footer: TableFooter,
7732
- Row: TableRow,
7733
- HeaderCell: TableHeaderCell,
7734
- Cell: TableCell,
7735
- Caption: TableCaption
7736
- });
7737
- function sortData(data, sort) {
7738
- if (!sort) {
7739
- return data;
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
7865
+ }
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
+ );
7740
7886
  }
7741
- const key = sort.id;
7742
- return [...data].sort((a, b) => {
7743
- const av = a[key];
7744
- const bv = b[key];
7745
- if (av == null && bv == null) {
7746
- return 0;
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
7747
7896
  }
7748
- if (av == null) {
7749
- return 1;
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;
7750
7925
  }
7751
- if (bv == null) {
7752
- return -1;
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++;
7931
+ }
7753
7932
  }
7754
- const cmp2 = av < bv ? -1 : av > bv ? 1 : 0;
7755
- return sort.direction === "asc" ? cmp2 : -cmp2;
7756
7933
  });
7934
+ return count;
7757
7935
  }
7758
- __name(sortData, "sortData");
7759
- function SortIndicator({ direction }) {
7760
- if (direction === void 0) {
7761
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4, opacity: 0.3 }, children: "\u21C5" });
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;
7945
+ }
7946
+ const childProps = child.props;
7947
+ if (!("heading" in childProps) && !("onSelect" in childProps) && !("icon" in childProps)) {
7948
+ emptyNode = child;
7949
+ return;
7950
+ }
7951
+ const groupChildren = childProps.children;
7952
+ const count = countVisibleItems(groupChildren, ctx.query);
7953
+ if (count > 0) {
7954
+ anyVisible = true;
7955
+ }
7956
+ });
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>.`);
7762
7978
  }
7763
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4 }, children: direction === "asc" ? "\u2191" : "\u2193" });
7979
+ return ctx;
7764
7980
  }
7765
- __name(SortIndicator, "SortIndicator");
7766
- function DataTable({
7767
- data,
7768
- columns,
7769
- pageSize = 10,
7770
- defaultSort,
7771
- onRowPress,
7772
- emptyState,
7773
- striped,
7774
- compact,
7775
- bordered,
7981
+ __name(useMenuContext, "useMenuContext");
7982
+ var MenuContent = /* @__PURE__ */ __name(({
7983
+ children,
7984
+ className,
7776
7985
  testID,
7777
- className
7778
- }) {
7779
- const [sort, setSort] = React.useState(defaultSort ?? null);
7780
- const sorted = React.useMemo(() => sortData(data, sort), [data, sort]);
7781
- const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));
7782
- const { page, goToPage, canPrev, canNext } = usePagination({ pageCount, defaultPage: 1 });
7783
- const pageSlice = React.useMemo(() => {
7784
- const start = (page - 1) * pageSize;
7785
- return sorted.slice(start, start + pageSize);
7786
- }, [sorted, page, pageSize]);
7787
- const handleSort = /* @__PURE__ */ __name((colId) => {
7788
- setSort((prev) => {
7789
- if (prev?.id !== colId) {
7790
- goToPage(1);
7791
- 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;
7792
8008
  }
7793
- if (prev.direction === "asc") {
7794
- 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;
7795
8028
  }
7796
- goToPage(1);
7797
- return null;
7798
- });
7799
- }, "handleSort");
7800
- const tableProps = {};
7801
- if (striped !== void 0) {
7802
- tableProps.striped = striped;
7803
- }
7804
- if (compact !== void 0) {
7805
- tableProps.compact = compact;
7806
- }
7807
- if (bordered !== void 0) {
7808
- tableProps.bordered = bordered;
7809
- }
7810
- if (testID !== void 0) {
7811
- tableProps.testID = testID;
7812
- }
7813
- if (className !== void 0) {
7814
- tableProps.className = className;
7815
- }
7816
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { width: "100%" }, children: [
7817
- /* @__PURE__ */ jsxRuntime.jsxs(Table, { ...tableProps, children: [
7818
- /* @__PURE__ */ jsxRuntime.jsx(Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: columns.map((col) => {
7819
- const align = col.align;
7820
- return /* @__PURE__ */ jsxRuntime.jsx(Table.HeaderCell, { ...align !== void 0 ? { align } : {}, children: col.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
7821
- reactNative.Pressable,
7822
- {
7823
- accessibilityRole: "button",
7824
- accessibilityLabel: `Sort by ${col.id}`,
7825
- "aria-label": `Sort by ${col.id}`,
7826
- onPress: () => handleSort(col.id),
7827
- style: { flexDirection: "row", alignItems: "center" },
7828
- children: [
7829
- typeof col.header === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children: col.header }) : col.header,
7830
- /* @__PURE__ */ jsxRuntime.jsx(
7831
- SortIndicator,
7832
- {
7833
- ...sort?.id === col.id ? { direction: sort.direction } : {}
7834
- }
7835
- )
7836
- ]
7837
- }
7838
- ) : col.header }, col.id);
7839
- }) }) }),
7840
- /* @__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(
7841
- 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,
7842
8043
  {
7843
- ...onRowPress !== void 0 ? { onPress: /* @__PURE__ */ __name(() => onRowPress(row), "onPress") } : {},
7844
- children: columns.map((col) => {
7845
- const colAlign = col.align;
7846
- return /* @__PURE__ */ jsxRuntime.jsx(
7847
- Table.Cell,
7848
- {
7849
- ...colAlign !== void 0 ? { align: colAlign } : {},
7850
- children: col.cell(row)
7851
- },
7852
- col.id
7853
- );
7854
- })
7855
- },
7856
- i
7857
- )) })
7858
- ] }),
7859
- pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(
7860
- PaginationControls,
7861
- {
7862
- page,
7863
- pageCount,
7864
- canPrev,
7865
- canNext,
7866
- goToPage
7867
- }
7868
- )
7869
- ] });
7870
- }
7871
- __name(DataTable, "DataTable");
7872
- function EmptyState({ children }) {
7873
- 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 });
7874
- }
7875
- __name(EmptyState, "EmptyState");
7876
- function PaginationControls({
7877
- page,
7878
- pageCount,
7879
- canPrev,
7880
- canNext,
7881
- goToPage
7882
- }) {
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;
7883
8083
  return /* @__PURE__ */ jsxRuntime.jsxs(
7884
- reactNative.View,
8084
+ reactNative.Pressable,
7885
8085
  {
7886
- style: {
7887
- flexDirection: "row",
7888
- justifyContent: "flex-end",
7889
- alignItems: "center",
7890
- paddingVertical: 8,
7891
- 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")
7892
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 },
7893
8104
  children: [
8105
+ icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
7894
8106
  /* @__PURE__ */ jsxRuntime.jsx(
7895
- reactNative.Pressable,
8107
+ reactNative.Text,
7896
8108
  {
7897
- onPress: canPrev ? () => goToPage(page - 1) : void 0,
7898
- accessibilityRole: "button",
7899
- accessibilityLabel: "Previous page",
7900
- "aria-label": "Previous page",
7901
- "aria-disabled": !canPrev,
7902
- style: { opacity: canPrev ? 1 : 0.4, paddingHorizontal: 8 },
7903
- 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
7904
8116
  }
7905
8117
  ),
7906
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: { fontSize: 14 }, "aria-live": "polite", children: [
7907
- page,
7908
- " / ",
7909
- pageCount
7910
- ] }),
7911
- /* @__PURE__ */ jsxRuntime.jsx(
7912
- reactNative.Pressable,
8118
+ shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
8119
+ reactNative.Text,
7913
8120
  {
7914
- onPress: canNext ? () => goToPage(page + 1) : void 0,
7915
- accessibilityRole: "button",
7916
- accessibilityLabel: "Next page",
7917
- "aria-label": "Next page",
7918
- "aria-disabled": !canNext,
7919
- style: { opacity: canNext ? 1 : 0.4, paddingHorizontal: 8 },
7920
- 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
7921
8128
  }
7922
8129
  )
7923
8130
  ]
7924
8131
  }
7925
8132
  );
7926
- }
7927
- __name(PaginationControls, "PaginationControls");
7928
- function formatDate(date$1, locale) {
7929
- try {
7930
- return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date$1.toDate(date.getLocalTimeZone()));
7931
- } catch {
7932
- return `${date$1.year}-${String(date$1.month).padStart(2, "0")}-${String(date$1.day).padStart(2, "0")}`;
7933
- }
7934
- }
7935
- __name(formatDate, "formatDate");
7936
- function CalendarIcon({ size = 16, color = "currentColor" }) {
8133
+ }, "MenuItem");
8134
+ MenuItem.displayName = "MenuItem";
8135
+ var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
7937
8136
  const colors = useThemeColors();
7938
- if (reactNative.Platform.OS === "web") {
7939
- return /* @__PURE__ */ jsxRuntime.jsx(
7940
- "svg",
7941
- {
7942
- width: size,
7943
- height: size,
7944
- viewBox: "0 0 24 24",
7945
- fill: "none",
7946
- stroke: color,
7947
- strokeWidth: "2",
7948
- strokeLinecap: "round",
7949
- strokeLinejoin: "round",
7950
- "aria-hidden": "true",
7951
- 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" })
8137
+ return /* @__PURE__ */ jsxRuntime.jsx(
8138
+ reactNative.View,
8139
+ {
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
7952
8149
  }
7953
- );
7954
- }
7955
- const resolvedColor = color === "currentColor" ? colors.semantic.text.muted : color;
8150
+ }
8151
+ );
8152
+ }, "MenuSeparator");
8153
+ MenuSeparator.displayName = "MenuSeparator";
8154
+ var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
8155
+ const colors = useThemeColors();
7956
8156
  return /* @__PURE__ */ jsxRuntime.jsx(
7957
- reactNative.Text,
8157
+ reactNative.View,
7958
8158
  {
7959
- accessibilityElementsHidden: true,
7960
- importantForAccessibility: "no-hide-descendants",
7961
- style: { fontSize: size, lineHeight: size, color: resolvedColor },
7962
- children: "\u{1F4C5}"
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
+ )
7963
8176
  }
7964
8177
  );
7965
- }
7966
- __name(CalendarIcon, "CalendarIcon");
7967
- function buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek) {
7968
- const out = {};
7969
- if (minValue !== void 0) {
7970
- out.minValue = minValue;
7971
- }
7972
- if (maxValue !== void 0) {
7973
- out.maxValue = maxValue;
7974
- }
7975
- if (isDateUnavailable !== void 0) {
7976
- out.isDateUnavailable = isDateUnavailable;
7977
- }
7978
- if (firstDayOfWeek !== void 0) {
7979
- out.firstDayOfWeek = firstDayOfWeek;
7980
- }
7981
- return out;
7982
- }
7983
- __name(buildCalendarOptional, "buildCalendarOptional");
7984
- function buildTriggerAriaProps(ariaProps) {
7985
- const out = {};
7986
- if (ariaProps["aria-labelledby"] !== void 0) {
7987
- out["aria-labelledby"] = ariaProps["aria-labelledby"];
7988
- }
7989
- if (ariaProps["aria-describedby"] !== void 0) {
7990
- out["aria-describedby"] = ariaProps["aria-describedby"];
7991
- }
7992
- if (ariaProps["aria-invalid"] !== void 0) {
7993
- out["aria-invalid"] = ariaProps["aria-invalid"];
7994
- }
7995
- if (ariaProps["aria-required"] !== void 0) {
7996
- out["aria-required"] = ariaProps["aria-required"];
7997
- }
7998
- return out;
7999
- }
8000
- __name(buildTriggerAriaProps, "buildTriggerAriaProps");
8001
- var DatePickerRoot = /* @__PURE__ */ __name(({
8002
- value,
8003
- defaultValue: defaultValue2,
8004
- onChange,
8005
- locale: localeProp,
8006
- minValue,
8007
- maxValue,
8008
- isDateUnavailable,
8009
- firstDayOfWeek,
8010
- placeholder,
8011
- disabled = false,
8012
- id,
8013
- name: _name,
8014
- className,
8015
- testID,
8016
- ...ariaProps
8017
- }) => {
8018
- const providerLocale = useLocale();
8019
- const locale = localeProp ?? providerLocale;
8020
- const [open, setOpen] = React.useState(false);
8021
- const isControlled = value !== void 0;
8022
- const [inner, setInner] = React.useState(defaultValue2 ?? null);
8023
- const current = isControlled ? value ?? null : inner;
8024
- const handleChange = React.useCallback(
8025
- (date) => {
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(
8185
+ (next) => {
8026
8186
  if (!isControlled) {
8027
- setInner(date);
8187
+ setInner(next);
8028
8188
  }
8029
- onChange?.(date);
8030
- setOpen(false);
8189
+ onOpenChange?.(next);
8031
8190
  },
8032
- [isControlled, onChange]
8191
+ [isControlled, onOpenChange]
8033
8192
  );
8034
- const handleOpenChange = React.useCallback(
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,
8213
+ {
8214
+ ref: (node) => {
8215
+ popover.triggerRef.current = node;
8216
+ },
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
8227
+ }
8228
+ );
8229
+ }
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
8255
+ });
8256
+ var ContextMenuCtx = React.createContext(null);
8257
+ var useContextMenuCtx = /* @__PURE__ */ __name(() => {
8258
+ const ctx = React.useContext(ContextMenuCtx);
8259
+ if (!ctx) {
8260
+ throw new Error("ContextMenu compound parts must be rendered inside a <ContextMenu>.");
8261
+ }
8262
+ return ctx;
8263
+ }, "useContextMenuCtx");
8264
+ var ContextMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8265
+ const [inner, setInner] = React.useState(defaultOpen);
8266
+ const isControlled = open !== void 0;
8267
+ const current = isControlled ? open : inner;
8268
+ const setOpen = React.useCallback(
8035
8269
  (next) => {
8036
- if (!disabled) {
8037
- setOpen(next);
8270
+ if (!isControlled) {
8271
+ setInner(next);
8038
8272
  }
8273
+ onOpenChange?.(next);
8039
8274
  },
8040
- [disabled]
8275
+ [isControlled, onOpenChange]
8041
8276
  );
8042
- const displayValue = current ? formatDate(current, locale) : null;
8043
- const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8044
- const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8045
- const colors = useThemeColors();
8046
- const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
8047
- const pressableStyle = {
8048
- flexDirection: "row",
8049
- alignItems: "center",
8050
- borderWidth: 1,
8051
- borderRadius: px(colors.radius.md),
8052
- paddingHorizontal: px(colors.spacing["3"]),
8053
- paddingVertical: px(colors.spacing["2"]),
8054
- backgroundColor: colors.semantic.background.elevated,
8055
- borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
8056
- opacity: disabled ? 0.6 : 1
8057
- };
8058
- const textStyle = {
8059
- flex: 1,
8060
- fontFamily: colors.fontFamily.body,
8061
- fontSize: px(colors.fontSize.md),
8062
- color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
8063
- };
8064
- const triggerExtraProps = {
8065
- role: "combobox",
8066
- accessibilityRole: "button",
8067
- "aria-haspopup": "dialog",
8068
- "aria-expanded": open,
8069
- ...triggerAriaProps
8070
- };
8071
- if (id !== void 0) {
8072
- triggerExtraProps.id = id;
8073
- triggerExtraProps.nativeID = id;
8074
- }
8075
- if (testID !== void 0) {
8076
- triggerExtraProps.testID = testID;
8077
- }
8078
- if (hasError) {
8079
- triggerExtraProps["aria-invalid"] = true;
8080
- }
8081
- if (ariaProps["aria-required"]) {
8082
- triggerExtraProps["aria-required"] = true;
8083
- }
8084
- if (disabled) {
8085
- triggerExtraProps["aria-disabled"] = true;
8086
- }
8087
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
8088
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
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(
8089
8313
  reactNative.Pressable,
8090
8314
  {
8091
- onPress: disabled ? void 0 : () => setOpen(!open),
8092
- disabled,
8093
- className: cn(
8094
- "flex-row items-center rounded-md border px-3 py-2",
8095
- hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
8096
- disabled ? "opacity-60" : void 0,
8097
- className
8098
- ),
8099
- style: pressableStyle,
8100
- ...triggerExtraProps,
8101
- children: [
8102
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
8103
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
8104
- ]
8105
- }
8106
- ) }),
8107
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
8108
- Calendar,
8109
- {
8110
- mode: "single",
8111
- value: current,
8112
- onChange: (date) => {
8113
- handleChange(date);
8315
+ ref: (node) => {
8316
+ popover.triggerRef.current = node;
8114
8317
  },
8115
- locale,
8116
- ...calendarOptional
8117
- }
8118
- ) })
8119
- ] });
8120
- }, "DatePickerRoot");
8121
- var DatePickerRange = /* @__PURE__ */ __name(({
8122
- value,
8123
- defaultValue: defaultValue2,
8124
- onChange,
8125
- locale: localeProp,
8126
- minValue,
8127
- maxValue,
8128
- isDateUnavailable,
8129
- firstDayOfWeek,
8130
- placeholder,
8131
- disabled = false,
8132
- id,
8133
- name: _name,
8134
- className,
8135
- testID,
8136
- ...ariaProps
8137
- }) => {
8138
- const providerLocale = useLocale();
8139
- const locale = localeProp ?? providerLocale;
8140
- const [open, setOpen] = React.useState(false);
8141
- const isControlled = value !== void 0;
8142
- const [inner, setInner] = React.useState(defaultValue2 ?? { start: null, end: null });
8143
- const current = isControlled ? value ?? { start: null, end: null } : inner;
8144
- const calendarValue = current.start !== null ? { start: current.start, end: current.end } : null;
8145
- const handleChange = React.useCallback(
8146
- (calRange) => {
8147
- const next = {
8148
- start: calRange?.start ?? null,
8149
- end: calRange?.end ?? null
8150
- };
8151
- if (!isControlled) {
8152
- setInner(next);
8153
- }
8154
- onChange?.(next);
8155
- if (next.start !== null && next.end !== null) {
8156
- setOpen(false);
8157
- }
8158
- },
8159
- [isControlled, onChange]
8160
- );
8161
- const handleOpenChange = React.useCallback(
8162
- (next) => {
8163
- if (!disabled) {
8164
- setOpen(next);
8165
- }
8166
- },
8167
- [disabled]
8168
- );
8169
- let displayValue = null;
8170
- if (current.start !== null) {
8171
- const startStr = formatDate(current.start, locale);
8172
- const endStr = current.end !== null ? formatDate(current.end, locale) : "";
8173
- displayValue = `${startStr} \u2013 ${endStr}`;
8174
- }
8175
- const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8176
- const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8177
- const colors = useThemeColors();
8178
- const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
8179
- const pressableStyle = {
8180
- flexDirection: "row",
8181
- alignItems: "center",
8182
- borderWidth: 1,
8183
- borderRadius: px(colors.radius.md),
8184
- paddingHorizontal: px(colors.spacing["3"]),
8185
- paddingVertical: px(colors.spacing["2"]),
8186
- backgroundColor: colors.semantic.background.elevated,
8187
- borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
8188
- opacity: disabled ? 0.6 : 1
8189
- };
8190
- const textStyle = {
8191
- flex: 1,
8192
- fontFamily: colors.fontFamily.body,
8193
- fontSize: px(colors.fontSize.md),
8194
- color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
8195
- };
8196
- const triggerExtraProps = {
8197
- role: "combobox",
8198
- accessibilityRole: "button",
8199
- "aria-haspopup": "dialog",
8200
- "aria-expanded": open,
8201
- ...triggerAriaProps
8202
- };
8203
- if (id !== void 0) {
8204
- triggerExtraProps.id = id;
8205
- triggerExtraProps.nativeID = id;
8206
- }
8207
- if (testID !== void 0) {
8208
- triggerExtraProps.testID = testID;
8209
- }
8210
- if (hasError) {
8211
- triggerExtraProps["aria-invalid"] = true;
8212
- }
8213
- if (ariaProps["aria-required"]) {
8214
- triggerExtraProps["aria-required"] = true;
8215
- }
8216
- if (disabled) {
8217
- triggerExtraProps["aria-disabled"] = true;
8218
- }
8219
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
8220
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
8221
- reactNative.Pressable,
8222
- {
8223
- onPress: disabled ? void 0 : () => setOpen(!open),
8224
- disabled,
8225
- className: cn(
8226
- "flex-row items-center rounded-md border px-3 py-2",
8227
- hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
8228
- disabled ? "opacity-60" : void 0,
8229
- className
8230
- ),
8231
- style: pressableStyle,
8232
- ...triggerExtraProps,
8233
- children: [
8234
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
8235
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
8236
- ]
8237
- }
8238
- ) }),
8239
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date range picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
8240
- Calendar,
8241
- {
8242
- mode: "range",
8243
- value: calendarValue,
8244
- onChange: (range2) => {
8245
- handleChange(range2);
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
8246
8326
  },
8247
- locale,
8248
- ...calendarOptional
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
8249
8330
  }
8250
- ) })
8251
- ] });
8252
- }, "DatePickerRange");
8253
- var DatePicker = Object.assign(DatePickerRoot, {
8254
- Range: DatePickerRange
8255
- });
8256
- var DialogContext = React.createContext(null);
8257
- var useDialogContext = /* @__PURE__ */ __name((label) => {
8258
- const ctx = React.useContext(DialogContext);
8259
- if (!ctx) {
8260
- throw new Error(`<${label}> must be rendered inside a <Dialog>.`);
8331
+ );
8261
8332
  }
8262
- return ctx;
8263
- }, "useDialogContext");
8264
- var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8265
- const [inner, setInner] = React.useState(defaultOpen);
8266
- const isControlled = open !== void 0;
8267
- const current = isControlled ? open : inner;
8268
- const setOpen = React.useCallback(
8269
- (next) => {
8270
- if (!isControlled) {
8271
- setInner(next);
8272
- }
8273
- onOpenChange?.(next);
8274
- },
8275
- [isControlled, onOpenChange]
8276
- );
8277
- const baseId = React.useId();
8278
- const triggerRef = React.useRef(null);
8279
- const ctxValue = {
8280
- open: current,
8281
- setOpen,
8282
- titleId: `${baseId}-title`,
8283
- descriptionId: `${baseId}-description`,
8284
- triggerRef
8285
- };
8286
- return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: ctxValue, children });
8287
- }, "DialogRoot");
8288
- var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
8289
- const ctx = useDialogContext("DialogTrigger");
8290
- const onPress = React.useCallback(() => ctx.setOpen(true), [ctx]);
8291
- if (asChild && React.isValidElement(children)) {
8333
+ if (React.isValidElement(children)) {
8292
8334
  const child = children;
8293
- const fire = /* @__PURE__ */ __name((existing) => (event) => {
8294
- existing?.(event);
8295
- ctx.setOpen(true);
8296
- }, "fire");
8335
+ const existing = child.props.onLongPress;
8297
8336
  return /* @__PURE__ */ jsxRuntime.jsx(
8298
8337
  Slot,
8299
8338
  {
8300
8339
  ref: (node) => {
8301
- ctx.triggerRef.current = node;
8340
+ popover.triggerRef.current = node;
8302
8341
  },
8303
- onClick: fire(child.props.onClick),
8304
- onPress: fire(child.props.onPress),
8305
- ...testID !== void 0 ? { "data-testid": testID } : {},
8342
+ onLongPress: (e) => {
8343
+ existing?.(e);
8344
+ openMenu();
8345
+ },
8346
+ accessibilityRole: "button",
8347
+ ...testID !== void 0 ? { testID } : {},
8306
8348
  ...className !== void 0 ? { className } : {},
8307
8349
  children: child
8308
8350
  }
@@ -8312,358 +8354,798 @@ var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, classNam
8312
8354
  reactNative.Pressable,
8313
8355
  {
8314
8356
  ref: (node) => {
8315
- ctx.triggerRef.current = node;
8357
+ popover.triggerRef.current = node;
8316
8358
  },
8317
- onPress,
8359
+ onLongPress: openMenu,
8318
8360
  ...testID !== void 0 ? { testID } : {},
8319
8361
  ...className !== void 0 ? { className } : {},
8320
- children: wrapStringChildren4(children)
8362
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8321
8363
  }
8322
8364
  );
8323
- }, "DialogTrigger");
8324
- function wrapStringChildren4(children) {
8325
- if (typeof children === "string" || typeof children === "number") {
8326
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
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 [];
8327
8381
  }
8328
- return children;
8329
- }
8330
- __name(wrapStringChildren4, "wrapStringChildren");
8331
- var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.24)";
8332
- var BLUR_AMOUNT2 = 4;
8333
- var OVERLAY_LAYOUT_BASE2 = {
8334
- position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
8335
- top: 0,
8336
- left: 0,
8337
- right: 0,
8338
- bottom: 0,
8339
- alignItems: "center",
8340
- justifyContent: "center",
8341
- // On native the BlurBackdrop sibling renders BEHIND this overlay and
8342
- // already provides dim + frosted-glass via expo-blur's `tint`/`intensity`.
8343
- // Painting SCRIM_COLOR on top would mask the blur entirely (the user
8344
- // sees only a flat tint), so the overlay stays transparent and the
8345
- // BlurView is the dominant visual on native.
8346
- ...reactNative.Platform.OS === "web" ? { zIndex: 50 } : { backgroundColor: "transparent" }
8347
- };
8348
- var CONTENT_LAYOUT_BASE3 = {
8349
- width: "100%",
8350
- maxWidth: 480,
8351
- // component-density literal not from theme
8352
- ...reactNative.Platform.OS === "web" ? {
8353
- boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
8354
- } : { elevation: 24 }
8355
- };
8356
- var FOCUSABLE_SELECTOR2 = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
8357
- var DialogContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
8358
- const ctx = useDialogContext("DialogContent");
8359
- const colors = useThemeColors();
8360
- const scheme = useColorScheme();
8361
- const contentRef = React.useRef(null);
8362
- const overlayStyle = {
8363
- ...OVERLAY_LAYOUT_BASE2,
8364
- padding: px(colors.spacing["4"])
8365
- };
8366
- const contentStyle = {
8367
- ...CONTENT_LAYOUT_BASE3,
8368
- borderRadius: px(colors.radius.xl),
8369
- padding: px(colors.spacing["6"]),
8370
- gap: px(colors.spacing["3"])
8371
- };
8372
- const [entered, setEntered] = React.useState(false);
8373
- React.useEffect(() => {
8374
- if (reactNative.Platform.OS !== "web") {
8375
- setEntered(true);
8376
- return;
8377
- }
8378
- if (!ctx.open) {
8379
- setEntered(false);
8380
- return;
8381
- }
8382
- const id = requestAnimationFrame(() => setEntered(true));
8383
- return () => cancelAnimationFrame(id);
8384
- }, [ctx.open]);
8385
- const enterStyle = reactNative.Platform.OS === "web" ? {
8386
- opacity: entered ? 1 : 0,
8387
- transform: [{ scale: entered ? 1 : 0.96 }],
8388
- transitionProperty: "opacity, transform",
8389
- transitionDuration: "150ms",
8390
- transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)"
8391
- } : {};
8392
- const overlayDomRef = React.useRef(null);
8393
- React.useEffect(() => {
8394
- if (reactNative.Platform.OS !== "web") {
8395
- return;
8396
- }
8397
- const node = overlayDomRef.current;
8398
- if (!node) {
8399
- return;
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 });
8400
8426
  }
8401
- node.style.transitionProperty = "background-color, backdrop-filter, -webkit-backdrop-filter";
8402
- node.style.transitionDuration = "150ms, 200ms, 200ms";
8403
- node.style.transitionTimingFunction = "ease-out";
8404
- if (entered) {
8405
- node.style.backgroundColor = SCRIM_COLOR2;
8406
- node.style.backdropFilter = `blur(${BLUR_AMOUNT2}px)`;
8407
- node.style.setProperty("-webkit-backdrop-filter", `blur(${BLUR_AMOUNT2}px)`);
8408
- } else {
8409
- node.style.backgroundColor = "rgba(0, 0, 0, 0)";
8410
- node.style.backdropFilter = "blur(0px)";
8411
- node.style.setProperty("-webkit-backdrop-filter", "blur(0px)");
8427
+ if (showPrevNext) {
8428
+ items.push({ type: "prev", disabled: currentPage <= 1 });
8412
8429
  }
8413
- }, [entered]);
8414
- React.useEffect(() => {
8415
- if (!ctx.open) {
8416
- 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);
8417
8445
  }
8418
- if (reactNative.Platform.OS !== "web") {
8419
- return;
8446
+ for (const p of range(siblingsStart, siblingsEnd)) {
8447
+ middle.push(p);
8420
8448
  }
8421
- if (typeof document === "undefined") {
8422
- return;
8449
+ if (siblingsEnd < safePageCount - safeBoundary - 1) {
8450
+ middle.push("ellipsis");
8451
+ } else if (safePageCount - safeBoundary > safeBoundary) {
8452
+ middle.push(safePageCount - safeBoundary);
8423
8453
  }
8424
- const previouslyFocused = document.activeElement;
8425
- const prevBodyOverflow = document.body.style.overflow;
8426
- document.body.style.overflow = "hidden";
8427
- const focusFirst = /* @__PURE__ */ __name(() => {
8428
- const node = contentRef.current;
8429
- if (!node) {
8454
+ const seen = /* @__PURE__ */ new Set();
8455
+ const pushPage = /* @__PURE__ */ __name((n) => {
8456
+ if (n < 1 || n > safePageCount || seen.has(n)) {
8430
8457
  return;
8431
8458
  }
8432
- const focusable = node.querySelectorAll(FOCUSABLE_SELECTOR2);
8433
- const first = focusable[0];
8434
- if (first) {
8435
- 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" });
8436
8468
  } else {
8437
- node.setAttribute("tabindex", "-1");
8438
- node.focus();
8439
- }
8440
- }, "focusFirst");
8441
- focusFirst();
8442
- const onKeyDown = /* @__PURE__ */ __name((event) => {
8443
- if (event.key === "Escape") {
8444
- event.preventDefault();
8445
- ctx.setOpen(false);
8446
- return;
8447
- }
8448
- if (event.key !== "Tab") {
8449
- return;
8450
- }
8451
- const node = contentRef.current;
8452
- if (!node) {
8453
- return;
8454
- }
8455
- const focusable = Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR2)).filter(
8456
- (el) => el.offsetParent !== null || el === document.activeElement
8457
- );
8458
- if (focusable.length === 0) {
8459
- event.preventDefault();
8460
- return;
8461
- }
8462
- const first = focusable[0];
8463
- const last = focusable[focusable.length - 1];
8464
- if (!first || !last) {
8465
- return;
8469
+ pushPage(m);
8466
8470
  }
8467
- if (event.shiftKey) {
8468
- if (document.activeElement === first || !node.contains(document.activeElement)) {
8469
- event.preventDefault();
8470
- last.focus();
8471
- }
8472
- } else if (document.activeElement === last) {
8473
- event.preventDefault();
8474
- first.focus();
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" };
8475
8686
  }
8476
- }, "onKeyDown");
8477
- document.addEventListener("keydown", onKeyDown);
8478
- return () => {
8479
- document.removeEventListener("keydown", onKeyDown);
8480
- document.body.style.overflow = prevBodyOverflow;
8481
- const restoreTo = ctx.triggerRef.current ?? previouslyFocused;
8482
- restoreTo?.focus?.();
8483
- };
8484
- }, [ctx.open, ctx.setOpen, ctx.triggerRef]);
8485
- const onOverlayPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
8687
+ if (prev.direction === "asc") {
8688
+ return { id: colId, direction: "desc" };
8689
+ }
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
8761
+ }
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
+ }) {
8486
8777
  return /* @__PURE__ */ jsxRuntime.jsxs(
8487
- reactNative.Modal,
8778
+ reactNative.View,
8488
8779
  {
8489
- visible: ctx.open,
8490
- transparent: true,
8491
- animationType: reactNative.Platform.OS === "web" ? "none" : "fade",
8492
- onRequestClose: () => ctx.setOpen(false),
8780
+ style: {
8781
+ flexDirection: "row",
8782
+ justifyContent: "flex-end",
8783
+ alignItems: "center",
8784
+ paddingVertical: 8,
8785
+ gap: 8
8786
+ },
8493
8787
  children: [
8494
- /* @__PURE__ */ jsxRuntime.jsx(BlurBackdrop, { intensity: 60, tint: scheme === "dark" ? "dark" : "light", style: reactNative.StyleSheet.absoluteFill }),
8495
8788
  /* @__PURE__ */ jsxRuntime.jsx(
8496
8789
  reactNative.Pressable,
8497
8790
  {
8498
- accessibilityRole: "none",
8499
- "aria-hidden": true,
8500
- ref: (node) => {
8501
- overlayDomRef.current = node;
8502
- },
8503
- style: overlayStyle,
8504
- onPress: onOverlayPress,
8505
- children: /* @__PURE__ */ jsxRuntime.jsx(
8506
- reactNative.Pressable,
8507
- {
8508
- onPress: (event) => event.stopPropagation?.(),
8509
- ref: (node) => {
8510
- contentRef.current = node;
8511
- },
8512
- role: "dialog",
8513
- accessibilityRole: "none",
8514
- "aria-modal": true,
8515
- "aria-labelledby": ctx.titleId,
8516
- "aria-describedby": ctx.descriptionId,
8517
- ...testID !== void 0 ? { testID } : {},
8518
- className: cn("w-full max-w-md rounded-xl bg-semantic-background-elevated p-6 gap-3", className),
8519
- style: [contentStyle, { backgroundColor: colors.semantic.background.elevated }, enterStyle],
8520
- children: /* @__PURE__ */ jsxRuntime.jsx(
8521
- reactNative.View,
8522
- {
8523
- className: "flex-col gap-1.5",
8524
- style: { flexDirection: "column", gap: px(colors.spacing["2"]) - 2 },
8525
- children
8526
- }
8527
- )
8528
- }
8529
- )
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" })
8798
+ }
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" })
8530
8815
  }
8531
8816
  )
8532
8817
  ]
8533
8818
  }
8534
8819
  );
8535
- }, "DialogContent");
8536
- var DialogTitle = /* @__PURE__ */ __name(({ children, className }) => {
8537
- const ctx = useDialogContext("DialogTitle");
8538
- const colors = useThemeColors();
8539
- return /* @__PURE__ */ jsxRuntime.jsx(
8540
- reactNative.Text,
8541
- {
8542
- nativeID: ctx.titleId,
8543
- id: ctx.titleId,
8544
- role: "heading",
8545
- "aria-level": 2,
8546
- className: cn("text-lg font-semibold text-semantic-text-default", className),
8547
- style: {
8548
- color: colors.semantic.text.default,
8549
- fontFamily: colors.fontFamily.display,
8550
- fontSize: px(colors.fontSize.lg),
8551
- fontWeight: colors.fontWeight.semibold
8552
- },
8553
- children
8554
- }
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" }) {
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;
8850
+ return /* @__PURE__ */ jsxRuntime.jsx(
8851
+ reactNative.Text,
8852
+ {
8853
+ accessibilityElementsHidden: true,
8854
+ importantForAccessibility: "no-hide-descendants",
8855
+ style: { fontSize: size, lineHeight: size, color: resolvedColor },
8856
+ children: "\u{1F4C5}"
8857
+ }
8858
+ );
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,
8908
+ className,
8909
+ testID,
8910
+ ...ariaProps
8911
+ }) => {
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]
8555
8935
  );
8556
- }, "DialogTitle");
8557
- var DialogDescription = /* @__PURE__ */ __name(({ children, className }) => {
8558
- const ctx = useDialogContext("DialogDescription");
8936
+ const displayValue = current ? formatDate(current, locale) : null;
8937
+ const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8938
+ const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8559
8939
  const colors = useThemeColors();
8560
- return /* @__PURE__ */ jsxRuntime.jsx(
8561
- reactNative.Text,
8562
- {
8563
- nativeID: ctx.descriptionId,
8564
- id: ctx.descriptionId,
8565
- className: cn("text-sm text-semantic-text-muted", className),
8566
- style: {
8567
- color: colors.semantic.text.muted,
8568
- fontFamily: colors.fontFamily.body,
8569
- fontSize: px(colors.fontSize.sm),
8570
- lineHeight: px(colors.fontSize.sm) * Number(colors.lineHeight.normal)
8571
- },
8572
- children
8573
- }
8574
- );
8575
- }, "DialogDescription");
8576
- var DialogClose = /* @__PURE__ */ __name(({
8577
- asChild = true,
8578
- children,
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,
8984
+ {
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,
8579
9028
  className,
8580
9029
  testID,
8581
- accessibilityLabel = "Close"
9030
+ ...ariaProps
8582
9031
  }) => {
8583
- const ctx = useDialogContext("DialogClose");
8584
- const colors = useThemeColors();
8585
- const onPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
8586
- if (asChild && React.isValidElement(children)) {
8587
- const child = children;
8588
- const fire = /* @__PURE__ */ __name((existing) => (event) => {
8589
- existing?.(event);
8590
- ctx.setOpen(false);
8591
- }, "fire");
8592
- return /* @__PURE__ */ jsxRuntime.jsx(
8593
- Slot,
8594
- {
8595
- onClick: fire(child.props.onClick),
8596
- onPress: fire(child.props.onPress),
8597
- ...testID !== void 0 ? { "data-testid": testID } : {},
8598
- ...className !== void 0 ? { className } : {},
8599
- children: child
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);
8600
9047
  }
8601
- );
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}`;
9068
+ }
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;
8602
9106
  }
8603
- if (children !== void 0) {
8604
- return /* @__PURE__ */ jsxRuntime.jsx(
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(
8605
9115
  reactNative.Pressable,
8606
9116
  {
8607
- onPress,
8608
- role: "button",
8609
- accessibilityRole: "button",
8610
- accessibilityLabel,
8611
- "aria-label": accessibilityLabel,
8612
- ...testID !== void 0 ? { testID } : {},
8613
- ...className !== void 0 ? { className } : {},
8614
- 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
+ ]
8615
9131
  }
8616
- );
8617
- }
8618
- return /* @__PURE__ */ jsxRuntime.jsx(
8619
- reactNative.Pressable,
8620
- {
8621
- onPress,
8622
- role: "button",
8623
- accessibilityRole: "button",
8624
- accessibilityLabel,
8625
- "aria-label": accessibilityLabel,
8626
- ...testID !== void 0 ? { testID } : {},
8627
- className: cn("absolute right-3 top-3 w-8 h-8 items-center justify-center rounded-md", className),
8628
- style: {
8629
- position: "absolute",
8630
- right: px(colors.spacing["3"]),
8631
- top: px(colors.spacing["3"]),
8632
- // 32×32 close hit target — component-density literal — not from theme
8633
- width: 32,
8634
- height: 32,
8635
- alignItems: "center",
8636
- justifyContent: "center",
8637
- borderRadius: px(colors.radius.md)
8638
- },
8639
- children: /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.close, { size: 18, color: colors.semantic.text.muted })
8640
- }
8641
- );
8642
- }, "DialogClose");
8643
- var DialogFooter = /* @__PURE__ */ __name(({ children, className }) => {
8644
- const colors = useThemeColors();
8645
- return /* @__PURE__ */ jsxRuntime.jsx(
8646
- reactNative.View,
8647
- {
8648
- className: cn("mt-4 flex-row items-center justify-end gap-2", className),
8649
- style: {
8650
- marginTop: px(colors.spacing["4"]),
8651
- flexDirection: "row",
8652
- alignItems: "center",
8653
- justifyContent: "flex-end",
8654
- gap: px(colors.spacing["2"])
8655
- },
8656
- children
8657
- }
8658
- );
8659
- }, "DialogFooter");
8660
- var Dialog = Object.assign(DialogRoot, {
8661
- Trigger: DialogTrigger,
8662
- Content: DialogContent,
8663
- Title: DialogTitle,
8664
- Description: DialogDescription,
8665
- Footer: DialogFooter,
8666
- 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
8667
9149
  });
8668
9150
  var Empty = /* @__PURE__ */ __name(({ icon, title, description, action, className, testID }) => {
8669
9151
  const colors = useThemeColors();
@@ -12495,6 +12977,344 @@ function translateOffscreen(side) {
12495
12977
  }
12496
12978
  }
12497
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
+ });
12498
13318
  var PULSE_DURATION_MS = 900;
12499
13319
  var PULSE_MIN = 0.55;
12500
13320
  var PULSE_MAX = 1;
@@ -14728,6 +15548,7 @@ exports.Carousel = Carousel;
14728
15548
  exports.Checkbox = Checkbox;
14729
15549
  exports.Collapsible = Collapsible;
14730
15550
  exports.Combobox = Combobox;
15551
+ exports.Command = Command;
14731
15552
  exports.ContextMenu = ContextMenu;
14732
15553
  exports.DataTable = DataTable;
14733
15554
  exports.DatePicker = DatePicker;
@@ -14766,6 +15587,7 @@ exports.SheetHeader = SheetHeader;
14766
15587
  exports.SheetPanel = SheetPanel;
14767
15588
  exports.SheetTitle = SheetTitle;
14768
15589
  exports.SheetTrigger = SheetTrigger;
15590
+ exports.Sidebar = Sidebar;
14769
15591
  exports.Skeleton = Skeleton;
14770
15592
  exports.Slider = Slider;
14771
15593
  exports.SliderGestureProvider = SliderGestureProvider;
@@ -14791,8 +15613,10 @@ exports.theme = theme;
14791
15613
  exports.themeDark = themeDark;
14792
15614
  exports.toast = toast2;
14793
15615
  exports.useCalendarCaption = useCalendarCaption;
15616
+ exports.useCommandContext = useCommandContext;
14794
15617
  exports.usePagination = usePagination;
14795
15618
  exports.usePopoverContext = usePopoverContext;
15619
+ exports.useSidebarContext = useSidebarContext;
14796
15620
  exports.useSliderInteractionActive = useSliderInteractionActive;
14797
15621
  //# sourceMappingURL=index.cjs.map
14798
15622
  //# sourceMappingURL=index.cjs.map