@astryxdesign/core 0.4.1 → 0.4.2-canary.464a445
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 +55 -0
- package/dist/Avatar/Avatar.d.ts +4 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +19 -23
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +9 -7
- package/dist/Chat/ChatMessage.d.ts +7 -0
- package/dist/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.d.ts +13 -1
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +19 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +5 -0
- package/dist/CommandPalette/CommandPaletteFooter.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteFooter.js +5 -3
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +2 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +19 -15
- package/dist/HoverCard/HoverCard.d.ts +1 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +5 -13
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +6 -5
- package/dist/InputGroup/groupStyles.d.ts.map +1 -1
- package/dist/InputGroup/groupStyles.js +7 -2
- package/dist/Layer/layerHost.d.ts +24 -0
- package/dist/Layer/layerHost.d.ts.map +1 -0
- package/dist/Layer/layerHost.js +79 -0
- package/dist/Layer/useLayer.d.ts +14 -6
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +158 -30
- package/dist/NavItem/navItemStyles.stylex.d.ts +17 -5
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +11 -5
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +5 -0
- package/dist/SideNav/SideNav.d.ts +7 -9
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +32 -5
- package/dist/SideNav/SideNavCollapseButton.d.ts +25 -9
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +39 -15
- package/dist/SideNav/SideNavCollapseContext.d.ts +21 -0
- package/dist/SideNav/SideNavCollapseContext.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseContext.js +16 -2
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +89 -32
- package/dist/SideNav/SideNavItem.d.ts +7 -2
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +119 -75
- package/dist/SideNav/SideNavSection.d.ts.map +1 -1
- package/dist/SideNav/SideNavSection.js +7 -16
- package/dist/SideNav/index.d.ts +1 -1
- package/dist/SideNav/index.d.ts.map +1 -1
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +56 -15
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -0
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +5 -0
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +14 -6
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +25 -93
- package/dist/TopNav/TopNavMegaMenuItem.js +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +10 -5
- package/dist/astryx.css +13 -7
- package/dist/astryx.umd.js +50 -50
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +16 -2
- package/dist/hooks/useMenuHover.d.ts +50 -5
- package/dist/hooks/useMenuHover.d.ts.map +1 -1
- package/dist/hooks/useMenuHover.js +171 -51
- package/dist/theme/defineTheme.d.ts +8 -2
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +8 -1
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +7 -0
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +1 -0
- package/dist/theme/expandMotionScale.d.ts +1 -0
- package/dist/theme/expandMotionScale.d.ts.map +1 -1
- package/dist/theme/expandMotionScale.js +1 -0
- package/dist/theme/expandRadiusScale.d.ts +1 -0
- package/dist/theme/expandRadiusScale.d.ts.map +1 -1
- package/dist/theme/expandRadiusScale.js +1 -0
- package/dist/theme/expandTypeScale.d.ts +1 -0
- package/dist/theme/expandTypeScale.d.ts.map +1 -1
- package/dist/theme/expandTypeScale.js +1 -0
- package/dist/theme/tokens.stylex.d.ts +3 -1
- package/dist/theme/tokens.stylex.d.ts.map +1 -1
- package/dist/theme/tokens.stylex.js +3 -1
- package/locales/en.json +84 -0
- package/locales/pseudo.json +63 -0
- package/package.json +3 -3
- package/src/Avatar/Avatar.doc.mjs +5 -2
- package/src/Avatar/Avatar.test.tsx +51 -0
- package/src/Avatar/Avatar.tsx +30 -20
- package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -1
- package/src/AvatarGroup/AvatarGroup.test.tsx +14 -0
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -2
- package/src/Button/Button.tsx +5 -3
- package/src/ButtonGroup/ButtonGroup.test.tsx +7 -4
- package/src/Card/Card.doc.mjs +2 -0
- package/src/Chat/Chat.doc.mjs +4 -1
- package/src/Chat/ChatMessage.doc.mjs +3 -3
- package/src/Chat/ChatMessage.tsx +7 -0
- package/src/Chat/ChatMessageBubble.doc.mjs +7 -0
- package/src/Chat/ChatMessageBubble.test.tsx +95 -6
- package/src/Chat/ChatMessageBubble.tsx +25 -0
- package/src/CheckboxInput/CheckboxInput.tsx +20 -0
- package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
- package/src/CommandPalette/CommandPaletteFooter.tsx +6 -3
- package/src/DateTimeInput/DateTimeInput.tsx +4 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +72 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +24 -20
- package/src/HoverCard/HoverCard.doc.mjs +3 -3
- package/src/HoverCard/HoverCard.test.tsx +283 -55
- package/src/HoverCard/HoverCard.tsx +5 -13
- package/src/HoverCard/useHoverCard.tsx +8 -11
- package/src/InputGroup/groupStyles.ts +7 -8
- package/src/Item/Item.doc.mjs +4 -0
- package/src/Layer/layerHost.test.ts +99 -0
- package/src/Layer/layerHost.ts +141 -0
- package/src/Layer/useLayer.doc.mjs +14 -4
- package/src/Layer/useLayer.test.tsx +332 -7
- package/src/Layer/useLayer.tsx +235 -36
- package/src/MobileNav/MobileNav.doc.mjs +7 -0
- package/src/NavItem/navItemStyles.stylex.ts +31 -5
- package/src/RadioList/RadioListItem.tsx +20 -0
- package/src/SideNav/SideNav.doc.mjs +13 -4
- package/src/SideNav/SideNav.test.tsx +858 -2
- package/src/SideNav/SideNav.tsx +37 -16
- package/src/SideNav/SideNavCollapseButton.doc.mjs +28 -6
- package/src/SideNav/SideNavCollapseButton.tsx +67 -15
- package/src/SideNav/SideNavCollapseContext.ts +29 -9
- package/src/SideNav/SideNavHeading.tsx +53 -25
- package/src/SideNav/SideNavItem.doc.mjs +13 -0
- package/src/SideNav/SideNavItem.tsx +97 -84
- package/src/SideNav/SideNavSection.tsx +6 -20
- package/src/SideNav/index.ts +2 -0
- package/src/Slider/Slider.test.tsx +69 -33
- package/src/Slider/Slider.tsx +65 -13
- package/src/Switch/Switch.tsx +20 -0
- package/src/TabList/TabList.doc.mjs +3 -0
- package/src/Text/Text.doc.mjs +1 -1
- package/src/Thumbnail/Thumbnail.doc.mjs +3 -0
- package/src/Thumbnail/Thumbnail.tsx +10 -0
- package/src/Timestamp/Timestamp.test.tsx +40 -22
- package/src/Toolbar/Toolbar.test.tsx +14 -14
- package/src/TopNav/TopNav.test.tsx +86 -1
- package/src/TopNav/TopNavHeading.tsx +21 -14
- package/src/TopNav/TopNavMegaMenu.test.tsx +43 -0
- package/src/TopNav/TopNavMegaMenu.tsx +29 -105
- package/src/TopNav/TopNavMegaMenuItem.tsx +1 -1
- package/src/TopNav/TopNavMenu.test.tsx +41 -0
- package/src/TopNav/TopNavMenu.tsx +14 -4
- package/src/TreeList/TreeList.doc.mjs +1 -0
- package/src/hooks/index.ts +5 -1
- package/src/hooks/useFocusTrap.test.tsx +16 -0
- package/src/hooks/useFocusTrap.ts +20 -2
- package/src/hooks/useMenuHover.test.tsx +364 -0
- package/src/hooks/useMenuHover.ts +243 -47
- package/src/theme/defineTheme.ts +9 -0
- package/src/theme/derivedVarRegistry.test.ts +78 -12
- package/src/theme/derivedVarRegistry.ts +4 -0
- package/src/theme/expandColorScale.ts +1 -0
- package/src/theme/expandMotionScale.ts +1 -0
- package/src/theme/expandRadiusScale.ts +1 -0
- package/src/theme/expandTypeScale.ts +1 -0
- package/src/theme/themingTargets.test.ts +152 -26
- package/src/theme/tokens.stylex.ts +3 -1
- package/src/theme/tokens.test.ts +12 -0
- package/src/theme/useTheme.test.tsx +18 -0
package/dist/hooks/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* SYNC: When modified, update this header
|
|
8
8
|
*/
|
|
9
|
-
export { useFocusTrap } from './useFocusTrap';
|
|
9
|
+
export { hasActiveFocusTrapEscape, isImeKeyEvent, useFocusTrap, } from './useFocusTrap';
|
|
10
10
|
export type { UseFocusTrapOptions, UseFocusTrapReturn } from './useFocusTrap';
|
|
11
11
|
export { useAnnounce } from './useAnnounce';
|
|
12
12
|
export type { AnnounceFn, AnnouncePoliteness } from './useAnnounce';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update this header
|
|
12
12
|
*/
|
|
13
|
-
export { useFocusTrap } from "./useFocusTrap.js";
|
|
13
|
+
export { hasActiveFocusTrapEscape, isImeKeyEvent, useFocusTrap } from "./useFocusTrap.js";
|
|
14
14
|
export { useAnnounce } from "./useAnnounce.js";
|
|
15
15
|
export { useClipboard } from "./useClipboard.js";
|
|
16
16
|
export { useGridFocus } from "./useGridFocus.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.ts"],"names":[],"mappings":"AAsFA;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAEV;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,
|
|
1
|
+
{"version":3,"file":"useFocusTrap.d.ts","sourceRoot":"","sources":["../../src/hooks/useFocusTrap.ts"],"names":[],"mappings":"AAsFA;;;;;GAKG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAEV;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,CAwNvB"}
|
|
@@ -277,12 +277,17 @@ export function useFocusTrap(options) {
|
|
|
277
277
|
lastFocusRef.current = target;
|
|
278
278
|
} else if (isKeyboardNavigationRef.current) {
|
|
279
279
|
// Focus escaped via keyboard - redirect it back
|
|
280
|
-
focusFirstDescendant(container);
|
|
280
|
+
const focusedFirst = focusFirstDescendant(container);
|
|
281
281
|
|
|
282
282
|
// If we're back at the same element (Shift+Tab from first element),
|
|
283
283
|
// try focusing the last element instead
|
|
284
|
-
if (lastFocusRef.current === document.activeElement) {
|
|
284
|
+
if (focusedFirst && lastFocusRef.current === document.activeElement) {
|
|
285
285
|
focusLastDescendant(container);
|
|
286
|
+
} else if (!focusedFirst && lastFocusRef.current instanceof HTMLElement && container.contains(lastFocusRef.current)) {
|
|
287
|
+
// A modal surface may intentionally have no tabbable controls and
|
|
288
|
+
// place initial focus on a tabIndex={-1} heading or panel. Preserve
|
|
289
|
+
// that programmatic focus target instead of letting Tab escape.
|
|
290
|
+
attemptFocus(lastFocusRef.current);
|
|
286
291
|
}
|
|
287
292
|
lastFocusRef.current = document.activeElement;
|
|
288
293
|
}
|
|
@@ -345,6 +350,15 @@ export function useFocusTrap(options) {
|
|
|
345
350
|
isKeyboardNavigationRef.current = true;
|
|
346
351
|
const focusable = getFocusableElements(container);
|
|
347
352
|
if (focusable.length === 0) {
|
|
353
|
+
// There is nowhere to advance to. Keep focus on the current
|
|
354
|
+
// programmatic target (for example a dialog panel with tabIndex=-1)
|
|
355
|
+
// rather than allowing the browser to move into background content.
|
|
356
|
+
event.preventDefault();
|
|
357
|
+
const active = document.activeElement;
|
|
358
|
+
if (active instanceof HTMLElement && container.contains(active)) {
|
|
359
|
+
lastFocusRef.current = active;
|
|
360
|
+
}
|
|
361
|
+
isKeyboardNavigationRef.current = false;
|
|
348
362
|
return;
|
|
349
363
|
}
|
|
350
364
|
const first = focusable[0];
|
|
@@ -1,18 +1,46 @@
|
|
|
1
|
-
interface UseMenuHoverOptions {
|
|
1
|
+
export interface UseMenuHoverOptions {
|
|
2
2
|
show: (options?: {
|
|
3
3
|
skipAutoFocus?: boolean;
|
|
4
4
|
}) => void;
|
|
5
5
|
hide: () => void;
|
|
6
6
|
isOpen: boolean;
|
|
7
7
|
isEnabled: boolean;
|
|
8
|
+
/** Delay before a hover opens the menu (ms). @default 150 */
|
|
8
9
|
showDelay?: number;
|
|
10
|
+
/** Delay before leaving the trigger or menu closes it (ms). @default 200 */
|
|
9
11
|
hideDelay?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Window after a hover-open in which a click confirms the menu instead of
|
|
14
|
+
* closing it. 0 opts out, making every click toggle. @default 500
|
|
15
|
+
*/
|
|
16
|
+
clickGuardMs?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Selector for the menu's focusable items, forwarded to `useListFocus`. A
|
|
19
|
+
* panel of links (a mega menu) needs an override; `role="menuitem"` rows do
|
|
20
|
+
* not. @default '[role="menuitem"]'
|
|
21
|
+
*/
|
|
22
|
+
itemSelector?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The popup's DOM id (`usePopover().id`). Supply it when the popup is a
|
|
25
|
+
* native `popover="auto"` and the trigger sits outside it; omit it for
|
|
26
|
+
* `popover="manual"` popups and triggers inside the panel.
|
|
27
|
+
*/
|
|
28
|
+
popoverId?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Whether the hook moves focus on a click or keyboard open. False for
|
|
31
|
+
* consumers that wire the pointer half only and leave focus to the popover's
|
|
32
|
+
* own trap — a panel that is a dialog rather than a menu (`SideNavItem`'s
|
|
33
|
+
* collapsed flyout) has no items for the hook to focus. @default true
|
|
34
|
+
*/
|
|
35
|
+
ownsFocus?: boolean;
|
|
10
36
|
}
|
|
11
|
-
interface UseMenuHoverReturn<T extends HTMLElement = HTMLElement> {
|
|
37
|
+
export interface UseMenuHoverReturn<T extends HTMLElement = HTMLElement> {
|
|
12
38
|
triggerProps: {
|
|
13
|
-
onClick: () => void;
|
|
39
|
+
onClick: (event?: React.MouseEvent) => void;
|
|
14
40
|
onMouseEnter: () => void;
|
|
15
41
|
onMouseLeave: () => void;
|
|
42
|
+
/** Present only when `popoverId` is supplied. */
|
|
43
|
+
popoverTarget?: string;
|
|
16
44
|
};
|
|
17
45
|
contentProps: {
|
|
18
46
|
onMouseEnter: () => void;
|
|
@@ -20,9 +48,26 @@ interface UseMenuHoverReturn<T extends HTMLElement = HTMLElement> {
|
|
|
20
48
|
onKeyDown: (e: React.KeyboardEvent) => void;
|
|
21
49
|
};
|
|
22
50
|
menuRef: React.RefObject<T | null>;
|
|
23
|
-
|
|
51
|
+
/** Focus the first enabled item. Returns false when there was none. */
|
|
52
|
+
focusFirst: () => boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Focus the first enabled item, falling back to the menu container when the
|
|
55
|
+
* menu is empty or still loading.
|
|
56
|
+
*/
|
|
57
|
+
focusMenu: () => void;
|
|
58
|
+
/**
|
|
59
|
+
* For consumers with their own click handler: call this in the open branch.
|
|
60
|
+
* Returns `true` when the click was the one following a hover-open — the menu
|
|
61
|
+
* is now pinned and the click must NOT be treated as a dismissal.
|
|
62
|
+
*/
|
|
63
|
+
confirmHoverOpen: () => boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Close, restoring focus to the trigger. For dismiss affordances rendered
|
|
66
|
+
* inside the popup, which are close buttons rather than the trigger and so
|
|
67
|
+
* must not carry its toggle and keyboard-activation semantics.
|
|
68
|
+
*/
|
|
69
|
+
close: () => void;
|
|
24
70
|
setTriggerEl: (el: HTMLElement | null) => void;
|
|
25
71
|
}
|
|
26
72
|
export declare function useMenuHover<T extends HTMLElement = HTMLElement>(options: UseMenuHoverOptions): UseMenuHoverReturn<T>;
|
|
27
|
-
export {};
|
|
28
73
|
//# sourceMappingURL=useMenuHover.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMenuHover.d.ts","sourceRoot":"","sources":["../../src/hooks/useMenuHover.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useMenuHover.d.ts","sourceRoot":"","sources":["../../src/hooks/useMenuHover.ts"],"names":[],"mappings":"AAwDA,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE;QAAC,aAAa,CAAC,EAAE,OAAO,CAAA;KAAC,KAAK,IAAI,CAAC;IACpD,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE,YAAY,EAAE;QACZ,OAAO,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;QAC5C,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,iDAAiD;QACjD,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,YAAY,EAAE;QACZ,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,YAAY,EAAE,MAAM,IAAI,CAAC;QACzB,SAAS,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;KAC7C,CAAC;IACF,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACnC,uEAAuE;IACvE,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B;;;OAGG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB;;;;OAIG;IACH,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC;;;;OAIG;IACH,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,YAAY,EAAE,CAAC,EAAE,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CAChD;AAED,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CAqQvB"}
|
|
@@ -4,26 +4,53 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file useMenuHover.ts
|
|
7
|
-
* @input Uses React hooks, useListFocus
|
|
7
|
+
* @input Uses React hooks, useListFocus, useMediaQuery
|
|
8
8
|
* @output Exports useMenuHover hook
|
|
9
|
-
* @position Internal hook; used by nav heading components
|
|
9
|
+
* @position Internal hook; used by nav heading components, TopNavMenu,
|
|
10
|
+
* TopNavMegaMenu and DropdownMenuSubMenu
|
|
10
11
|
*
|
|
11
|
-
* Hover as a progressive enhancement
|
|
12
|
+
* Hover as a progressive enhancement over standard popover behavior: click
|
|
13
|
+
* toggles, Escape and outside-click close, arrows navigate; on top of that,
|
|
14
|
+
* mouseenter opens after a delay and mouseleave closes one that hover opened.
|
|
12
15
|
*
|
|
13
|
-
*
|
|
14
|
-
* arrow keys navigate menu items.
|
|
16
|
+
* Three behaviors here are not obvious and are load-bearing:
|
|
15
17
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* - Click-to-close additionally skips the next mouseenter
|
|
18
|
+
* 1. Hover→click guard (#3121). A hover-opened menu is already open under the
|
|
19
|
+
* cursor when the pointer arrives, so the click that naturally follows would
|
|
20
|
+
* toggle it shut. Within `clickGuardMs` a click instead confirms it: the menu
|
|
21
|
+
* pins and behaves like a click-open from then on.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
+
* 2. Focus moves synchronously. `useLayer.show()` calls `showPopover()` in the
|
|
24
|
+
* same tick and the layer's children are always mounted, so items are
|
|
25
|
+
* focusable the moment `show()` returns — a `requestAnimationFrame` here
|
|
26
|
+
* lands after paint and races anything else moving focus. Hover-opens are the
|
|
27
|
+
* exception: the pointer is driving, so focus stays on the trigger. The hook
|
|
28
|
+
* always passes `skipAutoFocus` and owns focus itself, because the popover's
|
|
29
|
+
* auto-focus targets the first *tabbable* node while a menu wants its first
|
|
30
|
+
* item — under roving tabindex those are different elements.
|
|
31
|
+
*
|
|
32
|
+
* 3. Native light dismiss. A `popover="auto"` is dismissed by the browser on
|
|
33
|
+
* pointer interaction outside the panel, and a trigger outside the panel
|
|
34
|
+
* counts — before React's click handler runs. `popoverId` makes the trigger
|
|
35
|
+
* the panel's invoker, which exempts it. jsdom implements neither light
|
|
36
|
+
* dismiss nor invokers, so that wiring is only verifiable in a browser.
|
|
23
37
|
*/
|
|
24
38
|
import { useCallback, useEffect, useRef } from 'react';
|
|
39
|
+
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
25
40
|
import { useListFocus } from "./useListFocus.js";
|
|
26
41
|
import { useMediaQuery } from "./useMediaQuery.js";
|
|
42
|
+
const DEFAULT_CLICK_GUARD_MS = 500;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* How long after a close a mouseenter on the trigger is ignored.
|
|
46
|
+
*
|
|
47
|
+
* A panel positioned over its own trigger puts that trigger back under a
|
|
48
|
+
* stationary pointer when it closes, and the browser fires a fresh mouseenter —
|
|
49
|
+
* which reopened the menu the user had just dismissed. Time-bounded rather than
|
|
50
|
+
* a one-shot flag, so a deliberate re-hover seconds later still opens; a real
|
|
51
|
+
* mouseleave clears it early.
|
|
52
|
+
*/
|
|
53
|
+
const REOPEN_SUPPRESS_MS = 300;
|
|
27
54
|
export function useMenuHover(options) {
|
|
28
55
|
const {
|
|
29
56
|
show,
|
|
@@ -31,23 +58,35 @@ export function useMenuHover(options) {
|
|
|
31
58
|
isOpen,
|
|
32
59
|
isEnabled,
|
|
33
60
|
showDelay = 150,
|
|
34
|
-
hideDelay = 200
|
|
61
|
+
hideDelay = 200,
|
|
62
|
+
clickGuardMs = DEFAULT_CLICK_GUARD_MS,
|
|
63
|
+
itemSelector,
|
|
64
|
+
popoverId,
|
|
65
|
+
ownsFocus = true
|
|
35
66
|
} = options;
|
|
36
67
|
const hasHover = useMediaQuery('(hover: hover)');
|
|
37
68
|
const showTimerRef = useRef(null);
|
|
38
69
|
const hideTimerRef = useRef(null);
|
|
39
70
|
const triggerElRef = useRef(null);
|
|
40
|
-
|
|
71
|
+
/** Menu was hover-opened, so mouseleave may close it. */
|
|
41
72
|
const hoverModeRef = useRef(false);
|
|
42
|
-
|
|
43
|
-
|
|
73
|
+
const closedAtRef = useRef(0);
|
|
74
|
+
/** When the current open began as a hover-open; 0 once confirmed or closed. */
|
|
75
|
+
const hoverOpenedAtRef = useRef(0);
|
|
44
76
|
const prevIsOpenRef = useRef(isOpen);
|
|
45
77
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
78
|
+
// Catches every close, whatever caused it. A layout effect, not render: it
|
|
79
|
+
// must land before the browser hit-tests the vanished panel and fires the
|
|
80
|
+
// mouseenter REOPEN_SUPPRESS_MS exists to swallow.
|
|
81
|
+
useIsomorphicLayoutEffect(() => {
|
|
82
|
+
const wasOpen = prevIsOpenRef.current;
|
|
83
|
+
prevIsOpenRef.current = isOpen;
|
|
84
|
+
if (wasOpen && !isOpen) {
|
|
85
|
+
hoverModeRef.current = false;
|
|
86
|
+
hoverOpenedAtRef.current = 0;
|
|
87
|
+
closedAtRef.current = Date.now();
|
|
88
|
+
}
|
|
89
|
+
}, [isOpen]);
|
|
51
90
|
const clearTimeouts = useCallback(() => {
|
|
52
91
|
if (showTimerRef.current) {
|
|
53
92
|
clearTimeout(showTimerRef.current);
|
|
@@ -58,59 +97,133 @@ export function useMenuHover(options) {
|
|
|
58
97
|
hideTimerRef.current = null;
|
|
59
98
|
}
|
|
60
99
|
}, []);
|
|
100
|
+
|
|
101
|
+
// useListFocus needs an onEscape that is defined in terms of its own listRef;
|
|
102
|
+
// the indirection avoids the use-before-declare.
|
|
103
|
+
const escapeHandlerRef = useRef(() => {});
|
|
61
104
|
const {
|
|
62
105
|
listRef: menuRef,
|
|
63
106
|
handleKeyDown: handleListKeyDown,
|
|
64
107
|
focusFirst
|
|
65
108
|
} = useListFocus({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
hide();
|
|
69
|
-
}
|
|
109
|
+
itemSelector,
|
|
110
|
+
onEscape: () => escapeHandlerRef.current()
|
|
70
111
|
});
|
|
112
|
+
const hideAndRestoreFocus = useCallback(() => {
|
|
113
|
+
// Read before hiding: closing the layer moves focus itself.
|
|
114
|
+
const menuHadFocus = menuRef.current?.contains(document.activeElement) ?? false;
|
|
115
|
+
hide();
|
|
116
|
+
if (menuHadFocus) {
|
|
117
|
+
triggerElRef.current?.focus();
|
|
118
|
+
}
|
|
119
|
+
}, [hide, menuRef]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
escapeHandlerRef.current = () => {
|
|
122
|
+
clearTimeouts();
|
|
123
|
+
hideAndRestoreFocus();
|
|
124
|
+
};
|
|
125
|
+
}, [clearTimeouts, hideAndRestoreFocus]);
|
|
71
126
|
useEffect(() => {
|
|
72
127
|
return () => clearTimeouts();
|
|
73
128
|
}, [clearTimeouts]);
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
129
|
+
const focusMenu = useCallback(() => {
|
|
130
|
+
// An empty or still-loading menu has no focusable item; focus the container
|
|
131
|
+
// so keyboard ownership still transfers off the trigger's list.
|
|
132
|
+
if (!focusFirst()) {
|
|
133
|
+
menuRef.current?.focus();
|
|
134
|
+
}
|
|
135
|
+
}, [focusFirst, menuRef]);
|
|
136
|
+
const openAndFocus = useCallback(() => {
|
|
137
|
+
if (!ownsFocus) {
|
|
83
138
|
show();
|
|
84
|
-
|
|
139
|
+
return;
|
|
85
140
|
}
|
|
86
|
-
|
|
141
|
+
show({
|
|
142
|
+
skipAutoFocus: true
|
|
143
|
+
});
|
|
144
|
+
focusMenu();
|
|
145
|
+
}, [ownsFocus, show, focusMenu]);
|
|
146
|
+
const confirmHoverOpen = useCallback(() => {
|
|
147
|
+
const isConfirming = clickGuardMs > 0 && hoverOpenedAtRef.current > 0 && Date.now() - hoverOpenedAtRef.current < clickGuardMs;
|
|
148
|
+
if (!isConfirming) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
hoverModeRef.current = false;
|
|
152
|
+
hoverOpenedAtRef.current = 0;
|
|
153
|
+
return true;
|
|
154
|
+
}, [clickGuardMs]);
|
|
155
|
+
const handleClick = useCallback(event => {
|
|
156
|
+
// Cancel the invoker's default toggle so this handler stays the single
|
|
157
|
+
// source of truth; popoverTarget still exempts the trigger from dismissal.
|
|
158
|
+
if (popoverId) {
|
|
159
|
+
event?.preventDefault();
|
|
160
|
+
}
|
|
161
|
+
clearTimeouts();
|
|
87
162
|
|
|
88
|
-
|
|
163
|
+
// Enter/Space arrive as a click with detail 0, and always open. A keyboard
|
|
164
|
+
// user reaches the trigger of an open menu only because a hover-open left
|
|
165
|
+
// focus behind; closing there would stranded them outside a visible menu.
|
|
166
|
+
const isKeyboardActivation = event != null && event.detail === 0;
|
|
167
|
+
if (isKeyboardActivation) {
|
|
168
|
+
closedAtRef.current = 0;
|
|
169
|
+
hoverModeRef.current = false;
|
|
170
|
+
hoverOpenedAtRef.current = 0;
|
|
171
|
+
if (isOpen) {
|
|
172
|
+
if (ownsFocus) {
|
|
173
|
+
focusMenu();
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
openAndFocus();
|
|
177
|
+
}
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (!isOpen) {
|
|
181
|
+
closedAtRef.current = 0;
|
|
182
|
+
hoverModeRef.current = false;
|
|
183
|
+
hoverOpenedAtRef.current = 0;
|
|
184
|
+
openAndFocus();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (confirmHoverOpen()) {
|
|
188
|
+
if (ownsFocus) {
|
|
189
|
+
focusMenu();
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
hideAndRestoreFocus();
|
|
194
|
+
}, [popoverId, clearTimeouts, isOpen, ownsFocus, confirmHoverOpen, openAndFocus, focusMenu, hideAndRestoreFocus]);
|
|
89
195
|
const handleMouseEnter = useCallback(() => {
|
|
90
196
|
if (!hasHover) {
|
|
91
197
|
return;
|
|
92
198
|
}
|
|
93
|
-
if (
|
|
94
|
-
|
|
199
|
+
if (closedAtRef.current > 0 && Date.now() - closedAtRef.current < REOPEN_SUPPRESS_MS) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Re-entering an open menu's trigger must not un-pin it or re-arm the
|
|
203
|
+
// guard, which would make the next deliberate click another "confirm" and
|
|
204
|
+
// leave the menu undismissable.
|
|
205
|
+
if (isOpen) {
|
|
206
|
+
clearTimeouts();
|
|
95
207
|
return;
|
|
96
208
|
}
|
|
97
209
|
hoverModeRef.current = true;
|
|
98
210
|
clearTimeouts();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
show({
|
|
102
|
-
skipAutoFocus: true
|
|
103
|
-
});
|
|
104
|
-
}, showDelay);
|
|
105
|
-
} else {
|
|
211
|
+
const openByHover = () => {
|
|
212
|
+
hoverOpenedAtRef.current = Date.now();
|
|
106
213
|
show({
|
|
107
214
|
skipAutoFocus: true
|
|
108
215
|
});
|
|
216
|
+
};
|
|
217
|
+
if (showDelay > 0) {
|
|
218
|
+
showTimerRef.current = setTimeout(openByHover, showDelay);
|
|
219
|
+
} else {
|
|
220
|
+
openByHover();
|
|
109
221
|
}
|
|
110
|
-
}, [hasHover, clearTimeouts, show, showDelay]);
|
|
111
|
-
|
|
112
|
-
// Hover: mouseleave only closes if in hover mode
|
|
222
|
+
}, [hasHover, isOpen, clearTimeouts, show, showDelay]);
|
|
113
223
|
const handleMouseLeave = useCallback(() => {
|
|
224
|
+
// A real leave ends the stationary-pointer case the suppression window
|
|
225
|
+
// exists for, so the next enter is deliberate whenever it arrives.
|
|
226
|
+
closedAtRef.current = 0;
|
|
114
227
|
if (!hoverModeRef.current) {
|
|
115
228
|
return;
|
|
116
229
|
}
|
|
@@ -119,8 +232,6 @@ export function useMenuHover(options) {
|
|
|
119
232
|
hide();
|
|
120
233
|
}, hideDelay);
|
|
121
234
|
}, [clearTimeouts, hide, hideDelay]);
|
|
122
|
-
|
|
123
|
-
// Content: mouseenter cancels pending hide
|
|
124
235
|
const handleContentMouseEnter = useCallback(() => {
|
|
125
236
|
clearTimeouts();
|
|
126
237
|
}, [clearTimeouts]);
|
|
@@ -144,6 +255,9 @@ export function useMenuHover(options) {
|
|
|
144
255
|
},
|
|
145
256
|
menuRef,
|
|
146
257
|
focusFirst,
|
|
258
|
+
focusMenu,
|
|
259
|
+
confirmHoverOpen,
|
|
260
|
+
close: hideAndRestoreFocus,
|
|
147
261
|
setTriggerEl: noopRef
|
|
148
262
|
};
|
|
149
263
|
}
|
|
@@ -151,7 +265,10 @@ export function useMenuHover(options) {
|
|
|
151
265
|
triggerProps: {
|
|
152
266
|
onClick: handleClick,
|
|
153
267
|
onMouseEnter: handleMouseEnter,
|
|
154
|
-
onMouseLeave: handleMouseLeave
|
|
268
|
+
onMouseLeave: handleMouseLeave,
|
|
269
|
+
...(popoverId ? {
|
|
270
|
+
popoverTarget: popoverId
|
|
271
|
+
} : null)
|
|
155
272
|
},
|
|
156
273
|
contentProps: {
|
|
157
274
|
onMouseEnter: handleContentMouseEnter,
|
|
@@ -160,6 +277,9 @@ export function useMenuHover(options) {
|
|
|
160
277
|
},
|
|
161
278
|
menuRef,
|
|
162
279
|
focusFirst,
|
|
280
|
+
focusMenu,
|
|
281
|
+
confirmHoverOpen,
|
|
282
|
+
close: hideAndRestoreFocus,
|
|
163
283
|
setTriggerEl: setTriggerRef
|
|
164
284
|
};
|
|
165
285
|
}
|
|
@@ -26,19 +26,25 @@
|
|
|
26
26
|
* <App />
|
|
27
27
|
* </Theme>
|
|
28
28
|
* ```
|
|
29
|
+
*
|
|
30
|
+
* SYNC: `DefineThemeInput` is the theme surface. Adding, removing, or renaming
|
|
31
|
+
* a field means updating:
|
|
32
|
+
* - /packages/cli/assets/theme.template.ts (documents every field; the
|
|
33
|
+
* drift guard is scripts/check-theme-template.test.mjs)
|
|
34
|
+
* - /packages/cli/assets/docs/theme.doc.mjs (`astryx docs theme`)
|
|
29
35
|
*/
|
|
30
36
|
import type { IconRegistry } from '../Icon/globalIconRegistry';
|
|
31
37
|
import type { IndicatorRegistry } from '../Indicator/types';
|
|
32
38
|
import type { TypographyConfig } from './types';
|
|
33
39
|
import { type OnMediaOverrides, type ResolvedOnMedia } from './onMediaTokens';
|
|
34
|
-
import { colorDefaults, spacingDefaults, sizeDefaults, focusDefaults, radiusDefaults, shadowDefaults, durationDefaults, easeDefaults, typographyDefaults, textSizeDefaults, fontWeightDefaults, typeScaleDefaults } from './tokens.stylex';
|
|
40
|
+
import { colorDefaults, spacingDefaults, sizeDefaults, borderDefaults, focusDefaults, radiusDefaults, shadowDefaults, durationDefaults, easeDefaults, typographyDefaults, textSizeDefaults, fontWeightDefaults, typeScaleDefaults } from './tokens.stylex';
|
|
35
41
|
import { type MotionScaleConfig } from './expandMotionScale';
|
|
36
42
|
import { type RadiusScaleConfig } from './expandRadiusScale';
|
|
37
43
|
import { type ColorScaleConfig } from './expandColorScale';
|
|
38
44
|
import type { DomainTokenName } from './domainTokens';
|
|
39
45
|
import type { SyntaxThemeDefinition } from './syntax';
|
|
40
46
|
/** All valid Astryx core token names */
|
|
41
|
-
export type CoreTokenName = keyof typeof colorDefaults | keyof typeof spacingDefaults | keyof typeof sizeDefaults | keyof typeof focusDefaults | keyof typeof radiusDefaults | keyof typeof shadowDefaults | keyof typeof durationDefaults | keyof typeof easeDefaults | keyof typeof typographyDefaults | keyof typeof textSizeDefaults | keyof typeof fontWeightDefaults | keyof typeof typeScaleDefaults;
|
|
47
|
+
export type CoreTokenName = keyof typeof colorDefaults | keyof typeof spacingDefaults | keyof typeof sizeDefaults | keyof typeof borderDefaults | keyof typeof focusDefaults | keyof typeof radiusDefaults | keyof typeof shadowDefaults | keyof typeof durationDefaults | keyof typeof easeDefaults | keyof typeof typographyDefaults | keyof typeof textSizeDefaults | keyof typeof fontWeightDefaults | keyof typeof typeScaleDefaults;
|
|
42
48
|
/** All valid Astryx token names — core + domain tokens */
|
|
43
49
|
export type TokenName = CoreTokenName | DomainTokenName;
|
|
44
50
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineTheme.d.ts","sourceRoot":"","sources":["../../src/theme/defineTheme.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"defineTheme.d.ts","sourceRoot":"","sources":["../../src/theme/defineTheme.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,10 +28,16 @@
|
|
|
28
28
|
* <App />
|
|
29
29
|
* </Theme>
|
|
30
30
|
* ```
|
|
31
|
+
*
|
|
32
|
+
* SYNC: `DefineThemeInput` is the theme surface. Adding, removing, or renaming
|
|
33
|
+
* a field means updating:
|
|
34
|
+
* - /packages/cli/assets/theme.template.ts (documents every field; the
|
|
35
|
+
* drift guard is scripts/check-theme-template.test.mjs)
|
|
36
|
+
* - /packages/cli/assets/docs/theme.doc.mjs (`astryx docs theme`)
|
|
31
37
|
*/
|
|
32
38
|
|
|
33
39
|
import { resolveOnMedia } from "./onMediaTokens.js";
|
|
34
|
-
import { colorDefaults, spacingDefaults, sizeDefaults, focusDefaults, radiusDefaults, shadowDefaults, durationDefaults, easeDefaults, typographyDefaults, textSizeDefaults, fontWeightDefaults, typeScaleDefaults } from "./tokens.stylex.js";
|
|
40
|
+
import { colorDefaults, spacingDefaults, sizeDefaults, borderDefaults, focusDefaults, radiusDefaults, shadowDefaults, durationDefaults, easeDefaults, typographyDefaults, textSizeDefaults, fontWeightDefaults, typeScaleDefaults } from "./tokens.stylex.js";
|
|
35
41
|
import { expandTypeScale, generateTypeScaleComponents } from "./expandTypeScale.js";
|
|
36
42
|
import { expandMotionScale } from "./expandMotionScale.js";
|
|
37
43
|
import { expandRadiusScale } from "./expandRadiusScale.js";
|
|
@@ -120,6 +126,7 @@ export const tokenDefaults = {
|
|
|
120
126
|
...colorDefaults,
|
|
121
127
|
...spacingDefaults,
|
|
122
128
|
...sizeDefaults,
|
|
129
|
+
...borderDefaults,
|
|
123
130
|
...focusDefaults,
|
|
124
131
|
...radiusDefaults,
|
|
125
132
|
...shadowDefaults,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derivedVarRegistry.d.ts","sourceRoot":"","sources":["../../src/theme/derivedVarRegistry.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"derivedVarRegistry.d.ts","sourceRoot":"","sources":["../../src/theme/derivedVarRegistry.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,eAAe;IAC9B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CA0ChE,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,eAAe,EAAE,CAMnB"}
|
|
@@ -55,6 +55,13 @@ export const derivedVarRegistry = {
|
|
|
55
55
|
property: 'padding',
|
|
56
56
|
expand: 'container'
|
|
57
57
|
}],
|
|
58
|
+
'context-menu': [{
|
|
59
|
+
property: 'borderRadius',
|
|
60
|
+
vars: ['--_dropdown-menu-radius']
|
|
61
|
+
}, {
|
|
62
|
+
property: 'padding',
|
|
63
|
+
vars: ['--_dropdown-menu-padding']
|
|
64
|
+
}],
|
|
58
65
|
'dropdown-menu': [{
|
|
59
66
|
property: 'borderRadius',
|
|
60
67
|
vars: ['--_dropdown-menu-radius']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expandColorScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandColorScale.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"expandColorScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandColorScale.ts"],"names":[],"mappings":"AAwCA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAE3C;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAyCtD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,EACZ,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,GACf,MAAM,CAYR;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAoI3E"}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* SYNC: When modified, update:
|
|
17
17
|
* - /packages/core/src/theme/expandMotionScale.test.ts
|
|
18
18
|
* - /packages/core/src/theme/defineTheme.ts
|
|
19
|
+
* - /packages/cli/assets/theme.template.ts (the annotated field reference)
|
|
19
20
|
*/
|
|
20
21
|
/**
|
|
21
22
|
* Motion scale configuration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expandMotionScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandMotionScale.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"expandMotionScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandMotionScale.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAavD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CA0BnB"}
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* SYNC: When modified, update:
|
|
19
19
|
* - /packages/core/src/theme/expandMotionScale.test.ts
|
|
20
20
|
* - /packages/core/src/theme/defineTheme.ts
|
|
21
|
+
* - /packages/cli/assets/theme.template.ts (the annotated field reference)
|
|
21
22
|
*/
|
|
22
23
|
|
|
23
24
|
// =============================================================================
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* SYNC: When modified, update:
|
|
21
21
|
* - /packages/core/src/theme/expandRadiusScale.test.ts
|
|
22
22
|
* - /packages/core/src/theme/defineTheme.ts
|
|
23
|
+
* - /packages/cli/assets/theme.template.ts (the annotated field reference)
|
|
23
24
|
*/
|
|
24
25
|
/**
|
|
25
26
|
* Radius scale configuration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expandRadiusScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandRadiusScale.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"expandRadiusScale.d.ts","sourceRoot":"","sources":["../../src/theme/expandRadiusScale.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,yFAAyF;IACzF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAMvD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CAanB"}
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
* SYNC: When modified, update:
|
|
23
23
|
* - /packages/core/src/theme/expandRadiusScale.test.ts
|
|
24
24
|
* - /packages/core/src/theme/defineTheme.ts
|
|
25
|
+
* - /packages/cli/assets/theme.template.ts (the annotated field reference)
|
|
25
26
|
*/
|
|
26
27
|
|
|
27
28
|
// =============================================================================
|