reshaped 3.0.9 → 3.0.11-rc.0
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 +7 -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/tokens/font/font.transforms.js +6 -0
- package/dist/cjs/themes/_generator/tokens/font/font.types.d.ts +1 -0
- package/dist/cjs/themes/_generator/tokens/types.d.ts +1 -1
- 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/figma/theme.css +1 -1
- package/dist/cjs/themes/index.d.ts +17 -0
- package/dist/cjs/themes/index.js +3 -0
- package/dist/cjs/themes/reshaped/theme.css +1 -1
- package/dist/cjs/themes/slate/theme.css +1 -1
- 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/MenuItem/MenuItem.module.css +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/Reshaped/Reshaped.css +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/Select/Select.module.css +1 -1
- 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/Text/Text.module.css +1 -1
- package/dist/components/TextArea/TextArea.module.css +1 -1
- package/dist/components/TextField/TextField.module.css +1 -1
- 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 -8
- package/dist/components/_private/Flyout/tests/Flyout.stories.js +87 -62
- package/dist/components/_private/Flyout/useFlyout.js +11 -2
- 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/tokens/font/font.transforms.js +6 -0
- package/dist/themes/_generator/tokens/font/font.types.d.ts +1 -0
- package/dist/themes/_generator/tokens/types.d.ts +1 -1
- 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/figma/theme.css +1 -1
- package/dist/themes/index.d.ts +17 -0
- package/dist/themes/index.js +3 -0
- package/dist/themes/reshaped/theme.css +1 -1
- package/dist/themes/slate/theme.css +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/global.d.ts +1 -1
- package/package.json +1 -1
@@ -1 +1 @@
|
|
1
|
-
.root,button.root{background-color:var(--rs-menu-item-bg-color);color:var(--rs-menu-item-color);display:block;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-medium);padding:var(--rs-p-v) var(--rs-p-h);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,transform,box-shadow}.icon{color:var(--rs-menu-item-icon-color,inherit)}.content,.icon{transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:color}.--rounded-corners{border-radius:var(--rs-menu-item-radius)}.--size-small{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium,.--size-small{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2)}.--color-neutral{--rs-menu-item-icon-color:var(--rs-color-foreground-neutral-faded)}.--color-neutral.--selected,.--color-neutral:hover,.--color-neutral[data-rs-focus]{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-neutral),32%)}.--color-critical{--rs-menu-item-color:var(--rs-color-foreground-critical)}.--color-critical.--selected,.--color-critical:hover,.--color-critical[data-rs-focus]{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-critical),12%)}.--color-primary{--rs-menu-item-icon-color:var(--rs-color-foreground-neutral-faded)}.--color-primary:hover,.--color-primary[data-rs-focus]{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-neutral),32%)}.--color-primary.--selected,.--color-primary.--selected:hover{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-primary),12%);--rs-menu-item-color:var(--rs-color-foreground-primary);--rs-menu-item-icon-color:var(--rs-color-foreground-primary)}.--selected,.--selected:hover{cursor:default}.--disabled,.--disabled:hover{--rs-menu-item-color:var(--rs-color-foreground-disabled);--rs-menu-item-bg-color:none;--rs-menu-item-icon-color:var(--rs-color-foreground-disabled)}button.root{width:100%}.aligner button.root{box-sizing:initial}@media (--rs-viewport-m ){.--rounded-corners-true--m{border-radius:var(--rs-menu-item-radius)}.--rounded-corners-false--m{border-radius:0}.--size-small--m{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium--m,.--size-small--m{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium--m{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large--m{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2)}}@media (--rs-viewport-l ){.--rounded-corners-true--l{border-radius:var(--rs-menu-item-radius)}.--rounded-corners-false--l{border-radius:0}.--size-small--l{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium--l,.--size-small--l{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium--l{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large--l{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2)}}@media (--rs-viewport-xl ){.--rounded-corners-true--xl{border-radius:var(--rs-menu-item-radius)}.--rounded-corners-false--xl{border-radius:0}.--size-small--xl{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium--xl,.--size-small--xl{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium--xl{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large--xl{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2)}}
|
1
|
+
.root,button.root{background-color:var(--rs-menu-item-bg-color);color:var(--rs-menu-item-color);display:block;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-medium);padding:var(--rs-p-v) var(--rs-p-h);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,transform,box-shadow}.icon{color:var(--rs-menu-item-icon-color,inherit)}.content,.icon{transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:color}.--rounded-corners{border-radius:var(--rs-menu-item-radius)}.--size-small{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium,.--size-small{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}.--color-neutral{--rs-menu-item-icon-color:var(--rs-color-foreground-neutral-faded)}.--color-neutral.--selected,.--color-neutral:hover,.--color-neutral[data-rs-focus]{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-neutral),32%)}.--color-critical{--rs-menu-item-color:var(--rs-color-foreground-critical)}.--color-critical.--selected,.--color-critical:hover,.--color-critical[data-rs-focus]{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-critical),12%)}.--color-primary{--rs-menu-item-icon-color:var(--rs-color-foreground-neutral-faded)}.--color-primary:hover,.--color-primary[data-rs-focus]{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-neutral),32%)}.--color-primary.--selected,.--color-primary.--selected:hover{--rs-menu-item-bg-color:rgba(var(--rs-color-rgb-background-primary),12%);--rs-menu-item-color:var(--rs-color-foreground-primary);--rs-menu-item-icon-color:var(--rs-color-foreground-primary)}.--selected,.--selected:hover{cursor:default}.--disabled,.--disabled:hover{--rs-menu-item-color:var(--rs-color-foreground-disabled);--rs-menu-item-bg-color:none;--rs-menu-item-icon-color:var(--rs-color-foreground-disabled)}button.root{width:100%}.aligner button.root{box-sizing:initial}@media (--rs-viewport-m ){.--rounded-corners-true--m{border-radius:var(--rs-menu-item-radius)}.--rounded-corners-false--m{border-radius:0}.--size-small--m{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium--m,.--size-small--m{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium--m{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large--m{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}}@media (--rs-viewport-l ){.--rounded-corners-true--l{border-radius:var(--rs-menu-item-radius)}.--rounded-corners-false--l{border-radius:0}.--size-small--l{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium--l,.--size-small--l{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium--l{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large--l{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}}@media (--rs-viewport-xl ){.--rounded-corners-true--xl{border-radius:var(--rs-menu-item-radius)}.--rounded-corners-false--xl{border-radius:0}.--size-small--xl{--rs-p-v:var(--rs-unit-x1);--rs-p-h:var(--rs-unit-x2);--rs-menu-item-radius:var(--rs-radius-small)}.--size-medium--xl,.--size-small--xl{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}.--size-medium--xl{--rs-p-v:var(--rs-unit-x2);--rs-p-h:var(--rs-unit-x3);--rs-menu-item-radius:var(--rs-radius-small)}.--size-large--xl{--rs-p-v:var(--rs-unit-x3);--rs-p-h:var(--rs-unit-x4);--rs-menu-item-radius:var(--rs-radius-medium);font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2)}}
|
@@ -9,6 +9,7 @@ import Overlay from "../Overlay/index.js";
|
|
9
9
|
import useElementId from "../../hooks/useElementId.js";
|
10
10
|
import s from "./Modal.module.css";
|
11
11
|
import getPaddingStyles from "../../styles/padding/index.js";
|
12
|
+
import useHandlerRef from "../../hooks/useHandlerRef.js";
|
12
13
|
const DRAG_THRESHOLD = 32;
|
13
14
|
const DRAG_OPPOSITE_THRESHOLD = 100;
|
14
15
|
const DRAG_EDGE_BOUNDARY = 32;
|
@@ -40,6 +41,7 @@ const ModalSubtitle = (props) => {
|
|
40
41
|
};
|
41
42
|
const Modal = (props) => {
|
42
43
|
const { children, onClose, onOpen, active, size, padding = 4, position = "center", transparentOverlay, ariaLabel, autoFocus = true, disableSwipeGesture, overlayClassName, className, attributes, } = props;
|
44
|
+
const onCloseRef = useHandlerRef(onClose);
|
43
45
|
const id = useElementId();
|
44
46
|
const clientPosition = useResponsiveClientValue(position);
|
45
47
|
const [titleMounted, setTitleMounted] = React.useState(false);
|
@@ -110,7 +112,7 @@ const Modal = (props) => {
|
|
110
112
|
// Changing to a different direction will keep the modal opened
|
111
113
|
const shouldClose = clientPosition === "start" ? dragDirectionRef.current < 0 : dragDirectionRef.current > 0;
|
112
114
|
if (Math.abs(dragDistanceRef.current) > DRAG_THRESHOLD && shouldClose) {
|
113
|
-
|
115
|
+
onCloseRef.current?.();
|
114
116
|
}
|
115
117
|
else {
|
116
118
|
resetDragData();
|
@@ -151,8 +153,7 @@ const Modal = (props) => {
|
|
151
153
|
document.removeEventListener("touchmove", handleDrag);
|
152
154
|
document.removeEventListener("touchend", handleDragEnd);
|
153
155
|
};
|
154
|
-
|
155
|
-
}, [dragging, clientPosition]);
|
156
|
+
}, [dragging, clientPosition, onCloseRef, position, rootRef]);
|
156
157
|
// Syncing distance to the ref to avoid having a dependency on dragDistance in handleDragEnd
|
157
158
|
React.useEffect(() => {
|
158
159
|
const rootEl = rootRef.current;
|
@@ -14,7 +14,6 @@ declare const _default: {
|
|
14
14
|
};
|
15
15
|
};
|
16
16
|
export default _default;
|
17
|
-
export declare const foo: () => React.JSX.Element;
|
18
17
|
export declare const position: () => React.JSX.Element;
|
19
18
|
export declare const size: () => React.JSX.Element;
|
20
19
|
export declare const padding: () => React.JSX.Element;
|
@@ -9,7 +9,6 @@ import Switch from "../../Switch/index.js";
|
|
9
9
|
import TextField from "../../TextField/index.js";
|
10
10
|
import useToggle from "../../../hooks/useToggle.js";
|
11
11
|
import Radio from "../../Radio/index.js";
|
12
|
-
import Slider from "../../Slider/index.js";
|
13
12
|
export default {
|
14
13
|
title: "Components/Modal",
|
15
14
|
component: Modal,
|
@@ -19,21 +18,6 @@ export default {
|
|
19
18
|
},
|
20
19
|
},
|
21
20
|
};
|
22
|
-
export const foo = () => {
|
23
|
-
const { activate, deactivate, active } = useToggle(false);
|
24
|
-
return (<>
|
25
|
-
<Button onClick={console.log}>Other</Button>
|
26
|
-
<Button onClick={activate}>Open modal</Button>
|
27
|
-
<Button onClick={console.log}>Other</Button>
|
28
|
-
|
29
|
-
<Modal active={active} onClose={deactivate}>
|
30
|
-
<Slider name="slider" defaultValue={20} onChange={(args) => console.log(args.value)}/>
|
31
|
-
<Button onClick={console.log}>Btn 1</Button>
|
32
|
-
|
33
|
-
<Button onClick={console.log}>Btn 2</Button>
|
34
|
-
</Modal>
|
35
|
-
</>);
|
36
|
-
};
|
37
21
|
const Demo = (props) => {
|
38
22
|
const { active: activeProp, title, subtitle, children, ...modalProps } = props;
|
39
23
|
const { active, activate, deactivate } = useToggle(activeProp);
|
@@ -11,8 +11,11 @@ import useScrollLock from "../../hooks/useScrollLock.js";
|
|
11
11
|
import useIsDismissible from "../../hooks/_private/useIsDismissible.js";
|
12
12
|
import Portal from "../_private/Portal/index.js";
|
13
13
|
import s from "./Overlay.module.css";
|
14
|
+
import useHandlerRef from "../../hooks/useHandlerRef.js";
|
14
15
|
const Overlay = (props) => {
|
15
16
|
const { active, children, transparent, onClose, onOpen, className, attributes } = props;
|
17
|
+
const onCloseRef = useHandlerRef(onClose);
|
18
|
+
const onOpenRef = useHandlerRef(onOpen);
|
16
19
|
const clickThrough = transparent === true;
|
17
20
|
const opacity = clickThrough ? 0 : (1 - (transparent || 0)) * 0.7;
|
18
21
|
const [mounted, setMounted] = React.useState(false);
|
@@ -35,10 +38,8 @@ const Overlay = (props) => {
|
|
35
38
|
const close = React.useCallback(() => {
|
36
39
|
if (!visible || !isDismissible())
|
37
40
|
return;
|
38
|
-
|
39
|
-
|
40
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
41
|
-
}, [visible, isDismissible]);
|
41
|
+
onCloseRef.current?.();
|
42
|
+
}, [visible, isDismissible, onCloseRef]);
|
42
43
|
const handleMouseDown = (event) => {
|
43
44
|
isMouseDownValidRef.current = !isInsideChild(event.target);
|
44
45
|
};
|
@@ -84,11 +85,10 @@ const Overlay = (props) => {
|
|
84
85
|
trapFocus.trap({
|
85
86
|
initialFocusEl: contentRef.current.querySelector("[role=dialog][tabindex='-1']"),
|
86
87
|
});
|
87
|
-
|
88
|
+
onOpenRef.current?.();
|
88
89
|
return () => trapFocus.release();
|
89
90
|
// Ignoring onOpen since it might be not memoized when passed
|
90
|
-
|
91
|
-
}, [rendered]);
|
91
|
+
}, [rendered, onOpenRef]);
|
92
92
|
// Unlock scroll on unmount
|
93
93
|
React.useEffect(() => {
|
94
94
|
return () => {
|
@@ -47,7 +47,9 @@ class CustomElement extends window.HTMLElement {
|
|
47
47
|
root.render(overlay);
|
48
48
|
}
|
49
49
|
}
|
50
|
-
window.customElements.
|
50
|
+
if (!window.customElements.get("custom-element")) {
|
51
|
+
window.customElements.define("custom-element", CustomElement);
|
52
|
+
}
|
51
53
|
export const shadowDom = () => {
|
52
54
|
return (<Example>
|
53
55
|
<Example.Item>
|
@@ -5,14 +5,14 @@ import Dismissible from "../Dismissible/index.js";
|
|
5
5
|
import s from "./Popover.module.css";
|
6
6
|
import getPaddingStyles from "../../styles/padding/index.js";
|
7
7
|
const Popover = (props) => {
|
8
|
-
const { id, forcePosition, onOpen, onClose, active, defaultActive, children, width, contentGap, variant = "elevated", triggerType = "click", position = "bottom", disableHideAnimation, disableContentHover, instanceRef, containerRef, } = props;
|
8
|
+
const { id, forcePosition, onOpen, onClose, active, defaultActive, children, width, contentGap, variant = "elevated", triggerType = "click", position = "bottom", disableHideAnimation, disableContentHover, disableCloseOnOutsideClick, instanceRef, containerRef, } = props;
|
9
9
|
const padding = props.padding ?? (variant === "headless" ? 0 : 4);
|
10
10
|
const trapFocusMode = props.trapFocusMode || (triggerType === "hover" ? "content-menu" : undefined);
|
11
11
|
const paddingStyles = getPaddingStyles(padding);
|
12
12
|
const contentClassName = classNames(s.content, !!width && s["content--has-width"], variant && s[`content--variant-${variant}`], paddingStyles?.classNames);
|
13
13
|
return (
|
14
14
|
// @ts-ignore
|
15
|
-
_jsx(Flyout, { id: id, instanceRef: instanceRef, position: position, forcePosition: forcePosition, onOpen: onOpen, onClose: onClose, trapFocusMode: trapFocusMode, triggerType: triggerType, active: active, defaultActive: defaultActive, width: width, disableHideAnimation: disableHideAnimation, disableContentHover: disableContentHover, contentGap: contentGap, containerRef: containerRef, contentClassName: contentClassName, contentAttributes: { style: { ...paddingStyles?.variables } }, children: children }));
|
15
|
+
_jsx(Flyout, { id: id, instanceRef: instanceRef, position: position, forcePosition: forcePosition, onOpen: onOpen, onClose: onClose, trapFocusMode: trapFocusMode, triggerType: triggerType, active: active, defaultActive: defaultActive, width: width, disableHideAnimation: disableHideAnimation, disableContentHover: disableContentHover, disableCloseOnOutsideClick: disableCloseOnOutsideClick, contentGap: contentGap, containerRef: containerRef, contentClassName: contentClassName, contentAttributes: { style: { ...paddingStyles?.variables } }, children: children }));
|
16
16
|
};
|
17
17
|
const PopoverDismissible = (props) => {
|
18
18
|
const { handleClose } = useFlyoutContext();
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import type React from "react";
|
2
2
|
import type { FlyoutProps, FlyoutInstance } from "../_private/Flyout";
|
3
3
|
export type Instance = FlyoutInstance;
|
4
|
-
export type Props = Pick<FlyoutProps, "id" | "position" | "forcePosition" | "onOpen" | "onClose" | "width" | "trapFocusMode" | "active" | "defaultActive" | "contentGap" | "instanceRef" | "triggerType" | "disableHideAnimation" | "disableContentHover" | "containerRef"> & {
|
4
|
+
export type Props = Pick<FlyoutProps, "id" | "position" | "forcePosition" | "onOpen" | "onClose" | "width" | "trapFocusMode" | "active" | "defaultActive" | "contentGap" | "instanceRef" | "triggerType" | "disableHideAnimation" | "disableContentHover" | "disableCloseOnOutsideClick" | "containerRef"> & {
|
5
5
|
children?: React.ReactNode;
|
6
6
|
padding?: number;
|
7
7
|
variant?: "elevated" | "headless";
|
@@ -1 +1 @@
|
|
1
|
-
:root{--rs-z-index-raised:5;--rs-z-index-flyout:80;--rs-z-index-fixed:90;--rs-z-index-overlay:100;--rs-z-index-notification:110}@layer rs.reset{blockquote,body,dd,dl,figcaption,figure,h1,h2,h3,h4,h5,h6,li,ol,p,ul{margin:0;padding:0}ol[class],ul[class]{list-style:none}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}fieldset{border:0;margin:0;padding:0}img{display:block;max-width:100%}button,input,select,textarea{font:inherit}option{background:var(--rs-color-background-elevation-base)}label{cursor:pointer}input::placeholder,textarea::placeholder{color:var(--rs-color-foreground-neutral-faded);opacity:.5}html{-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;font-family:var(--rs-font-family-body);font-size:87.5%;font-weight:var(--rs-font-weight-regular);line-height:var(--rs-line-height-body-3);text-rendering:optimizelegibility;touch-action:manipulation}*{box-sizing:border-box}body,html{background:var(--rs-color-background-page);color:var(--rs-color-foreground-neutral);height:100%;scroll-behavior:smooth}}[data-rs-theme]:not(html){font-family:var(--rs-font-family-body);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-regular);line-height:var(--rs-line-height-body-3)}[data-rs-color-mode=light]{color-scheme:light}[data-rs-color-mode=dark]{color-scheme:dark}@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}[data-rs-no-transition] *,[data-rs-no-transition] :after,[data-rs-no-transition] :before{transition:none!important}
|
1
|
+
:root{--rs-z-index-raised:5;--rs-z-index-flyout:80;--rs-z-index-fixed:90;--rs-z-index-overlay:100;--rs-z-index-notification:110}@layer rs.reset{blockquote,body,dd,dl,figcaption,figure,h1,h2,h3,h4,h5,h6,li,ol,p,ul{margin:0;padding:0}ol[class],ul[class]{list-style:none}textarea{resize:vertical}table{border-collapse:collapse;border-spacing:0}fieldset{border:0;margin:0;padding:0}img{display:block;max-width:100%}button,input,select,textarea{font:inherit}option{background:var(--rs-color-background-elevation-base)}label{cursor:pointer}input::placeholder,textarea::placeholder{color:var(--rs-color-foreground-neutral-faded);opacity:.5}html{-webkit-text-size-adjust:100%;-webkit-font-smoothing:antialiased;font-family:var(--rs-font-family-body);font-size:87.5%;font-weight:var(--rs-font-weight-regular);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3);text-rendering:optimizelegibility;touch-action:manipulation}*{box-sizing:border-box}body,html{background:var(--rs-color-background-page);color:var(--rs-color-foreground-neutral);height:100%;scroll-behavior:smooth}}[data-rs-theme]:not(html){font-family:var(--rs-font-family-body);font-size:var(--rs-font-size-body-3);font-weight:var(--rs-font-weight-regular);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3)}[data-rs-color-mode=light]{color-scheme:light}[data-rs-color-mode=dark]{color-scheme:dark}@media (prefers-reduced-motion:reduce){*{animation-duration:.01ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-duration:.01ms!important}}[data-rs-no-transition] *,[data-rs-no-transition] :after,[data-rs-no-transition] :before{transition:none!important}
|
@@ -0,0 +1,149 @@
|
|
1
|
+
"use client";
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
3
|
+
import React from "react";
|
4
|
+
import { classNames } from "../../utilities/helpers.js";
|
5
|
+
import useDrag from "../../hooks/useDrag.js";
|
6
|
+
import View from "../View/index.js";
|
7
|
+
import s from "./Resizable.module.css";
|
8
|
+
const PrivateResizableHandle = (props) => {
|
9
|
+
const { containerRef, onDrag, index, direction, children } = props;
|
10
|
+
const { ref, active } = useDrag((args) => {
|
11
|
+
onDrag({ ...args, index });
|
12
|
+
}, {
|
13
|
+
containerRef,
|
14
|
+
orientation: direction === "row" ? "horizontal" : "vertical",
|
15
|
+
});
|
16
|
+
const handleClassNames = classNames(s.handle, active && s["handle--dragging"]);
|
17
|
+
if (children)
|
18
|
+
return _jsx(View.Item, { children: children({ ref }) });
|
19
|
+
return (_jsx(View.Item, { className: handleClassNames, attributes: {
|
20
|
+
role: "button",
|
21
|
+
tabIndex: 0,
|
22
|
+
ref: (el) => {
|
23
|
+
// @ts-ignore
|
24
|
+
ref.current = el;
|
25
|
+
},
|
26
|
+
} }));
|
27
|
+
};
|
28
|
+
const PrivateResizableItem = React.forwardRef((props, ref) => {
|
29
|
+
const { children, defaultSize, minSize, maxSize } = props;
|
30
|
+
const itemRef = React.useRef(null);
|
31
|
+
return (_jsx(View.Item, { grow: true, className: s.item, attributes: {
|
32
|
+
ref: (el) => {
|
33
|
+
if (typeof ref === "function")
|
34
|
+
ref(el);
|
35
|
+
itemRef.current = el;
|
36
|
+
},
|
37
|
+
style: {
|
38
|
+
"--rs-resizable-default-size": defaultSize,
|
39
|
+
"--rs-resizable-min-size": minSize,
|
40
|
+
"--rs-resizable-max-size": maxSize,
|
41
|
+
},
|
42
|
+
}, children: children }));
|
43
|
+
});
|
44
|
+
const Resizable = (props) => {
|
45
|
+
const { children, height, direction = "row", gap = 2, className, attributes } = props;
|
46
|
+
const rootClassNames = classNames(s.root, s[`--direction-${direction}`], className);
|
47
|
+
const containerRef = React.useRef(null);
|
48
|
+
const itemsRef = React.useRef([]);
|
49
|
+
const horizontal = direction === "row";
|
50
|
+
let currentHandleIndex = 0;
|
51
|
+
let currentItemIndex = 0;
|
52
|
+
itemsRef.current = [];
|
53
|
+
const checkedCrossedBoundaries = (args) => {
|
54
|
+
const { item, grow, itemsSize, itemsCount } = args;
|
55
|
+
const { minSize, maxSize } = item.props;
|
56
|
+
const nextPx = (grow / itemsCount / 100) * itemsSize;
|
57
|
+
const minPx = minSize && Number(minSize.replace("px", ""));
|
58
|
+
const maxPx = maxSize && Number(maxSize?.replace("px", ""));
|
59
|
+
if (minPx && minPx > nextPx)
|
60
|
+
return true;
|
61
|
+
if (maxPx && maxPx < nextPx)
|
62
|
+
return true;
|
63
|
+
return false;
|
64
|
+
};
|
65
|
+
const onDrag = (args) => {
|
66
|
+
const { index, x, y, triggerX, triggerY } = args;
|
67
|
+
const startItem = itemsRef.current[index];
|
68
|
+
const endItem = itemsRef.current[index + 1];
|
69
|
+
if (!startItem.el || !endItem.el)
|
70
|
+
return;
|
71
|
+
const itemsCount = itemsRef.current.length;
|
72
|
+
// Each item has a flex-grow of 1 as default and these values get updated while dragging for the items around the handle
|
73
|
+
// Grow value of all items besides currently updating ones
|
74
|
+
let currentItemsGrow = itemsCount * 100;
|
75
|
+
let itemsSize = 0;
|
76
|
+
itemsRef.current.forEach((item, i) => {
|
77
|
+
if (!item.el)
|
78
|
+
return;
|
79
|
+
itemsSize += horizontal ? item.el.clientWidth : item.el.clientHeight;
|
80
|
+
if (i === index || i === index + 1)
|
81
|
+
return;
|
82
|
+
currentItemsGrow -= Number(item.el.style.flexGrow || 100);
|
83
|
+
}, 0);
|
84
|
+
const startSize = horizontal ? startItem.el.clientWidth : startItem.el.clientHeight;
|
85
|
+
const startOffset = horizontal ? startItem.el.offsetLeft : startItem.el.offsetTop;
|
86
|
+
const endSize = horizontal ? endItem.el.clientWidth : endItem.el.clientHeight;
|
87
|
+
// Handles containing triggers are located lower based on the gap and padding inside the handle
|
88
|
+
const gapCompensation = (horizontal ? triggerX : triggerY) - startSize - startOffset;
|
89
|
+
const dragCoord = (horizontal ? x : y) - gapCompensation;
|
90
|
+
// Total size of the dragging area
|
91
|
+
const currentItemsSize = startSize + endSize;
|
92
|
+
// x is calculated based on container but we're changing grow based on current items
|
93
|
+
const percent = Math.min(1, Math.max(0, (dragCoord - startOffset) / currentItemsSize));
|
94
|
+
const nextStartGrow = Math.floor(percent * currentItemsGrow);
|
95
|
+
const nextEndGrow = Math.floor(currentItemsGrow - nextStartGrow);
|
96
|
+
// Validate that next grow values won't break the min/max size values
|
97
|
+
if (checkedCrossedBoundaries({ item: startItem, itemsSize, grow: nextStartGrow, itemsCount })) {
|
98
|
+
return;
|
99
|
+
}
|
100
|
+
if (checkedCrossedBoundaries({ item: endItem, itemsSize, grow: nextEndGrow, itemsCount })) {
|
101
|
+
return;
|
102
|
+
}
|
103
|
+
startItem.el.style.flexGrow = nextStartGrow.toString();
|
104
|
+
endItem.el.style.flexGrow = nextEndGrow.toString();
|
105
|
+
};
|
106
|
+
/**
|
107
|
+
* When passing sizes, items first get rendered with css
|
108
|
+
* and then have to be hydrated with flexGrow to enable correct resizing
|
109
|
+
*/
|
110
|
+
React.useEffect(() => {
|
111
|
+
const growValues = [];
|
112
|
+
// Calculate total size of items excluding gaps
|
113
|
+
let totalItemsSize = 0;
|
114
|
+
itemsRef.current.forEach((item) => {
|
115
|
+
if (!item.el)
|
116
|
+
return;
|
117
|
+
totalItemsSize += horizontal ? item.el.clientWidth : item.el.clientHeight;
|
118
|
+
});
|
119
|
+
// Calculate flex grow values of all items rendered by css originally
|
120
|
+
itemsRef.current.forEach((item, i) => {
|
121
|
+
if (!item.el)
|
122
|
+
return;
|
123
|
+
const itemSizePercent = (horizontal ? item.el.clientWidth : item.el.clientHeight) / totalItemsSize;
|
124
|
+
growValues[i] = itemsRef.current.length * itemSizePercent * 100;
|
125
|
+
});
|
126
|
+
// Apply flex grow after calculation is done to avoid layout shifts during the calculation
|
127
|
+
itemsRef.current.forEach((item, i) => {
|
128
|
+
if (!item.el || !growValues[i])
|
129
|
+
return;
|
130
|
+
item.el.style.flexGrow = growValues[i].toString();
|
131
|
+
item.el.setAttribute("data-rs-resizable-item-mounted", "");
|
132
|
+
});
|
133
|
+
}, [horizontal]);
|
134
|
+
const output = React.Children.map(children, (child) => {
|
135
|
+
const isComponent = React.isValidElement(child);
|
136
|
+
if (isComponent && child.type === Resizable.Handle && child.props) {
|
137
|
+
return (_jsx(PrivateResizableHandle, { ...child.props, containerRef: containerRef, index: currentHandleIndex++, onDrag: onDrag, direction: direction }));
|
138
|
+
}
|
139
|
+
if (isComponent && child.type === Resizable.Item && child.props) {
|
140
|
+
const index = currentHandleIndex;
|
141
|
+
return (_jsx(PrivateResizableItem, { ...child.props, index: currentItemIndex++, ref: (el) => (itemsRef.current[index] = { el, props: child.props }) }));
|
142
|
+
}
|
143
|
+
return null;
|
144
|
+
});
|
145
|
+
return (_jsx(View, { attributes: { ...attributes, ref: containerRef }, className: rootClassNames, height: height, direction: direction, align: "stretch", gap: gap, children: output }));
|
146
|
+
};
|
147
|
+
Resizable.Item = (() => null);
|
148
|
+
Resizable.Handle = (() => null);
|
149
|
+
export default Resizable;
|
@@ -0,0 +1 @@
|
|
1
|
+
.item{--rs-resizable-default-size:none;--rs-resizable-min-size:0;--rs-resizable-max-size:100%;flex-grow:100;max-width:var(--rs-resizable-default-size);min-width:var(--rs-resizable-default-size);overflow:hidden}.handle{flex-shrink:0;position:relative}.handle:after,.handle:before{border-radius:999px;content:"";position:absolute}.handle:after{background:var(--rs-color-border-neutral);opacity:0;transition:opacity var(--rs-duration-fast) var(--rs-easing-standard)}.handle--dragging:after,.handle:focus-visible:after,.handle:hover:after{opacity:.6}body:has(.handle--dragging) .handle:not(.handle--dragging){opacity:0}body:has(.--direction-row>.handle--dragging){cursor:ew-resize}body:has(.--direction-column>.handle--dragging){cursor:ns-resize}.--direction-row>.handle{cursor:ew-resize}.--direction-row>.handle:after,.--direction-row>.handle:before{inset-block:0;inset-inline-start:50%;transform:translateX(-50%)}.--direction-row>.handle:before{width:var(--rs-unit-x4)}.--direction-row>.handle:after{width:var(--rs-unit-x1)}.--direction-row>.item[data-rs-resizable-item-mounted]{max-width:var(--rs-resizable-max-size);min-width:var(--rs-resizable-min-size)}.--direction-column>.handle{cursor:ns-resize}.--direction-column>.handle:after,.--direction-column>.handle:before{inset-block-start:50%;inset-inline:0;transform:translateY(-50%)}.--direction-column>.handle:before{height:var(--rs-unit-x4)}.--direction-column>.handle:after{height:var(--rs-unit-x1)}.--direction-column>.item[data-rs-resizable-item-mounted]{max-height:var(--rs-resizable-max-size);min-height:var(--rs-resizable-min-size)}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import type React from "react";
|
2
|
+
import type { ViewProps } from "../View";
|
3
|
+
import type { UseDragCallbackArgs } from "../../hooks/useDrag";
|
4
|
+
export type Props = Pick<ViewProps, "children" | "className" | "attributes" | "height" | "direction" | "gap">;
|
5
|
+
export type ItemProps = {
|
6
|
+
children: React.ReactNode;
|
7
|
+
minSize?: `${number}px`;
|
8
|
+
maxSize?: `${number}px`;
|
9
|
+
defaultSize?: `${number}px`;
|
10
|
+
};
|
11
|
+
export type PrivateItemProps = ItemProps & {
|
12
|
+
index: number;
|
13
|
+
};
|
14
|
+
export type HandleProps = {
|
15
|
+
children?: (attributes: {
|
16
|
+
ref: React.RefObject<HTMLButtonElement>;
|
17
|
+
}) => React.ReactNode;
|
18
|
+
};
|
19
|
+
export type PrivateHandleProps = HandleProps & {
|
20
|
+
containerRef: React.RefObject<HTMLDivElement>;
|
21
|
+
index: number;
|
22
|
+
onDrag: (args: UseDragCallbackArgs & {
|
23
|
+
index: number;
|
24
|
+
}) => void;
|
25
|
+
} & Pick<Props, "direction">;
|
26
|
+
export type ItemsRefProps = {
|
27
|
+
el: HTMLDivElement | null;
|
28
|
+
props: ItemProps;
|
29
|
+
}[];
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from "./Resizable.js";
|
@@ -0,0 +1,15 @@
|
|
1
|
+
declare const _default: {
|
2
|
+
title: string;
|
3
|
+
component: {
|
4
|
+
(props: import("./..").ResizableProps): import("react").JSX.Element;
|
5
|
+
Item: import("react").FC<import("./..").ResizableItemProps>;
|
6
|
+
Handle: import("react").FC<import("./..").ResizableHandleProps>;
|
7
|
+
};
|
8
|
+
parameters: {
|
9
|
+
iframe: {
|
10
|
+
url: string;
|
11
|
+
};
|
12
|
+
};
|
13
|
+
};
|
14
|
+
export default _default;
|
15
|
+
export declare const base: () => import("react").JSX.Element;
|
@@ -0,0 +1,58 @@
|
|
1
|
+
import { Example } from "../../../utilities/storybook/index.js";
|
2
|
+
import Resizable from "../index.js";
|
3
|
+
import View from "../../View/index.js";
|
4
|
+
import Button from "../../Button/index.js";
|
5
|
+
export default {
|
6
|
+
title: "Components/Resizable",
|
7
|
+
component: Resizable,
|
8
|
+
parameters: {
|
9
|
+
iframe: {
|
10
|
+
url: "https://reshaped.so/docs/utilities/Resizable",
|
11
|
+
},
|
12
|
+
},
|
13
|
+
};
|
14
|
+
export const base = () => (<Example>
|
15
|
+
<Example.Item>
|
16
|
+
<Resizable height="300px" gap={4}>
|
17
|
+
<Resizable.Item minSize="100px" defaultSize="200px">
|
18
|
+
<View backgroundColor="neutral-faded" borderRadius="medium" align="center" justify="center" height="100%">
|
19
|
+
Panel
|
20
|
+
</View>
|
21
|
+
</Resizable.Item>
|
22
|
+
<Resizable.Handle />
|
23
|
+
<Resizable.Item>
|
24
|
+
<View backgroundColor="neutral-faded" borderRadius="medium" align="center" justify="center" height="100%">
|
25
|
+
Panel
|
26
|
+
</View>
|
27
|
+
</Resizable.Item>
|
28
|
+
<Resizable.Handle />
|
29
|
+
<Resizable.Item>
|
30
|
+
<Resizable height="100%" direction="column">
|
31
|
+
<Resizable.Item minSize="50px" maxSize="100px">
|
32
|
+
<View backgroundColor="neutral-faded" borderRadius="medium" align="center" justify="center" height="100%">
|
33
|
+
Panel
|
34
|
+
</View>
|
35
|
+
</Resizable.Item>
|
36
|
+
<Resizable.Handle />
|
37
|
+
<Resizable.Item>
|
38
|
+
<View backgroundColor="neutral-faded" borderRadius="medium" align="center" justify="center" height="100%">
|
39
|
+
Panel
|
40
|
+
</View>
|
41
|
+
</Resizable.Item>
|
42
|
+
<Resizable.Handle>
|
43
|
+
{(attributes) => (<View backgroundColor="primary-faded" padding={1} align="center" borderRadius="small">
|
44
|
+
<Button attributes={attributes} type="button">
|
45
|
+
Drag me
|
46
|
+
</Button>
|
47
|
+
</View>)}
|
48
|
+
</Resizable.Handle>
|
49
|
+
<Resizable.Item>
|
50
|
+
<View backgroundColor="neutral-faded" borderRadius="medium" align="center" justify="center" height="100%">
|
51
|
+
Panel
|
52
|
+
</View>
|
53
|
+
</Resizable.Item>
|
54
|
+
</Resizable>
|
55
|
+
</Resizable.Item>
|
56
|
+
</Resizable>
|
57
|
+
</Example.Item>
|
58
|
+
</Example>);
|
@@ -7,8 +7,10 @@ import getHeightStyles from "../../styles/height/index.js";
|
|
7
7
|
import getMaxHeightStyles from "../../styles/maxHeight/index.js";
|
8
8
|
import useIsomorphicLayoutEffect from "../../hooks/useIsomorphicLayoutEffect.js";
|
9
9
|
import s from "./ScrollArea.module.css";
|
10
|
+
import useHandlerRef from "../../hooks/useHandlerRef.js";
|
10
11
|
const ScrollAreaBar = (props) => {
|
11
12
|
const { ratio, position, vertical, onThumbMove } = props;
|
13
|
+
const onThumbMoveRef = useHandlerRef(onThumbMove);
|
12
14
|
const [dragging, setDragging] = React.useState(false);
|
13
15
|
const dragStartPositionRef = React.useRef(0);
|
14
16
|
const barRef = React.useRef(null);
|
@@ -38,10 +40,8 @@ const ScrollAreaBar = (props) => {
|
|
38
40
|
return;
|
39
41
|
const diff = vertical ? e.movementY : e.movementX;
|
40
42
|
const total = vertical ? elBar.scrollHeight : elBar.scrollWidth;
|
41
|
-
|
42
|
-
},
|
43
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
44
|
-
[ratio, vertical, dragging]);
|
43
|
+
onThumbMoveRef.current?.({ value: diff / total, type: "relative" });
|
44
|
+
}, [vertical, dragging, onThumbMoveRef]);
|
45
45
|
const handleDragEnd = React.useCallback(() => {
|
46
46
|
setDragging(false);
|
47
47
|
enableUserSelect();
|
@@ -1 +1 @@
|
|
1
|
-
.root{background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);display:flex;overflow:hidden;padding:calc(var(--rs-unit-x1) - 1px) 0;position:relative;z-index:0}.root:focus-within{border-color:var(--rs-color-border-primary);box-shadow:0 0 0 1px var(--rs-color-border-primary)}.input{align-items:center;-webkit-appearance:none;appearance:none;background:none;border:0;box-sizing:border-box;color:var(--rs-color-foreground-neutral);cursor:pointer;display:flex;flex-grow:1;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-regular);outline:none;padding-inline-end:calc(var(--rs-select-chevron-size) + var(--rs-select-gap) * 2 + var(--rs-unit-x1));padding-inline-start:var(--rs-select-gap);position:relative;width:100%;z-index:1}.input::-ms-expand{display:none}.slot{align-items:center;display:flex;flex-shrink:0;padding-inline-start:var(--rs-select-gap);position:relative;z-index:5}.input .slot{padding-inline-end:var(--rs-select-gap);padding-inline-start:0}.arrow{color:var(--rs-color-foreground-neutral-faded);display:flex;inset-block-start:50%;inset-inline-end:var(--rs-select-gap);pointer-events:none;position:absolute;transform:translateY(-50%);z-index:5}.--size-medium{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium .input{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded);border-color:transparent}.root.--variant-faded:focus-within{border-color:var(--rs-color-border-primary)}.root.--variant-headless{background:transparent;border-color:transparent}.root.--variant-headless.--status-error,.root.--variant-headless.--status-error:focus-within,.root.--variant-headless:focus-within{border-color:transparent;box-shadow:none}.root.--status-error{border-color:var(--rs-color-border-critical)}.root.--status-error:focus-within{border-color:var(--rs-color-border-primary)}.root.--placeholder .input{color:var(--rs-color-foreground-neutral-faded)}.root.--disabled{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled .arrow,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}@media (--rs-viewport-s ) and (hover:none){.input{font-size:var(--rs-font-size-body-2)!important}}@media (--rs-viewport-m ){.--size-medium--m{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium--m .input{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large--m{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large--m .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge--m{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge--m .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}}@media (--rs-viewport-l ){.--size-medium--l{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium--l .input{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large--l{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large--l .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge--l{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge--l .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}}@media (--rs-viewport-xl ){.--size-medium--xl{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium--xl .input{font-size:var(--rs-font-size-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large--xl{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large--xl .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge--xl{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge--xl .input{font-size:var(--rs-font-size-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}}
|
1
|
+
.root{background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);display:flex;overflow:hidden;padding:calc(var(--rs-unit-x1) - 1px) 0;position:relative;z-index:0}.root:focus-within{border-color:var(--rs-color-border-primary);box-shadow:0 0 0 1px var(--rs-color-border-primary)}.input{align-items:center;-webkit-appearance:none;appearance:none;background:none;border:0;box-sizing:border-box;color:var(--rs-color-foreground-neutral);cursor:pointer;display:flex;flex-grow:1;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-regular);outline:none;padding-inline-end:calc(var(--rs-select-chevron-size) + var(--rs-select-gap) * 2 + var(--rs-unit-x1));padding-inline-start:var(--rs-select-gap);position:relative;width:100%;z-index:1}.input::-ms-expand{display:none}.slot{align-items:center;display:flex;flex-shrink:0;padding-inline-start:var(--rs-select-gap);position:relative;z-index:5}.input .slot{padding-inline-end:var(--rs-select-gap);padding-inline-start:0}.arrow{color:var(--rs-color-foreground-neutral-faded);display:flex;inset-block-start:50%;inset-inline-end:var(--rs-select-gap);pointer-events:none;position:absolute;transform:translateY(-50%);z-index:5}.--size-medium{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium .input{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded);border-color:transparent}.root.--variant-faded:focus-within{border-color:var(--rs-color-border-primary)}.root.--variant-headless{background:transparent;border-color:transparent}.root.--variant-headless.--status-error,.root.--variant-headless.--status-error:focus-within,.root.--variant-headless:focus-within{border-color:transparent;box-shadow:none}.root.--status-error{border-color:var(--rs-color-border-critical)}.root.--status-error:focus-within{border-color:var(--rs-color-border-primary)}.root.--placeholder .input{color:var(--rs-color-foreground-neutral-faded)}.root.--disabled{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled .arrow,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}@media (--rs-viewport-s ) and (hover:none){.input{font-size:var(--rs-font-size-body-2)!important}}@media (--rs-viewport-m ){.--size-medium--m{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium--m .input{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large--m{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large--m .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge--m{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge--m .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}}@media (--rs-viewport-l ){.--size-medium--l{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium--l .input{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large--l{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large--l .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge--l{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge--l .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}}@media (--rs-viewport-xl ){.--size-medium--xl{--rs-select-gap:var(--rs-unit-x2);--rs-select-chevron-size:var(--rs-unit-x4);border-radius:var(--rs-radius-small)}.--size-medium--xl .input{font-size:var(--rs-font-size-body-3);letter-spacing:var(--rs-letter-spacing-body-3);line-height:var(--rs-line-height-body-3);padding-bottom:var(--rs-unit-x1);padding-top:var(--rs-unit-x1)}.--size-large--xl{--rs-select-gap:var(--rs-unit-x3);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-large--xl .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x2);padding-top:var(--rs-unit-x2)}.--size-xlarge--xl{--rs-select-gap:var(--rs-unit-x4);--rs-select-chevron-size:var(--rs-unit-x5);border-radius:var(--rs-radius-medium)}.--size-xlarge--xl .input{font-size:var(--rs-font-size-body-2);letter-spacing:var(--rs-letter-spacing-body-2);line-height:var(--rs-line-height-body-2);padding-bottom:var(--rs-unit-x3);padding-top:var(--rs-unit-x3)}}
|
@@ -48,9 +48,9 @@ type BaseProps = {
|
|
48
48
|
min?: number;
|
49
49
|
max?: number;
|
50
50
|
orientation?: "vertical" | "horizontal";
|
51
|
-
renderValue?: (args: {
|
51
|
+
renderValue?: ((args: {
|
52
52
|
value: number;
|
53
|
-
}) => string;
|
53
|
+
}) => string) | false;
|
54
54
|
className?: G.ClassName;
|
55
55
|
attributes?: G.Attributes<"div">;
|
56
56
|
};
|
@@ -15,10 +15,10 @@ export const applyStepToValue = (value, step) => {
|
|
15
15
|
export const getDragCoord = ({ event, vertical, }) => {
|
16
16
|
if (vertical) {
|
17
17
|
if (event instanceof MouseEvent)
|
18
|
-
return event.
|
19
|
-
return event.changedTouches[0].
|
18
|
+
return event.clientY;
|
19
|
+
return event.changedTouches[0].clientY;
|
20
20
|
}
|
21
21
|
if (event instanceof MouseEvent)
|
22
|
-
return event.
|
23
|
-
return event.changedTouches[0].
|
22
|
+
return event.clientX;
|
23
|
+
return event.changedTouches[0].clientX;
|
24
24
|
};
|
@@ -9,9 +9,12 @@ import { useFormControl } from "../FormControl/index.js";
|
|
9
9
|
import SliderThumb from "./SliderThumb.js";
|
10
10
|
import { applyStepToValue, getDragCoord } from "./Slider.utilities.js";
|
11
11
|
import s from "./Slider.module.css";
|
12
|
+
import useHandlerRef from "../../hooks/useHandlerRef.js";
|
12
13
|
const THUMB_SIZE = 16;
|
13
14
|
const SliderControlled = (props) => {
|
14
15
|
const { name, range, max, min, step = 1, onChange, onChangeCommit, renderValue, className, attributes, orientation = "horizontal", } = props;
|
16
|
+
const onChangeRef = useHandlerRef(onChange);
|
17
|
+
const onChangeCommitRef = useHandlerRef(onChangeCommit);
|
15
18
|
const vertical = orientation === "vertical";
|
16
19
|
const minValue = range && props.minValue !== undefined ? applyStepToValue(props.minValue, step) : undefined;
|
17
20
|
const maxValue = applyStepToValue(range ? props.maxValue : props.value, step);
|
@@ -79,22 +82,21 @@ const SliderControlled = (props) => {
|
|
79
82
|
const handleMinChange = React.useCallback((value, options) => {
|
80
83
|
if (!range)
|
81
84
|
return;
|
82
|
-
const method = options?.commit ?
|
85
|
+
const method = options?.commit ? onChangeCommitRef.current : onChangeRef.current;
|
86
|
+
// @ts-ignore - creating refs out of handler props loses connection to the range flag
|
83
87
|
method?.({ minValue: value, maxValue, name });
|
84
|
-
},
|
85
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
86
|
-
[maxValue, name, range]);
|
88
|
+
}, [maxValue, name, range, onChangeCommitRef, onChangeRef]);
|
87
89
|
const handleMaxChange = React.useCallback((value, options) => {
|
88
90
|
if (range) {
|
89
|
-
const method = options?.commit ?
|
91
|
+
const method = options?.commit ? onChangeCommitRef.current : onChangeRef.current;
|
92
|
+
// @ts-ignore - creating refs out of handler props loses connection to the range flag
|
90
93
|
method?.({ minValue: minValue, maxValue: value, name });
|
91
94
|
return;
|
92
95
|
}
|
93
|
-
const method = options?.commit ?
|
96
|
+
const method = options?.commit ? onChangeCommitRef.current : onChangeRef.current;
|
97
|
+
// @ts-ignore - creating refs out of handler props loses connection to the range flag
|
94
98
|
method?.({ value, name });
|
95
|
-
},
|
96
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
97
|
-
[minValue, name, range]);
|
99
|
+
}, [minValue, name, range, onChangeRef, onChangeCommitRef]);
|
98
100
|
const handleMouseDown = ({ nativeEvent }) => {
|
99
101
|
if (disabled)
|
100
102
|
return;
|
@@ -15,6 +15,6 @@ const SliderThumb = (props, ref) => {
|
|
15
15
|
const handleChange = (e) => {
|
16
16
|
onChange(+e.target.value);
|
17
17
|
};
|
18
|
-
return (_jsxs(_Fragment, { children: [_jsx("input", { className: s.input, type: "range", name: name, value: value, onChange: handleChange, disabled: disabled, max: max, min: min, step: step, "aria-labelledby": id, "aria-orientation": orientation }), _jsx("div", { ref: ref, className: thumbClassNames, onMouseDown: onDragStart, onTouchStart: onDragStart, style: { "--ts-slider-thumb-position": `${position}%` }, id: id, "aria-hidden": "true", children: _jsx(Theme, { colorMode: "inverted", children: _jsx(Text, { variant: "caption-1", weight: "medium", className: s.tooltip, attributes: { ref: tooltipRef }, children: tooltipValue }) }) })] }));
|
18
|
+
return (_jsxs(_Fragment, { children: [_jsx("input", { className: s.input, type: "range", name: name, value: value, onChange: handleChange, disabled: disabled, max: max, min: min, step: step, "aria-labelledby": id, "aria-orientation": orientation }), _jsx("div", { ref: ref, className: thumbClassNames, onMouseDown: onDragStart, onTouchStart: onDragStart, style: { "--ts-slider-thumb-position": `${position}%` }, id: id, "aria-hidden": "true", children: renderValue !== false && (_jsx(Theme, { colorMode: "inverted", children: _jsx(Text, { variant: "caption-1", weight: "medium", className: s.tooltip, attributes: { ref: tooltipRef }, children: tooltipValue }) })) })] }));
|
19
19
|
};
|
20
20
|
export default React.forwardRef(SliderThumb);
|
@@ -22,6 +22,7 @@ export const direction = () => (<Example>
|
|
22
22
|
<View height="200px">
|
23
23
|
<Slider range name="slider" defaultMinValue={30} defaultMaxValue={100} orientation="vertical"/>
|
24
24
|
</View>
|
25
|
+
<View height="2000px"/>
|
25
26
|
</Example.Item>
|
26
27
|
</Example>);
|
27
28
|
export const step = () => (<Example>
|
@@ -49,6 +50,9 @@ export const customRender = () => (<Example>
|
|
49
50
|
<Example.Item title="custom render">
|
50
51
|
<Slider name="slider" defaultValue={30} renderValue={(args) => `$${args.value}`}/>
|
51
52
|
</Example.Item>
|
53
|
+
<Example.Item title="no tooltip">
|
54
|
+
<Slider name="slider" defaultValue={30} renderValue={false}/>
|
55
|
+
</Example.Item>
|
52
56
|
</Example>);
|
53
57
|
export const formControl = () => (<Example>
|
54
58
|
<Example.Item title="form control, disabled">
|