aeon-ui-engine 1.4.0 → 1.8.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/CHANGELOG.md +139 -0
- package/CONSUMER.md +67 -27
- package/INTEGRATION.md +1 -1
- package/README.md +17 -8
- package/package.json +5 -2
- package/packages/cli/dist/bin.js +29 -3
- package/packages/cli/dist/{chunk-5L47SLNV.js → chunk-JMNRJCWF.js} +63 -9
- package/packages/cli/dist/index.d.ts +15 -1
- package/packages/cli/dist/index.js +3 -1
- package/packages/cli/node_modules/.bin/vitest +2 -2
- package/packages/cli/src/bin.ts +30 -2
- package/packages/cli/src/index.ts +1 -0
- package/packages/cli/src/init.ts +10 -4
- package/packages/cli/src/link.ts +61 -0
- package/packages/core/node_modules/.bin/vitest +2 -2
- package/packages/core/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/panda/styled-system/styles.css +0 -4
- package/packages/primitives/dist/{chunk-PB3LFHXU.js → chunk-VUPWYBGU.js} +14 -0
- package/packages/primitives/dist/index.js +1 -1
- package/packages/primitives/dist/machines/range-slider.d.ts +3 -3
- package/packages/primitives/dist/machines/slider.d.ts +22 -0
- package/packages/primitives/dist/machines/slider.js +1 -1
- package/packages/primitives/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/primitives/src/machines/slider.ts +17 -0
- package/packages/react/dist/index.d.ts +44 -5
- package/packages/react/dist/index.js +173 -48
- package/packages/react/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/react/src/dialog/dialog.test.tsx +27 -0
- package/packages/react/src/dialog/index.tsx +11 -3
- package/packages/react/src/floating/FloatingPositioner.tsx +19 -1
- package/packages/react/src/hooks/use-anchor-position.ts +88 -17
- package/packages/react/src/menu/index.tsx +45 -6
- package/packages/react/src/popover/index.tsx +31 -4
- package/packages/react/src/slider/index.tsx +66 -19
- package/packages/react/src/tooltip/index.tsx +7 -1
- package/packages/schemas/dist/index.js +3 -1
- package/packages/schemas/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
- package/packages/schemas/prompts/cursorrules.md +3 -1
- package/packages/schemas/registry/machines/slider.json +18 -1
- package/packages/schemas/src/prompts.ts +3 -1
- package/packages/tree/README.md +29 -0
- package/packages/tree/dist/index.d.ts +97 -0
- package/packages/tree/dist/index.js +107 -0
- package/packages/tree/node_modules/.bin/esbuild +21 -0
- package/packages/tree/node_modules/.bin/jiti +21 -0
- package/packages/tree/node_modules/.bin/tsc +21 -0
- package/packages/tree/node_modules/.bin/tsserver +21 -0
- package/packages/tree/node_modules/.bin/tsup +21 -0
- package/packages/tree/node_modules/.bin/tsup-node +21 -0
- package/packages/tree/node_modules/.bin/tsx +21 -0
- package/packages/tree/node_modules/.bin/vite +21 -0
- package/packages/tree/node_modules/.bin/vitest +21 -0
- package/packages/tree/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/packages/tree/package.json +42 -0
- package/packages/tree/src/exclusive-action.test.ts +54 -0
- package/packages/tree/src/exclusive-action.ts +104 -0
- package/packages/tree/src/index.ts +7 -0
- package/packages/tree/src/interpret.tsx +45 -0
- package/packages/tree/src/totality.ts +20 -0
- package/packages/tree/src/widget.ts +31 -0
- package/packages/tree/tsconfig.json +8 -0
- package/packages/tree/vitest.config.ts +8 -0
- package/scripts/link-scoped-packages.mjs +206 -0
- package/scripts/vite-aliases.mjs +9 -8
|
@@ -519,11 +519,15 @@ var Root4 = forwardRef5(function DialogRoot({ open, defaultOpen = false, onOpenC
|
|
|
519
519
|
const [snapshot, send] = useAeonMachine(dialogMachine, {
|
|
520
520
|
input: { open: defaultOpen }
|
|
521
521
|
});
|
|
522
|
-
const
|
|
522
|
+
const machineOpen = snapshot.context.open;
|
|
523
|
+
const resolvedOpen = open ?? machineOpen;
|
|
523
524
|
const contentRef = useRef(null);
|
|
525
|
+
const reportedOpen = useRef(machineOpen);
|
|
524
526
|
useEffect6(() => {
|
|
525
|
-
|
|
526
|
-
|
|
527
|
+
if (reportedOpen.current === machineOpen) return;
|
|
528
|
+
reportedOpen.current = machineOpen;
|
|
529
|
+
onOpenChange?.(machineOpen);
|
|
530
|
+
}, [machineOpen, onOpenChange]);
|
|
527
531
|
useEffect6(() => {
|
|
528
532
|
if (open !== void 0) {
|
|
529
533
|
send({ type: "SET_OPEN", open });
|
|
@@ -1247,7 +1251,7 @@ import {
|
|
|
1247
1251
|
} from "react";
|
|
1248
1252
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
1249
1253
|
var SliderCtx = createContext8(null);
|
|
1250
|
-
function
|
|
1254
|
+
function useSliderContext() {
|
|
1251
1255
|
const ctx = useContext8(SliderCtx);
|
|
1252
1256
|
if (!ctx) throw new Error("Slider parts must be used within Slider.Root");
|
|
1253
1257
|
return ctx;
|
|
@@ -1280,12 +1284,24 @@ var Root11 = forwardRef12(function SliderRoot({
|
|
|
1280
1284
|
});
|
|
1281
1285
|
const resolvedValue = value ?? snapshot.context.value;
|
|
1282
1286
|
const dragging = snapshot.matches({ interaction: "dragging" });
|
|
1283
|
-
useEffect9(() => {
|
|
1284
|
-
onValueChange?.(resolvedValue);
|
|
1285
|
-
}, [resolvedValue, onValueChange]);
|
|
1286
1287
|
useEffect9(() => {
|
|
1287
1288
|
if (value !== void 0) send({ type: "SET_VALUE", value });
|
|
1288
1289
|
}, [value, send]);
|
|
1290
|
+
useEffect9(() => {
|
|
1291
|
+
send({ type: "SET_BOUNDS", min, max, step });
|
|
1292
|
+
}, [min, max, step, send]);
|
|
1293
|
+
useEffect9(() => {
|
|
1294
|
+
send({ type: "SET_DISABLED", disabled });
|
|
1295
|
+
}, [disabled, send]);
|
|
1296
|
+
const commit = useCallback2(
|
|
1297
|
+
(next) => {
|
|
1298
|
+
if (disabled) return;
|
|
1299
|
+
const snapped = snapSliderValue(next, min, max, step);
|
|
1300
|
+
send({ type: "SET_VALUE", value: snapped });
|
|
1301
|
+
onValueChange?.(snapped);
|
|
1302
|
+
},
|
|
1303
|
+
[disabled, min, max, step, send, onValueChange]
|
|
1304
|
+
);
|
|
1289
1305
|
const setValueFromClientX = useCallback2(
|
|
1290
1306
|
(clientX) => {
|
|
1291
1307
|
const track = trackRef.current;
|
|
@@ -1293,11 +1309,9 @@ var Root11 = forwardRef12(function SliderRoot({
|
|
|
1293
1309
|
const rect = track.getBoundingClientRect();
|
|
1294
1310
|
if (rect.width <= 0) return;
|
|
1295
1311
|
const ratio = Math.min(1, Math.max(0, (clientX - rect.left) / rect.width));
|
|
1296
|
-
|
|
1297
|
-
send({ type: "SET_VALUE", value: next });
|
|
1298
|
-
if (value === void 0) onValueChange?.(next);
|
|
1312
|
+
commit(min + ratio * (max - min));
|
|
1299
1313
|
},
|
|
1300
|
-
[disabled, min, max
|
|
1314
|
+
[commit, disabled, min, max]
|
|
1301
1315
|
);
|
|
1302
1316
|
useEffect9(() => {
|
|
1303
1317
|
if (!dragging) return;
|
|
@@ -1318,12 +1332,25 @@ var Root11 = forwardRef12(function SliderRoot({
|
|
|
1318
1332
|
step,
|
|
1319
1333
|
disabled,
|
|
1320
1334
|
dragging,
|
|
1335
|
+
interaction: dragging ? "dragging" : "idle",
|
|
1321
1336
|
send,
|
|
1322
1337
|
onValueChange,
|
|
1338
|
+
commit,
|
|
1323
1339
|
setValueFromClientX,
|
|
1324
1340
|
trackRef
|
|
1325
1341
|
}),
|
|
1326
|
-
[
|
|
1342
|
+
[
|
|
1343
|
+
resolvedValue,
|
|
1344
|
+
min,
|
|
1345
|
+
max,
|
|
1346
|
+
step,
|
|
1347
|
+
disabled,
|
|
1348
|
+
dragging,
|
|
1349
|
+
send,
|
|
1350
|
+
onValueChange,
|
|
1351
|
+
commit,
|
|
1352
|
+
setValueFromClientX
|
|
1353
|
+
]
|
|
1327
1354
|
);
|
|
1328
1355
|
return /* @__PURE__ */ jsx11(SliderCtx.Provider, { value: ctx, children: /* @__PURE__ */ jsx11(
|
|
1329
1356
|
"div",
|
|
@@ -1342,7 +1369,7 @@ var Root11 = forwardRef12(function SliderRoot({
|
|
|
1342
1369
|
) });
|
|
1343
1370
|
});
|
|
1344
1371
|
var Track2 = forwardRef12(function SliderTrack({ onPointerDown, ...rest }, ref) {
|
|
1345
|
-
const { disabled, send, setValueFromClientX, trackRef } =
|
|
1372
|
+
const { disabled, send, setValueFromClientX, trackRef } = useSliderContext();
|
|
1346
1373
|
return /* @__PURE__ */ jsx11(
|
|
1347
1374
|
"div",
|
|
1348
1375
|
{
|
|
@@ -1368,7 +1395,7 @@ var Track2 = forwardRef12(function SliderTrack({ onPointerDown, ...rest }, ref)
|
|
|
1368
1395
|
);
|
|
1369
1396
|
});
|
|
1370
1397
|
var Range2 = forwardRef12(function SliderRange({ style, ...rest }, ref) {
|
|
1371
|
-
const { value, min, max } =
|
|
1398
|
+
const { value, min, max } = useSliderContext();
|
|
1372
1399
|
return /* @__PURE__ */ jsx11(
|
|
1373
1400
|
"div",
|
|
1374
1401
|
{
|
|
@@ -1380,7 +1407,7 @@ var Range2 = forwardRef12(function SliderRange({ style, ...rest }, ref) {
|
|
|
1380
1407
|
);
|
|
1381
1408
|
});
|
|
1382
1409
|
var Thumb2 = forwardRef12(function SliderThumb({ onKeyDown, onPointerDown, style, ...rest }, ref) {
|
|
1383
|
-
const { value, min, max, step, disabled, dragging, send, setValueFromClientX } =
|
|
1410
|
+
const { value, min, max, step, disabled, dragging, send, commit, setValueFromClientX } = useSliderContext();
|
|
1384
1411
|
return /* @__PURE__ */ jsx11(
|
|
1385
1412
|
"span",
|
|
1386
1413
|
{
|
|
@@ -1408,19 +1435,27 @@ var Thumb2 = forwardRef12(function SliderThumb({ onKeyDown, onPointerDown, style
|
|
|
1408
1435
|
if (disabled || e.defaultPrevented) return;
|
|
1409
1436
|
if (e.key === "ArrowRight" || e.key === "ArrowUp") {
|
|
1410
1437
|
e.preventDefault();
|
|
1411
|
-
|
|
1438
|
+
commit(value + step);
|
|
1412
1439
|
}
|
|
1413
1440
|
if (e.key === "ArrowLeft" || e.key === "ArrowDown") {
|
|
1414
1441
|
e.preventDefault();
|
|
1415
|
-
|
|
1442
|
+
commit(value - step);
|
|
1443
|
+
}
|
|
1444
|
+
if (e.key === "PageUp") {
|
|
1445
|
+
e.preventDefault();
|
|
1446
|
+
commit(value + (max - min) / 10);
|
|
1447
|
+
}
|
|
1448
|
+
if (e.key === "PageDown") {
|
|
1449
|
+
e.preventDefault();
|
|
1450
|
+
commit(value - (max - min) / 10);
|
|
1416
1451
|
}
|
|
1417
1452
|
if (e.key === "Home") {
|
|
1418
1453
|
e.preventDefault();
|
|
1419
|
-
|
|
1454
|
+
commit(min);
|
|
1420
1455
|
}
|
|
1421
1456
|
if (e.key === "End") {
|
|
1422
1457
|
e.preventDefault();
|
|
1423
|
-
|
|
1458
|
+
commit(max);
|
|
1424
1459
|
}
|
|
1425
1460
|
}
|
|
1426
1461
|
},
|
|
@@ -1430,7 +1465,7 @@ var Thumb2 = forwardRef12(function SliderThumb({ onKeyDown, onPointerDown, style
|
|
|
1430
1465
|
);
|
|
1431
1466
|
});
|
|
1432
1467
|
var ValueText = forwardRef12(function SliderValueText(props, ref) {
|
|
1433
|
-
const { value } =
|
|
1468
|
+
const { value } = useSliderContext();
|
|
1434
1469
|
return /* @__PURE__ */ jsx11("span", { ref, ...mergeProps(partOnlyAttrs3(sliderAnatomy.valueText), props), children: props.children ?? value });
|
|
1435
1470
|
});
|
|
1436
1471
|
var Slider = { Root: Root11, Track: Track2, Range: Range2, Thumb: Thumb2, ValueText };
|
|
@@ -2628,20 +2663,35 @@ import { forwardRef as forwardRef23 } from "react";
|
|
|
2628
2663
|
|
|
2629
2664
|
// src/hooks/use-anchor-position.ts
|
|
2630
2665
|
import { useEffect as useEffect13 } from "react";
|
|
2666
|
+
var DEFAULT_GUTTER = 4;
|
|
2667
|
+
var DEFAULT_Z_INDEX = 50;
|
|
2668
|
+
var DEFAULT_PADDING = 8;
|
|
2669
|
+
function splitPlacement(placement) {
|
|
2670
|
+
const [side, align] = placement.split("-");
|
|
2671
|
+
return [side, align];
|
|
2672
|
+
}
|
|
2631
2673
|
function useAnchorPosition(anchorRef, floatingRef, active, placement = "bottom-start", options = {}) {
|
|
2632
|
-
const {
|
|
2674
|
+
const {
|
|
2675
|
+
matchWidth = false,
|
|
2676
|
+
gutter = DEFAULT_GUTTER,
|
|
2677
|
+
zIndex = DEFAULT_Z_INDEX,
|
|
2678
|
+
padding = DEFAULT_PADDING
|
|
2679
|
+
} = options;
|
|
2633
2680
|
useEffect13(() => {
|
|
2634
2681
|
if (!active || !anchorRef.current || !floatingRef.current) return;
|
|
2682
|
+
let frame = 0;
|
|
2635
2683
|
const update = () => {
|
|
2636
2684
|
const anchor = anchorRef.current;
|
|
2637
2685
|
const floating = floatingRef.current;
|
|
2638
2686
|
if (!anchor || !floating) return;
|
|
2687
|
+
const [preferredSide, align] = splitPlacement(placement);
|
|
2639
2688
|
const rect = anchor.getBoundingClientRect();
|
|
2689
|
+
const viewportWidth = window.innerWidth;
|
|
2690
|
+
const viewportHeight = window.innerHeight;
|
|
2640
2691
|
floating.style.position = "fixed";
|
|
2641
|
-
floating.style.left = `${rect.left}px`;
|
|
2642
2692
|
floating.style.bottom = "";
|
|
2643
2693
|
floating.style.right = "";
|
|
2644
|
-
floating.style.zIndex =
|
|
2694
|
+
floating.style.zIndex = String(zIndex);
|
|
2645
2695
|
if (matchWidth) {
|
|
2646
2696
|
floating.style.width = `${rect.width}px`;
|
|
2647
2697
|
floating.style.minWidth = `${rect.width}px`;
|
|
@@ -2649,22 +2699,43 @@ function useAnchorPosition(anchorRef, floatingRef, active, placement = "bottom-s
|
|
|
2649
2699
|
floating.style.width = "";
|
|
2650
2700
|
floating.style.minWidth = "";
|
|
2651
2701
|
}
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2702
|
+
const width = floating.offsetWidth || floating.getBoundingClientRect().width;
|
|
2703
|
+
const height = floating.offsetHeight || floating.getBoundingClientRect().height;
|
|
2704
|
+
const roomBelow = viewportHeight - rect.bottom - gutter - padding;
|
|
2705
|
+
const roomAbove = rect.top - gutter - padding;
|
|
2706
|
+
const room = preferredSide === "top" ? roomAbove : roomBelow;
|
|
2707
|
+
const side = room >= height ? preferredSide : roomAbove > roomBelow ? "top" : "bottom";
|
|
2708
|
+
const available = side === "top" ? roomAbove : roomBelow;
|
|
2709
|
+
let left = rect.left;
|
|
2710
|
+
if (align === "end") left = rect.right - width;
|
|
2711
|
+
else if (align === "center") left = rect.left + rect.width / 2 - width / 2;
|
|
2712
|
+
const maxLeft = Math.max(padding, viewportWidth - width - padding);
|
|
2713
|
+
left = Math.min(Math.max(padding, left), maxLeft);
|
|
2714
|
+
const top = side === "top" ? Math.max(padding, rect.top - gutter - Math.min(height, Math.max(available, 0))) : Math.min(
|
|
2715
|
+
rect.bottom + gutter,
|
|
2716
|
+
Math.max(padding, viewportHeight - height - padding)
|
|
2717
|
+
);
|
|
2718
|
+
floating.style.left = `${Math.round(left)}px`;
|
|
2719
|
+
floating.style.top = `${Math.round(top)}px`;
|
|
2720
|
+
floating.style.setProperty("--aeon-available-height", `${Math.round(Math.max(available, 0))}px`);
|
|
2721
|
+
floating.style.setProperty("--aeon-anchor-width", `${Math.round(rect.width)}px`);
|
|
2722
|
+
floating.dataset.side = side;
|
|
2723
|
+
floating.dataset.align = align;
|
|
2724
|
+
};
|
|
2725
|
+
const schedule = () => {
|
|
2726
|
+
cancelAnimationFrame(frame);
|
|
2727
|
+
frame = requestAnimationFrame(update);
|
|
2658
2728
|
};
|
|
2659
2729
|
update();
|
|
2660
|
-
|
|
2661
|
-
window.addEventListener("resize",
|
|
2662
|
-
window.addEventListener("scroll",
|
|
2730
|
+
schedule();
|
|
2731
|
+
window.addEventListener("resize", schedule);
|
|
2732
|
+
window.addEventListener("scroll", schedule, true);
|
|
2663
2733
|
return () => {
|
|
2664
|
-
|
|
2665
|
-
window.removeEventListener("
|
|
2734
|
+
cancelAnimationFrame(frame);
|
|
2735
|
+
window.removeEventListener("resize", schedule);
|
|
2736
|
+
window.removeEventListener("scroll", schedule, true);
|
|
2666
2737
|
};
|
|
2667
|
-
}, [active, anchorRef, floatingRef, placement, matchWidth]);
|
|
2738
|
+
}, [active, anchorRef, floatingRef, placement, matchWidth, gutter, zIndex, padding]);
|
|
2668
2739
|
}
|
|
2669
2740
|
|
|
2670
2741
|
// src/floating/FloatingPositioner.tsx
|
|
@@ -2676,16 +2747,21 @@ var FloatingPositioner = forwardRef23(
|
|
|
2676
2747
|
part,
|
|
2677
2748
|
triggerRef,
|
|
2678
2749
|
positionerRef,
|
|
2750
|
+
anchorRef,
|
|
2679
2751
|
portalled = true,
|
|
2680
2752
|
placement = "bottom-start",
|
|
2681
2753
|
matchAnchorWidth = false,
|
|
2754
|
+
gutter,
|
|
2755
|
+
zIndex,
|
|
2682
2756
|
children,
|
|
2683
2757
|
className,
|
|
2684
2758
|
...rest
|
|
2685
2759
|
}, ref) {
|
|
2686
2760
|
const mounted = usePortalledMount();
|
|
2687
|
-
useAnchorPosition(triggerRef, positionerRef, open && portalled, placement, {
|
|
2688
|
-
matchWidth: matchAnchorWidth
|
|
2761
|
+
useAnchorPosition(anchorRef ?? triggerRef, positionerRef, open && portalled, placement, {
|
|
2762
|
+
matchWidth: matchAnchorWidth,
|
|
2763
|
+
gutter,
|
|
2764
|
+
zIndex
|
|
2689
2765
|
});
|
|
2690
2766
|
if (!open) return null;
|
|
2691
2767
|
const node = /* @__PURE__ */ jsx23(
|
|
@@ -3361,15 +3437,19 @@ var Root20 = forwardRef26(function PopoverRoot({ open, defaultOpen = false, onOp
|
|
|
3361
3437
|
const [snapshot, send] = useAeonMachine(popoverMachine3, {
|
|
3362
3438
|
input: { open: defaultOpen }
|
|
3363
3439
|
});
|
|
3364
|
-
const
|
|
3440
|
+
const machineOpen = snapshot.context.open;
|
|
3441
|
+
const resolvedOpen = open ?? machineOpen;
|
|
3365
3442
|
const rootRef = useRef9(null);
|
|
3366
3443
|
const triggerRef = useRef9(null);
|
|
3367
3444
|
const positionerRef = useRef9(null);
|
|
3368
3445
|
const triggerId = useId5();
|
|
3369
3446
|
const contentId = useId5();
|
|
3447
|
+
const reportedOpen = useRef9(machineOpen);
|
|
3370
3448
|
useEffect16(() => {
|
|
3371
|
-
|
|
3372
|
-
|
|
3449
|
+
if (reportedOpen.current === machineOpen) return;
|
|
3450
|
+
reportedOpen.current = machineOpen;
|
|
3451
|
+
onOpenChange?.(machineOpen);
|
|
3452
|
+
}, [machineOpen, onOpenChange]);
|
|
3373
3453
|
useEffect16(() => {
|
|
3374
3454
|
if (open !== void 0) send({ type: "SET_OPEN", open });
|
|
3375
3455
|
}, [open, send]);
|
|
@@ -3425,7 +3505,17 @@ var Trigger4 = forwardRef26(function PopoverTrigger({ onClick, ...rest }, ref) {
|
|
|
3425
3505
|
}
|
|
3426
3506
|
);
|
|
3427
3507
|
});
|
|
3428
|
-
var Positioner3 = forwardRef26(function PopoverPositioner({
|
|
3508
|
+
var Positioner3 = forwardRef26(function PopoverPositioner({
|
|
3509
|
+
portalled = true,
|
|
3510
|
+
placement = "bottom-start",
|
|
3511
|
+
anchorRef,
|
|
3512
|
+
matchAnchorWidth = false,
|
|
3513
|
+
gutter,
|
|
3514
|
+
zIndex,
|
|
3515
|
+
children,
|
|
3516
|
+
className,
|
|
3517
|
+
...rest
|
|
3518
|
+
}, ref) {
|
|
3429
3519
|
const { open, triggerRef, positionerRef } = usePopoverCtx();
|
|
3430
3520
|
return /* @__PURE__ */ jsx26(
|
|
3431
3521
|
FloatingPositioner,
|
|
@@ -3436,8 +3526,12 @@ var Positioner3 = forwardRef26(function PopoverPositioner({ portalled = true, pl
|
|
|
3436
3526
|
part: popoverAnatomy.positioner,
|
|
3437
3527
|
triggerRef,
|
|
3438
3528
|
positionerRef,
|
|
3529
|
+
anchorRef,
|
|
3530
|
+
matchAnchorWidth,
|
|
3439
3531
|
portalled,
|
|
3440
3532
|
placement,
|
|
3533
|
+
gutter,
|
|
3534
|
+
zIndex,
|
|
3441
3535
|
className,
|
|
3442
3536
|
...rest,
|
|
3443
3537
|
children
|
|
@@ -3520,15 +3614,19 @@ function useMenuCtx() {
|
|
|
3520
3614
|
}
|
|
3521
3615
|
var Root21 = forwardRef27(function MenuRoot({ open, defaultOpen = false, onOpenChange, children, className, ...rest }, ref) {
|
|
3522
3616
|
const [snapshot, send] = useAeonMachine(popoverMachine4, { input: { open: defaultOpen } });
|
|
3523
|
-
const
|
|
3617
|
+
const machineOpen = snapshot.context.open;
|
|
3618
|
+
const resolvedOpen = open ?? machineOpen;
|
|
3524
3619
|
const rootRef = useRef10(null);
|
|
3525
3620
|
const triggerRef = useRef10(null);
|
|
3526
3621
|
const positionerRef = useRef10(null);
|
|
3527
3622
|
const triggerId = useId6();
|
|
3528
3623
|
const menuId = useId6();
|
|
3624
|
+
const reportedOpen = useRef10(machineOpen);
|
|
3529
3625
|
useEffect17(() => {
|
|
3530
|
-
|
|
3531
|
-
|
|
3626
|
+
if (reportedOpen.current === machineOpen) return;
|
|
3627
|
+
reportedOpen.current = machineOpen;
|
|
3628
|
+
onOpenChange?.(machineOpen);
|
|
3629
|
+
}, [machineOpen, onOpenChange]);
|
|
3532
3630
|
useEffect17(() => {
|
|
3533
3631
|
if (open !== void 0) send({ type: "SET_OPEN", open });
|
|
3534
3632
|
}, [open, send]);
|
|
@@ -3583,7 +3681,7 @@ var Trigger5 = forwardRef27(function MenuTrigger({ onClick, ...rest }, ref) {
|
|
|
3583
3681
|
}
|
|
3584
3682
|
);
|
|
3585
3683
|
});
|
|
3586
|
-
var Positioner4 = forwardRef27(function MenuPositioner({ portalled = true, placement = "bottom-start", children, className, ...rest }, ref) {
|
|
3684
|
+
var Positioner4 = forwardRef27(function MenuPositioner({ portalled = true, placement = "bottom-start", gutter, zIndex, children, className, ...rest }, ref) {
|
|
3587
3685
|
const { open, triggerRef, positionerRef } = useMenuCtx();
|
|
3588
3686
|
return /* @__PURE__ */ jsx27(
|
|
3589
3687
|
FloatingPositioner,
|
|
@@ -3596,6 +3694,8 @@ var Positioner4 = forwardRef27(function MenuPositioner({ portalled = true, place
|
|
|
3596
3694
|
positionerRef,
|
|
3597
3695
|
portalled,
|
|
3598
3696
|
placement,
|
|
3697
|
+
gutter,
|
|
3698
|
+
zIndex,
|
|
3599
3699
|
className,
|
|
3600
3700
|
...rest,
|
|
3601
3701
|
children
|
|
@@ -3603,14 +3703,36 @@ var Positioner4 = forwardRef27(function MenuPositioner({ portalled = true, place
|
|
|
3603
3703
|
);
|
|
3604
3704
|
});
|
|
3605
3705
|
var Content7 = forwardRef27(function MenuContent({ onKeyDown, ...rest }, ref) {
|
|
3606
|
-
const { open, send, menuId } = useMenuCtx();
|
|
3706
|
+
const { open, send, menuId, triggerRef } = useMenuCtx();
|
|
3707
|
+
const contentRef = useRef10(null);
|
|
3708
|
+
useEffect17(() => {
|
|
3709
|
+
if (!open) return;
|
|
3710
|
+
const trigger = triggerRef.current;
|
|
3711
|
+
contentRef.current?.focus({ preventScroll: true });
|
|
3712
|
+
return () => {
|
|
3713
|
+
if (trigger?.isConnected) trigger.focus({ preventScroll: true });
|
|
3714
|
+
};
|
|
3715
|
+
}, [open, triggerRef]);
|
|
3716
|
+
useEffect17(() => {
|
|
3717
|
+
if (!open) return;
|
|
3718
|
+
const onDocumentKeyDown = (event) => {
|
|
3719
|
+
if (event.key === "Escape") send({ type: "ESCAPE" });
|
|
3720
|
+
};
|
|
3721
|
+
document.addEventListener("keydown", onDocumentKeyDown);
|
|
3722
|
+
return () => document.removeEventListener("keydown", onDocumentKeyDown);
|
|
3723
|
+
}, [open, send]);
|
|
3607
3724
|
if (!open) return null;
|
|
3608
3725
|
return /* @__PURE__ */ jsx27(
|
|
3609
3726
|
"div",
|
|
3610
3727
|
{
|
|
3611
|
-
ref
|
|
3728
|
+
ref: (node) => {
|
|
3729
|
+
contentRef.current = node;
|
|
3730
|
+
if (typeof ref === "function") ref(node);
|
|
3731
|
+
else if (ref) ref.current = node;
|
|
3732
|
+
},
|
|
3612
3733
|
id: menuId,
|
|
3613
3734
|
role: "menu",
|
|
3735
|
+
tabIndex: -1,
|
|
3614
3736
|
...mergeProps(
|
|
3615
3737
|
partAttrs23(menuAnatomy.scope, menuAnatomy.content, { state: "open" }),
|
|
3616
3738
|
{
|
|
@@ -3870,7 +3992,7 @@ var Trigger6 = forwardRef28(function TooltipTrigger({ onClick, onMouseEnter, onM
|
|
|
3870
3992
|
}
|
|
3871
3993
|
);
|
|
3872
3994
|
});
|
|
3873
|
-
var Positioner5 = forwardRef28(function TooltipPositioner({ portalled = true, placement = "top-start", children, className, ...rest }, ref) {
|
|
3995
|
+
var Positioner5 = forwardRef28(function TooltipPositioner({ portalled = true, placement = "top-start", gutter, zIndex, children, className, ...rest }, ref) {
|
|
3874
3996
|
const { open, triggerRef, positionerRef } = useTooltipCtx();
|
|
3875
3997
|
return /* @__PURE__ */ jsx28(
|
|
3876
3998
|
FloatingPositioner,
|
|
@@ -3883,6 +4005,8 @@ var Positioner5 = forwardRef28(function TooltipPositioner({ portalled = true, pl
|
|
|
3883
4005
|
positionerRef,
|
|
3884
4006
|
portalled,
|
|
3885
4007
|
placement,
|
|
4008
|
+
gutter,
|
|
4009
|
+
zIndex,
|
|
3886
4010
|
className,
|
|
3887
4011
|
...rest,
|
|
3888
4012
|
children
|
|
@@ -5864,6 +5988,7 @@ export {
|
|
|
5864
5988
|
useLayoutMode,
|
|
5865
5989
|
useScrollContext,
|
|
5866
5990
|
useScrollState,
|
|
5991
|
+
useSliderContext,
|
|
5867
5992
|
useStickyBarContext,
|
|
5868
5993
|
useToast,
|
|
5869
5994
|
useToastStore
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"3.2.4","results":[[":src/select/select.test.tsx",{"duration":
|
|
1
|
+
{"version":"3.2.4","results":[[":src/select/select.test.tsx",{"duration":196.07670899999994,"failed":false}],[":src/dialog/dialog.test.tsx",{"duration":181.65270800000008,"failed":false}],[":src/avatar/avatar.test.tsx",{"duration":117.92833299999984,"failed":false}],[":src/tooltip/tooltip.test.tsx",{"duration":210.20837500000016,"failed":false}],[":src/toast/toast.test.tsx",{"duration":134.57233399999996,"failed":false}]]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { render, screen } from '@testing-library/react'
|
|
2
2
|
import userEvent from '@testing-library/user-event'
|
|
3
|
+
import { useState } from 'react'
|
|
3
4
|
import { describe, expect, it, vi } from 'vitest'
|
|
4
5
|
import { Dialog } from '../dialog/index.js'
|
|
5
6
|
|
|
@@ -47,4 +48,30 @@ describe('Dialog', () => {
|
|
|
47
48
|
unmount()
|
|
48
49
|
expect(document.body.style.overflow).not.toBe('hidden')
|
|
49
50
|
})
|
|
51
|
+
|
|
52
|
+
it('reports the trigger to a controlled owner', async () => {
|
|
53
|
+
const user = userEvent.setup()
|
|
54
|
+
|
|
55
|
+
function Controlled() {
|
|
56
|
+
const [open, setOpen] = useState(false)
|
|
57
|
+
return (
|
|
58
|
+
<Dialog.Root open={open} onOpenChange={setOpen}>
|
|
59
|
+
<Dialog.Trigger>Open</Dialog.Trigger>
|
|
60
|
+
<Dialog.Portal portalled={false}>
|
|
61
|
+
<Dialog.Content>
|
|
62
|
+
<Dialog.Title>Title</Dialog.Title>
|
|
63
|
+
<Dialog.CloseTrigger>Close</Dialog.CloseTrigger>
|
|
64
|
+
</Dialog.Content>
|
|
65
|
+
</Dialog.Portal>
|
|
66
|
+
</Dialog.Root>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
render(<Controlled />)
|
|
71
|
+
await user.click(screen.getByRole('button', { name: 'Open' }))
|
|
72
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument()
|
|
73
|
+
|
|
74
|
+
await user.click(screen.getByRole('button', { name: 'Close dialog' }))
|
|
75
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
|
|
76
|
+
})
|
|
50
77
|
})
|
|
@@ -52,12 +52,20 @@ const Root = forwardRef<HTMLDivElement, DialogRootProps>(function DialogRoot(
|
|
|
52
52
|
input: { open: defaultOpen },
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
const
|
|
55
|
+
const machineOpen = snapshot.context.open
|
|
56
|
+
const resolvedOpen = open ?? machineOpen
|
|
56
57
|
const contentRef = useRef<HTMLDivElement>(null)
|
|
57
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Report the machine's intent, not the resolved value: a controlled owner
|
|
61
|
+
* holding `open` would otherwise never hear about its own trigger or escape.
|
|
62
|
+
*/
|
|
63
|
+
const reportedOpen = useRef(machineOpen)
|
|
58
64
|
useEffect(() => {
|
|
59
|
-
|
|
60
|
-
|
|
65
|
+
if (reportedOpen.current === machineOpen) return
|
|
66
|
+
reportedOpen.current = machineOpen
|
|
67
|
+
onOpenChange?.(machineOpen)
|
|
68
|
+
}, [machineOpen, onOpenChange])
|
|
61
69
|
|
|
62
70
|
useEffect(() => {
|
|
63
71
|
if (open !== undefined) {
|
|
@@ -10,9 +10,22 @@ export interface FloatingPositionerProps extends HTMLAttributes<HTMLDivElement>
|
|
|
10
10
|
part: string
|
|
11
11
|
triggerRef: RefObject<HTMLElement | null>
|
|
12
12
|
positionerRef: RefObject<HTMLDivElement | null>
|
|
13
|
+
/**
|
|
14
|
+
* Position against this element instead of the trigger.
|
|
15
|
+
*
|
|
16
|
+
* A trigger is often a small icon button pinned to one edge of a much larger
|
|
17
|
+
* region. Aligning to the button then throws a wide surface off-screen, and
|
|
18
|
+
* clamping only slides it back to the viewport edge. Anchoring to the region
|
|
19
|
+
* the surface belongs to puts it where the eye already is.
|
|
20
|
+
*/
|
|
21
|
+
anchorRef?: RefObject<HTMLElement | null>
|
|
13
22
|
portalled?: boolean
|
|
14
23
|
placement?: AnchorPlacement
|
|
15
24
|
matchAnchorWidth?: boolean
|
|
25
|
+
/** Gap between trigger and surface. */
|
|
26
|
+
gutter?: number
|
|
27
|
+
/** Stack level for the portalled surface. */
|
|
28
|
+
zIndex?: number
|
|
16
29
|
children?: ReactNode
|
|
17
30
|
}
|
|
18
31
|
|
|
@@ -24,9 +37,12 @@ export const FloatingPositioner = forwardRef<HTMLDivElement, FloatingPositionerP
|
|
|
24
37
|
part,
|
|
25
38
|
triggerRef,
|
|
26
39
|
positionerRef,
|
|
40
|
+
anchorRef,
|
|
27
41
|
portalled = true,
|
|
28
42
|
placement = 'bottom-start',
|
|
29
43
|
matchAnchorWidth = false,
|
|
44
|
+
gutter,
|
|
45
|
+
zIndex,
|
|
30
46
|
children,
|
|
31
47
|
className,
|
|
32
48
|
...rest
|
|
@@ -34,8 +50,10 @@ export const FloatingPositioner = forwardRef<HTMLDivElement, FloatingPositionerP
|
|
|
34
50
|
ref,
|
|
35
51
|
) {
|
|
36
52
|
const mounted = usePortalledMount()
|
|
37
|
-
useAnchorPosition(triggerRef, positionerRef, open && portalled, placement, {
|
|
53
|
+
useAnchorPosition(anchorRef ?? triggerRef, positionerRef, open && portalled, placement, {
|
|
38
54
|
matchWidth: matchAnchorWidth,
|
|
55
|
+
gutter,
|
|
56
|
+
zIndex,
|
|
39
57
|
})
|
|
40
58
|
|
|
41
59
|
if (!open) return null
|