@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
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi, afterEach} from 'vitest';
|
|
13
|
-
import {render, act} from '@testing-library/react';
|
|
13
|
+
import {render, act, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {useLayer, getPositionTryFallbacks} from './useLayer';
|
|
16
16
|
import type {
|
|
@@ -19,6 +19,12 @@ import type {
|
|
|
19
19
|
ContextRenderProps,
|
|
20
20
|
} from './useLayer';
|
|
21
21
|
|
|
22
|
+
function mockCSSStyleDeclaration(
|
|
23
|
+
styles: Partial<CSSStyleDeclaration>,
|
|
24
|
+
): CSSStyleDeclaration {
|
|
25
|
+
return styles as CSSStyleDeclaration;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
/**
|
|
23
29
|
* Minimal harness that exposes the imperative show/hide callbacks and renders
|
|
24
30
|
* the layer element so tests can assert on visibility.
|
|
@@ -47,7 +53,7 @@ function ContextLayerHarness({
|
|
|
47
53
|
const layer = useLayer({mode: 'context'});
|
|
48
54
|
return (
|
|
49
55
|
<>
|
|
50
|
-
<button type="button" ref={layer.ref}>
|
|
56
|
+
<button type="button" ref={layer.ref} onClick={layer.show}>
|
|
51
57
|
Trigger
|
|
52
58
|
</button>
|
|
53
59
|
{layer.render(<span>Layer content</span>, {placement, alignment})}
|
|
@@ -55,6 +61,82 @@ function ContextLayerHarness({
|
|
|
55
61
|
);
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
function ContextHostingHarness({
|
|
65
|
+
unsafe,
|
|
66
|
+
themeColor,
|
|
67
|
+
direction,
|
|
68
|
+
writingMode,
|
|
69
|
+
}: {
|
|
70
|
+
unsafe?: boolean;
|
|
71
|
+
themeColor?: string;
|
|
72
|
+
direction?: React.CSSProperties['direction'];
|
|
73
|
+
writingMode?: React.CSSProperties['writingMode'];
|
|
74
|
+
}) {
|
|
75
|
+
const layer = useLayer({mode: 'context', lazyMount: true});
|
|
76
|
+
const contents = (
|
|
77
|
+
<>
|
|
78
|
+
<button type="button" ref={layer.ref} onClick={layer.show}>
|
|
79
|
+
Trigger
|
|
80
|
+
</button>
|
|
81
|
+
{layer.render(<button type="button">Layer action</button>)}
|
|
82
|
+
<button type="button">Following control</button>
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const hostStyle = {
|
|
87
|
+
...(themeColor ? {'--test-layer-color': themeColor} : {}),
|
|
88
|
+
direction,
|
|
89
|
+
writingMode,
|
|
90
|
+
} as React.CSSProperties;
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div data-testid="host" style={hostStyle}>
|
|
94
|
+
{unsafe ? <p>{contents}</p> : contents}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function RelocatingContextHostingHarness({unsafe}: {unsafe: boolean}) {
|
|
100
|
+
const layer = useLayer({mode: 'context'});
|
|
101
|
+
const renderedLayer = layer.render(<span>Layer content</span>);
|
|
102
|
+
|
|
103
|
+
return unsafe ? (
|
|
104
|
+
<div data-testid="unsafe-host">
|
|
105
|
+
<p>{renderedLayer}</p>
|
|
106
|
+
</div>
|
|
107
|
+
) : (
|
|
108
|
+
<section data-testid="render-position">{renderedLayer}</section>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function RelocatingOpenContextHostingHarness({
|
|
113
|
+
unsafe,
|
|
114
|
+
onShow,
|
|
115
|
+
}: {
|
|
116
|
+
unsafe: boolean;
|
|
117
|
+
onShow?: () => void;
|
|
118
|
+
}) {
|
|
119
|
+
const layer = useLayer({mode: 'context', lazyMount: true, onShow});
|
|
120
|
+
const renderedLayer = layer.render(
|
|
121
|
+
<button type="button">Layer action</button>,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<>
|
|
126
|
+
<button type="button" ref={layer.ref} onClick={layer.show}>
|
|
127
|
+
Trigger
|
|
128
|
+
</button>
|
|
129
|
+
{unsafe ? (
|
|
130
|
+
<div data-testid="unsafe-host">
|
|
131
|
+
<p>{renderedLayer}</p>
|
|
132
|
+
</div>
|
|
133
|
+
) : (
|
|
134
|
+
<section data-testid="safe-host">{renderedLayer}</section>
|
|
135
|
+
)}
|
|
136
|
+
</>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
58
140
|
describe('getPositionTryFallbacks (issue #3671)', () => {
|
|
59
141
|
const FLIPS = 'flip-block, flip-inline, flip-block flip-inline';
|
|
60
142
|
|
|
@@ -130,10 +212,12 @@ describe('getPositionTryFallbacks (issue #3671)', () => {
|
|
|
130
212
|
}
|
|
131
213
|
});
|
|
132
214
|
|
|
133
|
-
it('updates the fallback list when placement/alignment props change on re-render', () => {
|
|
215
|
+
it('updates the fallback list when placement/alignment props change on re-render', async () => {
|
|
216
|
+
const user = userEvent.setup();
|
|
134
217
|
const {container, rerender} = render(
|
|
135
218
|
<ContextLayerHarness placement="above" alignment="center" />,
|
|
136
219
|
);
|
|
220
|
+
await user.click(container.querySelector('button')!);
|
|
137
221
|
const layerEl = container.querySelector('[popover]') as HTMLElement;
|
|
138
222
|
expect(layerEl.style.positionTryFallbacks).toContain('top span-left');
|
|
139
223
|
|
|
@@ -158,8 +242,10 @@ describe('getPositionTryFallbacks (issue #3671)', () => {
|
|
|
158
242
|
expect(layerEl.style.top).toBe('20px');
|
|
159
243
|
});
|
|
160
244
|
|
|
161
|
-
it('applies span fallbacks to the rendered popover for the default (above/center) layer', () => {
|
|
245
|
+
it('applies span fallbacks to the rendered popover for the default (above/center) layer', async () => {
|
|
246
|
+
const user = userEvent.setup();
|
|
162
247
|
const {container} = render(<ContextLayerHarness />);
|
|
248
|
+
await user.click(container.querySelector('button')!);
|
|
163
249
|
const layerEl = container.querySelector('[popover]') as HTMLElement;
|
|
164
250
|
expect(layerEl).not.toBeNull();
|
|
165
251
|
expect(layerEl.style.positionTryFallbacks).toBe(
|
|
@@ -188,7 +274,246 @@ describe('useLayer', () => {
|
|
|
188
274
|
}
|
|
189
275
|
});
|
|
190
276
|
|
|
277
|
+
describe('context hosting', () => {
|
|
278
|
+
it('keeps closed content mounted by default for existing consumers', () => {
|
|
279
|
+
const {container} = render(<ContextLayerHarness />);
|
|
280
|
+
|
|
281
|
+
expect(container.querySelector('template')).not.toBeNull();
|
|
282
|
+
expect(container.querySelector('[popover]')).not.toBeNull();
|
|
283
|
+
expect(container).toHaveTextContent('Layer content');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('renders only an inert marker until show is requested', () => {
|
|
287
|
+
const {container} = render(<ContextHostingHarness />);
|
|
288
|
+
|
|
289
|
+
const sentinel = container.querySelector('template');
|
|
290
|
+
expect(sentinel).not.toBeNull();
|
|
291
|
+
expect(sentinel).not.toHaveAttribute('id');
|
|
292
|
+
expect(container.querySelector('[popover]')).toBeNull();
|
|
293
|
+
expect(container).not.toHaveTextContent('Layer action');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('keeps the final layer inline when the JSX position is safe', async () => {
|
|
297
|
+
HTMLElement.prototype.showPopover = vi.fn();
|
|
298
|
+
const user = userEvent.setup();
|
|
299
|
+
const {container, getByRole} = render(<ContextHostingHarness />);
|
|
300
|
+
|
|
301
|
+
await user.click(getByRole('button', {name: 'Trigger'}));
|
|
302
|
+
|
|
303
|
+
const layer = container.querySelector('[popover]');
|
|
304
|
+
const following = getByRole('button', {name: 'Following control'});
|
|
305
|
+
expect(layer?.parentElement).toBe(container.firstElementChild);
|
|
306
|
+
expect(layer?.nextElementSibling).toBe(following);
|
|
307
|
+
expect(container.querySelector('template')).not.toBeNull();
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('portals out of an unsafe parent and preserves its logical writing context', async () => {
|
|
311
|
+
const getComputedStyleSpy = vi
|
|
312
|
+
.spyOn(window, 'getComputedStyle')
|
|
313
|
+
.mockImplementation(() =>
|
|
314
|
+
mockCSSStyleDeclaration({
|
|
315
|
+
getPropertyValue: () => '',
|
|
316
|
+
direction: 'rtl',
|
|
317
|
+
writingMode: 'vertical-rl',
|
|
318
|
+
}),
|
|
319
|
+
);
|
|
320
|
+
const showSpy = vi.fn();
|
|
321
|
+
HTMLElement.prototype.showPopover = showSpy;
|
|
322
|
+
const user = userEvent.setup();
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
const {container, getByRole} = render(<ContextHostingHarness unsafe />);
|
|
326
|
+
const trigger = getByRole('button', {name: 'Trigger'});
|
|
327
|
+
|
|
328
|
+
await user.click(trigger);
|
|
329
|
+
|
|
330
|
+
const host = container.querySelector('[data-testid="host"]');
|
|
331
|
+
const paragraph = container.querySelector('p');
|
|
332
|
+
const layer = container.querySelector('[popover]') as HTMLElement;
|
|
333
|
+
expect(layer.parentElement).toBe(host);
|
|
334
|
+
expect(paragraph?.contains(layer)).toBe(false);
|
|
335
|
+
expect(layer).toHaveStyle({
|
|
336
|
+
direction: 'rtl',
|
|
337
|
+
writingMode: 'vertical-rl',
|
|
338
|
+
});
|
|
339
|
+
expect(showSpy).toHaveBeenCalledWith({source: trigger});
|
|
340
|
+
} finally {
|
|
341
|
+
getComputedStyleSpy.mockRestore();
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('inherits custom properties from the corrective host without freezing an inline snapshot', async () => {
|
|
346
|
+
const originalGetComputedStyle = window.getComputedStyle.bind(window);
|
|
347
|
+
const getComputedStyleSpy = vi
|
|
348
|
+
.spyOn(window, 'getComputedStyle')
|
|
349
|
+
.mockImplementation(element => {
|
|
350
|
+
if (element.tagName.toLowerCase() !== 'template') {
|
|
351
|
+
return originalGetComputedStyle(element);
|
|
352
|
+
}
|
|
353
|
+
return mockCSSStyleDeclaration({
|
|
354
|
+
length: 1,
|
|
355
|
+
item: () => '--test-layer-color',
|
|
356
|
+
getPropertyValue: property =>
|
|
357
|
+
property === '--test-layer-color' ? 'rgb(1, 2, 3)' : '',
|
|
358
|
+
direction: 'ltr',
|
|
359
|
+
writingMode: 'horizontal-tb',
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
HTMLElement.prototype.showPopover = vi.fn();
|
|
363
|
+
const user = userEvent.setup();
|
|
364
|
+
try {
|
|
365
|
+
const {container, getByRole, rerender} = render(
|
|
366
|
+
<ContextHostingHarness unsafe themeColor="rgb(1, 2, 3)" />,
|
|
367
|
+
);
|
|
368
|
+
|
|
369
|
+
await user.click(getByRole('button', {name: 'Trigger'}));
|
|
370
|
+
|
|
371
|
+
let host = container.querySelector(
|
|
372
|
+
'[data-testid="host"]',
|
|
373
|
+
) as HTMLElement;
|
|
374
|
+
let layer = container.querySelector('[popover]') as HTMLElement;
|
|
375
|
+
expect(layer.parentElement).toBe(host);
|
|
376
|
+
expect(layer.style.getPropertyValue('--test-layer-color')).toBe('');
|
|
377
|
+
expect(host.style.getPropertyValue('--test-layer-color')).toBe(
|
|
378
|
+
'rgb(1, 2, 3)',
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
rerender(<ContextHostingHarness unsafe themeColor="rgb(4, 5, 6)" />);
|
|
382
|
+
|
|
383
|
+
host = container.querySelector('[data-testid="host"]') as HTMLElement;
|
|
384
|
+
layer = container.querySelector('[popover]') as HTMLElement;
|
|
385
|
+
expect(layer.parentElement).toBe(host);
|
|
386
|
+
expect(layer.style.getPropertyValue('--test-layer-color')).toBe('');
|
|
387
|
+
expect(host.style.getPropertyValue('--test-layer-color')).toBe(
|
|
388
|
+
'rgb(4, 5, 6)',
|
|
389
|
+
);
|
|
390
|
+
} finally {
|
|
391
|
+
getComputedStyleSpy.mockRestore();
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('keeps a shared writing context inheriting live from the corrective host', async () => {
|
|
396
|
+
const getComputedStyleSpy = vi
|
|
397
|
+
.spyOn(window, 'getComputedStyle')
|
|
398
|
+
.mockImplementation(element => {
|
|
399
|
+
const htmlElement = element as HTMLElement;
|
|
400
|
+
const host = htmlElement.matches('[data-testid="host"]')
|
|
401
|
+
? htmlElement
|
|
402
|
+
: htmlElement.closest<HTMLElement>('[data-testid="host"]');
|
|
403
|
+
return mockCSSStyleDeclaration({
|
|
404
|
+
getPropertyValue: () => '',
|
|
405
|
+
direction: host?.style.direction || 'ltr',
|
|
406
|
+
writingMode: host?.style.writingMode || 'horizontal-tb',
|
|
407
|
+
});
|
|
408
|
+
});
|
|
409
|
+
HTMLElement.prototype.showPopover = vi.fn();
|
|
410
|
+
const user = userEvent.setup();
|
|
411
|
+
|
|
412
|
+
try {
|
|
413
|
+
const {container, getByRole, rerender} = render(
|
|
414
|
+
<ContextHostingHarness
|
|
415
|
+
unsafe
|
|
416
|
+
direction="rtl"
|
|
417
|
+
writingMode="vertical-rl"
|
|
418
|
+
/>,
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
await user.click(getByRole('button', {name: 'Trigger'}));
|
|
422
|
+
|
|
423
|
+
let layer = container.querySelector('[popover]') as HTMLElement;
|
|
424
|
+
expect(layer.style.direction).toBe('');
|
|
425
|
+
expect(layer.style.writingMode).toBe('');
|
|
426
|
+
expect(window.getComputedStyle(layer).direction).toBe('rtl');
|
|
427
|
+
|
|
428
|
+
rerender(
|
|
429
|
+
<ContextHostingHarness
|
|
430
|
+
unsafe
|
|
431
|
+
direction="ltr"
|
|
432
|
+
writingMode="horizontal-tb"
|
|
433
|
+
/>,
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
layer = container.querySelector('[popover]') as HTMLElement;
|
|
437
|
+
expect(layer.style.direction).toBe('');
|
|
438
|
+
expect(layer.style.writingMode).toBe('');
|
|
439
|
+
expect(window.getComputedStyle(layer).direction).toBe('ltr');
|
|
440
|
+
} finally {
|
|
441
|
+
getComputedStyleSpy.mockRestore();
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('re-resolves the host when a persistent render call moves', () => {
|
|
446
|
+
const {container, rerender} = render(
|
|
447
|
+
<RelocatingContextHostingHarness unsafe />,
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
const host = container.querySelector('[data-testid="unsafe-host"]');
|
|
451
|
+
const paragraph = container.querySelector('p');
|
|
452
|
+
let layer = container.querySelector('[popover]');
|
|
453
|
+
expect(layer?.parentElement).toBe(host);
|
|
454
|
+
expect(paragraph?.contains(layer)).toBe(false);
|
|
455
|
+
|
|
456
|
+
rerender(<RelocatingContextHostingHarness unsafe={false} />);
|
|
457
|
+
|
|
458
|
+
const section = container.querySelector('section');
|
|
459
|
+
layer = container.querySelector('[popover]');
|
|
460
|
+
expect(layer?.parentElement).toBe(section);
|
|
461
|
+
expect(section?.querySelector('template')).not.toBeNull();
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('reopens an open lazy layer after its render call moves', async () => {
|
|
465
|
+
const showSpy = vi.fn(function (this: HTMLElement) {
|
|
466
|
+
if (!this.isConnected) {
|
|
467
|
+
throw new Error('showPopover called on a detached layer');
|
|
468
|
+
}
|
|
469
|
+
this.dataset.open = 'true';
|
|
470
|
+
});
|
|
471
|
+
const onShow = vi.fn();
|
|
472
|
+
HTMLElement.prototype.showPopover = showSpy;
|
|
473
|
+
const {container, getByRole, rerender} = render(
|
|
474
|
+
<RelocatingOpenContextHostingHarness unsafe onShow={onShow} />,
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
fireEvent.click(getByRole('button', {name: 'Trigger'}));
|
|
478
|
+
|
|
479
|
+
await waitFor(() => {
|
|
480
|
+
expect(container.querySelector('[popover]')).toHaveAttribute(
|
|
481
|
+
'data-open',
|
|
482
|
+
'true',
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
rerender(
|
|
487
|
+
<RelocatingOpenContextHostingHarness unsafe={false} onShow={onShow} />,
|
|
488
|
+
);
|
|
489
|
+
|
|
490
|
+
await waitFor(() => {
|
|
491
|
+
const layer = container.querySelector('[popover]');
|
|
492
|
+
expect(layer?.parentElement).toBe(
|
|
493
|
+
container.querySelector('[data-testid="safe-host"]'),
|
|
494
|
+
);
|
|
495
|
+
expect(layer).toHaveAttribute('data-open', 'true');
|
|
496
|
+
});
|
|
497
|
+
expect(showSpy).toHaveBeenCalledTimes(2);
|
|
498
|
+
expect(onShow).toHaveBeenCalledOnce();
|
|
499
|
+
});
|
|
500
|
+
});
|
|
501
|
+
|
|
191
502
|
describe('when the Popover API is supported', () => {
|
|
503
|
+
it('declares body type instead of inheriting the host context', () => {
|
|
504
|
+
const {container} = render(
|
|
505
|
+
<div style={{fontSize: '30px', lineHeight: '3'}}>
|
|
506
|
+
<LayerHarness onReady={() => {}} />
|
|
507
|
+
</div>,
|
|
508
|
+
);
|
|
509
|
+
|
|
510
|
+
const layer = container.querySelector('[popover]') as HTMLElement;
|
|
511
|
+
expect(layer).toHaveStyle({
|
|
512
|
+
fontSize: 'var(--text-body-size)',
|
|
513
|
+
lineHeight: 'var(--text-body-leading)',
|
|
514
|
+
});
|
|
515
|
+
});
|
|
516
|
+
|
|
192
517
|
it('calls showPopover/hidePopover on show/hide', () => {
|
|
193
518
|
const showSpy = vi.fn();
|
|
194
519
|
const hideSpy = vi.fn();
|
|
@@ -485,9 +810,9 @@ describe('useLayer context positioning', () => {
|
|
|
485
810
|
const NONE = {blockStart: '', blockEnd: '', inlineStart: '', inlineEnd: ''};
|
|
486
811
|
|
|
487
812
|
it('is flush by default', async () => {
|
|
488
|
-
expect(
|
|
489
|
-
|
|
490
|
-
);
|
|
813
|
+
expect(
|
|
814
|
+
await openAndGetOffsets(<OffsetHarness placement="below" />),
|
|
815
|
+
).toEqual(NONE);
|
|
491
816
|
});
|
|
492
817
|
|
|
493
818
|
// Both edges of the axis, so the gap survives a position-try-fallbacks
|