reshaped 3.9.0-canary.9 → 3.9.1-canary.2
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/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +2 -0
- package/dist/bundle.js +2 -2
- package/dist/components/Accordion/AccordionControlled.js +0 -1
- package/dist/components/Actionable/Actionable.d.ts +8 -3
- package/dist/components/Actionable/Actionable.js +17 -70
- package/dist/components/Actionable/Actionable.module.css +1 -1
- package/dist/components/Actionable/Actionable.types.d.ts +2 -36
- package/dist/components/Actionable/index.d.ts +2 -1
- package/dist/components/Badge/Badge.js +2 -2
- package/dist/components/Badge/Badge.module.css +1 -1
- package/dist/components/Badge/Badge.types.d.ts +1 -1
- package/dist/components/Button/Button.module.css +1 -1
- package/dist/components/Calendar/Calendar.module.css +1 -1
- package/dist/components/Calendar/Calendar.utils.js +6 -7
- package/dist/components/Card/Card.d.ts +2 -2
- package/dist/components/Card/Card.types.d.ts +5 -5
- package/dist/components/Carousel/Carousel.js +0 -1
- package/dist/components/Flyout/Flyout.constants.d.ts +1 -0
- package/dist/components/Flyout/Flyout.constants.js +1 -0
- package/dist/components/Flyout/Flyout.module.css +1 -1
- package/dist/components/Flyout/Flyout.types.d.ts +10 -8
- package/dist/components/Flyout/FlyoutContent.js +4 -49
- package/dist/components/Flyout/FlyoutControlled.js +94 -76
- package/dist/components/Flyout/FlyoutTrigger.js +3 -3
- package/dist/components/Flyout/useFlyout.d.ts +3 -4
- package/dist/components/Flyout/useFlyout.js +70 -88
- package/dist/components/Flyout/utilities/safeArea.d.ts +10 -0
- package/dist/components/Flyout/utilities/safeArea.js +100 -0
- package/dist/components/Grid/Grid.types.d.ts +4 -4
- package/dist/components/HiddenInput/HiddenInput.js +2 -3
- package/dist/components/Image/Image.js +1 -1
- package/dist/components/Modal/Modal.js +0 -3
- package/dist/components/Popover/Popover.module.css +1 -1
- package/dist/components/Reshaped/Reshaped.css +1 -1
- package/dist/components/ScrollArea/ScrollArea.js +6 -6
- package/dist/components/Select/Select.js +1 -1
- package/dist/components/Select/SelectCustomControlled.js +0 -1
- package/dist/components/Slider/SliderControlled.js +5 -4
- package/dist/components/Tabs/Tabs.module.css +1 -1
- package/dist/components/Tabs/Tabs.types.d.ts +3 -1
- package/dist/components/Tabs/TabsContext.d.ts +1 -0
- package/dist/components/Tabs/TabsControlled.js +2 -2
- package/dist/components/Tabs/TabsItem.js +2 -2
- package/dist/components/Tabs/TabsList.js +9 -5
- package/dist/components/Tabs/TabsPanel.js +1 -1
- package/dist/components/Text/Text.d.ts +1 -1
- package/dist/components/Text/Text.types.d.ts +3 -3
- package/dist/components/Toast/ToastContainer.js +0 -1
- package/dist/components/Tooltip/Tooltip.js +2 -2
- package/dist/components/Tooltip/Tooltip.module.css +1 -1
- package/dist/components/Tooltip/Tooltip.types.d.ts +1 -1
- package/dist/components/View/View.types.d.ts +4 -4
- package/dist/components/_private/Expandable/Expandable.js +1 -3
- package/dist/components/_private/Portal/Portal.js +0 -3
- package/dist/core/Actionable/Actionable.d.ts +4 -0
- package/dist/core/Actionable/Actionable.js +73 -0
- package/dist/core/Actionable/Actionable.types.d.ts +34 -0
- package/dist/core/Actionable/Actionable.types.js +1 -0
- package/dist/core/Actionable/index.d.ts +2 -0
- package/dist/core/Actionable/index.js +1 -0
- package/dist/hooks/_private/useDrag.js +0 -3
- package/dist/hooks/_private/usePrevious.js +0 -1
- package/dist/hooks/useOnClickOutside.js +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/types/global.d.ts +1 -1
- package/dist/utilities/a11y/TrapFocus.js +9 -3
- package/dist/utilities/dom/index.d.ts +0 -2
- package/dist/utilities/dom/index.js +0 -2
- package/dist/utilities/scroll/disable.js +4 -2
- package/package.json +7 -99
- package/README.md +0 -24
- package/dist/components/Flyout/utilities/calculatePosition.d.ts +0 -31
- package/dist/components/Flyout/utilities/calculatePosition.js +0 -178
- package/dist/components/Flyout/utilities/flyout.d.ts +0 -11
- package/dist/components/Flyout/utilities/flyout.js +0 -87
- package/dist/components/Flyout/utilities/getPositionFallbacks.d.ts +0 -3
- package/dist/components/Flyout/utilities/getPositionFallbacks.js +0 -39
- package/dist/components/Flyout/utilities/helpers.d.ts +0 -7
- package/dist/components/Flyout/utilities/helpers.js +0 -14
- package/dist/components/Flyout/utilities/isFullyVisible.d.ts +0 -12
- package/dist/components/Flyout/utilities/isFullyVisible.js +0 -22
- package/dist/utilities/dom/flyout.d.ts +0 -2
- package/dist/utilities/dom/flyout.js +0 -14
- package/dist/utilities/dom/userSelect.d.ts +0 -2
- package/dist/utilities/dom/userSelect.js +0 -6
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import * as keys from "../../constants/keys.js";
|
|
5
|
+
import { classNames } from "../../utilities/props.js";
|
|
6
|
+
const Actionable = forwardRef((props, ref) => {
|
|
7
|
+
const { children, render, href, onClick, type, disabled, as, stopPropagation, className, attributes, } = props;
|
|
8
|
+
const rootAttributes = { ...attributes };
|
|
9
|
+
const hasClickHandler = onClick || attributes?.onClick;
|
|
10
|
+
const hasFocusHandler = attributes?.onFocus || attributes?.onBlur;
|
|
11
|
+
const isLink = Boolean(href || attributes?.href);
|
|
12
|
+
// Including attributes ref for the cases when event listeners are added through it
|
|
13
|
+
// To make sure it doesn't render a span
|
|
14
|
+
const isButton = Boolean(hasClickHandler || hasFocusHandler || type || attributes?.ref);
|
|
15
|
+
const renderedAsButton = !isLink && isButton && (!as || as === "button");
|
|
16
|
+
// Using any here to let TS save on type resolving, otherwise TS throws an error due to the type complexity
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
|
+
let TagName;
|
|
19
|
+
if (isLink) {
|
|
20
|
+
TagName = "a";
|
|
21
|
+
rootAttributes.href = disabled ? undefined : href || attributes?.href;
|
|
22
|
+
}
|
|
23
|
+
else if (renderedAsButton) {
|
|
24
|
+
TagName = "button";
|
|
25
|
+
rootAttributes.type = type || attributes?.type || "button";
|
|
26
|
+
rootAttributes.disabled = disabled || attributes?.disabled;
|
|
27
|
+
}
|
|
28
|
+
else if (isButton) {
|
|
29
|
+
const isFocusable = as === "label";
|
|
30
|
+
const simulateButton = !isFocusable || hasClickHandler || hasFocusHandler;
|
|
31
|
+
TagName = as || "span";
|
|
32
|
+
rootAttributes.role = simulateButton ? "button" : undefined;
|
|
33
|
+
rootAttributes.tabIndex = simulateButton ? 0 : undefined;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
TagName = as || "span";
|
|
37
|
+
}
|
|
38
|
+
const handlePress = (event) => {
|
|
39
|
+
if (disabled)
|
|
40
|
+
return;
|
|
41
|
+
if (stopPropagation)
|
|
42
|
+
event.stopPropagation();
|
|
43
|
+
onClick?.(event);
|
|
44
|
+
attributes?.onClick?.(event);
|
|
45
|
+
};
|
|
46
|
+
const handleKeyDown = (event) => {
|
|
47
|
+
const isSpace = event.key === keys.SPACE;
|
|
48
|
+
const isEnter = event.key === keys.ENTER;
|
|
49
|
+
if (!isSpace && !isEnter)
|
|
50
|
+
return;
|
|
51
|
+
if (rootAttributes.role !== "button")
|
|
52
|
+
return;
|
|
53
|
+
if (stopPropagation)
|
|
54
|
+
event.stopPropagation();
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
handlePress(event);
|
|
57
|
+
};
|
|
58
|
+
const tagAttributes = {
|
|
59
|
+
ref: ref,
|
|
60
|
+
// rootAttributes can receive ref from Flyout
|
|
61
|
+
...rootAttributes,
|
|
62
|
+
className: classNames(className),
|
|
63
|
+
onClick: handlePress,
|
|
64
|
+
onKeyDown: handleKeyDown,
|
|
65
|
+
"aria-disabled": disabled ? true : undefined,
|
|
66
|
+
children: children,
|
|
67
|
+
};
|
|
68
|
+
if (render)
|
|
69
|
+
return render(tagAttributes);
|
|
70
|
+
return _jsx(TagName, { ...tagAttributes });
|
|
71
|
+
});
|
|
72
|
+
Actionable.displayName = "Actionable";
|
|
73
|
+
export default Actionable;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
import type * as G from "../../types/global";
|
|
3
|
+
export type AttributesRef = React.RefObject<HTMLButtonElement | null>;
|
|
4
|
+
type Attributes = G.Attributes<"button"> & Omit<React.JSX.IntrinsicElements["a"], keyof G.Attributes<"button">> & {
|
|
5
|
+
ref?: AttributesRef;
|
|
6
|
+
};
|
|
7
|
+
export type RenderAttributes = G.Attributes<"a"> & {
|
|
8
|
+
ref: React.RefObject<HTMLAnchorElement | null>;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
};
|
|
11
|
+
export type Props = {
|
|
12
|
+
/** Node for inserting the content */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
/** Render a custom root element, useful for integrating with routers */
|
|
15
|
+
render?: (attributes: RenderAttributes) => React.ReactNode;
|
|
16
|
+
/** Callback when clicked, renders it as a button tag if href is not provided */
|
|
17
|
+
onClick?: (e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) => void;
|
|
18
|
+
/** URL, renders it as an anchor tag */
|
|
19
|
+
href?: string;
|
|
20
|
+
/** Type attribute, renders it as a button tag */
|
|
21
|
+
type?: React.ButtonHTMLAttributes<HTMLButtonElement>["type"];
|
|
22
|
+
/** Disable from user interaction */
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
/** Prevent the event from bubbling up to the parent */
|
|
25
|
+
stopPropagation?: boolean;
|
|
26
|
+
/** Render as a different element */
|
|
27
|
+
as?: keyof React.JSX.IntrinsicElements;
|
|
28
|
+
/** Additional classname for the root element */
|
|
29
|
+
className?: G.ClassName;
|
|
30
|
+
/** Additional attributes for the root element */
|
|
31
|
+
attributes?: Attributes;
|
|
32
|
+
};
|
|
33
|
+
export type Ref = HTMLButtonElement | HTMLAnchorElement;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./Actionable.js";
|
|
@@ -4,7 +4,6 @@ import * as keys from "../../constants/keys.js";
|
|
|
4
4
|
import useHandlerRef from "../useHandlerRef.js";
|
|
5
5
|
import useHotkeys from "../useHotkeys.js";
|
|
6
6
|
import useToggle from "../useToggle.js";
|
|
7
|
-
import { disableUserSelect, enableUserSelect } from "../../utilities/dom/index.js";
|
|
8
7
|
import { disableScroll, enableScroll } from "../../utilities/scroll/index.js";
|
|
9
8
|
const useDrag = (cb, options) => {
|
|
10
9
|
const { disabled, containerRef: passedContainerRef, orientation = "all" } = options || {};
|
|
@@ -76,7 +75,6 @@ const useDrag = (cb, options) => {
|
|
|
76
75
|
const handleDragEnd = () => {
|
|
77
76
|
triggerCompensationRef.current = { x: 0, y: 0 };
|
|
78
77
|
toggle.deactivate();
|
|
79
|
-
enableUserSelect();
|
|
80
78
|
enableScroll();
|
|
81
79
|
};
|
|
82
80
|
document.addEventListener("touchmove", handleDrag, { passive: true });
|
|
@@ -103,7 +101,6 @@ const useDrag = (cb, options) => {
|
|
|
103
101
|
y: resolvedEvent.clientY - triggerRect.y,
|
|
104
102
|
};
|
|
105
103
|
toggle.activate();
|
|
106
|
-
disableUserSelect();
|
|
107
104
|
disableScroll();
|
|
108
105
|
};
|
|
109
106
|
triggerEl.addEventListener("touchstart", handleStart, { passive: true });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import * as keys from "../constants/keys.js";
|
|
2
3
|
import useHandlerRef from "./useHandlerRef.js";
|
|
3
4
|
const useOnClickOutside = (refs, handler, options) => {
|
|
4
5
|
const { disabled } = options || {};
|
|
@@ -25,11 +26,18 @@ const useOnClickOutside = (refs, handler, options) => {
|
|
|
25
26
|
}
|
|
26
27
|
});
|
|
27
28
|
};
|
|
29
|
+
const handleKeyDown = (event) => {
|
|
30
|
+
if (![keys.ENTER, keys.SPACE].includes(event.key))
|
|
31
|
+
return;
|
|
32
|
+
handleMouseDown(event);
|
|
33
|
+
};
|
|
28
34
|
document.addEventListener("mousedown", handleMouseDown, { passive: true });
|
|
29
35
|
document.addEventListener("touchstart", handleMouseDown, { passive: true });
|
|
36
|
+
document.addEventListener("keydown", handleKeyDown, { passive: true });
|
|
30
37
|
return () => {
|
|
31
38
|
document.removeEventListener("mousedown", handleMouseDown);
|
|
32
39
|
document.removeEventListener("touchstart", handleMouseDown);
|
|
40
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
33
41
|
};
|
|
34
42
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35
43
|
}, [...refs]);
|
package/dist/index.d.ts
CHANGED
|
@@ -110,6 +110,8 @@ export { default as Grid } from "./components/Grid";
|
|
|
110
110
|
export type { GridProps, GridItemProps } from "./components/Grid";
|
|
111
111
|
export { default as Hidden } from "./components/Hidden";
|
|
112
112
|
export type { HiddenProps } from "./components/Hidden";
|
|
113
|
+
export { default as HiddenInput } from "./components/HiddenInput";
|
|
114
|
+
export type { HiddenInputProps } from "./components/HiddenInput";
|
|
113
115
|
export { default as HiddenVisually } from "./components/HiddenVisually";
|
|
114
116
|
export type { HiddenVisuallyProps } from "./components/HiddenVisually";
|
|
115
117
|
export { default as Icon } from "./components/Icon";
|
package/dist/index.js
CHANGED
|
@@ -57,6 +57,7 @@ export { default as Flyout } from "./components/Flyout/index.js";
|
|
|
57
57
|
export { default as FormControl } from "./components/FormControl/index.js";
|
|
58
58
|
export { default as Grid } from "./components/Grid/index.js";
|
|
59
59
|
export { default as Hidden } from "./components/Hidden/index.js";
|
|
60
|
+
export { default as HiddenInput } from "./components/HiddenInput/index.js";
|
|
60
61
|
export { default as HiddenVisually } from "./components/HiddenVisually/index.js";
|
|
61
62
|
export { default as Icon } from "./components/Icon/index.js";
|
|
62
63
|
export { default as Image } from "./components/Image/index.js";
|
package/dist/types/global.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export type ClassName = ClassNameValue | ClassNameValue[] | ClassName[];
|
|
|
7
7
|
export type CSSVariable = `--${string}`;
|
|
8
8
|
export type StyleAttribute = React.CSSProperties | (React.CSSProperties & Record<CSSVariable, string | number | undefined>);
|
|
9
9
|
type DataAttributes = object | Record<`data-${string}`, string | boolean>;
|
|
10
|
-
export type Attributes<TagName extends keyof React.JSX.IntrinsicElements =
|
|
10
|
+
export type Attributes<TagName extends keyof React.JSX.IntrinsicElements | void = void> = (TagName extends keyof React.JSX.IntrinsicElements ? React.JSX.IntrinsicElements[TagName] : React.HTMLAttributes<HTMLElement>) & DataAttributes & {
|
|
11
11
|
style?: StyleAttribute;
|
|
12
12
|
};
|
|
13
13
|
export type Viewport = "s" | "m" | "l" | "xl";
|
|
@@ -80,6 +80,10 @@ class TrapFocus {
|
|
|
80
80
|
const el = shadowRoot ?? document;
|
|
81
81
|
el.removeEventListener("keydown", this.#handleKeyDown);
|
|
82
82
|
};
|
|
83
|
+
#isLast = () => {
|
|
84
|
+
const tailItem = _a.chain.tailId && _a.chain.get(_a.chain.tailId);
|
|
85
|
+
return tailItem && tailItem.data.#root === this.#root;
|
|
86
|
+
};
|
|
83
87
|
/**
|
|
84
88
|
* Trap the focus, add observer and keyboard event listeners
|
|
85
89
|
* and create a chain item
|
|
@@ -98,6 +102,8 @@ class TrapFocus {
|
|
|
98
102
|
this.#mutationObserver = new MutationObserver(() => {
|
|
99
103
|
if (!this.#root)
|
|
100
104
|
return;
|
|
105
|
+
if (!this.#isLast())
|
|
106
|
+
return;
|
|
101
107
|
const currentActiveElement = getActiveElement(this.#root);
|
|
102
108
|
// Focus stayed inside the wrapper, no need to refocus
|
|
103
109
|
if (this.#root.contains(currentActiveElement))
|
|
@@ -117,10 +123,10 @@ class TrapFocus {
|
|
|
117
123
|
this.#addListeners();
|
|
118
124
|
if (mode === "dialog")
|
|
119
125
|
this.#screenReaderTrap.trap();
|
|
120
|
-
// Don't add back to the chain if we're traversing back
|
|
121
|
-
const tailItem = _a.chain.tailId && _a.chain.get(_a.chain.tailId);
|
|
122
126
|
const currentActiveElement = getActiveElement(this.#root);
|
|
123
|
-
|
|
127
|
+
const isLastInChain = this.#isLast();
|
|
128
|
+
// Don't add back to the chain if we're traversing back
|
|
129
|
+
if (!isLastInChain) {
|
|
124
130
|
this.#chainId = _a.chain.add(this);
|
|
125
131
|
// If the focus was moved manually (e.g. with autoFocus) - keep it there
|
|
126
132
|
if (!this.#root.contains(currentActiveElement)) {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export { getRectFromCoordinates } from "./flyout";
|
|
2
1
|
export { getShadowRoot } from "./shadowDom";
|
|
3
|
-
export { enableUserSelect, disableUserSelect } from "./userSelect";
|
|
4
2
|
export { findParent, findClosestScrollableContainer, findClosestPositionContainer } from "./find";
|
|
5
3
|
export { triggerChangeEvent } from "./event";
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export { getRectFromCoordinates } from "./flyout.js";
|
|
2
1
|
export { getShadowRoot } from "./shadowDom.js";
|
|
3
|
-
export { enableUserSelect, disableUserSelect } from "./userSelect.js";
|
|
4
2
|
export { findParent, findClosestScrollableContainer, findClosestPositionContainer } from "./find.js";
|
|
5
3
|
export { triggerChangeEvent } from "./event.js";
|
|
@@ -4,10 +4,12 @@ export const preventDefault = (e) => e.preventDefault();
|
|
|
4
4
|
* without locking the page with overflow
|
|
5
5
|
*/
|
|
6
6
|
export const disableScroll = () => {
|
|
7
|
-
window.addEventListener("wheel", preventDefault);
|
|
8
|
-
window.addEventListener("touchmove", preventDefault);
|
|
7
|
+
window.addEventListener("wheel", preventDefault, { passive: false });
|
|
8
|
+
window.addEventListener("touchmove", preventDefault, { passive: false });
|
|
9
|
+
document.body.style.userSelect = "none";
|
|
9
10
|
};
|
|
10
11
|
export const enableScroll = () => {
|
|
11
12
|
window.removeEventListener("wheel", preventDefault);
|
|
12
13
|
window.removeEventListener("touchmove", preventDefault);
|
|
14
|
+
document.body.style.userSelect = "";
|
|
13
15
|
};
|
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.9.
|
|
4
|
+
"version": "3.9.1-canary.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"email": "hello@reshaped.so",
|
|
7
7
|
"homepage": "https://reshaped.so",
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
],
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
|
23
|
-
"url": "https://github.com/reshaped-ui/reshaped.git"
|
|
23
|
+
"url": "https://github.com/reshaped-ui/reshaped.git",
|
|
24
|
+
"directory": "packages/reshaped"
|
|
24
25
|
},
|
|
25
26
|
"bugs": {
|
|
26
27
|
"url": "https://github.com/reshaped-ui/reshaped/issues"
|
|
@@ -77,107 +78,24 @@
|
|
|
77
78
|
"browserslist": [
|
|
78
79
|
"defaults and not IE 11"
|
|
79
80
|
],
|
|
80
|
-
"devDependencies": {
|
|
81
|
-
"@changesets/cli": "2.29.7",
|
|
82
|
-
"@commitlint/cli": "20.1.0",
|
|
83
|
-
"@commitlint/config-conventional": "20.0.0",
|
|
84
|
-
"@commitlint/types": "20.0.0",
|
|
85
|
-
"@eslint/js": "9.38.0",
|
|
86
|
-
"@size-limit/preset-big-lib": "11.2.0",
|
|
87
|
-
"@storybook/addon-a11y": "10.0.0",
|
|
88
|
-
"@storybook/addon-docs": "10.0.0",
|
|
89
|
-
"@storybook/addon-vitest": "10.0.0",
|
|
90
|
-
"@storybook/react": "10.0.0",
|
|
91
|
-
"@storybook/react-vite": "10.0.0",
|
|
92
|
-
"@testing-library/user-event": "14.6.1",
|
|
93
|
-
"@types/culori": "4.0.1",
|
|
94
|
-
"@types/events": "3.0.3",
|
|
95
|
-
"@types/node": "24.9.2",
|
|
96
|
-
"@types/react": "19.2.2",
|
|
97
|
-
"@types/react-dom": "19.2.2",
|
|
98
|
-
"@vitejs/plugin-react": "5.1.0",
|
|
99
|
-
"@vitest/browser": "4.0.4",
|
|
100
|
-
"@vitest/browser-playwright": "4.0.4",
|
|
101
|
-
"@vitest/coverage-istanbul": "4.0.4",
|
|
102
|
-
"@vitest/coverage-v8": "4.0.4",
|
|
103
|
-
"chromatic": "13.3.2",
|
|
104
|
-
"eslint": "9.38.0",
|
|
105
|
-
"eslint-config-prettier": "10.1.8",
|
|
106
|
-
"eslint-import-resolver-typescript": "^4.4.4",
|
|
107
|
-
"eslint-plugin-import": "2.32.0",
|
|
108
|
-
"eslint-plugin-jsx-a11y": "6.10.2",
|
|
109
|
-
"eslint-plugin-prettier": "5.5.4",
|
|
110
|
-
"eslint-plugin-react": "7.37.5",
|
|
111
|
-
"eslint-plugin-react-hooks": "7.0.1",
|
|
112
|
-
"lefthook": "2.0.1",
|
|
113
|
-
"playwright": "1.56.1",
|
|
114
|
-
"postcss": "8.5.6",
|
|
115
|
-
"postcss-cli": "11.0.1",
|
|
116
|
-
"postcss-each": "1.1.0",
|
|
117
|
-
"postcss-nested": "7.0.2",
|
|
118
|
-
"prettier": "3.6.2",
|
|
119
|
-
"react": "18",
|
|
120
|
-
"react-dom": "18",
|
|
121
|
-
"react-shadow": "20.6.0",
|
|
122
|
-
"resolve-tspaths": "0.8.23",
|
|
123
|
-
"size-limit": "11.2.0",
|
|
124
|
-
"storybook": "10.0.0",
|
|
125
|
-
"stylelint": "16.25.0",
|
|
126
|
-
"stylelint-config-prettier": "9.0.5",
|
|
127
|
-
"stylelint-config-standard": "39.0.1",
|
|
128
|
-
"ts-node": "10.9.2",
|
|
129
|
-
"typescript": "5.9.3",
|
|
130
|
-
"typescript-eslint": "8.46.2",
|
|
131
|
-
"vite": "7.1.12",
|
|
132
|
-
"vite-tsconfig-paths": "5.1.4",
|
|
133
|
-
"vitest": "4.0.4",
|
|
134
|
-
"vitest-browser-react": "2.0.2"
|
|
135
|
-
},
|
|
136
81
|
"peerDependencies": {
|
|
137
82
|
"postcss": "^8",
|
|
138
83
|
"react": "^18 || ^19",
|
|
139
84
|
"react-dom": "^18 || ^19"
|
|
140
85
|
},
|
|
141
86
|
"dependencies": {
|
|
142
|
-
"@changesets/changelog-github": "0.5.1",
|
|
143
87
|
"@csstools/postcss-global-data": "3.1.0",
|
|
144
88
|
"chalk": "4.1.2",
|
|
145
89
|
"commander": "14.0.2",
|
|
146
90
|
"cssnano": "7.1.1",
|
|
147
91
|
"csstype": "3.1.3",
|
|
148
92
|
"culori": "4.0.2",
|
|
149
|
-
"postcss-custom-media": "11.0.6"
|
|
150
|
-
|
|
151
|
-
"size-limit": [
|
|
152
|
-
{
|
|
153
|
-
"name": "Library / JS",
|
|
154
|
-
"path": "dist/bundle.js",
|
|
155
|
-
"webpack": false
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"name": "Library / CSS",
|
|
159
|
-
"path": "dist/bundle.css",
|
|
160
|
-
"webpack": false
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
"name": "Theming / JS",
|
|
164
|
-
"path": "dist/tests/themingWithoutDefinition.js",
|
|
165
|
-
"webpack": true
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
"name": "Theming with a default theme definition / JS",
|
|
169
|
-
"path": "dist/tests/themingWithDefinition.js",
|
|
170
|
-
"webpack": true
|
|
171
|
-
}
|
|
172
|
-
],
|
|
173
|
-
"engines": {
|
|
174
|
-
"node": ">=22"
|
|
93
|
+
"postcss-custom-media": "11.0.6",
|
|
94
|
+
"@reshaped/utilities": "3.9.1-canary.2"
|
|
175
95
|
},
|
|
176
96
|
"scripts": {
|
|
177
|
-
"dev": "storybook dev -p 3001 --disable-telemetry",
|
|
178
97
|
"clean": "sh ./bin/clean.sh",
|
|
179
|
-
"
|
|
180
|
-
"changeset": "changeset",
|
|
98
|
+
"dev": "storybook dev -p 3001 -c ../../.storybook --disable-telemetry",
|
|
181
99
|
"build": "pnpm clean && pnpm build:esm && pnpm build:css && pnpm build:bundle",
|
|
182
100
|
"build:themes": "node bin/cli.js theming --config dist/cli/theming/reshaped.config.js --output src/themes",
|
|
183
101
|
"build:esm": "tsc -p tsconfig.esm.json && resolve-tspaths -p tsconfig.esm.json",
|
|
@@ -185,19 +103,9 @@
|
|
|
185
103
|
"build:stories": "tsc -p tsconfig.stories.json && resolve-tspaths -p tsconfig.stories.json",
|
|
186
104
|
"build:bundle": "vite build && cp dist/index.d.ts dist/bundle.d.ts",
|
|
187
105
|
"build:size": "pnpm clean && pnpm build:esm && pnpm build:bundle",
|
|
188
|
-
"build:storybook": "storybook build -o dist/app --disable-telemetry",
|
|
189
|
-
"build:chromatic": "STORYBOOK_ENV=chromatic storybook build",
|
|
190
|
-
"release": "sh ./bin/release.sh",
|
|
191
|
-
"release:canary": "sh ./bin/release-canary.sh",
|
|
192
106
|
"release:local": "pnpm build && pnpm pack --out reshaped-local.tgz",
|
|
193
|
-
"chromatic": "chromatic -b build:chromatic --project-token=$(cat .chromatic)",
|
|
194
|
-
"test:vrt": "pnpm chromatic",
|
|
195
|
-
"test:vrt:turbo": "pnpm chromatic --only-changed",
|
|
196
107
|
"test:browser": "vitest run --project=storybook",
|
|
197
108
|
"test:unit": "vitest run --project=unit",
|
|
198
|
-
"test:size": "size-limit"
|
|
199
|
-
"lint": "pnpm lint:js && pnpm lint:css",
|
|
200
|
-
"lint:js": "eslint './src/**/*.{ts,tsx}' --fix",
|
|
201
|
-
"lint:css": "stylelint 'src/**/*.css'"
|
|
109
|
+
"test:size": "size-limit"
|
|
202
110
|
}
|
|
203
111
|
}
|
package/README.md
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Reshaped
|
|
2
|
-
|
|
3
|
-
<img width="2400" height="1260" alt="3 0 (1)" src="https://github.com/user-attachments/assets/ef632fe9-9446-430f-b87d-bebebe6fb595" />
|
|
4
|
-
<br /><br />
|
|
5
|
-
|
|
6
|
-
Reshaped is a library with professionally crafted React & Figma components for building beautiful products or starting your own design system.
|
|
7
|
-
|
|
8
|
-
<br />
|
|
9
|
-
|
|
10
|
-
## Documentation
|
|
11
|
-
|
|
12
|
-
To get started, check out the [Reshaped documentation](https://reshaped.so/docs/getting-started/overview).
|
|
13
|
-
|
|
14
|
-
## Contributing
|
|
15
|
-
|
|
16
|
-
Read our [contribution guide](CONTRIBUTING.md) to learn about our principles, development process and testing.
|
|
17
|
-
|
|
18
|
-
## Maintainers
|
|
19
|
-
|
|
20
|
-
- Dmitry Belyaev, [@blvdmitry](https://x.com/blvdmitry)
|
|
21
|
-
|
|
22
|
-
## License
|
|
23
|
-
|
|
24
|
-
This project is licensed under the terms of the MIT license.
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type * as T from "../Flyout.types";
|
|
2
|
-
/**
|
|
3
|
-
* Calculate styles for the current position
|
|
4
|
-
*/
|
|
5
|
-
declare const calculatePosition: (args: {
|
|
6
|
-
triggerBounds: DOMRect;
|
|
7
|
-
flyoutBounds: {
|
|
8
|
-
width: number;
|
|
9
|
-
height: number;
|
|
10
|
-
};
|
|
11
|
-
passedContainer?: HTMLElement | null;
|
|
12
|
-
containerBounds: DOMRect;
|
|
13
|
-
} & Pick<T.Options, "position" | "rtl" | "width" | "contentGap" | "contentShift" | "fallbackAdjustLayout" | "fallbackMinWidth" | "fallbackMinHeight">) => {
|
|
14
|
-
position: T.Position;
|
|
15
|
-
styles: {
|
|
16
|
-
left: string | null;
|
|
17
|
-
right: string | null;
|
|
18
|
-
top: string | null;
|
|
19
|
-
bottom: string | null;
|
|
20
|
-
transform: string;
|
|
21
|
-
height: string | null;
|
|
22
|
-
width: string | null;
|
|
23
|
-
};
|
|
24
|
-
boundaries: {
|
|
25
|
-
left: number;
|
|
26
|
-
top: number;
|
|
27
|
-
height: number;
|
|
28
|
-
width: number;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
export default calculatePosition;
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
import { getRTLPosition, centerBySize } from "./helpers.js";
|
|
2
|
-
const SCREEN_OFFSET = 8;
|
|
3
|
-
/**
|
|
4
|
-
* Calculate styles for the current position
|
|
5
|
-
*/
|
|
6
|
-
const calculatePosition = (args) => {
|
|
7
|
-
const { triggerBounds, flyoutBounds, containerBounds, position: passedPosition, rtl, width: passedWidth, contentGap = 0, contentShift = 0, passedContainer, fallbackAdjustLayout, fallbackMinWidth, fallbackMinHeight, } = args;
|
|
8
|
-
const isFullWidth = passedWidth === "full" || passedWidth === "100%";
|
|
9
|
-
let left = 0;
|
|
10
|
-
let top = 0;
|
|
11
|
-
let bottom = null;
|
|
12
|
-
let right = null;
|
|
13
|
-
let height = undefined;
|
|
14
|
-
let width = undefined;
|
|
15
|
-
let position = passedPosition;
|
|
16
|
-
if (rtl)
|
|
17
|
-
position = getRTLPosition(position);
|
|
18
|
-
if (isFullWidth || width === "trigger") {
|
|
19
|
-
position = position.includes("top") ? "top" : "bottom";
|
|
20
|
-
}
|
|
21
|
-
const isHorizontalPosition = !!position.match(/^(start|end)/);
|
|
22
|
-
// contentGap adds padding to the flyout to make sure it doesn't disapper while moving the mouse to the content
|
|
23
|
-
// So its width/height is bigger than the visible part of the content
|
|
24
|
-
const flyoutWidth = flyoutBounds.width + (isHorizontalPosition ? contentGap : 0);
|
|
25
|
-
const flyoutHeight = flyoutBounds.height + (!isHorizontalPosition ? contentGap : 0);
|
|
26
|
-
const triggerWidth = triggerBounds.width;
|
|
27
|
-
const triggerHeight = triggerBounds.height;
|
|
28
|
-
// Detect passed container scroll to sync the flyout position with it
|
|
29
|
-
const containerX = passedContainer?.scrollLeft;
|
|
30
|
-
const containerY = passedContainer?.scrollTop;
|
|
31
|
-
const scrollX = containerX ?? window.scrollX;
|
|
32
|
-
const scrollY = containerY ?? window.scrollY;
|
|
33
|
-
const renderContainerHeight = passedContainer?.clientHeight ?? window.innerHeight;
|
|
34
|
-
const renderContainerWidth = passedContainer?.clientWidth ?? window.innerWidth;
|
|
35
|
-
// When rendering in the body, bottom bounds will be larrger than the viewport so we calculate it manually
|
|
36
|
-
const containerBoundsBottom = passedContainer
|
|
37
|
-
? containerBounds.bottom
|
|
38
|
-
: window.innerHeight - scrollY;
|
|
39
|
-
// When inside a container, adjut position based on the container scroll since flyout is rendered outside the scroll area
|
|
40
|
-
const relativeLeft = triggerBounds.left - containerBounds.left + (containerX || 0);
|
|
41
|
-
const relativeRight = containerBounds.right - triggerBounds.right - (containerX || 0);
|
|
42
|
-
const relativeTop = triggerBounds.top - containerBounds.top + (containerY || 0);
|
|
43
|
-
const relativeBottom = containerBoundsBottom - triggerBounds.bottom - (containerY || 0);
|
|
44
|
-
switch (position) {
|
|
45
|
-
case "start":
|
|
46
|
-
case "start-top":
|
|
47
|
-
case "start-bottom":
|
|
48
|
-
left = relativeLeft - flyoutWidth;
|
|
49
|
-
right = relativeRight + triggerWidth;
|
|
50
|
-
break;
|
|
51
|
-
case "end":
|
|
52
|
-
case "end-top":
|
|
53
|
-
case "end-bottom":
|
|
54
|
-
left = relativeLeft + triggerWidth;
|
|
55
|
-
break;
|
|
56
|
-
case "bottom":
|
|
57
|
-
case "top":
|
|
58
|
-
left = relativeLeft + centerBySize(triggerWidth, flyoutWidth) + contentShift;
|
|
59
|
-
break;
|
|
60
|
-
case "top-start":
|
|
61
|
-
case "bottom-start":
|
|
62
|
-
left = relativeLeft + contentShift;
|
|
63
|
-
break;
|
|
64
|
-
case "top-end":
|
|
65
|
-
case "bottom-end":
|
|
66
|
-
left = relativeLeft + triggerWidth - flyoutWidth + contentShift;
|
|
67
|
-
right = relativeRight - contentShift;
|
|
68
|
-
break;
|
|
69
|
-
default:
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
switch (position) {
|
|
73
|
-
case "top":
|
|
74
|
-
case "top-start":
|
|
75
|
-
case "top-end":
|
|
76
|
-
top = relativeTop - flyoutHeight;
|
|
77
|
-
bottom = relativeBottom + triggerHeight;
|
|
78
|
-
break;
|
|
79
|
-
case "bottom":
|
|
80
|
-
case "bottom-start":
|
|
81
|
-
case "bottom-end":
|
|
82
|
-
top = relativeTop + triggerHeight;
|
|
83
|
-
break;
|
|
84
|
-
case "start":
|
|
85
|
-
case "end":
|
|
86
|
-
top = relativeTop + centerBySize(triggerHeight, flyoutHeight) + contentShift;
|
|
87
|
-
break;
|
|
88
|
-
case "start-top":
|
|
89
|
-
case "end-top":
|
|
90
|
-
top = relativeTop + contentShift;
|
|
91
|
-
break;
|
|
92
|
-
case "start-bottom":
|
|
93
|
-
case "end-bottom":
|
|
94
|
-
top = relativeTop + triggerHeight - flyoutHeight + contentShift;
|
|
95
|
-
bottom = relativeBottom - contentShift;
|
|
96
|
-
break;
|
|
97
|
-
default:
|
|
98
|
-
break;
|
|
99
|
-
}
|
|
100
|
-
if (fallbackAdjustLayout) {
|
|
101
|
-
const getOverflow = () => {
|
|
102
|
-
return {
|
|
103
|
-
top: -top + scrollY + SCREEN_OFFSET,
|
|
104
|
-
bottom: top + flyoutHeight + SCREEN_OFFSET - scrollY - renderContainerHeight,
|
|
105
|
-
left: -left + scrollX + SCREEN_OFFSET,
|
|
106
|
-
right: left + flyoutWidth + SCREEN_OFFSET - scrollX - renderContainerWidth,
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
const overflow = getOverflow();
|
|
110
|
-
if (isHorizontalPosition) {
|
|
111
|
-
if (overflow.top > 0) {
|
|
112
|
-
top = SCREEN_OFFSET + scrollY;
|
|
113
|
-
if (bottom !== null)
|
|
114
|
-
bottom = bottom - overflow.top;
|
|
115
|
-
}
|
|
116
|
-
else if (overflow.bottom > 0) {
|
|
117
|
-
top = top - overflow.bottom;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
if (overflow.left > 0) {
|
|
122
|
-
left = SCREEN_OFFSET + scrollX;
|
|
123
|
-
if (right !== null)
|
|
124
|
-
right = right - overflow.left;
|
|
125
|
-
}
|
|
126
|
-
else if (overflow.right > 0) {
|
|
127
|
-
left = left - overflow.right;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
const updatedOverflow = getOverflow();
|
|
131
|
-
if (updatedOverflow.top > 0) {
|
|
132
|
-
height = Math.max(fallbackMinHeight ? parseInt(fallbackMinHeight) : 0, flyoutHeight - updatedOverflow.top);
|
|
133
|
-
top = top + (flyoutHeight - height);
|
|
134
|
-
}
|
|
135
|
-
else if (updatedOverflow.bottom > 0) {
|
|
136
|
-
height = Math.max(fallbackMinHeight ? parseInt(fallbackMinHeight) : 0, flyoutHeight - updatedOverflow.bottom);
|
|
137
|
-
if (bottom !== null)
|
|
138
|
-
bottom = bottom + (flyoutHeight - height);
|
|
139
|
-
}
|
|
140
|
-
if (updatedOverflow.left > 0) {
|
|
141
|
-
width = Math.max(fallbackMinWidth ? parseInt(fallbackMinWidth) : 0, flyoutWidth - updatedOverflow.left);
|
|
142
|
-
left = left + (flyoutWidth - width);
|
|
143
|
-
}
|
|
144
|
-
else if (updatedOverflow.right > 0) {
|
|
145
|
-
width = Math.max(fallbackMinWidth ? parseInt(fallbackMinWidth) : 0, flyoutWidth - updatedOverflow.right);
|
|
146
|
-
if (right !== null)
|
|
147
|
-
right = right + (flyoutWidth - width);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if (isFullWidth) {
|
|
151
|
-
left = SCREEN_OFFSET;
|
|
152
|
-
width = window.innerWidth - SCREEN_OFFSET * 2;
|
|
153
|
-
}
|
|
154
|
-
else if (passedWidth === "trigger") {
|
|
155
|
-
width = triggerBounds.width;
|
|
156
|
-
}
|
|
157
|
-
const translateX = right !== null ? -right : left;
|
|
158
|
-
const translateY = bottom !== null ? -bottom : top;
|
|
159
|
-
return {
|
|
160
|
-
position,
|
|
161
|
-
styles: {
|
|
162
|
-
left: right === null ? "0px" : null,
|
|
163
|
-
right: right === null ? null : "0px",
|
|
164
|
-
top: bottom === null ? "0px" : null,
|
|
165
|
-
bottom: bottom === null ? null : "0px",
|
|
166
|
-
transform: `translate(${translateX}px, ${translateY}px)`,
|
|
167
|
-
height: height !== undefined ? `${height}px` : null,
|
|
168
|
-
width: width !== undefined ? `${width}px` : (passedWidth ?? null),
|
|
169
|
-
},
|
|
170
|
-
boundaries: {
|
|
171
|
-
left,
|
|
172
|
-
top,
|
|
173
|
-
height: height ?? Math.ceil(flyoutHeight),
|
|
174
|
-
width: width ?? Math.ceil(flyoutWidth),
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
};
|
|
178
|
-
export default calculatePosition;
|