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.
Files changed (90) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/bin/cli.js +0 -1
  3. package/dist/bundle.css +1 -1
  4. package/dist/bundle.d.ts +3 -1
  5. package/dist/bundle.js +10 -10
  6. package/dist/cjs/themes/_generator/tokens/font/font.transforms.js +6 -0
  7. package/dist/cjs/themes/_generator/tokens/font/font.types.d.ts +1 -0
  8. package/dist/cjs/themes/_generator/tokens/types.d.ts +1 -1
  9. package/dist/cjs/themes/_generator/utilities/color.d.ts +16 -0
  10. package/dist/cjs/themes/_generator/utilities/color.js +57 -7
  11. package/dist/cjs/themes/_generator/utilities/generateBackgroundColors.js +4 -0
  12. package/dist/cjs/themes/_generator/utilities/tests/color.test.js +73 -42
  13. package/dist/cjs/themes/figma/theme.css +1 -1
  14. package/dist/cjs/themes/index.d.ts +17 -0
  15. package/dist/cjs/themes/index.js +3 -0
  16. package/dist/cjs/themes/reshaped/theme.css +1 -1
  17. package/dist/cjs/themes/slate/theme.css +1 -1
  18. package/dist/cjs/types/config.d.ts +1 -0
  19. package/dist/components/Button/Button.module.css +1 -1
  20. package/dist/components/Button/tests/Button.stories.js +3 -1
  21. package/dist/components/DropdownMenu/DropdownMenu.module.css +1 -1
  22. package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +1 -1
  23. package/dist/components/MenuItem/MenuItem.module.css +1 -1
  24. package/dist/components/Modal/Modal.js +4 -3
  25. package/dist/components/Modal/tests/Modal.stories.d.ts +0 -1
  26. package/dist/components/Modal/tests/Modal.stories.js +0 -16
  27. package/dist/components/Overlay/Overlay.js +7 -7
  28. package/dist/components/Overlay/tests/Overlay.stories.js +3 -1
  29. package/dist/components/Popover/Popover.js +2 -2
  30. package/dist/components/Popover/Popover.types.d.ts +1 -1
  31. package/dist/components/Reshaped/Reshaped.css +1 -1
  32. package/dist/components/Resizable/Resizable.d.ts +8 -0
  33. package/dist/components/Resizable/Resizable.js +149 -0
  34. package/dist/components/Resizable/Resizable.module.css +1 -0
  35. package/dist/components/Resizable/Resizable.types.d.ts +29 -0
  36. package/dist/components/Resizable/Resizable.types.js +1 -0
  37. package/dist/components/Resizable/index.d.ts +2 -0
  38. package/dist/components/Resizable/index.js +1 -0
  39. package/dist/components/Resizable/tests/Resizable.stories.d.ts +15 -0
  40. package/dist/components/Resizable/tests/Resizable.stories.js +58 -0
  41. package/dist/components/ScrollArea/ScrollArea.js +4 -4
  42. package/dist/components/Select/Select.module.css +1 -1
  43. package/dist/components/Slider/Slider.types.d.ts +2 -2
  44. package/dist/components/Slider/Slider.utilities.js +4 -4
  45. package/dist/components/Slider/SliderControlled.js +11 -9
  46. package/dist/components/Slider/SliderThumb.js +1 -1
  47. package/dist/components/Slider/tests/Slider.stories.js +4 -0
  48. package/dist/components/Text/Text.module.css +1 -1
  49. package/dist/components/TextArea/TextArea.module.css +1 -1
  50. package/dist/components/TextField/TextField.module.css +1 -1
  51. package/dist/components/Toast/Toast.types.d.ts +7 -6
  52. package/dist/components/Toast/index.d.ts +1 -1
  53. package/dist/components/Toast/useToast.d.ts +1 -1
  54. package/dist/components/Tooltip/tests/Tooltip.stories.js +31 -0
  55. package/dist/components/_private/Flyout/Flyout.context.d.ts +3 -1
  56. package/dist/components/_private/Flyout/Flyout.context.js +4 -1
  57. package/dist/components/_private/Flyout/Flyout.types.d.ts +1 -0
  58. package/dist/components/_private/Flyout/FlyoutContent.js +5 -7
  59. package/dist/components/_private/Flyout/FlyoutControlled.js +18 -12
  60. package/dist/components/_private/Flyout/FlyoutTrigger.js +3 -2
  61. package/dist/components/_private/Flyout/tests/Flyout.stories.d.ts +2 -8
  62. package/dist/components/_private/Flyout/tests/Flyout.stories.js +87 -62
  63. package/dist/components/_private/Flyout/useFlyout.js +11 -2
  64. package/dist/components/_private/Portal/Portal.module.css +1 -1
  65. package/dist/hooks/_private/useOnClickOutside.js +5 -3
  66. package/dist/hooks/tests/useDrag.stories.d.ts +6 -0
  67. package/dist/hooks/tests/useDrag.stories.js +29 -0
  68. package/dist/hooks/useDrag.d.ts +17 -0
  69. package/dist/hooks/useDrag.js +116 -0
  70. package/dist/hooks/useHandlerRef.d.ts +8 -0
  71. package/dist/hooks/useHandlerRef.js +16 -0
  72. package/dist/hooks/useScrollLock.js +4 -3
  73. package/dist/hooks/useToggle.js +1 -1
  74. package/dist/index.d.ts +3 -1
  75. package/dist/index.js +1 -0
  76. package/dist/themes/_generator/tests/themes.stories.js +23 -0
  77. package/dist/themes/_generator/tokens/font/font.transforms.js +6 -0
  78. package/dist/themes/_generator/tokens/font/font.types.d.ts +1 -0
  79. package/dist/themes/_generator/tokens/types.d.ts +1 -1
  80. package/dist/themes/_generator/utilities/color.d.ts +16 -0
  81. package/dist/themes/_generator/utilities/color.js +54 -6
  82. package/dist/themes/_generator/utilities/generateBackgroundColors.js +4 -0
  83. package/dist/themes/figma/theme.css +1 -1
  84. package/dist/themes/index.d.ts +17 -0
  85. package/dist/themes/index.js +3 -0
  86. package/dist/themes/reshaped/theme.css +1 -1
  87. package/dist/themes/slate/theme.css +1 -1
  88. package/dist/types/config.d.ts +1 -0
  89. package/dist/types/global.d.ts +1 -1
  90. 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
- onClose?.();
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
- // eslint-disable-next-line react-hooks/exhaustive-deps
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
- if (onClose)
39
- onClose();
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
- onOpen?.();
88
+ onOpenRef.current?.();
88
89
  return () => trapFocus.release();
89
90
  // Ignoring onOpen since it might be not memoized when passed
90
- // eslint-disable-next-line react-hooks/exhaustive-deps
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.define("custom-element", CustomElement);
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,8 @@
1
+ import React from "react";
2
+ import type * as T from "./Resizable.types";
3
+ declare const Resizable: {
4
+ (props: T.Props): import("react/jsx-runtime").JSX.Element;
5
+ Item: React.FC<T.ItemProps>;
6
+ Handle: React.FC<T.HandleProps>;
7
+ };
8
+ export default Resizable;
@@ -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,2 @@
1
+ export { default } from "./Resizable";
2
+ export type { Props as ResizableProps, ItemProps as ResizableItemProps, HandleProps as ResizableHandleProps, } from "./Resizable.types";
@@ -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
- onThumbMove({ value: diff / total, type: "relative" });
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.pageY || event.screenY;
19
- return event.changedTouches[0].pageY;
18
+ return event.clientY;
19
+ return event.changedTouches[0].clientY;
20
20
  }
21
21
  if (event instanceof MouseEvent)
22
- return event.pageX || event.screenX;
23
- return event.changedTouches[0].pageX;
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 ? onChangeCommit : onChange;
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 ? onChangeCommit : onChange;
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 ? onChangeCommit : onChange;
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">