reshaped 3.0.9 → 3.0.10
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 +6 -0
- package/bin/cli.js +0 -1
- package/dist/bundle.css +1 -1
- package/dist/bundle.d.ts +3 -1
- package/dist/bundle.js +10 -10
- package/dist/cjs/themes/_generator/utilities/color.d.ts +16 -0
- package/dist/cjs/themes/_generator/utilities/color.js +57 -7
- package/dist/cjs/themes/_generator/utilities/generateBackgroundColors.js +4 -0
- package/dist/cjs/themes/_generator/utilities/tests/color.test.js +73 -42
- package/dist/cjs/themes/index.d.ts +17 -0
- package/dist/cjs/themes/index.js +3 -0
- package/dist/cjs/types/config.d.ts +1 -0
- package/dist/components/Button/Button.module.css +1 -1
- package/dist/components/Button/tests/Button.stories.js +3 -1
- package/dist/components/DropdownMenu/DropdownMenu.module.css +1 -1
- package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +1 -1
- package/dist/components/Modal/Modal.js +4 -3
- package/dist/components/Modal/tests/Modal.stories.d.ts +0 -1
- package/dist/components/Modal/tests/Modal.stories.js +0 -16
- package/dist/components/Overlay/Overlay.js +7 -7
- package/dist/components/Overlay/tests/Overlay.stories.js +3 -1
- package/dist/components/Popover/Popover.js +2 -2
- package/dist/components/Popover/Popover.types.d.ts +1 -1
- package/dist/components/Resizable/Resizable.d.ts +8 -0
- package/dist/components/Resizable/Resizable.js +149 -0
- package/dist/components/Resizable/Resizable.module.css +1 -0
- package/dist/components/Resizable/Resizable.types.d.ts +29 -0
- package/dist/components/Resizable/Resizable.types.js +1 -0
- package/dist/components/Resizable/index.d.ts +2 -0
- package/dist/components/Resizable/index.js +1 -0
- package/dist/components/Resizable/tests/Resizable.stories.d.ts +15 -0
- package/dist/components/Resizable/tests/Resizable.stories.js +58 -0
- package/dist/components/ScrollArea/ScrollArea.js +4 -4
- package/dist/components/Slider/Slider.types.d.ts +2 -2
- package/dist/components/Slider/Slider.utilities.js +4 -4
- package/dist/components/Slider/SliderControlled.js +11 -9
- package/dist/components/Slider/SliderThumb.js +1 -1
- package/dist/components/Slider/tests/Slider.stories.js +4 -0
- package/dist/components/Toast/Toast.types.d.ts +7 -6
- package/dist/components/Toast/index.d.ts +1 -1
- package/dist/components/Toast/useToast.d.ts +1 -1
- package/dist/components/Tooltip/tests/Tooltip.stories.js +31 -0
- package/dist/components/_private/Flyout/Flyout.context.d.ts +3 -1
- package/dist/components/_private/Flyout/Flyout.context.js +4 -1
- package/dist/components/_private/Flyout/Flyout.types.d.ts +1 -0
- package/dist/components/_private/Flyout/FlyoutContent.js +5 -7
- package/dist/components/_private/Flyout/FlyoutControlled.js +18 -12
- package/dist/components/_private/Flyout/FlyoutTrigger.js +3 -2
- package/dist/components/_private/Flyout/tests/Flyout.stories.d.ts +2 -7
- package/dist/components/_private/Flyout/tests/Flyout.stories.js +87 -38
- package/dist/components/_private/Portal/Portal.module.css +1 -1
- package/dist/hooks/_private/useOnClickOutside.js +5 -3
- package/dist/hooks/tests/useDrag.stories.d.ts +6 -0
- package/dist/hooks/tests/useDrag.stories.js +29 -0
- package/dist/hooks/useDrag.d.ts +17 -0
- package/dist/hooks/useDrag.js +116 -0
- package/dist/hooks/useHandlerRef.d.ts +8 -0
- package/dist/hooks/useHandlerRef.js +16 -0
- package/dist/hooks/useScrollLock.js +4 -3
- package/dist/hooks/useToggle.js +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/themes/_generator/tests/themes.stories.js +23 -0
- package/dist/themes/_generator/utilities/color.d.ts +16 -0
- package/dist/themes/_generator/utilities/color.js +54 -6
- package/dist/themes/_generator/utilities/generateBackgroundColors.js +4 -0
- package/dist/themes/index.d.ts +17 -0
- package/dist/themes/index.js +3 -0
- package/dist/types/config.d.ts +1 -0
- package/dist/types/global.d.ts +1 -1
- package/package.json +1 -1
@@ -3,7 +3,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { useFlyoutContext, TriggerProvider } from "./Flyout.context.js";
|
4
4
|
const FlyoutTrigger = (props) => {
|
5
5
|
const { children } = props;
|
6
|
-
const { id, triggerElRef, triggerType, flyout, handleFocus, handleBlur, handleMouseEnter, handleMouseLeave, handleClick, trapFocusMode, } = useFlyoutContext();
|
6
|
+
const { id, triggerElRef, triggerType, flyout, handleFocus, handleBlur, handleMouseEnter, handleMouseLeave, handleClick, trapFocusMode, isSubmenu, } = useFlyoutContext();
|
7
7
|
let childrenAttributes = {
|
8
8
|
onBlur: handleBlur,
|
9
9
|
ref: triggerElRef,
|
@@ -15,7 +15,8 @@ const FlyoutTrigger = (props) => {
|
|
15
15
|
childrenAttributes.onMouseEnter = handleMouseEnter;
|
16
16
|
childrenAttributes.onMouseLeave = handleMouseLeave;
|
17
17
|
}
|
18
|
-
|
18
|
+
// Submenus open on keypress instead of hover
|
19
|
+
if ((triggerType === "hover" && !isSubmenu) || triggerType === "focus") {
|
19
20
|
childrenAttributes.onFocus = handleFocus;
|
20
21
|
childrenAttributes["aria-describedby"] = id;
|
21
22
|
}
|
@@ -5,13 +5,8 @@ declare const _default: {
|
|
5
5
|
export default _default;
|
6
6
|
export declare const positions: () => React.JSX.Element;
|
7
7
|
export declare const dynamicPosition: () => React.JSX.Element;
|
8
|
-
export declare const
|
9
|
-
export declare const
|
10
|
-
export declare const modeContentMenuClick: () => React.JSX.Element;
|
11
|
-
export declare const modeDialogHover: () => React.JSX.Element;
|
12
|
-
export declare const modeActionMenuHover: () => React.JSX.Element;
|
13
|
-
export declare const modeContentMenuHover: () => React.JSX.Element;
|
14
|
-
export declare const disableContentHover: () => React.JSX.Element;
|
8
|
+
export declare const modes: () => React.JSX.Element;
|
9
|
+
export declare const disableFlags: () => React.JSX.Element;
|
15
10
|
export declare const customPortalTarget: () => React.JSX.Element;
|
16
11
|
export declare const testWidthOverflowOnMobile: () => React.JSX.Element;
|
17
12
|
export declare const testInsideScrollArea: () => React.JSX.Element;
|
@@ -50,39 +50,70 @@ export const positions = () => (<div style={{ paddingTop: 200 }}>
|
|
50
50
|
export const dynamicPosition = () => (<div style={{ position: "absolute", top: 0, left: "50%" }}>
|
51
51
|
<Demo position="top"/>
|
52
52
|
</div>);
|
53
|
-
export const
|
54
|
-
<
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
<
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
53
|
+
export const modes = () => (<Example>
|
54
|
+
<Example.Item title="dialog click">
|
55
|
+
<Demo position="bottom-start" trapFocusMode="dialog">
|
56
|
+
<button type="button">Item 1</button>
|
57
|
+
<button type="button">Item 2</button>
|
58
|
+
<button type="button">Close</button>
|
59
|
+
</Demo>
|
60
|
+
</Example.Item>
|
61
|
+
|
62
|
+
<Example.Item title="action-menu click">
|
63
|
+
<Demo position="bottom-start" trapFocusMode="action-menu">
|
64
|
+
<button type="button">Item 1</button>
|
65
|
+
<button type="button">Item 2</button>
|
66
|
+
<button type="button">Close</button>
|
67
|
+
</Demo>
|
68
|
+
</Example.Item>
|
69
|
+
|
70
|
+
<Example.Item title="content-menu click">
|
71
|
+
<Demo position="bottom-start" trapFocusMode="content-menu">
|
72
|
+
<button type="button">Item 1</button>
|
73
|
+
<button type="button">Item 2</button>
|
74
|
+
<button type="button">Close</button>
|
75
|
+
</Demo>
|
76
|
+
</Example.Item>
|
77
|
+
|
78
|
+
<Example.Item title="dialog hover">
|
79
|
+
<Demo position="bottom-start" trapFocusMode="dialog" triggerType="hover">
|
80
|
+
<button type="button">Item 1</button>
|
81
|
+
<button type="button">Item 2</button>
|
82
|
+
<button type="button">Close</button>
|
83
|
+
</Demo>
|
84
|
+
</Example.Item>
|
85
|
+
|
86
|
+
<Example.Item title="action-menu hover">
|
87
|
+
<Demo position="bottom-start" trapFocusMode="action-menu" triggerType="hover">
|
88
|
+
<button type="button">Item 1</button>
|
89
|
+
<button type="button">Item 2</button>
|
90
|
+
<button type="button">Close</button>
|
91
|
+
</Demo>
|
92
|
+
</Example.Item>
|
93
|
+
|
94
|
+
<Example.Item title="content-menu hover">
|
95
|
+
<Demo position="bottom-start" trapFocusMode="content-menu" triggerType="hover">
|
96
|
+
<button type="button">Item 1</button>
|
97
|
+
<button type="button">Item 2</button>
|
98
|
+
<button type="button">Close</button>
|
99
|
+
</Demo>
|
100
|
+
</Example.Item>
|
101
|
+
</Example>);
|
102
|
+
export const disableFlags = () => (<Example>
|
103
|
+
<Example.Item title="disableContentHover">
|
104
|
+
<Demo triggerType="hover" disableContentHover>
|
105
|
+
Content
|
106
|
+
</Demo>
|
107
|
+
</Example.Item>
|
108
|
+
|
109
|
+
<Example.Item title="disableCloseOnOutsideClick">
|
110
|
+
<Demo disableCloseOnOutsideClick>Content</Demo>
|
111
|
+
</Example.Item>
|
112
|
+
|
113
|
+
<Example.Item title="disableHideAnimation">
|
114
|
+
<Demo disableHideAnimation>Content</Demo>
|
115
|
+
</Example.Item>
|
116
|
+
</Example>);
|
86
117
|
class CustomElement extends window.HTMLElement {
|
87
118
|
constructor() {
|
88
119
|
super();
|
@@ -99,7 +130,9 @@ class CustomElement extends window.HTMLElement {
|
|
99
130
|
root.render(node);
|
100
131
|
}
|
101
132
|
}
|
102
|
-
window.customElements.
|
133
|
+
if (!window.customElements.get("custom-element")) {
|
134
|
+
window.customElements.define("custom-element", CustomElement);
|
135
|
+
}
|
103
136
|
export const customPortalTarget = () => {
|
104
137
|
const portalRef = React.useRef(null);
|
105
138
|
return (<Example>
|
@@ -186,16 +219,32 @@ export const testInsideFixed = () => (<Example>
|
|
186
219
|
export const testDynamicBounds = () => {
|
187
220
|
const [left, setLeft] = React.useState("50%");
|
188
221
|
const [size, setSize] = React.useState("medium");
|
222
|
+
const flyoutRef = React.useRef();
|
223
|
+
React.useEffect(() => {
|
224
|
+
flyoutRef.current?.updatePosition();
|
225
|
+
}, [left]);
|
189
226
|
return (<View gap={4}>
|
190
227
|
<View direction="row" gap={2}>
|
191
|
-
<Button onClick={() =>
|
192
|
-
|
193
|
-
|
228
|
+
<Button onClick={() => {
|
229
|
+
setLeft("20%");
|
230
|
+
}}>
|
231
|
+
Left
|
232
|
+
</Button>
|
233
|
+
<Button onClick={() => {
|
234
|
+
setLeft("50%");
|
235
|
+
}}>
|
236
|
+
Center
|
237
|
+
</Button>
|
238
|
+
<Button onClick={() => {
|
239
|
+
setLeft("70%");
|
240
|
+
}}>
|
241
|
+
Right
|
242
|
+
</Button>
|
194
243
|
<Button onClick={() => setSize("large")}>Large button</Button>
|
195
244
|
<Button onClick={() => setSize("medium")}>Small button</Button>
|
196
245
|
</View>
|
197
246
|
<View height={100}>
|
198
|
-
<Flyout position="bottom" active>
|
247
|
+
<Flyout position="bottom" active instanceRef={flyoutRef}>
|
199
248
|
<Flyout.Trigger>
|
200
249
|
{(attributes) => (<div style={{ position: "absolute", left, top: "50%" }}>
|
201
250
|
<Button color="primary" attributes={attributes} size={size}>
|
@@ -1 +1 @@
|
|
1
|
-
.root{display:
|
1
|
+
.root{display:none}
|
@@ -1,7 +1,9 @@
|
|
1
|
+
import useHandlerRef from "../useHandlerRef.js";
|
1
2
|
import React from "react";
|
2
3
|
const useOnClickOutside = (refs, handler) => {
|
4
|
+
const handlerRef = useHandlerRef(handler);
|
3
5
|
React.useEffect(() => {
|
4
|
-
if (!
|
6
|
+
if (!handlerRef.current)
|
5
7
|
return;
|
6
8
|
const handleClick = (event) => {
|
7
9
|
let isInside = false;
|
@@ -14,7 +16,7 @@ const useOnClickOutside = (refs, handler) => {
|
|
14
16
|
});
|
15
17
|
if (isInside)
|
16
18
|
return;
|
17
|
-
|
19
|
+
handlerRef.current?.(event);
|
18
20
|
};
|
19
21
|
// Using events that happen before click to handle cases when element is hidden on click
|
20
22
|
document.addEventListener("mousedown", handleClick);
|
@@ -24,6 +26,6 @@ const useOnClickOutside = (refs, handler) => {
|
|
24
26
|
document.removeEventListener("touchstart", handleClick);
|
25
27
|
};
|
26
28
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
27
|
-
}, [
|
29
|
+
}, [handlerRef, ...refs]);
|
28
30
|
};
|
29
31
|
export default useOnClickOutside;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import View from "../../components/View/index.js";
|
3
|
+
import useDrag from "../useDrag.js";
|
4
|
+
import useToggle from "../useToggle.js";
|
5
|
+
import Button from "../../components/Button/index.js";
|
6
|
+
export default { title: "Hooks/useDrag" };
|
7
|
+
function Example() {
|
8
|
+
const [state, setState] = React.useState({ x: 0, y: 0 });
|
9
|
+
const disabledToggle = useToggle();
|
10
|
+
const { ref, containerRef, active } = useDrag((args) => {
|
11
|
+
setState(args);
|
12
|
+
}, {
|
13
|
+
disabled: disabledToggle.active,
|
14
|
+
});
|
15
|
+
return (<View direction="row" gap={4}>
|
16
|
+
<View backgroundColor="neutral-faded" borderRadius="medium" width="200px" height="200px" attributes={{ ref: containerRef }}>
|
17
|
+
<View height={8} width={8} borderRadius="small" animated backgroundColor={active ? "primary" : "neutral"} attributes={{
|
18
|
+
role: "button",
|
19
|
+
tabIndex: 0,
|
20
|
+
ref,
|
21
|
+
style: { translate: `${state.x}px ${state.y}px`, cursor: active ? "grabbing" : "grab" },
|
22
|
+
}}/>
|
23
|
+
</View>
|
24
|
+
<Button onClick={disabledToggle.toggle}>
|
25
|
+
{disabledToggle.active ? "Enable" : "Disable"}
|
26
|
+
</Button>
|
27
|
+
</View>);
|
28
|
+
}
|
29
|
+
export const state = () => <Example />;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import React from "react";
|
2
|
+
export type UseDragCallbackArgs = {
|
3
|
+
x: number;
|
4
|
+
y: number;
|
5
|
+
triggerX: number;
|
6
|
+
triggerY: number;
|
7
|
+
};
|
8
|
+
declare const useDrag: <TriggerElement extends HTMLElement = HTMLButtonElement, ContainerElement extends HTMLElement = HTMLDivElement>(cb: (args: UseDragCallbackArgs) => void, options?: {
|
9
|
+
disabled?: boolean;
|
10
|
+
containerRef?: React.RefObject<ContainerElement>;
|
11
|
+
orientation?: "horizontal" | "vertical" | "all";
|
12
|
+
}) => {
|
13
|
+
ref: React.MutableRefObject<TriggerElement | null>;
|
14
|
+
containerRef: React.RefObject<ContainerElement>;
|
15
|
+
active: boolean;
|
16
|
+
};
|
17
|
+
export default useDrag;
|
@@ -0,0 +1,116 @@
|
|
1
|
+
"use client";
|
2
|
+
import React from "react";
|
3
|
+
import { disableUserSelect, enableUserSelect, disableScroll, enableScroll } from "../utilities/dom.js";
|
4
|
+
import useToggle from "./useToggle.js";
|
5
|
+
import useHotkeys from "./useHotkeys.js";
|
6
|
+
import * as keys from "../constants/keys.js";
|
7
|
+
import useHandlerRef from "./useHandlerRef.js";
|
8
|
+
const useDrag = (cb, options) => {
|
9
|
+
const { disabled, containerRef: passedContainerRef, orientation = "all" } = options || {};
|
10
|
+
const cbRef = useHandlerRef(cb);
|
11
|
+
const toggle = useToggle();
|
12
|
+
const triggerRef = React.useRef(null);
|
13
|
+
const internalContainerRef = React.useRef(null);
|
14
|
+
const containerRef = passedContainerRef || internalContainerRef;
|
15
|
+
const triggerCompensationRef = React.useRef({ x: 0, y: 0 });
|
16
|
+
const isVertical = orientation === "vertical" || orientation === "all";
|
17
|
+
const isHorizontal = orientation === "horizontal" || orientation === "all";
|
18
|
+
const handleKeyboard = (x, y) => {
|
19
|
+
const triggerEl = triggerRef.current;
|
20
|
+
if (!triggerEl)
|
21
|
+
return;
|
22
|
+
const container = containerRef.current ?? document.body;
|
23
|
+
const containerRect = container.getBoundingClientRect();
|
24
|
+
const triggerRect = triggerEl?.getBoundingClientRect();
|
25
|
+
const nextArgs = { x: 0, y: 0, triggerX: 0, triggerY: 0 };
|
26
|
+
if (isVertical) {
|
27
|
+
const relativeY = Math.round(triggerRect.y) - containerRect.y + y;
|
28
|
+
nextArgs.y = Math.max(0, Math.min(relativeY, containerRect.height - triggerRect.height));
|
29
|
+
nextArgs.triggerY = triggerRect.y - containerRect.y;
|
30
|
+
}
|
31
|
+
if (isHorizontal) {
|
32
|
+
const relativeX = Math.round(triggerRect.x) - containerRect.x + x;
|
33
|
+
nextArgs.x = Math.max(0, Math.min(relativeX, containerRect.width - triggerRect.width));
|
34
|
+
nextArgs.triggerX = triggerRect.x - containerRect.x;
|
35
|
+
}
|
36
|
+
cb(nextArgs);
|
37
|
+
};
|
38
|
+
useHotkeys({
|
39
|
+
[keys.LEFT]: () => isHorizontal && handleKeyboard(-20, 0),
|
40
|
+
[keys.RIGHT]: () => isHorizontal && handleKeyboard(20, 0),
|
41
|
+
[keys.UP]: () => isVertical && handleKeyboard(0, -20),
|
42
|
+
[keys.DOWN]: () => isVertical && handleKeyboard(0, 20),
|
43
|
+
}, [], {
|
44
|
+
ref: triggerRef,
|
45
|
+
disabled,
|
46
|
+
});
|
47
|
+
React.useEffect(() => {
|
48
|
+
const triggerEl = triggerRef.current;
|
49
|
+
if (!triggerEl)
|
50
|
+
return;
|
51
|
+
if (!toggle.active)
|
52
|
+
return;
|
53
|
+
const handleDrag = (event) => {
|
54
|
+
const resolvedEvent = event instanceof MouseEvent ? event : event.changedTouches[0];
|
55
|
+
const container = containerRef.current ?? document.body;
|
56
|
+
const containerRect = container.getBoundingClientRect();
|
57
|
+
const triggerRect = triggerEl.getBoundingClientRect();
|
58
|
+
const triggerX = resolvedEvent.clientX - containerRect.x;
|
59
|
+
const triggerY = resolvedEvent.clientY - containerRect.y;
|
60
|
+
// Calculate position relative to the container
|
61
|
+
const relativeX = triggerX - triggerCompensationRef.current.x;
|
62
|
+
const relativeY = triggerY - triggerCompensationRef.current.y;
|
63
|
+
cbRef.current?.({
|
64
|
+
x: isHorizontal
|
65
|
+
? Math.max(0, Math.min(relativeX, containerRect.width - triggerRect.width))
|
66
|
+
: 0,
|
67
|
+
y: isVertical
|
68
|
+
? Math.max(0, Math.min(relativeY, containerRect.height - triggerRect.height))
|
69
|
+
: 0,
|
70
|
+
triggerX: triggerRect.x - containerRect.x,
|
71
|
+
triggerY: triggerRect.y - containerRect.y,
|
72
|
+
});
|
73
|
+
};
|
74
|
+
const handleDragEnd = () => {
|
75
|
+
triggerCompensationRef.current = { x: 0, y: 0 };
|
76
|
+
toggle.deactivate();
|
77
|
+
enableUserSelect();
|
78
|
+
enableScroll();
|
79
|
+
};
|
80
|
+
document.addEventListener("touchmove", handleDrag, { passive: true });
|
81
|
+
document.addEventListener("touchend", handleDragEnd, { passive: true });
|
82
|
+
document.addEventListener("mousemove", handleDrag, { passive: true });
|
83
|
+
document.addEventListener("mouseup", handleDragEnd, { passive: true });
|
84
|
+
return () => {
|
85
|
+
document.removeEventListener("touchmove", handleDrag);
|
86
|
+
document.removeEventListener("touchend", handleDragEnd);
|
87
|
+
document.removeEventListener("mousemove", handleDrag);
|
88
|
+
document.removeEventListener("mouseup", handleDragEnd);
|
89
|
+
};
|
90
|
+
}, [toggle, isHorizontal, isVertical, containerRef, cbRef]);
|
91
|
+
React.useEffect(() => {
|
92
|
+
const triggerEl = triggerRef.current;
|
93
|
+
if (!triggerEl || disabled)
|
94
|
+
return;
|
95
|
+
const handleStart = (event) => {
|
96
|
+
const resolvedEvent = event instanceof MouseEvent ? event : event.changedTouches[0];
|
97
|
+
// Find the coordinate of the event inside the trigger
|
98
|
+
const triggerRect = triggerEl.getBoundingClientRect();
|
99
|
+
triggerCompensationRef.current = {
|
100
|
+
x: resolvedEvent.clientX - triggerRect.x,
|
101
|
+
y: resolvedEvent.clientY - triggerRect.y,
|
102
|
+
};
|
103
|
+
toggle.activate();
|
104
|
+
disableUserSelect();
|
105
|
+
disableScroll();
|
106
|
+
};
|
107
|
+
triggerEl.addEventListener("touchstart", handleStart, { passive: true });
|
108
|
+
triggerEl.addEventListener("mousedown", handleStart, { passive: true });
|
109
|
+
return () => {
|
110
|
+
triggerEl.removeEventListener("touchstart", handleStart);
|
111
|
+
triggerEl.removeEventListener("mousedown", handleStart);
|
112
|
+
};
|
113
|
+
}, [toggle, disabled]);
|
114
|
+
return { ref: triggerRef, containerRef, active: toggle.active };
|
115
|
+
};
|
116
|
+
export default useDrag;
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import React from "react";
|
2
|
+
/**
|
3
|
+
* Hook for wrapping event handlers passed as props with a ref
|
4
|
+
* This way we can keep the instance of the ref the same and pass this ref to the effects dependency array
|
5
|
+
* While also making sure that function implementation stays up-to-date
|
6
|
+
*/
|
7
|
+
declare const useHandlerRef: <T>(cb: T) => React.RefObject<T>;
|
8
|
+
export default useHandlerRef;
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import React from "react";
|
2
|
+
import useIsomorphicLayoutEffect from "./useIsomorphicLayoutEffect.js";
|
3
|
+
/**
|
4
|
+
* Hook for wrapping event handlers passed as props with a ref
|
5
|
+
* This way we can keep the instance of the ref the same and pass this ref to the effects dependency array
|
6
|
+
* While also making sure that function implementation stays up-to-date
|
7
|
+
*/
|
8
|
+
const useHandlerRef = (cb) => {
|
9
|
+
const ref = React.useRef(cb);
|
10
|
+
// Update the callback on every render, keeping the ref instance the same
|
11
|
+
useIsomorphicLayoutEffect(() => {
|
12
|
+
ref.current = cb;
|
13
|
+
});
|
14
|
+
return ref;
|
15
|
+
};
|
16
|
+
export default useHandlerRef;
|
@@ -21,8 +21,8 @@ const useScrollLock = () => {
|
|
21
21
|
const [locked, setLocked] = React.useState(false);
|
22
22
|
const overflowStyleRef = React.useRef();
|
23
23
|
const isOverflowingRef = React.useRef(false);
|
24
|
-
const targetEl = document.body;
|
25
24
|
const lockScroll = React.useCallback(() => {
|
25
|
+
const targetEl = document.body;
|
26
26
|
const rect = targetEl.getBoundingClientRect();
|
27
27
|
isOverflowingRef.current = rect.left + rect.right < window.innerWidth;
|
28
28
|
overflowStyleRef.current = targetEl.style.overflow;
|
@@ -32,13 +32,14 @@ const useScrollLock = () => {
|
|
32
32
|
targetEl.style.paddingRight = `${scrollBarWidth}px`;
|
33
33
|
}
|
34
34
|
setLocked(true);
|
35
|
-
}, [setLocked, isOverflowingRef, overflowStyleRef
|
35
|
+
}, [setLocked, isOverflowingRef, overflowStyleRef]);
|
36
36
|
const unlockScroll = React.useCallback(() => {
|
37
|
+
const targetEl = document.body;
|
37
38
|
targetEl.style.overflow = overflowStyleRef.current || "";
|
38
39
|
if (isOverflowingRef.current)
|
39
40
|
targetEl.style.paddingRight = "";
|
40
41
|
setLocked(false);
|
41
|
-
}, [setLocked, isOverflowingRef, overflowStyleRef
|
42
|
+
}, [setLocked, isOverflowingRef, overflowStyleRef]);
|
42
43
|
return { scrollLocked: locked, lockScroll, unlockScroll };
|
43
44
|
};
|
44
45
|
export default useScrollLock;
|
package/dist/hooks/useToggle.js
CHANGED
@@ -11,6 +11,6 @@ const useToggle = (defaultValue) => {
|
|
11
11
|
const toggle = React.useCallback(() => {
|
12
12
|
setActive((active) => !active);
|
13
13
|
}, []);
|
14
|
-
return { active, activate, deactivate, toggle };
|
14
|
+
return React.useMemo(() => ({ active, activate, deactivate, toggle }), [activate, deactivate, toggle, active]);
|
15
15
|
};
|
16
16
|
export default useToggle;
|
package/dist/index.d.ts
CHANGED
@@ -75,6 +75,8 @@ export { default as RadioGroup } from "./components/RadioGroup";
|
|
75
75
|
export type { RadioGroupProps } from "./components/RadioGroup";
|
76
76
|
export { default as Reshaped } from "./components/Reshaped";
|
77
77
|
export type { ReshapedProps } from "./components/Reshaped";
|
78
|
+
export { default as Resizable } from "./components/Resizable";
|
79
|
+
export type { ResizableProps, ResizableItemProps, ResizableHandleProps, } from "./components/Resizable";
|
78
80
|
export { default as Scrim } from "./components/Scrim";
|
79
81
|
export type { ScrimProps } from "./components/Scrim";
|
80
82
|
export { default as ScrollArea } from "./components/ScrollArea";
|
@@ -102,7 +104,7 @@ export type { TextFieldProps } from "./components/TextField";
|
|
102
104
|
export { default as Timeline } from "./components/Timeline";
|
103
105
|
export type { TimelineProps, TimelineItemProps } from "./components/Timeline";
|
104
106
|
export { useToast, ToastProvider } from "./components/Toast";
|
105
|
-
export type { ToastProps, ToastProviderProps } from "./components/Toast";
|
107
|
+
export type { ToastProps, ToastProviderProps, ToastShowProps } from "./components/Toast";
|
106
108
|
export { default as Tooltip } from "./components/Tooltip";
|
107
109
|
export type { TooltipProps } from "./components/Tooltip";
|
108
110
|
export { default as View } from "./components/View";
|
package/dist/index.js
CHANGED
@@ -38,6 +38,7 @@ export { default as Progress } from "./components/Progress/index.js";
|
|
38
38
|
export { default as Radio } from "./components/Radio/index.js";
|
39
39
|
export { default as RadioGroup } from "./components/RadioGroup/index.js";
|
40
40
|
export { default as Reshaped } from "./components/Reshaped/index.js";
|
41
|
+
export { default as Resizable } from "./components/Resizable/index.js";
|
41
42
|
export { default as Scrim } from "./components/Scrim/index.js";
|
42
43
|
export { default as ScrollArea } from "./components/ScrollArea/index.js";
|
43
44
|
export { default as Select } from "./components/Select/index.js";
|
@@ -235,6 +235,20 @@ const onColorsCss = getThemeCSS("on-color", {
|
|
235
235
|
},
|
236
236
|
},
|
237
237
|
});
|
238
|
+
const onColorsCssApca = getThemeCSS("on-color-apca", {
|
239
|
+
color: {
|
240
|
+
backgroundPrimary: { hex: "#1abc9c", hexDark: "#16a085" },
|
241
|
+
backgroundPrimaryHighlighted: { hex: "#16a085", hexDark: "#1abc9c" },
|
242
|
+
},
|
243
|
+
}, {
|
244
|
+
colorContrastAlgorithm: "apca",
|
245
|
+
onColorValues: {
|
246
|
+
primary: {
|
247
|
+
hexLight: "#d1fae5",
|
248
|
+
hexDark: "#022c22",
|
249
|
+
},
|
250
|
+
},
|
251
|
+
});
|
238
252
|
export const onColors = () => (<Example>
|
239
253
|
<Example.Item title="custom on color values">
|
240
254
|
<style>{onColorsCss}</style>
|
@@ -245,4 +259,13 @@ export const onColors = () => (<Example>
|
|
245
259
|
</View>
|
246
260
|
</Theme>
|
247
261
|
</Example.Item>
|
262
|
+
<Example.Item title="custom on color values, apca">
|
263
|
+
<style>{onColorsCssApca}</style>
|
264
|
+
<Theme name="on-color-apca">
|
265
|
+
<View gap={2} direction="row">
|
266
|
+
<Button color="primary">Primary button</Button>
|
267
|
+
<Button color="critical">Critical button</Button>
|
268
|
+
</View>
|
269
|
+
</Theme>
|
270
|
+
</Example.Item>
|
248
271
|
</Example>);
|
@@ -81,9 +81,25 @@ export declare const getDarkModeColor: (hsl: HslColor) => {
|
|
81
81
|
};
|
82
82
|
export declare const getLuminanceDelta: (luminance: number) => number;
|
83
83
|
export declare function getRgbLuminance({ r, g, b }: RgbColor): number;
|
84
|
+
export declare const getOnColorWCAG: (args: {
|
85
|
+
bgHexColor: string;
|
86
|
+
lightHexColor?: string;
|
87
|
+
darkHexColor?: string;
|
88
|
+
}) => string;
|
89
|
+
export declare const getOnColorAPCA: (args: {
|
90
|
+
bgHexColor: string;
|
91
|
+
mode: "light" | "dark";
|
92
|
+
lightHexColor?: string;
|
93
|
+
darkHexColor?: string;
|
94
|
+
}) => string;
|
95
|
+
/**
|
96
|
+
* On color resolver
|
97
|
+
*/
|
84
98
|
export declare const getOnColor: (args: {
|
85
99
|
bgHexColor: string;
|
86
100
|
lightHexColor?: string;
|
87
101
|
darkHexColor?: string;
|
102
|
+
mode: "light" | "dark";
|
103
|
+
algorithm?: "wcag" | "apca";
|
88
104
|
}) => string;
|
89
105
|
export {};
|
@@ -301,29 +301,77 @@ export function getRgbLuminance({ r, g, b }) {
|
|
301
301
|
return Math.pow(y, 1 / 3) * 116 - 16;
|
302
302
|
}
|
303
303
|
}
|
304
|
+
/**
|
305
|
+
* WCAG contrast
|
306
|
+
*/
|
304
307
|
const RED = 0.2126;
|
305
308
|
const GREEN = 0.7152;
|
306
309
|
const BLUE = 0.0722;
|
307
310
|
const GAMMA = 2.4;
|
308
|
-
function
|
311
|
+
function luminanceWCAG(r, g, b) {
|
309
312
|
var a = [r, g, b].map((v) => {
|
310
313
|
v /= 255;
|
311
314
|
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, GAMMA);
|
312
315
|
});
|
313
316
|
return a[0] * RED + a[1] * GREEN + a[2] * BLUE;
|
314
317
|
}
|
315
|
-
function
|
316
|
-
var lum1 =
|
317
|
-
var lum2 =
|
318
|
+
function contrastWCAG(rgb1, rgb2) {
|
319
|
+
var lum1 = luminanceWCAG(...rgb1);
|
320
|
+
var lum2 = luminanceWCAG(...rgb2);
|
318
321
|
var brightest = Math.max(lum1, lum2);
|
319
322
|
var darkest = Math.min(lum1, lum2);
|
320
323
|
return (brightest + 0.05) / (darkest + 0.05);
|
321
324
|
}
|
322
|
-
export const
|
325
|
+
export const getOnColorWCAG = (args) => {
|
323
326
|
const { bgHexColor, lightHexColor = "#ffffff", darkHexColor = "#000000" } = args;
|
324
327
|
const bgRgb = hexToRgb(bgHexColor);
|
325
328
|
const lightRgb = hexToRgb(lightHexColor);
|
326
|
-
return
|
329
|
+
return contrastWCAG([bgRgb.r, bgRgb.g, bgRgb.b], [lightRgb.r, lightRgb.g, lightRgb.b]) > 4.5
|
327
330
|
? lightHexColor
|
328
331
|
: darkHexColor;
|
329
332
|
};
|
333
|
+
/**
|
334
|
+
* APCA contrast
|
335
|
+
*/
|
336
|
+
function luminanceAPCA({ r, g, b }) {
|
337
|
+
return (0.2126 * Math.pow(r / 255, 2.2) +
|
338
|
+
0.7152 * Math.pow(g / 255, 2.2) +
|
339
|
+
0.0722 * Math.pow(b / 255, 2.2));
|
340
|
+
}
|
341
|
+
function contrastAPCA(backgroundLuminance, textLuminance) {
|
342
|
+
// Calculate the contrast based on APCA
|
343
|
+
let Lc = textLuminance - backgroundLuminance;
|
344
|
+
return Math.abs(Lc); // Return the absolute value of contrast
|
345
|
+
}
|
346
|
+
export const getOnColorAPCA = (args) => {
|
347
|
+
const { bgHexColor, mode, lightHexColor = "#ffffff", darkHexColor = "#000000" } = args;
|
348
|
+
const bgHexAlpha = bgHexColor.slice(7);
|
349
|
+
const bgAlpha = bgHexAlpha ? Number((parseInt(bgHexAlpha, 16) / 255).toFixed(2)) : 1;
|
350
|
+
const bgColor = hexToRgb(bgHexColor.slice(0, 7));
|
351
|
+
const baseColor = mode === "light" ? { r: 255, g: 255, b: 255 } : { r: 0, g: 0, b: 0 };
|
352
|
+
const { r, g, b } = {
|
353
|
+
r: (1 - bgAlpha) * baseColor.r + bgAlpha * bgColor.r,
|
354
|
+
g: (1 - bgAlpha) * baseColor.g + bgAlpha * bgColor.g,
|
355
|
+
b: (1 - bgAlpha) * baseColor.b + bgAlpha * bgColor.b,
|
356
|
+
};
|
357
|
+
// Calculate luminance for background and for white & black
|
358
|
+
let backgroundLuminance = luminanceAPCA({ r, g, b });
|
359
|
+
let whiteLuminance = luminanceAPCA({ r: 255, g: 255, b: 255 });
|
360
|
+
let blackLuminance = luminanceAPCA({ r: 0, g: 0, b: 0 });
|
361
|
+
// Calculate contrast
|
362
|
+
let contrastWithWhite = contrastAPCA(backgroundLuminance, whiteLuminance);
|
363
|
+
let contrastWithBlack = contrastAPCA(backgroundLuminance, blackLuminance);
|
364
|
+
// Choose the color with higher contrast
|
365
|
+
return contrastWithWhite > contrastWithBlack ? lightHexColor : darkHexColor;
|
366
|
+
};
|
367
|
+
/**
|
368
|
+
* On color resolver
|
369
|
+
*/
|
370
|
+
export const getOnColor = (args) => {
|
371
|
+
if (args.algorithm === "apca") {
|
372
|
+
return getOnColorAPCA(args);
|
373
|
+
}
|
374
|
+
else {
|
375
|
+
return getOnColorWCAG(args);
|
376
|
+
}
|
377
|
+
};
|
@@ -29,10 +29,14 @@ const generateBackgroundColors = (definition, themeOptions) => {
|
|
29
29
|
};
|
30
30
|
const hex = getOnColor({
|
31
31
|
bgHexColor: bgToken.hex,
|
32
|
+
mode: "light",
|
33
|
+
algorithm: themeOptions?.colorContrastAlgorithm,
|
32
34
|
...onColorHexMap,
|
33
35
|
});
|
34
36
|
const hexDark = getOnColor({
|
35
37
|
bgHexColor: bgToken.hexDark || bgToken.hex,
|
38
|
+
mode: "dark",
|
39
|
+
algorithm: themeOptions?.colorContrastAlgorithm,
|
36
40
|
...onColorHexMap,
|
37
41
|
});
|
38
42
|
// eslint-disable-next-line no-param-reassign
|