@astryxdesign/core 0.5.2-canary.c9c8564 → 0.5.2-canary.e4f8e4e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/BottomSheet/BottomSheet.d.ts +3 -1
  2. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  3. package/dist/BottomSheet/BottomSheet.js +4 -3
  4. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts +2 -2
  5. package/dist/BottomSheet/BottomSheetEdgeTint.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheetEdgeTint.js +7 -10
  7. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  8. package/dist/BottomSheet/BottomSheetSwitcher.js +1 -1
  9. package/dist/Button/Button.d.ts +2 -1
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +11 -4
  12. package/dist/Carousel/Carousel.d.ts.map +1 -1
  13. package/dist/Carousel/Carousel.js +2 -2
  14. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  15. package/dist/Chat/ChatToolCalls.js +34 -17
  16. package/dist/ContextMenu/ContextMenu.d.ts +14 -3
  17. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  18. package/dist/ContextMenu/ContextMenu.js +149 -26
  19. package/dist/ContextMenu/index.d.ts +1 -0
  20. package/dist/ContextMenu/index.d.ts.map +1 -1
  21. package/dist/DropdownMenu/DropdownMenu.d.ts +24 -5
  22. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  23. package/dist/DropdownMenu/DropdownMenu.js +340 -26
  24. package/dist/DropdownMenu/DropdownMenuContext.d.ts +1 -1
  25. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  26. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  27. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  28. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +6 -2
  29. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  30. package/dist/DropdownMenu/DropdownMenuSubMenu.js +43 -14
  31. package/dist/DropdownMenu/MenuBottomSheet.d.ts +20 -0
  32. package/dist/DropdownMenu/MenuBottomSheet.d.ts.map +1 -0
  33. package/dist/DropdownMenu/MenuBottomSheet.js +36 -0
  34. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts +10 -0
  35. package/dist/DropdownMenu/MenuBottomSheetActionList.d.ts.map +1 -0
  36. package/dist/DropdownMenu/MenuBottomSheetActionList.js +111 -0
  37. package/dist/DropdownMenu/index.d.ts +2 -1
  38. package/dist/DropdownMenu/index.d.ts.map +1 -1
  39. package/dist/DropdownMenu/menuWidth.d.ts +14 -0
  40. package/dist/DropdownMenu/menuWidth.d.ts.map +1 -0
  41. package/dist/DropdownMenu/menuWidth.js +35 -0
  42. package/dist/DropdownMenu/useMenuOverflow.d.ts +10 -0
  43. package/dist/DropdownMenu/useMenuOverflow.d.ts.map +1 -0
  44. package/dist/DropdownMenu/useMenuOverflow.js +60 -0
  45. package/dist/MoreMenu/MoreMenu.d.ts +8 -2
  46. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  47. package/dist/MoreMenu/MoreMenu.js +2 -0
  48. package/dist/MultiSelector/MultiSelector.d.ts +11 -1
  49. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  50. package/dist/MultiSelector/MultiSelector.js +97 -68
  51. package/dist/MultiSelector/index.d.ts +1 -1
  52. package/dist/MultiSelector/index.d.ts.map +1 -1
  53. package/dist/Popover/Popover.d.ts +10 -6
  54. package/dist/Popover/Popover.d.ts.map +1 -1
  55. package/dist/Popover/Popover.js +141 -16
  56. package/dist/Popover/usePopover.d.ts +4 -0
  57. package/dist/Popover/usePopover.d.ts.map +1 -1
  58. package/dist/Popover/usePopover.js +52 -5
  59. package/dist/Selector/Selector.d.ts +10 -0
  60. package/dist/Selector/Selector.d.ts.map +1 -1
  61. package/dist/Selector/Selector.js +106 -80
  62. package/dist/Selector/SelectorBottomSheet.d.ts +21 -0
  63. package/dist/Selector/SelectorBottomSheet.d.ts.map +1 -0
  64. package/dist/Selector/SelectorBottomSheet.js +83 -0
  65. package/dist/Selector/index.d.ts +1 -1
  66. package/dist/Selector/index.d.ts.map +1 -1
  67. package/dist/Selector/selectorPresentation.stylex.d.ts +16 -0
  68. package/dist/Selector/selectorPresentation.stylex.d.ts.map +1 -0
  69. package/dist/Selector/selectorPresentation.stylex.js +21 -0
  70. package/dist/Selector/useSelectorPresentation.d.ts +32 -0
  71. package/dist/Selector/useSelectorPresentation.d.ts.map +1 -0
  72. package/dist/Selector/useSelectorPresentation.js +90 -0
  73. package/dist/Toast/useToastGesture.d.ts.map +1 -1
  74. package/dist/Toast/useToastGesture.js +46 -9
  75. package/dist/astryx.css +19 -1
  76. package/dist/hooks/useAdaptivePresentation.d.ts +5 -0
  77. package/dist/hooks/useAdaptivePresentation.d.ts.map +1 -0
  78. package/dist/hooks/useAdaptivePresentation.js +19 -0
  79. package/dist/hooks/useFocusReturnVisibility.d.ts +7 -0
  80. package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -0
  81. package/dist/hooks/useFocusReturnVisibility.js +35 -0
  82. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  83. package/dist/hooks/useFocusTrap.js +12 -0
  84. package/locales/en.json +20 -0
  85. package/locales/pseudo.json +15 -0
  86. package/package.json +2 -2
  87. package/src/BottomSheet/BottomSheet.doc.mjs +6 -0
  88. package/src/BottomSheet/BottomSheet.test.tsx +29 -0
  89. package/src/BottomSheet/BottomSheet.tsx +7 -4
  90. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +4 -6
  91. package/src/BottomSheet/BottomSheetEdgeTint.tsx +7 -10
  92. package/src/BottomSheet/BottomSheetSwitcher.tsx +1 -2
  93. package/src/Button/Button.doc.mjs +56 -0
  94. package/src/Button/Button.test.tsx +10 -0
  95. package/src/Button/Button.tsx +13 -5
  96. package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
  97. package/src/Carousel/Carousel.test.tsx +83 -0
  98. package/src/Carousel/Carousel.tsx +8 -2
  99. package/src/Chat/ChatToolCalls.test.tsx +44 -0
  100. package/src/Chat/ChatToolCalls.tsx +36 -15
  101. package/src/ContextMenu/ContextMenu.doc.mjs +13 -1
  102. package/src/ContextMenu/ContextMenu.test.tsx +131 -1
  103. package/src/ContextMenu/ContextMenu.tsx +199 -32
  104. package/src/ContextMenu/index.ts +1 -0
  105. package/src/DropdownMenu/DropdownMenu.doc.mjs +201 -40
  106. package/src/DropdownMenu/DropdownMenu.test.tsx +518 -7
  107. package/src/DropdownMenu/DropdownMenu.tsx +459 -28
  108. package/src/DropdownMenu/DropdownMenuContext.tsx +1 -1
  109. package/src/DropdownMenu/DropdownMenuItem.tsx +2 -0
  110. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +4 -2
  111. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +124 -0
  112. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +72 -17
  113. package/src/DropdownMenu/MenuBottomSheet.tsx +46 -0
  114. package/src/DropdownMenu/MenuBottomSheetActionList.tsx +141 -0
  115. package/src/DropdownMenu/index.ts +2 -0
  116. package/src/DropdownMenu/menuWidth.ts +51 -0
  117. package/src/DropdownMenu/useMenuOverflow.ts +77 -0
  118. package/src/IconButton/IconButton.doc.mjs +38 -0
  119. package/src/MoreMenu/MoreMenu.doc.mjs +17 -0
  120. package/src/MoreMenu/MoreMenu.test.tsx +47 -0
  121. package/src/MoreMenu/MoreMenu.tsx +13 -1
  122. package/src/MultiSelector/MultiSelector.doc.mjs +16 -0
  123. package/src/MultiSelector/MultiSelector.test.tsx +127 -0
  124. package/src/MultiSelector/MultiSelector.tsx +121 -73
  125. package/src/MultiSelector/index.ts +1 -0
  126. package/src/Popover/Popover.doc.mjs +11 -11
  127. package/src/Popover/Popover.test.tsx +397 -2
  128. package/src/Popover/Popover.tsx +228 -21
  129. package/src/Popover/usePopover.tsx +92 -15
  130. package/src/ProgressBar/ProgressBar.spec.md +208 -0
  131. package/src/SegmentedControl/SegmentedControl.doc.mjs +56 -0
  132. package/src/Selector/Selector.doc.mjs +12 -0
  133. package/src/Selector/Selector.test.tsx +135 -0
  134. package/src/Selector/Selector.tsx +141 -82
  135. package/src/Selector/SelectorBottomSheet.tsx +97 -0
  136. package/src/Selector/index.ts +1 -0
  137. package/src/Selector/selectorPresentation.stylex.ts +20 -0
  138. package/src/Selector/useSelectorPresentation.ts +147 -0
  139. package/src/Toast/ToastViewport.test.tsx +118 -4
  140. package/src/Toast/useToastGesture.ts +61 -8
  141. package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
  142. package/src/hooks/useAdaptivePresentation.ts +35 -0
  143. package/src/hooks/useFocusReturnVisibility.ts +45 -0
  144. package/src/hooks/useFocusTrap.test.tsx +40 -0
  145. package/src/hooks/useFocusTrap.ts +13 -0
  146. package/src/theme/themingTargets.test.ts +91 -25
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file selectorPresentation.stylex.ts
3
+ * @input Uses field border tokens
4
+ * @output Shared focus-return styles for Selector and MultiSelector
5
+ * @position Internal visual policy for selector presentation changes
6
+ */
7
+ import * as stylex from '@stylexjs/stylex';
8
+ export declare const selectorPresentationStyles: Readonly<{
9
+ readonly pointerRestoredFocus: Readonly<{
10
+ readonly borderColor: stylex.StyleXClassNameFor<"borderColor", "light-dark(#CCD3DB, #494D53)">;
11
+ readonly boxShadow: stylex.StyleXClassNameFor<"boxShadow", "none">;
12
+ readonly outlineWidth: stylex.StyleXClassNameFor<"outlineWidth", "0">;
13
+ readonly outlineStyle: stylex.StyleXClassNameFor<"outlineStyle", "none">;
14
+ }>;
15
+ }>;
16
+ //# sourceMappingURL=selectorPresentation.stylex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectorPresentation.stylex.d.ts","sourceRoot":"","sources":["../../src/Selector/selectorPresentation.stylex.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAG3C,eAAO,MAAM,0BAA0B;;;;;;;EAOrC,CAAC"}
@@ -0,0 +1,21 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file selectorPresentation.stylex.ts
5
+ * @input Uses field border tokens
6
+ * @output Shared focus-return styles for Selector and MultiSelector
7
+ * @position Internal visual policy for selector presentation changes
8
+ */
9
+
10
+ import * as stylex from '@stylexjs/stylex';
11
+ import "../theme/tokens.stylex.js";
12
+ import { colorVars } from "../theme/tokens.stylex.js";
13
+ export const selectorPresentationStyles = {
14
+ pointerRestoredFocus: {
15
+ kVAM5u: "xvy26l8",
16
+ kGVxlE: "x1gnnqk1",
17
+ kMeerF: "x1k57tk5",
18
+ k3XXqK: "x1t137rt",
19
+ $$css: true
20
+ }
21
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @file useSelectorPresentation.ts
3
+ * @input Uses the shared adaptive presentation policy and usePopover
4
+ * @output Coordinates popover and bottom-sheet disclosure state
5
+ * @position Internal presentation controller shared by Selector and MultiSelector
6
+ */
7
+ import { type FocusEvent, type RefObject } from 'react';
8
+ import { type UsePopoverOptions, type UsePopoverReturn } from '../Popover/usePopover';
9
+ import { type AdaptivePresentation, type ResolvedAdaptivePresentation } from '../hooks/useAdaptivePresentation';
10
+ interface UseSelectorPresentationOptions {
11
+ presentation: AdaptivePresentation;
12
+ onHide: () => void;
13
+ popoverOptions: Omit<UsePopoverOptions, 'onHide'>;
14
+ triggerRef: RefObject<HTMLElement | null>;
15
+ }
16
+ interface SelectorPresentationController {
17
+ activePresentation: ResolvedAdaptivePresentation;
18
+ hide: () => void;
19
+ isOpen: boolean;
20
+ isSheetOpen: boolean;
21
+ isTriggerFocusRingSuppressed: boolean;
22
+ onSheetOpenChange: (isOpen: boolean) => void;
23
+ onTriggerFocus: (event: FocusEvent<HTMLElement>) => void;
24
+ popover: UsePopoverReturn & {
25
+ wasJustDismissed: () => boolean;
26
+ };
27
+ show: () => void;
28
+ wasJustDismissed: () => boolean;
29
+ }
30
+ export declare function useSelectorPresentation({ presentation, onHide, popoverOptions, triggerRef, }: UseSelectorPresentationOptions): SelectorPresentationController;
31
+ export {};
32
+ //# sourceMappingURL=useSelectorPresentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSelectorPresentation.d.ts","sourceRoot":"","sources":["../../src/Selector/useSelectorPresentation.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AAEH,OAAO,EAIL,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAClC,MAAM,kCAAkC,CAAC;AAG1C,UAAU,8BAA8B;IACtC,YAAY,EAAE,oBAAoB,CAAC;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,cAAc,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IAClD,UAAU,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;CAC3C;AAED,UAAU,8BAA8B;IACtC,kBAAkB,EAAE,4BAA4B,CAAC;IACjD,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,4BAA4B,EAAE,OAAO,CAAC;IACtC,iBAAiB,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,CAAC,KAAK,EAAE,UAAU,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,gBAAgB,GAAG;QAAC,gBAAgB,EAAE,MAAM,OAAO,CAAA;KAAC,CAAC;IAC9D,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,gBAAgB,EAAE,MAAM,OAAO,CAAC;CACjC;AAED,wBAAgB,uBAAuB,CAAC,EACtC,YAAY,EACZ,MAAM,EACN,cAAc,EACd,UAAU,GACX,EAAE,8BAA8B,GAAG,8BAA8B,CA2FjE"}
@@ -0,0 +1,90 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useSelectorPresentation.ts
7
+ * @input Uses the shared adaptive presentation policy and usePopover
8
+ * @output Coordinates popover and bottom-sheet disclosure state
9
+ * @position Internal presentation controller shared by Selector and MultiSelector
10
+ */
11
+ import { useCallback, useRef, useState } from 'react';
12
+ import { usePopoverInternal } from "../Popover/usePopover.js";
13
+ import { useAdaptivePresentation } from "../hooks/useAdaptivePresentation.js";
14
+ import { useFocusReturnVisibility } from "../hooks/useFocusReturnVisibility.js";
15
+ export function useSelectorPresentation({
16
+ presentation,
17
+ onHide,
18
+ popoverOptions,
19
+ triggerRef
20
+ }) {
21
+ const resolvedPresentation = useAdaptivePresentation(presentation);
22
+ const activePresentationRef = useRef(resolvedPresentation);
23
+ const [isSheetOpen, setIsSheetOpen] = useState(false);
24
+ const isSheetOpenRef = useRef(false);
25
+ const onHideRef = useRef(onHide);
26
+ const {
27
+ isFocusRingSuppressed,
28
+ onFocusReturnTargetFocus,
29
+ prepareFocusReturn,
30
+ resetFocusReturn
31
+ } = useFocusReturnVisibility();
32
+ onHideRef.current = onHide;
33
+ const handlePopoverHide = useCallback(() => {
34
+ prepareFocusReturn();
35
+ onHideRef.current();
36
+ triggerRef.current?.focus();
37
+ }, [prepareFocusReturn, triggerRef]);
38
+ const popover = usePopoverInternal({
39
+ ...popoverOptions,
40
+ onHide: handlePopoverHide
41
+ });
42
+ const {
43
+ hide: hidePopover,
44
+ show: showPopover,
45
+ wasJustDismissed: wasPopoverJustDismissed
46
+ } = popover;
47
+ const show = useCallback(() => {
48
+ resetFocusReturn();
49
+ activePresentationRef.current = resolvedPresentation;
50
+ if (resolvedPresentation === 'bottom-sheet') {
51
+ isSheetOpenRef.current = true;
52
+ setIsSheetOpen(true);
53
+ } else {
54
+ showPopover();
55
+ }
56
+ }, [resetFocusReturn, resolvedPresentation, showPopover]);
57
+ const hide = useCallback(() => {
58
+ if (isSheetOpenRef.current) {
59
+ prepareFocusReturn();
60
+ isSheetOpenRef.current = false;
61
+ setIsSheetOpen(false);
62
+ onHideRef.current();
63
+ } else {
64
+ hidePopover();
65
+ }
66
+ }, [hidePopover, prepareFocusReturn]);
67
+ const handleTriggerFocus = useCallback(_event => onFocusReturnTargetFocus(), [onFocusReturnTargetFocus]);
68
+ const handleSheetOpenChange = useCallback(nextIsOpen => {
69
+ if (nextIsOpen) {
70
+ show();
71
+ } else {
72
+ hide();
73
+ }
74
+ }, [hide, show]);
75
+ const isOpen = popover.isOpen || isSheetOpen;
76
+ const activePresentation = isOpen ? activePresentationRef.current : resolvedPresentation;
77
+ const wasJustDismissed = useCallback(() => activePresentationRef.current === 'popover' && wasPopoverJustDismissed(), [wasPopoverJustDismissed]);
78
+ return {
79
+ activePresentation,
80
+ hide,
81
+ isOpen,
82
+ isSheetOpen,
83
+ isTriggerFocusRingSuppressed: isFocusRingSuppressed,
84
+ onSheetOpenChange: handleSheetOpenChange,
85
+ onTriggerFocus: handleTriggerFocus,
86
+ popover,
87
+ show,
88
+ wasJustDismissed
89
+ };
90
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"useToastGesture.d.ts","sourceRoot":"","sources":["../../src/Toast/useToastGesture.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,YAAY,IAAI,iBAAiB,EAAE,SAAS,EAAC,MAAM,OAAO,CAAC;AAWxE,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAoB3C,UAAU,sBAAsB;IAC9B,SAAS,EAAE,qBAAqB,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,CAClB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,WAAW,KACd,OAAO,CAAC;CACd;AAED,UAAU,oBAAoB;IAC5B,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAClE,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAChE,eAAe,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACpE,oBAAoB,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC1C,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAcD,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,OAAO,EACP,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACX,OAAO,EACP,kBAAkB,GACnB,EAAE,sBAAsB,GAAG,qBAAqB,CA4QhD"}
1
+ {"version":3,"file":"useToastGesture.d.ts","sourceRoot":"","sources":["../../src/Toast/useToastGesture.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAC,YAAY,IAAI,iBAAiB,EAAE,SAAS,EAAC,MAAM,OAAO,CAAC;AAWxE,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AAsB3C,UAAU,sBAAsB;IAC9B,SAAS,EAAE,qBAAqB,CAAC;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,MAAM,OAAO,CAAC;IAC7B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,kBAAkB,EAAE,CAClB,MAAM,EAAE,WAAW,GAAG,IAAI,EAC1B,IAAI,EAAE,WAAW,KACd,OAAO,CAAC;CACd;AAED,UAAU,oBAAoB;IAC5B,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAClE,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IAChE,eAAe,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACpE,oBAAoB,EAAE,CAAC,KAAK,EAAE,iBAAiB,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;CAC1E;AAED,UAAU,qBAAqB;IAC7B,OAAO,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC1C,QAAQ,EAAE,oBAAoB,CAAC;CAChC;AAcD,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,OAAO,EACP,aAAa,EACb,aAAa,EACb,UAAU,EACV,WAAW,EACX,OAAO,EACP,kBAAkB,GACnB,EAAE,sBAAsB,GAAG,qBAAqB,CA+ThD"}
@@ -62,6 +62,7 @@ export function useToastGesture({
62
62
  }
63
63
  const surfaceSize = Math.max(root.getBoundingClientRect().height, 1);
64
64
  gestureRef.current = {
65
+ source: point.source,
65
66
  pointerId: point.pointerId,
66
67
  startX: point.clientX,
67
68
  startY: point.clientY,
@@ -77,7 +78,7 @@ export function useToastGesture({
77
78
  const moveGesture = useCallback((point, preventDefault, releaseCapture) => {
78
79
  const state = gestureRef.current;
79
80
  const root = rootRef.current;
80
- if (!state || !root || point.pointerId !== state.pointerId) {
81
+ if (!state || !root || point.source !== state.source || point.pointerId !== state.pointerId) {
81
82
  return;
82
83
  }
83
84
  const deltaX = point.clientX - state.startX;
@@ -111,7 +112,7 @@ export function useToastGesture({
111
112
  const endGesture = useCallback(point => {
112
113
  const state = gestureRef.current;
113
114
  const root = rootRef.current;
114
- if (!state || !root || point.pointerId !== state.pointerId) {
115
+ if (!state || !root || point.source !== state.source || point.pointerId !== state.pointerId) {
115
116
  return;
116
117
  }
117
118
  const travel = Math.max(0, (point.clientY - state.startY) * state.direction);
@@ -120,6 +121,10 @@ export function useToastGesture({
120
121
  gestureRef.current = null;
121
122
  root.style.removeProperty('transition-duration');
122
123
  if (isDismissed) {
124
+ // The exit animation owns the final translation. Clear the live-drag
125
+ // transform/fade/scale first so a standalone Toast does not remain
126
+ // partially translated or faded after its dismiss callback fires.
127
+ clearTransientStyles(root);
123
128
  root.style.setProperty('--_toast-swipe-exit-y', state.direction === 1 ? SWIPE_EXIT_DISTANCE : `calc(-1 * ${SWIPE_EXIT_DISTANCE})`);
124
129
  dismiss();
125
130
  return;
@@ -130,7 +135,12 @@ export function useToastGesture({
130
135
  }
131
136
  }, [dismiss, resumeTimer]);
132
137
  const handlePointerDown = useCallback(event => {
133
- if (event.pointerType === 'pen' && (event.button == null || event.button === 0) && beginGesture(event, event.target)) {
138
+ if (event.pointerType === 'pen' && (event.button == null || event.button === 0) && beginGesture({
139
+ source: 'pen',
140
+ pointerId: event.pointerId,
141
+ clientX: event.clientX,
142
+ clientY: event.clientY
143
+ }, event.target)) {
134
144
  rootRef.current?.setPointerCapture?.(event.pointerId);
135
145
  }
136
146
  }, [beginGesture]);
@@ -138,17 +148,27 @@ export function useToastGesture({
138
148
  if (event.pointerType !== 'pen') {
139
149
  return;
140
150
  }
141
- moveGesture(event, () => event.preventDefault(), () => rootRef.current?.releasePointerCapture?.(event.pointerId));
151
+ moveGesture({
152
+ source: 'pen',
153
+ pointerId: event.pointerId,
154
+ clientX: event.clientX,
155
+ clientY: event.clientY
156
+ }, () => event.preventDefault(), () => rootRef.current?.releasePointerCapture?.(event.pointerId));
142
157
  }, [moveGesture]);
143
158
  const handlePointerUp = useCallback(event => {
144
159
  if (event.pointerType !== 'pen') {
145
160
  return;
146
161
  }
147
162
  rootRef.current?.releasePointerCapture?.(event.pointerId);
148
- endGesture(event);
163
+ endGesture({
164
+ source: 'pen',
165
+ pointerId: event.pointerId,
166
+ clientX: event.clientX,
167
+ clientY: event.clientY
168
+ });
149
169
  }, [endGesture]);
150
170
  const handlePointerCancel = useCallback(event => {
151
- if (event.pointerType === 'pen' && gestureRef.current?.pointerId === event.pointerId) {
171
+ if (event.pointerType === 'pen' && gestureRef.current?.source === 'pen' && gestureRef.current?.pointerId === event.pointerId) {
152
172
  resetGesture(true);
153
173
  }
154
174
  }, [resetGesture]);
@@ -158,21 +178,34 @@ export function useToastGesture({
158
178
  return;
159
179
  }
160
180
  const point = touch => ({
181
+ source: 'touch',
161
182
  pointerId: touch.identifier,
162
183
  clientX: touch.clientX,
163
184
  clientY: touch.clientY
164
185
  });
165
186
  const changedTouch = event => {
166
- const pointerId = gestureRef.current?.pointerId;
187
+ const state = gestureRef.current;
188
+ const pointerId = state?.source === 'touch' ? state.pointerId : null;
167
189
  return pointerId == null ? undefined : [...event.changedTouches].find(touch => touch.identifier === pointerId);
168
190
  };
169
191
  const handleTouchStart = event => {
170
- const touch = event.touches.length === 1 ? event.changedTouches[0] : null;
171
- if (touch) {
192
+ if (event.touches?.length !== 1) {
193
+ // A second contact means the browser may be handling pinch zoom or
194
+ // two-finger scrolling. Abandon any accepted one-finger swipe before
195
+ // touchmove can suppress that native gesture.
196
+ resetGesture(true);
197
+ return;
198
+ }
199
+ const touch = event.changedTouches[0];
200
+ if (touch != null) {
172
201
  beginGesture(point(touch), event.target);
173
202
  }
174
203
  };
175
204
  const handleTouchMove = event => {
205
+ if (event.touches?.length !== 1) {
206
+ resetGesture(true);
207
+ return;
208
+ }
176
209
  const touch = changedTouch(event);
177
210
  if (touch) {
178
211
  moveGesture(point(touch), () => {
@@ -183,6 +216,10 @@ export function useToastGesture({
183
216
  }
184
217
  };
185
218
  const handleTouchEnd = event => {
219
+ if (event.touches.length > 0) {
220
+ resetGesture(true);
221
+ return;
222
+ }
186
223
  const touch = changedTouch(event);
187
224
  if (touch) {
188
225
  endGesture(point(touch));
package/dist/astryx.css CHANGED
@@ -494,6 +494,7 @@
494
494
  .x1ho7dyk:not(#\#):not(#\#){margin-inline:calc(-1 * var(--spacing-2))}
495
495
  .x1ng9b9t:not(#\#):not(#\#){margin-inline:calc(-1 * var(--spacing-4))}
496
496
  .xhrcg97:not(#\#):not(#\#){margin-inline:var(--spacing-1)}
497
+ .xam6yil:not(#\#):not(#\#){margin-inline:var(--spacing-3)}
497
498
  .xvlecxo:not(#\#):not(#\#){margin-inline:var(--x-marginInline)}
498
499
  .x1a2a7pz:not(#\#):not(#\#){outline:none}
499
500
  .xaw4jrz:not(#\#):not(#\#){outline:var(--_focus-outline,none)}
@@ -597,6 +598,7 @@
597
598
  .x1i10hfl:not(#\#):not(#\#):not(#\#){-webkit-tap-highlight-color:transparent}
598
599
  .xg7jpbn:not(#\#):not(#\#):not(#\#){-webkit-text-fill-color:transparent}
599
600
  .xpdipgo:not(#\#):not(#\#):not(#\#){-webkit-touch-callout:none}
601
+ .x1winvzj:not(#\#):not(#\#):not(#\#){-webkit-user-select:none}
600
602
  .x8gbvx8:not(#\#):not(#\#):not(#\#){align-content:flex-start}
601
603
  .x1pha0wt:not(#\#):not(#\#):not(#\#){align-items:baseline}
602
604
  .x6s0dn4:not(#\#):not(#\#):not(#\#){align-items:center}
@@ -709,6 +711,7 @@
709
711
  .xafqdz2:not(#\#):not(#\#):not(#\#){background-image:linear-gradient(to bottom,var(--color-background-surface) 60%,transparent)}
710
712
  .x1vrk509:not(#\#):not(#\#):not(#\#){background-image:linear-gradient(var(--color-background-muted),var(--color-background-muted))}
711
713
  .x14bno8m:not(#\#):not(#\#):not(#\#){background-image:linear-gradient(var(--color-neutral),var(--color-neutral))}
714
+ .xpl5ynk:not(#\#):not(#\#):not(#\#){background-image:linear-gradient(var(--color-overlay-pressed),var(--color-overlay-pressed))}
712
715
  .x18o3ruo:not(#\#):not(#\#):not(#\#){background-image:none}
713
716
  .x1mwwwfo:not(#\#):not(#\#):not(#\#){border-collapse:collapse}
714
717
  .x16uus16:not(#\#):not(#\#):not(#\#){border-end-end-radius:0}
@@ -1012,6 +1015,7 @@
1012
1015
  .xkd40ry:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(-1 * var(--spacing-1))}
1013
1016
  .x3kzqx6:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(-1 * var(--spacing-2))}
1014
1017
  .xmequkd:not(#\#):not(#\#):not(#\#){margin-inline-end:calc(var(--spacing-1) * -1)}
1018
+ .xxeicf8:not(#\#):not(#\#):not(#\#){margin-inline-end:max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))}
1015
1019
  .xnur1sd:not(#\#):not(#\#):not(#\#){margin-inline-end:var(--spacing-1)}
1016
1020
  .x1c9tiao:not(#\#):not(#\#):not(#\#){margin-inline-end:var(--x-marginInlineEnd)}
1017
1021
  .x1qfufaz:not(#\#):not(#\#):not(#\#){margin-inline-start:-8px}
@@ -1022,9 +1026,11 @@
1022
1026
  .x1wim8z0:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--layout-padding-inner-x,var(--spacing-4)))}
1023
1027
  .x1s1akpx:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(-1 * var(--spacing-2))}
1024
1028
  .x1xrm450:not(#\#):not(#\#):not(#\#){margin-inline-start:calc(var(--spacing-2) - var(--spacing-1) + 1px)}
1029
+ .x47fqr9:not(#\#):not(#\#):not(#\#){margin-inline-start:max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))}
1025
1030
  .x12vn87o:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--_tree-indent,0px)}
1026
1031
  .xladpz9:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--spacing-0-5)}
1027
1032
  .x11g1kdw:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--spacing-1)}
1033
+ .x6i7dpz:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--spacing-3)}
1028
1034
  .x1l10yog:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--spacing-6)}
1029
1035
  .x4lel18:not(#\#):not(#\#):not(#\#){margin-inline-start:var(--x-marginInlineStart)}
1030
1036
  .xkm2don:not(#\#):not(#\#):not(#\#){mask-image:linear-gradient(to bottom,transparent,black 24px)}
@@ -1298,6 +1304,7 @@
1298
1304
  .x1vxsm5i:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){animation-name:xu7jd1z-B}
1299
1305
  .x18lne9g:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){animation-name:xwmkjkf-B}
1300
1306
  .x1spg45b.x1spg45b:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:var(--color-accent)}
1307
+ .x1anq1lc.x1anq1lc:active:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:var(--color-overlay-pressed)}
1301
1308
  .x1rmb4wm:not(:has(~ *:not([popover]):not(template))):not(#\#):not(#\#):not(#\#){border-end-end-radius:var(--radius-element)}
1302
1309
  .xturttb:not(:has(~ *:not([popover]):not(template))):not(#\#):not(#\#):not(#\#){border-end-start-radius:var(--radius-element)}
1303
1310
  .x1tzxhge:not(:has(~ *:not([popover]):not(template))):not(#\#):not(#\#):not(#\#){border-start-end-radius:var(--radius-element)}
@@ -1310,7 +1317,9 @@
1310
1317
  .x16khyan:is(:disabled,[aria-disabled="true"]):not(#\#):not(#\#):not(#\#){cursor:default}
1311
1318
  .x1y40yee:popover-open:not(#\#):not(#\#):not(#\#){display:flex}
1312
1319
  .x1sik18w:not(:first-child):not(#\#):not(#\#):not(#\#){margin-inline-start:var(--_avatar-group-overlap)}
1320
+ .x17xqekc:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){mask-image:linear-gradient(to left,transparent 0%,rgba(0,0,0,.3) 2px,black var(--spacing-1))}
1313
1321
  .x1nwey30:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){mask-image:linear-gradient(to left,transparent var(--_tab-strip-bleed),black calc(var(--_tab-strip-bleed) + var(--spacing-8)))}
1322
+ .x8ulde1:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){mask-image:linear-gradient(to right,transparent 0%,rgba(0,0,0,.3) 2px,black var(--spacing-1))}
1314
1323
  .x1rxa4r8:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){mask-image:linear-gradient(to right,transparent var(--_tab-strip-bleed),black calc(var(--_tab-strip-bleed) + var(--spacing-8)))}
1315
1324
  .x1euntei:focus-within:not(#\#):not(#\#):not(#\#){opacity:1}
1316
1325
  .x25t5g8:focus-visible:not(#\#):not(#\#):not(#\#){opacity:1}
@@ -1331,6 +1340,7 @@
1331
1340
  .xbt4iw:focus-within:not(#\#):not(#\#):not(#\#){pointer-events:auto}
1332
1341
  .xo74pv5:focus-within:not(#\#):not(#\#):not(#\#){position:static}
1333
1342
  .x1mqgsch:is([data-astryx-scrolling]):not(#\#):not(#\#):not(#\#){scrollbar-width:none}
1343
+ .x8ppqj.x8ppqj:active:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){transform:scale(.98)}
1334
1344
  .xaafvuh:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1) rotate(0deg)}
1335
1345
  .x1nxqau:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1) rotate(90deg)}
1336
1346
  .xgtlewx:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform:scaleX(-1)}
@@ -1414,7 +1424,6 @@
1414
1424
  @media (prefers-reduced-motion: reduce){.xsr0bmt.xsr0bmt:not(#\#):not(#\#):not(#\#){transition-duration:0s,0s}}
1415
1425
  @media (prefers-reduced-motion: reduce){.x12w9bfk.x12w9bfk:not(#\#):not(#\#):not(#\#){transition-duration:0s}}
1416
1426
  @media (prefers-reduced-motion: reduce){.x4wkmsb.x4wkmsb:not(#\#):not(#\#):not(#\#){transition-property:none}}
1417
- .x1anq1lc.x1anq1lc:active:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:var(--color-overlay-pressed)}
1418
1427
  .xzmimnh.xzmimnh:active:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-image:linear-gradient(var(--color-overlay-pressed),var(--color-overlay-pressed)),linear-gradient(var(--color-neutral),var(--color-neutral))}
1419
1428
  .x7uyq82.x7uyq82:active:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-image:linear-gradient(var(--color-overlay-pressed),var(--color-overlay-pressed))}
1420
1429
  @media (hover: hover) and (forced-colors: none){.xcgwt1n.xcgwt1n.xcgwt1n:where(.x1iwu4tg:hover *):not(#\#):not(#\#):not(#\#){background-color:color-mix(in srgb,var(--color-accent),var(--color-tint-hover) 15%)}}
@@ -1555,6 +1564,7 @@
1555
1564
  .x6h7pi7:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:calc(-1 * var(--container-padding-block-end,0px))}
1556
1565
  .x1cdrix3:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:calc(-1 * var(--radius-chat))}
1557
1566
  .xdrfirk:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:calc(-1 * var(--spacing-1-5))}
1567
+ .x1kps3mo:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:max(var(--spacing-4),env(safe-area-inset-bottom,0px))}
1558
1568
  .xlstkdb:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:var(--spacing-0-5)}
1559
1569
  .x14cgwvg:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:var(--spacing-1)}
1560
1570
  .x1p37lm5:not(#\#):not(#\#):not(#\#):not(#\#){margin-bottom:var(--spacing-2)}
@@ -1572,6 +1582,7 @@
1572
1582
  .x1c40v9y:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--spacing-1-5))}
1573
1583
  .x1ajqlyv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc(-1 * var(--spacing-2))}
1574
1584
  .x1233pnv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:calc((1em * var(--text-body-leading) - 6px) / 2)}
1585
+ .xsoubt3:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:max(var(--spacing-4),env(safe-area-inset-top,0px))}
1575
1586
  .xjc2qm6:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:var(--spacing-0-5)}
1576
1587
  .xcsaf9d:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:var(--spacing-1)}
1577
1588
  .xtbrsbv:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:var(--spacing-2)}
@@ -1585,7 +1596,9 @@
1585
1596
  .x1xiyphd:not(#\#):not(#\#):not(#\#):not(#\#){max-height:240px}
1586
1597
  .xuyqlj2:not(#\#):not(#\#):not(#\#):not(#\#){max-height:300px}
1587
1598
  .xbhvqqn:not(#\#):not(#\#):not(#\#):not(#\#){max-height:calc(100% - var(--spacing-3))}
1599
+ .xtm2925:not(#\#):not(#\#):not(#\#):not(#\#){max-height:calc(100vh - var(--spacing-4) - var(--spacing-4));max-height:calc(100dvb - max(var(--spacing-4),env(safe-area-inset-top,0px)) - max(var(--spacing-4),env(safe-area-inset-bottom,0px)))}
1588
1600
  .x14bu9tk:not(#\#):not(#\#):not(#\#):not(#\#){max-height:calc(92dvh + 48px)}
1601
+ .x1hkkhfe:not(#\#):not(#\#):not(#\#):not(#\#){max-height:min(300px,calc(100vh - var(--spacing-4) - var(--spacing-4)));max-height:min(300px,calc(100dvb - max(var(--spacing-4),env(safe-area-inset-top,0px)) - max(var(--spacing-4),env(safe-area-inset-bottom,0px))))}
1589
1602
  .xpnbb6b:not(#\#):not(#\#):not(#\#):not(#\#){max-height:min(480px,calc(100vh - 32px))}
1590
1603
  .x7ab17h:not(#\#):not(#\#):not(#\#):not(#\#){max-height:none}
1591
1604
  .xenllk4:not(#\#):not(#\#):not(#\#):not(#\#){max-height:var(--container-max-height,none)}
@@ -1604,6 +1617,8 @@
1604
1617
  .x11gisft:not(#\#):not(#\#):not(#\#):not(#\#){max-width:640px}
1605
1618
  .x1ap80js:not(#\#):not(#\#):not(#\#):not(#\#){max-width:800px}
1606
1619
  .xq8v1hd:not(#\#):not(#\#):not(#\#):not(#\#){max-width:90%}
1620
+ .xbd96yr:not(#\#):not(#\#):not(#\#):not(#\#){max-width:calc(100% - var(--spacing-4));max-width:calc(100% - max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px)))}
1621
+ .xs2v1xk:not(#\#):not(#\#):not(#\#):not(#\#){max-width:calc(100vw - var(--spacing-4) - var(--spacing-4));max-width:calc(100vi - max(var(--spacing-4),env(safe-area-inset-left,0px)) - max(var(--spacing-4),env(safe-area-inset-right,0px)))}
1607
1622
  .xl6temz:not(#\#):not(#\#):not(#\#):not(#\#){max-width:max(80%,280px)}
1608
1623
  .x1m1aaou:not(#\#):not(#\#):not(#\#):not(#\#){max-width:min(960px,calc(100dvw - var(--spacing-4)))}
1609
1624
  .x1x1rfll:not(#\#):not(#\#):not(#\#):not(#\#){max-width:none}
@@ -1629,6 +1644,7 @@
1629
1644
  .xeuugli:not(#\#):not(#\#):not(#\#):not(#\#){min-width:0}
1630
1645
  .x1i9suas:not(#\#):not(#\#):not(#\#):not(#\#){min-width:120px}
1631
1646
  .x1d77m7x:not(#\#):not(#\#):not(#\#):not(#\#){min-width:140px}
1647
+ .x12knhqr:not(#\#):not(#\#):not(#\#):not(#\#){min-width:160px;min-width:min(160px,calc(100vw - var(--spacing-4) - var(--spacing-4)));min-width:min(160px,calc(100vi - max(var(--spacing-4),env(safe-area-inset-left,0px)) - max(var(--spacing-4),env(safe-area-inset-right,0px))))}
1632
1648
  .x5w4yej:not(#\#):not(#\#):not(#\#):not(#\#){min-width:160px}
1633
1649
  .xfb3i0g:not(#\#):not(#\#):not(#\#):not(#\#){min-width:180px}
1634
1650
  .xgomdpo:not(#\#):not(#\#):not(#\#):not(#\#){min-width:1rem}
@@ -1641,6 +1657,8 @@
1641
1657
  .x900493:not(#\#):not(#\#):not(#\#):not(#\#){min-width:48px}
1642
1658
  .x13n9wmd:not(#\#):not(#\#):not(#\#):not(#\#){min-width:4ch}
1643
1659
  .xfvyar9:not(#\#):not(#\#):not(#\#):not(#\#){min-width:60px}
1660
+ .x1ks9poc:not(#\#):not(#\#):not(#\#):not(#\#){min-width:anchor-size(width);min-width:min(anchor-size(width),calc(100% - var(--spacing-4)));min-width:min(anchor-size(width),calc(100% - max(var(--spacing-4),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))))}
1661
+ .xagy28z:not(#\#):not(#\#):not(#\#):not(#\#){min-width:anchor-size(width);min-width:min(anchor-size(width),calc(100vw - var(--spacing-4) - var(--spacing-4)));min-width:min(anchor-size(width),calc(100vi - max(var(--spacing-4),env(safe-area-inset-left,0px)) - max(var(--spacing-4),env(safe-area-inset-right,0px))))}
1644
1662
  .xrzjruh:not(#\#):not(#\#):not(#\#):not(#\#){min-width:anchor-size(width)}
1645
1663
  .x8wyhu6:not(#\#):not(#\#):not(#\#):not(#\#){min-width:calc(anchor-size(width) + 16px)}
1646
1664
  .x1pshirs:not(#\#):not(#\#):not(#\#):not(#\#){min-width:fit-content}
@@ -0,0 +1,5 @@
1
+ export type AdaptivePresentation = 'popover' | 'bottom-sheet' | 'adaptive';
2
+ export type ResolvedAdaptivePresentation = Exclude<AdaptivePresentation, 'adaptive'>;
3
+ export declare const COMPACT_TOUCH_PRESENTATION_QUERY = "(max-width: 768px) and (pointer: coarse)";
4
+ export declare function useAdaptivePresentation(presentation: AdaptivePresentation): ResolvedAdaptivePresentation;
5
+ //# sourceMappingURL=useAdaptivePresentation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAdaptivePresentation.d.ts","sourceRoot":"","sources":["../../src/hooks/useAdaptivePresentation.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,cAAc,GAAG,UAAU,CAAC;AAC3E,MAAM,MAAM,4BAA4B,GAAG,OAAO,CAChD,oBAAoB,EACpB,UAAU,CACX,CAAC;AAKF,eAAO,MAAM,gCAAgC,6CACD,CAAC;AAE7C,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,oBAAoB,GACjC,4BAA4B,CAO9B"}
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useAdaptivePresentation.ts
7
+ * @input Uses the shared SSR-safe media-query hook
8
+ * @output Resolves popover/bottom-sheet presentation policy
9
+ * @position Internal overlay policy shared across component families
10
+ */
11
+ import { useMediaQuery } from "./useMediaQuery.js";
12
+ // Width keeps desktop-class tablets and large touch displays anchored by
13
+ // default. Pointer capability, rather than `hover: none`, avoids excluding
14
+ // touch browsers that also report hover capability.
15
+ export const COMPACT_TOUCH_PRESENTATION_QUERY = '(max-width: 768px) and (pointer: coarse)';
16
+ export function useAdaptivePresentation(presentation) {
17
+ const isCompactTouch = useMediaQuery(COMPACT_TOUCH_PRESENTATION_QUERY);
18
+ return presentation === 'adaptive' ? isCompactTouch ? 'bottom-sheet' : 'popover' : presentation;
19
+ }
@@ -0,0 +1,7 @@
1
+ export declare function useFocusReturnVisibility(): {
2
+ isFocusRingSuppressed: boolean;
3
+ onFocusReturnTargetFocus: () => void;
4
+ prepareFocusReturn: () => void;
5
+ resetFocusReturn: () => void;
6
+ };
7
+ //# sourceMappingURL=useFocusReturnVisibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useFocusReturnVisibility.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusReturnVisibility.ts"],"names":[],"mappings":"AAiBA,wBAAgB,wBAAwB;;;;;EA2BvC"}
@@ -0,0 +1,35 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useFocusReturnVisibility.ts
7
+ * @input Uses the shared interaction-modality tracker
8
+ * @output Preserves returned focus while suppressing pointer-only focus rings
9
+ * @position Internal focus-return policy for adaptive overlays
10
+ */
11
+ import { useCallback, useEffect, useState } from 'react';
12
+ import { getInteractionModality, trackInteractionModality } from "../utils/interactionModality.js";
13
+ export function useFocusReturnVisibility() {
14
+ const [isFocusRingSuppressed, setIsFocusRingSuppressed] = useState(false);
15
+ useEffect(() => {
16
+ trackInteractionModality();
17
+ }, []);
18
+ const prepareFocusReturn = useCallback(() => {
19
+ setIsFocusRingSuppressed(getInteractionModality() === 'pointer');
20
+ }, []);
21
+ const resetFocusReturn = useCallback(() => {
22
+ setIsFocusRingSuppressed(false);
23
+ }, []);
24
+ const onFocusReturnTargetFocus = useCallback(() => {
25
+ if (getInteractionModality() === 'keyboard') {
26
+ setIsFocusRingSuppressed(false);
27
+ }
28
+ }, []);
29
+ return {
30
+ isFocusRingSuppressed,
31
+ onFocusReturnTargetFocus,
32
+ prepareFocusReturn,
33
+ resetFocusReturn
34
+ };
35
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAgFD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAExC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CA6NvB"}
1
+ {"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAgFD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAExC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CA0OvB"}
@@ -321,6 +321,18 @@ export function useFocusTrap(options) {
321
321
  }
322
322
  const first = focusable[0];
323
323
  const last = focusable[focusable.length - 1];
324
+ if (document.activeElement === container) {
325
+ // Programmatic initial focus can sit on the trap container itself
326
+ // (for example a dialog panel with no content controls). Move into
327
+ // the tabbable cycle instead of letting Tab escape to the page.
328
+ event.preventDefault();
329
+ if (event.shiftKey) {
330
+ last.focus();
331
+ } else {
332
+ first.focus();
333
+ }
334
+ return;
335
+ }
324
336
  if (event.shiftKey) {
325
337
  // Shift+Tab: if on first element, wrap to last
326
338
  if (document.activeElement === first) {
package/locales/en.json CHANGED
@@ -415,6 +415,10 @@
415
415
  "defaultMessage": "Menu",
416
416
  "description": "Screen-reader-only fallback name for a dropdown menu popover. Very generic; consumers usually override. Noun (\"a menu\"), not the imperative."
417
417
  },
418
+ "@astryx.dropdownMenu.back": {
419
+ "defaultMessage": "Back",
420
+ "description": "Button label that returns from a nested action list to its parent inside a DropdownMenu bottom sheet. Imperative navigation action."
421
+ },
418
422
  "@astryx.lightbox.close": {
419
423
  "defaultMessage": "Close",
420
424
  "description": "\"Close\" = shut/dismiss (not \"nearby\"). Screen-reader-only label on the X button that dismisses a Lightbox."
@@ -951,6 +955,22 @@
951
955
  "defaultMessage": "Error: {message}",
952
956
  "description": "Screen-reader text for a tool call that failed. {message} is the error detail."
953
957
  },
958
+ "@astryx.chatToolCalls.status.pending": {
959
+ "defaultMessage": "Pending",
960
+ "description": "Screen-reader-only status label for a tool call that is waiting to begin."
961
+ },
962
+ "@astryx.chatToolCalls.status.running": {
963
+ "defaultMessage": "Running",
964
+ "description": "Screen-reader-only status label for a tool call that is currently running."
965
+ },
966
+ "@astryx.chatToolCalls.status.complete": {
967
+ "defaultMessage": "Complete",
968
+ "description": "Screen-reader-only status label for a tool call that completed successfully."
969
+ },
970
+ "@astryx.chatToolCalls.status.error": {
971
+ "defaultMessage": "Failed",
972
+ "description": "Screen-reader-only status label for a failed tool call when no error detail is supplied."
973
+ },
954
974
  "@astryx.chatToolCalls.groupLabel": {
955
975
  "defaultMessage": "{count} tool calls",
956
976
  "description": "Summary label shown in the group header when multiple tool calls are expanded. {count} is the number of calls."
@@ -311,6 +311,9 @@
311
311
  "@astryx.dropdownMenu.label": {
312
312
  "defaultMessage": "⟦Ṁéñú⟧"
313
313
  },
314
+ "@astryx.dropdownMenu.back": {
315
+ "defaultMessage": "⟦Ɓàçķ⟧"
316
+ },
314
317
  "@astryx.lightbox.close": {
315
318
  "defaultMessage": "⟦Çłóšé⟧"
316
319
  },
@@ -713,6 +716,18 @@
713
716
  "@astryx.chatToolCalls.error": {
714
717
  "defaultMessage": "⟦Éřřóř: {message}⟧"
715
718
  },
719
+ "@astryx.chatToolCalls.status.pending": {
720
+ "defaultMessage": "⟦Þéñðíñĝ⟧"
721
+ },
722
+ "@astryx.chatToolCalls.status.running": {
723
+ "defaultMessage": "⟦Řúññíñĝ⟧"
724
+ },
725
+ "@astryx.chatToolCalls.status.complete": {
726
+ "defaultMessage": "⟦Çóɱþłéţé⟧"
727
+ },
728
+ "@astryx.chatToolCalls.status.error": {
729
+ "defaultMessage": "⟦Ƒàíłéð⟧"
730
+ },
716
731
  "@astryx.chatToolCalls.groupLabel": {
717
732
  "defaultMessage": "⟦{count} ţóół çàłłš⟧"
718
733
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.5.2-canary.c9c8564",
3
+ "version": "0.5.2-canary.e4f8e4e",
4
4
  "displayName": "Astryx Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -661,7 +661,7 @@
661
661
  "react-dom": ">=19.0.0"
662
662
  },
663
663
  "devDependencies": {
664
- "@astryxdesign/cli": "0.5.2-canary.c9c8564",
664
+ "@astryxdesign/cli": "0.5.2-canary.e4f8e4e",
665
665
  "@babel/cli": "^8.0.4",
666
666
  "@babel/core": "^7.29.7",
667
667
  "@babel/preset-react": "^8.0.1",
@@ -71,6 +71,12 @@ export const docs = {
71
71
  description:
72
72
  'For a standalone sheet, called when it requests an open-state change. Automatic calls follow purpose: info dismisses on Escape, scrim click, or swipe; form dismisses on Escape only; required never dismisses implicitly. Omit inside BottomSheetSwitcher.',
73
73
  },
74
+ {
75
+ name: 'finalFocusRef',
76
+ type: 'RefObject<HTMLElement | null>',
77
+ description:
78
+ 'Optional explicit focus-return target for a standalone sheet. Use when the opener can remount or the active element is not a reliable trigger, such as an adaptive presentation switch. Omit inside BottomSheetSwitcher.',
79
+ },
74
80
  {
75
81
  name: 'purpose',
76
82
  type: "'required' | 'form' | 'info'",