reshaped 3.1.4 → 3.1.6
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 +21 -0
- package/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +2 -0
- package/dist/bundle.js +11 -12
- package/dist/components/Actionable/Actionable.d.ts +1 -1
- package/dist/components/Actionable/Actionable.js +2 -2
- package/dist/components/Actionable/Actionable.module.css +1 -1
- package/dist/components/Actionable/Actionable.types.d.ts +1 -0
- package/dist/components/Autocomplete/Autocomplete.js +10 -4
- package/dist/components/Button/Button.js +1 -1
- package/dist/components/Card/Card.d.ts +1 -1
- package/dist/components/Card/tests/Card.stories.d.ts +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +1 -1
- package/dist/components/FormControl/FormControl.context.d.ts +2 -1
- package/dist/components/Grid/Grid.d.ts +6 -0
- package/dist/components/Grid/Grid.js +46 -0
- package/dist/components/Grid/Grid.module.css +1 -0
- package/dist/components/Grid/Grid.types.d.ts +31 -0
- package/dist/components/Grid/Grid.types.js +1 -0
- package/dist/components/Grid/index.d.ts +2 -0
- package/dist/components/Grid/index.js +1 -0
- package/dist/components/Grid/tests/Grid.stories.d.ts +18 -0
- package/dist/components/Grid/tests/Grid.stories.js +170 -0
- package/dist/components/Icon/Icon.module.css +1 -1
- package/dist/components/Link/Link.d.ts +1 -1
- package/dist/components/Loader/Loader.module.css +1 -1
- package/dist/components/Loader/Loader.types.d.ts +1 -1
- package/dist/components/Loader/tests/Loader.stories.js +5 -3
- package/dist/components/Overlay/tests/Overlay.stories.js +1 -1
- package/dist/components/Popover/Popover.js +2 -4
- package/dist/components/Popover/Popover.types.d.ts +1 -1
- package/dist/components/Select/Select.js +1 -1
- package/dist/components/Table/Table.js +6 -4
- package/dist/components/Table/Table.types.d.ts +6 -1
- package/dist/components/Tabs/Tabs.d.ts +1 -1
- package/dist/components/Tabs/Tabs.module.css +1 -1
- package/dist/components/Tabs/TabsItem.d.ts +1 -1
- package/dist/components/Tabs/TabsItem.js +2 -3
- package/dist/components/Tabs/tests/Tabs.stories.d.ts +15 -13
- package/dist/components/Tabs/tests/Tabs.stories.js +71 -8
- package/dist/components/Tooltip/Tooltip.js +1 -1
- package/dist/components/View/View.js +7 -3
- package/dist/components/View/View.module.css +1 -1
- package/dist/components/View/View.types.d.ts +2 -2
- package/dist/components/_private/Expandable/Expandable.js +9 -5
- package/dist/components/_private/Flyout/Flyout.module.css +1 -1
- package/dist/components/_private/Flyout/Flyout.types.d.ts +11 -2
- package/dist/components/_private/Flyout/FlyoutControlled.js +33 -18
- package/dist/components/_private/Flyout/tests/Flyout.stories.d.ts +1 -0
- package/dist/components/_private/Flyout/tests/Flyout.stories.js +28 -18
- package/dist/components/_private/Flyout/useFlyout.d.ts +2 -1
- package/dist/components/_private/Flyout/useFlyout.js +46 -57
- package/dist/components/_private/Flyout/utilities/calculatePosition.js +16 -11
- package/dist/components/_private/Flyout/utilities/cooldown.d.ts +1 -1
- package/dist/components/_private/Flyout/utilities/cooldown.js +17 -5
- package/dist/components/_private/Flyout/utilities/getPositionFallbacks.d.ts +3 -0
- package/dist/components/_private/Flyout/utilities/getPositionFallbacks.js +39 -0
- package/dist/config/tailwind.d.ts +1 -1
- package/dist/hooks/_private/useOnClickOutside.js +3 -2
- package/dist/hooks/_private/useSingletonHotkeys.js +16 -13
- package/dist/hooks/tests/useHotkeys.stories.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/styles/align/align.module.css +1 -0
- package/dist/styles/align/index.d.ts +3 -0
- package/dist/styles/align/index.js +10 -0
- package/dist/styles/justify/index.d.ts +3 -0
- package/dist/styles/justify/index.js +10 -0
- package/dist/styles/justify/justify.module.css +1 -0
- package/dist/styles/types.d.ts +2 -0
- package/dist/tests/ShadowDOM.stories.d.ts +6 -0
- package/dist/tests/ShadowDOM.stories.js +110 -0
- package/dist/themes/_generator/tests/themes.stories.js +1 -1
- package/dist/utilities/a11y/TrapFocus.d.ts +1 -1
- package/dist/utilities/a11y/TrapFocus.js +14 -5
- package/dist/utilities/a11y/focus.d.ts +1 -1
- package/dist/utilities/a11y/focus.js +10 -5
- package/dist/utilities/dom.d.ts +2 -1
- package/dist/utilities/dom.js +12 -2
- package/package.json +31 -29
@@ -19,7 +19,7 @@ const getEventKey = (e) => {
|
|
19
19
|
if (!e.key)
|
20
20
|
return;
|
21
21
|
// Having alt pressed modifies e.key value, so relying on e.code for it
|
22
|
-
if (e.altKey && e.
|
22
|
+
if (e.altKey && /^[Key|Digit|Numpad]/.test(e.code)) {
|
23
23
|
return e.code.toLowerCase().replace(/key|digit|numpad/, "");
|
24
24
|
}
|
25
25
|
return e.key.toLowerCase();
|
@@ -70,17 +70,20 @@ export class HotkeyStore {
|
|
70
70
|
const hotkeyData = this.hotkeyMap[pressedId];
|
71
71
|
/**
|
72
72
|
* Support for `mod` that represents both Mac and Win keyboards
|
73
|
+
* We create the hotkeyId again to sort the mod key correctly
|
73
74
|
*/
|
74
|
-
const
|
75
|
-
|
76
|
-
const
|
75
|
+
const controlToModPressedId = getHotkeyId(pressedId.replace("control", "mod"));
|
76
|
+
const metaToModPressedId = getHotkeyId(pressedId.replace("meta", "mod"));
|
77
|
+
const hotkeyControlModData = pressedFormattedKeys.includes("control") && this.hotkeyMap[controlToModPressedId];
|
78
|
+
const hotkeyMetaModData = pressedFormattedKeys.includes("meta") && this.hotkeyMap[metaToModPressedId];
|
77
79
|
[hotkeyData, hotkeyControlModData, hotkeyMetaModData].forEach((hotkeyData) => {
|
78
80
|
if (!hotkeyData)
|
79
81
|
return;
|
80
82
|
if (hotkeyData?.size) {
|
81
83
|
hotkeyData.forEach((data) => {
|
84
|
+
const eventTarget = e.composedPath()[0];
|
82
85
|
if (data.ref?.current &&
|
83
|
-
!(
|
86
|
+
!(eventTarget === data.ref.current || data.ref.current.contains(eventTarget))) {
|
84
87
|
return;
|
85
88
|
}
|
86
89
|
const resolvedEvent = pressedMap[pressedId];
|
@@ -146,14 +149,6 @@ export const SingletonHotkeysProvider = (props) => {
|
|
146
149
|
return false;
|
147
150
|
return true;
|
148
151
|
};
|
149
|
-
const addHotkeys = React.useCallback((hotkeys, ref, options = {}) => {
|
150
|
-
setHooksCount((prev) => prev + 1);
|
151
|
-
globalHotkeyStore.bindHotkeys(hotkeys, ref, options);
|
152
|
-
return () => {
|
153
|
-
setHooksCount((prev) => prev - 1);
|
154
|
-
globalHotkeyStore.unbindHotkeys(hotkeys);
|
155
|
-
};
|
156
|
-
}, []);
|
157
152
|
const handleWindowKeyDown = React.useCallback((e) => {
|
158
153
|
// Browsers trigger keyboard event without passing e.key when you click on autocomplete
|
159
154
|
if (!e.key)
|
@@ -166,6 +161,14 @@ export const SingletonHotkeysProvider = (props) => {
|
|
166
161
|
return;
|
167
162
|
removePressedKey(e);
|
168
163
|
}, [removePressedKey]);
|
164
|
+
const addHotkeys = React.useCallback((hotkeys, ref, options = {}) => {
|
165
|
+
setHooksCount((prev) => prev + 1);
|
166
|
+
globalHotkeyStore.bindHotkeys(hotkeys, ref, options);
|
167
|
+
return () => {
|
168
|
+
setHooksCount((prev) => prev - 1);
|
169
|
+
globalHotkeyStore.unbindHotkeys(hotkeys);
|
170
|
+
};
|
171
|
+
}, []);
|
169
172
|
React.useEffect(() => {
|
170
173
|
window.addEventListener("keydown", handleWindowKeyDown);
|
171
174
|
window.addEventListener("keyup", handleWindowKeyUp);
|
@@ -6,10 +6,16 @@ function Example() {
|
|
6
6
|
"shift + b + n": () => console.log("pressed"),
|
7
7
|
"c + v": () => console.log(111),
|
8
8
|
"Meta + v": () => console.log(222),
|
9
|
+
"control + enter": () => console.log("control + enter"),
|
10
|
+
"meta + enter": () => console.log("meta + enter"),
|
11
|
+
"mod + enter": () => console.log("mod + enter"),
|
9
12
|
"mod + ArrowRight": () => console.log("right"),
|
10
13
|
"mod + ArrowUp": () => console.log("top"),
|
11
14
|
"shift + ArrowRight": () => console.log("right"),
|
12
15
|
"shift + ArrowUp": () => console.log("top"),
|
16
|
+
"alt+shift+n": () => console.log("alt+shift+n"),
|
17
|
+
"shift+alt+n": () => console.log("shift+alt+n"),
|
18
|
+
"alt+shiftLeft+n": () => console.log("alt+shiftLeft+n"),
|
13
19
|
});
|
14
20
|
const active = checkHotkeyState("shift + b + n");
|
15
21
|
const shiftActive = checkHotkeyState("shift");
|
package/dist/index.d.ts
CHANGED
@@ -41,6 +41,8 @@ export { default as FileUpload } from "./components/FileUpload";
|
|
41
41
|
export type { FileUploadProps } from "./components/FileUpload";
|
42
42
|
export { default as FormControl } from "./components/FormControl";
|
43
43
|
export type { FormControlProps } from "./components/FormControl";
|
44
|
+
export { default as Grid } from "./components/Grid";
|
45
|
+
export type { GridProps, GridItemProps } from "./components/Grid";
|
44
46
|
export { default as Hidden } from "./components/Hidden";
|
45
47
|
export type { HiddenProps } from "./components/Hidden";
|
46
48
|
export { default as HiddenVisually } from "./components/HiddenVisually";
|
package/dist/index.js
CHANGED
@@ -21,6 +21,7 @@ export { default as Divider } from "./components/Divider/index.js";
|
|
21
21
|
export { default as DropdownMenu } from "./components/DropdownMenu/index.js";
|
22
22
|
export { default as FileUpload } from "./components/FileUpload/index.js";
|
23
23
|
export { default as FormControl } from "./components/FormControl/index.js";
|
24
|
+
export { default as Grid } from "./components/Grid/index.js";
|
24
25
|
export { default as Hidden } from "./components/Hidden/index.js";
|
25
26
|
export { default as HiddenVisually } from "./components/HiddenVisually/index.js";
|
26
27
|
export { default as Hotkey } from "./components/Hotkey/index.js";
|
@@ -0,0 +1 @@
|
|
1
|
+
.--align-start{align-items:flex-start!important}.--align-end{align-items:flex-end!important}.--align-center{align-items:center!important}.--align-stretch{align-items:stretch!important}.--align-baseline{align-items:baseline!important}@media (--rs-viewport-m ){.--align-start--m{align-items:flex-start!important}.--align-end--m{align-items:flex-end!important}.--align-center--m{align-items:center!important}.--align-stretch--m{align-items:stretch!important}.--align-baseline--m{align-items:baseline!important}}@media (--rs-viewport-l ){.--align-start--l{align-items:flex-start!important}.--align-end--l{align-items:flex-end!important}.--align-center--l{align-items:center!important}.--align-stretch--l{align-items:stretch!important}.--align-baseline--l{align-items:baseline!important}}@media (--rs-viewport-xl ){.--align-start--xl{align-items:flex-start!important}.--align-end--xl{align-items:flex-end!important}.--align-center--xl{align-items:center!important}.--align-stretch--xl{align-items:stretch!important}.--align-baseline--xl{align-items:baseline!important}}
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { responsiveClassNames } from "../../utilities/helpers.js";
|
2
|
+
import s from "./align.module.css";
|
3
|
+
const getAlignStyles = (value) => {
|
4
|
+
if (!value)
|
5
|
+
return null;
|
6
|
+
return {
|
7
|
+
classNames: responsiveClassNames(s, "--align", value),
|
8
|
+
};
|
9
|
+
};
|
10
|
+
export default getAlignStyles;
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import { responsiveClassNames } from "../../utilities/helpers.js";
|
2
|
+
import s from "./justify.module.css";
|
3
|
+
const getJustifyStyles = (value) => {
|
4
|
+
if (!value)
|
5
|
+
return null;
|
6
|
+
return {
|
7
|
+
classNames: responsiveClassNames(s, "--justify", value),
|
8
|
+
};
|
9
|
+
};
|
10
|
+
export default getJustifyStyles;
|
@@ -0,0 +1 @@
|
|
1
|
+
.--justify-start{justify-content:flex-start}.--justify-end{justify-content:flex-end}.--justify-center{justify-content:center}.--justify-space-between{justify-content:space-between}@media (--rs-viewport-m ){.--justify-start--m{justify-content:flex-start}.--justify-end--m{justify-content:flex-end}.--justify-center--m{justify-content:center}.--justify-space-between--m{justify-content:space-between}}@media (--rs-viewport-l ){.--justify-start--l{justify-content:flex-start}.--justify-end--l{justify-content:flex-end}.--justify-center--l{justify-content:center}.--justify-space-between--l{justify-content:space-between}}@media (--rs-viewport-xl ){.--justify-start--xl{justify-content:flex-start}.--justify-end--xl{justify-content:flex-end}.--justify-center--xl{justify-content:center}.--justify-space-between--xl{justify-content:space-between}}
|
package/dist/styles/types.d.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import React from "react";
|
2
2
|
import * as G from "../types/global";
|
3
3
|
export type TextAlign = "start" | "center" | "end";
|
4
|
+
export type Justify = "start" | "center" | "end" | "space-between";
|
5
|
+
export type Align = "start" | "center" | "end" | "stretch" | "baseline";
|
4
6
|
export type Radius = "small" | "medium" | "large" | "circular" | "none";
|
5
7
|
export type Position = "relative" | "absolute" | "fixed" | "sticky" | "static";
|
6
8
|
export type BorderColor = "neutral" | "neutral-faded" | "critical" | "critical-faded" | "warning" | "warning-faded" | "positive" | "positive-faded" | "primary" | "primary-faded" | "disabled" | "brand" | "transparent";
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import React, { useEffect, useState, useRef, forwardRef } from "react";
|
2
|
+
import root from "react-shadow";
|
3
|
+
import { Example } from "../utilities/storybook/index.js";
|
4
|
+
import Autocomplete from "../components/Autocomplete/index.js";
|
5
|
+
import View from "../components/View/index.js";
|
6
|
+
import DropdownMenu from "../components/DropdownMenu/index.js";
|
7
|
+
import Reshaped from "../components/Reshaped/index.js";
|
8
|
+
import Select from "../components/Select/index.js";
|
9
|
+
import Button from "../components/Button/index.js";
|
10
|
+
import Tooltip from "../components/Tooltip/index.js";
|
11
|
+
export default {
|
12
|
+
title: "Meta/ShadowDOM",
|
13
|
+
};
|
14
|
+
const getStylesData = () => {
|
15
|
+
const sourceStylesContainer = document.head;
|
16
|
+
return Array.from(sourceStylesContainer.children).filter((x) => x instanceof HTMLStyleElement);
|
17
|
+
};
|
18
|
+
// Create a component to render inside the Shadow DOM
|
19
|
+
const ShadowDiv = forwardRef((props, ref) => {
|
20
|
+
const shadowRef = useRef(null);
|
21
|
+
// Load styles
|
22
|
+
useEffect(() => {
|
23
|
+
if (!shadowRef?.current)
|
24
|
+
return;
|
25
|
+
// Add styles to the shadow DOM
|
26
|
+
// const shadowEl = shadowRef?.current.shadowRoot;
|
27
|
+
const shadowEl = shadowRef?.current.shadowRoot;
|
28
|
+
if (!shadowEl)
|
29
|
+
return;
|
30
|
+
const sourceStylesContainer = document.head;
|
31
|
+
const observer = new MutationObserver(getStylesData);
|
32
|
+
observer.observe(sourceStylesContainer, {
|
33
|
+
characterData: true,
|
34
|
+
childList: true,
|
35
|
+
subtree: true,
|
36
|
+
});
|
37
|
+
let styleBlock = shadowEl.getElementById("custom-outer-style");
|
38
|
+
if (!styleBlock) {
|
39
|
+
styleBlock = document.createElement("span");
|
40
|
+
styleBlock.id = "custom-outer-style";
|
41
|
+
shadowEl.appendChild(styleBlock);
|
42
|
+
}
|
43
|
+
else {
|
44
|
+
styleBlock.innerHTML = "";
|
45
|
+
}
|
46
|
+
styleBlock.append(...getStylesData() // finds all <style> tags containing your web component ID
|
47
|
+
.map((x) => x.cloneNode(true)) // copies styles into the current instance of your web component. You might need to have multiple instances, so all of them need to track the styles.
|
48
|
+
);
|
49
|
+
return () => observer.disconnect();
|
50
|
+
}, []);
|
51
|
+
return (<Reshaped>
|
52
|
+
<root.div className="quote" ref={shadowRef}>
|
53
|
+
<div ref={ref}>
|
54
|
+
{/*
|
55
|
+
Adding padding here since otherwise mouseenter won't trigger on contents
|
56
|
+
when mouse is switching from outside the shadow dom
|
57
|
+
*/}
|
58
|
+
<View padding={4}>{props.children}</View>
|
59
|
+
</div>
|
60
|
+
</root.div>
|
61
|
+
</Reshaped>);
|
62
|
+
});
|
63
|
+
// Main Component
|
64
|
+
const Component = () => {
|
65
|
+
const [valueAutoShadow, setValueAutoShadow] = useState("");
|
66
|
+
const [valueDropdownShadow, setValueDropdownShadow] = useState("");
|
67
|
+
const optionsAuto = ["Pizza", "Pie", "Ice-cream"];
|
68
|
+
const optionsDropdown = ["Turtle", "Cat", "Long-necked giraffe"];
|
69
|
+
const handleChangeAutoShadow = (args) => {
|
70
|
+
console.log("Autocomlete shadow value=", args);
|
71
|
+
setValueAutoShadow(args.value);
|
72
|
+
};
|
73
|
+
const handleChangeDropdownShadow = (val) => {
|
74
|
+
console.log("Dropdown shadow value=", val);
|
75
|
+
setValueDropdownShadow(val);
|
76
|
+
};
|
77
|
+
return (<View paddingBottom={50}>
|
78
|
+
<ShadowDiv>
|
79
|
+
<View gap={4} direction="row" wrap={false}>
|
80
|
+
<Autocomplete name="fruit-shadow" placeholder="Pick your food" value={valueAutoShadow} onChange={handleChangeAutoShadow}>
|
81
|
+
{optionsAuto.map((option) => (<Autocomplete.Item key={option} value={option} onClick={() => handleChangeAutoShadow({ value: option, name: "fruit-auto" })}>
|
82
|
+
{option}
|
83
|
+
</Autocomplete.Item>))}
|
84
|
+
</Autocomplete>
|
85
|
+
|
86
|
+
<DropdownMenu>
|
87
|
+
<DropdownMenu.Trigger>
|
88
|
+
{(attributes) => (<Select placeholder="Pick your animal" name="font" inputAttributes={attributes}>
|
89
|
+
{valueDropdownShadow}
|
90
|
+
</Select>)}
|
91
|
+
</DropdownMenu.Trigger>
|
92
|
+
<DropdownMenu.Content>
|
93
|
+
{optionsDropdown.map((option) => (<DropdownMenu.Item onClick={() => handleChangeDropdownShadow(option)} key={option}>
|
94
|
+
{option}
|
95
|
+
</DropdownMenu.Item>))}
|
96
|
+
</DropdownMenu.Content>
|
97
|
+
</DropdownMenu>
|
98
|
+
|
99
|
+
<Tooltip text="Tooltip for button">
|
100
|
+
{(attributes) => <Button attributes={attributes}>Hover me</Button>}
|
101
|
+
</Tooltip>
|
102
|
+
</View>
|
103
|
+
</ShadowDiv>
|
104
|
+
</View>);
|
105
|
+
};
|
106
|
+
export const behavior = () => (<Example>
|
107
|
+
<Example.Item title="base">
|
108
|
+
<Component />
|
109
|
+
</Example.Item>
|
110
|
+
</Example>);
|
@@ -13,7 +13,7 @@ import Link from "../../../components/Link/index.js";
|
|
13
13
|
import Text from "../../../components/Text/index.js";
|
14
14
|
import { getThemeCSS, generateThemeColors, baseThemeDefinition } from "../../index.js";
|
15
15
|
export default {
|
16
|
-
title: "Themes",
|
16
|
+
title: "Meta/Themes",
|
17
17
|
parameters: {
|
18
18
|
iframe: { url: "https://reshaped.so/docs/tokens/theming/runtime-theming" },
|
19
19
|
},
|
@@ -2,6 +2,7 @@ import Chain from "../Chain.js";
|
|
2
2
|
import * as keys from "../../constants/keys.js";
|
3
3
|
import TrapScreenReader from "./TrapScreenReader.js";
|
4
4
|
import { getActiveElement, getFocusableElements, focusElement, getFocusData } from "./focus.js";
|
5
|
+
import { getShadowRoot } from "../dom.js";
|
5
6
|
import { checkKeyboardMode } from "./keyboardMode.js";
|
6
7
|
class TrapFocus {
|
7
8
|
static chain = new Chain();
|
@@ -34,7 +35,7 @@ class TrapFocus {
|
|
34
35
|
const isDown = navigationMode === "arrows" && key === keys.DOWN;
|
35
36
|
const isPrev = (isBackTab && navigationMode === "tabs") || isUp;
|
36
37
|
const isNext = (isNextTab && navigationMode === "tabs") || isDown;
|
37
|
-
const isFocusedOnTrigger = getActiveElement() === this.trigger;
|
38
|
+
const isFocusedOnTrigger = getActiveElement(this.root) === this.trigger;
|
38
39
|
const focusData = getFocusData({
|
39
40
|
root: this.root,
|
40
41
|
target: isPrev ? "prev" : "next",
|
@@ -61,15 +62,23 @@ class TrapFocus {
|
|
61
62
|
return;
|
62
63
|
focusElement(focusData.el, { pseudoFocus });
|
63
64
|
};
|
64
|
-
addListeners = () =>
|
65
|
-
|
65
|
+
addListeners = () => {
|
66
|
+
const shadowRoot = getShadowRoot(this.root);
|
67
|
+
const el = shadowRoot ?? document;
|
68
|
+
el.addEventListener("keydown", this.handleKeyDown);
|
69
|
+
};
|
70
|
+
removeListeners = () => {
|
71
|
+
const shadowRoot = getShadowRoot(this.root);
|
72
|
+
const el = shadowRoot ?? document;
|
73
|
+
el.removeEventListener("keydown", this.handleKeyDown);
|
74
|
+
};
|
66
75
|
/**
|
67
76
|
* Trap the focus, add observer and keyboard event listeners
|
68
77
|
* and create a chain item
|
69
78
|
*/
|
70
79
|
trap = (options = {}) => {
|
71
80
|
const { mode = "dialog", includeTrigger, initialFocusEl } = options;
|
72
|
-
const trigger = getActiveElement();
|
81
|
+
const trigger = getActiveElement(this.root);
|
73
82
|
const focusable = getFocusableElements(this.root, {
|
74
83
|
additionalElement: includeTrigger ? trigger : undefined,
|
75
84
|
});
|
@@ -77,7 +86,7 @@ class TrapFocus {
|
|
77
86
|
this.options = { ...options, pseudoFocus };
|
78
87
|
this.trigger = trigger;
|
79
88
|
this.mutationObserver = new MutationObserver(() => {
|
80
|
-
const currentActiveElement = getActiveElement();
|
89
|
+
const currentActiveElement = getActiveElement(this.root);
|
81
90
|
// Focus stayed inside the wrapper, no need to refocus
|
82
91
|
if (this.root.contains(currentActiveElement))
|
83
92
|
return;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import type { FocusableElement } from "./types";
|
2
2
|
export declare const focusableSelector = "a,button,input:not([type=\"hidden\"]),textarea,select,details,[tabindex]:not([tabindex=\"-1\"])";
|
3
|
-
export declare const getActiveElement: () => HTMLButtonElement;
|
3
|
+
export declare const getActiveElement: (originEl?: HTMLElement | null) => HTMLButtonElement;
|
4
4
|
export declare const focusElement: (el: FocusableElement, options?: {
|
5
5
|
pseudoFocus?: boolean;
|
6
6
|
}) => void;
|
@@ -1,11 +1,16 @@
|
|
1
|
+
import { getShadowRoot } from "../dom.js";
|
1
2
|
const pseudoFocusAttribute = "data-rs-focus";
|
2
3
|
export const focusableSelector = 'a,button,input:not([type="hidden"]),textarea,select,details,[tabindex]:not([tabindex="-1"])';
|
3
|
-
export const getActiveElement = () => {
|
4
|
-
const
|
5
|
-
|
4
|
+
export const getActiveElement = (originEl) => {
|
5
|
+
const shadowRoot = originEl ? getShadowRoot(originEl) : null;
|
6
|
+
const rootEl = shadowRoot ?? document;
|
7
|
+
const pseudoFocusedEl = rootEl.querySelector(`[${pseudoFocusAttribute}]`);
|
8
|
+
return (pseudoFocusedEl || rootEl.activeElement);
|
6
9
|
};
|
7
10
|
export const focusElement = (el, options) => {
|
8
|
-
|
11
|
+
const shadowRoot = getShadowRoot(el);
|
12
|
+
const rootEl = shadowRoot ?? document;
|
13
|
+
rootEl.querySelector(`[${pseudoFocusAttribute}]`)?.removeAttribute(pseudoFocusAttribute);
|
9
14
|
if (options?.pseudoFocus) {
|
10
15
|
el.setAttribute(pseudoFocusAttribute, "true");
|
11
16
|
}
|
@@ -59,7 +64,7 @@ export const getFocusData = (args) => {
|
|
59
64
|
const { root, target, options } = args;
|
60
65
|
const focusable = getFocusableElements(root, { additionalElement: options?.additionalElement });
|
61
66
|
const focusableLimit = focusable.length - 1;
|
62
|
-
const currentElement = getActiveElement();
|
67
|
+
const currentElement = getActiveElement(root);
|
63
68
|
const currentIndex = focusable.indexOf(currentElement);
|
64
69
|
const positions = {
|
65
70
|
next: currentIndex + 1,
|
package/dist/utilities/dom.d.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
export declare const getClosestFlyoutTarget: (el: HTMLElement | null) => HTMLElement;
|
1
|
+
export declare const getClosestFlyoutTarget: (el: HTMLElement | null, iteration?: number) => HTMLElement;
|
2
2
|
export declare const disableUserSelect: () => void;
|
3
3
|
export declare const enableUserSelect: () => void;
|
4
4
|
export declare const disableScroll: () => void;
|
5
5
|
export declare const enableScroll: () => void;
|
6
|
+
export declare const getShadowRoot: (el: HTMLElement | null) => ShadowRoot | null;
|
package/dist/utilities/dom.js
CHANGED
@@ -1,14 +1,20 @@
|
|
1
|
-
export const getClosestFlyoutTarget = (el) => {
|
1
|
+
export const getClosestFlyoutTarget = (el, iteration = 0) => {
|
2
2
|
const style = el && window.getComputedStyle(el);
|
3
3
|
const overflowY = style?.overflowY;
|
4
4
|
const position = style?.position;
|
5
5
|
const isScrollable = overflowY?.includes("scroll");
|
6
6
|
const isFixed = position === "fixed" || position === "sticky";
|
7
|
+
// Only check shadow root on the first run
|
8
|
+
if (iteration === 0) {
|
9
|
+
const shadowRoot = getShadowRoot(el);
|
10
|
+
if (shadowRoot?.firstElementChild)
|
11
|
+
return shadowRoot.firstElementChild;
|
12
|
+
}
|
7
13
|
if (el === document.body || !el)
|
8
14
|
return document.body;
|
9
15
|
if ((isScrollable && el.scrollHeight > el.clientHeight) || isFixed)
|
10
16
|
return el;
|
11
|
-
return getClosestFlyoutTarget(el.parentElement);
|
17
|
+
return getClosestFlyoutTarget(el.parentElement, iteration + 1);
|
12
18
|
};
|
13
19
|
export const disableUserSelect = () => {
|
14
20
|
document.body.style.userSelect = "none";
|
@@ -25,3 +31,7 @@ export const enableScroll = () => {
|
|
25
31
|
window.removeEventListener("wheel", preventDefault);
|
26
32
|
window.removeEventListener("touchmove", preventDefault);
|
27
33
|
};
|
34
|
+
export const getShadowRoot = (el) => {
|
35
|
+
const rootNode = el?.getRootNode();
|
36
|
+
return rootNode instanceof ShadowRoot ? rootNode : null;
|
37
|
+
};
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "reshaped",
|
3
3
|
"description": "Professionally crafted design system in React & Figma for building products of any scale and complexity",
|
4
|
-
"version": "3.1.
|
4
|
+
"version": "3.1.6",
|
5
5
|
"license": "MIT",
|
6
6
|
"email": "hello@reshaped.so",
|
7
7
|
"homepage": "https://reshaped.so",
|
@@ -93,31 +93,31 @@
|
|
93
93
|
"defaults and not IE 11"
|
94
94
|
],
|
95
95
|
"devDependencies": {
|
96
|
-
"@commitlint/cli": "19.
|
97
|
-
"@commitlint/config-conventional": "19.
|
98
|
-
"@commitlint/types": "19.0
|
99
|
-
"@eslint/js": "
|
100
|
-
"@size-limit/preset-big-lib": "11.1.
|
101
|
-
"@storybook/addon-a11y": "8.
|
102
|
-
"@storybook/addon-controls": "8.
|
103
|
-
"@storybook/addon-docs": "8.
|
104
|
-
"@storybook/addon-storysource": "8.
|
105
|
-
"@storybook/react": "8.
|
106
|
-
"@storybook/react-vite": "8.
|
96
|
+
"@commitlint/cli": "19.5.0",
|
97
|
+
"@commitlint/config-conventional": "19.5.0",
|
98
|
+
"@commitlint/types": "19.5.0",
|
99
|
+
"@eslint/js": "9.11.1",
|
100
|
+
"@size-limit/preset-big-lib": "11.1.5",
|
101
|
+
"@storybook/addon-a11y": "8.3.4",
|
102
|
+
"@storybook/addon-controls": "8.3.4",
|
103
|
+
"@storybook/addon-docs": "8.3.4",
|
104
|
+
"@storybook/addon-storysource": "8.3.4",
|
105
|
+
"@storybook/react": "8.3.4",
|
106
|
+
"@storybook/react-vite": "8.3.4",
|
107
107
|
"@testing-library/dom": "10.4.0",
|
108
|
-
"@testing-library/jest-dom": "6.
|
109
|
-
"@testing-library/react": "16.0.
|
108
|
+
"@testing-library/jest-dom": "6.5.0",
|
109
|
+
"@testing-library/react": "16.0.1",
|
110
110
|
"@testing-library/user-event": "14.5.2",
|
111
111
|
"@types/culori": "2.1.1",
|
112
112
|
"@types/events": "3.0.3",
|
113
|
-
"@types/jest": "29.5.
|
114
|
-
"@types/node": "22.
|
115
|
-
"@types/react": "18.3.
|
113
|
+
"@types/jest": "29.5.13",
|
114
|
+
"@types/node": "22.7.4",
|
115
|
+
"@types/react": "18.3.10",
|
116
116
|
"@types/react-dom": "18.3.0",
|
117
117
|
"@typescript-eslint/eslint-plugin": "7.6.0",
|
118
118
|
"@typescript-eslint/parser": "7.6.0",
|
119
119
|
"@vitejs/plugin-react": "4.3.1",
|
120
|
-
"chromatic": "11.
|
120
|
+
"chromatic": "11.10.4",
|
121
121
|
"cz-conventional-changelog": "3.3.0",
|
122
122
|
"eslint": "8.56.0",
|
123
123
|
"eslint-config-airbnb-typescript": "17.1.0",
|
@@ -127,30 +127,31 @@
|
|
127
127
|
"eslint-plugin-prettier": "5.1.3",
|
128
128
|
"eslint-plugin-react": "7.33.2",
|
129
129
|
"eslint-plugin-react-hooks": "4.6.0",
|
130
|
-
"globals": "
|
130
|
+
"globals": "15.9.0",
|
131
131
|
"identity-obj-proxy": "3.0.0",
|
132
132
|
"jest": "29.7.0",
|
133
133
|
"jest-environment-jsdom": "29.7.0",
|
134
134
|
"jest-matchmedia-mock": "1.1.0",
|
135
|
-
"lefthook": "1.7.
|
136
|
-
"postcss": "8.4.
|
135
|
+
"lefthook": "1.7.17",
|
136
|
+
"postcss": "8.4.47",
|
137
137
|
"postcss-cli": "11.0.0",
|
138
138
|
"postcss-each": "1.1.0",
|
139
139
|
"postcss-nested": "6.2.0",
|
140
140
|
"prettier": "3.3.3",
|
141
141
|
"react": "18.3.1",
|
142
142
|
"react-dom": "18.3.1",
|
143
|
-
"
|
144
|
-
"
|
145
|
-
"
|
146
|
-
"
|
143
|
+
"react-shadow": "20.5.0",
|
144
|
+
"resolve-tspaths": "0.8.22",
|
145
|
+
"size-limit": "11.1.5",
|
146
|
+
"storybook": "8.3.4",
|
147
|
+
"stylelint": "16.9.0",
|
147
148
|
"stylelint-config-prettier": "9.0.5",
|
148
149
|
"stylelint-config-standard": "36.0.1",
|
149
|
-
"ts-jest": "29.2.
|
150
|
+
"ts-jest": "29.2.5",
|
150
151
|
"ts-node": "10.9.2",
|
151
|
-
"typescript": "5.
|
152
|
-
"typescript-eslint": "
|
153
|
-
"vite": "5.4.
|
152
|
+
"typescript": "5.6.2",
|
153
|
+
"typescript-eslint": "8.7.0",
|
154
|
+
"vite": "5.4.8",
|
154
155
|
"vite-tsconfig-paths": "4.3.2"
|
155
156
|
},
|
156
157
|
"peerDependencies": {
|
@@ -163,6 +164,7 @@
|
|
163
164
|
"chalk": "4.1.2",
|
164
165
|
"commander": "11.1.0",
|
165
166
|
"cssnano": "7.0.5",
|
167
|
+
"csstype": "^3.1.3",
|
166
168
|
"culori": "4.0.1",
|
167
169
|
"postcss-custom-media": "11.0.0"
|
168
170
|
},
|