reshaped 3.5.4-canary.0 → 3.6.0-canary.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 (78) hide show
  1. package/CHANGELOG.md +11 -43
  2. package/dist/bundle.css +1 -1
  3. package/dist/bundle.d.ts +36 -31
  4. package/dist/bundle.js +10 -10
  5. package/dist/components/Autocomplete/tests/Autocomplete.stories.js +0 -1
  6. package/dist/components/Button/Button.types.d.ts +1 -1
  7. package/dist/components/Card/Card.d.ts +1 -1
  8. package/dist/components/Checkbox/Checkbox.module.css +1 -1
  9. package/dist/components/DropdownMenu/DropdownMenu.js +1 -1
  10. package/dist/components/DropdownMenu/DropdownMenu.types.d.ts +1 -1
  11. package/dist/components/DropdownMenu/tests/DropdownMenu.stories.d.ts +1 -1
  12. package/dist/components/DropdownMenu/tests/DropdownMenu.test.stories.d.ts +1 -1
  13. package/dist/components/Flyout/Flyout.constants.d.ts +6 -0
  14. package/dist/components/Flyout/Flyout.constants.js +19 -0
  15. package/dist/components/{_private/Flyout → Flyout}/Flyout.types.d.ts +3 -3
  16. package/dist/components/{_private/Flyout → Flyout}/FlyoutContent.js +25 -20
  17. package/dist/components/{_private/Flyout → Flyout}/FlyoutControlled.js +9 -9
  18. package/dist/components/{_private/Flyout → Flyout}/tests/Flyout.stories.d.ts +6 -4
  19. package/dist/components/{_private/Flyout → Flyout}/tests/Flyout.stories.js +128 -118
  20. package/dist/components/{_private/Flyout → Flyout}/useFlyout.d.ts +1 -1
  21. package/dist/components/Flyout/useFlyout.js +116 -0
  22. package/dist/components/Flyout/utilities/calculatePosition.d.ts +30 -0
  23. package/dist/components/Flyout/utilities/calculatePosition.js +129 -0
  24. package/dist/components/Flyout/utilities/flyout.d.ts +11 -0
  25. package/dist/components/Flyout/utilities/flyout.js +79 -0
  26. package/dist/components/Flyout/utilities/isFullyVisible.d.ts +10 -0
  27. package/dist/components/Flyout/utilities/isFullyVisible.js +24 -0
  28. package/dist/components/Link/Link.d.ts +1 -1
  29. package/dist/components/Popover/Popover.d.ts +1 -1
  30. package/dist/components/Popover/Popover.js +1 -1
  31. package/dist/components/Popover/Popover.types.d.ts +2 -1
  32. package/dist/components/Popover/tests/Popover.stories.d.ts +2 -2
  33. package/dist/components/Popover/tests/Popover.test.stories.d.ts +2 -2
  34. package/dist/components/Radio/Radio.module.css +1 -1
  35. package/dist/components/ScrollArea/ScrollArea.js +6 -3
  36. package/dist/components/ScrollArea/tests/ScrollArea.stories.d.ts +4 -13
  37. package/dist/components/ScrollArea/tests/ScrollArea.stories.js +30 -129
  38. package/dist/components/ScrollArea/tests/ScrollArea.test.stories.d.ts +23 -0
  39. package/dist/components/ScrollArea/tests/ScrollArea.test.stories.js +66 -0
  40. package/dist/components/Tabs/TabsContext.d.ts +2 -2
  41. package/dist/components/Tooltip/Tooltip.js +1 -1
  42. package/dist/components/Tooltip/Tooltip.types.d.ts +1 -1
  43. package/dist/config/tailwind.d.ts +1 -1
  44. package/dist/hooks/useIsomorphicLayoutEffect.d.ts +1 -1
  45. package/dist/index.d.ts +36 -31
  46. package/dist/index.js +20 -16
  47. package/dist/utilities/dom/find.d.ts +6 -9
  48. package/dist/utilities/dom/find.js +17 -15
  49. package/dist/utilities/dom/index.d.ts +1 -1
  50. package/dist/utilities/dom/index.js +1 -1
  51. package/dist/utilities/scroll/lock.js +4 -3
  52. package/package.json +10 -9
  53. package/CHANGELOG-old.md +0 -14
  54. package/dist/components/_private/Flyout/Flyout.constants.d.ts +0 -3
  55. package/dist/components/_private/Flyout/Flyout.constants.js +0 -3
  56. package/dist/components/_private/Flyout/useFlyout.js +0 -211
  57. package/dist/components/_private/Flyout/utilities/calculatePosition.d.ts +0 -19
  58. package/dist/components/_private/Flyout/utilities/calculatePosition.js +0 -102
  59. package/dist/components/_private/Flyout/utilities/isFullyVisible.d.ts +0 -8
  60. package/dist/components/_private/Flyout/utilities/isFullyVisible.js +0 -16
  61. /package/dist/components/{_private/Flyout → Flyout}/Flyout.context.d.ts +0 -0
  62. /package/dist/components/{_private/Flyout → Flyout}/Flyout.context.js +0 -0
  63. /package/dist/components/{_private/Flyout → Flyout}/Flyout.d.ts +0 -0
  64. /package/dist/components/{_private/Flyout → Flyout}/Flyout.js +0 -0
  65. /package/dist/components/{_private/Flyout → Flyout}/Flyout.module.css +0 -0
  66. /package/dist/components/{_private/Flyout → Flyout}/Flyout.types.js +0 -0
  67. /package/dist/components/{_private/Flyout → Flyout}/FlyoutContent.d.ts +0 -0
  68. /package/dist/components/{_private/Flyout → Flyout}/FlyoutControlled.d.ts +0 -0
  69. /package/dist/components/{_private/Flyout → Flyout}/FlyoutTrigger.d.ts +0 -0
  70. /package/dist/components/{_private/Flyout → Flyout}/FlyoutTrigger.js +0 -0
  71. /package/dist/components/{_private/Flyout → Flyout}/FlyoutUncontrolled.d.ts +0 -0
  72. /package/dist/components/{_private/Flyout → Flyout}/FlyoutUncontrolled.js +0 -0
  73. /package/dist/components/{_private/Flyout → Flyout}/index.d.ts +0 -0
  74. /package/dist/components/{_private/Flyout → Flyout}/index.js +0 -0
  75. /package/dist/components/{_private/Flyout → Flyout}/utilities/cooldown.d.ts +0 -0
  76. /package/dist/components/{_private/Flyout → Flyout}/utilities/cooldown.js +0 -0
  77. /package/dist/components/{_private/Flyout → Flyout}/utilities/getPositionFallbacks.d.ts +0 -0
  78. /package/dist/components/{_private/Flyout → Flyout}/utilities/getPositionFallbacks.js +0 -0
@@ -0,0 +1,79 @@
1
+ import { getRectFromCoordinates, getShadowRoot, findClosestPositionContainer } from "../../../utilities/dom/index.js";
2
+ import calculatePosition from "./calculatePosition.js";
3
+ import getPositionFallbacks from "./getPositionFallbacks.js";
4
+ import isFullyVisible from "./isFullyVisible.js";
5
+ import { resetStyles } from "../Flyout.constants.js";
6
+ /**
7
+ * Set position of the target element to fit on the screen
8
+ */
9
+ const flyout = (args) => {
10
+ const { triggerEl, flyoutEl, triggerBounds: passedTriggerBounds, contentShift = 0, contentGap = 0, position, fallbackPositions, width, container: passedContainer, lastUsedFallback, onFallback, rtl, } = args;
11
+ const targetClone = flyoutEl.cloneNode(true);
12
+ const baseUnit = getComputedStyle(flyoutEl).getPropertyValue("--rs-unit-x1");
13
+ const unitModifier = baseUnit ? parseInt(baseUnit) : 4;
14
+ const triggerBounds = passedTriggerBounds || triggerEl?.getBoundingClientRect();
15
+ if (!triggerBounds)
16
+ return;
17
+ const resolvedTriggerBounds = getRectFromCoordinates(triggerBounds);
18
+ // Reset all styles applied on the previous hook execution
19
+ targetClone.style.cssText = "";
20
+ Object.keys(resetStyles).forEach((key) => {
21
+ const value = resetStyles[key];
22
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
23
+ // @ts-ignore
24
+ if (value)
25
+ targetClone.style[key] = value.toString();
26
+ });
27
+ if (width === "trigger") {
28
+ targetClone.style.width = `${resolvedTriggerBounds.width}px`;
29
+ }
30
+ else if (width && width !== "full") {
31
+ targetClone.style.width = width;
32
+ }
33
+ const shadowRoot = triggerEl && getShadowRoot(triggerEl);
34
+ // Insert inside shadow root if possible to make sure styles are applied correctly
35
+ (shadowRoot || document.body).appendChild(targetClone);
36
+ const cloneRect = targetClone.getBoundingClientRect();
37
+ const flyoutBounds = { width: cloneRect.width, height: cloneRect.height };
38
+ const closestFixedContainer = !passedContainer && triggerEl ? findClosestPositionContainer({ el: triggerEl }) : undefined;
39
+ const container = passedContainer ||
40
+ // Render inside fixed position container automatically to keep their position synced on scroll
41
+ closestFixedContainer ||
42
+ document.body;
43
+ const renderContainerBounds = container.getBoundingClientRect();
44
+ const visualContainerBounds = (passedContainer || document.body).getBoundingClientRect();
45
+ let calculated = null;
46
+ const testOrder = getPositionFallbacks(position, fallbackPositions);
47
+ testOrder.some((currentPosition) => {
48
+ const tested = calculatePosition({
49
+ triggerBounds: resolvedTriggerBounds,
50
+ flyoutBounds,
51
+ containerBounds: renderContainerBounds,
52
+ position: currentPosition,
53
+ contentGap: contentGap * unitModifier,
54
+ contentShift: contentShift * unitModifier,
55
+ rtl,
56
+ width,
57
+ passedContainer,
58
+ });
59
+ const visible = isFullyVisible({
60
+ flyoutBounds: tested.boundaries,
61
+ visualContainerBounds,
62
+ renderContainerBounds,
63
+ container,
64
+ });
65
+ const validPosition = visible || fallbackPositions?.length === 0;
66
+ // Saving first try in case non of the options work
67
+ if (validPosition || lastUsedFallback === currentPosition) {
68
+ calculated = tested;
69
+ onFallback(currentPosition);
70
+ }
71
+ return validPosition;
72
+ });
73
+ if (!calculated) {
74
+ throw new Error(`[Reshaped] Can't calculate styles for the ${position} position`);
75
+ }
76
+ targetClone.parentNode?.removeChild(targetClone);
77
+ return calculated;
78
+ };
79
+ export default flyout;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Check if element visually fits on the screen
3
+ */
4
+ declare const isFullyVisible: (args: {
5
+ flyoutBounds: Pick<DOMRect, "left" | "top" | "width" | "height">;
6
+ visualContainerBounds: DOMRect;
7
+ renderContainerBounds: DOMRect;
8
+ container: HTMLElement;
9
+ }) => boolean;
10
+ export default isFullyVisible;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Check if element visually fits on the screen
3
+ */
4
+ const isFullyVisible = (args) => {
5
+ const { flyoutBounds, visualContainerBounds, renderContainerBounds, container } = args;
6
+ const scrollX = container === document.body ? window.scrollX : container.scrollLeft;
7
+ const scrollY = container === document.body ? window.scrollY : container.scrollTop;
8
+ if (renderContainerBounds.left + flyoutBounds.left - scrollX < visualContainerBounds.left) {
9
+ return false;
10
+ }
11
+ if (renderContainerBounds.top + flyoutBounds.top - scrollY < visualContainerBounds.top) {
12
+ return false;
13
+ }
14
+ if (renderContainerBounds.left + flyoutBounds.left + flyoutBounds.width - scrollX >
15
+ visualContainerBounds.right) {
16
+ return false;
17
+ }
18
+ if (renderContainerBounds.top + flyoutBounds.top + flyoutBounds.height - scrollY >
19
+ visualContainerBounds.bottom) {
20
+ return false;
21
+ }
22
+ return true;
23
+ };
24
+ export default isFullyVisible;
@@ -1,5 +1,5 @@
1
1
  import { type ActionableRef } from "../Actionable";
2
- declare const Link: import("react").ForwardRefExoticComponent<Pick<import("../Actionable").ActionableProps, "disabled" | "className" | "attributes" | "children" | "type" | "onClick" | "href" | "stopPropagation"> & {
2
+ declare const Link: import("react").ForwardRefExoticComponent<Pick<import("../Actionable").ActionableProps, "disabled" | "children" | "className" | "attributes" | "type" | "href" | "onClick" | "stopPropagation"> & {
3
3
  icon?: import("../Icon").IconProps["svg"];
4
4
  color?: "inherit" | "critical" | "primary" | "positive" | "warning";
5
5
  variant?: "plain" | "underline";
@@ -1,4 +1,4 @@
1
- import Flyout from "../_private/Flyout";
1
+ import Flyout from "../Flyout";
2
2
  import { type DismissibleProps } from "../Dismissible";
3
3
  import type * as T from "./Popover.types";
4
4
  declare const Popover: React.FC<T.Props> & {
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { classNames } from "../../utilities/helpers.js";
3
- import Flyout, { useFlyoutContext } from "../_private/Flyout/index.js";
3
+ import Flyout, { useFlyoutContext } from "../Flyout/index.js";
4
4
  import Dismissible from "../Dismissible/index.js";
5
5
  import s from "./Popover.module.css";
6
6
  import getPaddingStyles from "../../styles/padding/index.js";
@@ -1,8 +1,9 @@
1
1
  import type React from "react";
2
- import type { FlyoutProps, FlyoutInstance } from "../_private/Flyout";
2
+ import type { FlyoutProps, FlyoutInstance } from "../Flyout";
3
3
  export type Instance = FlyoutInstance;
4
4
  export type Props = Pick<FlyoutProps, "id" | "position" | "forcePosition" | "fallbackPositions" | "onOpen" | "onClose" | "width" | "trapFocusMode" | "active" | "defaultActive" | "contentGap" | "contentShift" | "instanceRef" | "triggerType" | "disableHideAnimation" | "disableContentHover" | "disableCloseOnOutsideClick" | "containerRef" | "initialFocusRef" | "originCoordinates"> & {
5
5
  children?: React.ReactNode;
6
6
  padding?: number;
7
+ /** @deprecated use Flyout utility instead, will be removed in v4 */
7
8
  variant?: "elevated" | "headless";
8
9
  };
@@ -2,8 +2,8 @@ declare const _default: {
2
2
  title: string;
3
3
  component: import("react").FC<import("./..").PopoverProps> & {
4
4
  Dismissible: import("react").FC<import("../../Dismissible").DismissibleProps>;
5
- Trigger: import("react").FC<import("../../_private/Flyout").FlyoutTriggerProps>;
6
- Content: import("react").FC<import("../../_private/Flyout").FlyoutContentProps>;
5
+ Trigger: import("react").FC<import("../../Flyout").FlyoutTriggerProps>;
6
+ Content: import("react").FC<import("../../Flyout").FlyoutContentProps>;
7
7
  };
8
8
  parameters: {
9
9
  iframe: {
@@ -4,8 +4,8 @@ declare const _default: {
4
4
  title: string;
5
5
  component: import("react").FC<import("./..").PopoverProps> & {
6
6
  Dismissible: import("react").FC<import("../../Dismissible").DismissibleProps>;
7
- Trigger: import("react").FC<import("../../_private/Flyout").FlyoutTriggerProps>;
8
- Content: import("react").FC<import("../../_private/Flyout").FlyoutContentProps>;
7
+ Trigger: import("react").FC<import("../../Flyout").FlyoutTriggerProps>;
8
+ Content: import("react").FC<import("../../Flyout").FlyoutContentProps>;
9
9
  };
10
10
  parameters: {
11
11
  iframe: {
@@ -1 +1 @@
1
- .root{align-items:center;cursor:pointer;display:inline-flex;gap:var(--rs-radio-gap);user-select:none;vertical-align:top;-webkit-tap-highlight-color:transparent}.root:hover .decorator{background:var(--rs-color-background-neutral-faded)}.field{position:relative}.decorator{background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);border-radius:50%;height:var(--rs-radio-line-height);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,border-color;width:var(--rs-radio-line-height)}.decorator:after{background:var(--rs-color-on-background-primary);border-radius:50%;content:"";height:calc(var(--rs-radio-line-height) * .4);left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:opacity,transform;width:calc(var(--rs-radio-line-height) * .4)}.--size-small{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}[data-rs-keyboard] .input:focus+.decorator{box-shadow:var(--rs-focus-shadow)}.root.--error .decorator{border-color:var(--rs-color-border-critical)}.input:checked+.decorator{background:var(--rs-color-background-primary);border-color:var(--rs-color-background-primary)}.input:checked+.decorator:after{opacity:1;transform:translate(-50%,-50%) scale(1)}.root.--disabled{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.root.--disabled .decorator{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled .decorator:after{background-color:var(--rs-color-foreground-disabled)}.root.--disabled .input:checked+.decorator{background:var(--rs-color-background-disabled);border-color:transparent}@media (--rs-viewport-m ){.--size-small--m{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--m{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--m{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}@media (--rs-viewport-l ){.--size-small--l{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--l{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--l{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--xl{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--xl{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}
1
+ @layer rs.radio.base;@layer rs.radio.error;@layer rs.radio.checked;@layer rs.radio.disabled;@layer rs.radio.base{.root{align-items:center;cursor:pointer;display:inline-flex;gap:var(--rs-radio-gap);user-select:none;vertical-align:top;-webkit-tap-highlight-color:transparent}.root:hover .decorator{background:var(--rs-color-background-neutral-faded)}.field{position:relative}.decorator{background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);border-radius:50%;height:var(--rs-radio-line-height);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,border-color;width:var(--rs-radio-line-height)}.decorator:after{background:var(--rs-color-on-background-primary);border-radius:50%;content:"";height:calc(var(--rs-radio-line-height) * .4);left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:opacity,transform;width:calc(var(--rs-radio-line-height) * .4)}.--size-small{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}[data-rs-keyboard] .input:focus+.decorator{box-shadow:var(--rs-focus-shadow)}}@layer rs.radio.error{.root.--error .decorator{border-color:var(--rs-color-border-critical)}}@layer rs.radio.checked{.input:checked+.decorator{background:var(--rs-color-background-primary);border-color:var(--rs-color-background-primary)}.input:checked+.decorator:after{opacity:1;transform:translate(-50%,-50%) scale(1)}}@layer rs.radio.disabled{.root.--disabled{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.root.--disabled .decorator{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled .decorator:after{background-color:var(--rs-color-foreground-disabled)}.root.--disabled .input:checked+.decorator{background:var(--rs-color-background-disabled);border-color:transparent}}@media (--rs-viewport-m ){.--size-small--m{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--m{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--m{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}@media (--rs-viewport-l ){.--size-small--l{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--l{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--l{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--xl{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--xl{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}
@@ -73,8 +73,11 @@ const ScrollArea = forwardRef((props, ref) => {
73
73
  const contentRef = React.useRef(null);
74
74
  const heightStyles = getHeightStyles(height);
75
75
  const maxHeightStyles = getMaxHeightStyles(maxHeight);
76
- const rootClassNames = classNames(s.root, scrollbarDisplay && s[`--display-${scrollbarDisplay}`], heightStyles?.classNames, className);
77
- const contentClassNames = classNames(s.content, maxHeightStyles?.classNames);
76
+ const rootClassNames = classNames(s.root, scrollbarDisplay && s[`--display-${scrollbarDisplay}`], heightStyles?.classNames, maxHeightStyles?.classNames, className);
77
+ const rootVariables = {
78
+ ...heightStyles?.variables,
79
+ ...maxHeightStyles?.variables,
80
+ };
78
81
  const updateScroll = React.useCallback(() => {
79
82
  const scrollableEl = scrollableRef.current;
80
83
  if (!scrollableEl)
@@ -131,7 +134,7 @@ const ScrollArea = forwardRef((props, ref) => {
131
134
  observer.observe(contentEl);
132
135
  return () => observer.disconnect();
133
136
  }, [updateScroll]);
134
- return (_jsxs("div", { ...attributes, className: rootClassNames, style: { ...heightStyles?.variables }, children: [_jsx("div", { className: s.scrollable, ref: scrollableRef, onScroll: handleScroll, tabIndex: 0, children: _jsx("div", { className: contentClassNames, ref: contentRef, style: { ...maxHeightStyles?.variables }, children: children }) }), scrollRatio.y < 1 && scrollbarDisplay !== "hidden" && (_jsx(ScrollAreaBar, { vertical: true, onThumbMove: handleThumbYMove, ratio: scrollRatio.y, position: scrollPosition.y })), scrollRatio.x < 1 && scrollbarDisplay !== "hidden" && (_jsx(ScrollAreaBar, { onThumbMove: handleThumbXMove, ratio: scrollRatio.x, position: scrollPosition.x }))] }));
137
+ return (_jsxs("div", { ...attributes, className: rootClassNames, style: rootVariables, children: [_jsx("div", { className: s.scrollable, ref: scrollableRef, onScroll: handleScroll, tabIndex: 0, children: _jsx("div", { className: s.content, ref: contentRef, children: children }) }), scrollRatio.y < 1 && scrollbarDisplay !== "hidden" && (_jsx(ScrollAreaBar, { vertical: true, onThumbMove: handleThumbYMove, ratio: scrollRatio.y, position: scrollPosition.y })), scrollRatio.x < 1 && scrollbarDisplay !== "hidden" && (_jsx(ScrollAreaBar, { onThumbMove: handleThumbXMove, ratio: scrollRatio.x, position: scrollPosition.x }))] }));
135
138
  });
136
139
  ScrollArea.displayName = "ScrollArea";
137
140
  export default ScrollArea;
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import { StoryObj } from "@storybook/react";
3
- import { Mock } from "@storybook/test";
4
3
  declare const _default: {
5
4
  title: string;
6
5
  component: React.ForwardRefExoticComponent<import("./..").ScrollAreaProps & React.RefAttributes<HTMLDivElement>>;
@@ -14,24 +13,16 @@ declare const _default: {
14
13
  };
15
14
  };
16
15
  export default _default;
17
- export declare const base: {
16
+ export declare const direction: {
18
17
  name: string;
19
18
  render: () => React.JSX.Element;
20
19
  };
21
- export declare const scrollbarDisplay: {
20
+ export declare const visibility: {
22
21
  name: string;
23
22
  render: () => React.JSX.Element;
24
23
  };
25
- export declare const height: {
24
+ export declare const composition: {
26
25
  name: string;
27
26
  render: () => React.JSX.Element;
28
27
  };
29
- export declare const onScroll: StoryObj<{
30
- handleScroll: Mock;
31
- }>;
32
- export declare const className: StoryObj;
33
- export declare const testNested: {
34
- name: string;
35
- render: () => React.JSX.Element;
36
- };
37
- export declare const testDynamicHeight: StoryObj;
28
+ export declare const dynamicHeight: StoryObj;
@@ -1,5 +1,4 @@
1
1
  import React from "react";
2
- import { userEvent, expect, waitFor, fn } from "@storybook/test";
3
2
  import { Example } from "../../../utilities/storybook/index.js";
4
3
  import ScrollArea from "../index.js";
5
4
  import View from "../../View/index.js";
@@ -17,10 +16,10 @@ export default {
17
16
  },
18
17
  },
19
18
  };
20
- export const base = {
21
- name: "base",
19
+ export const direction = {
20
+ name: "direction",
22
21
  render: () => (<Example>
23
- <Example.Item title="vertical scroll">
22
+ <Example.Item title="vertical">
24
23
  <ScrollArea height="100px" scrollbarDisplay="visible">
25
24
  <View backgroundColor="elevation-base" padding={4}>
26
25
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
@@ -34,7 +33,7 @@ export const base = {
34
33
  </ScrollArea>
35
34
  </Example.Item>
36
35
 
37
- <Example.Item title="horizontal scroll">
36
+ <Example.Item title="horizontal">
38
37
  <ScrollArea height="100px" scrollbarDisplay="visible">
39
38
  <View backgroundColor="elevation-base" padding={4} width="150%" height="100px">
40
39
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
@@ -43,7 +42,7 @@ export const base = {
43
42
  </ScrollArea>
44
43
  </Example.Item>
45
44
 
46
- <Example.Item title="horizontal and vertical scroll">
45
+ <Example.Item title="horizontal, vertical">
47
46
  <ScrollArea height="100px" scrollbarDisplay="visible">
48
47
  <View backgroundColor="elevation-base" padding={4} width="150%">
49
48
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
@@ -58,57 +57,11 @@ export const base = {
58
57
  </Example.Item>
59
58
  </Example>),
60
59
  };
61
- export const scrollbarDisplay = {
60
+ export const visibility = {
62
61
  name: "scrollbarDisplay",
63
62
  render: () => (<Example>
64
- <Example.Item title="scrollbarDisplay: hover">
63
+ <Example.Item title="visibility: hover">
65
64
  <ScrollArea height="100px">
66
- <View backgroundColor="elevation-base" padding={4} width="150%">
67
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
68
- has been the industry's standard dummy text ever since the 1500s, when an unknown
69
- printer took a galley of type and scrambled it to make a type specimen book. It has
70
- survived not only five centuries, but also the leap into electronic typesetting,
71
- remaining essentially unchanged. It was popularised in the 1960s with the release of
72
- Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
73
- publishing software like Aldus PageMaker including versions of Lorem Ipsum.
74
- </View>
75
- </ScrollArea>
76
- </Example.Item>
77
-
78
- <Example.Item title="scrollbarDisplay: hidden">
79
- <ScrollArea height="100px" scrollbarDisplay="hidden">
80
- <View backgroundColor="elevation-base" padding={4} width="150%">
81
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
82
- has been the industry's standard dummy text ever since the 1500s, when an unknown
83
- printer took a galley of type and scrambled it to make a type specimen book. It has
84
- survived not only five centuries, but also the leap into electronic typesetting,
85
- remaining essentially unchanged. It was popularised in the 1960s with the release of
86
- Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
87
- publishing software like Aldus PageMaker including versions of Lorem Ipsum.
88
- </View>
89
- </ScrollArea>
90
- </Example.Item>
91
-
92
- <Example.Item title="scrollbarDisplay: visible">
93
- <ScrollArea height="100px" scrollbarDisplay="visible">
94
- <View backgroundColor="elevation-base" padding={4} width="150%">
95
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
96
- has been the industry's standard dummy text ever since the 1500s, when an unknown
97
- printer took a galley of type and scrambled it to make a type specimen book. It has
98
- survived not only five centuries, but also the leap into electronic typesetting,
99
- remaining essentially unchanged. It was popularised in the 1960s with the release of
100
- Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
101
- publishing software like Aldus PageMaker including versions of Lorem Ipsum.
102
- </View>
103
- </ScrollArea>
104
- </Example.Item>
105
- </Example>),
106
- };
107
- export const height = {
108
- name: "height, maxHeight",
109
- render: () => (<Example>
110
- <Example.Item title="height: 80px">
111
- <ScrollArea height="80px">
112
65
  <View backgroundColor="elevation-base" padding={4}>
113
66
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
114
67
  has been the industry's standard dummy text ever since the 1500s, when an unknown
@@ -121,22 +74,8 @@ export const height = {
121
74
  </ScrollArea>
122
75
  </Example.Item>
123
76
 
124
- <Example.Item title="responsive height: s 80px, m: 120px">
125
- <ScrollArea height={{ s: "80px", m: "120px" }}>
126
- <View backgroundColor="elevation-base" padding={4}>
127
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
128
- has been the industry's standard dummy text ever since the 1500s, when an unknown
129
- printer took a galley of type and scrambled it to make a type specimen book. It has
130
- survived not only five centuries, but also the leap into electronic typesetting,
131
- remaining essentially unchanged. It was popularised in the 1960s with the release of
132
- Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
133
- publishing software like Aldus PageMaker including versions of Lorem Ipsum.
134
- </View>
135
- </ScrollArea>
136
- </Example.Item>
137
-
138
- <Example.Item title="maxHeight: 80px">
139
- <ScrollArea maxHeight="80px">
77
+ <Example.Item title="visibility: hidden">
78
+ <ScrollArea height="100px" scrollbarDisplay="hidden">
140
79
  <View backgroundColor="elevation-base" padding={4}>
141
80
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
142
81
  has been the industry's standard dummy text ever since the 1500s, when an unknown
@@ -149,8 +88,8 @@ export const height = {
149
88
  </ScrollArea>
150
89
  </Example.Item>
151
90
 
152
- <Example.Item title="responsive max height: s 80px, m: 200px">
153
- <ScrollArea maxHeight={{ s: "80px", m: "200px" }}>
91
+ <Example.Item title="visibility: visible">
92
+ <ScrollArea height="100px" scrollbarDisplay="visible">
154
93
  <View backgroundColor="elevation-base" padding={4}>
155
94
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
156
95
  has been the industry's standard dummy text ever since the 1500s, when an unknown
@@ -164,69 +103,26 @@ export const height = {
164
103
  </Example.Item>
165
104
  </Example>),
166
105
  };
167
- export const onScroll = {
168
- name: "ref, onScroll",
169
- args: {
170
- handleScroll: fn(),
171
- },
172
- render: (args) => {
173
- const ref = React.useRef(null);
174
- return (<View gap={4}>
175
- <View.Item>
176
- <Button onClick={() => ref.current?.scrollBy({ top: 50, left: 50 })}>Scroll</Button>
177
- </View.Item>
178
- <ScrollArea height="100px" ref={ref} scrollbarDisplay="visible" onScroll={args.handleScroll}>
179
- <View backgroundColor="neutral-faded" padding={4} width="1000px" height="200px">
180
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
181
- has been the industry's standard dummy text ever since the 1500s, when an unknown
182
- printer took a galley of type and scrambled it to make a type specimen book. It has
183
- survived not only five centuries, but also the leap into electronic typesetting,
184
- remaining essentially unchanged. It was popularised in the 1960s with the release of
185
- Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
186
- publishing software like Aldus PageMaker including versions of Lorem Ipsum.
187
- </View>
188
- </ScrollArea>
189
- </View>);
190
- },
191
- play: async ({ canvas, args }) => {
192
- const trigger = canvas.getAllByRole("button")[0];
193
- await userEvent.click(trigger);
194
- await waitFor(() => {
195
- expect(args.handleScroll).toHaveBeenCalledTimes(1);
196
- // x value is flaky, so only testing y here
197
- expect(args.handleScroll).toHaveBeenCalledWith(expect.objectContaining({ y: 0.5 }));
198
- });
199
- },
200
- };
201
- export const className = {
202
- name: "className, attributes",
203
- render: () => (<div data-testid="root">
204
- <ScrollArea className="test-classname" attributes={{ id: "test-id" }}>
205
- Content
206
- </ScrollArea>
207
- </div>),
208
- play: async ({ canvas }) => {
209
- const root = canvas.getByTestId("root").firstChild;
210
- expect(root).toHaveClass("test-classname");
211
- expect(root).toHaveAttribute("id", "test-id");
212
- },
213
- };
214
- export const testNested = {
215
- name: "test: nested",
216
- render: () => (<ScrollArea height="100px" scrollbarDisplay="visible">
217
- <View padding={4} paddingInline={16}>
218
- <ScrollArea height="200px" scrollbarDisplay="visible">
219
- {Array(20)
106
+ export const composition = {
107
+ name: "composition",
108
+ render: () => (<Example>
109
+ <Example.Item title="nested">
110
+ <ScrollArea height="100px">
111
+ <View padding={4} paddingInline={16}>
112
+ <ScrollArea height="200px">
113
+ {Array(20)
220
114
  .fill("")
221
115
  .map((_, index) => {
222
116
  return <div key={index}>Item {index + 1}</div>;
223
117
  })}
118
+ </ScrollArea>
119
+ </View>
224
120
  </ScrollArea>
225
- </View>
226
- </ScrollArea>),
121
+ </Example.Item>
122
+ </Example>),
227
123
  };
228
- export const testDynamicHeight = {
229
- name: "test: dynamic height change",
124
+ export const dynamicHeight = {
125
+ name: "composition, dynamic height change",
230
126
  render: () => {
231
127
  const [count, setCount] = React.useState(10);
232
128
  return (<View gap={4}>
@@ -241,4 +137,9 @@ export const testDynamicHeight = {
241
137
  </ScrollArea>
242
138
  </View>);
243
139
  },
140
+ // TODO: After Using play(), Storybook makes the scroll lag, but not when triggered manually in the browser
141
+ // play: async ({ canvas }) => {
142
+ // const trigger = canvas.getAllByRole("button")[0];
143
+ // await userEvent.click(trigger);
144
+ // },
244
145
  };
@@ -0,0 +1,23 @@
1
+ import React from "react";
2
+ import { StoryObj } from "@storybook/react";
3
+ import { fn } from "@storybook/test";
4
+ declare const _default: {
5
+ title: string;
6
+ component: React.ForwardRefExoticComponent<import("./..").ScrollAreaProps & React.RefAttributes<HTMLDivElement>>;
7
+ parameters: {
8
+ iframe: {
9
+ url: string;
10
+ };
11
+ a11y: {
12
+ disable: boolean;
13
+ };
14
+ chromatic: {
15
+ disableSnapshot: boolean;
16
+ };
17
+ };
18
+ };
19
+ export default _default;
20
+ export declare const onScroll: StoryObj<{
21
+ handleScroll: ReturnType<typeof fn>;
22
+ }>;
23
+ export declare const className: StoryObj;
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ import { expect, fn, userEvent, waitFor } from "@storybook/test";
3
+ import Button from "../../Button/index.js";
4
+ import ScrollArea from "../index.js";
5
+ import View from "../../View/index.js";
6
+ export default {
7
+ title: "Utility components/ScrollArea/tests",
8
+ component: ScrollArea,
9
+ parameters: {
10
+ iframe: {
11
+ url: "https://reshaped.so/docs/utilities/text",
12
+ },
13
+ // Skip because axe core incorrectly reports contrast issues
14
+ a11y: {
15
+ disable: true,
16
+ },
17
+ chromatic: { disableSnapshot: true },
18
+ },
19
+ };
20
+ export const onScroll = {
21
+ name: "ref, onScroll",
22
+ args: {
23
+ handleScroll: fn(),
24
+ },
25
+ render: (args) => {
26
+ const ref = React.useRef(null);
27
+ return (<View gap={4}>
28
+ <View.Item>
29
+ <Button onClick={() => ref.current?.scrollBy({ top: 50, left: 50 })}>Scroll</Button>
30
+ </View.Item>
31
+ <ScrollArea height="100px" ref={ref} scrollbarDisplay="visible" onScroll={args.handleScroll}>
32
+ <View backgroundColor="neutral-faded" padding={4} width="1000px" height="200px">
33
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
34
+ has been the industry's standard dummy text ever since the 1500s, when an unknown
35
+ printer took a galley of type and scrambled it to make a type specimen book. It has
36
+ survived not only five centuries, but also the leap into electronic typesetting,
37
+ remaining essentially unchanged. It was popularised in the 1960s with the release of
38
+ Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
39
+ publishing software like Aldus PageMaker including versions of Lorem Ipsum.
40
+ </View>
41
+ </ScrollArea>
42
+ </View>);
43
+ },
44
+ play: async ({ canvas, args }) => {
45
+ const trigger = canvas.getAllByRole("button")[0];
46
+ await userEvent.click(trigger);
47
+ await waitFor(() => {
48
+ expect(args.handleScroll).toHaveBeenCalledTimes(1);
49
+ // x value is flaky, so only testing y here
50
+ expect(args.handleScroll).toHaveBeenCalledWith(expect.objectContaining({ y: 0.5 }));
51
+ });
52
+ },
53
+ };
54
+ export const className = {
55
+ name: "className, attributes",
56
+ render: () => (<div data-testid="root">
57
+ <ScrollArea className="test-classname" attributes={{ id: "test-id" }}>
58
+ Content
59
+ </ScrollArea>
60
+ </div>),
61
+ play: async ({ canvas }) => {
62
+ const root = canvas.getByTestId("root").firstChild;
63
+ expect(root).toHaveClass("test-classname");
64
+ expect(root).toHaveAttribute("id", "test-id");
65
+ },
66
+ };
@@ -4,13 +4,13 @@ export declare const TabsProvider: React.Provider<T.Context>;
4
4
  export declare const useTabs: (value?: string) => {
5
5
  panelId: string | undefined;
6
6
  buttonId: string | undefined;
7
+ variant?: "bordered" | "borderless" | "pills" | "pills-elevated" | undefined;
7
8
  name?: string | undefined;
9
+ direction?: "column" | "row" | undefined;
8
10
  onChange?: ((args: {
9
11
  value: string;
10
12
  name?: string;
11
13
  }) => void) | undefined;
12
- variant?: "bordered" | "borderless" | "pills" | "pills-elevated" | undefined;
13
- direction?: "column" | "row" | undefined;
14
14
  itemWidth?: "equal" | undefined;
15
15
  size: NonNullable<T.BaseProps["size"]>;
16
16
  value?: string;
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import Theme from "../Theme/index.js";
4
4
  import Text from "../Text/index.js";
5
- import Flyout from "../_private/Flyout/index.js";
5
+ import Flyout from "../Flyout/index.js";
6
6
  import s from "./Tooltip.module.css";
7
7
  const Tooltip = (props) => {
8
8
  const { text, children, position = "bottom", ...flyoutProps } = props;
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import type { FlyoutProps, FlyoutTriggerProps } from "../_private/Flyout";
2
+ import type { FlyoutProps, FlyoutTriggerProps } from "../Flyout";
3
3
  export type Props = Pick<FlyoutProps, "id" | "position" | "onOpen" | "onClose" | "active" | "disabled" | "disableContentHover" | "containerRef" | "contentGap" | "contentShift" | "originCoordinates"> & {
4
4
  children: (attributes: Parameters<FlyoutTriggerProps["children"]>[0] | {}) => React.ReactNode;
5
5
  text?: React.ReactNode;
@@ -1,2 +1,2 @@
1
1
  import type { ThemeDefinition } from "../themes/_generator/tokens/types";
2
- export declare const getTheme: (theme?: ThemeDefinition) => Record<"borderRadius" | "backgroundColor" | "borderColor" | "boxShadow" | "spacing" | "textColor" | "colors" | "screens", Record<string, string>>;
2
+ export declare const getTheme: (theme?: ThemeDefinition) => Record<"backgroundColor" | "borderColor" | "borderRadius" | "spacing" | "boxShadow" | "textColor" | "colors" | "screens", Record<string, string>>;
@@ -1,3 +1,3 @@
1
1
  import React from "react";
2
- declare const useIsomorphicLayoutEffect: typeof React.useLayoutEffect;
2
+ declare const useIsomorphicLayoutEffect: typeof React.useEffect;
3
3
  export default useIsomorphicLayoutEffect;