@exponential_app/eui-react 0.2.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  ChoiceTilesFrame2,
3
3
  choiceColumns2,
4
- choiceValues2
5
- } from "./chunks/index-5yzzfez5.js";
4
+ choiceValues2,
5
+ ZOOM_MATH2,
6
+ useZoomableImage2
7
+ } from "./chunks/index-eny7hh6w.js";
6
8
 
7
9
  // packages/exponential-ui-react/src/surface.tsx
8
- import { useCallback as useCallback11, useEffect as useEffect20, useId as useId7, useImperativeHandle as useImperativeHandle2, useLayoutEffect as useLayoutEffect6, useMemo as useMemo18, useRef as useRef25, useState as useState21, useSyncExternalStore as useSyncExternalStore3 } from "react";
10
+ import { useCallback as useCallback11, useEffect as useEffect22, useId as useId7, useImperativeHandle as useImperativeHandle2, useLayoutEffect as useLayoutEffect7, useMemo as useMemo19, useRef as useRef26, useState as useState22, useSyncExternalStore as useSyncExternalStore3 } from "react";
9
11
  import {
10
12
  activeBreakpoint,
11
13
  applyContrast,
@@ -117,7 +119,7 @@ function extensionComponent(extensions, component) {
117
119
  }
118
120
 
119
121
  // packages/exponential-ui-react/src/node-view.tsx
120
- import { Component, Fragment as Fragment7, memo as memo2, useCallback as useCallback10, useContext as useContext6, useEffect as useEffect19, useMemo as useMemo17, useRef as useRef24 } from "react";
122
+ import { Component, Fragment as Fragment8, memo as memo2, useCallback as useCallback10, useContext as useContext6, useEffect as useEffect21, useMemo as useMemo18, useRef as useRef25 } from "react";
121
123
  import { UNKNOWN_COMPONENT, instanceSegment, isResponsiveValue, nativeRecipeProps as nativeRecipeProps4, responsiveAt, templateItemKeys, templateSiteKey, withOwnWrites } from "@exponential_app/eui";
122
124
  import { dynamicStyleEntries, nodeClass, queryToken, styleDirection } from "@exponential_app/eui/web";
123
125
 
@@ -252,7 +254,8 @@ import {
252
254
  File,
253
255
  Hand,
254
256
  Info,
255
- Loader,
257
+ LoaderCircle,
258
+ Maximize2,
256
259
  Menu,
257
260
  Mic,
258
261
  MicOff,
@@ -261,6 +264,7 @@ import {
261
264
  PhoneIncoming,
262
265
  PhoneOff,
263
266
  Play,
267
+ Pause,
264
268
  Plus,
265
269
  QrCode,
266
270
  ScanLine,
@@ -288,8 +292,9 @@ var CHROME = {
288
292
  send: Send,
289
293
  stop: Square,
290
294
  play: Play,
295
+ pause: Pause,
291
296
  attach: Paperclip,
292
- spinner: Loader,
297
+ spinner: LoaderCircle,
293
298
  placeholder: CircleDashed
294
299
  };
295
300
  var FALLBACK_ICONS = {
@@ -321,6 +326,7 @@ var FALLBACK_ICONS = {
321
326
  "ui-scan": ScanLine,
322
327
  "ui-qr-code": QrCode,
323
328
  "ui-hold": Hand,
329
+ "ui-fullscreen": Maximize2,
324
330
  "voice-level": AudioLines,
325
331
  "call-mute": Mic,
326
332
  "call-unmute": MicOff,
@@ -631,7 +637,8 @@ function ButtonNative({ node, props, rootProps, emit, children }) {
631
637
  const label = str(props.label);
632
638
  const icon = str(props.icon);
633
639
  const loading = bool(props.loading) || pending || submit && form.busy;
634
- const disabled = bool(props.disabled) || loading;
640
+ const disabled = bool(props.disabled);
641
+ const inert = disabled || loading;
635
642
  const iconOnly = props.size === `icon`;
636
643
  const Spinner = CHROME.spinner;
637
644
  const hasChild = node.children.length > 0;
@@ -646,7 +653,7 @@ function ButtonNative({ node, props, rootProps, emit, children }) {
646
653
  });
647
654
  const rootStyle = rootProps.style;
648
655
  const hold = bool(props.hold);
649
- const { held, handlers } = useHold(hold, disabled, emit);
656
+ const { held, handlers } = useHold(hold, inert, emit);
650
657
  const holdingLabel = str(props.holdingLabel);
651
658
  const paintedLabel = held && holdingLabel ? holdingLabel : shownLabel;
652
659
  const states = [...ctx.states ?? [], disabled ? `disabled` : ``, pending ? `pending` : ``, held ? `pressed` : ``].filter(Boolean).join(` `);
@@ -665,7 +672,7 @@ function ButtonNative({ node, props, rootProps, emit, children }) {
665
672
  ...hold ? handlers : {},
666
673
  onClick: (e) => {
667
674
  e.stopPropagation();
668
- if (hold)
675
+ if (hold || inert)
669
676
  return;
670
677
  track(emit(`press`));
671
678
  if (submit)
@@ -966,12 +973,12 @@ function ChartNative({ node, props, rootProps }) {
966
973
  strokeLinejoin: "round",
967
974
  strokeLinecap: "round"
968
975
  }),
969
- !sparkline ? s.values.map((v, i) => Number.isFinite(v) ? /* @__PURE__ */ jsx5("circle", {
970
- cx: px(i),
971
- cy: y(v),
972
- r: active === i ? 4 : 2.5,
976
+ !sparkline && active !== null && Number.isFinite(s.values[active]) ? /* @__PURE__ */ jsx5("circle", {
977
+ cx: px(active),
978
+ cy: y(s.values[active]),
979
+ r: 4,
973
980
  fill: color
974
- }, i) : null) : null
981
+ }) : null
975
982
  ]
976
983
  }, si);
977
984
  });
@@ -1136,15 +1143,17 @@ function ChartNative({ node, props, rootProps }) {
1136
1143
  fill: "currentColor",
1137
1144
  fontSize: AXIS_FONT,
1138
1145
  children: [
1139
- /* @__PURE__ */ jsx5("line", {
1140
- x1: mx(pad.l),
1141
- x2: mx(width - pad.r),
1142
- y1: zero,
1143
- y2: zero,
1144
- stroke: "currentColor",
1145
- strokeWidth: 1,
1146
- opacity: 0.6,
1147
- shapeRendering: "crispEdges"
1146
+ /* @__PURE__ */ jsx5("g", {
1147
+ ...part(`grid`),
1148
+ children: /* @__PURE__ */ jsx5("line", {
1149
+ x1: mx(pad.l),
1150
+ x2: mx(width - pad.r),
1151
+ y1: zero,
1152
+ y2: zero,
1153
+ stroke: "currentColor",
1154
+ strokeWidth: 1,
1155
+ shapeRendering: "crispEdges"
1156
+ })
1148
1157
  }),
1149
1158
  ticks.ticks.map((t, i) => /* @__PURE__ */ jsx5("text", {
1150
1159
  x: mx(pad.l - 6),
@@ -2274,8 +2283,7 @@ function TimePickerNative({ node, props, rootProps, emit, scope, domId }) {
2274
2283
  out.push(m);
2275
2284
  return out;
2276
2285
  }, [lo, hi, step]);
2277
- const clock = useMemo8(() => new Intl.DateTimeFormat(ctx.locale, { hour: `numeric`, minute: `2-digit` }), [ctx.locale]);
2278
- const show = (m) => clock.format(new Date(2000, 0, 1, Math.floor(m / 60), m % 60));
2286
+ const show = formatHHmm;
2279
2287
  const current = parseTime(value);
2280
2288
  const pick = (i) => {
2281
2289
  const next = formatHHmm(times[i]);
@@ -2384,10 +2392,46 @@ function TimePickerNative({ node, props, rootProps, emit, scope, domId }) {
2384
2392
  });
2385
2393
  }
2386
2394
 
2395
+ // packages/exponential-ui-react/src/natives/motion.tsx
2396
+ import { useEffect as useEffect8, useLayoutEffect as useLayoutEffect3, useRef as useRef11 } from "react";
2397
+ import { MotionView, motionA11y, motionBoxStyle, motionDeclaredSize } from "@exponential_app/eui/web";
2398
+ import { jsx as jsx10 } from "react/jsx-runtime";
2399
+ var CANVAS_STYLE = { display: `block`, width: `100%`, height: `100%` };
2400
+ function MotionNative({ node, props, rootProps, emit }) {
2401
+ const ctx = useSurfaceContext();
2402
+ const root = useRef11(null);
2403
+ const canvas = useRef11(null);
2404
+ const view = useRef11(null);
2405
+ useLayoutEffect3(() => {
2406
+ view.current = new MotionView(root.current, canvas.current);
2407
+ return () => {
2408
+ view.current?.destroy();
2409
+ view.current = null;
2410
+ };
2411
+ }, []);
2412
+ const host = ctx.host;
2413
+ const surfaceId = ctx.surfaceId;
2414
+ const pressable = Boolean(node.on?.press);
2415
+ useEffect8(() => {
2416
+ view.current?.update(props, { theme: ctx.theme, mode: ctx.mode, reducedMotion: ctx.reducedMotion, host, onError: (message) => host.onPaintError?.({ surfaceId, componentId: node.id, message }), emit: (event, payload) => void emit(event, payload), pressable }, node.style);
2417
+ });
2418
+ return /* @__PURE__ */ jsx10("div", {
2419
+ ref: root,
2420
+ ...rootProps,
2421
+ ...motionA11y(props.label, pressable),
2422
+ style: mergeStyle(rootProps, motionBoxStyle(motionDeclaredSize(props), node.style)),
2423
+ children: /* @__PURE__ */ jsx10("canvas", {
2424
+ ref: canvas,
2425
+ "aria-hidden": "true",
2426
+ style: CANVAS_STYLE
2427
+ })
2428
+ });
2429
+ }
2430
+
2387
2431
  // packages/exponential-ui-react/src/natives/resizable.tsx
2388
- import { useMemo as useMemo9, useRef as useRef11, useState as useState11 } from "react";
2432
+ import { useMemo as useMemo9, useRef as useRef12, useState as useState11 } from "react";
2389
2433
  import { dragDelta, keyboardResize, normalizeSizes, resizePanels, RESIZE_HANDLE_HIT } from "@exponential_app/eui";
2390
- import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
2434
+ import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2391
2435
  var RESIZE_KEYS = new Set([`ArrowLeft`, `ArrowRight`, `ArrowUp`, `ArrowDown`, `Home`, `End`, `Enter`]);
2392
2436
  function ResizableNative({ node, props, rootProps, emit, scope, domId }) {
2393
2437
  const ctx = useSurfaceContext();
@@ -2398,11 +2442,11 @@ function ResizableNative({ node, props, rootProps, emit, scope, domId }) {
2398
2442
  const external = useMemo9(() => normalizeSizes(arr(props.sizes), count, limits), [props.sizes, count, limits]);
2399
2443
  const [sizes, setBound] = useBoundState(node, scope, `sizes`, external);
2400
2444
  const [live, setLive] = useState11(null);
2401
- const liveRef = useRef11(null);
2445
+ const liveRef = useRef12(null);
2402
2446
  const shown = live ?? (sizes.length === count ? sizes : external);
2403
2447
  const hairline = num(ctx.theme.tokens.control?.hairline, 1);
2404
- const rootRef = useRef11(null);
2405
- const drag = useRef11(null);
2448
+ const rootRef = useRef12(null);
2449
+ const drag = useRef12(null);
2406
2450
  const commit = (next) => {
2407
2451
  setBound(next);
2408
2452
  emit(`change`, { sizes: next }, { sizes: next });
@@ -2453,12 +2497,12 @@ function ResizableNative({ node, props, rootProps, emit, scope, domId }) {
2453
2497
  const parts = [];
2454
2498
  for (let i = 0;i < count; i++) {
2455
2499
  const size = shown[i] ?? 0;
2456
- parts.push(/* @__PURE__ */ jsx10("div", {
2500
+ parts.push(/* @__PURE__ */ jsx11("div", {
2457
2501
  ...part.at(`panel`, i),
2458
2502
  id: `${domId}.panel.${i}`,
2459
2503
  "data-size": size,
2460
2504
  style: { flex: `${size} 1 0px` },
2461
- children: /* @__PURE__ */ jsx10(NodeView, {
2505
+ children: /* @__PURE__ */ jsx11(NodeView, {
2462
2506
  node: node.children[i]
2463
2507
  })
2464
2508
  }, node.children[i].id));
@@ -2481,12 +2525,12 @@ function ResizableNative({ node, props, rootProps, emit, scope, domId }) {
2481
2525
  onPointerCancel: onPointerEnd,
2482
2526
  onKeyDown: onKey(i),
2483
2527
  children: [
2484
- /* @__PURE__ */ jsx10("span", {
2528
+ /* @__PURE__ */ jsx11("span", {
2485
2529
  className: "xui-resize-hit",
2486
2530
  "aria-hidden": "true",
2487
2531
  style: { [orientation === `horizontal` ? `width` : `height`]: RESIZE_HANDLE_HIT }
2488
2532
  }),
2489
- bool(props.handle) ? /* @__PURE__ */ jsx10("span", {
2533
+ bool(props.handle) ? /* @__PURE__ */ jsx11("span", {
2490
2534
  ...part.at(`grip`, i),
2491
2535
  "aria-hidden": "true"
2492
2536
  }) : null
@@ -2494,7 +2538,7 @@ function ResizableNative({ node, props, rootProps, emit, scope, domId }) {
2494
2538
  }, `h${i}`));
2495
2539
  }
2496
2540
  }
2497
- return /* @__PURE__ */ jsx10("div", {
2541
+ return /* @__PURE__ */ jsx11("div", {
2498
2542
  ref: rootRef,
2499
2543
  ...rootProps,
2500
2544
  role: "group",
@@ -2505,10 +2549,10 @@ function ResizableNative({ node, props, rootProps, emit, scope, domId }) {
2505
2549
  }
2506
2550
 
2507
2551
  // packages/exponential-ui-react/src/natives/feedback.tsx
2508
- import { useEffect as useEffect8, useLayoutEffect as useLayoutEffect3, useRef as useRef12 } from "react";
2552
+ import { useEffect as useEffect9, useLayoutEffect as useLayoutEffect4, useRef as useRef13 } from "react";
2509
2553
  import { resolveRecipe, nativeRecipeProps as nativeRecipeProps2, voiceWave, voiceWaveBars, voiceWaveChildBox, voiceWavePath, voiceWaveVariant, TREE_GUIDE_BRIDGE, TREE_GUIDE_COLUMN, TREE_GUIDE_RADIUS, VOICE_WAVE_ACTIVITIES } from "@exponential_app/eui";
2510
2554
  import { voiceWaveAnimates, voiceWaveClock, voiceWaveFitChild, voiceWaveName } from "@exponential_app/eui/web";
2511
- import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
2555
+ import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
2512
2556
  function sizeOf(ctx, component, part, props, fallback) {
2513
2557
  const style = resolveRecipe(ctx.theme, { component, part, props: nativeRecipeProps2(component, props, ctx.extensionDefs) }, ctx.mode);
2514
2558
  return typeof style.width === `number` ? style.width : fallback;
@@ -2538,7 +2582,7 @@ function RingNative({ node, props, rootProps }) {
2538
2582
  width: size,
2539
2583
  height: size,
2540
2584
  children: [
2541
- /* @__PURE__ */ jsx11("circle", {
2585
+ /* @__PURE__ */ jsx12("circle", {
2542
2586
  ...part(`track`),
2543
2587
  cx: size / 2,
2544
2588
  cy: size / 2,
@@ -2548,7 +2592,7 @@ function RingNative({ node, props, rootProps }) {
2548
2592
  strokeWidth: stroke,
2549
2593
  style: { color: String(trackStyle.color ?? `currentColor`) }
2550
2594
  }),
2551
- /* @__PURE__ */ jsx11("circle", {
2595
+ /* @__PURE__ */ jsx12("circle", {
2552
2596
  ...part(`fill`),
2553
2597
  cx: size / 2,
2554
2598
  cy: size / 2,
@@ -2563,7 +2607,7 @@ function RingNative({ node, props, rootProps }) {
2563
2607
  })
2564
2608
  ]
2565
2609
  }),
2566
- label ? /* @__PURE__ */ jsx11("span", {
2610
+ label ? /* @__PURE__ */ jsx12("span", {
2567
2611
  ...part(`label`),
2568
2612
  children: label
2569
2613
  }) : null
@@ -2575,12 +2619,12 @@ function SpinnerNative({ props, rootProps }) {
2575
2619
  const size = sizeOf(ctx, `Spinner`, `root`, props, 20);
2576
2620
  const Icon = CHROME.spinner;
2577
2621
  const label = str(props.label) || ctx.t(`loading`);
2578
- return /* @__PURE__ */ jsx11("span", {
2622
+ return /* @__PURE__ */ jsx12("span", {
2579
2623
  ...rootProps,
2580
2624
  role: "status",
2581
2625
  "aria-label": label,
2582
2626
  style: mergeStyle(rootProps, { width: size, height: size }),
2583
- children: /* @__PURE__ */ jsx11(Icon, {
2627
+ children: /* @__PURE__ */ jsx12(Icon, {
2584
2628
  "aria-hidden": "true"
2585
2629
  })
2586
2630
  });
@@ -2596,7 +2640,7 @@ function SkeletonNative({ node, props, rootProps }) {
2596
2640
  if (rows >= 1) {
2597
2641
  const dot = props.dot === undefined ? true : bool(props.dot);
2598
2642
  const height = props.rowHeight === undefined ? `var(--xui-control-row)` : `${num(props.rowHeight)}px`;
2599
- return /* @__PURE__ */ jsx11("div", {
2643
+ return /* @__PURE__ */ jsx12("div", {
2600
2644
  ...rootProps,
2601
2645
  "data-rows": "",
2602
2646
  "aria-hidden": "true",
@@ -2606,14 +2650,14 @@ function SkeletonNative({ node, props, rootProps }) {
2606
2650
  ...part.at(`row`, r),
2607
2651
  style: { height },
2608
2652
  children: [
2609
- dot ? /* @__PURE__ */ jsx11("span", {
2653
+ dot ? /* @__PURE__ */ jsx12("span", {
2610
2654
  ...part.at(`dot`, r)
2611
2655
  }) : null,
2612
- /* @__PURE__ */ jsx11("span", {
2656
+ /* @__PURE__ */ jsx12("span", {
2613
2657
  ...part.at(`bar`, `${r}.0`),
2614
2658
  style: { width: lead }
2615
2659
  }),
2616
- /* @__PURE__ */ jsx11("span", {
2660
+ /* @__PURE__ */ jsx12("span", {
2617
2661
  ...part.at(`bar`, `${r}.1`),
2618
2662
  "data-title": "",
2619
2663
  style: { width: title }
@@ -2625,7 +2669,7 @@ function SkeletonNative({ node, props, rootProps }) {
2625
2669
  }
2626
2670
  const width = str(props.width, `100%`);
2627
2671
  const height = str(props.height, `16px`);
2628
- return /* @__PURE__ */ jsx11("div", {
2672
+ return /* @__PURE__ */ jsx12("div", {
2629
2673
  ...rootProps,
2630
2674
  "aria-hidden": "true",
2631
2675
  style: mergeStyle(rootProps, { width, height, borderRadius: bool(props.rounded) ? 9999 : undefined })
@@ -2641,7 +2685,7 @@ function TreeGuidesNative({ node, props, rootProps }) {
2641
2685
  const stroke = sizeOf(ctx, `TreeGuides`, `line`, props, 1);
2642
2686
  const line = part(`line`);
2643
2687
  const x = TREE_GUIDE_COLUMN / 2;
2644
- const vertical = (key) => /* @__PURE__ */ jsx11("i", {
2688
+ const vertical = (key) => /* @__PURE__ */ jsx12("i", {
2645
2689
  ...line,
2646
2690
  "data-vertical": "",
2647
2691
  style: { left: x, width: stroke, top: -TREE_GUIDE_BRIDGE, bottom: 0 }
@@ -2656,7 +2700,7 @@ function TreeGuidesNative({ node, props, rootProps }) {
2656
2700
  children: [
2657
2701
  pass.has(i) && !elbow ? vertical(`p`) : null,
2658
2702
  elbow && tee ? vertical(`t`) : null,
2659
- elbow ? /* @__PURE__ */ jsx11("i", {
2703
+ elbow ? /* @__PURE__ */ jsx12("i", {
2660
2704
  ...line,
2661
2705
  "data-elbow": "",
2662
2706
  style: {
@@ -2672,7 +2716,7 @@ function TreeGuidesNative({ node, props, rootProps }) {
2672
2716
  ]
2673
2717
  }, i));
2674
2718
  }
2675
- return /* @__PURE__ */ jsx11("span", {
2719
+ return /* @__PURE__ */ jsx12("span", {
2676
2720
  ...rootProps,
2677
2721
  "aria-hidden": "true",
2678
2722
  "data-tee": tee ? `true` : undefined,
@@ -2680,9 +2724,9 @@ function TreeGuidesNative({ node, props, rootProps }) {
2680
2724
  });
2681
2725
  }
2682
2726
  function VoiceWaveNative(p) {
2683
- return voiceWaveVariant(p.props.variant) === `bars` ? /* @__PURE__ */ jsx11(VoiceWaveBarsNative, {
2727
+ return voiceWaveVariant(p.props.variant) === `bars` ? /* @__PURE__ */ jsx12(VoiceWaveBarsNative, {
2684
2728
  ...p
2685
- }) : /* @__PURE__ */ jsx11(VoiceWaveRingNative, {
2729
+ }) : /* @__PURE__ */ jsx12(VoiceWaveRingNative, {
2686
2730
  ...p
2687
2731
  });
2688
2732
  }
@@ -2691,12 +2735,12 @@ function VoiceWaveBarsNative({ node, props, rootProps, children }) {
2691
2735
  const part = useParts(node, props);
2692
2736
  const activity = VOICE_WAVE_ACTIVITIES.includes(str(props.activity)) ? str(props.activity) : `idle`;
2693
2737
  const input = { size: str(props.size, `md`), activity, level: num(props.level, 0), bands: arr(props.bands).map((b) => num(b, 0)), reducedMotion: ctx.reducedMotion };
2694
- const latest = useRef12(input);
2738
+ const latest = useRef13(input);
2695
2739
  latest.current = input;
2696
- const elapsed = useRef12(0);
2697
- const rects = useRef12([]);
2740
+ const elapsed = useRef13(0);
2741
+ const rects = useRef13([]);
2698
2742
  const animates = voiceWaveAnimates(activity) && !ctx.reducedMotion;
2699
- useEffect8(() => {
2743
+ useEffect9(() => {
2700
2744
  if (!animates) {
2701
2745
  elapsed.current = 0;
2702
2746
  return;
@@ -2723,13 +2767,13 @@ function VoiceWaveBarsNative({ node, props, rootProps, children }) {
2723
2767
  "data-variant": "bars",
2724
2768
  style: mergeStyle(rootProps, { width: meter.width, height: meter.height }),
2725
2769
  children: [
2726
- /* @__PURE__ */ jsx11("svg", {
2770
+ /* @__PURE__ */ jsx12("svg", {
2727
2771
  viewBox: `0 0 ${meter.width} ${meter.height}`,
2728
2772
  width: meter.width,
2729
2773
  height: meter.height,
2730
2774
  "aria-hidden": "true",
2731
2775
  style: { color: colour },
2732
- children: meter.bars.map((bar, i) => /* @__PURE__ */ jsx11("rect", {
2776
+ children: meter.bars.map((bar, i) => /* @__PURE__ */ jsx12("rect", {
2733
2777
  ref: (el) => {
2734
2778
  rects.current[i] = el;
2735
2779
  },
@@ -2742,7 +2786,7 @@ function VoiceWaveBarsNative({ node, props, rootProps, children }) {
2742
2786
  fill: "currentColor"
2743
2787
  }, i))
2744
2788
  }),
2745
- node.children.length > 0 ? /* @__PURE__ */ jsx11("span", {
2789
+ node.children.length > 0 ? /* @__PURE__ */ jsx12("span", {
2746
2790
  ...part(`child`),
2747
2791
  "data-hidden": "true",
2748
2792
  "aria-hidden": "true",
@@ -2757,12 +2801,12 @@ function VoiceWaveRingNative({ node, props, rootProps, children }) {
2757
2801
  const size = sizeOf(ctx, `VoiceWave`, `root`, props, 56);
2758
2802
  const activity = VOICE_WAVE_ACTIVITIES.includes(str(props.activity)) ? str(props.activity) : `idle`;
2759
2803
  const input = { size, activity, level: num(props.level, 0), bands: arr(props.bands).map((b) => num(b, 0)), reducedMotion: ctx.reducedMotion };
2760
- const latest = useRef12(input);
2804
+ const latest = useRef13(input);
2761
2805
  latest.current = input;
2762
- const elapsed = useRef12(0);
2763
- const paths = useRef12([]);
2806
+ const elapsed = useRef13(0);
2807
+ const paths = useRef13([]);
2764
2808
  const animates = voiceWaveAnimates(activity) && !ctx.reducedMotion;
2765
- useEffect8(() => {
2809
+ useEffect9(() => {
2766
2810
  if (!animates) {
2767
2811
  elapsed.current = 0;
2768
2812
  return;
@@ -2772,9 +2816,9 @@ function VoiceWaveRingNative({ node, props, rootProps, children }) {
2772
2816
  voiceWave({ ...latest.current, elapsed: t }).rings.forEach((ring, k) => paths.current[k]?.setAttribute(`d`, voiceWavePath(ring)));
2773
2817
  });
2774
2818
  }, [animates]);
2775
- const childEl = useRef12(null);
2819
+ const childEl = useRef13(null);
2776
2820
  const hasChild = node.children.length > 0;
2777
- useLayoutEffect3(() => hasChild && childEl.current ? voiceWaveFitChild(childEl.current, (c) => voiceWaveChildBox(size, c).scale) : undefined, [hasChild, size]);
2821
+ useLayoutEffect4(() => hasChild && childEl.current ? voiceWaveFitChild(childEl.current, (c) => voiceWaveChildBox(size, c).scale) : undefined, [hasChild, size]);
2778
2822
  const wave = voiceWave({ ...input, elapsed: elapsed.current });
2779
2823
  const recipeProps = nativeRecipeProps2(`VoiceWave`, props);
2780
2824
  const colour = (name) => String(resolveRecipe(ctx.theme, { component: `VoiceWave`, part: name, props: recipeProps }, ctx.mode).color ?? `currentColor`);
@@ -2786,12 +2830,12 @@ function VoiceWaveRingNative({ node, props, rootProps, children }) {
2786
2830
  "aria-hidden": name ? undefined : `true`,
2787
2831
  style: mergeStyle(rootProps, { width: size, height: size }),
2788
2832
  children: [
2789
- /* @__PURE__ */ jsx11("svg", {
2833
+ /* @__PURE__ */ jsx12("svg", {
2790
2834
  viewBox: `0 0 ${size} ${size}`,
2791
2835
  width: size,
2792
2836
  height: size,
2793
2837
  "aria-hidden": "true",
2794
- children: wave.rings.map((ring, k) => /* @__PURE__ */ jsx11("path", {
2838
+ children: wave.rings.map((ring, k) => /* @__PURE__ */ jsx12("path", {
2795
2839
  ref: (el) => {
2796
2840
  paths.current[k] = el;
2797
2841
  },
@@ -2806,7 +2850,7 @@ function VoiceWaveRingNative({ node, props, rootProps, children }) {
2806
2850
  style: { color: colour(ring.part) }
2807
2851
  }, ring.part))
2808
2852
  }),
2809
- hasChild ? /* @__PURE__ */ jsx11("span", {
2853
+ hasChild ? /* @__PURE__ */ jsx12("span", {
2810
2854
  ref: childEl,
2811
2855
  ...part(`child`),
2812
2856
  "data-hidden": wave.childSize > 0 ? undefined : `true`,
@@ -2819,25 +2863,25 @@ function VoiceWaveRingNative({ node, props, rootProps, children }) {
2819
2863
  }
2820
2864
 
2821
2865
  // packages/exponential-ui-react/src/natives/inputs.tsx
2822
- import { useEffect as useEffect10, useId as useId4, useMemo as useMemo10, useRef as useRef14, useState as useState12 } from "react";
2866
+ import { useEffect as useEffect11, useId as useId4, useMemo as useMemo10, useRef as useRef15, useState as useState12 } from "react";
2823
2867
  import { Checkbox as CheckboxPrimitive, RadioGroup as RadioPrimitive, Slider as SliderPrimitive, Switch as SwitchPrimitive } from "radix-ui";
2824
2868
  import { boundPath as boundPath2, hostPath } from "@exponential_app/eui/web";
2825
2869
 
2826
2870
  // packages/exponential-ui-react/src/inputs.ts
2827
- import { useCallback as useCallback5, useEffect as useEffect9, useReducer, useRef as useRef13 } from "react";
2871
+ import { useCallback as useCallback5, useEffect as useEffect10, useReducer, useRef as useRef14 } from "react";
2828
2872
  import { DEBOUNCE_MS, HostOwnedController } from "@exponential_app/eui/web";
2829
2873
  function useHostOwnedValue({ external, send, writeLocal, debounceMs = DEBOUNCE_MS }) {
2830
2874
  const [, rerender] = useReducer((n) => n + 1, 0);
2831
- const ref = useRef13(null);
2875
+ const ref = useRef14(null);
2832
2876
  if (!ref.current)
2833
2877
  ref.current = new HostOwnedController({ initial: external, send, writeLocal, debounceMs, onChange: rerender });
2834
2878
  const c = ref.current;
2835
2879
  c.configure({ send, writeLocal, debounceMs });
2836
- useEffect9(() => {
2880
+ useEffect10(() => {
2837
2881
  c.attach();
2838
2882
  return () => c.dispose();
2839
2883
  }, [c]);
2840
- useEffect9(() => {
2884
+ useEffect10(() => {
2841
2885
  c.push(external);
2842
2886
  }, [c, external]);
2843
2887
  const onFocus = useCallback5(() => c.focus(), [c]);
@@ -2849,7 +2893,7 @@ function useHostOwnedValue({ external, send, writeLocal, debounceMs = DEBOUNCE_M
2849
2893
 
2850
2894
  // packages/exponential-ui-react/src/natives/inputs.tsx
2851
2895
  import { parseLocaleNumber } from "@exponential_app/eui/web";
2852
- import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
2896
+ import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
2853
2897
  function useInputSender(node, scope, prop, domId = node.id) {
2854
2898
  const ctx = useSurfaceContext();
2855
2899
  const path = boundPath2(node.props, prop, scope);
@@ -2862,13 +2906,13 @@ function useInputSender(node, scope, prop, domId = node.id) {
2862
2906
  return { send, writeLocal, path, name };
2863
2907
  }
2864
2908
  function InputNative(p) {
2865
- return /* @__PURE__ */ jsx12(TextFieldNative, {
2909
+ return /* @__PURE__ */ jsx13(TextFieldNative, {
2866
2910
  ...p,
2867
2911
  multiline: false
2868
2912
  });
2869
2913
  }
2870
2914
  function TextareaNative(p) {
2871
- return /* @__PURE__ */ jsx12(TextFieldNative, {
2915
+ return /* @__PURE__ */ jsx13(TextFieldNative, {
2872
2916
  ...p,
2873
2917
  multiline: true
2874
2918
  });
@@ -2891,7 +2935,7 @@ function TextFieldNative({ node, props, rootProps, emit, scope, domId, multiline
2891
2935
  const { send, writeLocal } = useInputSender(node, scope, `value`, domId);
2892
2936
  const external = str(props.value);
2893
2937
  const field = useHostOwnedValue({ external, send, writeLocal });
2894
- const focusRef = useRef14(null);
2938
+ const focusRef = useRef15(null);
2895
2939
  const f = useField({ node, domId, props, value: field.value, focusRef });
2896
2940
  const disabled = bool(props.disabled) || Boolean(f.form?.disabled);
2897
2941
  const label = str(props.label);
@@ -2900,7 +2944,7 @@ function TextFieldNative({ node, props, rootProps, emit, scope, domId, multiline
2900
2944
  const rows = Math.max(1, num(props.rows, 3));
2901
2945
  const maxRows = props.maxRows === undefined ? null : Math.max(rows, num(props.maxRows, rows));
2902
2946
  const auto = multiline && bool(props.autosize);
2903
- useEffect10(() => {
2947
+ useEffect11(() => {
2904
2948
  if (auto && focusRef.current)
2905
2949
  autosize(focusRef.current, rows, maxRows);
2906
2950
  }, [auto, field.value, rows, maxRows]);
@@ -2933,19 +2977,19 @@ function TextFieldNative({ node, props, rootProps, emit, scope, domId, multiline
2933
2977
  "data-pending": field.pending ? `true` : undefined,
2934
2978
  "data-revision": field.revision,
2935
2979
  children: [
2936
- /* @__PURE__ */ jsx12(TextPart, {
2980
+ /* @__PURE__ */ jsx13(TextPart, {
2937
2981
  part: part(`label`),
2938
2982
  text: label,
2939
2983
  as: "label",
2940
2984
  htmlFor: id
2941
2985
  }),
2942
- multiline ? /* @__PURE__ */ jsx12("textarea", {
2986
+ multiline ? /* @__PURE__ */ jsx13("textarea", {
2943
2987
  ref: focusRef,
2944
2988
  ...part(`field`, ...fieldStates),
2945
2989
  ...shared,
2946
2990
  rows,
2947
2991
  "data-autosize": auto ? `true` : undefined
2948
- }) : /* @__PURE__ */ jsx12("input", {
2992
+ }) : /* @__PURE__ */ jsx13("input", {
2949
2993
  ref: focusRef,
2950
2994
  ...part(`field`, ...fieldStates),
2951
2995
  ...shared,
@@ -2959,12 +3003,12 @@ function TextFieldNative({ node, props, rootProps, emit, scope, domId, multiline
2959
3003
  }
2960
3004
  }
2961
3005
  }),
2962
- /* @__PURE__ */ jsx12(TextPart, {
3006
+ /* @__PURE__ */ jsx13(TextPart, {
2963
3007
  part: part(`description`),
2964
3008
  text: description,
2965
3009
  id: `${id}-d`
2966
3010
  }),
2967
- /* @__PURE__ */ jsx12(FieldErrors, {
3011
+ /* @__PURE__ */ jsx13(FieldErrors, {
2968
3012
  part,
2969
3013
  field: f
2970
3014
  })
@@ -2987,7 +3031,7 @@ function NumberFieldNative({ node, props, rootProps, emit, scope, domId }) {
2987
3031
  const external = props.value === undefined || props.value === null || props.value === `` ? null : num(props.value);
2988
3032
  const [value, setValue] = useBoundState(node, scope, `value`, external);
2989
3033
  const [text, setText] = useState12(null);
2990
- const focusRef = useRef14(null);
3034
+ const focusRef = useRef15(null);
2991
3035
  const f = useField({ node, domId, props, value, focusRef });
2992
3036
  const disabled = bool(props.disabled) || Boolean(f.form?.disabled);
2993
3037
  const decimalSep = useMemo10(() => new Intl.NumberFormat(ctx.locale).formatToParts(1.1).find((p) => p.type === `decimal`)?.value ?? `.`, [ctx.locale]);
@@ -3015,7 +3059,7 @@ function NumberFieldNative({ node, props, rootProps, emit, scope, domId }) {
3015
3059
  return /* @__PURE__ */ jsxs9("div", {
3016
3060
  ...rootProps,
3017
3061
  children: [
3018
- /* @__PURE__ */ jsx12(TextPart, {
3062
+ /* @__PURE__ */ jsx13(TextPart, {
3019
3063
  part: part(`label`),
3020
3064
  text: props.label,
3021
3065
  as: "label",
@@ -3025,18 +3069,18 @@ function NumberFieldNative({ node, props, rootProps, emit, scope, domId }) {
3025
3069
  ...part(`field`, disabled && `disabled`, f.invalid && `invalid`),
3026
3070
  "data-xui-numberfield": "",
3027
3071
  children: [
3028
- /* @__PURE__ */ jsx12("button", {
3072
+ /* @__PURE__ */ jsx13("button", {
3029
3073
  type: "button",
3030
3074
  ...part(`decrement`, disabled && `disabled`),
3031
3075
  "aria-label": ctx.t(`decrement`),
3032
3076
  tabIndex: -1,
3033
3077
  disabled: disabled || min !== null && value !== null && value <= min,
3034
3078
  onClick: () => stepBy(-step),
3035
- children: /* @__PURE__ */ jsx12(BuiltinIcon, {
3079
+ children: /* @__PURE__ */ jsx13(BuiltinIcon, {
3036
3080
  slot: "NumberField.decrement"
3037
3081
  })
3038
3082
  }),
3039
- /* @__PURE__ */ jsx12("input", {
3083
+ /* @__PURE__ */ jsx13("input", {
3040
3084
  ref: focusRef,
3041
3085
  id,
3042
3086
  ...part(`input`),
@@ -3103,24 +3147,24 @@ function NumberFieldNative({ node, props, rootProps, emit, scope, domId }) {
3103
3147
  }
3104
3148
  }
3105
3149
  }),
3106
- unit ? /* @__PURE__ */ jsx12("span", {
3150
+ unit ? /* @__PURE__ */ jsx13("span", {
3107
3151
  ...part(`unit`),
3108
3152
  children: unit
3109
3153
  }) : null,
3110
- /* @__PURE__ */ jsx12("button", {
3154
+ /* @__PURE__ */ jsx13("button", {
3111
3155
  type: "button",
3112
3156
  ...part(`increment`, disabled && `disabled`),
3113
3157
  "aria-label": ctx.t(`increment`),
3114
3158
  tabIndex: -1,
3115
3159
  disabled: disabled || max !== null && value !== null && value >= max,
3116
3160
  onClick: () => stepBy(step),
3117
- children: /* @__PURE__ */ jsx12(BuiltinIcon, {
3161
+ children: /* @__PURE__ */ jsx13(BuiltinIcon, {
3118
3162
  slot: "NumberField.increment"
3119
3163
  })
3120
3164
  })
3121
3165
  ]
3122
3166
  }),
3123
- /* @__PURE__ */ jsx12(FieldErrors, {
3167
+ /* @__PURE__ */ jsx13(FieldErrors, {
3124
3168
  part,
3125
3169
  field: f
3126
3170
  })
@@ -3131,13 +3175,13 @@ function CheckboxNative({ node, props, rootProps, emit, scope, domId }) {
3131
3175
  const part = useParts(node, props);
3132
3176
  const id = useId4();
3133
3177
  const [checked, setChecked] = useBoundState(node, scope, `checked`, bool(props.checked));
3134
- const focusRef = useRef14(null);
3178
+ const focusRef = useRef15(null);
3135
3179
  const f = useField({ node, domId, props, value: checked, focusRef });
3136
3180
  const disabled = bool(props.disabled) || Boolean(f.form?.disabled);
3137
3181
  return /* @__PURE__ */ jsxs9("div", {
3138
3182
  ...rootProps,
3139
3183
  children: [
3140
- /* @__PURE__ */ jsx12(CheckboxPrimitive.Root, {
3184
+ /* @__PURE__ */ jsx13(CheckboxPrimitive.Root, {
3141
3185
  ref: focusRef,
3142
3186
  id,
3143
3187
  ...part(`box`, checked && `checked`, disabled && `disabled`, f.invalid && `invalid`),
@@ -3153,9 +3197,9 @@ function CheckboxNative({ node, props, rootProps, emit, scope, domId }) {
3153
3197
  f.touch();
3154
3198
  emit(`change`, { checked: value }, { checked: value });
3155
3199
  },
3156
- children: /* @__PURE__ */ jsx12(CheckboxPrimitive.Indicator, {
3200
+ children: /* @__PURE__ */ jsx13(CheckboxPrimitive.Indicator, {
3157
3201
  ...part(`check`),
3158
- children: /* @__PURE__ */ jsx12(BuiltinIcon, {
3202
+ children: /* @__PURE__ */ jsx13(BuiltinIcon, {
3159
3203
  slot: "Checkbox.check"
3160
3204
  })
3161
3205
  })
@@ -3163,17 +3207,17 @@ function CheckboxNative({ node, props, rootProps, emit, scope, domId }) {
3163
3207
  /* @__PURE__ */ jsxs9("div", {
3164
3208
  className: "xui-field-text",
3165
3209
  children: [
3166
- /* @__PURE__ */ jsx12(TextPart, {
3210
+ /* @__PURE__ */ jsx13(TextPart, {
3167
3211
  part: part(`label`),
3168
3212
  text: props.label,
3169
3213
  as: "label",
3170
3214
  htmlFor: id
3171
3215
  }),
3172
- /* @__PURE__ */ jsx12(TextPart, {
3216
+ /* @__PURE__ */ jsx13(TextPart, {
3173
3217
  part: part(`description`),
3174
3218
  text: props.description
3175
3219
  }),
3176
- /* @__PURE__ */ jsx12(FieldErrors, {
3220
+ /* @__PURE__ */ jsx13(FieldErrors, {
3177
3221
  part,
3178
3222
  field: f
3179
3223
  })
@@ -3187,7 +3231,7 @@ function SwitchNative({ node, props, rootProps, emit, scope, domId }) {
3187
3231
  const id = useId4();
3188
3232
  const ctx = useSurfaceContext();
3189
3233
  const [checked, setChecked] = useBoundState(node, scope, `checked`, bool(props.checked));
3190
- const focusRef = useRef14(null);
3234
+ const focusRef = useRef15(null);
3191
3235
  const f = useField({ node, domId, props, value: checked, focusRef });
3192
3236
  const disabled = bool(props.disabled) || Boolean(f.form?.disabled);
3193
3237
  const travel = useMemo10(() => {
@@ -3209,24 +3253,24 @@ function SwitchNative({ node, props, rootProps, emit, scope, domId }) {
3209
3253
  /* @__PURE__ */ jsxs9("div", {
3210
3254
  ...part(`body`),
3211
3255
  children: [
3212
- /* @__PURE__ */ jsx12(TextPart, {
3256
+ /* @__PURE__ */ jsx13(TextPart, {
3213
3257
  part: part(`label`),
3214
3258
  text: props.label,
3215
3259
  as: "label",
3216
3260
  htmlFor: id
3217
3261
  }),
3218
- /* @__PURE__ */ jsx12(TextPart, {
3262
+ /* @__PURE__ */ jsx13(TextPart, {
3219
3263
  part: part(`description`),
3220
3264
  text: description,
3221
3265
  id: `${id}-d`
3222
3266
  }),
3223
- /* @__PURE__ */ jsx12(FieldErrors, {
3267
+ /* @__PURE__ */ jsx13(FieldErrors, {
3224
3268
  part,
3225
3269
  field: f
3226
3270
  })
3227
3271
  ]
3228
3272
  }),
3229
- /* @__PURE__ */ jsx12(SwitchPrimitive.Root, {
3273
+ /* @__PURE__ */ jsx13(SwitchPrimitive.Root, {
3230
3274
  ref: focusRef,
3231
3275
  id,
3232
3276
  ...part(`track`, checked && `checked`, disabled && `disabled`),
@@ -3240,7 +3284,7 @@ function SwitchNative({ node, props, rootProps, emit, scope, domId }) {
3240
3284
  f.change(next);
3241
3285
  emit(`change`, { checked: next }, { checked: next });
3242
3286
  },
3243
- children: /* @__PURE__ */ jsx12(SwitchPrimitive.Thumb, {
3287
+ children: /* @__PURE__ */ jsx13(SwitchPrimitive.Thumb, {
3244
3288
  ...part(`thumb`, checked && `checked`)
3245
3289
  })
3246
3290
  })
@@ -3253,7 +3297,7 @@ function RadioNative({ node, props, rootProps, emit, scope, domId }) {
3253
3297
  const id = useId4();
3254
3298
  const options = objects(props.options);
3255
3299
  const [value, setValue] = useBoundState(node, scope, `value`, str(props.value));
3256
- const focusRef = useRef14(null);
3300
+ const focusRef = useRef15(null);
3257
3301
  const itemRef = useMemo10(() => ({
3258
3302
  get current() {
3259
3303
  return focusRef.current?.querySelector(`[data-state="checked"]`) ?? focusRef.current?.querySelector(`button`);
@@ -3266,12 +3310,12 @@ function RadioNative({ node, props, rootProps, emit, scope, domId }) {
3266
3310
  "aria-labelledby": props.label ? `${id}-l` : undefined,
3267
3311
  "aria-describedby": f.describedBy,
3268
3312
  children: [
3269
- /* @__PURE__ */ jsx12(TextPart, {
3313
+ /* @__PURE__ */ jsx13(TextPart, {
3270
3314
  part: part(`label`),
3271
3315
  text: props.label,
3272
3316
  id: `${id}-l`
3273
3317
  }),
3274
- /* @__PURE__ */ jsx12(RadioPrimitive.Root, {
3318
+ /* @__PURE__ */ jsx13(RadioPrimitive.Root, {
3275
3319
  ref: focusRef,
3276
3320
  ...part(`items`),
3277
3321
  className: `${part(`items`).className} xui-radio-items`,
@@ -3294,24 +3338,24 @@ function RadioNative({ node, props, rootProps, emit, scope, domId }) {
3294
3338
  htmlFor: oid,
3295
3339
  "data-xui-id": `${part.domId}.item.${i}`,
3296
3340
  children: [
3297
- /* @__PURE__ */ jsx12(RadioPrimitive.Item, {
3341
+ /* @__PURE__ */ jsx13(RadioPrimitive.Item, {
3298
3342
  id: oid,
3299
3343
  value: o.value,
3300
3344
  disabled: bool(o.disabled),
3301
3345
  ...part(`item`, checked && `checked`, bool(o.disabled) && `disabled`, f.invalid && `invalid`),
3302
3346
  "data-xui-id": `${part.domId}.dot.${i}`,
3303
- children: /* @__PURE__ */ jsx12(RadioPrimitive.Indicator, {
3347
+ children: /* @__PURE__ */ jsx13(RadioPrimitive.Indicator, {
3304
3348
  ...part(`dot`, checked && `checked`)
3305
3349
  })
3306
3350
  }),
3307
- o.icon ? /* @__PURE__ */ jsx12(IconGlyph, {
3351
+ o.icon ? /* @__PURE__ */ jsx13(IconGlyph, {
3308
3352
  icons: ctx.host.icons,
3309
3353
  name: o.icon,
3310
3354
  className: "xui-icon",
3311
3355
  width: 16,
3312
3356
  height: 16
3313
3357
  }) : null,
3314
- /* @__PURE__ */ jsx12("span", {
3358
+ /* @__PURE__ */ jsx13("span", {
3315
3359
  ...part.at(`label`, i),
3316
3360
  children: str(o.label)
3317
3361
  })
@@ -3319,7 +3363,7 @@ function RadioNative({ node, props, rootProps, emit, scope, domId }) {
3319
3363
  }, o.value);
3320
3364
  })
3321
3365
  }),
3322
- /* @__PURE__ */ jsx12(FieldErrors, {
3366
+ /* @__PURE__ */ jsx13(FieldErrors, {
3323
3367
  part,
3324
3368
  field: f
3325
3369
  })
@@ -3341,13 +3385,13 @@ function SliderNative({ node, props, rootProps, emit, scope }) {
3341
3385
  ...part(`header`),
3342
3386
  className: `${part(`header`).className} xui-slider-head`,
3343
3387
  children: [
3344
- /* @__PURE__ */ jsx12(TextPart, {
3388
+ /* @__PURE__ */ jsx13(TextPart, {
3345
3389
  part: part(`label`),
3346
3390
  text: props.label,
3347
3391
  as: "label",
3348
3392
  htmlFor: id
3349
3393
  }),
3350
- /* @__PURE__ */ jsx12("span", {
3394
+ /* @__PURE__ */ jsx13("span", {
3351
3395
  ...part(`value`),
3352
3396
  children: ctx.formatter.number(value)
3353
3397
  })
@@ -3364,13 +3408,13 @@ function SliderNative({ node, props, rootProps, emit, scope }) {
3364
3408
  onValueChange: ([next]) => setValue(next),
3365
3409
  onValueCommit: ([next]) => void emit(`change`, { value: next }, { value: next }),
3366
3410
  children: [
3367
- /* @__PURE__ */ jsx12(SliderPrimitive.Track, {
3411
+ /* @__PURE__ */ jsx13(SliderPrimitive.Track, {
3368
3412
  ...part(`track`),
3369
- children: /* @__PURE__ */ jsx12(SliderPrimitive.Range, {
3413
+ children: /* @__PURE__ */ jsx13(SliderPrimitive.Range, {
3370
3414
  ...part(`range`)
3371
3415
  })
3372
3416
  }),
3373
- /* @__PURE__ */ jsx12(SliderPrimitive.Thumb, {
3417
+ /* @__PURE__ */ jsx13(SliderPrimitive.Thumb, {
3374
3418
  id,
3375
3419
  ...part(`thumb`),
3376
3420
  "aria-label": str(props.label) || undefined
@@ -3387,7 +3431,7 @@ function ComposerNative({ node, props, rootProps, emit, scope, domId }) {
3387
3431
  const external = str(props.value);
3388
3432
  const field = useHostOwnedValue({ external, send, writeLocal });
3389
3433
  const busy = bool(props.busy);
3390
- const ref = useRef14(null);
3434
+ const ref = useRef15(null);
3391
3435
  const grow = () => {
3392
3436
  const el = ref.current;
3393
3437
  if (!el)
@@ -3395,7 +3439,7 @@ function ComposerNative({ node, props, rootProps, emit, scope, domId }) {
3395
3439
  el.style.height = `auto`;
3396
3440
  el.style.height = `${Math.min(200, el.scrollHeight)}px`;
3397
3441
  };
3398
- useEffect10(grow, [field.value]);
3442
+ useEffect11(grow, [field.value]);
3399
3443
  const submit = () => {
3400
3444
  if (busy) {
3401
3445
  emit(`stop`);
@@ -3414,7 +3458,7 @@ function ComposerNative({ node, props, rootProps, emit, scope, domId }) {
3414
3458
  ...rootProps,
3415
3459
  "data-busy": busy ? `true` : undefined,
3416
3460
  children: [
3417
- /* @__PURE__ */ jsx12("textarea", {
3461
+ /* @__PURE__ */ jsx13("textarea", {
3418
3462
  ref,
3419
3463
  ...part(`field`, field.focused && `focus`),
3420
3464
  rows: 1,
@@ -3437,24 +3481,24 @@ function ComposerNative({ node, props, rootProps, emit, scope, domId }) {
3437
3481
  /* @__PURE__ */ jsxs9("div", {
3438
3482
  className: "xui-composer-bar",
3439
3483
  children: [
3440
- bool(props.attachments) ? /* @__PURE__ */ jsx12("button", {
3484
+ bool(props.attachments) ? /* @__PURE__ */ jsx13("button", {
3441
3485
  type: "button",
3442
3486
  ...part(`attachment`),
3443
3487
  "aria-label": ctx.t(`browse`),
3444
3488
  onClick: () => void emit(`attach`),
3445
- children: /* @__PURE__ */ jsx12(BuiltinIcon, {
3489
+ children: /* @__PURE__ */ jsx13(BuiltinIcon, {
3446
3490
  slot: "Composer.attachment"
3447
3491
  })
3448
3492
  }) : null,
3449
- /* @__PURE__ */ jsx12("button", {
3493
+ /* @__PURE__ */ jsx13("button", {
3450
3494
  type: "button",
3451
3495
  ...part(`send`, busy && `pressed`),
3452
3496
  "aria-label": busy ? ctx.t(`stop`) : submitLabel,
3453
3497
  disabled: !busy && field.value.trim() === ``,
3454
3498
  onClick: submit,
3455
- children: busy ? /* @__PURE__ */ jsx12(BuiltinIcon, {
3499
+ children: busy ? /* @__PURE__ */ jsx13(BuiltinIcon, {
3456
3500
  slot: "Composer.stop"
3457
- }) : /* @__PURE__ */ jsx12(BuiltinIcon, {
3501
+ }) : /* @__PURE__ */ jsx13(BuiltinIcon, {
3458
3502
  slot: "Composer.send"
3459
3503
  })
3460
3504
  })
@@ -3465,30 +3509,30 @@ function ComposerNative({ node, props, rootProps, emit, scope, domId }) {
3465
3509
  }
3466
3510
 
3467
3511
  // packages/exponential-ui-react/src/natives/layout.tsx
3468
- import { memo, useCallback as useCallback7, useContext as useContext4, useEffect as useEffect12, useMemo as useMemo12, useRef as useRef16 } from "react";
3512
+ import { memo, useCallback as useCallback7, useContext as useContext4, useEffect as useEffect13, useMemo as useMemo12, useRef as useRef17 } from "react";
3469
3513
  import { listSections, sectionRows, WINDOW_THRESHOLD as CATALOG_WINDOW_THRESHOLD } from "@exponential_app/eui";
3470
3514
  import { getPointer, LITERAL_ROWS_ROOT } from "@exponential_app/eui/web";
3471
3515
 
3472
3516
  // packages/exponential-ui-react/src/list.tsx
3473
- import { forwardRef, useCallback as useCallback6, useEffect as useEffect11, useImperativeHandle, useLayoutEffect as useLayoutEffect4, useMemo as useMemo11, useRef as useRef15, useState as useState13 } from "react";
3517
+ import { forwardRef, useCallback as useCallback6, useEffect as useEffect12, useImperativeHandle, useLayoutEffect as useLayoutEffect5, useMemo as useMemo11, useRef as useRef16, useState as useState13 } from "react";
3474
3518
  import { itemExtents, itemOffsets, scrollOffsetForIndex, stickyHeader, virtualWindow, WINDOW_OVERSCAN } from "@exponential_app/eui";
3475
3519
  import { listViewport as viewportOf, scrollParent } from "@exponential_app/eui/web";
3476
- import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
3477
- var useIsoLayoutEffect2 = typeof window === `undefined` ? useEffect11 : useLayoutEffect4;
3520
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
3521
+ var useIsoLayoutEffect2 = typeof window === `undefined` ? useEffect12 : useLayoutEffect5;
3478
3522
  var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem, estimatedItemHeight = 40, overscan = WINDOW_OVERSCAN, className, axis = `vertical`, direction = `ltr`, gap = 0, divider, stickyRows, itemProps }, handle) {
3479
- const ref = useRef15(null);
3480
- const extentsByKey = useRef15(new Map);
3481
- const crossByKey = useRef15(new Map);
3482
- const observed = useRef15(new Map);
3483
- const keyOfEl = useRef15(new WeakMap);
3484
- const observer = useRef15(null);
3523
+ const ref = useRef16(null);
3524
+ const extentsByKey = useRef16(new Map);
3525
+ const crossByKey = useRef16(new Map);
3526
+ const observed = useRef16(new Map);
3527
+ const keyOfEl = useRef16(new WeakMap);
3528
+ const observer = useRef16(null);
3485
3529
  const [version, bump] = useState13(0);
3486
3530
  const [view, setView] = useState13(null);
3487
3531
  const horizontal = axis === `horizontal`;
3488
3532
  const rtl = horizontal && direction === `rtl`;
3489
3533
  const estimate = useCallback6((i) => typeof estimatedItemHeight === `function` ? estimatedItemHeight(i) : estimatedItemHeight, [estimatedItemHeight]);
3490
- const measured = useRef15(0);
3491
- const extentsCache = useRef15(null);
3534
+ const measured = useRef16(0);
3535
+ const extentsCache = useRef16(null);
3492
3536
  const extents = () => {
3493
3537
  const c = extentsCache.current;
3494
3538
  if (c && c.count === count && c.itemKey === itemKey && c.estimate === estimatedItemHeight && c.measured === measured.current)
@@ -3504,7 +3548,7 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3504
3548
  extentsCache.current = { count, itemKey, estimate: estimatedItemHeight, measured: measured.current, ext };
3505
3549
  return ext;
3506
3550
  };
3507
- useEffect11(() => {
3551
+ useEffect12(() => {
3508
3552
  if (typeof ResizeObserver === `undefined`)
3509
3553
  return;
3510
3554
  const ro = new ResizeObserver((entries) => {
@@ -3593,7 +3637,7 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3593
3637
  const win = virtualWindow(ext, gap, scroll, viewport, overscan);
3594
3638
  const headers = useMemo11(() => [...stickyRows ?? []].filter((r) => r >= 0 && r < count).sort((a, b) => a - b), [stickyRows, count]);
3595
3639
  const pinned = headers.length && scroll >= 0 ? stickyHeader(off, ext, headers, scroll) : null;
3596
- const pending = useRef15(null);
3640
+ const pending = useRef16(null);
3597
3641
  const jump = (index, align) => {
3598
3642
  const el = ref.current;
3599
3643
  if (!el || index < 0 || index >= count)
@@ -3616,7 +3660,7 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3616
3660
  window.scrollBy(by);
3617
3661
  return true;
3618
3662
  };
3619
- useEffect11(() => {
3663
+ useEffect12(() => {
3620
3664
  const p = pending.current;
3621
3665
  if (!p)
3622
3666
  return;
@@ -3625,7 +3669,7 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3625
3669
  else
3626
3670
  jump(p.index, p.align);
3627
3671
  });
3628
- useEffect11(() => {
3672
+ useEffect12(() => {
3629
3673
  const target = scroller ?? window;
3630
3674
  const cancel = () => {
3631
3675
  pending.current = null;
@@ -3666,7 +3710,7 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3666
3710
  ...itemProps?.(i) ?? {},
3667
3711
  style: { ...place(at), ...isPinned ? { zIndex: 1 } : {} },
3668
3712
  children: [
3669
- line ? /* @__PURE__ */ jsx13("div", {
3713
+ line ? /* @__PURE__ */ jsx14("div", {
3670
3714
  className: "xui-list-gap",
3671
3715
  "aria-hidden": "true",
3672
3716
  "data-axis": axis,
@@ -3678,7 +3722,7 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3678
3722
  }, key);
3679
3723
  });
3680
3724
  const spacer = horizontal ? { width: total, height: cross || undefined } : { height: total };
3681
- return /* @__PURE__ */ jsx13("div", {
3725
+ return /* @__PURE__ */ jsx14("div", {
3682
3726
  ref,
3683
3727
  className: className ? `xui-list-window ${className}` : `xui-list-window`,
3684
3728
  "data-axis": axis,
@@ -3690,11 +3734,11 @@ var WindowedList = forwardRef(function WindowedList({ count, itemKey, renderItem
3690
3734
  });
3691
3735
 
3692
3736
  // packages/exponential-ui-react/src/natives/layout.tsx
3693
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
3737
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
3694
3738
  function BoxNative({ node, props, rootProps, emit, children }) {
3695
3739
  const pressable = bool(props.pressable) || Boolean(node.on?.press);
3696
3740
  if (!pressable)
3697
- return /* @__PURE__ */ jsx14("div", {
3741
+ return /* @__PURE__ */ jsx15("div", {
3698
3742
  ...rootProps,
3699
3743
  children
3700
3744
  });
@@ -3706,7 +3750,7 @@ function BoxNative({ node, props, rootProps, emit, children }) {
3706
3750
  emit(`press`);
3707
3751
  }
3708
3752
  };
3709
- return /* @__PURE__ */ jsx14("div", {
3753
+ return /* @__PURE__ */ jsx15("div", {
3710
3754
  ...rootProps,
3711
3755
  "data-pressable": "true",
3712
3756
  role: "button",
@@ -3763,10 +3807,10 @@ function ListNative({ node, props, rootProps, scope, domId }) {
3763
3807
  const prev = rows[r - 1];
3764
3808
  return `item` in row && `item` in prev ? row.item : null;
3765
3809
  };
3766
- const windowRef = useRef16(null);
3767
- const rootRef = useRef16(null);
3810
+ const windowRef = useRef17(null);
3811
+ const rootRef = useRef17(null);
3768
3812
  const rowOfIndex = useCallback7((index) => rows.findIndex((r) => (`item` in r) && r.item === (tpl ? childCount + index : index)), [rows, tpl, childCount]);
3769
- useEffect12(() => ctx.registerScroller(domId, (index, align) => {
3813
+ useEffect13(() => ctx.registerScroller(domId, (index, align) => {
3770
3814
  const r = rowOfIndex(index);
3771
3815
  if (r < 0)
3772
3816
  return;
@@ -3778,7 +3822,7 @@ function ListNative({ node, props, rootProps, scope, domId }) {
3778
3822
  el?.scrollIntoView(horizontal ? { inline: block, block: `nearest` } : { block, inline: `nearest` });
3779
3823
  }
3780
3824
  }), [ctx, domId, rowOfIndex, windowed, horizontal]);
3781
- const renderRow = (r) => /* @__PURE__ */ jsx14(ListRowView, {
3825
+ const renderRow = (r) => /* @__PURE__ */ jsx15(ListRowView, {
3782
3826
  row: rows[r],
3783
3827
  node,
3784
3828
  tpl,
@@ -3794,19 +3838,19 @@ function ListNative({ node, props, rootProps, scope, domId }) {
3794
3838
  };
3795
3839
  const divider = (r) => {
3796
3840
  const before = dividerBefore(r);
3797
- return before === null ? null : /* @__PURE__ */ jsx14("div", {
3841
+ return before === null ? null : /* @__PURE__ */ jsx15("div", {
3798
3842
  ...part.at(`divider`, before),
3799
3843
  role: "separator"
3800
3844
  });
3801
3845
  };
3802
3846
  if (windowed) {
3803
3847
  const headerRows = sticky ? rows.flatMap((row, r) => (`header` in row) ? [r] : []) : undefined;
3804
- return /* @__PURE__ */ jsx14("div", {
3848
+ return /* @__PURE__ */ jsx15("div", {
3805
3849
  ref: rootRef,
3806
3850
  ...rootProps,
3807
3851
  style,
3808
3852
  role: listRole,
3809
- children: /* @__PURE__ */ jsx14(WindowedList, {
3853
+ children: /* @__PURE__ */ jsx15(WindowedList, {
3810
3854
  ref: windowRef,
3811
3855
  count: rows.length,
3812
3856
  itemKey: keyOf,
@@ -3831,7 +3875,7 @@ function ListNative({ node, props, rootProps, scope, domId }) {
3831
3875
  "data-xui-row": r,
3832
3876
  ...itemAttrs(r),
3833
3877
  children: [
3834
- line ? /* @__PURE__ */ jsx14("div", {
3878
+ line ? /* @__PURE__ */ jsx15("div", {
3835
3879
  className: "xui-list-gap",
3836
3880
  "aria-hidden": "true",
3837
3881
  "data-axis": axis,
@@ -3842,7 +3886,7 @@ function ListNative({ node, props, rootProps, scope, domId }) {
3842
3886
  ]
3843
3887
  }, keyOf(r)));
3844
3888
  }
3845
- return /* @__PURE__ */ jsx14("div", {
3889
+ return /* @__PURE__ */ jsx15("div", {
3846
3890
  ref: rootRef,
3847
3891
  ...rootProps,
3848
3892
  style,
@@ -3855,11 +3899,11 @@ var ListRowView = memo(function ListRowView({ row, node, tpl, sections, childCou
3855
3899
  const section = sections?.[row.header];
3856
3900
  if (!section)
3857
3901
  return null;
3858
- return /* @__PURE__ */ jsx14("div", {
3902
+ return /* @__PURE__ */ jsx15("div", {
3859
3903
  ...part.at(`section`, row.header),
3860
3904
  role: "heading",
3861
3905
  "aria-level": 3,
3862
- children: node.slots?.section ? /* @__PURE__ */ jsx14(LiteralScope, {
3906
+ children: node.slots?.section ? /* @__PURE__ */ jsx15(LiteralScope, {
3863
3907
  value: { value: section.value, count: section.count, index: row.header },
3864
3908
  pointer: `${LITERAL_ROWS_ROOT}/${node.id.replace(/[~/]/g, `_`)}/sections/${row.header}`,
3865
3909
  suffix: `.${row.header}`,
@@ -3868,13 +3912,13 @@ var ListRowView = memo(function ListRowView({ row, node, tpl, sections, childCou
3868
3912
  });
3869
3913
  }
3870
3914
  if (row.item < childCount)
3871
- return /* @__PURE__ */ jsx14(NodeView, {
3915
+ return /* @__PURE__ */ jsx15(NodeView, {
3872
3916
  node: node.children[row.item]
3873
3917
  });
3874
3918
  const item = tpl?.items[row.item - childCount];
3875
3919
  if (!tpl || !item)
3876
3920
  return null;
3877
- return /* @__PURE__ */ jsx14(TemplateItemView, {
3921
+ return /* @__PURE__ */ jsx15(TemplateItemView, {
3878
3922
  tpl: tpl.tpl,
3879
3923
  item
3880
3924
  });
@@ -3890,13 +3934,13 @@ function LiteralScope({ value, pointer, suffix, node }) {
3890
3934
  };
3891
3935
  return deriveContext(ctx, { setData }, data);
3892
3936
  }, [ctx, pointer, value]);
3893
- return /* @__PURE__ */ jsx14(SurfaceContext.Provider, {
3937
+ return /* @__PURE__ */ jsx15(SurfaceContext.Provider, {
3894
3938
  value: view,
3895
- children: /* @__PURE__ */ jsx14(ScopeContext.Provider, {
3939
+ children: /* @__PURE__ */ jsx15(ScopeContext.Provider, {
3896
3940
  value: pointer,
3897
- children: /* @__PURE__ */ jsx14(InstanceContext.Provider, {
3941
+ children: /* @__PURE__ */ jsx15(InstanceContext.Provider, {
3898
3942
  value: `${outer}${suffix}`,
3899
- children: /* @__PURE__ */ jsx14(NodeView, {
3943
+ children: /* @__PURE__ */ jsx15(NodeView, {
3900
3944
  node
3901
3945
  })
3902
3946
  })
@@ -3911,7 +3955,7 @@ function UnknownNative({ node, props, rootProps }) {
3911
3955
  role: "note",
3912
3956
  "data-xui-unknown": str(props.component, node.component),
3913
3957
  children: [
3914
- /* @__PURE__ */ jsx14(BuiltinIcon, {
3958
+ /* @__PURE__ */ jsx15(BuiltinIcon, {
3915
3959
  slot: "Unknown.root",
3916
3960
  size: 16
3917
3961
  }),
@@ -3928,12 +3972,13 @@ function UnknownNative({ node, props, rootProps }) {
3928
3972
  }
3929
3973
 
3930
3974
  // packages/exponential-ui-react/src/natives/media.tsx
3931
- import { useEffect as useEffect13, useRef as useRef17, useState as useState14 } from "react";
3975
+ import { useEffect as useEffect14, useRef as useRef18, useState as useState14 } from "react";
3932
3976
  import { Avatar as AvatarPrimitive } from "radix-ui";
3933
3977
  import { MEDIA_ASPECT_RATIO, MEDIA_INTRINSIC_WIDTH } from "@exponential_app/eui";
3934
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
3978
+ import { mediaClock } from "@exponential_app/eui/web";
3979
+ import { jsx as jsx16, jsxs as jsxs12, Fragment as Fragment2 } from "react/jsx-runtime";
3935
3980
  function MediaSizer() {
3936
- return /* @__PURE__ */ jsx15("svg", {
3981
+ return /* @__PURE__ */ jsx16("svg", {
3937
3982
  className: "xui-media-sizer",
3938
3983
  "aria-hidden": "true",
3939
3984
  width: MEDIA_INTRINSIC_WIDTH,
@@ -3948,7 +3993,7 @@ function ImageNative({ node, props, rootProps }) {
3948
3993
  const alt = str(props.alt);
3949
3994
  const fit = str(props.fit, `cover`);
3950
3995
  const [state, setState] = useState14(`loading`);
3951
- useEffect13(() => setState(`loading`), [src]);
3996
+ useEffect14(() => setState(`loading`), [src]);
3952
3997
  const style = {};
3953
3998
  if (props.width !== undefined)
3954
3999
  style.width = num(props.width);
@@ -3973,7 +4018,7 @@ function ImageNative({ node, props, rootProps }) {
3973
4018
  "aria-label": failed ? alt : undefined,
3974
4019
  "data-state": src ? shown : `empty`,
3975
4020
  children: [
3976
- src && url && shown !== `error` ? /* @__PURE__ */ jsx15("img", {
4021
+ src && url && shown !== `error` ? /* @__PURE__ */ jsx16("img", {
3977
4022
  src: url,
3978
4023
  alt,
3979
4024
  loading: props.loading === `eager` ? `eager` : `lazy`,
@@ -3982,14 +4027,14 @@ function ImageNative({ node, props, rootProps }) {
3982
4027
  onLoad: () => setState(`loaded`),
3983
4028
  onError: () => setState(`error`)
3984
4029
  }) : null,
3985
- /* @__PURE__ */ jsx15(MediaSizer, {}),
3986
- failed ? /* @__PURE__ */ jsx15("div", {
4030
+ /* @__PURE__ */ jsx16(MediaSizer, {}),
4031
+ failed ? /* @__PURE__ */ jsx16("div", {
3987
4032
  ...part(`fallback`),
3988
4033
  "aria-hidden": "true",
3989
- children: fallback ? /* @__PURE__ */ jsx15(IconGlyph, {
4034
+ children: fallback ? /* @__PURE__ */ jsx16(IconGlyph, {
3990
4035
  icons: ctx.host.icons,
3991
4036
  name: fallback
3992
- }) : /* @__PURE__ */ jsx15(BuiltinIcon, {
4037
+ }) : /* @__PURE__ */ jsx16(BuiltinIcon, {
3993
4038
  slot: "Image.fallback"
3994
4039
  })
3995
4040
  }) : null
@@ -4001,24 +4046,54 @@ function VideoNative({ node, props, rootProps }) {
4001
4046
  const part = useParts(node, props);
4002
4047
  const src = str(props.src);
4003
4048
  const poster = str(props.poster);
4049
+ const autoplay = bool(props.autoplay);
4050
+ const [started, setStarted] = useState14(false);
4004
4051
  const url = useMediaSrc(ctx.host, src, `stream`);
4005
4052
  const posterUrl = useMediaSrc(ctx.host, poster);
4006
4053
  const ratio = num(props.aspectRatio, MEDIA_ASPECT_RATIO) || MEDIA_ASPECT_RATIO;
4054
+ const durationMs = props.durationMs !== undefined ? num(props.durationMs) : undefined;
4055
+ const Play = CHROME.play;
4007
4056
  return /* @__PURE__ */ jsxs12("div", {
4008
4057
  ...rootProps,
4009
4058
  style: mergeStyle(rootProps, { aspectRatio: String(ratio) }),
4010
4059
  children: [
4011
- /* @__PURE__ */ jsx15(MediaSizer, {}),
4012
- /* @__PURE__ */ jsx15("video", {
4060
+ /* @__PURE__ */ jsx16(MediaSizer, {}),
4061
+ started || autoplay ? /* @__PURE__ */ jsx16("video", {
4013
4062
  ...part(`controls`),
4014
4063
  src: url,
4015
4064
  poster: posterUrl,
4016
4065
  controls: true,
4017
- autoPlay: bool(props.autoplay),
4018
- muted: bool(props.autoplay),
4066
+ autoPlay: true,
4067
+ muted: autoplay && !started,
4019
4068
  playsInline: true,
4020
4069
  preload: "metadata",
4021
- "data-duration-ms": props.durationMs !== undefined ? num(props.durationMs) : undefined
4070
+ "data-duration-ms": durationMs
4071
+ }) : /* @__PURE__ */ jsxs12(Fragment2, {
4072
+ children: [
4073
+ posterUrl ? /* @__PURE__ */ jsx16("img", {
4074
+ className: "xui-video-poster",
4075
+ src: posterUrl,
4076
+ alt: "",
4077
+ "aria-hidden": "true",
4078
+ decoding: "async",
4079
+ draggable: false
4080
+ }) : null,
4081
+ /* @__PURE__ */ jsx16("button", {
4082
+ type: "button",
4083
+ className: "xui-media-play",
4084
+ "data-size": "lg",
4085
+ "aria-label": ctx.t(`play`),
4086
+ disabled: !url,
4087
+ onClick: () => setStarted(true),
4088
+ children: /* @__PURE__ */ jsx16(Play, {
4089
+ "aria-hidden": "true"
4090
+ })
4091
+ }),
4092
+ durationMs !== undefined ? /* @__PURE__ */ jsx16("span", {
4093
+ className: "xui-video-duration",
4094
+ children: mediaClock(durationMs)
4095
+ }) : null
4096
+ ]
4022
4097
  })
4023
4098
  ]
4024
4099
  });
@@ -4029,21 +4104,67 @@ function AudioPlayerNative({ node, props, rootProps }) {
4029
4104
  const src = str(props.src);
4030
4105
  const title = str(props.title);
4031
4106
  const url = useMediaSrc(ctx.host, src, `stream`);
4107
+ const audio = useRef18(null);
4108
+ const [playing, setPlaying] = useState14(false);
4109
+ const [position, setPosition] = useState14(0);
4110
+ const [loadedMs, setLoadedMs] = useState14(null);
4111
+ const durationMs = props.durationMs !== undefined ? num(props.durationMs) : loadedMs ?? 0;
4112
+ const Glyph = playing ? CHROME.pause : CHROME.play;
4113
+ const toggle = () => {
4114
+ const el = audio.current;
4115
+ if (!el)
4116
+ return;
4117
+ if (el.paused)
4118
+ el.play()?.catch(() => setPlaying(false));
4119
+ else
4120
+ el.pause();
4121
+ };
4032
4122
  return /* @__PURE__ */ jsxs12("div", {
4033
4123
  ...rootProps,
4034
4124
  style: mergeStyle(rootProps, { flexDirection: `column`, gap: `var(--xui-spacing-xs)` }),
4035
4125
  children: [
4036
- title ? /* @__PURE__ */ jsx15("span", {
4126
+ title ? /* @__PURE__ */ jsx16("span", {
4037
4127
  ...part(`track`),
4038
4128
  children: title
4039
4129
  }) : null,
4040
- /* @__PURE__ */ jsx15("audio", {
4130
+ /* @__PURE__ */ jsxs12("div", {
4041
4131
  ...part(`controls`),
4132
+ "data-duration-ms": props.durationMs !== undefined ? num(props.durationMs) : undefined,
4133
+ children: [
4134
+ /* @__PURE__ */ jsx16("button", {
4135
+ type: "button",
4136
+ className: "xui-media-play",
4137
+ "data-size": "sm",
4138
+ "aria-label": ctx.t(playing ? `pause` : `play`),
4139
+ disabled: !url,
4140
+ onClick: toggle,
4141
+ children: /* @__PURE__ */ jsx16(Glyph, {
4142
+ "aria-hidden": "true"
4143
+ })
4144
+ }),
4145
+ /* @__PURE__ */ jsx16("span", {
4146
+ className: "xui-audio-progress",
4147
+ "aria-hidden": "true",
4148
+ children: /* @__PURE__ */ jsx16("span", {
4149
+ style: { width: `${durationMs > 0 ? Math.min(100, position / durationMs * 100) : 0}%` }
4150
+ })
4151
+ }),
4152
+ /* @__PURE__ */ jsx16("span", {
4153
+ className: "xui-audio-clock",
4154
+ children: `${mediaClock(position)} / ${mediaClock(durationMs)}`
4155
+ })
4156
+ ]
4157
+ }),
4158
+ /* @__PURE__ */ jsx16("audio", {
4159
+ ref: audio,
4042
4160
  src: url,
4043
- controls: true,
4044
4161
  preload: "metadata",
4045
4162
  "aria-label": title || undefined,
4046
- "data-duration-ms": props.durationMs !== undefined ? num(props.durationMs) : undefined
4163
+ onPlay: () => setPlaying(true),
4164
+ onPause: () => setPlaying(false),
4165
+ onEnded: () => setPlaying(false),
4166
+ onTimeUpdate: (e) => setPosition(e.currentTarget.currentTime * 1000),
4167
+ onLoadedMetadata: (e) => setLoadedMs(Number.isFinite(e.currentTarget.duration) ? e.currentTarget.duration * 1000 : null)
4047
4168
  })
4048
4169
  ]
4049
4170
  });
@@ -4071,12 +4192,12 @@ function AvatarNative({ node, props, rootProps }) {
4071
4192
  "aria-label": name || undefined,
4072
4193
  role: "img",
4073
4194
  children: [
4074
- src ? /* @__PURE__ */ jsx15(AvatarPrimitive.Image, {
4195
+ src ? /* @__PURE__ */ jsx16(AvatarPrimitive.Image, {
4075
4196
  ...part(`image`),
4076
4197
  src: url,
4077
4198
  alt: name
4078
4199
  }) : null,
4079
- /* @__PURE__ */ jsx15(AvatarPrimitive.Fallback, {
4200
+ /* @__PURE__ */ jsx16(AvatarPrimitive.Fallback, {
4080
4201
  ...part(`fallback`),
4081
4202
  delayMs: src ? 300 : undefined,
4082
4203
  style: tint,
@@ -4085,10 +4206,42 @@ function AvatarNative({ node, props, rootProps }) {
4085
4206
  ]
4086
4207
  });
4087
4208
  }
4209
+ function CarouselThumbnail({ attrs, src, current, label, onPress }) {
4210
+ const ctx = useSurfaceContext();
4211
+ const url = useMediaSrc(ctx.host, src);
4212
+ const [broken, setBroken] = useState14(null);
4213
+ return /* @__PURE__ */ jsxs12("button", {
4214
+ type: "button",
4215
+ ...attrs,
4216
+ "aria-label": label,
4217
+ "aria-current": current ? `true` : undefined,
4218
+ "data-current": current ? `true` : undefined,
4219
+ onClick: onPress,
4220
+ children: [
4221
+ /* @__PURE__ */ jsx16("span", {
4222
+ className: "xui-carousel-thumb-fallback",
4223
+ "aria-hidden": "true",
4224
+ children: /* @__PURE__ */ jsx16(BuiltinIcon, {
4225
+ slot: "Image.fallback"
4226
+ })
4227
+ }),
4228
+ src && url && broken !== url ? /* @__PURE__ */ jsx16("img", {
4229
+ className: "xui-carousel-thumb",
4230
+ src: url,
4231
+ alt: "",
4232
+ "aria-hidden": "true",
4233
+ loading: "lazy",
4234
+ decoding: "async",
4235
+ draggable: false,
4236
+ onError: () => setBroken(url)
4237
+ }) : null
4238
+ ]
4239
+ });
4240
+ }
4088
4241
  function CarouselNative({ node, props, rootProps, emit, scope }) {
4089
4242
  const ctx = useSurfaceContext();
4090
4243
  const part = useParts(node, props);
4091
- const track = useRef17(null);
4244
+ const track = useRef18(null);
4092
4245
  const pages = node.children;
4093
4246
  const [page, setPage] = useBoundState(node, scope, `page`, num(props.page, 0));
4094
4247
  const scrollTo = (i) => {
@@ -4097,7 +4250,7 @@ function CarouselNative({ node, props, rootProps, emit, scope }) {
4097
4250
  el.scrollTo({ left: el.children[i].offsetLeft, behavior: ctx.reducedMotion ? `auto` : `smooth` });
4098
4251
  };
4099
4252
  const external = num(props.page, 0);
4100
- useEffect13(() => scrollTo(external), [external]);
4253
+ useEffect14(() => scrollTo(external), [external]);
4101
4254
  const onScroll = () => {
4102
4255
  const el = track.current;
4103
4256
  if (!el || el.clientWidth === 0)
@@ -4118,6 +4271,44 @@ function CarouselNative({ node, props, rootProps, emit, scope }) {
4118
4271
  scrollTo(target);
4119
4272
  };
4120
4273
  const many = pages.length > 1;
4274
+ const counter = many && bool(props.counter);
4275
+ const thumbnails = many && Array.isArray(props.thumbnails) ? props.thumbnails : null;
4276
+ const strip = useRef18(null);
4277
+ useEffect14(() => {
4278
+ const el = strip.current;
4279
+ const thumb = el?.children[page];
4280
+ if (!el || !thumb)
4281
+ return;
4282
+ const a = el.getBoundingClientRect();
4283
+ const b = thumb.getBoundingClientRect();
4284
+ const delta = b.left < a.left ? b.left - a.left : b.right > a.right ? b.right - a.right : 0;
4285
+ if (delta !== 0)
4286
+ el.scrollLeft += delta;
4287
+ }, [page, thumbnails !== null]);
4288
+ const trackView = /* @__PURE__ */ jsx16("div", {
4289
+ ref: track,
4290
+ className: "xui-carousel-track",
4291
+ onScroll,
4292
+ "aria-live": "polite",
4293
+ children: pages.map((child, i) => {
4294
+ const active = i === page;
4295
+ const attrs = part(`page`, active && `selected`);
4296
+ if (!active)
4297
+ delete attrs[`data-xui-id`];
4298
+ return /* @__PURE__ */ jsx16("div", {
4299
+ ...attrs,
4300
+ role: "group",
4301
+ "aria-roledescription": ctx.t(`slide`),
4302
+ "aria-label": ctx.t(`pageOf`, { page: i + 1, total: pages.length }),
4303
+ "aria-hidden": active ? undefined : true,
4304
+ "data-xui-inactive": active ? undefined : ``,
4305
+ ...active ? {} : INERT,
4306
+ children: /* @__PURE__ */ jsx16(NodeView, {
4307
+ node: child
4308
+ })
4309
+ }, child.id);
4310
+ })
4311
+ });
4121
4312
  return /* @__PURE__ */ jsxs12("div", {
4122
4313
  ...rootProps,
4123
4314
  role: "region",
@@ -4130,49 +4321,47 @@ function CarouselNative({ node, props, rootProps, emit, scope }) {
4130
4321
  go(page + (rtl ? 1 : -1));
4131
4322
  },
4132
4323
  children: [
4133
- /* @__PURE__ */ jsx15("div", {
4134
- ref: track,
4135
- className: "xui-carousel-track",
4136
- onScroll,
4137
- "aria-live": "polite",
4138
- children: pages.map((child, i) => {
4139
- const active = i === page;
4140
- const attrs = part(`page`, active && `selected`);
4141
- if (!active)
4142
- delete attrs[`data-xui-id`];
4143
- return /* @__PURE__ */ jsx15("div", {
4144
- ...attrs,
4145
- role: "group",
4146
- "aria-roledescription": ctx.t(`slide`),
4147
- "aria-label": ctx.t(`pageOf`, { page: i + 1, total: pages.length }),
4148
- "aria-hidden": active ? undefined : true,
4149
- "data-xui-inactive": active ? undefined : ``,
4150
- ...active ? {} : INERT,
4151
- children: /* @__PURE__ */ jsx15(NodeView, {
4152
- node: child
4153
- })
4154
- }, child.id);
4155
- })
4156
- }),
4324
+ counter ? /* @__PURE__ */ jsxs12("div", {
4325
+ className: "xui-carousel-stage",
4326
+ children: [
4327
+ trackView,
4328
+ /* @__PURE__ */ jsx16("span", {
4329
+ ...part(`counter`),
4330
+ "aria-hidden": "true",
4331
+ children: ctx.t(`pageCounter`, { page: page + 1, total: pages.length })
4332
+ })
4333
+ ]
4334
+ }) : trackView,
4335
+ thumbnails ? /* @__PURE__ */ jsx16("div", {
4336
+ ref: strip,
4337
+ ...part(`thumbnails`),
4338
+ children: pages.map((child, i) => /* @__PURE__ */ jsx16(CarouselThumbnail, {
4339
+ attrs: part.at(`thumbnail`, i, i === page && `selected`),
4340
+ src: typeof thumbnails[i] === `string` ? thumbnails[i] : ``,
4341
+ current: i === page,
4342
+ label: ctx.t(`pageOf`, { page: i + 1, total: pages.length }),
4343
+ onPress: () => go(i)
4344
+ }, child.id))
4345
+ }) : null,
4157
4346
  many ? /* @__PURE__ */ jsxs12("div", {
4158
4347
  ...withClass(part(`controls`), `xui-carousel-controls`),
4159
4348
  children: [
4160
- /* @__PURE__ */ jsx15("button", {
4349
+ /* @__PURE__ */ jsx16("button", {
4161
4350
  type: "button",
4162
4351
  ...withClass(part(`previous`), `xui-carousel-nav`),
4163
4352
  "aria-label": ctx.t(`previous`),
4164
4353
  disabled: !bool(props.loop) && page === 0,
4165
4354
  onClick: () => go(page - 1),
4166
- children: /* @__PURE__ */ jsx15(BuiltinIcon, {
4355
+ children: /* @__PURE__ */ jsx16(BuiltinIcon, {
4167
4356
  slot: "Carousel.previous"
4168
4357
  })
4169
4358
  }),
4170
- props.indicators !== false ? /* @__PURE__ */ jsx15("div", {
4359
+ props.indicators !== false ? /* @__PURE__ */ jsx16("div", {
4171
4360
  ...part(`indicator`),
4172
4361
  className: "xui-carousel-dots",
4173
4362
  "data-xui-part": "Carousel/indicators",
4174
4363
  role: "tablist",
4175
- children: pages.map((child, i) => /* @__PURE__ */ jsx15("button", {
4364
+ children: pages.map((child, i) => /* @__PURE__ */ jsx16("button", {
4176
4365
  type: "button",
4177
4366
  ...part(`indicator`, i === page && `selected`),
4178
4367
  "data-xui-id": undefined,
@@ -4182,13 +4371,13 @@ function CarouselNative({ node, props, rootProps, emit, scope }) {
4182
4371
  onClick: () => go(i)
4183
4372
  }, child.id))
4184
4373
  }) : null,
4185
- /* @__PURE__ */ jsx15("button", {
4374
+ /* @__PURE__ */ jsx16("button", {
4186
4375
  type: "button",
4187
4376
  ...withClass(part(`next`), `xui-carousel-nav`),
4188
4377
  "aria-label": ctx.t(`next`),
4189
4378
  disabled: !bool(props.loop) && page === pages.length - 1,
4190
4379
  onClick: () => go(page + 1),
4191
- children: /* @__PURE__ */ jsx15(BuiltinIcon, {
4380
+ children: /* @__PURE__ */ jsx16(BuiltinIcon, {
4192
4381
  slot: "Carousel.next"
4193
4382
  })
4194
4383
  })
@@ -4199,10 +4388,10 @@ function CarouselNative({ node, props, rootProps, emit, scope }) {
4199
4388
  }
4200
4389
 
4201
4390
  // packages/exponential-ui-react/src/natives/nav.tsx
4202
- import { Fragment as Fragment2, useRef as useRef18, useState as useState15 } from "react";
4391
+ import { Fragment as Fragment3, useRef as useRef19, useState as useState15 } from "react";
4203
4392
  import { Accordion as AccordionPrimitive, Tabs as TabsPrimitive, ToggleGroup as ToggleGroupPrimitive } from "radix-ui";
4204
4393
  import { segmentedBadge } from "@exponential_app/eui/web";
4205
- import { jsx as jsx16, jsxs as jsxs13, Fragment as Fragment3 } from "react/jsx-runtime";
4394
+ import { jsx as jsx17, jsxs as jsxs13, Fragment as Fragment4 } from "react/jsx-runtime";
4206
4395
  function TabsNative({ node, props, rootProps, emit, scope }) {
4207
4396
  const ctx = useSurfaceContext();
4208
4397
  const part = useParts(node, props);
@@ -4243,23 +4432,23 @@ function TabsNative({ node, props, rootProps, emit, scope }) {
4243
4432
  /* @__PURE__ */ jsxs13("span", {
4244
4433
  className: "xui-Tabs-tab-body",
4245
4434
  children: [
4246
- tab.icon ? /* @__PURE__ */ jsx16(IconGlyph, {
4435
+ tab.icon ? /* @__PURE__ */ jsx17(IconGlyph, {
4247
4436
  icons: ctx.host.icons,
4248
4437
  name: tab.icon,
4249
4438
  className: "xui-icon",
4250
4439
  width: 16,
4251
4440
  height: 16
4252
4441
  }) : null,
4253
- /* @__PURE__ */ jsx16("span", {
4442
+ /* @__PURE__ */ jsx17("span", {
4254
4443
  children: str(tab.label)
4255
4444
  }),
4256
- tab.count !== undefined ? /* @__PURE__ */ jsx16("span", {
4445
+ tab.count !== undefined ? /* @__PURE__ */ jsx17("span", {
4257
4446
  "data-count": "",
4258
4447
  children: ctx.formatter.number(num(tab.count))
4259
4448
  }) : null
4260
4449
  ]
4261
4450
  }),
4262
- /* @__PURE__ */ jsx16("span", {
4451
+ /* @__PURE__ */ jsx17("span", {
4263
4452
  ...part(`indicator`, selected && `selected`),
4264
4453
  "aria-hidden": "true"
4265
4454
  })
@@ -4267,29 +4456,29 @@ function TabsNative({ node, props, rootProps, emit, scope }) {
4267
4456
  }, tab.value);
4268
4457
  if (!closable)
4269
4458
  return trigger;
4270
- return /* @__PURE__ */ jsxs13(Fragment2, {
4459
+ return /* @__PURE__ */ jsxs13(Fragment3, {
4271
4460
  children: [
4272
4461
  trigger,
4273
- /* @__PURE__ */ jsx16("button", {
4462
+ /* @__PURE__ */ jsx17("button", {
4274
4463
  type: "button",
4275
4464
  ...part.at(`close`, i, lent?.index === i && lent.state),
4276
4465
  "aria-label": ctx.t(`closeTab`, { name: str(tab.label) }),
4277
4466
  onPointerEnter: lending ? () => lend(i, `hover`) : undefined,
4278
4467
  onPointerLeave: lending ? () => lend(i, null) : undefined,
4279
4468
  onClick: () => void emit(`close`, { value: tab.value }),
4280
- children: /* @__PURE__ */ jsx16(BuiltinIcon, {
4469
+ children: /* @__PURE__ */ jsx17(BuiltinIcon, {
4281
4470
  slot: "Tabs.close"
4282
4471
  })
4283
4472
  })
4284
4473
  ]
4285
4474
  }, tab.value);
4286
4475
  }),
4287
- bool(props.addable) ? /* @__PURE__ */ jsx16("button", {
4476
+ bool(props.addable) ? /* @__PURE__ */ jsx17("button", {
4288
4477
  type: "button",
4289
4478
  ...part(`new`),
4290
4479
  "aria-label": ctx.t(`newTab`),
4291
4480
  onClick: () => void emit(`new`),
4292
- children: /* @__PURE__ */ jsx16(BuiltinIcon, {
4481
+ children: /* @__PURE__ */ jsx17(BuiltinIcon, {
4293
4482
  slot: "Tabs.new"
4294
4483
  })
4295
4484
  }) : null
@@ -4299,10 +4488,10 @@ function TabsNative({ node, props, rootProps, emit, scope }) {
4299
4488
  const attrs = part(`content`);
4300
4489
  if (tab.value !== value)
4301
4490
  delete attrs[`data-xui-id`];
4302
- return /* @__PURE__ */ jsx16(TabsPrimitive.Content, {
4491
+ return /* @__PURE__ */ jsx17(TabsPrimitive.Content, {
4303
4492
  value: tab.value,
4304
4493
  ...attrs,
4305
- children: node.children[i] ? /* @__PURE__ */ jsx16(NodeView, {
4494
+ children: node.children[i] ? /* @__PURE__ */ jsx17(NodeView, {
4306
4495
  node: node.children[i]
4307
4496
  }) : null
4308
4497
  }, tab.value);
@@ -4326,26 +4515,26 @@ function SegmentedNative({ node, props, rootProps, emit, scope }) {
4326
4515
  const isSelected = (item) => multiple ? asArray(value).includes(item.value) : value === item.value;
4327
4516
  const content = (item, selected) => {
4328
4517
  const badge = bar ? segmentedBadge(item.count) : null;
4329
- return /* @__PURE__ */ jsxs13(Fragment3, {
4518
+ return /* @__PURE__ */ jsxs13(Fragment4, {
4330
4519
  children: [
4331
4520
  item.icon ? /* @__PURE__ */ jsxs13("span", {
4332
4521
  ...part(`icon`, selected && `selected`),
4333
4522
  "aria-hidden": "true",
4334
4523
  children: [
4335
- /* @__PURE__ */ jsx16(IconGlyph, {
4524
+ /* @__PURE__ */ jsx17(IconGlyph, {
4336
4525
  icons: ctx.host.icons,
4337
4526
  name: item.icon,
4338
4527
  className: "xui-icon",
4339
4528
  width: bar ? 20 : 16,
4340
4529
  height: bar ? 20 : 16
4341
4530
  }),
4342
- badge ? /* @__PURE__ */ jsx16("span", {
4531
+ badge ? /* @__PURE__ */ jsx17("span", {
4343
4532
  ...part(`badge`, selected && `selected`),
4344
4533
  children: badge
4345
4534
  }) : null
4346
4535
  ]
4347
4536
  }) : null,
4348
- item.label ? /* @__PURE__ */ jsx16("span", {
4537
+ item.label ? /* @__PURE__ */ jsx17("span", {
4349
4538
  ...part(`label`, selected && `selected`),
4350
4539
  children: str(item.label)
4351
4540
  }) : null
@@ -4353,7 +4542,7 @@ function SegmentedNative({ node, props, rootProps, emit, scope }) {
4353
4542
  });
4354
4543
  };
4355
4544
  if (bar)
4356
- return /* @__PURE__ */ jsx16(SegmentedBar, {
4545
+ return /* @__PURE__ */ jsx17(SegmentedBar, {
4357
4546
  node,
4358
4547
  rootProps,
4359
4548
  vertical,
@@ -4368,7 +4557,7 @@ function SegmentedNative({ node, props, rootProps, emit, scope }) {
4368
4557
  });
4369
4558
  const body = items.map((item) => {
4370
4559
  const selected = isSelected(item);
4371
- return /* @__PURE__ */ jsx16(ToggleGroupPrimitive.Item, {
4560
+ return /* @__PURE__ */ jsx17(ToggleGroupPrimitive.Item, {
4372
4561
  value: item.value,
4373
4562
  disabled: bool(item.disabled),
4374
4563
  "aria-label": item.label ? undefined : item.value,
@@ -4377,7 +4566,7 @@ function SegmentedNative({ node, props, rootProps, emit, scope }) {
4377
4566
  }, item.value);
4378
4567
  });
4379
4568
  if (multiple) {
4380
- return /* @__PURE__ */ jsx16(ToggleGroupPrimitive.Root, {
4569
+ return /* @__PURE__ */ jsx17(ToggleGroupPrimitive.Root, {
4381
4570
  ...rootProps,
4382
4571
  type: "multiple",
4383
4572
  value: Array.isArray(value) ? value : asArray(value),
@@ -4391,7 +4580,7 @@ function SegmentedNative({ node, props, rootProps, emit, scope }) {
4391
4580
  children: body
4392
4581
  });
4393
4582
  }
4394
- return /* @__PURE__ */ jsx16(ToggleGroupPrimitive.Root, {
4583
+ return /* @__PURE__ */ jsx17(ToggleGroupPrimitive.Root, {
4395
4584
  ...rootProps,
4396
4585
  type: "single",
4397
4586
  value,
@@ -4409,7 +4598,7 @@ function SegmentedNative({ node, props, rootProps, emit, scope }) {
4409
4598
  }
4410
4599
  function SegmentedBar({ rootProps, vertical, items, value, part, content, onPick }) {
4411
4600
  const ctx = useSurfaceContext();
4412
- const refs = useRef18([]);
4601
+ const refs = useRef19([]);
4413
4602
  const enabled = items.map((item, i) => bool(item.disabled) ? -1 : i).filter((i) => i >= 0);
4414
4603
  const selectedIndex = items.findIndex((item) => item.value === value && !bool(item.disabled));
4415
4604
  const [focusIndex, setFocusIndex] = useState15(null);
@@ -4436,13 +4625,13 @@ function SegmentedBar({ rootProps, vertical, items, value, part, content, onPick
4436
4625
  refs.current[next]?.focus();
4437
4626
  return true;
4438
4627
  };
4439
- return /* @__PURE__ */ jsx16("nav", {
4628
+ return /* @__PURE__ */ jsx17("nav", {
4440
4629
  ...rootProps,
4441
4630
  dir: ctx.direction,
4442
4631
  children: items.map((item, i) => {
4443
4632
  const selected = item.value === value;
4444
4633
  const disabled = bool(item.disabled);
4445
- return /* @__PURE__ */ jsx16("button", {
4634
+ return /* @__PURE__ */ jsx17("button", {
4446
4635
  ref: (el) => void (refs.current[i] = el),
4447
4636
  type: "button",
4448
4637
  ...part(`item`, selected && `selected`, disabled && `disabled`),
@@ -4476,9 +4665,9 @@ function AccordionNative({ node, props, rootProps, emit, scope }) {
4476
4665
  value: item.value,
4477
4666
  ...part.at(`item`, i, open && `open`),
4478
4667
  children: [
4479
- /* @__PURE__ */ jsx16(AccordionPrimitive.Header, {
4668
+ /* @__PURE__ */ jsx17(AccordionPrimitive.Header, {
4480
4669
  asChild: true,
4481
- children: /* @__PURE__ */ jsx16("div", {
4670
+ children: /* @__PURE__ */ jsx17("div", {
4482
4671
  style: { display: `flex` },
4483
4672
  children: /* @__PURE__ */ jsxs13(AccordionPrimitive.Trigger, {
4484
4673
  ...part.at(`trigger`, i, open && `open`),
@@ -4487,13 +4676,13 @@ function AccordionNative({ node, props, rootProps, emit, scope }) {
4487
4676
  className: "xui-accordion-title",
4488
4677
  children: [
4489
4678
  str(item.title),
4490
- item.count !== undefined ? /* @__PURE__ */ jsx16("span", {
4679
+ item.count !== undefined ? /* @__PURE__ */ jsx17("span", {
4491
4680
  ...part.at(`count`, i),
4492
4681
  children: ctx.formatter.number(num(item.count))
4493
4682
  }) : null
4494
4683
  ]
4495
4684
  }),
4496
- /* @__PURE__ */ jsx16(BuiltinIcon, {
4685
+ /* @__PURE__ */ jsx17(BuiltinIcon, {
4497
4686
  slot: "Accordion.trigger",
4498
4687
  size: 16
4499
4688
  })
@@ -4501,9 +4690,9 @@ function AccordionNative({ node, props, rootProps, emit, scope }) {
4501
4690
  })
4502
4691
  })
4503
4692
  }),
4504
- /* @__PURE__ */ jsx16(AccordionPrimitive.Content, {
4693
+ /* @__PURE__ */ jsx17(AccordionPrimitive.Content, {
4505
4694
  ...part.at(`content`, i, open && `open`),
4506
- children: node.children[i] ? /* @__PURE__ */ jsx16(NodeView, {
4695
+ children: node.children[i] ? /* @__PURE__ */ jsx17(NodeView, {
4507
4696
  node: node.children[i]
4508
4697
  }) : null
4509
4698
  })
@@ -4511,7 +4700,7 @@ function AccordionNative({ node, props, rootProps, emit, scope }) {
4511
4700
  }, item.value);
4512
4701
  });
4513
4702
  if (multiple) {
4514
- return /* @__PURE__ */ jsx16(AccordionPrimitive.Root, {
4703
+ return /* @__PURE__ */ jsx17(AccordionPrimitive.Root, {
4515
4704
  ...rootProps,
4516
4705
  type: "multiple",
4517
4706
  value: asArray(value),
@@ -4523,7 +4712,7 @@ function AccordionNative({ node, props, rootProps, emit, scope }) {
4523
4712
  children: body
4524
4713
  });
4525
4714
  }
4526
- return /* @__PURE__ */ jsx16(AccordionPrimitive.Root, {
4715
+ return /* @__PURE__ */ jsx17(AccordionPrimitive.Root, {
4527
4716
  ...rootProps,
4528
4717
  type: "single",
4529
4718
  collapsible: true,
@@ -4539,17 +4728,17 @@ function AccordionNative({ node, props, rootProps, emit, scope }) {
4539
4728
  var asArray = (v) => Array.isArray(v) ? v : v ? v.split(`,`) : [];
4540
4729
 
4541
4730
  // packages/exponential-ui-react/src/natives/overlays.tsx
4542
- import { forwardRef as forwardRef2, useCallback as useCallback8, useEffect as useEffect15, useRef as useRef20, useState as useState17 } from "react";
4731
+ import { forwardRef as forwardRef2, useCallback as useCallback8, useEffect as useEffect16, useRef as useRef21, useState as useState17 } from "react";
4543
4732
  import { createPortal } from "react-dom";
4544
4733
  import { ContextMenu as ContextPrimitive, Dialog as DialogPrimitive, DropdownMenu as MenuPrimitive, Popover as PopoverPrimitive2, Tooltip as TooltipPrimitive } from "radix-ui";
4545
4734
  import { OVERLAY_OFFSET as OVERLAY_OFFSET2, OVERLAY_PADDING as OVERLAY_PADDING2 } from "@exponential_app/eui";
4546
- import { isBinding as isBinding2 } from "@exponential_app/eui/web";
4735
+ import { isBinding as isBinding2, overlayOpenFocus } from "@exponential_app/eui/web";
4547
4736
  import { absolutePath as absolutePath2 } from "@exponential_app/eui/web";
4548
4737
 
4549
4738
  // packages/exponential-ui-react/src/natives/search.tsx
4550
- import { useEffect as useEffect14, useId as useId5, useLayoutEffect as useLayoutEffect5, useRef as useRef19, useState as useState16 } from "react";
4739
+ import { useEffect as useEffect15, useId as useId5, useLayoutEffect as useLayoutEffect6, useRef as useRef20, useState as useState16 } from "react";
4551
4740
  import { elementScale } from "@exponential_app/eui/web";
4552
- import { jsx as jsx17, jsxs as jsxs14, Fragment as Fragment4 } from "react/jsx-runtime";
4741
+ import { jsx as jsx18, jsxs as jsxs14, Fragment as Fragment5 } from "react/jsx-runtime";
4553
4742
  function searchMatches(item, query) {
4554
4743
  const needle = query.trim().toLowerCase();
4555
4744
  return needle === `` || str(item.label).toLowerCase().includes(needle) || str(item.identifier).toLowerCase().includes(needle);
@@ -4558,7 +4747,7 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4558
4747
  const ctx = useSurfaceContext();
4559
4748
  const listId = useId5();
4560
4749
  const [active, setActive] = useState16(0);
4561
- const listRef = useRef19(null);
4750
+ const listRef = useRef20(null);
4562
4751
  const [moreBelow, setMoreBelow] = useState16(false);
4563
4752
  const at = Math.min(active, Math.max(0, rows.length - 1));
4564
4753
  const single = (name) => {
@@ -4567,14 +4756,14 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4567
4756
  attrs[`data-xui-id`] = `${attrs[`data-xui-id`]}${suffix}`;
4568
4757
  return attrs;
4569
4758
  };
4570
- useEffect14(() => setActive(0), [query]);
4759
+ useEffect15(() => setActive(0), [query]);
4571
4760
  const measure = () => {
4572
4761
  const list = listRef.current;
4573
4762
  if (list)
4574
4763
  setMoreBelow(list.scrollTop + list.clientHeight < list.scrollHeight - 1);
4575
4764
  };
4576
- useLayoutEffect5(measure, [rows.length, maxRows]);
4577
- useLayoutEffect5(() => {
4765
+ useLayoutEffect6(measure, [rows.length, maxRows]);
4766
+ useLayoutEffect6(() => {
4578
4767
  const list = listRef.current;
4579
4768
  const row = list?.querySelector(`[data-active="true"]`);
4580
4769
  if (!list || !row)
@@ -4608,7 +4797,7 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4608
4797
  }
4609
4798
  };
4610
4799
  const activeId = rows[at] ? `${listId}-${rows[at].index}` : undefined;
4611
- return /* @__PURE__ */ jsxs14(Fragment4, {
4800
+ return /* @__PURE__ */ jsxs14(Fragment5, {
4612
4801
  children: [
4613
4802
  /* @__PURE__ */ jsxs14("div", {
4614
4803
  ...single(`head`),
@@ -4616,10 +4805,10 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4616
4805
  /* @__PURE__ */ jsxs14("div", {
4617
4806
  ...single(`search`),
4618
4807
  children: [
4619
- /* @__PURE__ */ jsx17(BuiltinIcon, {
4808
+ /* @__PURE__ */ jsx18(BuiltinIcon, {
4620
4809
  slot: "SearchList.search"
4621
4810
  }),
4622
- /* @__PURE__ */ jsx17("input", {
4811
+ /* @__PURE__ */ jsx18("input", {
4623
4812
  type: "text",
4624
4813
  role: "combobox",
4625
4814
  "aria-expanded": "true",
@@ -4634,7 +4823,7 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4634
4823
  })
4635
4824
  ]
4636
4825
  }),
4637
- showCount && query.trim() !== `` ? /* @__PURE__ */ jsx17("span", {
4826
+ showCount && query.trim() !== `` ? /* @__PURE__ */ jsx18("span", {
4638
4827
  ...single(`count`),
4639
4828
  role: "status",
4640
4829
  "aria-live": "polite",
@@ -4656,7 +4845,7 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4656
4845
  rows.map(({ index, item }, pos) => {
4657
4846
  const isActive = pos === at;
4658
4847
  const disabled = bool(item.disabled);
4659
- return /* @__PURE__ */ jsx17("div", {
4848
+ return /* @__PURE__ */ jsx18("div", {
4660
4849
  id: `${listId}-${index}`,
4661
4850
  role: "option",
4662
4851
  "aria-selected": isActive,
@@ -4666,28 +4855,28 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4666
4855
  onPointerMove: () => pos !== at && setActive(pos),
4667
4856
  onPointerDown: (e) => e.preventDefault(),
4668
4857
  onClick: () => pick(pos),
4669
- children: renderRow ? renderRow(item, index) : /* @__PURE__ */ jsxs14(Fragment4, {
4858
+ children: renderRow ? renderRow(item, index) : /* @__PURE__ */ jsxs14(Fragment5, {
4670
4859
  children: [
4671
- item.icon ? /* @__PURE__ */ jsx17("span", {
4860
+ item.icon ? /* @__PURE__ */ jsx18("span", {
4672
4861
  ...part.at(`icon`, index),
4673
4862
  "aria-hidden": "true",
4674
- children: /* @__PURE__ */ jsx17(IconGlyph, {
4863
+ children: /* @__PURE__ */ jsx18(IconGlyph, {
4675
4864
  icons: ctx.host.icons,
4676
4865
  name: item.icon
4677
4866
  })
4678
4867
  }) : null,
4679
- str(item.identifier) ? /* @__PURE__ */ jsx17("span", {
4868
+ str(item.identifier) ? /* @__PURE__ */ jsx18("span", {
4680
4869
  ...part.at(`identifier`, index),
4681
4870
  children: str(item.identifier)
4682
4871
  }) : null,
4683
- /* @__PURE__ */ jsx17("span", {
4872
+ /* @__PURE__ */ jsx18("span", {
4684
4873
  ...part.at(`label`, index),
4685
4874
  children: str(item.label)
4686
4875
  }),
4687
- picked !== undefined && picked !== `` && item.value === picked ? /* @__PURE__ */ jsx17("span", {
4876
+ picked !== undefined && picked !== `` && item.value === picked ? /* @__PURE__ */ jsx18("span", {
4688
4877
  ...part.at(`check`, index),
4689
4878
  "aria-hidden": "true",
4690
- children: /* @__PURE__ */ jsx17(BuiltinIcon, {
4879
+ children: /* @__PURE__ */ jsx18(BuiltinIcon, {
4691
4880
  slot: "SearchList.check"
4692
4881
  })
4693
4882
  }) : null
@@ -4695,13 +4884,13 @@ function SearchBody({ part, owner, suffix, rows, query, onQuery, placeholder, em
4695
4884
  })
4696
4885
  }, `${index}`);
4697
4886
  }),
4698
- rows.length === 0 ? /* @__PURE__ */ jsx17("div", {
4887
+ rows.length === 0 ? /* @__PURE__ */ jsx18("div", {
4699
4888
  ...single(`empty`),
4700
4889
  children: emptyText
4701
4890
  }) : null
4702
4891
  ]
4703
4892
  }),
4704
- moreBelow && rows.length > maxRows ? /* @__PURE__ */ jsx17("div", {
4893
+ moreBelow && rows.length > maxRows ? /* @__PURE__ */ jsx18("div", {
4705
4894
  ...single(`fade`),
4706
4895
  "aria-hidden": "true"
4707
4896
  }) : null
@@ -4717,8 +4906,8 @@ function SearchListNative({ node, props, rootProps, emit, scope }) {
4717
4906
  const [query, setQuery] = useBoundState(node, scope, `query`, str(props.query));
4718
4907
  const [picked, setPicked] = useBoundState(node, scope, `value`, str(props.value));
4719
4908
  const hostSearches = Boolean(node.on?.search);
4720
- const typed = useRef19(false);
4721
- useEffect14(() => {
4909
+ const typed = useRef20(false);
4910
+ useEffect15(() => {
4722
4911
  if (!typed.current)
4723
4912
  return;
4724
4913
  const t = setTimeout(() => void emit(`search`, { query }), DEBOUNCE_MS);
@@ -4726,9 +4915,9 @@ function SearchListNative({ node, props, rootProps, emit, scope }) {
4726
4915
  }, [query]);
4727
4916
  const rows = items.map((item, index) => ({ index, item })).filter(({ item }) => hostSearches || searchMatches(item, query));
4728
4917
  const maxRows = Math.max(1, Math.floor(num(props.maxRows, 8)));
4729
- return /* @__PURE__ */ jsx17("div", {
4918
+ return /* @__PURE__ */ jsx18("div", {
4730
4919
  ...rootProps,
4731
- children: /* @__PURE__ */ jsx17(SearchBody, {
4920
+ children: /* @__PURE__ */ jsx18(SearchBody, {
4732
4921
  part,
4733
4922
  owner: "SearchList",
4734
4923
  suffix: "",
@@ -4752,7 +4941,7 @@ function SearchListNative({ node, props, rootProps, emit, scope }) {
4752
4941
  }
4753
4942
 
4754
4943
  // packages/exponential-ui-react/src/natives/overlays.tsx
4755
- import { jsx as jsx18, jsxs as jsxs15, Fragment as Fragment5 } from "react/jsx-runtime";
4944
+ import { jsx as jsx19, jsxs as jsxs15, Fragment as Fragment6 } from "react/jsx-runtime";
4756
4945
  function useOpenState(node, scope, external, emit) {
4757
4946
  const [open, setOpen] = useBoundState(node, scope, `open`, external);
4758
4947
  const change = useCallback8((next) => {
@@ -4762,7 +4951,7 @@ function useOpenState(node, scope, external, emit) {
4762
4951
  return [open, change];
4763
4952
  }
4764
4953
  var Trigger = forwardRef2(function Trigger({ children, ...rest }, ref) {
4765
- return /* @__PURE__ */ jsx18("span", {
4954
+ return /* @__PURE__ */ jsx19("span", {
4766
4955
  ref,
4767
4956
  className: "xui-trigger",
4768
4957
  ...rest,
@@ -4775,20 +4964,20 @@ function overlayRootProps(rootProps, trigger, triggerNode) {
4775
4964
  return { ...rootProps, "data-xui-overlay-root": triggerNode?.component === `Link` ? `stretch` : `` };
4776
4965
  }
4777
4966
  function DialogNative(p) {
4778
- return /* @__PURE__ */ jsx18(ModalNative, {
4967
+ return /* @__PURE__ */ jsx19(ModalNative, {
4779
4968
  ...p,
4780
4969
  kind: "Dialog"
4781
4970
  });
4782
4971
  }
4783
4972
  function DrawerNative(p) {
4784
- return /* @__PURE__ */ jsx18(ModalNative, {
4973
+ return /* @__PURE__ */ jsx19(ModalNative, {
4785
4974
  ...p,
4786
4975
  kind: "Drawer"
4787
4976
  });
4788
4977
  }
4789
4978
  function useDragToDismiss(side, enabled, onDismiss, reducedMotion) {
4790
- const panel = useRef20(null);
4791
- const drag = useRef20(null);
4979
+ const panel = useRef21(null);
4980
+ const drag = useRef21(null);
4792
4981
  const sign = side === `bottom` || side === `right` ? 1 : -1;
4793
4982
  const axis = side === `left` || side === `right` ? `x` : `y`;
4794
4983
  const distance = (e) => {
@@ -4848,11 +5037,11 @@ function ModalNative({ node, props, rootProps, emit, children, slots, scope, kin
4848
5037
  open,
4849
5038
  onOpenChange: (next) => next || dismissible ? setOpen(next) : undefined,
4850
5039
  children: [
4851
- /* @__PURE__ */ jsx18("div", {
5040
+ /* @__PURE__ */ jsx19("div", {
4852
5041
  ...overlayRootProps(rootProps, slots.trigger, node.slots?.trigger),
4853
- children: slots.trigger ? /* @__PURE__ */ jsx18(DialogPrimitive.Trigger, {
5042
+ children: slots.trigger ? /* @__PURE__ */ jsx19(DialogPrimitive.Trigger, {
4854
5043
  asChild: true,
4855
- children: /* @__PURE__ */ jsx18(Trigger, {
5044
+ children: /* @__PURE__ */ jsx19(Trigger, {
4856
5045
  children: slots.trigger
4857
5046
  })
4858
5047
  }) : null
@@ -4860,7 +5049,7 @@ function ModalNative({ node, props, rootProps, emit, children, slots, scope, kin
4860
5049
  /* @__PURE__ */ jsxs15(DialogPrimitive.Portal, {
4861
5050
  container: ctx.portal ?? undefined,
4862
5051
  children: [
4863
- /* @__PURE__ */ jsx18(DialogPrimitive.Overlay, {
5052
+ /* @__PURE__ */ jsx19(DialogPrimitive.Overlay, {
4864
5053
  ...part(`overlay`, open && `open`),
4865
5054
  "data-xui-overlay-backdrop": kind
4866
5055
  }),
@@ -4874,18 +5063,10 @@ function ModalNative({ node, props, rootProps, emit, children, slots, scope, kin
4874
5063
  onEscapeKeyDown: dismissible ? undefined : (e) => e.preventDefault(),
4875
5064
  onPointerDownOutside: dismissible ? undefined : (e) => e.preventDefault(),
4876
5065
  onInteractOutside: dismissible ? undefined : (e) => e.preventDefault(),
4877
- onOpenAutoFocus: (e) => {
4878
- const content = e.currentTarget;
4879
- const marked = content?.querySelector(`[data-xui-autofocus]`) ?? content?.querySelector(`[data-xui-part="AlertDialog/cancel"]`);
4880
- const target = marked && (marked.matches(`button,input,textarea,select,a[href],[tabindex]`) ? marked : marked.querySelector(`button,input,textarea,select,a[href],[tabindex]`));
4881
- if (target) {
4882
- e.preventDefault();
4883
- target.focus();
4884
- }
4885
- },
5066
+ onOpenAutoFocus: overlayOpenFocus,
4886
5067
  ...description ? {} : { "aria-describedby": undefined },
4887
5068
  children: [
4888
- kind === `Drawer` && (side === `bottom` || side === `top`) ? /* @__PURE__ */ jsx18("div", {
5069
+ kind === `Drawer` && (side === `bottom` || side === `top`) ? /* @__PURE__ */ jsx19("div", {
4889
5070
  ...part(`handle`),
4890
5071
  "aria-hidden": "true",
4891
5072
  ...drag.handlers
@@ -4894,39 +5075,39 @@ function ModalNative({ node, props, rootProps, emit, children, slots, scope, kin
4894
5075
  className: "xui-overlay-head",
4895
5076
  ...kind === `Drawer` ? drag.handlers : {},
4896
5077
  children: [
4897
- title ? /* @__PURE__ */ jsx18(DialogPrimitive.Title, {
5078
+ title ? /* @__PURE__ */ jsx19(DialogPrimitive.Title, {
4898
5079
  ...part(`title`),
4899
5080
  children: title
4900
- }) : /* @__PURE__ */ jsx18(DialogPrimitive.Title, {
5081
+ }) : /* @__PURE__ */ jsx19(DialogPrimitive.Title, {
4901
5082
  className: "xui-sr-only",
4902
5083
  children: ctx.t(`dialog`)
4903
5084
  }),
4904
- description ? /* @__PURE__ */ jsx18(DialogPrimitive.Description, {
5085
+ description ? /* @__PURE__ */ jsx19(DialogPrimitive.Description, {
4905
5086
  ...part(`description`),
4906
5087
  children: description
4907
5088
  }) : null
4908
5089
  ]
4909
- }) : /* @__PURE__ */ jsx18(DialogPrimitive.Title, {
5090
+ }) : /* @__PURE__ */ jsx19(DialogPrimitive.Title, {
4910
5091
  className: "xui-sr-only",
4911
5092
  children: ctx.t(`dialog`)
4912
5093
  }),
4913
5094
  /* @__PURE__ */ jsxs15(CloseOnSubmitContext.Provider, {
4914
5095
  value: dismissible ? close : null,
4915
5096
  children: [
4916
- /* @__PURE__ */ jsx18("div", {
5097
+ /* @__PURE__ */ jsx19("div", {
4917
5098
  className: "xui-overlay-body",
4918
5099
  children
4919
5100
  }),
4920
- slots.footer ? /* @__PURE__ */ jsx18("div", {
5101
+ slots.footer ? /* @__PURE__ */ jsx19("div", {
4921
5102
  ...part(`footer`),
4922
5103
  children: slots.footer
4923
5104
  }) : null
4924
5105
  ]
4925
5106
  }),
4926
- kind === `Dialog` && dismissible ? /* @__PURE__ */ jsx18(DialogPrimitive.Close, {
5107
+ kind === `Dialog` && dismissible ? /* @__PURE__ */ jsx19(DialogPrimitive.Close, {
4927
5108
  ...part(`close`),
4928
5109
  "aria-label": ctx.t(`close`),
4929
- children: /* @__PURE__ */ jsx18(BuiltinIcon, {
5110
+ children: /* @__PURE__ */ jsx19(BuiltinIcon, {
4930
5111
  slot: "Dialog.close"
4931
5112
  })
4932
5113
  }) : null
@@ -4945,10 +5126,10 @@ function PopoverNative({ node, props, rootProps, emit, children, slots, scope })
4945
5126
  const [open, setOpen] = useOpenState(node, scope, bool(props.open), emit);
4946
5127
  const side = str(props.side, `bottom`);
4947
5128
  const hoverMode = props.openOn === `hover` && ctx.hover;
4948
- const timer = useRef20(null);
4949
- const openRef = useRef20(open);
5129
+ const timer = useRef21(null);
5130
+ const openRef = useRef21(open);
4950
5131
  openRef.current = open;
4951
- const contentRef = useRef20(null);
5132
+ const contentRef = useRef21(null);
4952
5133
  const schedule = (next) => {
4953
5134
  if (timer.current)
4954
5135
  clearTimeout(timer.current);
@@ -4957,7 +5138,7 @@ function PopoverNative({ node, props, rootProps, emit, children, slots, scope })
4957
5138
  setOpen(next);
4958
5139
  }, next ? HOVER_OPEN_MS : HOVER_CLOSE_MS);
4959
5140
  };
4960
- useEffect15(() => () => void (timer.current && clearTimeout(timer.current)), []);
5141
+ useEffect16(() => () => void (timer.current && clearTimeout(timer.current)), []);
4961
5142
  const hoverProps = hoverMode ? {
4962
5143
  onPointerEnter: (e) => e.pointerType !== `touch` && schedule(true),
4963
5144
  onPointerLeave: (e) => e.pointerType !== `touch` && schedule(false),
@@ -4972,24 +5153,24 @@ function PopoverNative({ node, props, rootProps, emit, children, slots, scope })
4972
5153
  open,
4973
5154
  onOpenChange: setOpen,
4974
5155
  children: [
4975
- /* @__PURE__ */ jsx18("div", {
5156
+ /* @__PURE__ */ jsx19("div", {
4976
5157
  ...overlayRootProps(rootProps, slots.trigger, node.slots?.trigger),
4977
- children: slots.trigger ? /* @__PURE__ */ jsx18(PopoverPrimitive2.Trigger, {
5158
+ children: slots.trigger ? /* @__PURE__ */ jsx19(PopoverPrimitive2.Trigger, {
4978
5159
  asChild: true,
4979
- children: /* @__PURE__ */ jsx18(Trigger, {
5160
+ children: /* @__PURE__ */ jsx19(Trigger, {
4980
5161
  ...hoverProps,
4981
5162
  children: slots.trigger
4982
5163
  })
4983
- }) : /* @__PURE__ */ jsx18(PopoverPrimitive2.Anchor, {
5164
+ }) : /* @__PURE__ */ jsx19(PopoverPrimitive2.Anchor, {
4984
5165
  asChild: true,
4985
- children: /* @__PURE__ */ jsx18("span", {
5166
+ children: /* @__PURE__ */ jsx19("span", {
4986
5167
  style: { display: `inline-flex` }
4987
5168
  })
4988
5169
  })
4989
5170
  }),
4990
- /* @__PURE__ */ jsx18(PopoverPrimitive2.Portal, {
5171
+ /* @__PURE__ */ jsx19(PopoverPrimitive2.Portal, {
4991
5172
  container: ctx.portal ?? undefined,
4992
- children: /* @__PURE__ */ jsx18(PopoverPrimitive2.Content, {
5173
+ children: /* @__PURE__ */ jsx19(PopoverPrimitive2.Content, {
4993
5174
  ref: contentRef,
4994
5175
  ...part(`content`, open && `open`),
4995
5176
  side,
@@ -5002,7 +5183,7 @@ function PopoverNative({ node, props, rootProps, emit, children, slots, scope })
5002
5183
  onOpenAutoFocus: hoverMode ? (e) => e.preventDefault() : undefined,
5003
5184
  onPointerEnter: hoverMode ? () => schedule(true) : undefined,
5004
5185
  onPointerLeave: hoverMode ? () => schedule(false) : undefined,
5005
- children: /* @__PURE__ */ jsx18(CloseOnSubmitContext.Provider, {
5186
+ children: /* @__PURE__ */ jsx19(CloseOnSubmitContext.Provider, {
5006
5187
  value: null,
5007
5188
  children
5008
5189
  })
@@ -5016,25 +5197,25 @@ function TooltipNative({ node, props, rootProps, children }) {
5016
5197
  const part = useParts(node, props);
5017
5198
  const side = str(props.side, `top`);
5018
5199
  const content = str(props.content) || str(props.text);
5019
- return /* @__PURE__ */ jsx18(TooltipPrimitive.Provider, {
5200
+ return /* @__PURE__ */ jsx19(TooltipPrimitive.Provider, {
5020
5201
  delayDuration: 300,
5021
5202
  children: /* @__PURE__ */ jsxs15(TooltipPrimitive.Root, {
5022
5203
  children: [
5023
- /* @__PURE__ */ jsx18("div", {
5204
+ /* @__PURE__ */ jsx19("div", {
5024
5205
  ...rootProps,
5025
5206
  "data-xui-overlay-root": "",
5026
- children: /* @__PURE__ */ jsx18(TooltipPrimitive.Trigger, {
5207
+ children: /* @__PURE__ */ jsx19(TooltipPrimitive.Trigger, {
5027
5208
  asChild: true,
5028
- children: /* @__PURE__ */ jsx18("div", {
5209
+ children: /* @__PURE__ */ jsx19("div", {
5029
5210
  ...part(`anchor`),
5030
5211
  tabIndex: 0,
5031
5212
  children
5032
5213
  })
5033
5214
  })
5034
5215
  }),
5035
- /* @__PURE__ */ jsx18(TooltipPrimitive.Portal, {
5216
+ /* @__PURE__ */ jsx19(TooltipPrimitive.Portal, {
5036
5217
  container: ctx.portal ?? undefined,
5037
- children: /* @__PURE__ */ jsx18(TooltipPrimitive.Content, {
5218
+ children: /* @__PURE__ */ jsx19(TooltipPrimitive.Content, {
5038
5219
  ...part(`content`),
5039
5220
  side,
5040
5221
  sideOffset: OVERLAY_OFFSET2,
@@ -5050,13 +5231,13 @@ function TooltipNative({ node, props, rootProps, children }) {
5050
5231
  function MenuSearch({ item, i, part, emit, close }) {
5051
5232
  const ctx = useSurfaceContext();
5052
5233
  const [query, setQuery] = useState17(``);
5053
- const box = useRef20(null);
5054
- useEffect15(() => {
5234
+ const box = useRef21(null);
5235
+ useEffect16(() => {
5055
5236
  const frame = requestAnimationFrame(() => box.current?.querySelector(`input`)?.focus({ preventScroll: true }));
5056
5237
  return () => cancelAnimationFrame(frame);
5057
5238
  }, []);
5058
5239
  const rows = objects(item.items).map((entry, index) => ({ index, entry })).filter(({ entry }) => entry.kind !== `separator` && entry.kind !== `label` && !entry.separator && searchMatches({ label: str(entry.label) }, query)).map(({ index, entry }) => ({ index, item: { label: str(entry.label), value: str(entry.value ?? entry.label), icon: entry.icon, disabled: bool(entry.disabled) } }));
5059
- return /* @__PURE__ */ jsx18("div", {
5240
+ return /* @__PURE__ */ jsx19("div", {
5060
5241
  ref: box,
5061
5242
  className: "xui-menu-search",
5062
5243
  onPointerEnter: (e) => {
@@ -5064,7 +5245,7 @@ function MenuSearch({ item, i, part, emit, close }) {
5064
5245
  if (input && !e.currentTarget.contains(document.activeElement))
5065
5246
  input.focus({ preventScroll: true });
5066
5247
  },
5067
- children: /* @__PURE__ */ jsx18(SearchBody, {
5248
+ children: /* @__PURE__ */ jsx19(SearchBody, {
5068
5249
  part,
5069
5250
  owner: "Menu",
5070
5251
  suffix: `.${i}`,
@@ -5082,13 +5263,13 @@ function MenuSearch({ item, i, part, emit, close }) {
5082
5263
  close();
5083
5264
  },
5084
5265
  rowPart: (_, __, active) => part(`item`, active && `selected`),
5085
- renderRow: (row) => /* @__PURE__ */ jsxs15(Fragment5, {
5266
+ renderRow: (row) => /* @__PURE__ */ jsxs15(Fragment6, {
5086
5267
  children: [
5087
- row.icon ? /* @__PURE__ */ jsx18(IconGlyph, {
5268
+ row.icon ? /* @__PURE__ */ jsx19(IconGlyph, {
5088
5269
  icons: ctx.host.icons,
5089
5270
  name: row.icon
5090
5271
  }) : null,
5091
- /* @__PURE__ */ jsx18("span", {
5272
+ /* @__PURE__ */ jsx19("span", {
5092
5273
  className: "xui-menu-label",
5093
5274
  children: row.label
5094
5275
  })
@@ -5101,24 +5282,24 @@ function MenuItems({ ns, items, rawItems, part, overlay, emit, scope, path, clos
5101
5282
  const ctx = useSurfaceContext();
5102
5283
  const raws = objects(rawItems);
5103
5284
  const N = ns;
5104
- return /* @__PURE__ */ jsx18(Fragment5, {
5285
+ return /* @__PURE__ */ jsx19(Fragment6, {
5105
5286
  children: items.map((item, i) => {
5106
5287
  const kind = item.separator ? `separator` : item.kind ?? `item`;
5107
5288
  const key = `${path}${i}`;
5108
- const icon = item.icon ? /* @__PURE__ */ jsx18(IconGlyph, {
5289
+ const icon = item.icon ? /* @__PURE__ */ jsx19(IconGlyph, {
5109
5290
  icons: ctx.host.icons,
5110
5291
  name: item.icon
5111
5292
  }) : null;
5112
- const shortcut = item.shortcut ? /* @__PURE__ */ jsx18("span", {
5293
+ const shortcut = item.shortcut ? /* @__PURE__ */ jsx19("span", {
5113
5294
  ...part(`shortcut`),
5114
5295
  children: item.shortcut
5115
5296
  }) : null;
5116
5297
  if (kind === `separator`)
5117
- return /* @__PURE__ */ jsx18(N.Separator, {
5298
+ return /* @__PURE__ */ jsx19(N.Separator, {
5118
5299
  ...part(`separator`)
5119
5300
  }, key);
5120
5301
  if (kind === `label`)
5121
- return /* @__PURE__ */ jsx18(N.Label, {
5302
+ return /* @__PURE__ */ jsx19(N.Label, {
5122
5303
  ...part(`label`),
5123
5304
  children: str(item.label)
5124
5305
  }, key);
@@ -5130,33 +5311,33 @@ function MenuItems({ ns, items, rawItems, part, overlay, emit, scope, path, clos
5130
5311
  disabled: bool(item.disabled),
5131
5312
  children: [
5132
5313
  icon,
5133
- /* @__PURE__ */ jsx18("span", {
5314
+ /* @__PURE__ */ jsx19("span", {
5134
5315
  className: "xui-menu-label",
5135
5316
  children: str(item.label)
5136
5317
  }),
5137
- /* @__PURE__ */ jsx18("span", {
5318
+ /* @__PURE__ */ jsx19("span", {
5138
5319
  ...part(`submenuIndicator`),
5139
- children: /* @__PURE__ */ jsx18(BuiltinIcon, {
5320
+ children: /* @__PURE__ */ jsx19(BuiltinIcon, {
5140
5321
  slot: "Menu.submenuIndicator"
5141
5322
  })
5142
5323
  })
5143
5324
  ]
5144
5325
  }),
5145
- /* @__PURE__ */ jsx18(N.Portal, {
5326
+ /* @__PURE__ */ jsx19(N.Portal, {
5146
5327
  container: ctx.portal ?? undefined,
5147
- children: /* @__PURE__ */ jsx18(N.SubContent, {
5328
+ children: /* @__PURE__ */ jsx19(N.SubContent, {
5148
5329
  ...part(`content`),
5149
5330
  sideOffset: 2,
5150
5331
  collisionPadding: OVERLAY_PADDING2,
5151
5332
  "data-xui-overlay": `${overlay}.sub`,
5152
5333
  "data-searchable": item.searchable ? `true` : undefined,
5153
- children: item.searchable ? /* @__PURE__ */ jsx18(MenuSearch, {
5334
+ children: item.searchable ? /* @__PURE__ */ jsx19(MenuSearch, {
5154
5335
  item,
5155
5336
  i: key,
5156
5337
  part,
5157
5338
  emit,
5158
5339
  close
5159
- }) : /* @__PURE__ */ jsx18(MenuItems, {
5340
+ }) : /* @__PURE__ */ jsx19(MenuItems, {
5160
5341
  ns,
5161
5342
  items: objects(item.items),
5162
5343
  rawItems: raws[i]?.items,
@@ -5186,15 +5367,15 @@ function MenuItems({ ns, items, rawItems, part, overlay, emit, scope, path, clos
5186
5367
  },
5187
5368
  onSelect: (e) => e.preventDefault(),
5188
5369
  children: [
5189
- /* @__PURE__ */ jsx18("span", {
5370
+ /* @__PURE__ */ jsx19("span", {
5190
5371
  ...part(`check`),
5191
- children: /* @__PURE__ */ jsx18(N.ItemIndicator, {
5192
- children: /* @__PURE__ */ jsx18(BuiltinIcon, {
5372
+ children: /* @__PURE__ */ jsx19(N.ItemIndicator, {
5373
+ children: /* @__PURE__ */ jsx19(BuiltinIcon, {
5193
5374
  slot: "Menu.check"
5194
5375
  })
5195
5376
  })
5196
5377
  }),
5197
- /* @__PURE__ */ jsx18("span", {
5378
+ /* @__PURE__ */ jsx19("span", {
5198
5379
  className: "xui-menu-label",
5199
5380
  children: str(item.label)
5200
5381
  }),
@@ -5209,7 +5390,7 @@ function MenuItems({ ns, items, rawItems, part, overlay, emit, scope, path, clos
5209
5390
  onSelect: () => void emit(`select`, { value: item.value ?? item.label }),
5210
5391
  children: [
5211
5392
  icon,
5212
- /* @__PURE__ */ jsx18("span", {
5393
+ /* @__PURE__ */ jsx19("span", {
5213
5394
  className: "xui-menu-label",
5214
5395
  children: str(item.label)
5215
5396
  }),
@@ -5220,9 +5401,9 @@ function MenuItems({ ns, items, rawItems, part, overlay, emit, scope, path, clos
5220
5401
  });
5221
5402
  }
5222
5403
  function MenuNative(p) {
5223
- return p.props.openOn === `contextmenu` ? /* @__PURE__ */ jsx18(ContextMenuOpening, {
5404
+ return p.props.openOn === `contextmenu` ? /* @__PURE__ */ jsx19(ContextMenuOpening, {
5224
5405
  ...p
5225
- }) : /* @__PURE__ */ jsx18(PressMenuOpening, {
5406
+ }) : /* @__PURE__ */ jsx19(PressMenuOpening, {
5226
5407
  ...p
5227
5408
  });
5228
5409
  }
@@ -5239,41 +5420,41 @@ function PressMenuOpening({ node, props, rootProps, emit, children, scope }) {
5239
5420
  onOpenChange: setOpen,
5240
5421
  dir: ctx.direction,
5241
5422
  children: [
5242
- /* @__PURE__ */ jsx18("div", {
5423
+ /* @__PURE__ */ jsx19("div", {
5243
5424
  ...overlayRootProps(rootProps, true, child),
5244
- children: /* @__PURE__ */ jsx18(MenuPrimitive.Trigger, {
5425
+ children: /* @__PURE__ */ jsx19(MenuPrimitive.Trigger, {
5245
5426
  asChild: true,
5246
- children: child ? /* @__PURE__ */ jsx18(Trigger, {
5427
+ children: child ? /* @__PURE__ */ jsx19(Trigger, {
5247
5428
  children
5248
5429
  }) : /* @__PURE__ */ jsxs15("button", {
5249
5430
  type: "button",
5250
5431
  ...part(`trigger`, open && `open`),
5251
5432
  "aria-label": label || ctx.t(`menu`),
5252
5433
  children: [
5253
- icon ? /* @__PURE__ */ jsx18(IconGlyph, {
5434
+ icon ? /* @__PURE__ */ jsx19(IconGlyph, {
5254
5435
  icons: ctx.host.icons,
5255
5436
  name: icon,
5256
5437
  className: "xui-icon",
5257
5438
  width: 16,
5258
5439
  height: 16
5259
5440
  }) : null,
5260
- label || !icon ? /* @__PURE__ */ jsx18("span", {
5441
+ label || !icon ? /* @__PURE__ */ jsx19("span", {
5261
5442
  children: label || ctx.t(`menu`)
5262
5443
  }) : null
5263
5444
  ]
5264
5445
  })
5265
5446
  })
5266
5447
  }),
5267
- /* @__PURE__ */ jsx18(MenuPrimitive.Portal, {
5448
+ /* @__PURE__ */ jsx19(MenuPrimitive.Portal, {
5268
5449
  container: ctx.portal ?? undefined,
5269
- children: /* @__PURE__ */ jsx18(MenuPrimitive.Content, {
5450
+ children: /* @__PURE__ */ jsx19(MenuPrimitive.Content, {
5270
5451
  ...part(`content`, open && `open`),
5271
5452
  align: "start",
5272
5453
  sideOffset: OVERLAY_OFFSET2,
5273
5454
  collisionPadding: OVERLAY_PADDING2,
5274
5455
  "data-xui-overlay": "Menu",
5275
5456
  "data-open-on": "press",
5276
- children: /* @__PURE__ */ jsx18(MenuItems, {
5457
+ children: /* @__PURE__ */ jsx19(MenuItems, {
5277
5458
  ns: MenuPrimitive,
5278
5459
  items,
5279
5460
  rawItems: node.props.items,
@@ -5301,9 +5482,9 @@ function ContextMenuOpening({ node, props, rootProps, emit, children, scope }) {
5301
5482
  onOpenChange: setOpen,
5302
5483
  dir: ctx.direction,
5303
5484
  children: [
5304
- /* @__PURE__ */ jsx18(ContextPrimitive.Trigger, {
5485
+ /* @__PURE__ */ jsx19(ContextPrimitive.Trigger, {
5305
5486
  asChild: true,
5306
- children: /* @__PURE__ */ jsx18("div", {
5487
+ children: /* @__PURE__ */ jsx19("div", {
5307
5488
  ...rootProps,
5308
5489
  "data-state": open ? `open` : `closed`,
5309
5490
  onKeyDown: (e) => {
@@ -5316,14 +5497,14 @@ function ContextMenuOpening({ node, props, rootProps, emit, children, scope }) {
5316
5497
  children
5317
5498
  })
5318
5499
  }),
5319
- /* @__PURE__ */ jsx18(ContextPrimitive.Portal, {
5500
+ /* @__PURE__ */ jsx19(ContextPrimitive.Portal, {
5320
5501
  container: ctx.portal ?? undefined,
5321
- children: /* @__PURE__ */ jsx18(ContextPrimitive.Content, {
5502
+ children: /* @__PURE__ */ jsx19(ContextPrimitive.Content, {
5322
5503
  ...part(`content`, open && `open`),
5323
5504
  collisionPadding: OVERLAY_PADDING2,
5324
5505
  "data-xui-overlay": "Menu",
5325
5506
  "data-open-on": "contextmenu",
5326
- children: /* @__PURE__ */ jsx18(MenuItems, {
5507
+ children: /* @__PURE__ */ jsx19(MenuItems, {
5327
5508
  ns: ContextPrimitive,
5328
5509
  items,
5329
5510
  rawItems: node.props.items,
@@ -5347,15 +5528,15 @@ function ToastNative({ node, props, rootProps, emit, scope }) {
5347
5528
  const [paused, setPaused] = useState17(false);
5348
5529
  const duration = props.duration === undefined ? 5000 : Math.max(0, num(props.duration, 5000));
5349
5530
  const type = str(props.type, `info`);
5350
- const remaining = useRef20(duration);
5351
- const startedAt = useRef20(0);
5531
+ const remaining = useRef21(duration);
5532
+ const startedAt = useRef21(0);
5352
5533
  const close = useCallback8(() => {
5353
5534
  setOpenState(false);
5354
5535
  emit(`dismiss`, undefined, { open: false });
5355
5536
  emit(`change`, { open: false }, { open: false });
5356
5537
  }, [setOpenState, emit]);
5357
5538
  const [shown, setShown] = useState17(open);
5358
- useEffect15(() => {
5539
+ useEffect16(() => {
5359
5540
  if (open) {
5360
5541
  setShown(true);
5361
5542
  setLeaving(false);
@@ -5372,7 +5553,7 @@ function ToastNative({ node, props, rootProps, emit, scope }) {
5372
5553
  }, ms);
5373
5554
  return () => clearTimeout(t);
5374
5555
  }, [open]);
5375
- useEffect15(() => {
5556
+ useEffect16(() => {
5376
5557
  if (!open || duration === 0 || paused)
5377
5558
  return;
5378
5559
  startedAt.current = Date.now();
@@ -5406,37 +5587,37 @@ function ToastNative({ node, props, rootProps, emit, scope }) {
5406
5587
  }
5407
5588
  },
5408
5589
  children: [
5409
- /* @__PURE__ */ jsx18("span", {
5590
+ /* @__PURE__ */ jsx19("span", {
5410
5591
  ...part(`icon`),
5411
- children: /* @__PURE__ */ jsx18(BuiltinIcon, {
5592
+ children: /* @__PURE__ */ jsx19(BuiltinIcon, {
5412
5593
  slot: `Toast.icon.${type}`
5413
5594
  })
5414
5595
  }),
5415
5596
  /* @__PURE__ */ jsxs15("div", {
5416
5597
  className: "xui-toast-text",
5417
5598
  children: [
5418
- /* @__PURE__ */ jsx18("span", {
5599
+ /* @__PURE__ */ jsx19("span", {
5419
5600
  ...part(`title`),
5420
5601
  children: title
5421
5602
  }),
5422
- description ? /* @__PURE__ */ jsx18("span", {
5603
+ description ? /* @__PURE__ */ jsx19("span", {
5423
5604
  ...part(`description`),
5424
5605
  children: description
5425
5606
  }) : null
5426
5607
  ]
5427
5608
  }),
5428
- actionLabel ? /* @__PURE__ */ jsx18("button", {
5609
+ actionLabel ? /* @__PURE__ */ jsx19("button", {
5429
5610
  type: "button",
5430
5611
  ...part(`action`),
5431
5612
  onClick: () => void emit(`action`),
5432
5613
  children: actionLabel
5433
5614
  }) : null,
5434
- props.dismissible !== false ? /* @__PURE__ */ jsx18("button", {
5615
+ props.dismissible !== false ? /* @__PURE__ */ jsx19("button", {
5435
5616
  type: "button",
5436
5617
  ...part(`close`),
5437
5618
  "aria-label": ctx.t(`dismiss`),
5438
5619
  onClick: close,
5439
- children: /* @__PURE__ */ jsx18(BuiltinIcon, {
5620
+ children: /* @__PURE__ */ jsx19(BuiltinIcon, {
5440
5621
  slot: "Toast.close"
5441
5622
  })
5442
5623
  }) : null
@@ -5445,10 +5626,10 @@ function ToastNative({ node, props, rootProps, emit, scope }) {
5445
5626
  }
5446
5627
 
5447
5628
  // packages/exponential-ui-react/src/natives/qr.tsx
5448
- import { useEffect as useEffect16, useMemo as useMemo13, useRef as useRef21, useState as useState18 } from "react";
5629
+ import { useEffect as useEffect17, useMemo as useMemo13, useRef as useRef22, useState as useState18 } from "react";
5449
5630
  import { nativeRecipeProps as nativeRecipeProps3, resolveRecipe as resolveRecipe2 } from "@exponential_app/eui";
5450
5631
  import { QR_CORNERS, QR_SCANNER, qrCornerPath, qrFeedColour, qrPaint, qrScanFormats, qrScanReporter } from "@exponential_app/eui/web";
5451
- import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
5632
+ import { jsx as jsx20, jsxs as jsxs16 } from "react/jsx-runtime";
5452
5633
  function recipeOf(ctx, component, part, props) {
5453
5634
  return resolveRecipe2(ctx.theme, { component, part, props: nativeRecipeProps3(component, props, ctx.extensionDefs) }, ctx.mode);
5454
5635
  }
@@ -5475,24 +5656,24 @@ function QrCodeNative({ node, props, rootProps }) {
5475
5656
  "aria-hidden": label ? undefined : `true`,
5476
5657
  "data-empty": paint.matrix ? undefined : `true`,
5477
5658
  children: [
5478
- /* @__PURE__ */ jsx19("span", {
5659
+ /* @__PURE__ */ jsx20("span", {
5479
5660
  ...part(`plate`),
5480
5661
  style: { width: size, height: size, backgroundColor: paint.plate },
5481
- children: paint.matrix ? /* @__PURE__ */ jsx19("svg", {
5662
+ children: paint.matrix ? /* @__PURE__ */ jsx20("svg", {
5482
5663
  viewBox: `0 0 ${paint.modules} ${paint.modules}`,
5483
5664
  width: size,
5484
5665
  height: size,
5485
5666
  shapeRendering: "crispEdges",
5486
5667
  "aria-hidden": "true",
5487
5668
  focusable: "false",
5488
- children: /* @__PURE__ */ jsx19("path", {
5669
+ children: /* @__PURE__ */ jsx20("path", {
5489
5670
  ...part(`module`),
5490
5671
  d: paint.path,
5491
5672
  fill: paint.module
5492
5673
  })
5493
5674
  }) : null
5494
5675
  }),
5495
- label ? /* @__PURE__ */ jsx19("span", {
5676
+ label ? /* @__PURE__ */ jsx20("span", {
5496
5677
  ...part(`label`),
5497
5678
  "aria-hidden": "true",
5498
5679
  children: label
@@ -5507,13 +5688,13 @@ function QrScannerNative({ node, props, rootProps, emit }) {
5507
5688
  const host = ctx.host.qrScanner;
5508
5689
  const formats = qrScanFormats(props.formats);
5509
5690
  const formatsKey = formats.join(`,`);
5510
- const feedRef = useRef21(null);
5691
+ const feedRef = useRef22(null);
5511
5692
  const [live, setLive] = useState18(false);
5512
- const emitRef = useRef21(emit);
5693
+ const emitRef = useRef22(emit);
5513
5694
  emitRef.current = emit;
5514
- const announce = useRef21(ctx.announce);
5695
+ const announce = useRef22(ctx.announce);
5515
5696
  announce.current = ctx.announce;
5516
- useEffect16(() => {
5697
+ useEffect17(() => {
5517
5698
  const feed = feedRef.current;
5518
5699
  if (!host || disabled || !feed) {
5519
5700
  setLive(false);
@@ -5551,19 +5732,19 @@ function QrScannerNative({ node, props, rootProps, emit }) {
5551
5732
  role: "img",
5552
5733
  "aria-label": camera ? label : `${label}, ${ctx.t(`cameraUnavailable`)}`,
5553
5734
  children: [
5554
- /* @__PURE__ */ jsx19("span", {
5735
+ /* @__PURE__ */ jsx20("span", {
5555
5736
  ref: feedRef,
5556
5737
  ...part(`feed`),
5557
5738
  style: { backgroundColor: qrFeedColour(feedColour) },
5558
5739
  "aria-hidden": "true"
5559
5740
  }),
5560
- QR_CORNERS.map((corner) => /* @__PURE__ */ jsx19("svg", {
5741
+ QR_CORNERS.map((corner) => /* @__PURE__ */ jsx20("svg", {
5561
5742
  ...part(`corner`),
5562
5743
  "data-corner": corner,
5563
5744
  viewBox: `0 0 ${QR_SCANNER.cornerLength} ${QR_SCANNER.cornerLength}`,
5564
5745
  "aria-hidden": "true",
5565
5746
  focusable: "false",
5566
- children: /* @__PURE__ */ jsx19("path", {
5747
+ children: /* @__PURE__ */ jsx20("path", {
5567
5748
  d: qrCornerPath(corner, radius),
5568
5749
  fill: "none",
5569
5750
  stroke: "currentColor",
@@ -5572,30 +5753,30 @@ function QrScannerNative({ node, props, rootProps, emit }) {
5572
5753
  strokeLinejoin: "round"
5573
5754
  })
5574
5755
  }, corner)),
5575
- camera ? /* @__PURE__ */ jsx19("span", {
5756
+ camera ? /* @__PURE__ */ jsx20("span", {
5576
5757
  ...part(`scanLine`),
5577
5758
  "aria-hidden": "true"
5578
5759
  }) : /* @__PURE__ */ jsxs16("span", {
5579
5760
  ...part(`placeholder`),
5580
5761
  "aria-hidden": "true",
5581
5762
  children: [
5582
- /* @__PURE__ */ jsx19("span", {
5763
+ /* @__PURE__ */ jsx20("span", {
5583
5764
  ...part(`placeholderIcon`),
5584
- children: /* @__PURE__ */ jsx19(IconGlyph, {
5765
+ children: /* @__PURE__ */ jsx20(IconGlyph, {
5585
5766
  icons: ctx.host.icons,
5586
5767
  name: QR_SCANNER.placeholderIcon,
5587
5768
  width: QR_SCANNER.placeholderIconSize,
5588
5769
  height: QR_SCANNER.placeholderIconSize
5589
5770
  })
5590
5771
  }),
5591
- /* @__PURE__ */ jsx19("span", {
5772
+ /* @__PURE__ */ jsx20("span", {
5592
5773
  children: ctx.t(`cameraUnavailable`)
5593
5774
  })
5594
5775
  ]
5595
5776
  })
5596
5777
  ]
5597
5778
  }),
5598
- hint ? /* @__PURE__ */ jsx19("span", {
5779
+ hint ? /* @__PURE__ */ jsx20("span", {
5599
5780
  ...part(`hint`),
5600
5781
  children: hint
5601
5782
  }) : null
@@ -5604,18 +5785,18 @@ function QrScannerNative({ node, props, rootProps, emit }) {
5604
5785
  }
5605
5786
 
5606
5787
  // packages/exponential-ui-react/src/natives/select.tsx
5607
- import { useEffect as useEffect17, useId as useId6, useMemo as useMemo14, useRef as useRef22, useState as useState19 } from "react";
5788
+ import { useEffect as useEffect18, useId as useId6, useMemo as useMemo14, useRef as useRef23, useState as useState19 } from "react";
5608
5789
  import { Popover as PopoverPrimitive3, Select as SelectPrimitive } from "radix-ui";
5609
5790
  import { OVERLAY_OFFSET as OVERLAY_OFFSET3, OVERLAY_PADDING as OVERLAY_PADDING3 } from "@exponential_app/eui";
5610
5791
  import { boundPath as boundPath3 } from "@exponential_app/eui/web";
5611
- import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
5792
+ import { jsx as jsx21, jsxs as jsxs17 } from "react/jsx-runtime";
5612
5793
  var EMPTY = `\x00xui-empty`;
5613
5794
  var toRadix = (value) => value === `` ? EMPTY : value;
5614
5795
  var fromRadix = (value) => value === EMPTY ? `` : value;
5615
5796
  function useNativeEmptyOption(root, empty) {
5616
- const emptyNow = useRef22(empty);
5797
+ const emptyNow = useRef23(empty);
5617
5798
  emptyNow.current = empty;
5618
- useEffect17(() => {
5799
+ useEffect18(() => {
5619
5800
  if (!root || typeof MutationObserver === `undefined`)
5620
5801
  return;
5621
5802
  const seen = new WeakSet;
@@ -5649,7 +5830,7 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5649
5830
  const raw = props.value;
5650
5831
  const rawIsArray = Array.isArray(raw);
5651
5832
  const [value, setValue] = useBoundState(node, scope, `value`, multiple ? asList(raw) : str(raw));
5652
- const triggerRef = useRef22(null);
5833
+ const triggerRef = useRef23(null);
5653
5834
  const f = useField({ node, domId, props, value, focusRef: triggerRef });
5654
5835
  const disabled = bool(props.disabled) || Boolean(f.form?.disabled);
5655
5836
  const [open, setOpen] = useState19(false);
@@ -5657,7 +5838,7 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5657
5838
  const source = str(props.source);
5658
5839
  const optionsBound = boundPath3(node.props, `options`, scope) !== undefined;
5659
5840
  const [sourced, setSourced] = useState19(null);
5660
- const request = useRef22(0);
5841
+ const request = useRef23(0);
5661
5842
  const askSource = (q) => {
5662
5843
  if (!source || !ctx.host.optionSource)
5663
5844
  return;
@@ -5674,7 +5855,7 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5674
5855
  else
5675
5856
  take(r);
5676
5857
  };
5677
- useEffect17(() => () => {
5858
+ useEffect18(() => () => {
5678
5859
  request.current++;
5679
5860
  }, []);
5680
5861
  const inline = objects(props.options);
@@ -5689,7 +5870,7 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5689
5870
  f.touch();
5690
5871
  emit(`change`, { value: out }, { value: out });
5691
5872
  };
5692
- useEffect17(() => {
5873
+ useEffect18(() => {
5693
5874
  if (!searchable || !open)
5694
5875
  return;
5695
5876
  const t = setTimeout(() => {
@@ -5698,12 +5879,12 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5698
5879
  }, DEBOUNCE_MS);
5699
5880
  return () => clearTimeout(t);
5700
5881
  }, [query, open, searchable, source]);
5701
- useEffect17(() => {
5882
+ useEffect18(() => {
5702
5883
  if (!source || !ctx.host.optionSource || searchable)
5703
5884
  return;
5704
5885
  askSource(``);
5705
5886
  }, [source, ctx.host, searchable]);
5706
- const label = /* @__PURE__ */ jsx20(TextPart, {
5887
+ const label = /* @__PURE__ */ jsx21(TextPart, {
5707
5888
  part: part(`label`),
5708
5889
  text: props.label,
5709
5890
  as: "label",
@@ -5739,26 +5920,26 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5739
5920
  "aria-invalid": f.invalid || undefined,
5740
5921
  "aria-describedby": f.describedBy,
5741
5922
  children: [
5742
- /* @__PURE__ */ jsx20("span", {
5743
- children: chosen ? /* @__PURE__ */ jsx20(SelectPrimitive.Value, {
5923
+ /* @__PURE__ */ jsx21("span", {
5924
+ children: chosen ? /* @__PURE__ */ jsx21(SelectPrimitive.Value, {
5744
5925
  placeholder: chosenLabel,
5745
5926
  children: chosenLabel
5746
- }) : /* @__PURE__ */ jsx20("span", {
5927
+ }) : /* @__PURE__ */ jsx21("span", {
5747
5928
  ...part(`placeholder`),
5748
5929
  children: placeholder
5749
5930
  })
5750
5931
  }),
5751
- /* @__PURE__ */ jsx20(SelectPrimitive.Icon, {
5932
+ /* @__PURE__ */ jsx21(SelectPrimitive.Icon, {
5752
5933
  asChild: true,
5753
- children: /* @__PURE__ */ jsx20(BuiltinIcon, {
5934
+ children: /* @__PURE__ */ jsx21(BuiltinIcon, {
5754
5935
  slot: "Select.trigger"
5755
5936
  })
5756
5937
  })
5757
5938
  ]
5758
5939
  }),
5759
- /* @__PURE__ */ jsx20(SelectPrimitive.Portal, {
5940
+ /* @__PURE__ */ jsx21(SelectPrimitive.Portal, {
5760
5941
  container: ctx.portal ?? undefined,
5761
- children: /* @__PURE__ */ jsx20(SelectPrimitive.Content, {
5942
+ children: /* @__PURE__ */ jsx21(SelectPrimitive.Content, {
5762
5943
  ...part(`content`, open && `open`),
5763
5944
  position: "popper",
5764
5945
  sideOffset: OVERLAY_OFFSET3,
@@ -5767,7 +5948,7 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5767
5948
  style: { minWidth: `var(--radix-select-trigger-width)` },
5768
5949
  children: /* @__PURE__ */ jsxs17(SelectPrimitive.Viewport, {
5769
5950
  children: [
5770
- options.length === 0 ? /* @__PURE__ */ jsx20("div", {
5951
+ options.length === 0 ? /* @__PURE__ */ jsx21("div", {
5771
5952
  ...part(`empty`),
5772
5953
  children: str(props.emptyText) || ctx.t(`noResults`)
5773
5954
  }) : null,
@@ -5776,17 +5957,17 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5776
5957
  disabled: bool(o.disabled),
5777
5958
  ...part(`item`, o.value === value && `selected`, bool(o.disabled) && `disabled`),
5778
5959
  children: [
5779
- o.icon ? /* @__PURE__ */ jsx20(IconGlyph, {
5960
+ o.icon ? /* @__PURE__ */ jsx21(IconGlyph, {
5780
5961
  icons: ctx.host.icons,
5781
5962
  name: o.icon
5782
5963
  }) : null,
5783
- /* @__PURE__ */ jsx20(SelectPrimitive.ItemText, {
5964
+ /* @__PURE__ */ jsx21(SelectPrimitive.ItemText, {
5784
5965
  children: str(o.label)
5785
5966
  }),
5786
- /* @__PURE__ */ jsx20(SelectPrimitive.ItemIndicator, {
5967
+ /* @__PURE__ */ jsx21(SelectPrimitive.ItemIndicator, {
5787
5968
  ...part(`check`),
5788
5969
  className: `${part(`check`).className} xui-Select-check`,
5789
- children: /* @__PURE__ */ jsx20(BuiltinIcon, {
5970
+ children: /* @__PURE__ */ jsx21(BuiltinIcon, {
5790
5971
  slot: "Select.check",
5791
5972
  size: 16
5792
5973
  })
@@ -5799,14 +5980,14 @@ function SelectNative({ node, props, rootProps, emit, scope, domId }) {
5799
5980
  })
5800
5981
  ]
5801
5982
  }),
5802
- /* @__PURE__ */ jsx20(FieldErrors, {
5983
+ /* @__PURE__ */ jsx21(FieldErrors, {
5803
5984
  part,
5804
5985
  field: f
5805
5986
  })
5806
5987
  ]
5807
5988
  });
5808
5989
  }
5809
- return /* @__PURE__ */ jsx20(Combobox, {
5990
+ return /* @__PURE__ */ jsx21(Combobox, {
5810
5991
  ...{ node, props, rootProps, part, id, listId, multiple, searchable, placeholder, options, value, commit, open, setOpen, query, setQuery, disabled, triggerRef, label, source },
5811
5992
  localFilter: !optionsBound && !source,
5812
5993
  field: f
@@ -5817,7 +5998,7 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5817
5998
  const selected = multiple ? value : value ? [value] : [];
5818
5999
  const chosen = options.filter((o) => selected.includes(o.value));
5819
6000
  const shown = useMemo14(() => query && localFilter ? options.filter((o) => str(o.label).toLowerCase().includes(query.toLowerCase())) : options, [options, query, localFilter]);
5820
- const listRef = useRef22(null);
6001
+ const listRef = useRef23(null);
5821
6002
  const pick = (i) => {
5822
6003
  const o = shown[i];
5823
6004
  if (!o || bool(o.disabled))
@@ -5830,21 +6011,21 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5830
6011
  }
5831
6012
  };
5832
6013
  const nav = useListNavigation({ count: shown.length, isDisabled: (i) => bool(shown[i]?.disabled), labelOf: (i) => str(shown[i]?.label), onPick: pick, typeahead: !searchable });
5833
- useEffect17(() => {
6014
+ useEffect18(() => {
5834
6015
  if (open) {
5835
6016
  const i = shown.findIndex((o) => selected.includes(o.value));
5836
6017
  nav.setActive(i >= 0 ? i : shown.findIndex((o) => !bool(o.disabled)));
5837
6018
  } else
5838
6019
  setQuery(``);
5839
6020
  }, [open]);
5840
- useEffect17(() => {
6021
+ useEffect18(() => {
5841
6022
  if (!searchable || !open)
5842
6023
  return;
5843
6024
  nav.setActive(shown.findIndex((o) => !bool(o.disabled)));
5844
6025
  }, [query]);
5845
6026
  const optionId = (i) => `${listId}-${i}`;
5846
6027
  const activeId = nav.active >= 0 && nav.active < shown.length ? optionId(nav.active) : undefined;
5847
- useEffect17(() => {
6028
+ useEffect18(() => {
5848
6029
  if (activeId)
5849
6030
  listRef.current?.querySelector(`[id="${activeId}"]`)?.scrollIntoView?.({ block: `nearest` });
5850
6031
  }, [activeId]);
@@ -5875,18 +6056,18 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5875
6056
  }
5876
6057
  },
5877
6058
  children: [
5878
- /* @__PURE__ */ jsx20("span", {
5879
- children: chosen.length ? chosen.map((o) => str(o.label)).join(`, `) : /* @__PURE__ */ jsx20("span", {
6059
+ /* @__PURE__ */ jsx21("span", {
6060
+ children: chosen.length ? chosen.map((o) => str(o.label)).join(`, `) : /* @__PURE__ */ jsx21("span", {
5880
6061
  ...part(`placeholder`),
5881
6062
  children: placeholder
5882
6063
  })
5883
6064
  }),
5884
- /* @__PURE__ */ jsx20(BuiltinIcon, {
6065
+ /* @__PURE__ */ jsx21(BuiltinIcon, {
5885
6066
  slot: "Select.trigger"
5886
6067
  })
5887
6068
  ]
5888
6069
  }),
5889
- /* @__PURE__ */ jsx20(PopoverPrimitive3.Portal, {
6070
+ /* @__PURE__ */ jsx21(PopoverPrimitive3.Portal, {
5890
6071
  container: ctx.portal ?? undefined,
5891
6072
  children: /* @__PURE__ */ jsxs17(PopoverPrimitive3.Content, {
5892
6073
  ...part(`content`, open && `open`),
@@ -5906,11 +6087,11 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5906
6087
  searchable ? /* @__PURE__ */ jsxs17("div", {
5907
6088
  className: "xui-Select-searchbox",
5908
6089
  children: [
5909
- /* @__PURE__ */ jsx20(BuiltinIcon, {
6090
+ /* @__PURE__ */ jsx21(BuiltinIcon, {
5910
6091
  slot: "Select.search",
5911
6092
  size: 16
5912
6093
  }),
5913
- /* @__PURE__ */ jsx20("input", {
6094
+ /* @__PURE__ */ jsx21("input", {
5914
6095
  ...part(`search`),
5915
6096
  className: `${part(`search`).className} xui-Select-search`,
5916
6097
  role: "combobox",
@@ -5937,7 +6118,7 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5937
6118
  className: "xui-Select-listbox",
5938
6119
  onKeyDown: searchable ? undefined : nav.onKeyDown,
5939
6120
  children: [
5940
- shown.length === 0 ? /* @__PURE__ */ jsx20("div", {
6121
+ shown.length === 0 ? /* @__PURE__ */ jsx21("div", {
5941
6122
  ...part(`empty`),
5942
6123
  children: str(props.emptyText) || ctx.t(`noResults`)
5943
6124
  }) : null,
@@ -5955,17 +6136,17 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5955
6136
  onMouseDown: (e) => e.preventDefault(),
5956
6137
  onClick: () => pick(i),
5957
6138
  children: [
5958
- o.icon ? /* @__PURE__ */ jsx20(IconGlyph, {
6139
+ o.icon ? /* @__PURE__ */ jsx21(IconGlyph, {
5959
6140
  icons: ctx.host.icons,
5960
6141
  name: o.icon
5961
6142
  }) : null,
5962
- /* @__PURE__ */ jsx20("span", {
6143
+ /* @__PURE__ */ jsx21("span", {
5963
6144
  children: str(o.label)
5964
6145
  }),
5965
- isSel ? /* @__PURE__ */ jsx20("span", {
6146
+ isSel ? /* @__PURE__ */ jsx21("span", {
5966
6147
  ...part(`check`),
5967
6148
  className: `${part(`check`).className} xui-Select-check`,
5968
- children: /* @__PURE__ */ jsx20(BuiltinIcon, {
6149
+ children: /* @__PURE__ */ jsx21(BuiltinIcon, {
5969
6150
  slot: "Select.check",
5970
6151
  size: 16
5971
6152
  })
@@ -5980,7 +6161,7 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5980
6161
  })
5981
6162
  ]
5982
6163
  }),
5983
- /* @__PURE__ */ jsx20(FieldErrors, {
6164
+ /* @__PURE__ */ jsx21(FieldErrors, {
5984
6165
  part,
5985
6166
  field
5986
6167
  })
@@ -5989,14 +6170,14 @@ function Combobox({ props, rootProps, part, id, listId, multiple, searchable, pl
5989
6170
  }
5990
6171
 
5991
6172
  // packages/exponential-ui-react/src/natives/table.tsx
5992
- import { useCallback as useCallback9, useContext as useContext5, useEffect as useEffect18, useMemo as useMemo15, useRef as useRef23, useState as useState20 } from "react";
6173
+ import { useCallback as useCallback9, useContext as useContext5, useEffect as useEffect19, useMemo as useMemo15, useRef as useRef24, useState as useState20 } from "react";
5993
6174
  import { Checkbox as CheckboxPrimitive2 } from "radix-ui";
5994
6175
  import { tableRowKeys, WINDOW_THRESHOLD as WINDOW_THRESHOLD2 } from "@exponential_app/eui";
5995
6176
  import { boundPath as boundPath4, getPointer as getPointer2, setPointer as setPointer2, LITERAL_ROWS_ROOT as LITERAL_ROWS_ROOT2 } from "@exponential_app/eui/web";
5996
6177
  import { partClass as partClass3 } from "@exponential_app/eui/web";
5997
6178
  import { displayString as displayString2 } from "@exponential_app/eui";
5998
- import { sortRows } from "@exponential_app/eui/web";
5999
- import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
6179
+ import { sortRows, tableMinWidth, tableTemplate } from "@exponential_app/eui/web";
6180
+ import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
6000
6181
  var CURRENCY_CODE = /^[A-Za-z]{3}$/;
6001
6182
  var cellNumber = (v) => typeof v === `number` ? v : typeof v === `string` && v.trim() !== `` ? Number(v) : NaN;
6002
6183
  function TableNative({ node, props, rootProps, emit, scope, domId }) {
@@ -6015,7 +6196,8 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6015
6196
  const rowKeys = useMemo15(() => tableRowKeys(rows, rowKey), [rows, rowKey]);
6016
6197
  const keyOf = (_row, i) => rowKeys[i] ?? String(i);
6017
6198
  const order = useMemo15(() => sortBound ? rows.map((_, i) => i) : sortRows(rows, sort, columns.find((c) => c.key === sort?.key), ctx.locale), [rows, sort, sortBound, columns, ctx.locale]);
6018
- const template = [selectable === `multiple` ? `var(--xui-control-checkbox, 16px)` : null, ...columns.map((c) => c.width ? `${c.width}px` : `minmax(0, 1fr)`)].filter(Boolean).join(` `);
6199
+ const template = tableTemplate(columns, selectable === `multiple`);
6200
+ const minWidth = tableMinWidth(columns, selectable === `multiple`);
6019
6201
  const cycle = (c) => {
6020
6202
  const next = sort?.key === c.key && sort.direction === `asc` ? { key: c.key, direction: `desc` } : { key: c.key, direction: `asc` };
6021
6203
  setSort(next);
@@ -6033,9 +6215,9 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6033
6215
  const [focusKey, setFocusKey] = useState20(null);
6034
6216
  const orderKeys = order.map((i) => keyOf(rows[i], i));
6035
6217
  const stopKey = focusKey !== null && orderKeys.includes(focusKey) ? focusKey : orderKeys.find((k) => selected.includes(k)) ?? orderKeys[0] ?? null;
6036
- const bodyRef = useRef23(null);
6037
- const windowRef = useRef23(null);
6038
- const pendingFocus = useRef23(null);
6218
+ const bodyRef = useRef24(null);
6219
+ const windowRef = useRef24(null);
6220
+ const pendingFocus = useRef24(null);
6039
6221
  const focusRow = useCallback9((key) => {
6040
6222
  const k = `[role="row"][data-key="${typeof CSS !== `undefined` && CSS.escape ? CSS.escape(key) : key.replace(/"/g, `\\"`)}"]`;
6041
6223
  return bodyRef.current?.querySelector(`:scope > ${k}, :scope > .xui-list-window > .xui-list-item > ${k}`) ?? null;
@@ -6054,7 +6236,7 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6054
6236
  windowRef.current?.scrollToIndex(clamped);
6055
6237
  }
6056
6238
  };
6057
- useEffect18(() => ctx.registerScroller(domId, (index, align) => {
6239
+ useEffect19(() => ctx.registerScroller(domId, (index, align) => {
6058
6240
  const pos = order.indexOf(index);
6059
6241
  if (pos < 0)
6060
6242
  return;
@@ -6086,19 +6268,19 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6086
6268
  case `relativeTime`:
6087
6269
  return missing ? `` : ctx.formatter.relativeTime(v, ctx.now());
6088
6270
  case `boolean`:
6089
- return v ? /* @__PURE__ */ jsx21(BuiltinIcon, {
6271
+ return v ? /* @__PURE__ */ jsx22(BuiltinIcon, {
6090
6272
  slot: "Checkbox.check",
6091
6273
  size: 16
6092
- }) : /* @__PURE__ */ jsx21("span", {
6274
+ }) : /* @__PURE__ */ jsx22("span", {
6093
6275
  className: "xui-sr-only",
6094
6276
  children: "—"
6095
6277
  });
6096
6278
  case `badge`:
6097
- return v === undefined || v === null || v === `` ? null : /* @__PURE__ */ jsx21("span", {
6279
+ return v === undefined || v === null || v === `` ? null : /* @__PURE__ */ jsx22("span", {
6098
6280
  className: `${ctx.compiled.scope} ${partClass3(`Badge`, `root`)} xui-table-badge`,
6099
6281
  "data-xui-part": "Badge/root",
6100
6282
  "data-m-variant": "secondary",
6101
- children: /* @__PURE__ */ jsx21("span", {
6283
+ children: /* @__PURE__ */ jsx22("span", {
6102
6284
  className: `${ctx.compiled.scope} ${partClass3(`Badge`, `label`)}`,
6103
6285
  "data-xui-part": "Badge/label",
6104
6286
  "data-m-variant": "secondary",
@@ -6110,7 +6292,7 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6110
6292
  if (!slot)
6111
6293
  return null;
6112
6294
  const key = keyOf(row, index);
6113
- return /* @__PURE__ */ jsx21(RowScope, {
6295
+ return /* @__PURE__ */ jsx22(RowScope, {
6114
6296
  rowsPath,
6115
6297
  row: rowsPath ? row : literalEdits[key] ?? row,
6116
6298
  rowKey: key,
@@ -6168,55 +6350,60 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6168
6350
  }
6169
6351
  },
6170
6352
  children: [
6171
- selectable === `multiple` ? /* @__PURE__ */ jsx21("div", {
6353
+ selectable === `multiple` ? /* @__PURE__ */ jsx22("div", {
6172
6354
  role: "gridcell",
6173
6355
  className: "xui-table-check",
6174
- children: /* @__PURE__ */ jsx21(CheckboxPrimitive2.Root, {
6356
+ children: /* @__PURE__ */ jsx22(CheckboxPrimitive2.Root, {
6175
6357
  ...part.at(`checkbox`, key, isSel && `checked`),
6176
6358
  className: `${part(`checkbox`).className} xui-Checkbox-box`,
6177
6359
  checked: isSel,
6178
6360
  "aria-label": ctx.t(`selectRow`),
6179
6361
  onClick: (e) => e.stopPropagation(),
6180
6362
  onCheckedChange: (next) => select(next === true ? [...selected, key] : selected.filter((k) => k !== key)),
6181
- children: /* @__PURE__ */ jsx21(CheckboxPrimitive2.Indicator, {
6363
+ children: /* @__PURE__ */ jsx22(CheckboxPrimitive2.Indicator, {
6182
6364
  className: "xui-Checkbox-check",
6183
- children: /* @__PURE__ */ jsx21(BuiltinIcon, {
6365
+ children: /* @__PURE__ */ jsx22(BuiltinIcon, {
6184
6366
  slot: "Checkbox.check"
6185
6367
  })
6186
6368
  })
6187
6369
  })
6188
6370
  }) : null,
6189
- columns.map((c, ci) => /* @__PURE__ */ jsx21("div", {
6371
+ columns.map((c, ci) => /* @__PURE__ */ jsx22("div", {
6190
6372
  role: interactive ? `gridcell` : `cell`,
6191
6373
  ...part.atWith(`cell`, `${key}.${ci}`, { align: c.align ?? `start` }),
6192
6374
  "data-type": c.type ?? `text`,
6193
- children: cell(c, row, index)
6375
+ "data-truncate": c.truncate ? `true` : undefined,
6376
+ children: c.truncate ? /* @__PURE__ */ jsx22("span", {
6377
+ className: "xui-table-text",
6378
+ children: cell(c, row, index)
6379
+ }) : cell(c, row, index)
6194
6380
  }, c.key))
6195
6381
  ]
6196
6382
  }, key);
6197
6383
  };
6198
- const header = /* @__PURE__ */ jsx21("div", {
6384
+ const header = /* @__PURE__ */ jsx22("div", {
6199
6385
  role: "rowgroup",
6200
6386
  ...part(`header`),
6201
6387
  "data-sticky": bool(props.stickyHeader) ? `true` : undefined,
6388
+ style: { minWidth },
6202
6389
  children: /* @__PURE__ */ jsxs18("div", {
6203
6390
  role: "row",
6204
6391
  "aria-rowindex": 1,
6205
6392
  className: "xui-table-row",
6206
6393
  style: { gridTemplateColumns: template },
6207
6394
  children: [
6208
- selectable === `multiple` ? /* @__PURE__ */ jsx21("div", {
6395
+ selectable === `multiple` ? /* @__PURE__ */ jsx22("div", {
6209
6396
  role: "columnheader",
6210
6397
  className: "xui-table-check",
6211
- children: /* @__PURE__ */ jsx21(CheckboxPrimitive2.Root, {
6398
+ children: /* @__PURE__ */ jsx22(CheckboxPrimitive2.Root, {
6212
6399
  ...part.at(`checkbox`, `header`, allSelected && `checked`),
6213
6400
  className: `${part(`checkbox`).className} xui-Checkbox-box`,
6214
6401
  checked: allSelected ? true : someSelected ? `indeterminate` : false,
6215
6402
  "aria-label": ctx.t(`selectAll`),
6216
6403
  onCheckedChange: (next) => select(next === true ? allKeys : []),
6217
- children: /* @__PURE__ */ jsx21(CheckboxPrimitive2.Indicator, {
6404
+ children: /* @__PURE__ */ jsx22(CheckboxPrimitive2.Indicator, {
6218
6405
  className: "xui-Checkbox-check",
6219
- children: /* @__PURE__ */ jsx21(BuiltinIcon, {
6406
+ children: /* @__PURE__ */ jsx22(BuiltinIcon, {
6220
6407
  slot: "Checkbox.check"
6221
6408
  })
6222
6409
  })
@@ -6225,7 +6412,7 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6225
6412
  columns.map((c, ci) => {
6226
6413
  const active = sort?.key === c.key ? sort.direction : null;
6227
6414
  const ariaSort = active === `asc` ? `ascending` : active === `desc` ? `descending` : c.sortable ? `none` : undefined;
6228
- return /* @__PURE__ */ jsx21("div", {
6415
+ return /* @__PURE__ */ jsx22("div", {
6229
6416
  role: "columnheader",
6230
6417
  "aria-sort": ariaSort,
6231
6418
  ...part.atWith(`headerCell`, ci, { align: c.align ?? `start` }),
@@ -6235,19 +6422,19 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6235
6422
  "aria-label": phrase(ctx, active === `asc` ? `sortByDescending` : `sortByAscending`, { name: str(c.label) }, () => `${str(c.label)}: ${ctx.t(active === `asc` ? `sortDescending` : `sortAscending`)}`),
6236
6423
  onClick: () => cycle(c),
6237
6424
  children: [
6238
- /* @__PURE__ */ jsx21("span", {
6425
+ /* @__PURE__ */ jsx22("span", {
6239
6426
  children: str(c.label)
6240
6427
  }),
6241
- /* @__PURE__ */ jsx21("span", {
6428
+ /* @__PURE__ */ jsx22("span", {
6242
6429
  ...part(`sortIcon`),
6243
6430
  "data-direction": active ?? undefined,
6244
6431
  "aria-hidden": "true",
6245
- children: active ? /* @__PURE__ */ jsx21(BuiltinIcon, {
6432
+ children: active ? /* @__PURE__ */ jsx22(BuiltinIcon, {
6246
6433
  slot: `Table.sortIcon.${active}`
6247
6434
  }) : null
6248
6435
  })
6249
6436
  ]
6250
- }) : /* @__PURE__ */ jsx21("span", {
6437
+ }) : /* @__PURE__ */ jsx22("span", {
6251
6438
  children: str(c.label)
6252
6439
  })
6253
6440
  }, c.key);
@@ -6266,19 +6453,20 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6266
6453
  "data-windowed": windowed ? `true` : undefined,
6267
6454
  children: [
6268
6455
  header,
6269
- /* @__PURE__ */ jsx21("div", {
6456
+ /* @__PURE__ */ jsx22("div", {
6270
6457
  role: "rowgroup",
6271
6458
  ...part(`body`),
6272
6459
  className: `${part(`body`).className} xui-table-body`,
6460
+ style: { minWidth },
6273
6461
  ref: bodyRef,
6274
- children: rows.length === 0 ? /* @__PURE__ */ jsx21("div", {
6462
+ children: rows.length === 0 ? /* @__PURE__ */ jsx22("div", {
6275
6463
  role: "row",
6276
- children: /* @__PURE__ */ jsx21("div", {
6464
+ children: /* @__PURE__ */ jsx22("div", {
6277
6465
  role: "cell",
6278
6466
  ...part(`empty`),
6279
6467
  children: str(props.emptyText) || ctx.t(`noResults`)
6280
6468
  })
6281
- }) : windowed ? /* @__PURE__ */ jsx21(WindowedList, {
6469
+ }) : windowed ? /* @__PURE__ */ jsx22(WindowedList, {
6282
6470
  ref: windowRef,
6283
6471
  count: order.length,
6284
6472
  itemKey: (i) => keyOf(rows[order[i]], order[i]),
@@ -6287,12 +6475,12 @@ function TableNative({ node, props, rootProps, emit, scope, domId }) {
6287
6475
  renderItem: renderRow
6288
6476
  }) : order.map((_, pos) => renderRow(pos))
6289
6477
  }),
6290
- caption ? /* @__PURE__ */ jsx21("div", {
6478
+ caption ? /* @__PURE__ */ jsx22("div", {
6291
6479
  ...part(`caption`),
6292
6480
  id: `${domId}.caption`,
6293
6481
  children: caption
6294
6482
  }) : null,
6295
- selectable === `multiple` && selected.length ? /* @__PURE__ */ jsx21("span", {
6483
+ selectable === `multiple` && selected.length ? /* @__PURE__ */ jsx22("span", {
6296
6484
  className: "xui-sr-only",
6297
6485
  "aria-live": "polite",
6298
6486
  children: ctx.t(`selectedCount`, { count: selected.length })
@@ -6316,13 +6504,13 @@ function RowScope({ rowsPath, row, rowKey, index, tableId, node, onLiteralEdit }
6316
6504
  };
6317
6505
  return deriveContext(ctx, { setData }, data);
6318
6506
  }, [ctx, rowsPath, literalPath, row, rowKey, onLiteralEdit]);
6319
- return /* @__PURE__ */ jsx21(SurfaceContext.Provider, {
6507
+ return /* @__PURE__ */ jsx22(SurfaceContext.Provider, {
6320
6508
  value: view,
6321
- children: /* @__PURE__ */ jsx21(ScopeContext.Provider, {
6509
+ children: /* @__PURE__ */ jsx22(ScopeContext.Provider, {
6322
6510
  value: rowsPath ? `${rowsPath}/${index}` : literalPath,
6323
- children: /* @__PURE__ */ jsx21(InstanceContext.Provider, {
6511
+ children: /* @__PURE__ */ jsx22(InstanceContext.Provider, {
6324
6512
  value: `${outer}.${rowKey}`,
6325
- children: /* @__PURE__ */ jsx21(NodeView, {
6513
+ children: /* @__PURE__ */ jsx22(NodeView, {
6326
6514
  node
6327
6515
  })
6328
6516
  })
@@ -6334,25 +6522,25 @@ function RowScope({ rowsPath, row, rowKey, index, tableId, node, onLiteralEdit }
6334
6522
  import { displayString as displayString3 } from "@exponential_app/eui";
6335
6523
 
6336
6524
  // packages/exponential-ui-react/src/markdown.tsx
6337
- import { Fragment as Fragment6, createElement, useMemo as useMemo16 } from "react";
6525
+ import { Fragment as Fragment7, createElement, useMemo as useMemo16 } from "react";
6338
6526
  import { linkHref as linkHref3, mediaRequestOf, parseMarkdown } from "@exponential_app/eui/web";
6339
6527
  import { MAX_LINK_NESTING, MAX_LINK_DEST, MAX_BLOCK_NESTING, linkAt, wholeImage, parseList } from "@exponential_app/eui/web";
6340
- import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
6528
+ import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
6341
6529
  function MarkdownImage({ host, src, alt }) {
6342
6530
  const media = useMediaSource(host, src);
6343
6531
  if (mediaRequestOf(host, src) === null)
6344
- return alt ? /* @__PURE__ */ jsx22("p", {
6532
+ return alt ? /* @__PURE__ */ jsx23("p", {
6345
6533
  className: "xui-Markdown-paragraph",
6346
6534
  children: alt
6347
6535
  }) : null;
6348
- return /* @__PURE__ */ jsx22("div", {
6536
+ return /* @__PURE__ */ jsx23("div", {
6349
6537
  className: "xui-Markdown-image",
6350
6538
  role: "img",
6351
6539
  "aria-label": alt,
6352
- children: media.url && !media.error ? /* @__PURE__ */ jsx22("img", {
6540
+ children: media.url && !media.error ? /* @__PURE__ */ jsx23("img", {
6353
6541
  alt: "",
6354
6542
  src: media.url
6355
- }) : /* @__PURE__ */ jsx22("span", {
6543
+ }) : /* @__PURE__ */ jsx23("span", {
6356
6544
  className: "xui-Markdown-imageAlt",
6357
6545
  children: alt
6358
6546
  })
@@ -6363,7 +6551,7 @@ function MarkdownLink({ host, href, children }) {
6363
6551
  e.preventDefault();
6364
6552
  host.openUrl(href);
6365
6553
  } : undefined;
6366
- return /* @__PURE__ */ jsx22("a", {
6554
+ return /* @__PURE__ */ jsx23("a", {
6367
6555
  className: "xui-Markdown-link",
6368
6556
  href,
6369
6557
  target: "_blank",
@@ -6378,30 +6566,30 @@ function inline(nodes, host) {
6378
6566
  return n;
6379
6567
  switch (n.type) {
6380
6568
  case `code`:
6381
- return /* @__PURE__ */ jsx22("code", {
6569
+ return /* @__PURE__ */ jsx23("code", {
6382
6570
  className: "xui-Markdown-code",
6383
6571
  children: n.text
6384
6572
  }, k);
6385
6573
  case `strong`:
6386
- return /* @__PURE__ */ jsx22("strong", {
6574
+ return /* @__PURE__ */ jsx23("strong", {
6387
6575
  children: inline(n.children, host)
6388
6576
  }, k);
6389
6577
  case `em`:
6390
- return /* @__PURE__ */ jsx22("em", {
6578
+ return /* @__PURE__ */ jsx23("em", {
6391
6579
  children: inline(n.children, host)
6392
6580
  }, k);
6393
6581
  case `del`:
6394
- return /* @__PURE__ */ jsx22("del", {
6582
+ return /* @__PURE__ */ jsx23("del", {
6395
6583
  children: n.text
6396
6584
  }, k);
6397
6585
  case `link`: {
6398
6586
  const href = linkHref3(host, n.dest);
6399
6587
  const label = inline(n.children, host);
6400
- return href ? /* @__PURE__ */ jsx22(MarkdownLink, {
6588
+ return href ? /* @__PURE__ */ jsx23(MarkdownLink, {
6401
6589
  host,
6402
6590
  href,
6403
6591
  children: label
6404
- }, k) : /* @__PURE__ */ jsx22("span", {
6592
+ }, k) : /* @__PURE__ */ jsx23("span", {
6405
6593
  className: "xui-Markdown-link",
6406
6594
  "data-denied": "",
6407
6595
  children: label
@@ -6415,49 +6603,49 @@ function renderList(list, host, key) {
6415
6603
  className: "xui-Markdown-listItem",
6416
6604
  "data-task": item.task === undefined ? undefined : item.task ? `done` : `todo`,
6417
6605
  children: [
6418
- item.task === undefined ? null : /* @__PURE__ */ jsx22("input", {
6606
+ item.task === undefined ? null : /* @__PURE__ */ jsx23("input", {
6419
6607
  type: "checkbox",
6420
6608
  checked: item.task,
6421
6609
  readOnly: true
6422
6610
  }),
6423
6611
  item.task === undefined ? null : ` `,
6424
6612
  inline(item.content, host),
6425
- item.children.map((c, ci) => /* @__PURE__ */ jsx22(Fragment6, {
6613
+ item.children.map((c, ci) => /* @__PURE__ */ jsx23(Fragment7, {
6426
6614
  children: renderList(c, host, ci)
6427
6615
  }, `c${ci}`))
6428
6616
  ]
6429
6617
  }, n));
6430
- return list.ordered ? /* @__PURE__ */ jsx22("ol", {
6618
+ return list.ordered ? /* @__PURE__ */ jsx23("ol", {
6431
6619
  children: items
6432
- }, key) : /* @__PURE__ */ jsx22("ul", {
6620
+ }, key) : /* @__PURE__ */ jsx23("ul", {
6433
6621
  children: items
6434
6622
  }, key);
6435
6623
  }
6436
6624
  function block(b, host, key) {
6437
6625
  switch (b.type) {
6438
6626
  case `paragraph`:
6439
- return /* @__PURE__ */ jsx22("p", {
6627
+ return /* @__PURE__ */ jsx23("p", {
6440
6628
  className: "xui-Markdown-paragraph",
6441
6629
  children: inline(b.children, host)
6442
6630
  }, key);
6443
6631
  case `image`:
6444
- return /* @__PURE__ */ jsx22(MarkdownImage, {
6632
+ return /* @__PURE__ */ jsx23(MarkdownImage, {
6445
6633
  host,
6446
6634
  src: b.src,
6447
6635
  alt: b.alt
6448
6636
  }, key);
6449
6637
  case `codeBlock`:
6450
- return /* @__PURE__ */ jsx22("pre", {
6638
+ return /* @__PURE__ */ jsx23("pre", {
6451
6639
  className: "xui-Markdown-codeBlock",
6452
6640
  "data-lang": b.lang,
6453
- children: /* @__PURE__ */ jsx22("code", {
6641
+ children: /* @__PURE__ */ jsx23("code", {
6454
6642
  children: b.text
6455
6643
  })
6456
6644
  }, key);
6457
6645
  case `heading`:
6458
6646
  return createElement(`h${Math.min(b.level, 6)}`, { key, className: `xui-Markdown-heading`, "data-level": b.level }, ...inline(b.children, host));
6459
6647
  case `quote`:
6460
- return /* @__PURE__ */ jsx22("blockquote", {
6648
+ return /* @__PURE__ */ jsx23("blockquote", {
6461
6649
  className: "xui-Markdown-quote",
6462
6650
  children: blocks(b.children, host)
6463
6651
  }, key);
@@ -6467,17 +6655,17 @@ function block(b, host, key) {
6467
6655
  return /* @__PURE__ */ jsxs19("table", {
6468
6656
  className: "xui-Markdown-table",
6469
6657
  children: [
6470
- /* @__PURE__ */ jsx22("thead", {
6471
- children: /* @__PURE__ */ jsx22("tr", {
6472
- children: b.head.map((h, c) => /* @__PURE__ */ jsx22("th", {
6658
+ /* @__PURE__ */ jsx23("thead", {
6659
+ children: /* @__PURE__ */ jsx23("tr", {
6660
+ children: b.head.map((h, c) => /* @__PURE__ */ jsx23("th", {
6473
6661
  style: b.align[c] ? { textAlign: b.align[c] } : undefined,
6474
6662
  children: inline(h, host)
6475
6663
  }, c))
6476
6664
  })
6477
6665
  }),
6478
- /* @__PURE__ */ jsx22("tbody", {
6479
- children: b.rows.map((r, ri) => /* @__PURE__ */ jsx22("tr", {
6480
- children: r.map((cell, c) => /* @__PURE__ */ jsx22("td", {
6666
+ /* @__PURE__ */ jsx23("tbody", {
6667
+ children: b.rows.map((r, ri) => /* @__PURE__ */ jsx23("tr", {
6668
+ children: r.map((cell, c) => /* @__PURE__ */ jsx23("td", {
6481
6669
  style: b.align[c] ? { textAlign: b.align[c] } : undefined,
6482
6670
  children: inline(cell, host)
6483
6671
  }, c))
@@ -6486,11 +6674,11 @@ function block(b, host, key) {
6486
6674
  ]
6487
6675
  }, key);
6488
6676
  case `rule`:
6489
- return /* @__PURE__ */ jsx22("hr", {}, key);
6677
+ return /* @__PURE__ */ jsx23("hr", {}, key);
6490
6678
  }
6491
6679
  }
6492
6680
  function blocks(tree, host) {
6493
- return tree.map((b, k) => /* @__PURE__ */ jsx22(Fragment6, {
6681
+ return tree.map((b, k) => /* @__PURE__ */ jsx23(Fragment7, {
6494
6682
  children: block(b, host, k)
6495
6683
  }, k));
6496
6684
  }
@@ -6499,14 +6687,14 @@ function renderMarkdown(text, host = {}) {
6499
6687
  }
6500
6688
  function BuiltinMarkdown({ text, className, host }) {
6501
6689
  const tree = useMemo16(() => renderMarkdown(text, host), [text, host]);
6502
- return /* @__PURE__ */ jsx22("div", {
6690
+ return /* @__PURE__ */ jsx23("div", {
6503
6691
  className: className ? `xui-md ${className}` : `xui-md`,
6504
6692
  children: tree
6505
6693
  });
6506
6694
  }
6507
6695
 
6508
6696
  // packages/exponential-ui-react/src/natives/text.tsx
6509
- import { jsx as jsx23 } from "react/jsx-runtime";
6697
+ import { jsx as jsx24 } from "react/jsx-runtime";
6510
6698
  function TextNative({ props, rootProps }) {
6511
6699
  const lines = num(props.lines, 0);
6512
6700
  const align = props.align === `end` ? `end` : props.align === `center` ? `center` : props.align === `start` ? `start` : undefined;
@@ -6514,7 +6702,7 @@ function TextNative({ props, rootProps }) {
6514
6702
  if (lines > 1)
6515
6703
  style.WebkitLineClamp = lines;
6516
6704
  const live = props.live === `polite` || props.live === `assertive` ? props.live : undefined;
6517
- return /* @__PURE__ */ jsx23("span", {
6705
+ return /* @__PURE__ */ jsx24("span", {
6518
6706
  ...rootProps,
6519
6707
  "aria-live": live,
6520
6708
  "aria-atomic": live ? true : undefined,
@@ -6531,14 +6719,14 @@ function MarkdownNative({ props, rootProps }) {
6531
6719
  const text = displayString3(props.text);
6532
6720
  const Host = ctx.host.Markdown;
6533
6721
  const lines = num(props.lines, 0);
6534
- return /* @__PURE__ */ jsx23("div", {
6722
+ return /* @__PURE__ */ jsx24("div", {
6535
6723
  ...rootProps,
6536
6724
  "data-lines": lines > 0 ? lines : undefined,
6537
6725
  style: mergeStyle(rootProps, lines > 0 ? { WebkitLineClamp: lines } : undefined),
6538
- children: Host ? /* @__PURE__ */ jsx23(Host, {
6726
+ children: Host ? /* @__PURE__ */ jsx24(Host, {
6539
6727
  text,
6540
6728
  className: "xui-md"
6541
- }) : /* @__PURE__ */ jsx23(BuiltinMarkdown, {
6729
+ }) : /* @__PURE__ */ jsx24(BuiltinMarkdown, {
6542
6730
  text,
6543
6731
  host: ctx.host
6544
6732
  })
@@ -6548,18 +6736,190 @@ function IconNative({ props, rootProps }) {
6548
6736
  const ctx = useSurfaceContext();
6549
6737
  const name = str(props.name, `ui-icon-placeholder`);
6550
6738
  const label = str(props.label);
6551
- return /* @__PURE__ */ jsx23("span", {
6739
+ return /* @__PURE__ */ jsx24("span", {
6552
6740
  ...rootProps,
6553
6741
  role: label ? `img` : undefined,
6554
6742
  "aria-label": label || undefined,
6555
6743
  "aria-hidden": label ? undefined : true,
6556
- children: /* @__PURE__ */ jsx23(IconGlyph, {
6744
+ children: /* @__PURE__ */ jsx24(IconGlyph, {
6557
6745
  icons: ctx.host.icons,
6558
6746
  name
6559
6747
  })
6560
6748
  });
6561
6749
  }
6562
6750
 
6751
+ // packages/exponential-ui-react/src/natives/zoomable-image.tsx
6752
+ import { useEffect as useEffect20, useMemo as useMemo17, useState as useState21 } from "react";
6753
+ import { DropdownMenu as MenuPrimitive2 } from "radix-ui";
6754
+ import { MEDIA_INTRINSIC_WIDTH as MEDIA_INTRINSIC_WIDTH2, OVERLAY_OFFSET as OVERLAY_OFFSET4, OVERLAY_PADDING as OVERLAY_PADDING4, ZOOM } from "@exponential_app/eui";
6755
+ import { ZOOMABLE_IMAGE_NATIVE_TRANSITION, zoomBoxAspect, zoomableImageLayout } from "@exponential_app/eui/web/primitives";
6756
+ import { jsx as jsx25, jsxs as jsxs20 } from "react/jsx-runtime";
6757
+ var LAYOUT = zoomableImageLayout(ZOOM.pill);
6758
+ var positive = (v) => typeof v === `number` && Number.isFinite(v) && v > 0 ? v : undefined;
6759
+ function ZoomableImageNative({ node, props, rootProps, emit, scope }) {
6760
+ const ctx = useSurfaceContext();
6761
+ const part = useParts(node, props);
6762
+ const menuNode = useMemo17(() => ({ id: `${node.id}.menu`, component: `Menu`, props: {}, children: [] }), [node.id]);
6763
+ const menuPart = useParts(menuNode, menuNode.props);
6764
+ const src = str(props.src);
6765
+ const alt = str(props.alt);
6766
+ const controls = str(props.controls, `auto`);
6767
+ const media = useMediaSource(ctx.host, src);
6768
+ const [, setScale] = useBoundState(node, scope, `scale`, positive(props.scale));
6769
+ const zoom = useZoomableImage2({
6770
+ src: media.url,
6771
+ naturalWidth: positive(props.naturalWidth),
6772
+ naturalHeight: positive(props.naturalHeight),
6773
+ initial: str(props.initial, `auto`),
6774
+ maxScale: positive(props.maxScale),
6775
+ scale: positive(props.scale),
6776
+ controls,
6777
+ transition: ctx.reducedMotion ? null : ZOOMABLE_IMAGE_NATIVE_TRANSITION,
6778
+ onZoom: (scale, atFit) => {
6779
+ setScale(scale);
6780
+ emit(`zoom`, { scale, atFit }, { scale });
6781
+ },
6782
+ onTap: () => void emit(`tap`)
6783
+ });
6784
+ const [menuOpen, setMenuOpen] = useState21(false);
6785
+ useEffect20(() => zoom.controller.current?.holdPill(menuOpen), [menuOpen]);
6786
+ const styled = node.style !== undefined && (node.style.height !== undefined || node.style.aspectRatio !== undefined);
6787
+ const aspect = zoomBoxAspect(ZOOM_MATH2, zoom.natural, styled);
6788
+ const items = menuOpen ? zoom.menuItems(ctx.t(`zoomFit`)).map((item, i) => ({ kind: `checkbox`, label: item.label, value: String(i), checked: item.checked })) : [];
6789
+ const choose = (event, payload) => {
6790
+ if (event !== `select`)
6791
+ return;
6792
+ const c = zoom.controller.current;
6793
+ const f = c?.frame();
6794
+ const picked = c && f ? zoom.menuItems(ctx.t(`zoomFit`))[num(payload?.value, -1)] : undefined;
6795
+ setMenuOpen(false);
6796
+ if (!c || !picked)
6797
+ return;
6798
+ if (picked.scale === null)
6799
+ c.rest();
6800
+ else
6801
+ c.zoomScale(picked.scale);
6802
+ };
6803
+ const { pill } = zoom;
6804
+ return /* @__PURE__ */ jsxs20("div", {
6805
+ ...rootProps,
6806
+ ref: zoom.rootRef,
6807
+ role: "group",
6808
+ "aria-label": alt || undefined,
6809
+ tabIndex: 0,
6810
+ style: mergeStyle(rootProps, { ...LAYOUT.root, ...aspect !== null ? { aspectRatio: String(aspect) } : {} }),
6811
+ children: [
6812
+ /* @__PURE__ */ jsx25("img", {
6813
+ ...part(`image`),
6814
+ ref: zoom.imageRef,
6815
+ src: media.url || undefined,
6816
+ alt,
6817
+ draggable: false,
6818
+ loading: "lazy",
6819
+ decoding: "async",
6820
+ style: { ...LAYOUT.image, ...zoom.natural ? { width: zoom.natural.width, height: zoom.natural.height } : {} },
6821
+ onLoad: zoom.onImageLoad
6822
+ }),
6823
+ /* @__PURE__ */ jsx25("svg", {
6824
+ className: "xui-media-sizer",
6825
+ "aria-hidden": "true",
6826
+ width: MEDIA_INTRINSIC_WIDTH2,
6827
+ height: 1
6828
+ }),
6829
+ controls !== `none` ? /* @__PURE__ */ jsxs20("div", {
6830
+ ...part(`pill`),
6831
+ ref: zoom.pillRef,
6832
+ role: "toolbar",
6833
+ "data-state": zoom.pillVisible ? `open` : `closed`,
6834
+ style: zoom.pillVisible ? LAYOUT.pill : { ...LAYOUT.pill, ...LAYOUT.pillHidden },
6835
+ children: [
6836
+ /* @__PURE__ */ jsx25("button", {
6837
+ type: "button",
6838
+ ...part(`zoomOut`, pill.atMin && `disabled`),
6839
+ style: LAYOUT.button,
6840
+ "aria-label": ctx.t(`zoomOut`),
6841
+ disabled: pill.atMin,
6842
+ onClick: () => zoom.controller.current?.step(-1),
6843
+ children: /* @__PURE__ */ jsx25(BuiltinIcon, {
6844
+ slot: "ZoomableImage.zoomOut",
6845
+ size: 16
6846
+ })
6847
+ }),
6848
+ /* @__PURE__ */ jsxs20(MenuPrimitive2.Root, {
6849
+ open: menuOpen,
6850
+ onOpenChange: setMenuOpen,
6851
+ dir: ctx.direction,
6852
+ children: [
6853
+ /* @__PURE__ */ jsx25(MenuPrimitive2.Trigger, {
6854
+ asChild: true,
6855
+ children: /* @__PURE__ */ jsx25("button", {
6856
+ type: "button",
6857
+ ...part(`percent`, menuOpen && `open`),
6858
+ style: LAYOUT.percent,
6859
+ "aria-label": ctx.t(`zoomLevel`),
6860
+ children: pill.percent
6861
+ })
6862
+ }),
6863
+ /* @__PURE__ */ jsx25(MenuPrimitive2.Portal, {
6864
+ container: ctx.portal ?? undefined,
6865
+ children: /* @__PURE__ */ jsx25(MenuPrimitive2.Content, {
6866
+ ...menuPart(`content`, menuOpen && `open`),
6867
+ side: "top",
6868
+ align: "center",
6869
+ sideOffset: OVERLAY_OFFSET4,
6870
+ collisionPadding: OVERLAY_PADDING4,
6871
+ "data-xui-overlay": "Menu",
6872
+ "data-open-on": "press",
6873
+ children: /* @__PURE__ */ jsx25(MenuItems, {
6874
+ ns: MenuPrimitive2,
6875
+ items,
6876
+ rawItems: undefined,
6877
+ part: menuPart,
6878
+ overlay: "Menu",
6879
+ emit: choose,
6880
+ scope,
6881
+ path: "",
6882
+ close: () => setMenuOpen(false)
6883
+ })
6884
+ })
6885
+ })
6886
+ ]
6887
+ }),
6888
+ /* @__PURE__ */ jsx25("button", {
6889
+ type: "button",
6890
+ ...part(`zoomIn`, pill.atMax && `disabled`),
6891
+ style: LAYOUT.button,
6892
+ "aria-label": ctx.t(`zoomIn`),
6893
+ disabled: pill.atMax,
6894
+ onClick: () => zoom.controller.current?.step(1),
6895
+ children: /* @__PURE__ */ jsx25(BuiltinIcon, {
6896
+ slot: "ZoomableImage.zoomIn",
6897
+ size: 16
6898
+ })
6899
+ }),
6900
+ /* @__PURE__ */ jsx25("span", {
6901
+ ...part(`divider`),
6902
+ "aria-hidden": "true",
6903
+ style: LAYOUT.divider
6904
+ }),
6905
+ /* @__PURE__ */ jsx25("button", {
6906
+ type: "button",
6907
+ ...part(`fit`, pill.atRest && `selected`),
6908
+ style: LAYOUT.button,
6909
+ "aria-label": ctx.t(`zoomToFit`),
6910
+ "aria-pressed": pill.atRest,
6911
+ onClick: () => zoom.controller.current?.rest(),
6912
+ children: /* @__PURE__ */ jsx25(BuiltinIcon, {
6913
+ slot: "ZoomableImage.fit",
6914
+ size: 16
6915
+ })
6916
+ })
6917
+ ]
6918
+ }) : null
6919
+ ]
6920
+ });
6921
+ }
6922
+
6563
6923
  // packages/exponential-ui-react/src/natives/index.ts
6564
6924
  var NATIVES = {
6565
6925
  Box: BoxNative,
@@ -6569,6 +6929,7 @@ var NATIVES = {
6569
6929
  Markdown: MarkdownNative,
6570
6930
  CodeBlock: CodeBlockNative,
6571
6931
  Image: ImageNative,
6932
+ ZoomableImage: ZoomableImageNative,
6572
6933
  Icon: IconNative,
6573
6934
  Video: VideoNative,
6574
6935
  AudioPlayer: AudioPlayerNative,
@@ -6588,6 +6949,7 @@ var NATIVES = {
6588
6949
  Spinner: SpinnerNative,
6589
6950
  Skeleton: SkeletonNative,
6590
6951
  VoiceWave: VoiceWaveNative,
6952
+ Motion: MotionNative,
6591
6953
  Table: TableNative,
6592
6954
  Chart: ChartNative,
6593
6955
  Button: ButtonNative,
@@ -6618,7 +6980,7 @@ var NATIVE_NAMES = Object.keys(NATIVES);
6618
6980
 
6619
6981
  // packages/exponential-ui-react/src/node-view.tsx
6620
6982
  import { cssValue, isMacroComponent, partClass as partClass4, propAttribute as propAttribute2 } from "@exponential_app/eui/web";
6621
- import { jsx as jsx24, jsxs as jsxs20, Fragment as Fragment8 } from "react/jsx-runtime";
6983
+ import { jsx as jsx26, jsxs as jsxs21, Fragment as Fragment9 } from "react/jsx-runtime";
6622
6984
  var CONTAINERS = new Set([`Box`, `List`]);
6623
6985
  function styleIdOf(node) {
6624
6986
  return node.styleId ?? node.id;
@@ -6626,7 +6988,7 @@ function styleIdOf(node) {
6626
6988
  function useRootProps(node, props, domId = node.id, recipeProps, style) {
6627
6989
  const ctx = useSurfaceContext();
6628
6990
  const scope = useContext6(ScopeContext);
6629
- return useMemo17(() => {
6991
+ return useMemo18(() => {
6630
6992
  const macros = extensionMacroNames(ctx.extensions);
6631
6993
  const classes = [`xui-el`, nodeClass(styleIdOf(node)), ctx.compiled.scope, partClass4(node.component, `root`)];
6632
6994
  const attrs = {};
@@ -6721,13 +7083,13 @@ var NodeView = memo2(function NodeView({ node }) {
6721
7083
  return null;
6722
7084
  const own = ownDirection(node, ctx);
6723
7085
  if (own && own !== ctx.direction)
6724
- return /* @__PURE__ */ jsx24(DirectedNode, {
7086
+ return /* @__PURE__ */ jsx26(DirectedNode, {
6725
7087
  node,
6726
7088
  scope,
6727
7089
  direction: own,
6728
7090
  live
6729
7091
  });
6730
- return /* @__PURE__ */ jsx24(BoundNode, {
7092
+ return /* @__PURE__ */ jsx26(BoundNode, {
6731
7093
  node,
6732
7094
  scope,
6733
7095
  live
@@ -6741,10 +7103,10 @@ function ownDirection(node, ctx) {
6741
7103
  }
6742
7104
  function DirectedNode({ node, scope, direction, live }) {
6743
7105
  const ctx = useSurfaceContext();
6744
- const value = useMemo17(() => deriveContext(ctx, { direction }), [ctx, direction]);
6745
- return /* @__PURE__ */ jsx24(SurfaceContext.Provider, {
7106
+ const value = useMemo18(() => deriveContext(ctx, { direction }), [ctx, direction]);
7107
+ return /* @__PURE__ */ jsx26(SurfaceContext.Provider, {
6746
7108
  value,
6747
- children: /* @__PURE__ */ jsx24(BoundNode, {
7109
+ children: /* @__PURE__ */ jsx26(BoundNode, {
6748
7110
  node,
6749
7111
  scope,
6750
7112
  live
@@ -6756,8 +7118,8 @@ var BoundNode = memo2(function BoundNode({ node, scope, live }) {
6756
7118
  const instance = useContext6(InstanceContext);
6757
7119
  const domId = `${node.id}${instance}`;
6758
7120
  const data = ctx.data;
6759
- const rctx = useMemo17(() => resolveContextOf(ctx, scope), [ctx, scope, data, live]);
6760
- const props = useMemo17(() => {
7121
+ const rctx = useMemo18(() => resolveContextOf(ctx, scope), [ctx, scope, data, live]);
7122
+ const props = useMemo18(() => {
6761
7123
  const out = resolveNodeProps(node.component, node.props, rctx, ctx.extensionDefs);
6762
7124
  for (const name of responsiveProps(node.component, ctx.extensionDefs)) {
6763
7125
  const v = out[name];
@@ -6766,8 +7128,8 @@ var BoundNode = memo2(function BoundNode({ node, scope, live }) {
6766
7128
  }
6767
7129
  return out;
6768
7130
  }, [node.props, node.component, rctx, ctx.extensionDefs, ctx.breakpoint]);
6769
- const recipeProps = useMemo17(() => node.recipe ? resolveValue(node.recipe.props, rctx) : undefined, [node.recipe, rctx]);
6770
- const dynamicStyle = useMemo17(() => {
7131
+ const recipeProps = useMemo18(() => node.recipe ? resolveValue(node.recipe.props, rctx) : undefined, [node.recipe, rctx]);
7132
+ const dynamicStyle = useMemo18(() => {
6771
7133
  const entries = dynamicStyleEntries(node.style);
6772
7134
  if (entries.length === 0)
6773
7135
  return;
@@ -6785,30 +7147,30 @@ var BoundNode = memo2(function BoundNode({ node, scope, live }) {
6785
7147
  const Painter = Override ?? Native ?? NATIVES[UNKNOWN_COMPONENT];
6786
7148
  const unknown = node.component === UNKNOWN_COMPONENT || !Native && !Override;
6787
7149
  const onUnknown = ctx.host.onUnknown;
6788
- useEffect19(() => {
7150
+ useEffect21(() => {
6789
7151
  if (unknown)
6790
7152
  onUnknown?.(node);
6791
7153
  }, [unknown, onUnknown, node]);
6792
7154
  if (ctx.measure && !CONTAINERS.has(node.component)) {
6793
7155
  const size = ctx.measure(node);
6794
7156
  if (size) {
6795
- return /* @__PURE__ */ jsx24("div", {
7157
+ return /* @__PURE__ */ jsx26("div", {
6796
7158
  className: `xui-el ${nodeClass(node.id)} xui-leaf`,
6797
7159
  "data-xui-id": domId,
6798
7160
  "data-xui-c": node.component,
6799
- children: /* @__PURE__ */ jsx24("div", {
7161
+ children: /* @__PURE__ */ jsx26("div", {
6800
7162
  className: "xui-measured",
6801
7163
  style: { width: size.w, height: size.h }
6802
7164
  })
6803
7165
  });
6804
7166
  }
6805
7167
  }
6806
- const children = /* @__PURE__ */ jsxs20(Fragment8, {
7168
+ const children = /* @__PURE__ */ jsxs21(Fragment9, {
6807
7169
  children: [
6808
- node.children.map((child) => /* @__PURE__ */ jsx24(NodeView, {
7170
+ node.children.map((child) => /* @__PURE__ */ jsx26(NodeView, {
6809
7171
  node: child
6810
7172
  }, child.id)),
6811
- node.template ? /* @__PURE__ */ jsx24(TemplateChildren, {
7173
+ node.template ? /* @__PURE__ */ jsx26(TemplateChildren, {
6812
7174
  node,
6813
7175
  scope
6814
7176
  }) : null
@@ -6816,18 +7178,18 @@ var BoundNode = memo2(function BoundNode({ node, scope, live }) {
6816
7178
  });
6817
7179
  const slots = {};
6818
7180
  for (const [name, slot] of Object.entries(node.slots ?? {}))
6819
- slots[name] = /* @__PURE__ */ jsx24(NodeView, {
7181
+ slots[name] = /* @__PURE__ */ jsx26(NodeView, {
6820
7182
  node: slot
6821
7183
  }, slot.id);
6822
7184
  const painterProps = { node, props, theme: ctx.theme, mode: ctx.mode, tokens: ctx.theme.tokens, children, slots, emit, rootProps, scope, domId };
6823
7185
  if (UNGUARDED.has(node.component) && !Override)
6824
- return /* @__PURE__ */ jsx24(Painter, {
7186
+ return /* @__PURE__ */ jsx26(Painter, {
6825
7187
  ...painterProps
6826
7188
  });
6827
- return /* @__PURE__ */ jsx24(PaintBoundary, {
7189
+ return /* @__PURE__ */ jsx26(PaintBoundary, {
6828
7190
  node,
6829
7191
  domId,
6830
- children: /* @__PURE__ */ jsx24(Painter, {
7192
+ children: /* @__PURE__ */ jsx26(Painter, {
6831
7193
  ...painterProps
6832
7194
  })
6833
7195
  });
@@ -6887,7 +7249,7 @@ class PaintBoundary extends Component {
6887
7249
  render() {
6888
7250
  const { node, domId, children } = this.props;
6889
7251
  if (this.state.failed)
6890
- return /* @__PURE__ */ jsx24("div", {
7252
+ return /* @__PURE__ */ jsx26("div", {
6891
7253
  className: `xui-el ${nodeClass(node.id)}`,
6892
7254
  "data-xui-id": domId,
6893
7255
  "data-xui-c": node.component,
@@ -6913,11 +7275,11 @@ function templateItems(ctx, node, scope) {
6913
7275
  var itemInstance = (instance, key) => `${instance}.${instanceSegment(key)}`;
6914
7276
  function TemplateItemView({ tpl, item }) {
6915
7277
  const instance = useContext6(InstanceContext);
6916
- return /* @__PURE__ */ jsx24(ScopeContext.Provider, {
7278
+ return /* @__PURE__ */ jsx26(ScopeContext.Provider, {
6917
7279
  value: item.path,
6918
- children: /* @__PURE__ */ jsx24(InstanceContext.Provider, {
7280
+ children: /* @__PURE__ */ jsx26(InstanceContext.Provider, {
6919
7281
  value: itemInstance(instance, item.key),
6920
- children: /* @__PURE__ */ jsx24(NodeView, {
7282
+ children: /* @__PURE__ */ jsx26(NodeView, {
6921
7283
  node: tpl
6922
7284
  })
6923
7285
  })
@@ -6926,24 +7288,24 @@ function TemplateItemView({ tpl, item }) {
6926
7288
  function TemplateChildren({ node, scope }) {
6927
7289
  const ctx = useSurfaceContext();
6928
7290
  const t = templateItems(ctx, node, scope);
6929
- const last = useRef24({ keys: new Set, generation: 0 });
7291
+ const last = useRef25({ keys: new Set, generation: 0 });
6930
7292
  const keys = t ? t.items.map((item) => item.key) : [];
6931
7293
  let generation = last.current.generation;
6932
7294
  if (keys.length > 0 && last.current.keys.size > 0 && !keys.some((k) => last.current.keys.has(k)))
6933
7295
  generation++;
6934
- useEffect19(() => {
7296
+ useEffect21(() => {
6935
7297
  last.current = { keys: new Set(keys), generation };
6936
7298
  });
6937
7299
  if (!t)
6938
7300
  return null;
6939
- return /* @__PURE__ */ jsx24(TemplateBlock, {
7301
+ return /* @__PURE__ */ jsx26(TemplateBlock, {
6940
7302
  items: t.items,
6941
7303
  tpl: t.tpl
6942
7304
  }, generation);
6943
7305
  }
6944
7306
  function TemplateBlock({ items, tpl }) {
6945
- return /* @__PURE__ */ jsx24(Fragment8, {
6946
- children: items.map((item) => /* @__PURE__ */ jsx24(TemplateItemView, {
7307
+ return /* @__PURE__ */ jsx26(Fragment9, {
7308
+ children: items.map((item) => /* @__PURE__ */ jsx26(TemplateItemView, {
6947
7309
  tpl,
6948
7310
  item
6949
7311
  }, item.key))
@@ -6954,7 +7316,7 @@ function TemplateBlock({ items, tpl }) {
6954
7316
  import { openAllowed } from "@exponential_app/eui/web";
6955
7317
  import { compiledTheme } from "@exponential_app/eui/web";
6956
7318
  import { layoutSize as layoutSize2 } from "@exponential_app/eui/web";
6957
- import { jsx as jsx25, jsxs as jsxs21 } from "react/jsx-runtime";
7319
+ import { jsx as jsx27, jsxs as jsxs22 } from "react/jsx-runtime";
6958
7320
  var resolvedCache = new Map;
6959
7321
  function resolveThemeInput(input) {
6960
7322
  if (!input)
@@ -6998,7 +7360,7 @@ function surfaceTheme(theme, density, highContrast) {
6998
7360
  var EMPTY2 = [];
6999
7361
  var NO_TEMPLATES = {};
7000
7362
  var EMPTY_HOST = {};
7001
- var useIsoLayoutEffect3 = typeof window === `undefined` ? useEffect20 : useLayoutEffect6;
7363
+ var useIsoLayoutEffect3 = typeof window === `undefined` ? useEffect22 : useLayoutEffect7;
7002
7364
  function surfaceLayout(box, inputs) {
7003
7365
  const breakpoint = activeBreakpoint(box.width, inputs.breakpoints);
7004
7366
  const height = inputs.viewportHeight ?? box.height;
@@ -7151,30 +7513,30 @@ function ExponentialSurface({
7151
7513
  const reducedMotion = useMediaQuery(`(prefers-reduced-motion: reduce)`);
7152
7514
  const hover = useMediaQuery(`(hover: hover)`, true);
7153
7515
  const mode = modeSetting === `system` ? resolveMode(`system`, prefersDark) : modeSetting;
7154
- const resolution = useMemo18(() => resolveThemeInput(themeProp), [themeProp]);
7516
+ const resolution = useMemo19(() => resolveThemeInput(themeProp), [themeProp]);
7155
7517
  const baseTheme = resolution.theme;
7156
7518
  const onThemeIssues = host?.onThemeIssues;
7157
- useEffect20(() => {
7519
+ useEffect22(() => {
7158
7520
  if (resolution.issues.length > 0)
7159
7521
  onThemeIssues?.(resolution.issues);
7160
7522
  }, [resolution, onThemeIssues]);
7161
7523
  const theme = surfaceTheme(baseTheme, density, contrast === `high` || contrast === `system` && prefersContrast);
7162
7524
  const global = useSyncExternalStore3(subscribeExtensions, registeredExtensions, registeredExtensions);
7163
- const extensions = useMemo18(() => [...global, ...extensionsProp], [global, extensionsProp]);
7164
- const extensionDefs = useMemo18(() => extensionCatalogs(extensions), [extensions]);
7165
- const macros = useMemo18(() => extensionMacroNames(extensions), [extensions]);
7166
- const compiled = useMemo18(() => compiledTheme(theme, { extensionMacros: macros }), [theme, macros]);
7525
+ const extensions = useMemo19(() => [...global, ...extensionsProp], [global, extensionsProp]);
7526
+ const extensionDefs = useMemo19(() => extensionCatalogs(extensions), [extensions]);
7527
+ const macros = useMemo19(() => extensionMacroNames(extensions), [extensions]);
7528
+ const compiled = useMemo19(() => compiledTheme(theme, { extensionMacros: macros }), [theme, macros]);
7167
7529
  const direction = directionProp ?? textDirection(locale);
7168
- const strings = useMemo18(() => stringTable(stringOverrides ?? {}), [stringOverrides]);
7530
+ const strings = useMemo19(() => stringTable(stringOverrides ?? {}), [stringOverrides]);
7169
7531
  const t = useCallback11((id, params) => formatString(strings[id] ?? id, params ?? {}), [strings]);
7170
- const [localData, setLocalData] = useState21(dataProp ?? {});
7171
- const [seenData, setSeenData] = useState21(dataProp);
7532
+ const [localData, setLocalData] = useState22(dataProp ?? {});
7533
+ const [seenData, setSeenData] = useState22(dataProp);
7172
7534
  if (dataProp !== seenData && !sameData(dataProp, seenData)) {
7173
7535
  setSeenData(dataProp);
7174
7536
  setLocalData(dataProp ?? {});
7175
7537
  }
7176
7538
  const data = surface ? surface.data : localData;
7177
- const latestSurface = useRef25(surface);
7539
+ const latestSurface = useRef26(surface);
7178
7540
  latestSurface.current = surface;
7179
7541
  const setData = useCallback11((pointer, value) => {
7180
7542
  const current = latestSurface.current;
@@ -7183,40 +7545,40 @@ function ExponentialSurface({
7183
7545
  else
7184
7546
  setLocalData((cur) => setPointer3(cur, pointer, value));
7185
7547
  }, []);
7186
- const lastTree = useRef25({ root: null, templates: NO_TEMPLATES });
7548
+ const lastTree = useRef26({ root: null, templates: NO_TEMPLATES });
7187
7549
  const rawRoot = surface ? surface.root : rootProp ?? null;
7188
- const root = useMemo18(() => lastTree.current.root = share(lastTree.current.root, rawRoot), [rawRoot]);
7550
+ const root = useMemo19(() => lastTree.current.root = share(lastTree.current.root, rawRoot), [rawRoot]);
7189
7551
  const rawTemplates = (surface ? surface.templates : templatesProp) ?? NO_TEMPLATES;
7190
- const templates = useMemo18(() => lastTree.current.templates = share(lastTree.current.templates, rawTemplates), [rawTemplates]);
7552
+ const templates = useMemo19(() => lastTree.current.templates = share(lastTree.current.templates, rawTemplates), [rawTemplates]);
7191
7553
  const templateNode = useCallback11((componentId) => templates[componentId], [templates]);
7192
- const templateRoots = useMemo18(() => Object.values(templates), [templates]);
7193
- const lastBudget = useRef25(undefined);
7194
- const budget = useMemo18(() => {
7554
+ const templateRoots = useMemo19(() => Object.values(templates), [templates]);
7555
+ const lastBudget = useRef26(undefined);
7556
+ const budget = useMemo19(() => {
7195
7557
  const next = root ? templateBudget(root, data, templateNode) : undefined;
7196
7558
  if (sameBudget(lastBudget.current, next))
7197
7559
  return lastBudget.current;
7198
7560
  return lastBudget.current = next;
7199
7561
  }, [root, data, templateNode]);
7200
- useEffect20(() => {
7562
+ useEffect22(() => {
7201
7563
  if (budget?.issue)
7202
7564
  console.warn(`[exponential-ui] ${surfaceId}: ${budget.issue.id}: ${budget.issue.message}`);
7203
7565
  }, [surfaceId, budget?.issue?.id, budget?.issue?.message]);
7204
- useEffect20(() => {
7566
+ useEffect22(() => {
7205
7567
  if (IS_DEV && root)
7206
7568
  warnMissingTemplates(surfaceId, root, templates);
7207
7569
  }, [surfaceId, root, templates]);
7208
- const sheet = useMemo18(() => root ? compileNodeSheet([root, ...templateRoots], surfaceId, theme) : { css: ``, queries: [], chunks: NO_CHUNKS }, [root, templateRoots, surfaceId, theme]);
7209
- const lastBatches = useRef25([]);
7210
- const batches = useMemo18(() => lastBatches.current = nodeSheetBatches(lastBatches.current, sheet.chunks), [sheet.chunks]);
7211
- const [rootEl, setRootEl] = useState21(null);
7212
- const [portal, setPortal] = useState21(null);
7213
- const [toastLayer, setToastLayer] = useState21(null);
7214
- const box = useRef25({ width: typeof width === `number` ? width : 0, height: undefined, measured: false });
7570
+ const sheet = useMemo19(() => root ? compileNodeSheet([root, ...templateRoots], surfaceId, theme) : { css: ``, queries: [], chunks: NO_CHUNKS }, [root, templateRoots, surfaceId, theme]);
7571
+ const lastBatches = useRef26([]);
7572
+ const batches = useMemo19(() => lastBatches.current = nodeSheetBatches(lastBatches.current, sheet.chunks), [sheet.chunks]);
7573
+ const [rootEl, setRootEl] = useState22(null);
7574
+ const [portal, setPortal] = useState22(null);
7575
+ const [toastLayer, setToastLayer] = useState22(null);
7576
+ const box = useRef26({ width: typeof width === `number` ? width : 0, height: undefined, measured: false });
7215
7577
  const layoutInputs = { breakpoints: theme.tokens.breakpoint ?? {}, queries: sheet.queries, viewportHeight, hover, reducedMotion };
7216
7578
  const { breakpoint, xq } = surfaceLayout(box.current, layoutInputs);
7217
- const inputsRef = useRef25(layoutInputs);
7579
+ const inputsRef = useRef26(layoutInputs);
7218
7580
  inputsRef.current = layoutInputs;
7219
- const [, setLayoutKey] = useState21(``);
7581
+ const [, setLayoutKey] = useState22(``);
7220
7582
  useIsoLayoutEffect3(() => {
7221
7583
  if (!rootEl)
7222
7584
  return;
@@ -7236,8 +7598,8 @@ function ExponentialSurface({
7236
7598
  ro.observe(rootEl);
7237
7599
  return () => ro.disconnect();
7238
7600
  }, [rootEl]);
7239
- const politeRef = useRef25(null);
7240
- const assertiveRef = useRef25(null);
7601
+ const politeRef = useRef26(null);
7602
+ const assertiveRef = useRef26(null);
7241
7603
  const announce = useCallback11((text, live = `polite`) => {
7242
7604
  const el = live === `assertive` ? assertiveRef.current : politeRef.current;
7243
7605
  if (!el)
@@ -7247,18 +7609,18 @@ function ExponentialSurface({
7247
7609
  el.textContent = text;
7248
7610
  }, 30);
7249
7611
  }, []);
7250
- const functions = useMemo18(() => ({ ...CLIENT_FUNCTIONS2, ...host?.functions ?? {} }), [host?.functions]);
7251
- const formatter = useMemo18(() => memoFormatter(lazyFormatter(locale, timeZone)), [locale, timeZone]);
7252
- const liveClock = useMemo18(() => usesLiveClock(root) || usesLiveClock(templateRoots), [root, templateRoots]);
7253
- const [minute, setMinute] = useState21(() => Date.now());
7254
- useEffect20(() => {
7612
+ const functions = useMemo19(() => ({ ...CLIENT_FUNCTIONS2, ...host?.functions ?? {} }), [host?.functions]);
7613
+ const formatter = useMemo19(() => memoFormatter(lazyFormatter(locale, timeZone)), [locale, timeZone]);
7614
+ const liveClock = useMemo19(() => usesLiveClock(root) || usesLiveClock(templateRoots), [root, templateRoots]);
7615
+ const [minute, setMinute] = useState22(() => Date.now());
7616
+ useEffect22(() => {
7255
7617
  if (!liveClock)
7256
7618
  return;
7257
7619
  const timer = setInterval(() => setMinute(Date.now()), 60000);
7258
7620
  return () => clearInterval(timer);
7259
7621
  }, [liveClock]);
7260
- const now = useMemo18(() => () => Date.now(), [minute]);
7261
- const scrollers = useRef25(new Map);
7622
+ const now = useMemo19(() => () => Date.now(), [minute]);
7623
+ const scrollers = useRef26(new Map);
7262
7624
  const registerScroller = useCallback11((id, scroll) => {
7263
7625
  scrollers.current.set(id, scroll);
7264
7626
  return () => {
@@ -7266,12 +7628,12 @@ function ExponentialSurface({
7266
7628
  scrollers.current.delete(id);
7267
7629
  };
7268
7630
  }, []);
7269
- const paintFailures = useRef25(new Map).current;
7631
+ const paintFailures = useRef26(new Map).current;
7270
7632
  const hostValue = host ?? EMPTY_HOST;
7271
7633
  const openUrl = useCallback11((url) => openAllowed(hostValue, url), [hostValue]);
7272
- const live = useRef25({ data, breakpoint, xq, mode });
7634
+ const live = useRef26({ data, breakpoint, xq, mode });
7273
7635
  live.current = { data, breakpoint, xq, mode };
7274
- const listeners = useRef25(new Set).current;
7636
+ const listeners = useRef26(new Set).current;
7275
7637
  const subscribe = useCallback11((listener) => {
7276
7638
  listeners.add(listener);
7277
7639
  return () => void listeners.delete(listener);
@@ -7280,7 +7642,7 @@ function ExponentialSurface({
7280
7642
  for (const listener of [...listeners])
7281
7643
  listener();
7282
7644
  }, [data, breakpoint, xq, mode, listeners]);
7283
- const ctx = useMemo18(() => withLive({
7645
+ const ctx = useMemo19(() => withLive({
7284
7646
  surfaceId,
7285
7647
  compiled,
7286
7648
  theme,
@@ -7353,9 +7715,9 @@ function ExponentialSurface({
7353
7715
  const md = theme.tokens.breakpoint?.md ?? 768;
7354
7716
  const scopeSel = `.${surfaceClass(surfaceId)}`;
7355
7717
  const layerCss = `@layer xui-base{@container xui (width >= ${md}px){${scopeSel} .xui-toast-layer{left:auto;right:var(--xui-spacing-lg);transform:none;align-items:flex-end}${scopeSel}[dir="rtl"] .xui-toast-layer{right:auto;left:var(--xui-spacing-lg)}}}`;
7356
- const themeHtml = useMemo18(() => ({ __html: `${BASE_CSS}
7718
+ const themeHtml = useMemo19(() => ({ __html: `${BASE_CSS}
7357
7719
  ${compiled.css}` }), [compiled.css]);
7358
- const nodesHtml = useMemo18(() => {
7720
+ const nodesHtml = useMemo19(() => {
7359
7721
  const list = batches.length ? batches : [{ chunks: NO_CHUNKS, css: sheet.css }];
7360
7722
  return list.map((batch, i) => {
7361
7723
  const css = i === 0 ? `${batch.css}${layerCss}` : batch.css;
@@ -7367,7 +7729,7 @@ ${compiled.css}` }), [compiled.css]);
7367
7729
  return html;
7368
7730
  });
7369
7731
  }, [batches, sheet.css, layerCss]);
7370
- return /* @__PURE__ */ jsxs21("div", {
7732
+ return /* @__PURE__ */ jsxs22("div", {
7371
7733
  ref: setRootEl,
7372
7734
  className: [`xui-surface`, compiled.scope, surfaceClass(surfaceId), className].filter(Boolean).join(` `),
7373
7735
  "data-xui-surface": surfaceId,
@@ -7379,29 +7741,29 @@ ${compiled.css}` }), [compiled.css]);
7379
7741
  dir: direction,
7380
7742
  style: width === undefined ? style : { width, ...style },
7381
7743
  children: [
7382
- /* @__PURE__ */ jsx25("style", {
7744
+ /* @__PURE__ */ jsx27("style", {
7383
7745
  "data-xui-style": "theme",
7384
7746
  dangerouslySetInnerHTML: themeHtml
7385
7747
  }),
7386
- nodesHtml.map((html, i) => /* @__PURE__ */ jsx25("style", {
7748
+ nodesHtml.map((html, i) => /* @__PURE__ */ jsx27("style", {
7387
7749
  "data-xui-style": "nodes",
7388
7750
  dangerouslySetInnerHTML: html
7389
7751
  }, i)),
7390
- /* @__PURE__ */ jsx25(SurfaceContext.Provider, {
7752
+ /* @__PURE__ */ jsx27(SurfaceContext.Provider, {
7391
7753
  value: ctx,
7392
- children: /* @__PURE__ */ jsxs21("div", {
7754
+ children: /* @__PURE__ */ jsxs22("div", {
7393
7755
  className: "xui-container",
7394
7756
  children: [
7395
- root ? /* @__PURE__ */ jsx25(NodeView, {
7757
+ root ? /* @__PURE__ */ jsx27(NodeView, {
7396
7758
  node: root
7397
7759
  }) : null,
7398
7760
  children,
7399
- /* @__PURE__ */ jsx25("div", {
7761
+ /* @__PURE__ */ jsx27("div", {
7400
7762
  ref: setPortal,
7401
7763
  className: "xui-layer",
7402
7764
  "data-xui-layer": "overlay"
7403
7765
  }),
7404
- /* @__PURE__ */ jsx25("div", {
7766
+ /* @__PURE__ */ jsx27("div", {
7405
7767
  ref: setToastLayer,
7406
7768
  className: "xui-toast-layer",
7407
7769
  "data-xui-layer": "toast"
@@ -7409,14 +7771,14 @@ ${compiled.css}` }), [compiled.css]);
7409
7771
  ]
7410
7772
  })
7411
7773
  }),
7412
- /* @__PURE__ */ jsx25("div", {
7774
+ /* @__PURE__ */ jsx27("div", {
7413
7775
  ref: politeRef,
7414
7776
  className: "xui-sr-only",
7415
7777
  "aria-live": "polite",
7416
7778
  "aria-atomic": "true",
7417
7779
  "data-xui-live": "polite"
7418
7780
  }),
7419
- /* @__PURE__ */ jsx25("div", {
7781
+ /* @__PURE__ */ jsx27("div", {
7420
7782
  ref: assertiveRef,
7421
7783
  className: "xui-sr-only",
7422
7784
  "aria-live": "assertive",
@@ -7427,21 +7789,21 @@ ${compiled.css}` }), [compiled.css]);
7427
7789
  });
7428
7790
  }
7429
7791
  // packages/exponential-ui-react/src/use-surface.ts
7430
- import { useCallback as useCallback12, useMemo as useMemo19, useRef as useRef26, useState as useState22 } from "react";
7792
+ import { useCallback as useCallback12, useMemo as useMemo20, useRef as useRef27, useState as useState23 } from "react";
7431
7793
  import { CORE_CATALOG_ID, reduceNested, reduceSurface } from "@exponential_app/eui";
7432
7794
  import { setPointer as setPointer4 } from "@exponential_app/eui/web";
7433
7795
  var NO_EXTENSIONS = [];
7434
7796
  function useSurface(options = {}) {
7435
7797
  const surfaceId = options.surfaceId ?? `main`;
7436
7798
  const extensions = options.extensions ?? NO_EXTENSIONS;
7437
- const initialRef = useRef26({
7799
+ const initialRef = useRef27({
7438
7800
  catalogId: options.catalogId ?? CORE_CATALOG_ID,
7439
7801
  components: [],
7440
7802
  nested: options.initial ?? null,
7441
7803
  data: options.data ?? {},
7442
7804
  deleted: false
7443
7805
  });
7444
- const [inner, setInner] = useState22(initialRef.current);
7806
+ const [inner, setInner] = useState23(initialRef.current);
7445
7807
  const apply = useCallback12((message) => {
7446
7808
  setInner((cur) => {
7447
7809
  if (message.createSurface) {
@@ -7478,7 +7840,7 @@ function useSurface(options = {}) {
7478
7840
  setInner((cur) => ({ ...cur, nested: tree, components: [], deleted: false }));
7479
7841
  }, []);
7480
7842
  const reset = useCallback12(() => setInner(initialRef.current), []);
7481
- const reduced = useMemo19(() => {
7843
+ const reduced = useMemo20(() => {
7482
7844
  if (inner.deleted)
7483
7845
  return { root: null, issues: [] };
7484
7846
  if (inner.nested)
@@ -7511,8 +7873,8 @@ import { BASE_CSS as BASE_CSS2 } from "@exponential_app/eui/web";
7511
7873
  import { getPointer as getPointer4, setPointer as setPointer5, absolutePath as absolutePath4, resolveValue as resolveValue2, resolveProps, resolveNodeProps as resolveNodeProps2, resolveVisible as resolveVisible2, bindTree, boundPath as boundPath5, isBinding as isBinding3, isCall as isCall2, hasDynamic, memoFormatter as memoFormatter2, CLIENT_FUNCTIONS as CLIENT_FUNCTIONS3 } from "@exponential_app/eui/web";
7512
7874
 
7513
7875
  // packages/exponential-ui-react/src/host-surface.tsx
7514
- import { useCallback as useCallback13, useMemo as useMemo20, useSyncExternalStore as useSyncExternalStore4 } from "react";
7515
- import { jsx as jsx26, Fragment as Fragment9 } from "react/jsx-runtime";
7876
+ import { useCallback as useCallback13, useMemo as useMemo21, useSyncExternalStore as useSyncExternalStore4 } from "react";
7877
+ import { jsx as jsx28, Fragment as Fragment10 } from "react/jsx-runtime";
7516
7878
  function hostPlugin(host, base = {}) {
7517
7879
  return {
7518
7880
  ...base,
@@ -7542,7 +7904,7 @@ function useHostSurfaceIds(host) {
7542
7904
  const subscribe = useCallback13((cb) => host.subscribe(cb), [host]);
7543
7905
  const key = useSyncExternalStore4(subscribe, () => host.surfaceIds().join(`
7544
7906
  `));
7545
- return useMemo20(() => key ? key.split(`
7907
+ return useMemo21(() => key ? key.split(`
7546
7908
  `) : [], [key]);
7547
7909
  }
7548
7910
  function useHostStatus(host) {
@@ -7557,7 +7919,7 @@ function useHostSurface(host, surfaceId) {
7557
7919
  const store = useSyncExternalStore4(subscribeHost, () => host.surface(surfaceId));
7558
7920
  const subscribeStore = useCallback13((cb) => store ? store.subscribe(cb) : noop(), [store]);
7559
7921
  const version = useSyncExternalStore4(subscribeStore, () => store?.version ?? -1);
7560
- return useMemo20(() => store ? stateOf(host, store) : null, [host, store, version]);
7922
+ return useMemo21(() => store ? stateOf(host, store) : null, [host, store, version]);
7561
7923
  }
7562
7924
  function stateOf(host, store) {
7563
7925
  return {
@@ -7583,12 +7945,12 @@ function stateOf(host, store) {
7583
7945
  }
7584
7946
  function HostSurface({ host, surfaceId, plugin, fallback = null, ...rest }) {
7585
7947
  const surface = useHostSurface(host, surfaceId);
7586
- const p = useMemo20(() => hostPlugin(host, plugin), [host, plugin]);
7948
+ const p = useMemo21(() => hostPlugin(host, plugin), [host, plugin]);
7587
7949
  if (!surface)
7588
- return /* @__PURE__ */ jsx26(Fragment9, {
7950
+ return /* @__PURE__ */ jsx28(Fragment10, {
7589
7951
  children: fallback
7590
7952
  });
7591
- return /* @__PURE__ */ jsx26(ExponentialSurface, {
7953
+ return /* @__PURE__ */ jsx28(ExponentialSurface, {
7592
7954
  ...rest,
7593
7955
  theme: surface.theme ?? rest.theme,
7594
7956
  id: rest.id ?? surfaceId,
@@ -7696,5 +8058,5 @@ export {
7696
8058
  walkNodes
7697
8059
  };
7698
8060
 
7699
- //# debugId=6CB3D248B75B3F5F64756E2164756E21
8061
+ //# debugId=39A4F0FB7E01DD0264756E2164756E21
7700
8062
  //# sourceMappingURL=index.js.map