@astryxdesign/core 0.4.1 → 0.4.2-canary.356d2f9
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 +40 -8
- package/dist/astryx.umd.js +50 -50
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/containerReveal.stylex.d.ts +71 -4
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
- package/dist/hooks/containerReveal.stylex.js +57 -5
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useContainerReveal.d.ts +60 -3
- package/dist/hooks/useContainerReveal.d.ts.map +1 -1
- package/dist/hooks/useContainerReveal.js +27 -5
- 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 +16 -5
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +44 -48
- 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/mergeComponents.d.ts +20 -0
- package/dist/theme/mergeComponents.d.ts.map +1 -0
- package/dist/theme/mergeComponents.js +56 -0
- package/dist/theme/onMediaTokens.d.ts +6 -1
- package/dist/theme/onMediaTokens.d.ts.map +1 -1
- package/dist/theme/onMediaTokens.js +11 -3
- 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/containerReveal.stylex.ts +140 -9
- package/src/hooks/index.ts +6 -1
- package/src/hooks/useContainerReveal.doc.mjs +11 -5
- package/src/hooks/useContainerReveal.test.tsx +70 -3
- package/src/hooks/useContainerReveal.ts +86 -7
- 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.test.ts +127 -0
- package/src/theme/defineTheme.ts +57 -51
- 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/mergeComponents.ts +59 -0
- package/src/theme/onMediaTokens.ts +9 -2
- 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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/HoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG7E,OAAO,EAAe,KAAK,qBAAqB,EAAC,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,YAAY,EAAC,qBAAqB,EAAC,MAAM,gBAAgB,CAAC;AAiB1D,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,SAAS,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAiBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,OAAO,EACP,SAAmB,EACnB,SAAoB,EACpB,KAAW,EACX,SAAe,EACf,YAAqB,EACrB,SAAgB,EAChB,KAAK,EACL,YAAY,EACZ,kBAA2B,EAC3B,MAAM,EACN,aAAa,EACb,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,cAAc,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"HoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/HoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAsB,KAAK,YAAY,EAAE,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAG7E,OAAO,EAAe,KAAK,qBAAqB,EAAC,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAAC,cAAc,EAAE,cAAc,EAAC,MAAM,mBAAmB,CAAC;AACtE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAG5C,YAAY,EAAC,qBAAqB,EAAC,MAAM,gBAAgB,CAAC;AAiB1D,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,SAAS,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;;;;;OAOG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAEtC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAiBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,EACxB,QAAQ,EACR,OAAO,EACP,SAAmB,EACnB,SAAoB,EACpB,KAAW,EACX,SAAe,EACf,YAAqB,EACrB,SAAgB,EAChB,KAAK,EACL,YAAY,EACZ,kBAA2B,EAC3B,MAAM,EACN,aAAa,EACb,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,cAAc,GAAG,YAAY,CAyG/B;yBA1He,SAAS"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @file HoverCard.tsx
|
|
7
7
|
* @input Uses React, useHoverCard hook
|
|
8
8
|
* @output Exports HoverCard component for hover/focus triggered layers
|
|
9
|
-
* @position Layer component;
|
|
9
|
+
* @position Layer component; inline-safe trigger wrapper, floating layer hosted by useLayer
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update these files to stay in sync:
|
|
12
12
|
* - /packages/core/src/HoverCard/HoverCard.test.tsx
|
|
@@ -127,18 +127,10 @@ export function HoverCard({
|
|
|
127
127
|
};
|
|
128
128
|
}, [textOnly, hoverCard.ref, hoverCard.describedBy]);
|
|
129
129
|
|
|
130
|
-
//
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
// anchor positioning resolves the trigger reference regardless of where the
|
|
135
|
-
// element sits in the DOM, so no portal is needed to "escape" layout.
|
|
136
|
-
//
|
|
137
|
-
// The layer renders as inline-safe phrasing markup (a `<span>`, see
|
|
138
|
-
// useHoverCard), which stays put inside a `<p>` instead of being reparented
|
|
139
|
-
// by the HTML parser. That keeps the server markup and the first client
|
|
140
|
-
// render identical, so there is no hydration mismatch — and it preserves the
|
|
141
|
-
// inline-safety guarantee (no block elements injected into a paragraph).
|
|
130
|
+
// While closed, useLayer leaves only an inert <template> marker at this JSX
|
|
131
|
+
// position. When the card needs to open, it uses that marker to keep the
|
|
132
|
+
// final layer inline when the parent is safe or portal it outside a <p>,
|
|
133
|
+
// link, or other ancestor that cannot contain it safely.
|
|
142
134
|
const renderedHoverCard = hoverCard.renderHoverCard(content, {
|
|
143
135
|
xstyle,
|
|
144
136
|
className,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useHoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/useHoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"useHoverCard.d.ts","sourceRoot":"","sources":["../../src/HoverCard/useHoverCard.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAIL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AA4B3B;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,qBAAqB,CAAC;IAErC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEtC;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;IACH,eAAe,EAAE,CACf,QAAQ,EAAE,SAAS,EACnB,KAAK,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,KAC5C,SAAS,CAAC;IAEf;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;IAEjB;;OAEG;IACH,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB;AAyBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAkT5E"}
|
|
@@ -88,6 +88,7 @@ export function useHoverCard(options = {}) {
|
|
|
88
88
|
} = options;
|
|
89
89
|
const layer = useLayer({
|
|
90
90
|
mode: 'context',
|
|
91
|
+
lazyMount: true,
|
|
91
92
|
onShow,
|
|
92
93
|
onHide
|
|
93
94
|
});
|
|
@@ -254,15 +255,15 @@ export function useHoverCard(options = {}) {
|
|
|
254
255
|
// Consumer surface style props land on the layer container — the
|
|
255
256
|
// themed surface (bg/radius/shadow) where the theme class lives — so
|
|
256
257
|
// customizing the card targets the same element as the theme. The inner
|
|
257
|
-
//
|
|
258
|
+
// div keeps `styles.content` for padding.
|
|
258
259
|
xstyle: [popoverXstyle, layerAnimations[renderPlacement], props?.xstyle],
|
|
259
260
|
className: props?.className ? `${themeClassName} ${props.className}` : themeClassName,
|
|
260
261
|
style: props?.style,
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
as: '
|
|
262
|
+
// useLayer mounts only after it has verified or corrected the parent,
|
|
263
|
+
// so rich HoverCard content can use block-safe markup.
|
|
264
|
+
as: 'div'
|
|
264
265
|
};
|
|
265
|
-
return layer.render(/*#__PURE__*/_jsx("
|
|
266
|
+
return layer.render(/*#__PURE__*/_jsx("div", {
|
|
266
267
|
...{
|
|
267
268
|
className: "x1lliihq x1vlblms xvmdzux x126nfab x1t818jl"
|
|
268
269
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"groupStyles.d.ts","sourceRoot":"","sources":["../../src/InputGroup/groupStyles.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"groupStyles.d.ts","sourceRoot":"","sources":["../../src/InputGroup/groupStyles.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAQ3C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;EA6BtB,CAAC"}
|
|
@@ -10,6 +10,11 @@
|
|
|
10
10
|
import * as stylex from '@stylexjs/stylex';
|
|
11
11
|
import "../theme/tokens.stylex.js";
|
|
12
12
|
import { radiusVars, borderVars } from "../theme/tokens.stylex.js";
|
|
13
|
+
|
|
14
|
+
// A grouped control may be followed by context-layer infrastructure rather
|
|
15
|
+
// than another control. Neither the inert marker nor the popover is a visual
|
|
16
|
+
// group member, so skip both when finding the trailing edge.
|
|
17
|
+
const IS_LAST_ITEM = ':not(:has(~ *:not([popover]):not(template)))';
|
|
13
18
|
export const groupStyles = {
|
|
14
19
|
inGroup: {
|
|
15
20
|
kUk6DE: "x98rzlu",
|
|
@@ -18,8 +23,8 @@ export const groupStyles = {
|
|
|
18
23
|
keTefX: "xd10s4z x1pwwqoy",
|
|
19
24
|
krdFHd: "x15mokao x8eehn2",
|
|
20
25
|
kVL7Gh: "xbiv7yw x1xrp5p4",
|
|
21
|
-
kfmiAY: "x1ga7v0g
|
|
22
|
-
kT0f0o: "x16uus16
|
|
26
|
+
kfmiAY: "x1ga7v0g x1tzxhge",
|
|
27
|
+
kT0f0o: "x16uus16 x1rmb4wm",
|
|
23
28
|
kXnDq0: "x1rm9qnc",
|
|
24
29
|
$$css: true
|
|
25
30
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return the corrective portal target for a layer's intended inline parent.
|
|
3
|
+
*
|
|
4
|
+
* A null result means the inline parent and all of its ancestors are safe, so
|
|
5
|
+
* the layer should stay at its JSX position. Otherwise the result is the
|
|
6
|
+
* nearest element outside every unsafe ancestor around that position.
|
|
7
|
+
*
|
|
8
|
+
* Walking up from the actual render position (rather than the trigger, or
|
|
9
|
+
* portaling to `document.body`) keeps the two things a layer inherits there:
|
|
10
|
+
*
|
|
11
|
+
* - **Theme.** Theme scopes live on DOM ancestors. Staying as close as
|
|
12
|
+
* possible to the intended render position preserves their component rules
|
|
13
|
+
* and custom properties; `document.body` may sit outside a nested scope.
|
|
14
|
+
* - **Tab order.** Sequential focus follows DOM order, so a host near the
|
|
15
|
+
* trigger keeps the layer's focusables next to it. (`show()` also passes
|
|
16
|
+
* the trigger as the popover's invoker `source`, which pins focus order to
|
|
17
|
+
* the invoker in browsers that support it.)
|
|
18
|
+
*
|
|
19
|
+
* The outermost unsafe ancestor matters. A safe div may itself sit inside an
|
|
20
|
+
* anchor; stopping at that div would still put the layer's buttons inside the
|
|
21
|
+
* link. Walking the whole chain ensures the target is outside both.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveLayerPortalTarget(inlineParent: HTMLElement | null): HTMLElement | null;
|
|
24
|
+
//# sourceMappingURL=layerHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layerHost.d.ts","sourceRoot":"","sources":["../../src/Layer/layerHost.ts"],"names":[],"mappings":"AAqGA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,WAAW,GAAG,IAAI,GAC/B,WAAW,GAAG,IAAI,CAepB"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file layerHost.ts
|
|
5
|
+
* @input Uses the layer's intended inline parent element
|
|
6
|
+
* @output Exports resolveLayerPortalTarget, the corrective portal target
|
|
7
|
+
* @position Layer utility; used by useLayer to place the popover in the DOM
|
|
8
|
+
*
|
|
9
|
+
* SYNC: When modified, update:
|
|
10
|
+
* - /packages/core/src/Layer/layerHost.test.ts
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Ancestors a layer must not be hosted inside.
|
|
15
|
+
*
|
|
16
|
+
* Two overlapping reasons, both verified in Chrome:
|
|
17
|
+
*
|
|
18
|
+
* 1. The HTML parser owns server markup. `<p>` and the heading-ish elements
|
|
19
|
+
* take phrasing content only, so a block element inside one makes the
|
|
20
|
+
* parser close the paragraph and reparent the rest — the layer's content
|
|
21
|
+
* ends up in the page instead of the popover. A nested `<a>` triggers the
|
|
22
|
+
* same tearing through the adoption agency algorithm.
|
|
23
|
+
* 2. Interactive ancestors capture the layer's own interactions. A card
|
|
24
|
+
* hosted inside an `<a>` or `<button>` puts its links and buttons inside
|
|
25
|
+
* that control: clicking one navigates the wrapping link, and every
|
|
26
|
+
* focusable in the card joins the control's own tab stop.
|
|
27
|
+
*
|
|
28
|
+
* Inline formatting elements are on the list for a third, milder reason: a
|
|
29
|
+
* layer hosted in one inherits its typography (font-size, text-align), so a
|
|
30
|
+
* card in a 13px centered paragraph renders 13px and centered.
|
|
31
|
+
*/
|
|
32
|
+
const UNSAFE_HOSTS = new Set([
|
|
33
|
+
// Phrasing-content-only containers
|
|
34
|
+
'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'dt', 'pre', 'legend', 'data', 'dfn', 'meter', 'output', 'progress', 'option', 'optgroup',
|
|
35
|
+
// Structural containers whose direct children are restricted. An inert
|
|
36
|
+
// <template> marker is valid script-supporting content in these positions,
|
|
37
|
+
// but the eventual div/span layer is not.
|
|
38
|
+
'table', 'thead', 'tbody', 'tfoot', 'tr', 'colgroup', 'ul', 'ol', 'menu', 'dl', 'select', 'datalist', 'picture', 'hgroup', 'ruby', 'rt', 'rp',
|
|
39
|
+
// Interactive containers
|
|
40
|
+
'a', 'button', 'label', 'summary',
|
|
41
|
+
// Inline formatting context
|
|
42
|
+
'span', 'em', 'strong', 'b', 'i', 'u', 's', 'small', 'mark', 'code', 'kbd', 'samp', 'var', 'sub', 'sup', 'abbr', 'cite', 'q', 'time', 'bdi', 'bdo', 'ins', 'del']);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Return the corrective portal target for a layer's intended inline parent.
|
|
46
|
+
*
|
|
47
|
+
* A null result means the inline parent and all of its ancestors are safe, so
|
|
48
|
+
* the layer should stay at its JSX position. Otherwise the result is the
|
|
49
|
+
* nearest element outside every unsafe ancestor around that position.
|
|
50
|
+
*
|
|
51
|
+
* Walking up from the actual render position (rather than the trigger, or
|
|
52
|
+
* portaling to `document.body`) keeps the two things a layer inherits there:
|
|
53
|
+
*
|
|
54
|
+
* - **Theme.** Theme scopes live on DOM ancestors. Staying as close as
|
|
55
|
+
* possible to the intended render position preserves their component rules
|
|
56
|
+
* and custom properties; `document.body` may sit outside a nested scope.
|
|
57
|
+
* - **Tab order.** Sequential focus follows DOM order, so a host near the
|
|
58
|
+
* trigger keeps the layer's focusables next to it. (`show()` also passes
|
|
59
|
+
* the trigger as the popover's invoker `source`, which pins focus order to
|
|
60
|
+
* the invoker in browsers that support it.)
|
|
61
|
+
*
|
|
62
|
+
* The outermost unsafe ancestor matters. A safe div may itself sit inside an
|
|
63
|
+
* anchor; stopping at that div would still put the layer's buttons inside the
|
|
64
|
+
* link. Walking the whole chain ensures the target is outside both.
|
|
65
|
+
*/
|
|
66
|
+
export function resolveLayerPortalTarget(inlineParent) {
|
|
67
|
+
if (!inlineParent) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
let outermostUnsafe = null;
|
|
71
|
+
let node = inlineParent;
|
|
72
|
+
while (node) {
|
|
73
|
+
if (UNSAFE_HOSTS.has(node.tagName.toLowerCase())) {
|
|
74
|
+
outermostUnsafe = node;
|
|
75
|
+
}
|
|
76
|
+
node = node.parentElement;
|
|
77
|
+
}
|
|
78
|
+
return outermostUnsafe?.parentElement ?? null;
|
|
79
|
+
}
|
package/dist/Layer/useLayer.d.ts
CHANGED
|
@@ -94,12 +94,11 @@ export interface ContextRenderProps {
|
|
|
94
94
|
/**
|
|
95
95
|
* HTML tag to render the popover container as.
|
|
96
96
|
*
|
|
97
|
-
* Defaults to `'div'`.
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* the same on either tag.
|
|
97
|
+
* Defaults to `'div'`. Context layers render an inert `<template>` marker at
|
|
98
|
+
* the JSX position. The marker's parent is checked before the requested
|
|
99
|
+
* container mounts there or portals outside ancestors that cannot safely
|
|
100
|
+
* contain it. The marker remains available to detect a new parent if the
|
|
101
|
+
* render call moves. With `lazyMount`, the first check waits until `show()`.
|
|
103
102
|
*
|
|
104
103
|
* @default 'div'
|
|
105
104
|
*/
|
|
@@ -162,6 +161,15 @@ interface BaseLayerOptions {
|
|
|
162
161
|
*/
|
|
163
162
|
export interface ContextLayerOptions extends BaseLayerOptions {
|
|
164
163
|
mode: 'context';
|
|
164
|
+
/**
|
|
165
|
+
* Defer mounting the final layer and resolving its inline/portal position
|
|
166
|
+
* until `show()` is requested. Hiding unmounts it while the inert marker
|
|
167
|
+
* remains at the JSX position. Use this when rich content must never enter
|
|
168
|
+
* an unsafe ancestor, even briefly, and does not need to exist while closed.
|
|
169
|
+
*
|
|
170
|
+
* @default false
|
|
171
|
+
*/
|
|
172
|
+
lazyMount?: boolean;
|
|
165
173
|
}
|
|
166
174
|
/**
|
|
167
175
|
* Options for fixed mode (manual positioning)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLayer.d.ts","sourceRoot":"","sources":["../../src/Layer/useLayer.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,EAMZ,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"useLayer.d.ts","sourceRoot":"","sources":["../../src/Layer/useLayer.tsx"],"names":[],"mappings":"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"}
|
package/dist/Layer/useLayer.js
CHANGED
|
@@ -15,10 +15,12 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import React, { useCallback, useEffect, useId, useRef, useState } from 'react';
|
|
17
17
|
import * as stylex from '@stylexjs/stylex';
|
|
18
|
+
import { createPortal } from 'react-dom';
|
|
18
19
|
import { addAnchorName, removeAnchorName } from "./anchorName.js";
|
|
20
|
+
import { resolveLayerPortalTarget } from "./layerHost.js";
|
|
19
21
|
import "../theme/tokens.stylex.js";
|
|
20
|
-
import { typographyVars } from "../theme/tokens.stylex.js";
|
|
21
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
22
|
+
import { typeScaleVars, typographyVars } from "../theme/tokens.stylex.js";
|
|
23
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
24
|
const _temp = {
|
|
23
25
|
keoZOQ: "x1vhfslr",
|
|
24
26
|
k1K539: "xlm3tn6",
|
|
@@ -38,6 +40,8 @@ const styles = {
|
|
|
38
40
|
ksu8eU: "xng3xce",
|
|
39
41
|
kVQacm: "x1rea2x4",
|
|
40
42
|
kMv6JI: "x9ynric",
|
|
43
|
+
kGuDYH: "xjm74w1",
|
|
44
|
+
kLWn49: "xw6l6zx",
|
|
41
45
|
kWkggS: "xjbqb8w",
|
|
42
46
|
$$css: true
|
|
43
47
|
},
|
|
@@ -100,17 +104,40 @@ const styles = {
|
|
|
100
104
|
function toCssLength(value) {
|
|
101
105
|
return typeof value === 'number' ? `${value}px` : value;
|
|
102
106
|
}
|
|
107
|
+
function readPortalWritingContext(element, portalTarget) {
|
|
108
|
+
const view = element.ownerDocument.defaultView;
|
|
109
|
+
if (!view) {
|
|
110
|
+
return {};
|
|
111
|
+
}
|
|
112
|
+
const sourceStyle = view.getComputedStyle(element);
|
|
113
|
+
const targetStyle = view.getComputedStyle(portalTarget);
|
|
114
|
+
|
|
115
|
+
// Do not snapshot custom properties here. The portal target is the closest
|
|
116
|
+
// safe ancestor, so theme variables continue to inherit and update there.
|
|
117
|
+
// These two properties can be set on the unsafe chain itself and directly
|
|
118
|
+
// affect the logical anchor-positioning keywords used by the layer. Only
|
|
119
|
+
// override values the portal would actually lose; matching values should
|
|
120
|
+
// keep inheriting from the target so later direction changes remain live.
|
|
121
|
+
return {
|
|
122
|
+
...(sourceStyle.direction !== targetStyle.direction && {
|
|
123
|
+
direction: sourceStyle.direction
|
|
124
|
+
}),
|
|
125
|
+
...(sourceStyle.writingMode !== targetStyle.writingMode && {
|
|
126
|
+
writingMode: sourceStyle.writingMode
|
|
127
|
+
})
|
|
128
|
+
};
|
|
129
|
+
}
|
|
103
130
|
|
|
104
131
|
/**
|
|
105
132
|
* Map logical placement/alignment to a CSS position-area value.
|
|
106
133
|
*
|
|
107
134
|
* Uses the self-* logical keyword family: the inline axis resolves against
|
|
108
|
-
* the popover's own
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
135
|
+
* the popover's own direction (inherited inline or preserved when portaled),
|
|
136
|
+
* so it mirrors in RTL without placement-specific JS. The block axis is
|
|
137
|
+
* direction-neutral but must come from the same keyword family — mixing
|
|
138
|
+
* physical `top` with `self-inline-*` produces an invalid position-area
|
|
139
|
+
* (computes to `none`, which pins the popover to the viewport corner because
|
|
140
|
+
* styles.base zeroes the UA margins).
|
|
114
141
|
*
|
|
115
142
|
* Note the plain logical family (`inline-start`, no `self-`) is NOT a
|
|
116
143
|
* substitute: it resolves against the containing block — the page root for
|
|
@@ -182,36 +209,101 @@ export function useLayer(options) {
|
|
|
182
209
|
onHide,
|
|
183
210
|
lightDismiss = false
|
|
184
211
|
} = options;
|
|
212
|
+
const lazyMount = mode === 'context' ? options.lazyMount ?? false : false;
|
|
185
213
|
const id = useId();
|
|
186
214
|
const anchorId = `--astryx-layer-${id.replace(/:/g, '')}`;
|
|
187
215
|
const [isOpen, setIsOpen] = useState(false);
|
|
188
216
|
const popoverRef = useRef(null);
|
|
217
|
+
// The DOM element on which the current logical open state was applied.
|
|
218
|
+
// A portal target change replaces the popover element; retaining the old
|
|
219
|
+
// reference lets the ref callback recognize and reopen its replacement.
|
|
220
|
+
const openedPopoverRef = useRef(null);
|
|
189
221
|
const triggerRef = useRef(null);
|
|
222
|
+
// Context layers place a persistent inert marker at their real JSX position.
|
|
223
|
+
// Its parent tells us whether the final layer can stay inline or needs a
|
|
224
|
+
// corrective portal, including after the render call moves.
|
|
225
|
+
const sentinelRef = useRef(null);
|
|
226
|
+
const contextMountRef = useRef(null);
|
|
227
|
+
const [contextMount, setContextMount] = useState(null);
|
|
228
|
+
// A show() that arrives before the final layer mounts is replayed when its
|
|
229
|
+
// popover ref attaches.
|
|
230
|
+
const pendingShowRef = useRef(false);
|
|
190
231
|
|
|
191
232
|
// Ref mirrors isOpen for synchronous reads inside show/hide.
|
|
192
233
|
// State drives re-renders; the ref lets the imperative calls avoid
|
|
193
234
|
// stale-closure reads of the previous isOpen value.
|
|
194
235
|
const isOpenRef = useRef(false);
|
|
236
|
+
const showPopoverElement = useCallback(popover => {
|
|
237
|
+
// Finding infra-4: the Popover API is unsupported on Safari <17 and
|
|
238
|
+
// Firefox <125. On those browsers `showPopover` does not exist, so fall
|
|
239
|
+
// back to plain visibility instead of throwing.
|
|
240
|
+
if (typeof popover.showPopover === 'function') {
|
|
241
|
+
// The trigger is passed as the popover's invoker `source`: a layer
|
|
242
|
+
// hosted away from its trigger then still takes its sequential focus
|
|
243
|
+
// order (and its popover nesting) from the trigger rather than from its
|
|
244
|
+
// own DOM position. Browsers without the option ignore it.
|
|
245
|
+
popover.showPopover({
|
|
246
|
+
source: triggerRef.current ?? undefined
|
|
247
|
+
});
|
|
248
|
+
} else {
|
|
249
|
+
popover.style.display = 'block';
|
|
250
|
+
}
|
|
251
|
+
openedPopoverRef.current = popover;
|
|
252
|
+
}, []);
|
|
253
|
+
const isCurrentContextPopover = useCallback(popover => {
|
|
254
|
+
if (mode !== 'context') {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
const mount = contextMountRef.current;
|
|
258
|
+
if (mount === null) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
const expectedParent = mount.portalTarget ?? sentinelRef.current?.parentElement ?? null;
|
|
262
|
+
return popover.parentElement === expectedParent;
|
|
263
|
+
}, [mode]);
|
|
264
|
+
const requestContextMount = useCallback(() => {
|
|
265
|
+
if (mode !== 'context') {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const sentinel = sentinelRef.current;
|
|
269
|
+
const inlineParent = sentinel?.parentElement ?? null;
|
|
270
|
+
if (!sentinel || !inlineParent) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
const portalTarget = resolveLayerPortalTarget(inlineParent);
|
|
274
|
+
const mount = {
|
|
275
|
+
portalTarget,
|
|
276
|
+
portalStyle: portalTarget ? readPortalWritingContext(sentinel, portalTarget) : {}
|
|
277
|
+
};
|
|
278
|
+
contextMountRef.current = mount;
|
|
279
|
+
setContextMount(mount);
|
|
280
|
+
}, [mode]);
|
|
281
|
+
const clearContextMount = useCallback(() => {
|
|
282
|
+
if (mode !== 'context' || !lazyMount) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
contextMountRef.current = null;
|
|
286
|
+
setContextMount(null);
|
|
287
|
+
}, [mode, lazyMount]);
|
|
195
288
|
const show = useCallback(() => {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
popover.style.display = 'block';
|
|
208
|
-
}
|
|
289
|
+
// A context popover left over until React commits a previous hide must not
|
|
290
|
+
// be reopened. The synchronous mount ref is the source of truth.
|
|
291
|
+
const candidate = popoverRef.current;
|
|
292
|
+
const popover = candidate && isCurrentContextPopover(candidate) ? candidate : null;
|
|
293
|
+
if (!popover) {
|
|
294
|
+
pendingShowRef.current = true;
|
|
295
|
+
requestContextMount();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (!isOpenRef.current) {
|
|
299
|
+
showPopoverElement(popover);
|
|
209
300
|
isOpenRef.current = true;
|
|
210
301
|
setIsOpen(true);
|
|
211
302
|
onShow?.();
|
|
212
303
|
}
|
|
213
|
-
}, [onShow]);
|
|
304
|
+
}, [onShow, requestContextMount, showPopoverElement, isCurrentContextPopover]);
|
|
214
305
|
const hide = useCallback(() => {
|
|
306
|
+
pendingShowRef.current = false;
|
|
215
307
|
if (isOpenRef.current) {
|
|
216
308
|
const el = popoverRef.current;
|
|
217
309
|
// See finding infra-4 note in `show`: mirror the same guard on hide so
|
|
@@ -223,11 +315,13 @@ export function useLayer(options) {
|
|
|
223
315
|
el.style.display = 'none';
|
|
224
316
|
}
|
|
225
317
|
}
|
|
318
|
+
openedPopoverRef.current = null;
|
|
226
319
|
isOpenRef.current = false;
|
|
227
320
|
setIsOpen(false);
|
|
228
321
|
onHide?.();
|
|
229
322
|
}
|
|
230
|
-
|
|
323
|
+
clearContextMount();
|
|
324
|
+
}, [onHide, clearContextMount]);
|
|
231
325
|
|
|
232
326
|
// Ref for trigger element (context mode only)
|
|
233
327
|
const ref = mode === 'context' ? el => {
|
|
@@ -255,11 +349,13 @@ export function useLayer(options) {
|
|
|
255
349
|
const handleToggle = useCallback(e => {
|
|
256
350
|
const toggleEvent = e;
|
|
257
351
|
if (toggleEvent.newState === 'closed' && isOpenRef.current) {
|
|
352
|
+
openedPopoverRef.current = null;
|
|
258
353
|
isOpenRef.current = false;
|
|
259
354
|
setIsOpen(false);
|
|
260
355
|
onHide?.();
|
|
356
|
+
clearContextMount();
|
|
261
357
|
}
|
|
262
|
-
}, [onHide]);
|
|
358
|
+
}, [onHide, clearContextMount]);
|
|
263
359
|
|
|
264
360
|
// Ref callback for popover element — sets up the `toggle` listener.
|
|
265
361
|
// Tracks the element + handler currently bound so the listener is removed
|
|
@@ -283,7 +379,24 @@ export function useLayer(options) {
|
|
|
283
379
|
const popoverRefCallback = useCallback(el => {
|
|
284
380
|
popoverRef.current = el;
|
|
285
381
|
bindToggleListener(el, handleToggle);
|
|
286
|
-
|
|
382
|
+
if (el && pendingShowRef.current) {
|
|
383
|
+
pendingShowRef.current = false;
|
|
384
|
+
show();
|
|
385
|
+
} else if (el && isOpenRef.current && openedPopoverRef.current !== el && isCurrentContextPopover(el)) {
|
|
386
|
+
// Changing a portal target remounts the popover. Preserve the logical
|
|
387
|
+
// open state without firing onShow again for the replacement element.
|
|
388
|
+
showPopoverElement(el);
|
|
389
|
+
}
|
|
390
|
+
}, [handleToggle, bindToggleListener, show, showPopoverElement, isCurrentContextPopover]);
|
|
391
|
+
const sentinelRefCallback = useCallback(el => {
|
|
392
|
+
sentinelRef.current = el;
|
|
393
|
+
if (el && (!lazyMount || pendingShowRef.current || isOpenRef.current)) {
|
|
394
|
+
// The render call may have moved while the hook stayed mounted.
|
|
395
|
+
// Resolve again from the newly attached marker rather than reusing a
|
|
396
|
+
// portal target from its previous JSX position.
|
|
397
|
+
requestContextMount();
|
|
398
|
+
}
|
|
399
|
+
}, [lazyMount, requestContextMount]);
|
|
287
400
|
|
|
288
401
|
// Re-bind when the handler identity changes while the element stays mounted,
|
|
289
402
|
// and detach on unmount.
|
|
@@ -302,6 +415,17 @@ export function useLayer(options) {
|
|
|
302
415
|
|
|
303
416
|
// Render function for context mode
|
|
304
417
|
const renderContext = useCallback((children, props) => {
|
|
418
|
+
// Keep the marker mounted after resolving the layer. Apart from giving
|
|
419
|
+
// us the real JSX parent on first show, this lets its ref report when a
|
|
420
|
+
// persistent hook's render call moves to a different host.
|
|
421
|
+
const sentinel = /*#__PURE__*/_jsx("template", {
|
|
422
|
+
ref: sentinelRefCallback
|
|
423
|
+
});
|
|
424
|
+
if (contextMount === null) {
|
|
425
|
+
return /*#__PURE__*/_jsx(_Fragment, {
|
|
426
|
+
children: sentinel
|
|
427
|
+
});
|
|
428
|
+
}
|
|
305
429
|
const {
|
|
306
430
|
placement = 'above',
|
|
307
431
|
alignment = 'center',
|
|
@@ -332,10 +456,10 @@ export function useLayer(options) {
|
|
|
332
456
|
const stylexResult = stylex.props(styles.base, offsetStyle, xstyle);
|
|
333
457
|
const combinedClassName = extraClassName ? `${extraClassName} ${stylexResult.className ?? ''}` : stylexResult.className;
|
|
334
458
|
|
|
335
|
-
//
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
|
|
459
|
+
// The marker gives us the actual JSX parent without mounting arbitrary
|
|
460
|
+
// children there. Safe positions preserve the existing DOM order and
|
|
461
|
+
// cascade; unsafe positions use the nearest corrective portal target.
|
|
462
|
+
const layer = /*#__PURE__*/_jsx(Container, {
|
|
339
463
|
ref: popoverRefCallback,
|
|
340
464
|
id: id,
|
|
341
465
|
role: role,
|
|
@@ -345,13 +469,17 @@ export function useLayer(options) {
|
|
|
345
469
|
style: {
|
|
346
470
|
...stylexResult.style,
|
|
347
471
|
...anchorStyle,
|
|
472
|
+
...contextMount.portalStyle,
|
|
348
473
|
...extraStyle
|
|
349
474
|
},
|
|
350
475
|
onMouseEnter: onMouseEnter,
|
|
351
476
|
onMouseLeave: onMouseLeave,
|
|
352
477
|
children: children
|
|
353
478
|
});
|
|
354
|
-
|
|
479
|
+
return /*#__PURE__*/_jsxs(_Fragment, {
|
|
480
|
+
children: [sentinel, contextMount.portalTarget ? /*#__PURE__*/createPortal(layer, contextMount.portalTarget) : layer]
|
|
481
|
+
});
|
|
482
|
+
}, [anchorId, contextMount, id, lightDismiss, popoverRefCallback, sentinelRefCallback]);
|
|
355
483
|
|
|
356
484
|
// Render function for fixed mode
|
|
357
485
|
const renderFixed = useCallback((children, props) => {
|
|
@@ -9,8 +9,13 @@
|
|
|
9
9
|
* disabled state) so all nav-like components stay in sync — especially important
|
|
10
10
|
* when TopNav items render inside MobileNav drawers alongside SideNav items.
|
|
11
11
|
*
|
|
12
|
-
* Individual components layer their own overrides (e.g. collapsed mode,
|
|
13
|
-
*
|
|
12
|
+
* Individual components layer their own overrides (e.g. collapsed mode,
|
|
13
|
+
* indentation) via stylex.props composition.
|
|
14
|
+
*
|
|
15
|
+
* The focus ring is not defined here. Compose
|
|
16
|
+
* `focusOutlineProps.focusVisible` (utils/focusOutline.stylex.ts) at the call
|
|
17
|
+
* site, on whichever element actually takes focus — in a split-action row that
|
|
18
|
+
* is the link and the toggle, not the row that contains them.
|
|
14
19
|
*/
|
|
15
20
|
export type NavItemSize = 'sm' | 'md' | 'lg';
|
|
16
21
|
import * as stylex from '@stylexjs/stylex';
|
|
@@ -63,15 +68,22 @@ export declare const navItemStyles: Readonly<{
|
|
|
63
68
|
}>;
|
|
64
69
|
}>;
|
|
65
70
|
readonly selected: Readonly<{
|
|
66
|
-
readonly backgroundColor: stylex.StyleXClassNameFor<"backgroundColor", "light-dark(rgba(5, 54, 89, 0.1), rgba(223, 226, 229, 0.2))">;
|
|
71
|
+
readonly backgroundColor: stylex.StyleXClassNameFor<"backgroundColor", "light-dark(rgba(5, 54, 89, 0.1), rgba(223, 226, 229, 0.2))" | "Highlight">;
|
|
72
|
+
readonly color: stylex.StyleXClassNameFor<"color", "HighlightText" | null>;
|
|
67
73
|
readonly fontWeight: stylex.StyleXClassNameFor<"fontWeight", "500">;
|
|
68
74
|
readonly ':hover': stylex.StyleXClassNameFor<":hover", {
|
|
69
75
|
readonly '@media (hover: hover)': {
|
|
70
|
-
readonly backgroundColor:
|
|
76
|
+
readonly backgroundColor: {
|
|
77
|
+
readonly default: stylex.StyleXVar<"light-dark(rgba(5, 54, 89, 0.1), rgba(223, 226, 229, 0.2))">;
|
|
78
|
+
readonly '@media (forced-colors: active)': "Highlight";
|
|
79
|
+
};
|
|
71
80
|
};
|
|
72
81
|
}>;
|
|
73
82
|
readonly ':active': stylex.StyleXClassNameFor<":active", {
|
|
74
|
-
readonly backgroundColor:
|
|
83
|
+
readonly backgroundColor: {
|
|
84
|
+
readonly default: stylex.StyleXVar<"light-dark(rgba(5, 54, 89, 0.1), rgba(223, 226, 229, 0.2))">;
|
|
85
|
+
readonly '@media (forced-colors: active)': "Highlight";
|
|
86
|
+
};
|
|
75
87
|
}>;
|
|
76
88
|
}>;
|
|
77
89
|
readonly disabled: Readonly<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navItemStyles.stylex.d.ts","sourceRoot":"","sources":["../../src/NavItem/navItemStyles.stylex.ts"],"names":[],"mappings":"AAEA
|
|
1
|
+
{"version":3,"file":"navItemStyles.stylex.d.ts","sourceRoot":"","sources":["../../src/NavItem/navItemStyles.stylex.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAU3C;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4FxB,CAAC"}
|
|
@@ -11,8 +11,13 @@
|
|
|
11
11
|
* disabled state) so all nav-like components stay in sync — especially important
|
|
12
12
|
* when TopNav items render inside MobileNav drawers alongside SideNav items.
|
|
13
13
|
*
|
|
14
|
-
* Individual components layer their own overrides (e.g. collapsed mode,
|
|
15
|
-
*
|
|
14
|
+
* Individual components layer their own overrides (e.g. collapsed mode,
|
|
15
|
+
* indentation) via stylex.props composition.
|
|
16
|
+
*
|
|
17
|
+
* The focus ring is not defined here. Compose
|
|
18
|
+
* `focusOutlineProps.focusVisible` (utils/focusOutline.stylex.ts) at the call
|
|
19
|
+
* site, on whichever element actually takes focus — in a split-action row that
|
|
20
|
+
* is the link and the toggle, not the row that contains them.
|
|
16
21
|
*/
|
|
17
22
|
|
|
18
23
|
import * as stylex from '@stylexjs/stylex';
|
|
@@ -63,10 +68,11 @@ export const navItemStyles = {
|
|
|
63
68
|
$$css: true
|
|
64
69
|
},
|
|
65
70
|
selected: {
|
|
66
|
-
kWkggS: "x17x4s8c",
|
|
71
|
+
kWkggS: "x17x4s8c x1jzqe4",
|
|
72
|
+
kMwMTN: "x1k5gbb1",
|
|
67
73
|
k63SB2: "x1e4wzip",
|
|
68
|
-
kHE3J0: "x1sua13m",
|
|
69
|
-
kSReZ0: "xjtnuge",
|
|
74
|
+
kHE3J0: "x1sua13m x1jawyga",
|
|
75
|
+
kSReZ0: "xjtnuge x1vo6n7o",
|
|
70
76
|
$$css: true
|
|
71
77
|
},
|
|
72
78
|
disabled: {
|