@nori-ui/core 1.8.0 → 1.9.1

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/client.cjs CHANGED
@@ -7091,220 +7091,15 @@ var Collapsible = Object.assign(CollapsibleRoot, {
7091
7091
  var Combobox = /* @__PURE__ */ __name((props) => {
7092
7092
  return /* @__PURE__ */ jsxRuntime.jsx(Select, { searchable: true, ...props });
7093
7093
  }, "Combobox");
7094
- var MenuContext = React.createContext(null);
7095
- var MenuContextProvider = /* @__PURE__ */ __name(({
7096
- open,
7097
- toggle,
7098
- close,
7099
- children
7100
- }) => /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, toggle: toggle ?? close, close }, children }), "MenuContextProvider");
7101
- function useMenuContext(caller) {
7102
- const ctx = React.useContext(MenuContext);
7094
+ var DialogContext = React.createContext(null);
7095
+ var useDialogContext = /* @__PURE__ */ __name((label) => {
7096
+ const ctx = React.useContext(DialogContext);
7103
7097
  if (!ctx) {
7104
- throw new Error(`<${caller}> must be rendered inside a <DropdownMenu> or <ContextMenu>.`);
7098
+ throw new Error(`<${label}> must be rendered inside a <Dialog>.`);
7105
7099
  }
7106
7100
  return ctx;
7107
- }
7108
- __name(useMenuContext, "useMenuContext");
7109
- var MenuContent = /* @__PURE__ */ __name(({
7110
- children,
7111
- className,
7112
- testID,
7113
- side = "bottom",
7114
- align = "start",
7115
- "aria-label": ariaLabel
7116
- }) => {
7117
- const colors = useThemeColors();
7118
- const containerRef = React.useRef(null);
7119
- React.useEffect(() => {
7120
- if (reactNative.Platform.OS !== "web") {
7121
- return;
7122
- }
7123
- if (typeof document === "undefined") {
7124
- return;
7125
- }
7126
- const container = containerRef.current;
7127
- if (!container) {
7128
- return;
7129
- }
7130
- const getItems = /* @__PURE__ */ __name(() => Array.from(container.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')), "getItems");
7131
- const onKeyDown = /* @__PURE__ */ __name((e) => {
7132
- const items = getItems();
7133
- if (items.length === 0) {
7134
- return;
7135
- }
7136
- const focused = document.activeElement;
7137
- const idx = focused ? items.indexOf(focused) : -1;
7138
- switch (e.key) {
7139
- case "ArrowDown":
7140
- e.preventDefault();
7141
- items[idx < items.length - 1 ? idx + 1 : 0]?.focus();
7142
- break;
7143
- case "ArrowUp":
7144
- e.preventDefault();
7145
- items[idx > 0 ? idx - 1 : items.length - 1]?.focus();
7146
- break;
7147
- case "Home":
7148
- e.preventDefault();
7149
- items[0]?.focus();
7150
- break;
7151
- case "End":
7152
- e.preventDefault();
7153
- items[items.length - 1]?.focus();
7154
- break;
7155
- }
7156
- }, "onKeyDown");
7157
- container.addEventListener("keydown", onKeyDown);
7158
- return () => container.removeEventListener("keydown", onKeyDown);
7159
- });
7160
- return /* @__PURE__ */ jsxRuntime.jsx(
7161
- Popover.Content,
7162
- {
7163
- side,
7164
- align,
7165
- ...testID !== void 0 ? { testID } : {},
7166
- ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
7167
- ...className !== void 0 ? { className } : {},
7168
- children: /* @__PURE__ */ jsxRuntime.jsx(
7169
- reactNative.View,
7170
- {
7171
- ref: containerRef,
7172
- ...{
7173
- role: "menu",
7174
- ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {}
7175
- },
7176
- style: {
7177
- minWidth: 160,
7178
- paddingVertical: px(colors.spacing["1"]),
7179
- margin: -px(colors.spacing["4"]),
7180
- borderRadius: px(colors.radius.lg),
7181
- overflow: "hidden"
7182
- },
7183
- children
7184
- }
7185
- )
7186
- }
7187
- );
7188
- }, "MenuContent");
7189
- MenuContent.displayName = "MenuContent";
7190
- var MenuItem = /* @__PURE__ */ __name(({
7191
- onSelect,
7192
- disabled = false,
7193
- destructive = false,
7194
- icon,
7195
- shortcut,
7196
- children,
7197
- className,
7198
- testID
7199
- }) => {
7200
- const colors = useThemeColors();
7201
- const menu = useMenuContext("MenuItem");
7202
- const handlePress = React.useCallback(() => {
7203
- if (disabled) {
7204
- return;
7205
- }
7206
- onSelect?.();
7207
- menu.close();
7208
- }, [disabled, onSelect, menu]);
7209
- const textColor = destructive ? colors.color.danger : disabled ? colors.semantic.text.muted : colors.semantic.text.default;
7210
- return /* @__PURE__ */ jsxRuntime.jsxs(
7211
- reactNative.Pressable,
7212
- {
7213
- onPress: handlePress,
7214
- disabled,
7215
- ...{
7216
- role: "menuitem",
7217
- "aria-disabled": disabled ? "true" : void 0,
7218
- tabIndex: disabled ? -1 : 0,
7219
- onKeyDown: /* @__PURE__ */ __name((e) => {
7220
- if (e.key === "Enter" || e.key === " ") {
7221
- e.preventDefault();
7222
- handlePress();
7223
- }
7224
- }, "onKeyDown")
7225
- },
7226
- ...testID !== void 0 ? { testID } : {},
7227
- className: cn("flex-row items-center gap-2 px-3 py-2", className),
7228
- style: { opacity: disabled ? 0.4 : 1 },
7229
- accessibilityRole: "menuitem",
7230
- accessibilityState: { disabled },
7231
- children: [
7232
- icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
7233
- /* @__PURE__ */ jsxRuntime.jsx(
7234
- reactNative.Text,
7235
- {
7236
- style: {
7237
- flex: 1,
7238
- fontFamily: colors.fontFamily.body,
7239
- fontSize: px(colors.fontSize.sm),
7240
- color: textColor
7241
- },
7242
- children
7243
- }
7244
- ),
7245
- shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
7246
- reactNative.Text,
7247
- {
7248
- ...{ "aria-hidden": "true" },
7249
- style: {
7250
- fontFamily: colors.fontFamily.body,
7251
- fontSize: px(colors.fontSize.xs),
7252
- color: colors.semantic.text.muted
7253
- },
7254
- children: shortcut
7255
- }
7256
- )
7257
- ]
7258
- }
7259
- );
7260
- }, "MenuItem");
7261
- MenuItem.displayName = "MenuItem";
7262
- var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
7263
- const colors = useThemeColors();
7264
- return /* @__PURE__ */ jsxRuntime.jsx(
7265
- reactNative.View,
7266
- {
7267
- ...{ role: "separator" },
7268
- accessibilityRole: "none",
7269
- ...testID !== void 0 ? { testID } : {},
7270
- className: cn("mx-1 my-1", className),
7271
- style: {
7272
- height: 1,
7273
- marginVertical: 4,
7274
- marginHorizontal: 4,
7275
- backgroundColor: colors.semantic.border.default
7276
- }
7277
- }
7278
- );
7279
- }, "MenuSeparator");
7280
- MenuSeparator.displayName = "MenuSeparator";
7281
- var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
7282
- const colors = useThemeColors();
7283
- return /* @__PURE__ */ jsxRuntime.jsx(
7284
- reactNative.View,
7285
- {
7286
- ...{ role: "presentation" },
7287
- ...testID !== void 0 ? { testID } : {},
7288
- className: cn("px-3 pt-2 pb-1", className),
7289
- children: /* @__PURE__ */ jsxRuntime.jsx(
7290
- reactNative.Text,
7291
- {
7292
- style: {
7293
- fontFamily: colors.fontFamily.body,
7294
- fontSize: px(colors.fontSize.xs),
7295
- color: colors.semantic.text.muted,
7296
- textTransform: "uppercase",
7297
- letterSpacing: 0.6,
7298
- fontWeight: "600"
7299
- },
7300
- children
7301
- }
7302
- )
7303
- }
7304
- );
7305
- }, "MenuLabel");
7306
- MenuLabel.displayName = "MenuLabel";
7307
- var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7101
+ }, "useDialogContext");
7102
+ var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7308
7103
  const [inner, setInner] = React.useState(defaultOpen);
7309
7104
  const isControlled = open !== void 0;
7310
7105
  const current = isControlled ? open : inner;
@@ -7317,37 +7112,34 @@ var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOp
7317
7112
  },
7318
7113
  [isControlled, onOpenChange]
7319
7114
  );
7320
- const toggle = React.useCallback(() => setOpen(!current), [setOpen, current]);
7321
- const close = React.useCallback(() => setOpen(false), [setOpen]);
7322
- return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: current, toggle, close, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
7323
- }, "DropdownMenuRoot");
7324
- var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7325
- const menu = useMenuContext("DropdownMenu.Trigger");
7326
- const popover = usePopoverContext("DropdownMenu.Trigger");
7327
- const onPress = React.useCallback(() => {
7328
- popover.measureTrigger();
7329
- popover.setOpen(!popover.open);
7330
- }, [popover]);
7331
- if (React.isValidElement(children)) {
7115
+ const baseId = React.useId();
7116
+ const triggerRef = React.useRef(null);
7117
+ const ctxValue = {
7118
+ open: current,
7119
+ setOpen,
7120
+ titleId: `${baseId}-title`,
7121
+ descriptionId: `${baseId}-description`,
7122
+ triggerRef
7123
+ };
7124
+ return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: ctxValue, children });
7125
+ }, "DialogRoot");
7126
+ var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
7127
+ const ctx = useDialogContext("DialogTrigger");
7128
+ const onPress = React.useCallback(() => ctx.setOpen(true), [ctx]);
7129
+ if (asChild && React.isValidElement(children)) {
7332
7130
  const child = children;
7333
7131
  const fire = /* @__PURE__ */ __name((existing) => (event) => {
7334
7132
  existing?.(event);
7335
- popover.measureTrigger();
7336
- popover.setOpen(!popover.open);
7133
+ ctx.setOpen(true);
7337
7134
  }, "fire");
7338
7135
  return /* @__PURE__ */ jsxRuntime.jsx(
7339
7136
  Slot,
7340
7137
  {
7341
7138
  ref: (node) => {
7342
- popover.triggerRef.current = node;
7139
+ ctx.triggerRef.current = node;
7343
7140
  },
7344
7141
  onClick: fire(child.props.onClick),
7345
7142
  onPress: fire(child.props.onPress),
7346
- ...{
7347
- "aria-haspopup": "menu",
7348
- "aria-expanded": menu.open,
7349
- "aria-controls": popover.contentId
7350
- },
7351
7143
  ...testID !== void 0 ? { "data-testid": testID } : {},
7352
7144
  ...className !== void 0 ? { className } : {},
7353
7145
  children: child
@@ -7358,972 +7150,1222 @@ var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID
7358
7150
  reactNative.Pressable,
7359
7151
  {
7360
7152
  ref: (node) => {
7361
- popover.triggerRef.current = node;
7153
+ ctx.triggerRef.current = node;
7362
7154
  },
7363
7155
  onPress,
7364
- ...{
7365
- "aria-haspopup": "menu",
7366
- "aria-expanded": menu.open,
7367
- "aria-controls": popover.contentId
7368
- },
7369
7156
  ...testID !== void 0 ? { testID } : {},
7370
7157
  ...className !== void 0 ? { className } : {},
7371
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7158
+ children: wrapStringChildren4(children)
7372
7159
  }
7373
7160
  );
7374
- }, "DropdownMenuTrigger");
7375
- var DropdownMenuContent = /* @__PURE__ */ __name((props) => /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }), "DropdownMenuContent");
7376
- var DropdownMenu = Object.assign(DropdownMenuRoot, {
7377
- Trigger: DropdownMenuTrigger,
7378
- Content: DropdownMenuContent,
7379
- Item: MenuItem,
7380
- Separator: MenuSeparator,
7381
- Label: MenuLabel
7382
- });
7383
- var ContextMenuCtx = React.createContext(null);
7384
- var useContextMenuCtx = /* @__PURE__ */ __name(() => {
7385
- const ctx = React.useContext(ContextMenuCtx);
7386
- if (!ctx) {
7387
- throw new Error("ContextMenu compound parts must be rendered inside a <ContextMenu>.");
7161
+ }, "DialogTrigger");
7162
+ function wrapStringChildren4(children) {
7163
+ if (typeof children === "string" || typeof children === "number") {
7164
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
7388
7165
  }
7389
- return ctx;
7390
- }, "useContextMenuCtx");
7391
- var ContextMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7392
- const [inner, setInner] = React.useState(defaultOpen);
7393
- const isControlled = open !== void 0;
7394
- const current = isControlled ? open : inner;
7395
- const setOpen = React.useCallback(
7396
- (next) => {
7397
- if (!isControlled) {
7398
- setInner(next);
7166
+ return children;
7167
+ }
7168
+ __name(wrapStringChildren4, "wrapStringChildren");
7169
+ var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.24)";
7170
+ var BLUR_AMOUNT2 = 4;
7171
+ var OVERLAY_LAYOUT_BASE2 = {
7172
+ position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
7173
+ top: 0,
7174
+ left: 0,
7175
+ right: 0,
7176
+ bottom: 0,
7177
+ alignItems: "center",
7178
+ justifyContent: "center",
7179
+ // On native the BlurBackdrop sibling renders BEHIND this overlay and
7180
+ // already provides dim + frosted-glass via expo-blur's `tint`/`intensity`.
7181
+ // Painting SCRIM_COLOR on top would mask the blur entirely (the user
7182
+ // sees only a flat tint), so the overlay stays transparent and the
7183
+ // BlurView is the dominant visual on native.
7184
+ ...reactNative.Platform.OS === "web" ? { zIndex: 50 } : { backgroundColor: "transparent" }
7185
+ };
7186
+ var CONTENT_LAYOUT_BASE3 = {
7187
+ width: "100%",
7188
+ maxWidth: 480,
7189
+ // component-density literal — not from theme
7190
+ ...reactNative.Platform.OS === "web" ? {
7191
+ boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
7192
+ } : { elevation: 24 }
7193
+ };
7194
+ var FOCUSABLE_SELECTOR2 = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
7195
+ var DialogContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
7196
+ const ctx = useDialogContext("DialogContent");
7197
+ const colors = useThemeColors();
7198
+ const scheme = useColorScheme();
7199
+ const contentRef = React.useRef(null);
7200
+ const overlayStyle = {
7201
+ ...OVERLAY_LAYOUT_BASE2,
7202
+ padding: px(colors.spacing["4"])
7203
+ };
7204
+ const contentStyle = {
7205
+ ...CONTENT_LAYOUT_BASE3,
7206
+ borderRadius: px(colors.radius.xl),
7207
+ padding: px(colors.spacing["6"]),
7208
+ gap: px(colors.spacing["3"])
7209
+ };
7210
+ const [entered, setEntered] = React.useState(false);
7211
+ React.useEffect(() => {
7212
+ if (reactNative.Platform.OS !== "web") {
7213
+ setEntered(true);
7214
+ return;
7215
+ }
7216
+ if (!ctx.open) {
7217
+ setEntered(false);
7218
+ return;
7219
+ }
7220
+ const id = requestAnimationFrame(() => setEntered(true));
7221
+ return () => cancelAnimationFrame(id);
7222
+ }, [ctx.open]);
7223
+ const enterStyle = reactNative.Platform.OS === "web" ? {
7224
+ opacity: entered ? 1 : 0,
7225
+ transform: [{ scale: entered ? 1 : 0.96 }],
7226
+ transitionProperty: "opacity, transform",
7227
+ transitionDuration: "150ms",
7228
+ transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)"
7229
+ } : {};
7230
+ const overlayDomRef = React.useRef(null);
7231
+ React.useEffect(() => {
7232
+ if (reactNative.Platform.OS !== "web") {
7233
+ return;
7234
+ }
7235
+ const node = overlayDomRef.current;
7236
+ if (!node) {
7237
+ return;
7238
+ }
7239
+ node.style.transitionProperty = "background-color, backdrop-filter, -webkit-backdrop-filter";
7240
+ node.style.transitionDuration = "150ms, 200ms, 200ms";
7241
+ node.style.transitionTimingFunction = "ease-out";
7242
+ if (entered) {
7243
+ node.style.backgroundColor = SCRIM_COLOR2;
7244
+ node.style.backdropFilter = `blur(${BLUR_AMOUNT2}px)`;
7245
+ node.style.setProperty("-webkit-backdrop-filter", `blur(${BLUR_AMOUNT2}px)`);
7246
+ } else {
7247
+ node.style.backgroundColor = "rgba(0, 0, 0, 0)";
7248
+ node.style.backdropFilter = "blur(0px)";
7249
+ node.style.setProperty("-webkit-backdrop-filter", "blur(0px)");
7250
+ }
7251
+ }, [entered]);
7252
+ React.useEffect(() => {
7253
+ if (!ctx.open) {
7254
+ return;
7255
+ }
7256
+ if (reactNative.Platform.OS !== "web") {
7257
+ return;
7258
+ }
7259
+ if (typeof document === "undefined") {
7260
+ return;
7261
+ }
7262
+ const previouslyFocused = document.activeElement;
7263
+ const prevBodyOverflow = document.body.style.overflow;
7264
+ document.body.style.overflow = "hidden";
7265
+ const focusFirst = /* @__PURE__ */ __name(() => {
7266
+ const node = contentRef.current;
7267
+ if (!node) {
7268
+ return;
7399
7269
  }
7400
- onOpenChange?.(next);
7401
- },
7402
- [isControlled, onOpenChange]
7403
- );
7404
- return /* @__PURE__ */ jsxRuntime.jsx(ContextMenuCtx.Provider, { value: { open: current, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
7405
- }, "ContextMenuRoot");
7406
- var ContextMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7407
- const ctx = useContextMenuCtx();
7408
- const popover = usePopoverContext("ContextMenu.Trigger");
7409
- const openMenu = React.useCallback(() => {
7410
- popover.measureTrigger();
7411
- ctx.setOpen(true);
7412
- }, [ctx, popover]);
7413
- if (reactNative.Platform.OS === "web") {
7414
- if (React.isValidElement(children)) {
7415
- const child = children;
7416
- const existing = child.props.onContextMenu;
7417
- return /* @__PURE__ */ jsxRuntime.jsx(
7418
- Slot,
7419
- {
7420
- ref: (node) => {
7421
- popover.triggerRef.current = node;
7422
- },
7423
- onContextMenu: (e) => {
7424
- e.preventDefault();
7425
- existing?.(e);
7426
- openMenu();
7427
- },
7428
- ...{
7429
- "aria-haspopup": "menu",
7430
- "aria-expanded": ctx.open,
7431
- "aria-controls": popover.contentId
7432
- },
7433
- ...testID !== void 0 ? { "data-testid": testID } : {},
7434
- ...className !== void 0 ? { className } : {},
7435
- children: child
7436
- }
7270
+ const focusable = node.querySelectorAll(FOCUSABLE_SELECTOR2);
7271
+ const first = focusable[0];
7272
+ if (first) {
7273
+ first.focus();
7274
+ } else {
7275
+ node.setAttribute("tabindex", "-1");
7276
+ node.focus();
7277
+ }
7278
+ }, "focusFirst");
7279
+ focusFirst();
7280
+ const onKeyDown = /* @__PURE__ */ __name((event) => {
7281
+ if (event.key === "Escape") {
7282
+ event.preventDefault();
7283
+ ctx.setOpen(false);
7284
+ return;
7285
+ }
7286
+ if (event.key !== "Tab") {
7287
+ return;
7288
+ }
7289
+ const node = contentRef.current;
7290
+ if (!node) {
7291
+ return;
7292
+ }
7293
+ const focusable = Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR2)).filter(
7294
+ (el) => el.offsetParent !== null || el === document.activeElement
7437
7295
  );
7438
- }
7439
- return /* @__PURE__ */ jsxRuntime.jsx(
7440
- reactNative.Pressable,
7441
- {
7442
- ref: (node) => {
7443
- popover.triggerRef.current = node;
7444
- },
7445
- ...{
7446
- onContextMenu: /* @__PURE__ */ __name((e) => {
7447
- e.preventDefault();
7448
- openMenu();
7449
- }, "onContextMenu"),
7450
- "aria-haspopup": "menu",
7451
- "aria-expanded": ctx.open,
7452
- "aria-controls": popover.contentId
7453
- },
7454
- ...testID !== void 0 ? { testID } : {},
7455
- ...className !== void 0 ? { className } : {},
7456
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7296
+ if (focusable.length === 0) {
7297
+ event.preventDefault();
7298
+ return;
7457
7299
  }
7458
- );
7459
- }
7460
- if (React.isValidElement(children)) {
7461
- const child = children;
7462
- const existing = child.props.onLongPress;
7463
- return /* @__PURE__ */ jsxRuntime.jsx(
7464
- Slot,
7465
- {
7466
- ref: (node) => {
7467
- popover.triggerRef.current = node;
7468
- },
7469
- onLongPress: (e) => {
7470
- existing?.(e);
7471
- openMenu();
7472
- },
7473
- accessibilityRole: "button",
7474
- ...testID !== void 0 ? { testID } : {},
7475
- ...className !== void 0 ? { className } : {},
7476
- children: child
7300
+ const first = focusable[0];
7301
+ const last = focusable[focusable.length - 1];
7302
+ if (!first || !last) {
7303
+ return;
7477
7304
  }
7478
- );
7479
- }
7480
- return /* @__PURE__ */ jsxRuntime.jsx(
7481
- reactNative.Pressable,
7482
- {
7483
- ref: (node) => {
7484
- popover.triggerRef.current = node;
7485
- },
7486
- onLongPress: openMenu,
7487
- ...testID !== void 0 ? { testID } : {},
7488
- ...className !== void 0 ? { className } : {},
7489
- children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
7490
- }
7491
- );
7492
- }, "ContextMenuTrigger");
7493
- var ContextMenuContent = /* @__PURE__ */ __name((props) => {
7494
- const ctx = useContextMenuCtx();
7495
- const close = React.useCallback(() => ctx.setOpen(false), [ctx]);
7496
- return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: ctx.open, close, children: /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }) });
7497
- }, "ContextMenuContent");
7498
- var ContextMenu = Object.assign(ContextMenuRoot, {
7499
- Trigger: ContextMenuTrigger,
7500
- Content: ContextMenuContent,
7501
- Item: MenuItem,
7502
- Separator: MenuSeparator,
7503
- Label: MenuLabel
7504
- });
7505
- var range = /* @__PURE__ */ __name((from, to) => {
7506
- if (to < from) {
7507
- return [];
7508
- }
7509
- const out = new Array(to - from + 1);
7510
- for (let i = 0; i < out.length; i += 1) {
7511
- out[i] = from + i;
7512
- }
7513
- return out;
7514
- }, "range");
7515
- function usePagination(args) {
7516
- const {
7517
- page: controlledPage,
7518
- defaultPage = 1,
7519
- pageCount,
7520
- siblingCount = 1,
7521
- boundaryCount = 1,
7522
- showFirstLast = false,
7523
- showPrevNext = true,
7524
- onPageChange
7525
- } = args;
7526
- const isControlled = controlledPage !== void 0;
7527
- const [uncontrolledPage, setUncontrolledPage] = React.useState(defaultPage);
7528
- const onChangeRef = React.useRef(onPageChange);
7529
- onChangeRef.current = onPageChange;
7530
- const safePageCount = Math.max(1, Math.floor(pageCount));
7531
- const rawPage = isControlled ? controlledPage : uncontrolledPage;
7532
- const currentPage = Math.min(Math.max(1, Math.floor(rawPage)), safePageCount);
7533
- const goToPage = React.useCallback(
7534
- (next2) => {
7535
- const clamped = Math.min(Math.max(1, Math.floor(next2)), Math.max(1, Math.floor(pageCount)));
7536
- if (!isControlled) {
7537
- setUncontrolledPage(clamped);
7305
+ if (event.shiftKey) {
7306
+ if (document.activeElement === first || !node.contains(document.activeElement)) {
7307
+ event.preventDefault();
7308
+ last.focus();
7309
+ }
7310
+ } else if (document.activeElement === last) {
7311
+ event.preventDefault();
7312
+ first.focus();
7538
7313
  }
7539
- onChangeRef.current?.(clamped);
7540
- },
7541
- [isControlled, pageCount]
7314
+ }, "onKeyDown");
7315
+ document.addEventListener("keydown", onKeyDown);
7316
+ return () => {
7317
+ document.removeEventListener("keydown", onKeyDown);
7318
+ document.body.style.overflow = prevBodyOverflow;
7319
+ const restoreTo = ctx.triggerRef.current ?? previouslyFocused;
7320
+ restoreTo?.focus?.();
7321
+ };
7322
+ }, [ctx.open, ctx.setOpen, ctx.triggerRef]);
7323
+ const onOverlayPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
7324
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7325
+ reactNative.Modal,
7326
+ {
7327
+ visible: ctx.open,
7328
+ transparent: true,
7329
+ animationType: reactNative.Platform.OS === "web" ? "none" : "fade",
7330
+ onRequestClose: () => ctx.setOpen(false),
7331
+ children: [
7332
+ /* @__PURE__ */ jsxRuntime.jsx(BlurBackdrop, { intensity: 60, tint: scheme === "dark" ? "dark" : "light", style: reactNative.StyleSheet.absoluteFill }),
7333
+ /* @__PURE__ */ jsxRuntime.jsx(
7334
+ reactNative.Pressable,
7335
+ {
7336
+ accessibilityRole: "none",
7337
+ "aria-hidden": true,
7338
+ ref: (node) => {
7339
+ overlayDomRef.current = node;
7340
+ },
7341
+ style: overlayStyle,
7342
+ onPress: onOverlayPress,
7343
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7344
+ reactNative.Pressable,
7345
+ {
7346
+ onPress: (event) => event.stopPropagation?.(),
7347
+ ref: (node) => {
7348
+ contentRef.current = node;
7349
+ },
7350
+ role: "dialog",
7351
+ accessibilityRole: "none",
7352
+ "aria-modal": true,
7353
+ "aria-labelledby": ctx.titleId,
7354
+ "aria-describedby": ctx.descriptionId,
7355
+ ...testID !== void 0 ? { testID } : {},
7356
+ className: cn("w-full max-w-md rounded-xl bg-semantic-background-elevated p-6 gap-3", className),
7357
+ style: [contentStyle, { backgroundColor: colors.semantic.background.elevated }, enterStyle],
7358
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7359
+ reactNative.View,
7360
+ {
7361
+ className: "flex-col gap-1.5",
7362
+ style: { flexDirection: "column", gap: px(colors.spacing["2"]) - 2 },
7363
+ children
7364
+ }
7365
+ )
7366
+ }
7367
+ )
7368
+ }
7369
+ )
7370
+ ]
7371
+ }
7542
7372
  );
7543
- const prev = React.useCallback(() => goToPage(currentPage - 1), [goToPage, currentPage]);
7544
- const next = React.useCallback(() => goToPage(currentPage + 1), [goToPage, currentPage]);
7545
- const first = React.useCallback(() => goToPage(1), [goToPage]);
7546
- const last = React.useCallback(() => goToPage(safePageCount), [goToPage, safePageCount]);
7547
- const pages = React.useMemo(() => {
7548
- const items = [];
7549
- const safeSibling = Math.max(0, Math.floor(siblingCount));
7550
- const safeBoundary = Math.max(0, Math.floor(boundaryCount));
7551
- if (showFirstLast) {
7552
- items.push({ type: "first", disabled: currentPage <= 1 });
7373
+ }, "DialogContent");
7374
+ var DialogTitle = /* @__PURE__ */ __name(({ children, className }) => {
7375
+ const ctx = useDialogContext("DialogTitle");
7376
+ const colors = useThemeColors();
7377
+ return /* @__PURE__ */ jsxRuntime.jsx(
7378
+ reactNative.Text,
7379
+ {
7380
+ nativeID: ctx.titleId,
7381
+ id: ctx.titleId,
7382
+ role: "heading",
7383
+ "aria-level": 2,
7384
+ className: cn("text-lg font-semibold text-semantic-text-default", className),
7385
+ style: {
7386
+ color: colors.semantic.text.default,
7387
+ fontFamily: colors.fontFamily.display,
7388
+ fontSize: px(colors.fontSize.lg),
7389
+ fontWeight: colors.fontWeight.semibold
7390
+ },
7391
+ children
7553
7392
  }
7554
- if (showPrevNext) {
7555
- items.push({ type: "prev", disabled: currentPage <= 1 });
7393
+ );
7394
+ }, "DialogTitle");
7395
+ var DialogDescription = /* @__PURE__ */ __name(({ children, className }) => {
7396
+ const ctx = useDialogContext("DialogDescription");
7397
+ const colors = useThemeColors();
7398
+ return /* @__PURE__ */ jsxRuntime.jsx(
7399
+ reactNative.Text,
7400
+ {
7401
+ nativeID: ctx.descriptionId,
7402
+ id: ctx.descriptionId,
7403
+ className: cn("text-sm text-semantic-text-muted", className),
7404
+ style: {
7405
+ color: colors.semantic.text.muted,
7406
+ fontFamily: colors.fontFamily.body,
7407
+ fontSize: px(colors.fontSize.sm),
7408
+ lineHeight: px(colors.fontSize.sm) * Number(colors.lineHeight.normal)
7409
+ },
7410
+ children
7556
7411
  }
7557
- const startPages = range(1, Math.min(safeBoundary, safePageCount));
7558
- const endPages = range(Math.max(safePageCount - safeBoundary + 1, safeBoundary + 1), safePageCount);
7559
- const siblingsStart = Math.max(
7560
- Math.min(currentPage - safeSibling, safePageCount - safeBoundary - safeSibling * 2 - 1),
7561
- safeBoundary + 2
7412
+ );
7413
+ }, "DialogDescription");
7414
+ var DialogClose = /* @__PURE__ */ __name(({
7415
+ asChild = true,
7416
+ children,
7417
+ className,
7418
+ testID,
7419
+ accessibilityLabel = "Close"
7420
+ }) => {
7421
+ const ctx = useDialogContext("DialogClose");
7422
+ const colors = useThemeColors();
7423
+ const onPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
7424
+ if (asChild && React.isValidElement(children)) {
7425
+ const child = children;
7426
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
7427
+ existing?.(event);
7428
+ ctx.setOpen(false);
7429
+ }, "fire");
7430
+ return /* @__PURE__ */ jsxRuntime.jsx(
7431
+ Slot,
7432
+ {
7433
+ onClick: fire(child.props.onClick),
7434
+ onPress: fire(child.props.onPress),
7435
+ ...testID !== void 0 ? { "data-testid": testID } : {},
7436
+ ...className !== void 0 ? { className } : {},
7437
+ children: child
7438
+ }
7562
7439
  );
7563
- const siblingsEnd = Math.min(
7564
- Math.max(currentPage + safeSibling, safeBoundary + safeSibling * 2 + 2),
7565
- endPages.length > 0 ? endPages[0] - 2 : safePageCount - 1
7440
+ }
7441
+ if (children !== void 0) {
7442
+ return /* @__PURE__ */ jsxRuntime.jsx(
7443
+ reactNative.Pressable,
7444
+ {
7445
+ onPress,
7446
+ role: "button",
7447
+ accessibilityRole: "button",
7448
+ accessibilityLabel,
7449
+ "aria-label": accessibilityLabel,
7450
+ ...testID !== void 0 ? { testID } : {},
7451
+ ...className !== void 0 ? { className } : {},
7452
+ children: wrapStringChildren4(children)
7453
+ }
7566
7454
  );
7567
- const middle = [];
7568
- if (siblingsStart > safeBoundary + 2) {
7569
- middle.push("ellipsis");
7570
- } else if (safeBoundary + 1 < safePageCount - safeBoundary) {
7571
- middle.push(safeBoundary + 1);
7572
- }
7573
- for (const p of range(siblingsStart, siblingsEnd)) {
7574
- middle.push(p);
7575
- }
7576
- if (siblingsEnd < safePageCount - safeBoundary - 1) {
7577
- middle.push("ellipsis");
7578
- } else if (safePageCount - safeBoundary > safeBoundary) {
7579
- middle.push(safePageCount - safeBoundary);
7455
+ }
7456
+ return /* @__PURE__ */ jsxRuntime.jsx(
7457
+ reactNative.Pressable,
7458
+ {
7459
+ onPress,
7460
+ role: "button",
7461
+ accessibilityRole: "button",
7462
+ accessibilityLabel,
7463
+ "aria-label": accessibilityLabel,
7464
+ ...testID !== void 0 ? { testID } : {},
7465
+ className: cn("absolute right-3 top-3 w-8 h-8 items-center justify-center rounded-md", className),
7466
+ style: {
7467
+ position: "absolute",
7468
+ right: px(colors.spacing["3"]),
7469
+ top: px(colors.spacing["3"]),
7470
+ // 32×32 close hit target — component-density literal — not from theme
7471
+ width: 32,
7472
+ height: 32,
7473
+ alignItems: "center",
7474
+ justifyContent: "center",
7475
+ borderRadius: px(colors.radius.md)
7476
+ },
7477
+ children: /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.close, { size: 18, color: colors.semantic.text.muted })
7580
7478
  }
7581
- const seen = /* @__PURE__ */ new Set();
7582
- const pushPage = /* @__PURE__ */ __name((n) => {
7583
- if (n < 1 || n > safePageCount || seen.has(n)) {
7584
- return;
7585
- }
7586
- seen.add(n);
7587
- items.push({ type: "page", page: n, selected: n === currentPage });
7588
- }, "pushPage");
7589
- for (const n of startPages) {
7590
- pushPage(n);
7479
+ );
7480
+ }, "DialogClose");
7481
+ var DialogFooter = /* @__PURE__ */ __name(({ children, className }) => {
7482
+ const colors = useThemeColors();
7483
+ return /* @__PURE__ */ jsxRuntime.jsx(
7484
+ reactNative.View,
7485
+ {
7486
+ className: cn("mt-4 flex-row items-center justify-end gap-2", className),
7487
+ style: {
7488
+ marginTop: px(colors.spacing["4"]),
7489
+ flexDirection: "row",
7490
+ alignItems: "center",
7491
+ justifyContent: "flex-end",
7492
+ gap: px(colors.spacing["2"])
7493
+ },
7494
+ children
7591
7495
  }
7592
- for (const m of middle) {
7593
- if (m === "ellipsis") {
7594
- items.push({ type: "ellipsis" });
7595
- } else {
7596
- pushPage(m);
7496
+ );
7497
+ }, "DialogFooter");
7498
+ var Dialog = Object.assign(DialogRoot, {
7499
+ Trigger: DialogTrigger,
7500
+ Content: DialogContent,
7501
+ Title: DialogTitle,
7502
+ Description: DialogDescription,
7503
+ Footer: DialogFooter,
7504
+ Close: DialogClose
7505
+ });
7506
+ var CommandContext = React.createContext(null);
7507
+ function useCommandContext(caller) {
7508
+ const ctx = React.useContext(CommandContext);
7509
+ if (!ctx) {
7510
+ throw new Error(`<${caller}> must be rendered inside <Command>.`);
7511
+ }
7512
+ return ctx;
7513
+ }
7514
+ __name(useCommandContext, "useCommandContext");
7515
+ var CommandRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
7516
+ const [inner, setInner] = React.useState(defaultOpen);
7517
+ const isControlled = open !== void 0;
7518
+ const current = isControlled ? open : inner;
7519
+ const [query, setQuery] = React.useState("");
7520
+ const setOpen = React.useCallback(
7521
+ (next) => {
7522
+ if (!isControlled) {
7523
+ setInner(next);
7597
7524
  }
7525
+ if (!next) {
7526
+ setQuery("");
7527
+ }
7528
+ onOpenChange?.(next);
7529
+ },
7530
+ [isControlled, onOpenChange]
7531
+ );
7532
+ React.useEffect(() => {
7533
+ if (reactNative.Platform.OS !== "web") {
7534
+ return;
7598
7535
  }
7599
- for (const n of endPages) {
7600
- pushPage(n);
7536
+ const handler = /* @__PURE__ */ __name((e) => {
7537
+ if ((e.metaKey || e.ctrlKey) && e.key === "k") {
7538
+ e.preventDefault();
7539
+ setOpen(!current);
7540
+ }
7541
+ }, "handler");
7542
+ window.addEventListener("keydown", handler);
7543
+ return () => window.removeEventListener("keydown", handler);
7544
+ }, [current, setOpen]);
7545
+ const ctxValue = {
7546
+ open: current,
7547
+ setOpen,
7548
+ query,
7549
+ setQuery
7550
+ };
7551
+ return /* @__PURE__ */ jsxRuntime.jsx(CommandContext.Provider, { value: ctxValue, children });
7552
+ }, "CommandRoot");
7553
+ var CommandTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
7554
+ const ctx = useCommandContext("Command.Trigger");
7555
+ const open = /* @__PURE__ */ __name(() => ctx.setOpen(true), "open");
7556
+ if (reactNative.Platform.OS === "web") {
7557
+ if (React.isValidElement(children)) {
7558
+ const child = children;
7559
+ const existingOnClick = child.props.onClick;
7560
+ const existingOnPress = child.props.onPress;
7561
+ const fire = /* @__PURE__ */ __name((e) => {
7562
+ existingOnClick?.(e);
7563
+ existingOnPress?.(e);
7564
+ open();
7565
+ }, "fire");
7566
+ const extraProps = {
7567
+ onClick: fire,
7568
+ "aria-haspopup": "dialog",
7569
+ "aria-expanded": ctx.open ? "true" : "false"
7570
+ };
7571
+ if (existingOnPress !== void 0) {
7572
+ extraProps.onPress = fire;
7573
+ }
7574
+ return React.cloneElement(child, extraProps);
7601
7575
  }
7602
- if (showPrevNext) {
7603
- items.push({ type: "next", disabled: currentPage >= safePageCount });
7576
+ return /* @__PURE__ */ jsxRuntime.jsx(
7577
+ "button",
7578
+ {
7579
+ type: "button",
7580
+ "data-testid": testID,
7581
+ className: cn("nori-command-trigger", className),
7582
+ "aria-haspopup": "dialog",
7583
+ "aria-expanded": ctx.open,
7584
+ onClick: open,
7585
+ children
7586
+ }
7587
+ );
7588
+ }
7589
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Pressable, { testID, onPress: open, accessibilityRole: "button", children });
7590
+ }, "CommandTrigger");
7591
+ var CommandDialogInner = /* @__PURE__ */ __name(({
7592
+ placeholder = "Type a command or search\u2026",
7593
+ children,
7594
+ className,
7595
+ testID
7596
+ }) => {
7597
+ const ctx = useCommandContext("Command.Dialog");
7598
+ const colors = useThemeColors();
7599
+ const inputRef = React.useRef(null);
7600
+ React.useEffect(() => {
7601
+ if (!ctx.open) {
7602
+ return;
7604
7603
  }
7605
- if (showFirstLast) {
7606
- items.push({ type: "last", disabled: currentPage >= safePageCount });
7604
+ if (reactNative.Platform.OS !== "web") {
7605
+ return;
7607
7606
  }
7608
- return items;
7609
- }, [currentPage, safePageCount, siblingCount, boundaryCount, showFirstLast, showPrevNext]);
7610
- return {
7611
- page: currentPage,
7612
- pages,
7613
- canPrev: currentPage > 1,
7614
- canNext: currentPage < safePageCount,
7615
- goToPage,
7616
- prev,
7617
- next,
7618
- first,
7619
- last
7620
- };
7621
- }
7622
- __name(usePagination, "usePagination");
7623
- var TableContext = React.createContext({
7624
- striped: false,
7625
- compact: false,
7626
- bordered: false,
7627
- rowIndex: 0,
7628
- setRowIndex: /* @__PURE__ */ __name(() => {
7629
- }, "setRowIndex")
7630
- });
7631
- function buildTableCompound(parts) {
7632
- return Object.assign(parts.Root, {
7633
- Header: parts.Header,
7634
- Body: parts.Body,
7635
- Footer: parts.Footer,
7636
- Row: parts.Row,
7637
- HeaderCell: parts.HeaderCell,
7638
- Cell: parts.Cell,
7639
- Caption: parts.Caption
7640
- });
7641
- }
7642
- __name(buildTableCompound, "buildTableCompound");
7643
- var TableRoot = /* @__PURE__ */ __name(({ striped = false, compact = false, bordered = false, children, className, testID }) => {
7644
- const [rowIndex, setRowIndex] = React.useState(0);
7645
- const ctxValue = {
7646
- striped,
7647
- compact,
7648
- bordered,
7649
- rowIndex,
7650
- setRowIndex
7651
- };
7652
- return /* @__PURE__ */ jsxRuntime.jsx(TableContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx(
7653
- "table",
7607
+ const id = setTimeout(() => inputRef.current?.focus(), 50);
7608
+ return () => clearTimeout(id);
7609
+ }, [ctx.open]);
7610
+ const contentProps = testID !== void 0 ? { testID, className: cn("nori-command-dialog", className) } : { className: cn("nori-command-dialog", className) };
7611
+ return /* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: ctx.open, onOpenChange: ctx.setOpen, children: /* @__PURE__ */ jsxRuntime.jsx(Dialog.Content, { ...contentProps, children: reactNative.Platform.OS === "web" ? /* @__PURE__ */ jsxRuntime.jsxs(
7612
+ "div",
7654
7613
  {
7655
- className: cn(
7656
- "w-full caption-bottom text-sm",
7657
- bordered && "border border-semantic-border-default",
7658
- className
7659
- ),
7660
- ...testID !== void 0 ? { "data-testid": testID } : {},
7661
- children
7614
+ style: {
7615
+ maxHeight: "80vh",
7616
+ display: "flex",
7617
+ flexDirection: "column",
7618
+ overflow: "hidden",
7619
+ minWidth: 360
7620
+ },
7621
+ children: [
7622
+ /* @__PURE__ */ jsxRuntime.jsxs(
7623
+ "div",
7624
+ {
7625
+ style: {
7626
+ padding: `${colors.spacing["3"]}px ${colors.spacing["4"]}px`,
7627
+ borderBottom: `1px solid ${colors.semantic.border.default}`,
7628
+ display: "flex",
7629
+ alignItems: "center",
7630
+ gap: colors.spacing["2"]
7631
+ },
7632
+ children: [
7633
+ /* @__PURE__ */ jsxRuntime.jsx(
7634
+ "svg",
7635
+ {
7636
+ width: "16",
7637
+ height: "16",
7638
+ viewBox: "0 0 16 16",
7639
+ fill: "none",
7640
+ "aria-hidden": "true",
7641
+ style: { color: colors.semantic.text.muted, flexShrink: 0 },
7642
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7643
+ "path",
7644
+ {
7645
+ d: "M6.5 11a4.5 4.5 0 1 0 0-9 4.5 4.5 0 0 0 0 9ZM14 14l-3-3",
7646
+ stroke: "currentColor",
7647
+ strokeWidth: "1.5",
7648
+ strokeLinecap: "round",
7649
+ strokeLinejoin: "round"
7650
+ }
7651
+ )
7652
+ }
7653
+ ),
7654
+ /* @__PURE__ */ jsxRuntime.jsx(
7655
+ "input",
7656
+ {
7657
+ ref: inputRef,
7658
+ type: "text",
7659
+ role: "combobox",
7660
+ "aria-expanded": true,
7661
+ "aria-autocomplete": "list",
7662
+ autoComplete: "off",
7663
+ spellCheck: false,
7664
+ placeholder,
7665
+ value: ctx.query,
7666
+ onChange: (e) => ctx.setQuery(e.target.value),
7667
+ style: {
7668
+ flex: 1,
7669
+ fontSize: 15,
7670
+ background: "transparent",
7671
+ border: "none",
7672
+ outline: "none",
7673
+ color: colors.semantic.text.default,
7674
+ width: "100%"
7675
+ }
7676
+ }
7677
+ )
7678
+ ]
7679
+ }
7680
+ ),
7681
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", style: { overflowY: "auto", flex: 1, maxHeight: 400 }, children })
7682
+ ]
7662
7683
  }
7663
- ) }) });
7664
- }, "TableRoot");
7665
- var TableHeader = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7666
- "thead",
7667
- {
7668
- className: cn("[&_tr]:border-b [&_tr]:border-semantic-border-default", className),
7669
- ...testID !== void 0 ? { "data-testid": testID } : {},
7670
- children
7671
- }
7672
- ), "TableHeader");
7673
- var TableBody = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7674
- "tbody",
7675
- {
7676
- className: cn("[&_tr:last-child]:border-0", className),
7677
- ...testID !== void 0 ? { "data-testid": testID } : {},
7678
- children
7679
- }
7680
- ), "TableBody");
7681
- var TableFooter = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7682
- "tfoot",
7683
- {
7684
- className: cn("border-t border-semantic-border-default font-medium", className),
7685
- ...testID !== void 0 ? { "data-testid": testID } : {},
7686
- children
7687
- }
7688
- ), "TableFooter");
7689
- var TableRow = /* @__PURE__ */ __name(({ selected = false, onPress, children, className, testID }) => {
7684
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flex: 1 }, children: [
7685
+ /* @__PURE__ */ jsxRuntime.jsx(
7686
+ reactNative.TextInput,
7687
+ {
7688
+ placeholder,
7689
+ placeholderTextColor: colors.semantic.text.muted,
7690
+ value: ctx.query,
7691
+ onChangeText: ctx.setQuery,
7692
+ autoFocus: ctx.open,
7693
+ style: {
7694
+ fontSize: 15,
7695
+ color: colors.semantic.text.default,
7696
+ paddingHorizontal: px(colors.spacing["4"]),
7697
+ paddingVertical: px(colors.spacing["3"]),
7698
+ borderBottomWidth: 1,
7699
+ borderBottomColor: colors.semantic.border.default
7700
+ }
7701
+ }
7702
+ ),
7703
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { style: { maxHeight: 400 }, children })
7704
+ ] }) }) });
7705
+ }, "CommandDialogInner");
7706
+ var CommandEmpty = /* @__PURE__ */ __name(({ children, className, testID }) => {
7690
7707
  const colors = useThemeColors();
7691
- const handleClick = React.useCallback(() => {
7692
- onPress?.();
7693
- }, [onPress]);
7708
+ if (reactNative.Platform.OS === "web") {
7709
+ return /* @__PURE__ */ jsxRuntime.jsx(
7710
+ "div",
7711
+ {
7712
+ "data-testid": testID,
7713
+ role: "status",
7714
+ "aria-live": "polite",
7715
+ className: cn("nori-command-empty", className),
7716
+ style: {
7717
+ paddingTop: colors.spacing["6"],
7718
+ paddingBottom: colors.spacing["6"],
7719
+ paddingLeft: colors.spacing["4"],
7720
+ paddingRight: colors.spacing["4"],
7721
+ textAlign: "center",
7722
+ color: colors.semantic.text.muted,
7723
+ fontSize: 14
7724
+ },
7725
+ children
7726
+ }
7727
+ );
7728
+ }
7694
7729
  return /* @__PURE__ */ jsxRuntime.jsx(
7695
- "tr",
7730
+ reactNative.View,
7696
7731
  {
7697
- className: cn(
7698
- "border-b border-semantic-border-default transition-colors",
7699
- onPress && "cursor-pointer hover:bg-semantic-background-subtle",
7700
- selected && "bg-semantic-background-subtle",
7701
- className
7702
- ),
7703
- style: selected ? { backgroundColor: colors.semantic.background.subtle } : void 0,
7704
- onClick: onPress ? handleClick : void 0,
7705
- ...testID !== void 0 ? { "data-testid": testID } : {},
7706
- children
7732
+ testID,
7733
+ style: {
7734
+ paddingVertical: px(colors.spacing["6"]),
7735
+ paddingHorizontal: px(colors.spacing["4"]),
7736
+ alignItems: "center"
7737
+ },
7738
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: colors.semantic.text.muted, fontSize: 14 }, children: typeof children === "string" ? children : "No results found." })
7707
7739
  }
7708
7740
  );
7709
- }, "TableRow");
7710
- var TableHeaderCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7711
- "th",
7712
- {
7713
- className: cn(
7714
- "h-10 px-4 font-medium text-semantic-text-secondary",
7715
- align === "right" && "text-right",
7716
- align === "center" && "text-center",
7717
- align === "left" && "text-left",
7718
- className
7719
- ),
7720
- colSpan,
7721
- ...testID !== void 0 ? { "data-testid": testID } : {},
7722
- children
7741
+ }, "CommandEmpty");
7742
+ var CommandGroup = /* @__PURE__ */ __name(({ heading, children, className, testID }) => {
7743
+ const ctx = useCommandContext("Command.Group");
7744
+ const groupId = React.useId();
7745
+ const colors = useThemeColors();
7746
+ const visibleCount = countVisibleItems(children, ctx.query);
7747
+ if (visibleCount === 0) {
7748
+ return null;
7723
7749
  }
7724
- ), "TableHeaderCell");
7725
- var TableCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7726
- "td",
7727
- {
7728
- className: cn(
7729
- "p-4 align-middle",
7730
- align === "right" && "text-right",
7731
- align === "center" && "text-center",
7732
- align === "left" && "text-left",
7733
- className
7750
+ if (reactNative.Platform.OS === "web") {
7751
+ return /* @__PURE__ */ jsxRuntime.jsxs(
7752
+ "section",
7753
+ {
7754
+ "data-testid": testID,
7755
+ "aria-labelledby": heading ? `${groupId}-heading` : void 0,
7756
+ className: cn("nori-command-group", className),
7757
+ children: [
7758
+ heading && /* @__PURE__ */ jsxRuntime.jsx(
7759
+ "div",
7760
+ {
7761
+ id: `${groupId}-heading`,
7762
+ style: {
7763
+ padding: `${colors.spacing["2"]}px ${colors.spacing["4"]}px ${colors.spacing["1"]}px`,
7764
+ fontSize: 11,
7765
+ fontWeight: 600,
7766
+ letterSpacing: "0.05em",
7767
+ textTransform: "uppercase",
7768
+ color: colors.semantic.text.muted
7769
+ },
7770
+ children: heading
7771
+ }
7772
+ ),
7773
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { paddingBottom: colors.spacing["2"] }, children })
7774
+ ]
7775
+ }
7776
+ );
7777
+ }
7778
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { testID, children: [
7779
+ heading && /* @__PURE__ */ jsxRuntime.jsx(
7780
+ reactNative.View,
7781
+ {
7782
+ style: {
7783
+ paddingHorizontal: px(colors.spacing["4"]),
7784
+ paddingTop: px(colors.spacing["2"]),
7785
+ paddingBottom: px(colors.spacing["1"])
7786
+ },
7787
+ children: /* @__PURE__ */ jsxRuntime.jsx(
7788
+ reactNative.Text,
7789
+ {
7790
+ style: {
7791
+ fontSize: 11,
7792
+ fontWeight: "600",
7793
+ textTransform: "uppercase",
7794
+ color: colors.semantic.text.muted,
7795
+ letterSpacing: 0.5
7796
+ },
7797
+ children: heading
7798
+ }
7799
+ )
7800
+ }
7734
7801
  ),
7735
- colSpan,
7736
- ...testID !== void 0 ? { "data-testid": testID } : {},
7737
7802
  children
7803
+ ] });
7804
+ }, "CommandGroup");
7805
+ var CommandItem = /* @__PURE__ */ __name(({ onSelect, disabled = false, children, className, testID }) => {
7806
+ const ctx = useCommandContext("Command.Item");
7807
+ const colors = useThemeColors();
7808
+ const text = extractText(children);
7809
+ const visible = matchesQuery(text, ctx.query);
7810
+ if (!visible) {
7811
+ return null;
7738
7812
  }
7739
- ), "TableCell");
7740
- var TableCaption = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
7741
- "caption",
7742
- {
7743
- className: cn("mt-4 text-sm text-semantic-text-secondary", className),
7744
- ...testID !== void 0 ? { "data-testid": testID } : {},
7745
- children
7813
+ const handleSelect = /* @__PURE__ */ __name(() => {
7814
+ if (disabled) {
7815
+ return;
7816
+ }
7817
+ onSelect?.();
7818
+ ctx.setOpen(false);
7819
+ }, "handleSelect");
7820
+ if (reactNative.Platform.OS === "web") {
7821
+ return /* @__PURE__ */ jsxRuntime.jsx(
7822
+ "div",
7823
+ {
7824
+ "data-testid": testID,
7825
+ role: "option",
7826
+ "aria-selected": "false",
7827
+ "aria-disabled": disabled,
7828
+ tabIndex: disabled ? -1 : 0,
7829
+ className: cn("nori-command-item", className),
7830
+ onClick: handleSelect,
7831
+ onKeyDown: (e) => {
7832
+ if (e.key === "Enter") {
7833
+ e.preventDefault();
7834
+ handleSelect();
7835
+ }
7836
+ },
7837
+ onMouseEnter: (e) => {
7838
+ if (!disabled) {
7839
+ e.currentTarget.style.background = `${colors.semantic.interactive.primary}14`;
7840
+ }
7841
+ },
7842
+ onMouseLeave: (e) => {
7843
+ e.currentTarget.style.background = "transparent";
7844
+ },
7845
+ onFocus: (e) => {
7846
+ if (!disabled) {
7847
+ e.currentTarget.style.background = `${colors.semantic.interactive.primary}14`;
7848
+ }
7849
+ },
7850
+ onBlur: (e) => {
7851
+ e.currentTarget.style.background = "transparent";
7852
+ },
7853
+ style: {
7854
+ display: "flex",
7855
+ alignItems: "center",
7856
+ justifyContent: "space-between",
7857
+ padding: `${colors.spacing["2"]}px ${colors.spacing["4"]}px`,
7858
+ cursor: disabled ? "not-allowed" : "pointer",
7859
+ opacity: disabled ? 0.5 : 1,
7860
+ fontSize: 14,
7861
+ color: colors.semantic.text.default,
7862
+ borderRadius: colors.radius.sm,
7863
+ margin: `0 ${colors.spacing["1"]}px`,
7864
+ outline: "none"
7865
+ },
7866
+ children
7867
+ }
7868
+ );
7746
7869
  }
7747
- ), "TableCaption");
7748
- var Table = buildTableCompound({
7749
- Root: TableRoot,
7750
- Header: TableHeader,
7751
- Body: TableBody,
7752
- Footer: TableFooter,
7753
- Row: TableRow,
7754
- HeaderCell: TableHeaderCell,
7755
- Cell: TableCell,
7756
- Caption: TableCaption
7757
- });
7758
- function sortData(data, sort) {
7759
- if (!sort) {
7760
- return data;
7870
+ return /* @__PURE__ */ jsxRuntime.jsx(
7871
+ reactNative.Pressable,
7872
+ {
7873
+ testID,
7874
+ onPress: handleSelect,
7875
+ disabled,
7876
+ accessibilityRole: "button",
7877
+ style: ({ pressed }) => ({
7878
+ flexDirection: "row",
7879
+ alignItems: "center",
7880
+ justifyContent: "space-between",
7881
+ paddingHorizontal: px(colors.spacing["4"]),
7882
+ paddingVertical: px(colors.spacing["3"]),
7883
+ opacity: disabled ? 0.5 : pressed ? 0.7 : 1
7884
+ }),
7885
+ children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14, color: colors.semantic.text.default }, children }) : children
7886
+ }
7887
+ );
7888
+ }, "CommandItem");
7889
+ var CommandShortcut = /* @__PURE__ */ __name(({ children, className }) => {
7890
+ const colors = useThemeColors();
7891
+ if (reactNative.Platform.OS === "web") {
7892
+ return /* @__PURE__ */ jsxRuntime.jsx(
7893
+ "span",
7894
+ {
7895
+ "aria-hidden": "true",
7896
+ className: cn("nori-command-shortcut", className),
7897
+ style: {
7898
+ marginLeft: "auto",
7899
+ fontSize: 12,
7900
+ color: colors.semantic.text.muted,
7901
+ letterSpacing: "0.05em",
7902
+ opacity: 0.7
7903
+ },
7904
+ children
7905
+ }
7906
+ );
7761
7907
  }
7762
- const key = sort.id;
7763
- return [...data].sort((a, b) => {
7764
- const av = a[key];
7765
- const bv = b[key];
7766
- if (av == null && bv == null) {
7767
- return 0;
7908
+ return /* @__PURE__ */ jsxRuntime.jsx(
7909
+ reactNative.Text,
7910
+ {
7911
+ style: {
7912
+ fontSize: 12,
7913
+ color: colors.semantic.text.muted,
7914
+ opacity: 0.7
7915
+ },
7916
+ children: typeof children === "string" ? children : null
7768
7917
  }
7769
- if (av == null) {
7770
- return 1;
7918
+ );
7919
+ }, "CommandShortcut");
7920
+ function extractText(node) {
7921
+ if (typeof node === "string" || typeof node === "number") {
7922
+ return String(node);
7923
+ }
7924
+ if (Array.isArray(node)) {
7925
+ return node.map(extractText).join(" ");
7926
+ }
7927
+ if (React.isValidElement(node)) {
7928
+ const el = node;
7929
+ return extractText(el.props.children);
7930
+ }
7931
+ return "";
7932
+ }
7933
+ __name(extractText, "extractText");
7934
+ function matchesQuery(text, query) {
7935
+ if (!query.trim()) {
7936
+ return true;
7937
+ }
7938
+ return text.toLowerCase().includes(query.toLowerCase().trim());
7939
+ }
7940
+ __name(matchesQuery, "matchesQuery");
7941
+ function countVisibleItems(children, query) {
7942
+ let count = 0;
7943
+ React.Children.forEach(children, (child) => {
7944
+ if (!React.isValidElement(child)) {
7945
+ return;
7771
7946
  }
7772
- if (bv == null) {
7773
- return -1;
7947
+ const props = child.props;
7948
+ if ("onSelect" in props || !("heading" in props)) {
7949
+ const text = extractText(props.children);
7950
+ if (matchesQuery(text, query)) {
7951
+ count++;
7952
+ }
7774
7953
  }
7775
- const cmp2 = av < bv ? -1 : av > bv ? 1 : 0;
7776
- return sort.direction === "asc" ? cmp2 : -cmp2;
7777
7954
  });
7955
+ return count;
7778
7956
  }
7779
- __name(sortData, "sortData");
7780
- function SortIndicator({ direction }) {
7781
- if (direction === void 0) {
7782
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4, opacity: 0.3 }, children: "\u21C5" });
7957
+ __name(countVisibleItems, "countVisibleItems");
7958
+ var CommandDialogWrapper = /* @__PURE__ */ __name((props) => {
7959
+ const ctx = useCommandContext("Command.Dialog");
7960
+ const { children, ...rest } = props;
7961
+ let anyVisible = false;
7962
+ let emptyNode = null;
7963
+ React.Children.forEach(children, (child) => {
7964
+ if (!React.isValidElement(child)) {
7965
+ return;
7966
+ }
7967
+ const childProps = child.props;
7968
+ if (!("heading" in childProps) && !("onSelect" in childProps) && !("icon" in childProps)) {
7969
+ emptyNode = child;
7970
+ return;
7971
+ }
7972
+ const groupChildren = childProps.children;
7973
+ const count = countVisibleItems(groupChildren, ctx.query);
7974
+ if (count > 0) {
7975
+ anyVisible = true;
7976
+ }
7977
+ });
7978
+ return /* @__PURE__ */ jsxRuntime.jsx(CommandDialogInner, { ...rest, children: anyVisible ? children : emptyNode ?? /* @__PURE__ */ jsxRuntime.jsx(CommandEmpty, { children: "No results found." }) });
7979
+ }, "CommandDialogWrapper");
7980
+ var Command = Object.assign(CommandRoot, {
7981
+ Trigger: CommandTrigger,
7982
+ Dialog: CommandDialogWrapper,
7983
+ Empty: CommandEmpty,
7984
+ Group: CommandGroup,
7985
+ Item: CommandItem,
7986
+ Shortcut: CommandShortcut
7987
+ });
7988
+ var MenuContext = React.createContext(null);
7989
+ var MenuContextProvider = /* @__PURE__ */ __name(({
7990
+ open,
7991
+ toggle,
7992
+ close,
7993
+ children
7994
+ }) => /* @__PURE__ */ jsxRuntime.jsx(MenuContext.Provider, { value: { open, toggle: toggle ?? close, close }, children }), "MenuContextProvider");
7995
+ function useMenuContext(caller) {
7996
+ const ctx = React.useContext(MenuContext);
7997
+ if (!ctx) {
7998
+ throw new Error(`<${caller}> must be rendered inside a <DropdownMenu> or <ContextMenu>.`);
7783
7999
  }
7784
- return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4 }, children: direction === "asc" ? "\u2191" : "\u2193" });
8000
+ return ctx;
7785
8001
  }
7786
- __name(SortIndicator, "SortIndicator");
7787
- function DataTable({
7788
- data,
7789
- columns,
7790
- pageSize = 10,
7791
- defaultSort,
7792
- onRowPress,
7793
- emptyState,
7794
- striped,
7795
- compact,
7796
- bordered,
8002
+ __name(useMenuContext, "useMenuContext");
8003
+ var MenuContent = /* @__PURE__ */ __name(({
8004
+ children,
8005
+ className,
7797
8006
  testID,
7798
- className
7799
- }) {
7800
- const [sort, setSort] = React.useState(defaultSort ?? null);
7801
- const sorted = React.useMemo(() => sortData(data, sort), [data, sort]);
7802
- const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));
7803
- const { page, goToPage, canPrev, canNext } = usePagination({ pageCount, defaultPage: 1 });
7804
- const pageSlice = React.useMemo(() => {
7805
- const start = (page - 1) * pageSize;
7806
- return sorted.slice(start, start + pageSize);
7807
- }, [sorted, page, pageSize]);
7808
- const handleSort = /* @__PURE__ */ __name((colId) => {
7809
- setSort((prev) => {
7810
- if (prev?.id !== colId) {
7811
- goToPage(1);
7812
- return { id: colId, direction: "asc" };
8007
+ side = "bottom",
8008
+ align = "start",
8009
+ "aria-label": ariaLabel
8010
+ }) => {
8011
+ const colors = useThemeColors();
8012
+ const containerRef = React.useRef(null);
8013
+ React.useEffect(() => {
8014
+ if (reactNative.Platform.OS !== "web") {
8015
+ return;
8016
+ }
8017
+ if (typeof document === "undefined") {
8018
+ return;
8019
+ }
8020
+ const container = containerRef.current;
8021
+ if (!container) {
8022
+ return;
8023
+ }
8024
+ const getItems = /* @__PURE__ */ __name(() => Array.from(container.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')), "getItems");
8025
+ const onKeyDown = /* @__PURE__ */ __name((e) => {
8026
+ const items = getItems();
8027
+ if (items.length === 0) {
8028
+ return;
7813
8029
  }
7814
- if (prev.direction === "asc") {
7815
- return { id: colId, direction: "desc" };
8030
+ const focused = document.activeElement;
8031
+ const idx = focused ? items.indexOf(focused) : -1;
8032
+ switch (e.key) {
8033
+ case "ArrowDown":
8034
+ e.preventDefault();
8035
+ items[idx < items.length - 1 ? idx + 1 : 0]?.focus();
8036
+ break;
8037
+ case "ArrowUp":
8038
+ e.preventDefault();
8039
+ items[idx > 0 ? idx - 1 : items.length - 1]?.focus();
8040
+ break;
8041
+ case "Home":
8042
+ e.preventDefault();
8043
+ items[0]?.focus();
8044
+ break;
8045
+ case "End":
8046
+ e.preventDefault();
8047
+ items[items.length - 1]?.focus();
8048
+ break;
7816
8049
  }
7817
- goToPage(1);
7818
- return null;
7819
- });
7820
- }, "handleSort");
7821
- const tableProps = {};
7822
- if (striped !== void 0) {
7823
- tableProps.striped = striped;
7824
- }
7825
- if (compact !== void 0) {
7826
- tableProps.compact = compact;
7827
- }
7828
- if (bordered !== void 0) {
7829
- tableProps.bordered = bordered;
7830
- }
7831
- if (testID !== void 0) {
7832
- tableProps.testID = testID;
7833
- }
7834
- if (className !== void 0) {
7835
- tableProps.className = className;
7836
- }
7837
- return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { width: "100%" }, children: [
7838
- /* @__PURE__ */ jsxRuntime.jsxs(Table, { ...tableProps, children: [
7839
- /* @__PURE__ */ jsxRuntime.jsx(Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: columns.map((col) => {
7840
- const align = col.align;
7841
- return /* @__PURE__ */ jsxRuntime.jsx(Table.HeaderCell, { ...align !== void 0 ? { align } : {}, children: col.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
7842
- reactNative.Pressable,
7843
- {
7844
- accessibilityRole: "button",
7845
- accessibilityLabel: `Sort by ${col.id}`,
7846
- "aria-label": `Sort by ${col.id}`,
7847
- onPress: () => handleSort(col.id),
7848
- style: { flexDirection: "row", alignItems: "center" },
7849
- children: [
7850
- typeof col.header === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children: col.header }) : col.header,
7851
- /* @__PURE__ */ jsxRuntime.jsx(
7852
- SortIndicator,
7853
- {
7854
- ...sort?.id === col.id ? { direction: sort.direction } : {}
7855
- }
7856
- )
7857
- ]
7858
- }
7859
- ) : col.header }, col.id);
7860
- }) }) }),
7861
- /* @__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(
7862
- Table.Row,
8050
+ }, "onKeyDown");
8051
+ container.addEventListener("keydown", onKeyDown);
8052
+ return () => container.removeEventListener("keydown", onKeyDown);
8053
+ });
8054
+ return /* @__PURE__ */ jsxRuntime.jsx(
8055
+ Popover.Content,
8056
+ {
8057
+ side,
8058
+ align,
8059
+ ...testID !== void 0 ? { testID } : {},
8060
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {},
8061
+ ...className !== void 0 ? { className } : {},
8062
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8063
+ reactNative.View,
7863
8064
  {
7864
- ...onRowPress !== void 0 ? { onPress: /* @__PURE__ */ __name(() => onRowPress(row), "onPress") } : {},
7865
- children: columns.map((col) => {
7866
- const colAlign = col.align;
7867
- return /* @__PURE__ */ jsxRuntime.jsx(
7868
- Table.Cell,
7869
- {
7870
- ...colAlign !== void 0 ? { align: colAlign } : {},
7871
- children: col.cell(row)
7872
- },
7873
- col.id
7874
- );
7875
- })
7876
- },
7877
- i
7878
- )) })
7879
- ] }),
7880
- pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(
7881
- PaginationControls,
7882
- {
7883
- page,
7884
- pageCount,
7885
- canPrev,
7886
- canNext,
7887
- goToPage
7888
- }
7889
- )
7890
- ] });
7891
- }
7892
- __name(DataTable, "DataTable");
7893
- function EmptyState({ children }) {
7894
- 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 });
7895
- }
7896
- __name(EmptyState, "EmptyState");
7897
- function PaginationControls({
7898
- page,
7899
- pageCount,
7900
- canPrev,
7901
- canNext,
7902
- goToPage
7903
- }) {
8065
+ ref: containerRef,
8066
+ ...{
8067
+ role: "menu",
8068
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel } : {}
8069
+ },
8070
+ style: {
8071
+ minWidth: 160,
8072
+ paddingVertical: px(colors.spacing["1"]),
8073
+ margin: -px(colors.spacing["4"]),
8074
+ borderRadius: px(colors.radius.lg),
8075
+ overflow: "hidden"
8076
+ },
8077
+ children
8078
+ }
8079
+ )
8080
+ }
8081
+ );
8082
+ }, "MenuContent");
8083
+ MenuContent.displayName = "MenuContent";
8084
+ var MenuItem = /* @__PURE__ */ __name(({
8085
+ onSelect,
8086
+ disabled = false,
8087
+ destructive = false,
8088
+ icon,
8089
+ shortcut,
8090
+ children,
8091
+ className,
8092
+ testID
8093
+ }) => {
8094
+ const colors = useThemeColors();
8095
+ const menu = useMenuContext("MenuItem");
8096
+ const handlePress = React.useCallback(() => {
8097
+ if (disabled) {
8098
+ return;
8099
+ }
8100
+ onSelect?.();
8101
+ menu.close();
8102
+ }, [disabled, onSelect, menu]);
8103
+ const textColor = destructive ? colors.color.danger : disabled ? colors.semantic.text.muted : colors.semantic.text.default;
7904
8104
  return /* @__PURE__ */ jsxRuntime.jsxs(
7905
- reactNative.View,
8105
+ reactNative.Pressable,
7906
8106
  {
7907
- style: {
7908
- flexDirection: "row",
7909
- justifyContent: "flex-end",
7910
- alignItems: "center",
7911
- paddingVertical: 8,
7912
- gap: 8
8107
+ onPress: handlePress,
8108
+ disabled,
8109
+ ...{
8110
+ role: "menuitem",
8111
+ "aria-disabled": disabled ? "true" : void 0,
8112
+ tabIndex: disabled ? -1 : 0,
8113
+ onKeyDown: /* @__PURE__ */ __name((e) => {
8114
+ if (e.key === "Enter" || e.key === " ") {
8115
+ e.preventDefault();
8116
+ handlePress();
8117
+ }
8118
+ }, "onKeyDown")
7913
8119
  },
8120
+ ...testID !== void 0 ? { testID } : {},
8121
+ className: cn("flex-row items-center gap-2 px-3 py-2", className),
8122
+ style: { opacity: disabled ? 0.4 : 1 },
8123
+ accessibilityRole: "menuitem",
8124
+ accessibilityState: { disabled },
7914
8125
  children: [
8126
+ icon !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { width: 16, height: 16, alignItems: "center", justifyContent: "center" }, children: icon }),
7915
8127
  /* @__PURE__ */ jsxRuntime.jsx(
7916
- reactNative.Pressable,
8128
+ reactNative.Text,
7917
8129
  {
7918
- onPress: canPrev ? () => goToPage(page - 1) : void 0,
7919
- accessibilityRole: "button",
7920
- accessibilityLabel: "Previous page",
7921
- "aria-label": "Previous page",
7922
- "aria-disabled": !canPrev,
7923
- style: { opacity: canPrev ? 1 : 0.4, paddingHorizontal: 8 },
7924
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "\u2039 Prev" })
8130
+ style: {
8131
+ flex: 1,
8132
+ fontFamily: colors.fontFamily.body,
8133
+ fontSize: px(colors.fontSize.sm),
8134
+ color: textColor
8135
+ },
8136
+ children
7925
8137
  }
7926
8138
  ),
7927
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: { fontSize: 14 }, "aria-live": "polite", children: [
7928
- page,
7929
- " / ",
7930
- pageCount
7931
- ] }),
7932
- /* @__PURE__ */ jsxRuntime.jsx(
7933
- reactNative.Pressable,
8139
+ shortcut !== void 0 && reactNative.Platform.OS === "web" && /* @__PURE__ */ jsxRuntime.jsx(
8140
+ reactNative.Text,
7934
8141
  {
7935
- onPress: canNext ? () => goToPage(page + 1) : void 0,
7936
- accessibilityRole: "button",
7937
- accessibilityLabel: "Next page",
7938
- "aria-label": "Next page",
7939
- "aria-disabled": !canNext,
7940
- style: { opacity: canNext ? 1 : 0.4, paddingHorizontal: 8 },
7941
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "Next \u203A" })
8142
+ ...{ "aria-hidden": "true" },
8143
+ style: {
8144
+ fontFamily: colors.fontFamily.body,
8145
+ fontSize: px(colors.fontSize.xs),
8146
+ color: colors.semantic.text.muted
8147
+ },
8148
+ children: shortcut
7942
8149
  }
7943
8150
  )
7944
8151
  ]
7945
8152
  }
7946
8153
  );
7947
- }
7948
- __name(PaginationControls, "PaginationControls");
7949
- function formatDate(date$1, locale) {
7950
- try {
7951
- return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date$1.toDate(date.getLocalTimeZone()));
7952
- } catch {
7953
- return `${date$1.year}-${String(date$1.month).padStart(2, "0")}-${String(date$1.day).padStart(2, "0")}`;
7954
- }
7955
- }
7956
- __name(formatDate, "formatDate");
7957
- function CalendarIcon({ size = 16, color = "currentColor" }) {
8154
+ }, "MenuItem");
8155
+ MenuItem.displayName = "MenuItem";
8156
+ var MenuSeparator = /* @__PURE__ */ __name(({ className, testID }) => {
7958
8157
  const colors = useThemeColors();
7959
- if (reactNative.Platform.OS === "web") {
7960
- return /* @__PURE__ */ jsxRuntime.jsx(
7961
- "svg",
7962
- {
7963
- width: size,
7964
- height: size,
7965
- viewBox: "0 0 24 24",
7966
- fill: "none",
7967
- stroke: color,
7968
- strokeWidth: "2",
7969
- strokeLinecap: "round",
7970
- strokeLinejoin: "round",
7971
- "aria-hidden": "true",
7972
- 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" })
8158
+ return /* @__PURE__ */ jsxRuntime.jsx(
8159
+ reactNative.View,
8160
+ {
8161
+ ...{ role: "separator" },
8162
+ accessibilityRole: "none",
8163
+ ...testID !== void 0 ? { testID } : {},
8164
+ className: cn("mx-1 my-1", className),
8165
+ style: {
8166
+ height: 1,
8167
+ marginVertical: 4,
8168
+ marginHorizontal: 4,
8169
+ backgroundColor: colors.semantic.border.default
7973
8170
  }
7974
- );
7975
- }
7976
- const resolvedColor = color === "currentColor" ? colors.semantic.text.muted : color;
8171
+ }
8172
+ );
8173
+ }, "MenuSeparator");
8174
+ MenuSeparator.displayName = "MenuSeparator";
8175
+ var MenuLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
8176
+ const colors = useThemeColors();
7977
8177
  return /* @__PURE__ */ jsxRuntime.jsx(
7978
- reactNative.Text,
8178
+ reactNative.View,
7979
8179
  {
7980
- accessibilityElementsHidden: true,
7981
- importantForAccessibility: "no-hide-descendants",
7982
- style: { fontSize: size, lineHeight: size, color: resolvedColor },
7983
- children: "\u{1F4C5}"
8180
+ ...{ role: "presentation" },
8181
+ ...testID !== void 0 ? { testID } : {},
8182
+ className: cn("px-3 pt-2 pb-1", className),
8183
+ children: /* @__PURE__ */ jsxRuntime.jsx(
8184
+ reactNative.Text,
8185
+ {
8186
+ style: {
8187
+ fontFamily: colors.fontFamily.body,
8188
+ fontSize: px(colors.fontSize.xs),
8189
+ color: colors.semantic.text.muted,
8190
+ textTransform: "uppercase",
8191
+ letterSpacing: 0.6,
8192
+ fontWeight: "600"
8193
+ },
8194
+ children
8195
+ }
8196
+ )
7984
8197
  }
7985
8198
  );
7986
- }
7987
- __name(CalendarIcon, "CalendarIcon");
7988
- function buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek) {
7989
- const out = {};
7990
- if (minValue !== void 0) {
7991
- out.minValue = minValue;
7992
- }
7993
- if (maxValue !== void 0) {
7994
- out.maxValue = maxValue;
7995
- }
7996
- if (isDateUnavailable !== void 0) {
7997
- out.isDateUnavailable = isDateUnavailable;
7998
- }
7999
- if (firstDayOfWeek !== void 0) {
8000
- out.firstDayOfWeek = firstDayOfWeek;
8001
- }
8002
- return out;
8003
- }
8004
- __name(buildCalendarOptional, "buildCalendarOptional");
8005
- function buildTriggerAriaProps(ariaProps) {
8006
- const out = {};
8007
- if (ariaProps["aria-labelledby"] !== void 0) {
8008
- out["aria-labelledby"] = ariaProps["aria-labelledby"];
8009
- }
8010
- if (ariaProps["aria-describedby"] !== void 0) {
8011
- out["aria-describedby"] = ariaProps["aria-describedby"];
8012
- }
8013
- if (ariaProps["aria-invalid"] !== void 0) {
8014
- out["aria-invalid"] = ariaProps["aria-invalid"];
8015
- }
8016
- if (ariaProps["aria-required"] !== void 0) {
8017
- out["aria-required"] = ariaProps["aria-required"];
8018
- }
8019
- return out;
8020
- }
8021
- __name(buildTriggerAriaProps, "buildTriggerAriaProps");
8022
- var DatePickerRoot = /* @__PURE__ */ __name(({
8023
- value,
8024
- defaultValue: defaultValue2,
8025
- onChange,
8026
- locale: localeProp,
8027
- minValue,
8028
- maxValue,
8029
- isDateUnavailable,
8030
- firstDayOfWeek,
8031
- placeholder,
8032
- disabled = false,
8033
- id,
8034
- name: _name,
8035
- className,
8036
- testID,
8037
- ...ariaProps
8038
- }) => {
8039
- const providerLocale = useLocale();
8040
- const locale = localeProp ?? providerLocale;
8041
- const [open, setOpen] = React.useState(false);
8042
- const isControlled = value !== void 0;
8043
- const [inner, setInner] = React.useState(defaultValue2 ?? null);
8044
- const current = isControlled ? value ?? null : inner;
8045
- const handleChange = React.useCallback(
8046
- (date) => {
8199
+ }, "MenuLabel");
8200
+ MenuLabel.displayName = "MenuLabel";
8201
+ var DropdownMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8202
+ const [inner, setInner] = React.useState(defaultOpen);
8203
+ const isControlled = open !== void 0;
8204
+ const current = isControlled ? open : inner;
8205
+ const setOpen = React.useCallback(
8206
+ (next) => {
8047
8207
  if (!isControlled) {
8048
- setInner(date);
8208
+ setInner(next);
8049
8209
  }
8050
- onChange?.(date);
8051
- setOpen(false);
8210
+ onOpenChange?.(next);
8052
8211
  },
8053
- [isControlled, onChange]
8212
+ [isControlled, onOpenChange]
8054
8213
  );
8055
- const handleOpenChange = React.useCallback(
8214
+ const toggle = React.useCallback(() => setOpen(!current), [setOpen, current]);
8215
+ const close = React.useCallback(() => setOpen(false), [setOpen]);
8216
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: current, toggle, close, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
8217
+ }, "DropdownMenuRoot");
8218
+ var DropdownMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
8219
+ const menu = useMenuContext("DropdownMenu.Trigger");
8220
+ const popover = usePopoverContext("DropdownMenu.Trigger");
8221
+ const onPress = React.useCallback(() => {
8222
+ popover.measureTrigger();
8223
+ popover.setOpen(!popover.open);
8224
+ }, [popover]);
8225
+ if (React.isValidElement(children)) {
8226
+ const child = children;
8227
+ const fire = /* @__PURE__ */ __name((existing) => (event) => {
8228
+ existing?.(event);
8229
+ popover.measureTrigger();
8230
+ popover.setOpen(!popover.open);
8231
+ }, "fire");
8232
+ return /* @__PURE__ */ jsxRuntime.jsx(
8233
+ Slot,
8234
+ {
8235
+ ref: (node) => {
8236
+ popover.triggerRef.current = node;
8237
+ },
8238
+ onClick: fire(child.props.onClick),
8239
+ onPress: fire(child.props.onPress),
8240
+ ...{
8241
+ "aria-haspopup": "menu",
8242
+ "aria-expanded": menu.open,
8243
+ "aria-controls": popover.contentId
8244
+ },
8245
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8246
+ ...className !== void 0 ? { className } : {},
8247
+ children: child
8248
+ }
8249
+ );
8250
+ }
8251
+ return /* @__PURE__ */ jsxRuntime.jsx(
8252
+ reactNative.Pressable,
8253
+ {
8254
+ ref: (node) => {
8255
+ popover.triggerRef.current = node;
8256
+ },
8257
+ onPress,
8258
+ ...{
8259
+ "aria-haspopup": "menu",
8260
+ "aria-expanded": menu.open,
8261
+ "aria-controls": popover.contentId
8262
+ },
8263
+ ...testID !== void 0 ? { testID } : {},
8264
+ ...className !== void 0 ? { className } : {},
8265
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8266
+ }
8267
+ );
8268
+ }, "DropdownMenuTrigger");
8269
+ var DropdownMenuContent = /* @__PURE__ */ __name((props) => /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }), "DropdownMenuContent");
8270
+ var DropdownMenu = Object.assign(DropdownMenuRoot, {
8271
+ Trigger: DropdownMenuTrigger,
8272
+ Content: DropdownMenuContent,
8273
+ Item: MenuItem,
8274
+ Separator: MenuSeparator,
8275
+ Label: MenuLabel
8276
+ });
8277
+ var ContextMenuCtx = React.createContext(null);
8278
+ var useContextMenuCtx = /* @__PURE__ */ __name(() => {
8279
+ const ctx = React.useContext(ContextMenuCtx);
8280
+ if (!ctx) {
8281
+ throw new Error("ContextMenu compound parts must be rendered inside a <ContextMenu>.");
8282
+ }
8283
+ return ctx;
8284
+ }, "useContextMenuCtx");
8285
+ var ContextMenuRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8286
+ const [inner, setInner] = React.useState(defaultOpen);
8287
+ const isControlled = open !== void 0;
8288
+ const current = isControlled ? open : inner;
8289
+ const setOpen = React.useCallback(
8056
8290
  (next) => {
8057
- if (!disabled) {
8058
- setOpen(next);
8291
+ if (!isControlled) {
8292
+ setInner(next);
8059
8293
  }
8294
+ onOpenChange?.(next);
8060
8295
  },
8061
- [disabled]
8296
+ [isControlled, onOpenChange]
8062
8297
  );
8063
- const displayValue = current ? formatDate(current, locale) : null;
8064
- const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8065
- const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8066
- const colors = useThemeColors();
8067
- const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
8068
- const pressableStyle = {
8069
- flexDirection: "row",
8070
- alignItems: "center",
8071
- borderWidth: 1,
8072
- borderRadius: px(colors.radius.md),
8073
- paddingHorizontal: px(colors.spacing["3"]),
8074
- paddingVertical: px(colors.spacing["2"]),
8075
- backgroundColor: colors.semantic.background.elevated,
8076
- borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
8077
- opacity: disabled ? 0.6 : 1
8078
- };
8079
- const textStyle = {
8080
- flex: 1,
8081
- fontFamily: colors.fontFamily.body,
8082
- fontSize: px(colors.fontSize.md),
8083
- color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
8084
- };
8085
- const triggerExtraProps = {
8086
- role: "combobox",
8087
- accessibilityRole: "button",
8088
- "aria-haspopup": "dialog",
8089
- "aria-expanded": open,
8090
- ...triggerAriaProps
8091
- };
8092
- if (id !== void 0) {
8093
- triggerExtraProps.id = id;
8094
- triggerExtraProps.nativeID = id;
8095
- }
8096
- if (testID !== void 0) {
8097
- triggerExtraProps.testID = testID;
8098
- }
8099
- if (hasError) {
8100
- triggerExtraProps["aria-invalid"] = true;
8101
- }
8102
- if (ariaProps["aria-required"]) {
8103
- triggerExtraProps["aria-required"] = true;
8104
- }
8105
- if (disabled) {
8106
- triggerExtraProps["aria-disabled"] = true;
8107
- }
8108
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
8109
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
8298
+ return /* @__PURE__ */ jsxRuntime.jsx(ContextMenuCtx.Provider, { value: { open: current, setOpen }, children: /* @__PURE__ */ jsxRuntime.jsx(Popover, { open: current, onOpenChange: setOpen, children }) });
8299
+ }, "ContextMenuRoot");
8300
+ var ContextMenuTrigger = /* @__PURE__ */ __name(({ children, className, testID }) => {
8301
+ const ctx = useContextMenuCtx();
8302
+ const popover = usePopoverContext("ContextMenu.Trigger");
8303
+ const openMenu = React.useCallback(() => {
8304
+ popover.measureTrigger();
8305
+ ctx.setOpen(true);
8306
+ }, [ctx, popover]);
8307
+ if (reactNative.Platform.OS === "web") {
8308
+ if (React.isValidElement(children)) {
8309
+ const child = children;
8310
+ const existing = child.props.onContextMenu;
8311
+ return /* @__PURE__ */ jsxRuntime.jsx(
8312
+ Slot,
8313
+ {
8314
+ ref: (node) => {
8315
+ popover.triggerRef.current = node;
8316
+ },
8317
+ onContextMenu: (e) => {
8318
+ e.preventDefault();
8319
+ existing?.(e);
8320
+ openMenu();
8321
+ },
8322
+ ...{
8323
+ "aria-haspopup": "menu",
8324
+ "aria-expanded": ctx.open,
8325
+ "aria-controls": popover.contentId
8326
+ },
8327
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8328
+ ...className !== void 0 ? { className } : {},
8329
+ children: child
8330
+ }
8331
+ );
8332
+ }
8333
+ return /* @__PURE__ */ jsxRuntime.jsx(
8110
8334
  reactNative.Pressable,
8111
8335
  {
8112
- onPress: disabled ? void 0 : () => setOpen(!open),
8113
- disabled,
8114
- className: cn(
8115
- "flex-row items-center rounded-md border px-3 py-2",
8116
- hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
8117
- disabled ? "opacity-60" : void 0,
8118
- className
8119
- ),
8120
- style: pressableStyle,
8121
- ...triggerExtraProps,
8122
- children: [
8123
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
8124
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
8125
- ]
8126
- }
8127
- ) }),
8128
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
8129
- Calendar,
8130
- {
8131
- mode: "single",
8132
- value: current,
8133
- onChange: (date) => {
8134
- handleChange(date);
8336
+ ref: (node) => {
8337
+ popover.triggerRef.current = node;
8135
8338
  },
8136
- locale,
8137
- ...calendarOptional
8138
- }
8139
- ) })
8140
- ] });
8141
- }, "DatePickerRoot");
8142
- var DatePickerRange = /* @__PURE__ */ __name(({
8143
- value,
8144
- defaultValue: defaultValue2,
8145
- onChange,
8146
- locale: localeProp,
8147
- minValue,
8148
- maxValue,
8149
- isDateUnavailable,
8150
- firstDayOfWeek,
8151
- placeholder,
8152
- disabled = false,
8153
- id,
8154
- name: _name,
8155
- className,
8156
- testID,
8157
- ...ariaProps
8158
- }) => {
8159
- const providerLocale = useLocale();
8160
- const locale = localeProp ?? providerLocale;
8161
- const [open, setOpen] = React.useState(false);
8162
- const isControlled = value !== void 0;
8163
- const [inner, setInner] = React.useState(defaultValue2 ?? { start: null, end: null });
8164
- const current = isControlled ? value ?? { start: null, end: null } : inner;
8165
- const calendarValue = current.start !== null ? { start: current.start, end: current.end } : null;
8166
- const handleChange = React.useCallback(
8167
- (calRange) => {
8168
- const next = {
8169
- start: calRange?.start ?? null,
8170
- end: calRange?.end ?? null
8171
- };
8172
- if (!isControlled) {
8173
- setInner(next);
8174
- }
8175
- onChange?.(next);
8176
- if (next.start !== null && next.end !== null) {
8177
- setOpen(false);
8178
- }
8179
- },
8180
- [isControlled, onChange]
8181
- );
8182
- const handleOpenChange = React.useCallback(
8183
- (next) => {
8184
- if (!disabled) {
8185
- setOpen(next);
8186
- }
8187
- },
8188
- [disabled]
8189
- );
8190
- let displayValue = null;
8191
- if (current.start !== null) {
8192
- const startStr = formatDate(current.start, locale);
8193
- const endStr = current.end !== null ? formatDate(current.end, locale) : "";
8194
- displayValue = `${startStr} \u2013 ${endStr}`;
8195
- }
8196
- const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8197
- const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8198
- const colors = useThemeColors();
8199
- const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
8200
- const pressableStyle = {
8201
- flexDirection: "row",
8202
- alignItems: "center",
8203
- borderWidth: 1,
8204
- borderRadius: px(colors.radius.md),
8205
- paddingHorizontal: px(colors.spacing["3"]),
8206
- paddingVertical: px(colors.spacing["2"]),
8207
- backgroundColor: colors.semantic.background.elevated,
8208
- borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
8209
- opacity: disabled ? 0.6 : 1
8210
- };
8211
- const textStyle = {
8212
- flex: 1,
8213
- fontFamily: colors.fontFamily.body,
8214
- fontSize: px(colors.fontSize.md),
8215
- color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
8216
- };
8217
- const triggerExtraProps = {
8218
- role: "combobox",
8219
- accessibilityRole: "button",
8220
- "aria-haspopup": "dialog",
8221
- "aria-expanded": open,
8222
- ...triggerAriaProps
8223
- };
8224
- if (id !== void 0) {
8225
- triggerExtraProps.id = id;
8226
- triggerExtraProps.nativeID = id;
8227
- }
8228
- if (testID !== void 0) {
8229
- triggerExtraProps.testID = testID;
8230
- }
8231
- if (hasError) {
8232
- triggerExtraProps["aria-invalid"] = true;
8233
- }
8234
- if (ariaProps["aria-required"]) {
8235
- triggerExtraProps["aria-required"] = true;
8236
- }
8237
- if (disabled) {
8238
- triggerExtraProps["aria-disabled"] = true;
8239
- }
8240
- return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
8241
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
8242
- reactNative.Pressable,
8243
- {
8244
- onPress: disabled ? void 0 : () => setOpen(!open),
8245
- disabled,
8246
- className: cn(
8247
- "flex-row items-center rounded-md border px-3 py-2",
8248
- hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
8249
- disabled ? "opacity-60" : void 0,
8250
- className
8251
- ),
8252
- style: pressableStyle,
8253
- ...triggerExtraProps,
8254
- children: [
8255
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
8256
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
8257
- ]
8258
- }
8259
- ) }),
8260
- /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date range picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
8261
- Calendar,
8262
- {
8263
- mode: "range",
8264
- value: calendarValue,
8265
- onChange: (range2) => {
8266
- handleChange(range2);
8339
+ ...{
8340
+ onContextMenu: /* @__PURE__ */ __name((e) => {
8341
+ e.preventDefault();
8342
+ openMenu();
8343
+ }, "onContextMenu"),
8344
+ "aria-haspopup": "menu",
8345
+ "aria-expanded": ctx.open,
8346
+ "aria-controls": popover.contentId
8267
8347
  },
8268
- locale,
8269
- ...calendarOptional
8348
+ ...testID !== void 0 ? { testID } : {},
8349
+ ...className !== void 0 ? { className } : {},
8350
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8270
8351
  }
8271
- ) })
8272
- ] });
8273
- }, "DatePickerRange");
8274
- var DatePicker = Object.assign(DatePickerRoot, {
8275
- Range: DatePickerRange
8276
- });
8277
- var DialogContext = React.createContext(null);
8278
- var useDialogContext = /* @__PURE__ */ __name((label) => {
8279
- const ctx = React.useContext(DialogContext);
8280
- if (!ctx) {
8281
- throw new Error(`<${label}> must be rendered inside a <Dialog>.`);
8352
+ );
8282
8353
  }
8283
- return ctx;
8284
- }, "useDialogContext");
8285
- var DialogRoot = /* @__PURE__ */ __name(({ open, defaultOpen = false, onOpenChange, children }) => {
8286
- const [inner, setInner] = React.useState(defaultOpen);
8287
- const isControlled = open !== void 0;
8288
- const current = isControlled ? open : inner;
8289
- const setOpen = React.useCallback(
8290
- (next) => {
8291
- if (!isControlled) {
8292
- setInner(next);
8293
- }
8294
- onOpenChange?.(next);
8295
- },
8296
- [isControlled, onOpenChange]
8297
- );
8298
- const baseId = React.useId();
8299
- const triggerRef = React.useRef(null);
8300
- const ctxValue = {
8301
- open: current,
8302
- setOpen,
8303
- titleId: `${baseId}-title`,
8304
- descriptionId: `${baseId}-description`,
8305
- triggerRef
8306
- };
8307
- return /* @__PURE__ */ jsxRuntime.jsx(DialogContext.Provider, { value: ctxValue, children });
8308
- }, "DialogRoot");
8309
- var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, className, testID }) => {
8310
- const ctx = useDialogContext("DialogTrigger");
8311
- const onPress = React.useCallback(() => ctx.setOpen(true), [ctx]);
8312
- if (asChild && React.isValidElement(children)) {
8354
+ if (React.isValidElement(children)) {
8313
8355
  const child = children;
8314
- const fire = /* @__PURE__ */ __name((existing) => (event) => {
8315
- existing?.(event);
8316
- ctx.setOpen(true);
8317
- }, "fire");
8356
+ const existing = child.props.onLongPress;
8318
8357
  return /* @__PURE__ */ jsxRuntime.jsx(
8319
8358
  Slot,
8320
8359
  {
8321
8360
  ref: (node) => {
8322
- ctx.triggerRef.current = node;
8361
+ popover.triggerRef.current = node;
8323
8362
  },
8324
- onClick: fire(child.props.onClick),
8325
- onPress: fire(child.props.onPress),
8326
- ...testID !== void 0 ? { "data-testid": testID } : {},
8363
+ onLongPress: (e) => {
8364
+ existing?.(e);
8365
+ openMenu();
8366
+ },
8367
+ accessibilityRole: "button",
8368
+ ...testID !== void 0 ? { testID } : {},
8327
8369
  ...className !== void 0 ? { className } : {},
8328
8370
  children: child
8329
8371
  }
@@ -8333,358 +8375,798 @@ var DialogTrigger = /* @__PURE__ */ __name(({ asChild = true, children, classNam
8333
8375
  reactNative.Pressable,
8334
8376
  {
8335
8377
  ref: (node) => {
8336
- ctx.triggerRef.current = node;
8378
+ popover.triggerRef.current = node;
8337
8379
  },
8338
- onPress,
8380
+ onLongPress: openMenu,
8339
8381
  ...testID !== void 0 ? { testID } : {},
8340
8382
  ...className !== void 0 ? { className } : {},
8341
- children: wrapStringChildren4(children)
8383
+ children: typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children }) : children
8342
8384
  }
8343
8385
  );
8344
- }, "DialogTrigger");
8345
- function wrapStringChildren4(children) {
8346
- if (typeof children === "string" || typeof children === "number") {
8347
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children });
8386
+ }, "ContextMenuTrigger");
8387
+ var ContextMenuContent = /* @__PURE__ */ __name((props) => {
8388
+ const ctx = useContextMenuCtx();
8389
+ const close = React.useCallback(() => ctx.setOpen(false), [ctx]);
8390
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuContextProvider, { open: ctx.open, close, children: /* @__PURE__ */ jsxRuntime.jsx(MenuContent, { ...props }) });
8391
+ }, "ContextMenuContent");
8392
+ var ContextMenu = Object.assign(ContextMenuRoot, {
8393
+ Trigger: ContextMenuTrigger,
8394
+ Content: ContextMenuContent,
8395
+ Item: MenuItem,
8396
+ Separator: MenuSeparator,
8397
+ Label: MenuLabel
8398
+ });
8399
+ var range = /* @__PURE__ */ __name((from, to) => {
8400
+ if (to < from) {
8401
+ return [];
8348
8402
  }
8349
- return children;
8350
- }
8351
- __name(wrapStringChildren4, "wrapStringChildren");
8352
- var SCRIM_COLOR2 = "rgba(0, 0, 0, 0.24)";
8353
- var BLUR_AMOUNT2 = 4;
8354
- var OVERLAY_LAYOUT_BASE2 = {
8355
- position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
8356
- top: 0,
8357
- left: 0,
8358
- right: 0,
8359
- bottom: 0,
8360
- alignItems: "center",
8361
- justifyContent: "center",
8362
- // On native the BlurBackdrop sibling renders BEHIND this overlay and
8363
- // already provides dim + frosted-glass via expo-blur's `tint`/`intensity`.
8364
- // Painting SCRIM_COLOR on top would mask the blur entirely (the user
8365
- // sees only a flat tint), so the overlay stays transparent and the
8366
- // BlurView is the dominant visual on native.
8367
- ...reactNative.Platform.OS === "web" ? { zIndex: 50 } : { backgroundColor: "transparent" }
8368
- };
8369
- var CONTENT_LAYOUT_BASE3 = {
8370
- width: "100%",
8371
- maxWidth: 480,
8372
- // component-density literal not from theme
8373
- ...reactNative.Platform.OS === "web" ? {
8374
- boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
8375
- } : { elevation: 24 }
8376
- };
8377
- var FOCUSABLE_SELECTOR2 = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]):not([type="hidden"]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
8378
- var DialogContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
8379
- const ctx = useDialogContext("DialogContent");
8380
- const colors = useThemeColors();
8381
- const scheme = useColorScheme();
8382
- const contentRef = React.useRef(null);
8383
- const overlayStyle = {
8384
- ...OVERLAY_LAYOUT_BASE2,
8385
- padding: px(colors.spacing["4"])
8386
- };
8387
- const contentStyle = {
8388
- ...CONTENT_LAYOUT_BASE3,
8389
- borderRadius: px(colors.radius.xl),
8390
- padding: px(colors.spacing["6"]),
8391
- gap: px(colors.spacing["3"])
8392
- };
8393
- const [entered, setEntered] = React.useState(false);
8394
- React.useEffect(() => {
8395
- if (reactNative.Platform.OS !== "web") {
8396
- setEntered(true);
8397
- return;
8398
- }
8399
- if (!ctx.open) {
8400
- setEntered(false);
8401
- return;
8402
- }
8403
- const id = requestAnimationFrame(() => setEntered(true));
8404
- return () => cancelAnimationFrame(id);
8405
- }, [ctx.open]);
8406
- const enterStyle = reactNative.Platform.OS === "web" ? {
8407
- opacity: entered ? 1 : 0,
8408
- transform: [{ scale: entered ? 1 : 0.96 }],
8409
- transitionProperty: "opacity, transform",
8410
- transitionDuration: "150ms",
8411
- transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)"
8412
- } : {};
8413
- const overlayDomRef = React.useRef(null);
8414
- React.useEffect(() => {
8415
- if (reactNative.Platform.OS !== "web") {
8416
- return;
8417
- }
8418
- const node = overlayDomRef.current;
8419
- if (!node) {
8420
- return;
8403
+ const out = new Array(to - from + 1);
8404
+ for (let i = 0; i < out.length; i += 1) {
8405
+ out[i] = from + i;
8406
+ }
8407
+ return out;
8408
+ }, "range");
8409
+ function usePagination(args) {
8410
+ const {
8411
+ page: controlledPage,
8412
+ defaultPage = 1,
8413
+ pageCount,
8414
+ siblingCount = 1,
8415
+ boundaryCount = 1,
8416
+ showFirstLast = false,
8417
+ showPrevNext = true,
8418
+ onPageChange
8419
+ } = args;
8420
+ const isControlled = controlledPage !== void 0;
8421
+ const [uncontrolledPage, setUncontrolledPage] = React.useState(defaultPage);
8422
+ const onChangeRef = React.useRef(onPageChange);
8423
+ onChangeRef.current = onPageChange;
8424
+ const safePageCount = Math.max(1, Math.floor(pageCount));
8425
+ const rawPage = isControlled ? controlledPage : uncontrolledPage;
8426
+ const currentPage = Math.min(Math.max(1, Math.floor(rawPage)), safePageCount);
8427
+ const goToPage = React.useCallback(
8428
+ (next2) => {
8429
+ const clamped = Math.min(Math.max(1, Math.floor(next2)), Math.max(1, Math.floor(pageCount)));
8430
+ if (!isControlled) {
8431
+ setUncontrolledPage(clamped);
8432
+ }
8433
+ onChangeRef.current?.(clamped);
8434
+ },
8435
+ [isControlled, pageCount]
8436
+ );
8437
+ const prev = React.useCallback(() => goToPage(currentPage - 1), [goToPage, currentPage]);
8438
+ const next = React.useCallback(() => goToPage(currentPage + 1), [goToPage, currentPage]);
8439
+ const first = React.useCallback(() => goToPage(1), [goToPage]);
8440
+ const last = React.useCallback(() => goToPage(safePageCount), [goToPage, safePageCount]);
8441
+ const pages = React.useMemo(() => {
8442
+ const items = [];
8443
+ const safeSibling = Math.max(0, Math.floor(siblingCount));
8444
+ const safeBoundary = Math.max(0, Math.floor(boundaryCount));
8445
+ if (showFirstLast) {
8446
+ items.push({ type: "first", disabled: currentPage <= 1 });
8421
8447
  }
8422
- node.style.transitionProperty = "background-color, backdrop-filter, -webkit-backdrop-filter";
8423
- node.style.transitionDuration = "150ms, 200ms, 200ms";
8424
- node.style.transitionTimingFunction = "ease-out";
8425
- if (entered) {
8426
- node.style.backgroundColor = SCRIM_COLOR2;
8427
- node.style.backdropFilter = `blur(${BLUR_AMOUNT2}px)`;
8428
- node.style.setProperty("-webkit-backdrop-filter", `blur(${BLUR_AMOUNT2}px)`);
8429
- } else {
8430
- node.style.backgroundColor = "rgba(0, 0, 0, 0)";
8431
- node.style.backdropFilter = "blur(0px)";
8432
- node.style.setProperty("-webkit-backdrop-filter", "blur(0px)");
8448
+ if (showPrevNext) {
8449
+ items.push({ type: "prev", disabled: currentPage <= 1 });
8433
8450
  }
8434
- }, [entered]);
8435
- React.useEffect(() => {
8436
- if (!ctx.open) {
8437
- return;
8451
+ const startPages = range(1, Math.min(safeBoundary, safePageCount));
8452
+ const endPages = range(Math.max(safePageCount - safeBoundary + 1, safeBoundary + 1), safePageCount);
8453
+ const siblingsStart = Math.max(
8454
+ Math.min(currentPage - safeSibling, safePageCount - safeBoundary - safeSibling * 2 - 1),
8455
+ safeBoundary + 2
8456
+ );
8457
+ const siblingsEnd = Math.min(
8458
+ Math.max(currentPage + safeSibling, safeBoundary + safeSibling * 2 + 2),
8459
+ endPages.length > 0 ? endPages[0] - 2 : safePageCount - 1
8460
+ );
8461
+ const middle = [];
8462
+ if (siblingsStart > safeBoundary + 2) {
8463
+ middle.push("ellipsis");
8464
+ } else if (safeBoundary + 1 < safePageCount - safeBoundary) {
8465
+ middle.push(safeBoundary + 1);
8438
8466
  }
8439
- if (reactNative.Platform.OS !== "web") {
8440
- return;
8467
+ for (const p of range(siblingsStart, siblingsEnd)) {
8468
+ middle.push(p);
8441
8469
  }
8442
- if (typeof document === "undefined") {
8443
- return;
8470
+ if (siblingsEnd < safePageCount - safeBoundary - 1) {
8471
+ middle.push("ellipsis");
8472
+ } else if (safePageCount - safeBoundary > safeBoundary) {
8473
+ middle.push(safePageCount - safeBoundary);
8444
8474
  }
8445
- const previouslyFocused = document.activeElement;
8446
- const prevBodyOverflow = document.body.style.overflow;
8447
- document.body.style.overflow = "hidden";
8448
- const focusFirst = /* @__PURE__ */ __name(() => {
8449
- const node = contentRef.current;
8450
- if (!node) {
8475
+ const seen = /* @__PURE__ */ new Set();
8476
+ const pushPage = /* @__PURE__ */ __name((n) => {
8477
+ if (n < 1 || n > safePageCount || seen.has(n)) {
8451
8478
  return;
8452
8479
  }
8453
- const focusable = node.querySelectorAll(FOCUSABLE_SELECTOR2);
8454
- const first = focusable[0];
8455
- if (first) {
8456
- first.focus();
8480
+ seen.add(n);
8481
+ items.push({ type: "page", page: n, selected: n === currentPage });
8482
+ }, "pushPage");
8483
+ for (const n of startPages) {
8484
+ pushPage(n);
8485
+ }
8486
+ for (const m of middle) {
8487
+ if (m === "ellipsis") {
8488
+ items.push({ type: "ellipsis" });
8457
8489
  } else {
8458
- node.setAttribute("tabindex", "-1");
8459
- node.focus();
8460
- }
8461
- }, "focusFirst");
8462
- focusFirst();
8463
- const onKeyDown = /* @__PURE__ */ __name((event) => {
8464
- if (event.key === "Escape") {
8465
- event.preventDefault();
8466
- ctx.setOpen(false);
8467
- return;
8468
- }
8469
- if (event.key !== "Tab") {
8470
- return;
8471
- }
8472
- const node = contentRef.current;
8473
- if (!node) {
8474
- return;
8475
- }
8476
- const focusable = Array.from(node.querySelectorAll(FOCUSABLE_SELECTOR2)).filter(
8477
- (el) => el.offsetParent !== null || el === document.activeElement
8478
- );
8479
- if (focusable.length === 0) {
8480
- event.preventDefault();
8481
- return;
8482
- }
8483
- const first = focusable[0];
8484
- const last = focusable[focusable.length - 1];
8485
- if (!first || !last) {
8486
- return;
8490
+ pushPage(m);
8487
8491
  }
8488
- if (event.shiftKey) {
8489
- if (document.activeElement === first || !node.contains(document.activeElement)) {
8490
- event.preventDefault();
8491
- last.focus();
8492
- }
8493
- } else if (document.activeElement === last) {
8494
- event.preventDefault();
8495
- first.focus();
8492
+ }
8493
+ for (const n of endPages) {
8494
+ pushPage(n);
8495
+ }
8496
+ if (showPrevNext) {
8497
+ items.push({ type: "next", disabled: currentPage >= safePageCount });
8498
+ }
8499
+ if (showFirstLast) {
8500
+ items.push({ type: "last", disabled: currentPage >= safePageCount });
8501
+ }
8502
+ return items;
8503
+ }, [currentPage, safePageCount, siblingCount, boundaryCount, showFirstLast, showPrevNext]);
8504
+ return {
8505
+ page: currentPage,
8506
+ pages,
8507
+ canPrev: currentPage > 1,
8508
+ canNext: currentPage < safePageCount,
8509
+ goToPage,
8510
+ prev,
8511
+ next,
8512
+ first,
8513
+ last
8514
+ };
8515
+ }
8516
+ __name(usePagination, "usePagination");
8517
+ var TableContext = React.createContext({
8518
+ striped: false,
8519
+ compact: false,
8520
+ bordered: false,
8521
+ rowIndex: 0,
8522
+ setRowIndex: /* @__PURE__ */ __name(() => {
8523
+ }, "setRowIndex")
8524
+ });
8525
+ function buildTableCompound(parts) {
8526
+ return Object.assign(parts.Root, {
8527
+ Header: parts.Header,
8528
+ Body: parts.Body,
8529
+ Footer: parts.Footer,
8530
+ Row: parts.Row,
8531
+ HeaderCell: parts.HeaderCell,
8532
+ Cell: parts.Cell,
8533
+ Caption: parts.Caption
8534
+ });
8535
+ }
8536
+ __name(buildTableCompound, "buildTableCompound");
8537
+ var TableRoot = /* @__PURE__ */ __name(({ striped = false, compact = false, bordered = false, children, className, testID }) => {
8538
+ const [rowIndex, setRowIndex] = React.useState(0);
8539
+ const ctxValue = {
8540
+ striped,
8541
+ compact,
8542
+ bordered,
8543
+ rowIndex,
8544
+ setRowIndex
8545
+ };
8546
+ return /* @__PURE__ */ jsxRuntime.jsx(TableContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full overflow-auto", className), children: /* @__PURE__ */ jsxRuntime.jsx(
8547
+ "table",
8548
+ {
8549
+ className: cn(
8550
+ "w-full caption-bottom text-sm",
8551
+ bordered && "border border-semantic-border-default",
8552
+ className
8553
+ ),
8554
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8555
+ children
8556
+ }
8557
+ ) }) });
8558
+ }, "TableRoot");
8559
+ var TableHeader = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8560
+ "thead",
8561
+ {
8562
+ className: cn("[&_tr]:border-b [&_tr]:border-semantic-border-default", className),
8563
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8564
+ children
8565
+ }
8566
+ ), "TableHeader");
8567
+ var TableBody = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8568
+ "tbody",
8569
+ {
8570
+ className: cn("[&_tr:last-child]:border-0", className),
8571
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8572
+ children
8573
+ }
8574
+ ), "TableBody");
8575
+ var TableFooter = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8576
+ "tfoot",
8577
+ {
8578
+ className: cn("border-t border-semantic-border-default font-medium", className),
8579
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8580
+ children
8581
+ }
8582
+ ), "TableFooter");
8583
+ var TableRow = /* @__PURE__ */ __name(({ selected = false, onPress, children, className, testID }) => {
8584
+ const colors = useThemeColors();
8585
+ const handleClick = React.useCallback(() => {
8586
+ onPress?.();
8587
+ }, [onPress]);
8588
+ return /* @__PURE__ */ jsxRuntime.jsx(
8589
+ "tr",
8590
+ {
8591
+ className: cn(
8592
+ "border-b border-semantic-border-default transition-colors",
8593
+ onPress && "cursor-pointer hover:bg-semantic-background-subtle",
8594
+ selected && "bg-semantic-background-subtle",
8595
+ className
8596
+ ),
8597
+ style: selected ? { backgroundColor: colors.semantic.background.subtle } : void 0,
8598
+ onClick: onPress ? handleClick : void 0,
8599
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8600
+ children
8601
+ }
8602
+ );
8603
+ }, "TableRow");
8604
+ var TableHeaderCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8605
+ "th",
8606
+ {
8607
+ className: cn(
8608
+ "h-10 px-4 font-medium text-semantic-text-secondary",
8609
+ align === "right" && "text-right",
8610
+ align === "center" && "text-center",
8611
+ align === "left" && "text-left",
8612
+ className
8613
+ ),
8614
+ colSpan,
8615
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8616
+ children
8617
+ }
8618
+ ), "TableHeaderCell");
8619
+ var TableCell = /* @__PURE__ */ __name(({ align = "left", colSpan, children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8620
+ "td",
8621
+ {
8622
+ className: cn(
8623
+ "p-4 align-middle",
8624
+ align === "right" && "text-right",
8625
+ align === "center" && "text-center",
8626
+ align === "left" && "text-left",
8627
+ className
8628
+ ),
8629
+ colSpan,
8630
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8631
+ children
8632
+ }
8633
+ ), "TableCell");
8634
+ var TableCaption = /* @__PURE__ */ __name(({ children, className, testID }) => /* @__PURE__ */ jsxRuntime.jsx(
8635
+ "caption",
8636
+ {
8637
+ className: cn("mt-4 text-sm text-semantic-text-secondary", className),
8638
+ ...testID !== void 0 ? { "data-testid": testID } : {},
8639
+ children
8640
+ }
8641
+ ), "TableCaption");
8642
+ var Table = buildTableCompound({
8643
+ Root: TableRoot,
8644
+ Header: TableHeader,
8645
+ Body: TableBody,
8646
+ Footer: TableFooter,
8647
+ Row: TableRow,
8648
+ HeaderCell: TableHeaderCell,
8649
+ Cell: TableCell,
8650
+ Caption: TableCaption
8651
+ });
8652
+ function sortData(data, sort) {
8653
+ if (!sort) {
8654
+ return data;
8655
+ }
8656
+ const key = sort.id;
8657
+ return [...data].sort((a, b) => {
8658
+ const av = a[key];
8659
+ const bv = b[key];
8660
+ if (av == null && bv == null) {
8661
+ return 0;
8662
+ }
8663
+ if (av == null) {
8664
+ return 1;
8665
+ }
8666
+ if (bv == null) {
8667
+ return -1;
8668
+ }
8669
+ const cmp2 = av < bv ? -1 : av > bv ? 1 : 0;
8670
+ return sort.direction === "asc" ? cmp2 : -cmp2;
8671
+ });
8672
+ }
8673
+ __name(sortData, "sortData");
8674
+ function SortIndicator({ direction }) {
8675
+ if (direction === void 0) {
8676
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4, opacity: 0.3 }, children: "\u21C5" });
8677
+ }
8678
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { marginLeft: 4 }, children: direction === "asc" ? "\u2191" : "\u2193" });
8679
+ }
8680
+ __name(SortIndicator, "SortIndicator");
8681
+ function DataTable({
8682
+ data,
8683
+ columns,
8684
+ pageSize = 10,
8685
+ defaultSort,
8686
+ onRowPress,
8687
+ emptyState,
8688
+ striped,
8689
+ compact,
8690
+ bordered,
8691
+ testID,
8692
+ className
8693
+ }) {
8694
+ const [sort, setSort] = React.useState(defaultSort ?? null);
8695
+ const sorted = React.useMemo(() => sortData(data, sort), [data, sort]);
8696
+ const pageCount = Math.max(1, Math.ceil(sorted.length / pageSize));
8697
+ const { page, goToPage, canPrev, canNext } = usePagination({ pageCount, defaultPage: 1 });
8698
+ const pageSlice = React.useMemo(() => {
8699
+ const start = (page - 1) * pageSize;
8700
+ return sorted.slice(start, start + pageSize);
8701
+ }, [sorted, page, pageSize]);
8702
+ const handleSort = /* @__PURE__ */ __name((colId) => {
8703
+ setSort((prev) => {
8704
+ if (prev?.id !== colId) {
8705
+ goToPage(1);
8706
+ return { id: colId, direction: "asc" };
8496
8707
  }
8497
- }, "onKeyDown");
8498
- document.addEventListener("keydown", onKeyDown);
8499
- return () => {
8500
- document.removeEventListener("keydown", onKeyDown);
8501
- document.body.style.overflow = prevBodyOverflow;
8502
- const restoreTo = ctx.triggerRef.current ?? previouslyFocused;
8503
- restoreTo?.focus?.();
8504
- };
8505
- }, [ctx.open, ctx.setOpen, ctx.triggerRef]);
8506
- const onOverlayPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
8708
+ if (prev.direction === "asc") {
8709
+ return { id: colId, direction: "desc" };
8710
+ }
8711
+ goToPage(1);
8712
+ return null;
8713
+ });
8714
+ }, "handleSort");
8715
+ const tableProps = {};
8716
+ if (striped !== void 0) {
8717
+ tableProps.striped = striped;
8718
+ }
8719
+ if (compact !== void 0) {
8720
+ tableProps.compact = compact;
8721
+ }
8722
+ if (bordered !== void 0) {
8723
+ tableProps.bordered = bordered;
8724
+ }
8725
+ if (testID !== void 0) {
8726
+ tableProps.testID = testID;
8727
+ }
8728
+ if (className !== void 0) {
8729
+ tableProps.className = className;
8730
+ }
8731
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { width: "100%" }, children: [
8732
+ /* @__PURE__ */ jsxRuntime.jsxs(Table, { ...tableProps, children: [
8733
+ /* @__PURE__ */ jsxRuntime.jsx(Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: columns.map((col) => {
8734
+ const align = col.align;
8735
+ return /* @__PURE__ */ jsxRuntime.jsx(Table.HeaderCell, { ...align !== void 0 ? { align } : {}, children: col.sortable ? /* @__PURE__ */ jsxRuntime.jsxs(
8736
+ reactNative.Pressable,
8737
+ {
8738
+ accessibilityRole: "button",
8739
+ accessibilityLabel: `Sort by ${col.id}`,
8740
+ "aria-label": `Sort by ${col.id}`,
8741
+ onPress: () => handleSort(col.id),
8742
+ style: { flexDirection: "row", alignItems: "center" },
8743
+ children: [
8744
+ typeof col.header === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { children: col.header }) : col.header,
8745
+ /* @__PURE__ */ jsxRuntime.jsx(
8746
+ SortIndicator,
8747
+ {
8748
+ ...sort?.id === col.id ? { direction: sort.direction } : {}
8749
+ }
8750
+ )
8751
+ ]
8752
+ }
8753
+ ) : col.header }, col.id);
8754
+ }) }) }),
8755
+ /* @__PURE__ */ jsxRuntime.jsx(Table.Body, { children: pageSlice.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx(Table.Cell, { colSpan: columns.length, children: /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { children: emptyState ?? "No data" }) }) }) : pageSlice.map((row, i) => /* @__PURE__ */ jsxRuntime.jsx(
8756
+ Table.Row,
8757
+ {
8758
+ ...onRowPress !== void 0 ? { onPress: /* @__PURE__ */ __name(() => onRowPress(row), "onPress") } : {},
8759
+ children: columns.map((col) => {
8760
+ const colAlign = col.align;
8761
+ return /* @__PURE__ */ jsxRuntime.jsx(
8762
+ Table.Cell,
8763
+ {
8764
+ ...colAlign !== void 0 ? { align: colAlign } : {},
8765
+ children: col.cell(row)
8766
+ },
8767
+ col.id
8768
+ );
8769
+ })
8770
+ },
8771
+ i
8772
+ )) })
8773
+ ] }),
8774
+ pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(
8775
+ PaginationControls,
8776
+ {
8777
+ page,
8778
+ pageCount,
8779
+ canPrev,
8780
+ canNext,
8781
+ goToPage
8782
+ }
8783
+ )
8784
+ ] });
8785
+ }
8786
+ __name(DataTable, "DataTable");
8787
+ function EmptyState({ children }) {
8788
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { paddingVertical: 32, alignItems: "center" }, children: typeof children === "string" ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { color: "#888", fontSize: 14 }, children }) : children });
8789
+ }
8790
+ __name(EmptyState, "EmptyState");
8791
+ function PaginationControls({
8792
+ page,
8793
+ pageCount,
8794
+ canPrev,
8795
+ canNext,
8796
+ goToPage
8797
+ }) {
8507
8798
  return /* @__PURE__ */ jsxRuntime.jsxs(
8508
- reactNative.Modal,
8799
+ reactNative.View,
8509
8800
  {
8510
- visible: ctx.open,
8511
- transparent: true,
8512
- animationType: reactNative.Platform.OS === "web" ? "none" : "fade",
8513
- onRequestClose: () => ctx.setOpen(false),
8801
+ style: {
8802
+ flexDirection: "row",
8803
+ justifyContent: "flex-end",
8804
+ alignItems: "center",
8805
+ paddingVertical: 8,
8806
+ gap: 8
8807
+ },
8514
8808
  children: [
8515
- /* @__PURE__ */ jsxRuntime.jsx(BlurBackdrop, { intensity: 60, tint: scheme === "dark" ? "dark" : "light", style: reactNative.StyleSheet.absoluteFill }),
8516
8809
  /* @__PURE__ */ jsxRuntime.jsx(
8517
8810
  reactNative.Pressable,
8518
8811
  {
8519
- accessibilityRole: "none",
8520
- "aria-hidden": true,
8521
- ref: (node) => {
8522
- overlayDomRef.current = node;
8523
- },
8524
- style: overlayStyle,
8525
- onPress: onOverlayPress,
8526
- children: /* @__PURE__ */ jsxRuntime.jsx(
8527
- reactNative.Pressable,
8528
- {
8529
- onPress: (event) => event.stopPropagation?.(),
8530
- ref: (node) => {
8531
- contentRef.current = node;
8532
- },
8533
- role: "dialog",
8534
- accessibilityRole: "none",
8535
- "aria-modal": true,
8536
- "aria-labelledby": ctx.titleId,
8537
- "aria-describedby": ctx.descriptionId,
8538
- ...testID !== void 0 ? { testID } : {},
8539
- className: cn("w-full max-w-md rounded-xl bg-semantic-background-elevated p-6 gap-3", className),
8540
- style: [contentStyle, { backgroundColor: colors.semantic.background.elevated }, enterStyle],
8541
- children: /* @__PURE__ */ jsxRuntime.jsx(
8542
- reactNative.View,
8543
- {
8544
- className: "flex-col gap-1.5",
8545
- style: { flexDirection: "column", gap: px(colors.spacing["2"]) - 2 },
8546
- children
8547
- }
8548
- )
8549
- }
8550
- )
8812
+ onPress: canPrev ? () => goToPage(page - 1) : void 0,
8813
+ accessibilityRole: "button",
8814
+ accessibilityLabel: "Previous page",
8815
+ "aria-label": "Previous page",
8816
+ "aria-disabled": !canPrev,
8817
+ style: { opacity: canPrev ? 1 : 0.4, paddingHorizontal: 8 },
8818
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "\u2039 Prev" })
8819
+ }
8820
+ ),
8821
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: { fontSize: 14 }, "aria-live": "polite", children: [
8822
+ page,
8823
+ " / ",
8824
+ pageCount
8825
+ ] }),
8826
+ /* @__PURE__ */ jsxRuntime.jsx(
8827
+ reactNative.Pressable,
8828
+ {
8829
+ onPress: canNext ? () => goToPage(page + 1) : void 0,
8830
+ accessibilityRole: "button",
8831
+ accessibilityLabel: "Next page",
8832
+ "aria-label": "Next page",
8833
+ "aria-disabled": !canNext,
8834
+ style: { opacity: canNext ? 1 : 0.4, paddingHorizontal: 8 },
8835
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: { fontSize: 14 }, children: "Next \u203A" })
8551
8836
  }
8552
8837
  )
8553
8838
  ]
8554
8839
  }
8555
8840
  );
8556
- }, "DialogContent");
8557
- var DialogTitle = /* @__PURE__ */ __name(({ children, className }) => {
8558
- const ctx = useDialogContext("DialogTitle");
8559
- const colors = useThemeColors();
8560
- return /* @__PURE__ */ jsxRuntime.jsx(
8561
- reactNative.Text,
8562
- {
8563
- nativeID: ctx.titleId,
8564
- id: ctx.titleId,
8565
- role: "heading",
8566
- "aria-level": 2,
8567
- className: cn("text-lg font-semibold text-semantic-text-default", className),
8568
- style: {
8569
- color: colors.semantic.text.default,
8570
- fontFamily: colors.fontFamily.display,
8571
- fontSize: px(colors.fontSize.lg),
8572
- fontWeight: colors.fontWeight.semibold
8573
- },
8574
- children
8575
- }
8841
+ }
8842
+ __name(PaginationControls, "PaginationControls");
8843
+ function formatDate(date$1, locale) {
8844
+ try {
8845
+ return new Intl.DateTimeFormat(locale, { dateStyle: "medium" }).format(date$1.toDate(date.getLocalTimeZone()));
8846
+ } catch {
8847
+ return `${date$1.year}-${String(date$1.month).padStart(2, "0")}-${String(date$1.day).padStart(2, "0")}`;
8848
+ }
8849
+ }
8850
+ __name(formatDate, "formatDate");
8851
+ function CalendarIcon({ size = 16, color = "currentColor" }) {
8852
+ const colors = useThemeColors();
8853
+ if (reactNative.Platform.OS === "web") {
8854
+ return /* @__PURE__ */ jsxRuntime.jsx(
8855
+ "svg",
8856
+ {
8857
+ width: size,
8858
+ height: size,
8859
+ viewBox: "0 0 24 24",
8860
+ fill: "none",
8861
+ stroke: color,
8862
+ strokeWidth: "2",
8863
+ strokeLinecap: "round",
8864
+ strokeLinejoin: "round",
8865
+ "aria-hidden": "true",
8866
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8 2v4M16 2v4M3 10h18M5 4h14a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" })
8867
+ }
8868
+ );
8869
+ }
8870
+ const resolvedColor = color === "currentColor" ? colors.semantic.text.muted : color;
8871
+ return /* @__PURE__ */ jsxRuntime.jsx(
8872
+ reactNative.Text,
8873
+ {
8874
+ accessibilityElementsHidden: true,
8875
+ importantForAccessibility: "no-hide-descendants",
8876
+ style: { fontSize: size, lineHeight: size, color: resolvedColor },
8877
+ children: "\u{1F4C5}"
8878
+ }
8879
+ );
8880
+ }
8881
+ __name(CalendarIcon, "CalendarIcon");
8882
+ function buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek) {
8883
+ const out = {};
8884
+ if (minValue !== void 0) {
8885
+ out.minValue = minValue;
8886
+ }
8887
+ if (maxValue !== void 0) {
8888
+ out.maxValue = maxValue;
8889
+ }
8890
+ if (isDateUnavailable !== void 0) {
8891
+ out.isDateUnavailable = isDateUnavailable;
8892
+ }
8893
+ if (firstDayOfWeek !== void 0) {
8894
+ out.firstDayOfWeek = firstDayOfWeek;
8895
+ }
8896
+ return out;
8897
+ }
8898
+ __name(buildCalendarOptional, "buildCalendarOptional");
8899
+ function buildTriggerAriaProps(ariaProps) {
8900
+ const out = {};
8901
+ if (ariaProps["aria-labelledby"] !== void 0) {
8902
+ out["aria-labelledby"] = ariaProps["aria-labelledby"];
8903
+ }
8904
+ if (ariaProps["aria-describedby"] !== void 0) {
8905
+ out["aria-describedby"] = ariaProps["aria-describedby"];
8906
+ }
8907
+ if (ariaProps["aria-invalid"] !== void 0) {
8908
+ out["aria-invalid"] = ariaProps["aria-invalid"];
8909
+ }
8910
+ if (ariaProps["aria-required"] !== void 0) {
8911
+ out["aria-required"] = ariaProps["aria-required"];
8912
+ }
8913
+ return out;
8914
+ }
8915
+ __name(buildTriggerAriaProps, "buildTriggerAriaProps");
8916
+ var DatePickerRoot = /* @__PURE__ */ __name(({
8917
+ value,
8918
+ defaultValue: defaultValue2,
8919
+ onChange,
8920
+ locale: localeProp,
8921
+ minValue,
8922
+ maxValue,
8923
+ isDateUnavailable,
8924
+ firstDayOfWeek,
8925
+ placeholder,
8926
+ disabled = false,
8927
+ id,
8928
+ name: _name,
8929
+ className,
8930
+ testID,
8931
+ ...ariaProps
8932
+ }) => {
8933
+ const providerLocale = useLocale();
8934
+ const locale = localeProp ?? providerLocale;
8935
+ const [open, setOpen] = React.useState(false);
8936
+ const isControlled = value !== void 0;
8937
+ const [inner, setInner] = React.useState(defaultValue2 ?? null);
8938
+ const current = isControlled ? value ?? null : inner;
8939
+ const handleChange = React.useCallback(
8940
+ (date) => {
8941
+ if (!isControlled) {
8942
+ setInner(date);
8943
+ }
8944
+ onChange?.(date);
8945
+ setOpen(false);
8946
+ },
8947
+ [isControlled, onChange]
8948
+ );
8949
+ const handleOpenChange = React.useCallback(
8950
+ (next) => {
8951
+ if (!disabled) {
8952
+ setOpen(next);
8953
+ }
8954
+ },
8955
+ [disabled]
8576
8956
  );
8577
- }, "DialogTitle");
8578
- var DialogDescription = /* @__PURE__ */ __name(({ children, className }) => {
8579
- const ctx = useDialogContext("DialogDescription");
8957
+ const displayValue = current ? formatDate(current, locale) : null;
8958
+ const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
8959
+ const triggerAriaProps = buildTriggerAriaProps(ariaProps);
8580
8960
  const colors = useThemeColors();
8581
- return /* @__PURE__ */ jsxRuntime.jsx(
8582
- reactNative.Text,
8583
- {
8584
- nativeID: ctx.descriptionId,
8585
- id: ctx.descriptionId,
8586
- className: cn("text-sm text-semantic-text-muted", className),
8587
- style: {
8588
- color: colors.semantic.text.muted,
8589
- fontFamily: colors.fontFamily.body,
8590
- fontSize: px(colors.fontSize.sm),
8591
- lineHeight: px(colors.fontSize.sm) * Number(colors.lineHeight.normal)
8592
- },
8593
- children
8594
- }
8595
- );
8596
- }, "DialogDescription");
8597
- var DialogClose = /* @__PURE__ */ __name(({
8598
- asChild = true,
8599
- children,
8961
+ const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
8962
+ const pressableStyle = {
8963
+ flexDirection: "row",
8964
+ alignItems: "center",
8965
+ borderWidth: 1,
8966
+ borderRadius: px(colors.radius.md),
8967
+ paddingHorizontal: px(colors.spacing["3"]),
8968
+ paddingVertical: px(colors.spacing["2"]),
8969
+ backgroundColor: colors.semantic.background.elevated,
8970
+ borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
8971
+ opacity: disabled ? 0.6 : 1
8972
+ };
8973
+ const textStyle = {
8974
+ flex: 1,
8975
+ fontFamily: colors.fontFamily.body,
8976
+ fontSize: px(colors.fontSize.md),
8977
+ color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
8978
+ };
8979
+ const triggerExtraProps = {
8980
+ role: "combobox",
8981
+ accessibilityRole: "button",
8982
+ "aria-haspopup": "dialog",
8983
+ "aria-expanded": open,
8984
+ ...triggerAriaProps
8985
+ };
8986
+ if (id !== void 0) {
8987
+ triggerExtraProps.id = id;
8988
+ triggerExtraProps.nativeID = id;
8989
+ }
8990
+ if (testID !== void 0) {
8991
+ triggerExtraProps.testID = testID;
8992
+ }
8993
+ if (hasError) {
8994
+ triggerExtraProps["aria-invalid"] = true;
8995
+ }
8996
+ if (ariaProps["aria-required"]) {
8997
+ triggerExtraProps["aria-required"] = true;
8998
+ }
8999
+ if (disabled) {
9000
+ triggerExtraProps["aria-disabled"] = true;
9001
+ }
9002
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
9003
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
9004
+ reactNative.Pressable,
9005
+ {
9006
+ onPress: disabled ? void 0 : () => setOpen(!open),
9007
+ disabled,
9008
+ className: cn(
9009
+ "flex-row items-center rounded-md border px-3 py-2",
9010
+ hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
9011
+ disabled ? "opacity-60" : void 0,
9012
+ className
9013
+ ),
9014
+ style: pressableStyle,
9015
+ ...triggerExtraProps,
9016
+ children: [
9017
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
9018
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
9019
+ ]
9020
+ }
9021
+ ) }),
9022
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
9023
+ Calendar,
9024
+ {
9025
+ mode: "single",
9026
+ value: current,
9027
+ onChange: (date) => {
9028
+ handleChange(date);
9029
+ },
9030
+ locale,
9031
+ ...calendarOptional
9032
+ }
9033
+ ) })
9034
+ ] });
9035
+ }, "DatePickerRoot");
9036
+ var DatePickerRange = /* @__PURE__ */ __name(({
9037
+ value,
9038
+ defaultValue: defaultValue2,
9039
+ onChange,
9040
+ locale: localeProp,
9041
+ minValue,
9042
+ maxValue,
9043
+ isDateUnavailable,
9044
+ firstDayOfWeek,
9045
+ placeholder,
9046
+ disabled = false,
9047
+ id,
9048
+ name: _name,
8600
9049
  className,
8601
9050
  testID,
8602
- accessibilityLabel = "Close"
9051
+ ...ariaProps
8603
9052
  }) => {
8604
- const ctx = useDialogContext("DialogClose");
8605
- const colors = useThemeColors();
8606
- const onPress = React.useCallback(() => ctx.setOpen(false), [ctx]);
8607
- if (asChild && React.isValidElement(children)) {
8608
- const child = children;
8609
- const fire = /* @__PURE__ */ __name((existing) => (event) => {
8610
- existing?.(event);
8611
- ctx.setOpen(false);
8612
- }, "fire");
8613
- return /* @__PURE__ */ jsxRuntime.jsx(
8614
- Slot,
8615
- {
8616
- onClick: fire(child.props.onClick),
8617
- onPress: fire(child.props.onPress),
8618
- ...testID !== void 0 ? { "data-testid": testID } : {},
8619
- ...className !== void 0 ? { className } : {},
8620
- children: child
9053
+ const providerLocale = useLocale();
9054
+ const locale = localeProp ?? providerLocale;
9055
+ const [open, setOpen] = React.useState(false);
9056
+ const isControlled = value !== void 0;
9057
+ const [inner, setInner] = React.useState(defaultValue2 ?? { start: null, end: null });
9058
+ const current = isControlled ? value ?? { start: null, end: null } : inner;
9059
+ const calendarValue = current.start !== null ? { start: current.start, end: current.end } : null;
9060
+ const handleChange = React.useCallback(
9061
+ (calRange) => {
9062
+ const next = {
9063
+ start: calRange?.start ?? null,
9064
+ end: calRange?.end ?? null
9065
+ };
9066
+ if (!isControlled) {
9067
+ setInner(next);
8621
9068
  }
8622
- );
9069
+ onChange?.(next);
9070
+ if (next.start !== null && next.end !== null) {
9071
+ setOpen(false);
9072
+ }
9073
+ },
9074
+ [isControlled, onChange]
9075
+ );
9076
+ const handleOpenChange = React.useCallback(
9077
+ (next) => {
9078
+ if (!disabled) {
9079
+ setOpen(next);
9080
+ }
9081
+ },
9082
+ [disabled]
9083
+ );
9084
+ let displayValue = null;
9085
+ if (current.start !== null) {
9086
+ const startStr = formatDate(current.start, locale);
9087
+ const endStr = current.end !== null ? formatDate(current.end, locale) : "";
9088
+ displayValue = `${startStr} \u2013 ${endStr}`;
9089
+ }
9090
+ const calendarOptional = buildCalendarOptional(minValue, maxValue, isDateUnavailable, firstDayOfWeek);
9091
+ const triggerAriaProps = buildTriggerAriaProps(ariaProps);
9092
+ const colors = useThemeColors();
9093
+ const hasError = ariaProps["aria-invalid"] === true || ariaProps["aria-invalid"] === "true";
9094
+ const pressableStyle = {
9095
+ flexDirection: "row",
9096
+ alignItems: "center",
9097
+ borderWidth: 1,
9098
+ borderRadius: px(colors.radius.md),
9099
+ paddingHorizontal: px(colors.spacing["3"]),
9100
+ paddingVertical: px(colors.spacing["2"]),
9101
+ backgroundColor: colors.semantic.background.elevated,
9102
+ borderColor: hasError ? colors.color.danger : colors.semantic.border.default,
9103
+ opacity: disabled ? 0.6 : 1
9104
+ };
9105
+ const textStyle = {
9106
+ flex: 1,
9107
+ fontFamily: colors.fontFamily.body,
9108
+ fontSize: px(colors.fontSize.md),
9109
+ color: displayValue ? colors.semantic.text.default : colors.semantic.text.muted
9110
+ };
9111
+ const triggerExtraProps = {
9112
+ role: "combobox",
9113
+ accessibilityRole: "button",
9114
+ "aria-haspopup": "dialog",
9115
+ "aria-expanded": open,
9116
+ ...triggerAriaProps
9117
+ };
9118
+ if (id !== void 0) {
9119
+ triggerExtraProps.id = id;
9120
+ triggerExtraProps.nativeID = id;
9121
+ }
9122
+ if (testID !== void 0) {
9123
+ triggerExtraProps.testID = testID;
9124
+ }
9125
+ if (hasError) {
9126
+ triggerExtraProps["aria-invalid"] = true;
8623
9127
  }
8624
- if (children !== void 0) {
8625
- return /* @__PURE__ */ jsxRuntime.jsx(
9128
+ if (ariaProps["aria-required"]) {
9129
+ triggerExtraProps["aria-required"] = true;
9130
+ }
9131
+ if (disabled) {
9132
+ triggerExtraProps["aria-disabled"] = true;
9133
+ }
9134
+ return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange: handleOpenChange, children: [
9135
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Trigger, { asChild: false, className: cn(className), children: /* @__PURE__ */ jsxRuntime.jsxs(
8626
9136
  reactNative.Pressable,
8627
9137
  {
8628
- onPress,
8629
- role: "button",
8630
- accessibilityRole: "button",
8631
- accessibilityLabel,
8632
- "aria-label": accessibilityLabel,
8633
- ...testID !== void 0 ? { testID } : {},
8634
- ...className !== void 0 ? { className } : {},
8635
- children: wrapStringChildren4(children)
9138
+ onPress: disabled ? void 0 : () => setOpen(!open),
9139
+ disabled,
9140
+ className: cn(
9141
+ "flex-row items-center rounded-md border px-3 py-2",
9142
+ hasError ? "border-semantic-interactive-destructive" : "border-semantic-border-default",
9143
+ disabled ? "opacity-60" : void 0,
9144
+ className
9145
+ ),
9146
+ style: pressableStyle,
9147
+ ...triggerExtraProps,
9148
+ children: [
9149
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, numberOfLines: 1, children: displayValue ?? placeholder ?? "" }),
9150
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { marginLeft: px(colors.spacing["2"]) }, children: /* @__PURE__ */ jsxRuntime.jsx(CalendarIcon, { size: 16, color: colors.semantic.text.muted }) })
9151
+ ]
8636
9152
  }
8637
- );
8638
- }
8639
- return /* @__PURE__ */ jsxRuntime.jsx(
8640
- reactNative.Pressable,
8641
- {
8642
- onPress,
8643
- role: "button",
8644
- accessibilityRole: "button",
8645
- accessibilityLabel,
8646
- "aria-label": accessibilityLabel,
8647
- ...testID !== void 0 ? { testID } : {},
8648
- className: cn("absolute right-3 top-3 w-8 h-8 items-center justify-center rounded-md", className),
8649
- style: {
8650
- position: "absolute",
8651
- right: px(colors.spacing["3"]),
8652
- top: px(colors.spacing["3"]),
8653
- // 32×32 close hit target — component-density literal — not from theme
8654
- width: 32,
8655
- height: 32,
8656
- alignItems: "center",
8657
- justifyContent: "center",
8658
- borderRadius: px(colors.radius.md)
8659
- },
8660
- children: /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.close, { size: 18, color: colors.semantic.text.muted })
8661
- }
8662
- );
8663
- }, "DialogClose");
8664
- var DialogFooter = /* @__PURE__ */ __name(({ children, className }) => {
8665
- const colors = useThemeColors();
8666
- return /* @__PURE__ */ jsxRuntime.jsx(
8667
- reactNative.View,
8668
- {
8669
- className: cn("mt-4 flex-row items-center justify-end gap-2", className),
8670
- style: {
8671
- marginTop: px(colors.spacing["4"]),
8672
- flexDirection: "row",
8673
- alignItems: "center",
8674
- justifyContent: "flex-end",
8675
- gap: px(colors.spacing["2"])
8676
- },
8677
- children
8678
- }
8679
- );
8680
- }, "DialogFooter");
8681
- var Dialog = Object.assign(DialogRoot, {
8682
- Trigger: DialogTrigger,
8683
- Content: DialogContent,
8684
- Title: DialogTitle,
8685
- Description: DialogDescription,
8686
- Footer: DialogFooter,
8687
- Close: DialogClose
9153
+ ) }),
9154
+ /* @__PURE__ */ jsxRuntime.jsx(Popover.Content, { "aria-label": "Date range picker", side: "bottom", align: "start", children: /* @__PURE__ */ jsxRuntime.jsx(
9155
+ Calendar,
9156
+ {
9157
+ mode: "range",
9158
+ value: calendarValue,
9159
+ onChange: (range2) => {
9160
+ handleChange(range2);
9161
+ },
9162
+ locale,
9163
+ ...calendarOptional
9164
+ }
9165
+ ) })
9166
+ ] });
9167
+ }, "DatePickerRange");
9168
+ var DatePicker = Object.assign(DatePickerRoot, {
9169
+ Range: DatePickerRange
8688
9170
  });
8689
9171
  var Empty = /* @__PURE__ */ __name(({ icon, title, description, action, className, testID }) => {
8690
9172
  const colors = useThemeColors();
@@ -12516,6 +12998,344 @@ function translateOffscreen(side) {
12516
12998
  }
12517
12999
  }
12518
13000
  __name(translateOffscreen, "translateOffscreen");
13001
+ var SidebarContext = React.createContext(null);
13002
+ function useSidebarContext(caller) {
13003
+ const ctx = React.useContext(SidebarContext);
13004
+ if (!ctx) {
13005
+ throw new Error(`<${caller}> must be rendered inside <Sidebar>.`);
13006
+ }
13007
+ return ctx;
13008
+ }
13009
+ __name(useSidebarContext, "useSidebarContext");
13010
+ var EXPANDED_WIDTH = 240;
13011
+ var COLLAPSED_WIDTH = 56;
13012
+ var SidebarRoot = /* @__PURE__ */ __name(({
13013
+ collapsed,
13014
+ defaultCollapsed = false,
13015
+ onCollapsedChange,
13016
+ side = "left",
13017
+ variant = "standard",
13018
+ children,
13019
+ className,
13020
+ testID
13021
+ }) => {
13022
+ const [inner, setInner] = React.useState(defaultCollapsed);
13023
+ const isControlled = collapsed !== void 0;
13024
+ const current = isControlled ? collapsed : inner;
13025
+ const navId = React.useId();
13026
+ const colors = useThemeColors();
13027
+ const setCollapsed = React.useCallback(
13028
+ (next) => {
13029
+ if (!isControlled) {
13030
+ setInner(next);
13031
+ }
13032
+ onCollapsedChange?.(next);
13033
+ },
13034
+ [isControlled, onCollapsedChange]
13035
+ );
13036
+ const toggleCollapsed = React.useCallback(() => {
13037
+ setCollapsed(!current);
13038
+ }, [current, setCollapsed]);
13039
+ const ctxValue = {
13040
+ collapsed: current,
13041
+ setCollapsed,
13042
+ toggleCollapsed,
13043
+ navId
13044
+ };
13045
+ const width = current ? COLLAPSED_WIDTH : EXPANDED_WIDTH;
13046
+ const containerStyle = reactNative.Platform.OS === "web" ? {
13047
+ position: "fixed",
13048
+ top: 0,
13049
+ bottom: 0,
13050
+ [side]: 0,
13051
+ width,
13052
+ transitionProperty: "width",
13053
+ transitionDuration: "200ms",
13054
+ transitionTimingFunction: "cubic-bezier(0.16, 1, 0.3, 1)",
13055
+ display: "flex",
13056
+ flexDirection: "column",
13057
+ overflow: "hidden",
13058
+ zIndex: 40
13059
+ } : {
13060
+ width,
13061
+ flexDirection: "column",
13062
+ overflow: "hidden"
13063
+ };
13064
+ const variantStyle = reactNative.Platform.OS === "web" ? variant === "floating" ? {
13065
+ margin: 8,
13066
+ borderRadius: colors.radius.lg,
13067
+ top: 8,
13068
+ bottom: 8,
13069
+ height: "auto"
13070
+ } : variant === "inset" ? {
13071
+ boxShadow: "4px 0 16px rgba(0,0,0,0.08)"
13072
+ } : {} : {};
13073
+ const rootStyle = {
13074
+ ...containerStyle,
13075
+ ...variantStyle,
13076
+ backgroundColor: colors.semantic.background.elevated,
13077
+ borderRightWidth: variant !== "floating" ? 1 : 0,
13078
+ borderRightColor: colors.semantic.border.default
13079
+ };
13080
+ if (reactNative.Platform.OS === "web") {
13081
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx(
13082
+ "nav",
13083
+ {
13084
+ id: navId,
13085
+ "aria-label": "Sidebar",
13086
+ "data-collapsed": current,
13087
+ "data-side": side,
13088
+ "data-variant": variant,
13089
+ "data-testid": testID,
13090
+ className: cn(
13091
+ "nori-sidebar flex flex-col overflow-hidden transition-[width] duration-200",
13092
+ className
13093
+ ),
13094
+ style: rootStyle,
13095
+ children
13096
+ }
13097
+ ) });
13098
+ }
13099
+ return /* @__PURE__ */ jsxRuntime.jsx(SidebarContext.Provider, { value: ctxValue, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: rootStyle, testID, accessibilityRole: "menu", accessibilityLabel: "Sidebar", children }) });
13100
+ }, "SidebarRoot");
13101
+ var SidebarHeader = /* @__PURE__ */ __name(({ children, className, testID }) => {
13102
+ const colors = useThemeColors();
13103
+ const style = {
13104
+ padding: px(colors.spacing["4"]),
13105
+ borderBottomWidth: 1,
13106
+ borderBottomColor: colors.semantic.border.default,
13107
+ flexDirection: "row",
13108
+ alignItems: "center",
13109
+ gap: px(colors.spacing["2"]),
13110
+ overflow: "hidden"
13111
+ };
13112
+ if (reactNative.Platform.OS === "web") {
13113
+ return /* @__PURE__ */ jsxRuntime.jsx(
13114
+ "div",
13115
+ {
13116
+ "data-testid": testID,
13117
+ className: cn("nori-sidebar-header", className),
13118
+ style,
13119
+ children
13120
+ }
13121
+ );
13122
+ }
13123
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13124
+ }, "SidebarHeader");
13125
+ var SidebarContent = /* @__PURE__ */ __name(({ children, className, testID }) => {
13126
+ const style = { flex: 1, overflow: "hidden" };
13127
+ if (reactNative.Platform.OS === "web") {
13128
+ return /* @__PURE__ */ jsxRuntime.jsx(
13129
+ "div",
13130
+ {
13131
+ "data-testid": testID,
13132
+ className: cn("nori-sidebar-content", className),
13133
+ style: { flex: 1, overflowY: "auto", overflowX: "hidden" },
13134
+ children
13135
+ }
13136
+ );
13137
+ }
13138
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.ScrollView, { style, testID, contentContainerStyle: { flexGrow: 1 }, children });
13139
+ }, "SidebarContent");
13140
+ var SidebarFooter = /* @__PURE__ */ __name(({ children, className, testID }) => {
13141
+ const colors = useThemeColors();
13142
+ const style = {
13143
+ padding: px(colors.spacing["4"]),
13144
+ borderTopWidth: 1,
13145
+ borderTopColor: colors.semantic.border.default,
13146
+ overflow: "hidden"
13147
+ };
13148
+ if (reactNative.Platform.OS === "web") {
13149
+ return /* @__PURE__ */ jsxRuntime.jsx(
13150
+ "div",
13151
+ {
13152
+ "data-testid": testID,
13153
+ className: cn("nori-sidebar-footer", className),
13154
+ style,
13155
+ children
13156
+ }
13157
+ );
13158
+ }
13159
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13160
+ }, "SidebarFooter");
13161
+ var SidebarGroup = /* @__PURE__ */ __name(({ children, className, testID }) => {
13162
+ const colors = useThemeColors();
13163
+ const style = {
13164
+ paddingTop: px(colors.spacing["2"]),
13165
+ paddingBottom: px(colors.spacing["2"])
13166
+ };
13167
+ if (reactNative.Platform.OS === "web") {
13168
+ return /* @__PURE__ */ jsxRuntime.jsx(
13169
+ "div",
13170
+ {
13171
+ "data-testid": testID,
13172
+ className: cn("nori-sidebar-group", className),
13173
+ style,
13174
+ children
13175
+ }
13176
+ );
13177
+ }
13178
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13179
+ }, "SidebarGroup");
13180
+ var SidebarGroupLabel = /* @__PURE__ */ __name(({ children, className, testID }) => {
13181
+ const ctx = useSidebarContext("Sidebar.GroupLabel");
13182
+ const colors = useThemeColors();
13183
+ if (ctx.collapsed) {
13184
+ return null;
13185
+ }
13186
+ const style = {
13187
+ paddingHorizontal: px(colors.spacing["4"]),
13188
+ paddingVertical: px(colors.spacing["1"])
13189
+ };
13190
+ const textStyle = {
13191
+ fontSize: 11,
13192
+ fontWeight: "600",
13193
+ letterSpacing: 0.5,
13194
+ textTransform: "uppercase",
13195
+ color: colors.semantic.text.muted
13196
+ };
13197
+ if (reactNative.Platform.OS === "web") {
13198
+ return /* @__PURE__ */ jsxRuntime.jsx(
13199
+ "div",
13200
+ {
13201
+ "data-testid": testID,
13202
+ className: cn("nori-sidebar-group-label", className),
13203
+ style,
13204
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: textStyle, children })
13205
+ }
13206
+ );
13207
+ }
13208
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: textStyle, children }) });
13209
+ }, "SidebarGroupLabel");
13210
+ var SidebarMenu = /* @__PURE__ */ __name(({ children, className, testID }) => {
13211
+ const colors = useThemeColors();
13212
+ const style = {
13213
+ paddingHorizontal: px(colors.spacing["2"]),
13214
+ gap: px(colors.spacing["1"])
13215
+ };
13216
+ if (reactNative.Platform.OS === "web") {
13217
+ return /* @__PURE__ */ jsxRuntime.jsx(
13218
+ "ul",
13219
+ {
13220
+ "data-testid": testID,
13221
+ className: cn("nori-sidebar-menu", className),
13222
+ style: {
13223
+ ...style,
13224
+ listStyle: "none",
13225
+ margin: 0,
13226
+ padding: `0 ${colors.spacing["2"]}px`
13227
+ },
13228
+ children
13229
+ }
13230
+ );
13231
+ }
13232
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style, testID, children });
13233
+ }, "SidebarMenu");
13234
+ var SidebarMenuItem = /* @__PURE__ */ __name(({
13235
+ icon,
13236
+ active = false,
13237
+ disabled = false,
13238
+ onPress,
13239
+ children,
13240
+ className,
13241
+ testID
13242
+ }) => {
13243
+ const ctx = useSidebarContext("Sidebar.MenuItem");
13244
+ const colors = useThemeColors();
13245
+ const itemStyle = {
13246
+ flexDirection: "row",
13247
+ alignItems: "center",
13248
+ borderRadius: px(colors.radius.md),
13249
+ paddingHorizontal: px(colors.spacing["3"]),
13250
+ paddingVertical: px(colors.spacing["2"]),
13251
+ gap: px(colors.spacing["3"]),
13252
+ opacity: disabled ? 0.5 : 1,
13253
+ ...ctx.collapsed ? { justifyContent: "center", paddingHorizontal: px(colors.spacing["2"]) } : {}
13254
+ };
13255
+ const activeBg = colors.semantic.interactive.primary;
13256
+ const labelStr = typeof children === "string" ? children : void 0;
13257
+ const labelTextStyle = {
13258
+ fontSize: 14,
13259
+ fontWeight: active ? "600" : "400",
13260
+ color: active ? colors.semantic.text.default : colors.semantic.text.muted,
13261
+ flex: 1
13262
+ };
13263
+ if (reactNative.Platform.OS === "web") {
13264
+ return /* @__PURE__ */ jsxRuntime.jsx("li", { style: { listStyle: "none" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
13265
+ "button",
13266
+ {
13267
+ type: "button",
13268
+ "data-testid": testID,
13269
+ "aria-current": active ? "page" : void 0,
13270
+ "aria-disabled": disabled,
13271
+ title: ctx.collapsed && labelStr ? labelStr : void 0,
13272
+ disabled,
13273
+ onClick: disabled ? void 0 : onPress,
13274
+ className: cn("nori-sidebar-menu-item", className),
13275
+ style: {
13276
+ display: "flex",
13277
+ alignItems: "center",
13278
+ gap: colors.spacing["3"],
13279
+ width: "100%",
13280
+ textAlign: "left",
13281
+ border: "none",
13282
+ cursor: disabled ? "not-allowed" : "pointer",
13283
+ borderRadius: colors.radius.md,
13284
+ padding: ctx.collapsed ? `${colors.spacing["2"]}px` : `${colors.spacing["2"]}px ${colors.spacing["3"]}px`,
13285
+ justifyContent: ctx.collapsed ? "center" : "flex-start",
13286
+ background: active ? `${activeBg}1a` : "transparent",
13287
+ opacity: disabled ? 0.5 : 1
13288
+ },
13289
+ children: [
13290
+ icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "nori-sidebar-menu-item-icon", "aria-hidden": "true", children: icon }),
13291
+ !ctx.collapsed && /* @__PURE__ */ jsxRuntime.jsx(
13292
+ "span",
13293
+ {
13294
+ style: {
13295
+ fontSize: 14,
13296
+ fontWeight: active ? 600 : 400,
13297
+ color: active ? colors.semantic.text.default : colors.semantic.text.muted,
13298
+ flex: 1,
13299
+ overflow: "hidden",
13300
+ whiteSpace: "nowrap",
13301
+ textOverflow: "ellipsis"
13302
+ },
13303
+ children
13304
+ }
13305
+ )
13306
+ ]
13307
+ }
13308
+ ) });
13309
+ }
13310
+ return /* @__PURE__ */ jsxRuntime.jsxs(
13311
+ reactNative.Pressable,
13312
+ {
13313
+ testID,
13314
+ onPress: disabled ? void 0 : onPress,
13315
+ disabled,
13316
+ accessibilityRole: "menuitem",
13317
+ accessibilityState: { selected: active, disabled },
13318
+ style: ({ pressed }) => [
13319
+ itemStyle,
13320
+ active ? { backgroundColor: `${activeBg}1a` } : {},
13321
+ pressed && { opacity: 0.7 }
13322
+ ],
13323
+ children: [
13324
+ icon && /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { children: icon }),
13325
+ !ctx.collapsed && /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: labelTextStyle, numberOfLines: 1, children })
13326
+ ]
13327
+ }
13328
+ );
13329
+ }, "SidebarMenuItem");
13330
+ var Sidebar = Object.assign(SidebarRoot, {
13331
+ Header: SidebarHeader,
13332
+ Content: SidebarContent,
13333
+ Footer: SidebarFooter,
13334
+ Group: SidebarGroup,
13335
+ GroupLabel: SidebarGroupLabel,
13336
+ Menu: SidebarMenu,
13337
+ MenuItem: SidebarMenuItem
13338
+ });
12519
13339
  var PULSE_DURATION_MS = 900;
12520
13340
  var PULSE_MIN = 0.55;
12521
13341
  var PULSE_MAX = 1;
@@ -14886,6 +15706,7 @@ exports.Carousel = Carousel;
14886
15706
  exports.Checkbox = Checkbox;
14887
15707
  exports.Collapsible = Collapsible;
14888
15708
  exports.Combobox = Combobox;
15709
+ exports.Command = Command;
14889
15710
  exports.ContextMenu = ContextMenu;
14890
15711
  exports.DataTable = DataTable;
14891
15712
  exports.DatePicker = DatePicker;
@@ -14928,6 +15749,7 @@ exports.SheetHeader = SheetHeader;
14928
15749
  exports.SheetPanel = SheetPanel;
14929
15750
  exports.SheetTitle = SheetTitle;
14930
15751
  exports.SheetTrigger = SheetTrigger;
15752
+ exports.Sidebar = Sidebar;
14931
15753
  exports.Skeleton = Skeleton;
14932
15754
  exports.Slider = Slider;
14933
15755
  exports.SliderGestureProvider = SliderGestureProvider;
@@ -14963,10 +15785,12 @@ exports.themeDark = themeDark;
14963
15785
  exports.toast = toast2;
14964
15786
  exports.useCalendarCaption = useCalendarCaption;
14965
15787
  exports.useColorScheme = useColorScheme;
15788
+ exports.useCommandContext = useCommandContext;
14966
15789
  exports.useLocale = useLocale;
14967
15790
  exports.usePagination = usePagination;
14968
15791
  exports.usePopoverContext = usePopoverContext;
14969
15792
  exports.useSemanticIcon = useSemanticIcon;
15793
+ exports.useSidebarContext = useSidebarContext;
14970
15794
  exports.useSliderInteractionActive = useSliderInteractionActive;
14971
15795
  exports.useTheme = useTheme;
14972
15796
  exports.useThemeColors = useThemeColors;