reshaped 3.3.12 → 3.4.0-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 (69) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/bundle.css +1 -1
  3. package/dist/bundle.d.ts +4 -1
  4. package/dist/bundle.js +11 -11
  5. package/dist/components/Autocomplete/Autocomplete.js +34 -24
  6. package/dist/components/Autocomplete/Autocomplete.types.d.ts +1 -1
  7. package/dist/components/Autocomplete/tests/Autocomplete.stories.js +8 -1
  8. package/dist/components/Carousel/Carousel.js +53 -4
  9. package/dist/components/Carousel/Carousel.types.d.ts +5 -0
  10. package/dist/components/Carousel/tests/Carousel.stories.d.ts +20 -4
  11. package/dist/components/Carousel/tests/Carousel.stories.js +195 -102
  12. package/dist/components/Container/Container.module.css +1 -1
  13. package/dist/components/ContextMenu/ContextMenu.js +2 -2
  14. package/dist/components/ContextMenu/tests/ContextMenu.test.stories.js +1 -1
  15. package/dist/components/DropdownMenu/DropdownMenu.js +6 -1
  16. package/dist/components/DropdownMenu/tests/DropdownMenu.test.stories.js +2 -2
  17. package/dist/components/Popover/Popover.js +1 -1
  18. package/dist/components/Popover/tests/Popover.test.stories.js +4 -4
  19. package/dist/components/ProgressIndicator/ProgressIndicator.d.ts +3 -0
  20. package/dist/components/ProgressIndicator/ProgressIndicator.js +101 -0
  21. package/dist/components/ProgressIndicator/ProgressIndicator.module.css +1 -0
  22. package/dist/components/ProgressIndicator/ProgressIndicator.types.d.ts +9 -0
  23. package/dist/components/ProgressIndicator/ProgressIndicator.types.js +1 -0
  24. package/dist/components/ProgressIndicator/index.d.ts +2 -0
  25. package/dist/components/ProgressIndicator/index.js +1 -0
  26. package/dist/components/ProgressIndicator/tests/ProgressIndicator.stories.d.ts +19 -0
  27. package/dist/components/ProgressIndicator/tests/ProgressIndicator.stories.js +85 -0
  28. package/dist/components/Reshaped/Reshaped.js +4 -5
  29. package/dist/components/Table/index.d.ts +1 -1
  30. package/dist/components/Table/tests/Table.stories.d.ts +5 -5
  31. package/dist/components/Table/tests/Table.test.stories.d.ts +5 -5
  32. package/dist/components/TextField/TextField.module.css +1 -1
  33. package/dist/components/Toast/tests/Toast.stories.js +22 -7
  34. package/dist/components/Tooltip/tests/Tooltip.test.stories.js +1 -1
  35. package/dist/components/_private/Flyout/Flyout.module.css +1 -1
  36. package/dist/components/_private/Flyout/Flyout.types.d.ts +14 -3
  37. package/dist/components/_private/Flyout/FlyoutContent.js +37 -7
  38. package/dist/components/_private/Flyout/FlyoutControlled.js +12 -11
  39. package/dist/components/_private/Flyout/FlyoutUncontrolled.js +3 -5
  40. package/dist/components/_private/Flyout/index.d.ts +1 -1
  41. package/dist/components/_private/Flyout/tests/Flyout.stories.d.ts +79 -13
  42. package/dist/components/_private/Flyout/tests/Flyout.stories.js +526 -280
  43. package/dist/components/_private/Flyout/useFlyout.js +9 -3
  44. package/dist/components/_private/Flyout/utilities/isFullyVisible.d.ts +3 -1
  45. package/dist/components/_private/Flyout/utilities/isFullyVisible.js +2 -2
  46. package/dist/hooks/_private/usePrevious.d.ts +2 -0
  47. package/dist/hooks/_private/usePrevious.js +17 -0
  48. package/dist/hooks/_private/useSingletonEnvironment.d.ts +1 -1
  49. package/dist/hooks/_private/useSingletonEnvironment.js +1 -1
  50. package/dist/hooks/_private/useSingletonKeyboardMode.d.ts +13 -2
  51. package/dist/hooks/_private/useSingletonKeyboardMode.js +48 -15
  52. package/dist/hooks/tests/useKeyboardMode.stories.d.ts +6 -0
  53. package/dist/hooks/tests/useKeyboardMode.stories.js +37 -0
  54. package/dist/hooks/useKeyboardMode.d.ts +7 -0
  55. package/dist/hooks/useKeyboardMode.js +13 -0
  56. package/dist/index.d.ts +4 -1
  57. package/dist/index.js +2 -0
  58. package/dist/utilities/a11y/index.d.ts +1 -1
  59. package/dist/utilities/a11y/index.js +1 -1
  60. package/dist/utilities/a11y/keyboardMode.d.ts +2 -2
  61. package/dist/utilities/a11y/keyboardMode.js +2 -2
  62. package/dist/utilities/dom/find.d.ts +4 -1
  63. package/dist/utilities/dom/find.js +4 -4
  64. package/dist/utilities/scroll/lockStandard.js +1 -1
  65. package/package.json +34 -35
  66. package/dist/components/Carousel/tests/Carousel.test.stories.d.ts +0 -17
  67. package/dist/components/Carousel/tests/Carousel.test.stories.js +0 -52
  68. package/dist/components/_private/Flyout/tests/Flyout.test.stories.d.ts +0 -28
  69. package/dist/components/_private/Flyout/tests/Flyout.test.stories.js +0 -205
@@ -14,7 +14,7 @@ const Popover = (props) => {
14
14
  };
15
15
  const PopoverDismissible = (props) => {
16
16
  const { handleClose } = useFlyoutContext();
17
- return _jsx(Dismissible, { ...props, onClose: handleClose });
17
+ return _jsx(Dismissible, { ...props, onClose: () => handleClose({}) });
18
18
  };
19
19
  Popover.Dismissible = PopoverDismissible;
20
20
  Popover.Trigger = Flyout.Trigger;
@@ -33,7 +33,7 @@ export const defaultActive = {
33
33
  await userEvent.click(document.body);
34
34
  await waitFor(() => {
35
35
  expect(args.handleClose).toHaveBeenCalledTimes(1);
36
- expect(args.handleClose).toHaveBeenCalledWith();
36
+ expect(args.handleClose).toHaveBeenCalledWith({ reason: "outside-click" });
37
37
  expect(item).not.toBeInTheDocument();
38
38
  });
39
39
  await userEvent.click(trigger);
@@ -63,7 +63,7 @@ export const active = {
63
63
  await userEvent.click(document.body);
64
64
  await waitFor(() => {
65
65
  expect(args.handleClose).toHaveBeenCalledTimes(1);
66
- expect(args.handleClose).toHaveBeenCalledWith();
66
+ expect(args.handleClose).toHaveBeenCalledWith({ reason: "outside-click" });
67
67
  });
68
68
  expect(item).toBeInTheDocument();
69
69
  },
@@ -116,7 +116,7 @@ export const dismissible = {
116
116
  await userEvent.click(closeButton);
117
117
  await waitFor(() => {
118
118
  expect(args.handleClose).toHaveBeenCalledTimes(1);
119
- expect(args.handleClose).toHaveBeenCalledWith();
119
+ expect(args.handleClose).toHaveBeenCalledWith({});
120
120
  });
121
121
  },
122
122
  };
@@ -143,7 +143,7 @@ export const triggerType = {
143
143
  await userEvent.unhover(trigger);
144
144
  await waitFor(() => {
145
145
  expect(args.handleClose).toHaveBeenCalledTimes(1);
146
- expect(args.handleClose).toHaveBeenCalledWith();
146
+ expect(args.handleClose).toHaveBeenCalledWith({});
147
147
  });
148
148
  },
149
149
  };
@@ -0,0 +1,3 @@
1
+ import type * as T from "./ProgressIndicator.types";
2
+ declare const ProgressIndicator: (props: T.Props) => import("react/jsx-runtime").JSX.Element;
3
+ export default ProgressIndicator;
@@ -0,0 +1,101 @@
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 { onNextFrame } from "../../utilities/animation.js";
6
+ import usePrevious from "../../hooks/_private/usePrevious.js";
7
+ import s from "./ProgressIndicator.module.css";
8
+ const MAX_RENDERED_ITEMS = 7;
9
+ const BOUNDARY = (MAX_RENDERED_ITEMS - 1) / 2;
10
+ const ProgressIndicator = (props) => {
11
+ const { total, activeIndex = 0, color = "primary", ariaLabel, className, attributes } = props;
12
+ const allItemsVisible = total < MAX_RENDERED_ITEMS;
13
+ const firstRenderedIndex = React.useMemo(() => {
14
+ if (allItemsVisible)
15
+ return 0;
16
+ if (activeIndex <= BOUNDARY)
17
+ return 0;
18
+ if (activeIndex >= total - 1 - BOUNDARY)
19
+ return total - MAX_RENDERED_ITEMS;
20
+ return activeIndex - BOUNDARY;
21
+ }, [activeIndex, allItemsVisible, total]);
22
+ const [startIndex, setStartIndex] = React.useState(firstRenderedIndex);
23
+ const previousActiveIndex = usePrevious(activeIndex);
24
+ const [shift, setShift] = React.useState(null);
25
+ const [animated, setAnimatedState] = React.useState(true);
26
+ const animatedRef = React.useRef(true);
27
+ const rootClassName = classNames(s.root, className, shift && s[`--shift-${shift}`], color && s[`--color-${color}`], animated && s["--animated"]);
28
+ const barAttributes = ariaLabel
29
+ ? {
30
+ "aria-label": ariaLabel,
31
+ role: "progressbar",
32
+ "aria-valuenow": activeIndex,
33
+ "aria-valuemin": 0,
34
+ "aria-valuemax": total - 1,
35
+ }
36
+ : {};
37
+ const setAnimated = (animated) => {
38
+ setAnimatedState(animated);
39
+ animatedRef.current = animated;
40
+ };
41
+ /**
42
+ * After the shift transition, disable the animation and reset the items position
43
+ */
44
+ const handleTransitionEnd = (event) => {
45
+ if (event.target !== event.currentTarget || event.pseudoElement)
46
+ return;
47
+ setAnimated(false);
48
+ };
49
+ React.useEffect(() => {
50
+ if (animated)
51
+ return;
52
+ setShift(null);
53
+ }, [animated]);
54
+ React.useEffect(() => {
55
+ if (shift)
56
+ return;
57
+ onNextFrame(() => setAnimated(true));
58
+ }, [shift, firstRenderedIndex]);
59
+ React.useEffect(() => {
60
+ if (previousActiveIndex === activeIndex)
61
+ return;
62
+ const direction = previousActiveIndex && activeIndex < previousActiveIndex ? "start" : "end";
63
+ const lastIndex = total - 1;
64
+ const endThreshold = lastIndex - BOUNDARY;
65
+ const isAtStartEdge = activeIndex < BOUNDARY || (direction === "end" && activeIndex === BOUNDARY);
66
+ const isAtEndEdge = activeIndex > endThreshold || (direction === "start" && activeIndex === endThreshold);
67
+ const isAtEdge = isAtStartEdge || isAtEndEdge;
68
+ if (allItemsVisible || isAtEdge || !animatedRef.current) {
69
+ setStartIndex(firstRenderedIndex);
70
+ return;
71
+ }
72
+ setStartIndex(firstRenderedIndex);
73
+ setShift(direction);
74
+ }, [activeIndex, firstRenderedIndex, allItemsVisible, previousActiveIndex, total]);
75
+ const renderItems = () => {
76
+ let selectionDelta = 0;
77
+ if (shift === "start")
78
+ selectionDelta = -1;
79
+ if (shift === "end")
80
+ selectionDelta = 1;
81
+ const itemAmount = Math.min(MAX_RENDERED_ITEMS, total);
82
+ const items = [];
83
+ const lastIndex = total - 1;
84
+ const activeVisibleIndex = activeIndex - startIndex + selectionDelta;
85
+ const rightExtra = Math.max(BOUNDARY - activeIndex, 0);
86
+ const leftExtra = Math.max(BOUNDARY - (lastIndex - activeIndex), 0);
87
+ const rightModifierIndex = activeVisibleIndex + rightExtra + 1;
88
+ const leftModifierIndex = activeVisibleIndex - leftExtra - 1;
89
+ for (let i = 0; i < itemAmount; i += 1) {
90
+ const isActive = i === activeVisibleIndex;
91
+ const isSmall = i === rightModifierIndex + 1 || i === leftModifierIndex - 1;
92
+ const isSmaller = i === rightModifierIndex + 2 || i === leftModifierIndex - 2;
93
+ const isHidden = i > rightModifierIndex + 2 || i < leftModifierIndex - 2;
94
+ const itemClassName = classNames(s.item, isActive && s["item--active"], !allItemsVisible && isSmall && s["item--variant-secondary"], !allItemsVisible && isSmaller && s["item--variant-tertiary"], !allItemsVisible && isHidden && s["item--variant-hidden"]);
95
+ items.push(_jsx("div", { className: itemClassName }, i));
96
+ }
97
+ return items;
98
+ };
99
+ return (_jsx("div", { ...attributes, className: rootClassName, children: _jsx("div", { ...barAttributes, className: s.container, onTransitionEnd: handleTransitionEnd, children: renderItems() }) }));
100
+ };
101
+ export default ProgressIndicator;
@@ -0,0 +1 @@
1
+ .root{line-height:0}.container{display:inline-flex;position:relative;vertical-align:top}.container:after,.container:before{content:"";inset-inline-start:calc(var(--rs-unit-x4) * -1);opacity:0;position:absolute}.container:after,.container:before,.item{background:var(--rs-color-background-neutral);border-radius:999px;height:var(--rs-unit-x2);width:var(--rs-unit-x2)}.item{margin-inline-start:var(--rs-unit-x2)}.item:first-child{margin-inline-start:0}.item.item--active{background:var(--rs-color-background-primary);transform:scale(1.2)}.item.item--variant-secondary{opacity:.6}.item.item--variant-tertiary{opacity:.3}.item.item--variant-hidden{opacity:0}.--color-media .container:after,.--color-media .container:before,.--color-media .item{background:var(--rs-color-white)}.--color-media .item{opacity:.6}.--color-media .item.item--active{opacity:1}.--color-media .item.item--variant-secondary{opacity:.3}.--color-media .item.item--variant-tertiary{opacity:.1}.--color-media .item.item--variant-hidden{opacity:0}.--shift-start .container,[dir=rtl] .--shift-end .container{transform:translateX(var(--rs-unit-x4))}.--shift-end .container,[dir=rtl] .--shift-start .container{transform:translateX(calc(var(--rs-unit-x4) * -1))}.--shift-end .container:after,.--shift-start .container:before{opacity:.3}.--shift-end.--color-media .container:after,.--shift-start.--color-media .container:before{opacity:.1}.--shift-start .container:before{inset-inline-end:auto;inset-inline-start:calc(var(--rs-unit-x4) * -1)}.--shift-end .container:after{inset-inline-end:calc(var(--rs-unit-x4) * -1);inset-inline-start:auto}.--animated .container,.--animated .container:after,.--animated .container:before,.--animated .item{transition:var(--rs-duration-slow) var(--rs-easing-decelerate);transition-property:transform,opacity,background-color}
@@ -0,0 +1,9 @@
1
+ import type * as G from "../../types/global";
2
+ export type Props = {
3
+ total: number;
4
+ activeIndex?: number;
5
+ color?: "primary" | "media";
6
+ ariaLabel?: string;
7
+ className?: G.ClassName;
8
+ attributes?: G.Attributes<"div">;
9
+ };
@@ -0,0 +1,2 @@
1
+ export { default } from "./ProgressIndicator";
2
+ export type { Props as ProgressIndicatorProps } from "./ProgressIndicator.types";
@@ -0,0 +1 @@
1
+ export { default } from "./ProgressIndicator.js";
@@ -0,0 +1,19 @@
1
+ import React from "react";
2
+ import { StoryObj } from "@storybook/react";
3
+ declare const _default: {
4
+ title: string;
5
+ component: (props: import("./..").ProgressIndicatorProps) => React.JSX.Element;
6
+ parameters: {
7
+ iframe: {
8
+ url: string;
9
+ };
10
+ };
11
+ };
12
+ export default _default;
13
+ export declare const base: StoryObj;
14
+ export declare const color: {
15
+ name: string;
16
+ render: () => React.JSX.Element;
17
+ };
18
+ export declare const ariaLabel: StoryObj;
19
+ export declare const className: StoryObj;
@@ -0,0 +1,85 @@
1
+ import React from "react";
2
+ import { expect } from "@storybook/test";
3
+ import { Example } from "../../../utilities/storybook/index.js";
4
+ import ProgressIndicator from "../index.js";
5
+ import View from "../../View/index.js";
6
+ import Button from "../../Button/index.js";
7
+ import Text from "../../Text/index.js";
8
+ import Scrim from "../../Scrim/index.js";
9
+ export default {
10
+ title: "Components/ProgressIndicator",
11
+ component: ProgressIndicator,
12
+ parameters: {
13
+ iframe: {
14
+ url: "https://reshaped.so/docs/components/progress-indicator",
15
+ },
16
+ },
17
+ };
18
+ export const base = {
19
+ name: "base",
20
+ render: () => {
21
+ const [activeIndex, setActiveIndex] = React.useState(0);
22
+ const total = 10;
23
+ return (<Example>
24
+ <Example.Item title="base">
25
+ <View gap={4}>
26
+ <View direction="row" gap={2} align="center">
27
+ <Button onClick={() => {
28
+ setActiveIndex((prev) => Math.max(0, prev - 1));
29
+ }}>
30
+ Previous
31
+ </Button>
32
+ <Button onClick={() => {
33
+ setActiveIndex((prev) => Math.min(total - 1, prev + 1));
34
+ }}>
35
+ Next
36
+ </Button>
37
+ <Text weight="medium">Index: {activeIndex}</Text>
38
+ </View>
39
+ <ProgressIndicator total={total} activeIndex={activeIndex}/>
40
+ </View>
41
+ </Example.Item>
42
+ </Example>);
43
+ },
44
+ };
45
+ export const color = {
46
+ name: "color",
47
+ render: () => {
48
+ return (<Example>
49
+ <Example.Item title="color: primary">
50
+ <ProgressIndicator total={10} activeIndex={5} color="primary"/>
51
+ </Example.Item>
52
+ <Example.Item title="color: media">
53
+ <View borderRadius="medium" overflow="hidden" width="300px">
54
+ <Scrim position="bottom" backgroundSlot={<View aspectRatio={16 / 9} backgroundColor="neutral-faded"/>}>
55
+ <View align="center">
56
+ <ProgressIndicator total={10} activeIndex={5} color="media"/>
57
+ </View>
58
+ </Scrim>
59
+ </View>
60
+ </Example.Item>
61
+ </Example>);
62
+ },
63
+ };
64
+ export const ariaLabel = {
65
+ name: "ariaLabel",
66
+ render: () => <ProgressIndicator total={10} className="test-classname" ariaLabel="Progress"/>,
67
+ play: async ({ canvas }) => {
68
+ const progress = canvas.getByRole("progressbar");
69
+ expect(progress).toHaveAttribute("aria-valuenow", "0");
70
+ expect(progress).toHaveAttribute("aria-valuemin", "0");
71
+ expect(progress).toHaveAttribute("aria-valuemax", "9");
72
+ expect(progress).toHaveAccessibleName("Progress");
73
+ },
74
+ };
75
+ export const className = {
76
+ name: "className, attributes",
77
+ render: () => (<div data-testid="root">
78
+ <ProgressIndicator total={10} className="test-classname" attributes={{ id: "test-id" }}/>
79
+ </div>),
80
+ play: async ({ canvas }) => {
81
+ const root = canvas.getByTestId("root").firstChild;
82
+ expect(root).toHaveClass("test-classname");
83
+ expect(root).toHaveAttribute("id", "test-id");
84
+ },
85
+ };
@@ -5,16 +5,15 @@ import { classNames } from "../../utilities/helpers.js";
5
5
  import { GlobalColorMode, PrivateTheme } from "../Theme/index.js";
6
6
  import { ToastProvider } from "../Toast/index.js";
7
7
  import { useGlobalColorMode } from "../Theme/useTheme.js";
8
- import useSingletonKeyboardMode from "../../hooks/_private/useSingletonKeyboardMode.js";
9
- import { SingletonEnvironmentContext, useSingletonRTL, } from "../../hooks/_private/useSingletonEnvironment.js";
8
+ import { SingletonEnvironmentContext, useSingletonEnvironment, } from "../../hooks/_private/useSingletonEnvironment.js";
9
+ import { SingletonKeyboardModeProvider } from "../../hooks/_private/useSingletonKeyboardMode.js";
10
10
  import { SingletonHotkeysProvider } from "../../hooks/_private/useSingletonHotkeys.js";
11
11
  import "./Reshaped.css";
12
12
  import s from "./Reshaped.module.css";
13
13
  const ReshapedInner = (props) => {
14
14
  const { children, defaultRTL, defaultViewport = "s", toastOptions } = props;
15
- const rtlState = useSingletonRTL(defaultRTL);
16
- useSingletonKeyboardMode();
17
- return (_jsx(SingletonEnvironmentContext.Provider, { value: { rtl: rtlState, defaultViewport }, children: _jsx(SingletonHotkeysProvider, { children: _jsx(ToastProvider, { options: toastOptions, children: children }) }) }));
15
+ const rtlState = useSingletonEnvironment(defaultRTL);
16
+ return (_jsx(SingletonKeyboardModeProvider, { children: _jsx(SingletonEnvironmentContext.Provider, { value: { rtl: rtlState, defaultViewport }, children: _jsx(SingletonHotkeysProvider, { children: _jsx(ToastProvider, { options: toastOptions, children: children }) }) }) }));
18
17
  };
19
18
  const Reshaped = (props) => {
20
19
  const { theme, defaultTheme = "reshaped", defaultColorMode, scoped, className } = props;
@@ -1,2 +1,2 @@
1
1
  export { default } from "./Table";
2
- export type { Props as TableProps } from "./Table.types";
2
+ export type { Props as TableProps, HeadProps as TableHeadProps, BodyProps as TableBodyProps, RowProps as TableRowProps, CellProps as TableCellProps, HeadingProps as TableHeadingProps, } from "./Table.types";
@@ -3,11 +3,11 @@ declare const _default: {
3
3
  title: string;
4
4
  component: {
5
5
  (props: import("./..").TableProps): React.JSX.Element;
6
- Cell: (props: import("../Table.types").CellProps) => React.JSX.Element;
7
- Heading: (props: import("../Table.types").HeadingProps) => React.JSX.Element;
8
- Row: (props: import("../Table.types").RowProps) => React.JSX.Element;
9
- Body: (props: import("../Table.types").BodyProps) => React.JSX.Element;
10
- Head: (props: import("../Table.types").HeadProps) => React.JSX.Element;
6
+ Cell: (props: import("./..").TableCellProps) => React.JSX.Element;
7
+ Heading: (props: import("./..").TableHeadingProps) => React.JSX.Element;
8
+ Row: (props: import("./..").TableRowProps) => React.JSX.Element;
9
+ Body: (props: import("./..").TableBodyProps) => React.JSX.Element;
10
+ Head: (props: import("./..").TableHeadProps) => React.JSX.Element;
11
11
  };
12
12
  parameters: {
13
13
  iframe: {
@@ -3,11 +3,11 @@ declare const _default: {
3
3
  title: string;
4
4
  component: {
5
5
  (props: import("./..").TableProps): import("react").JSX.Element;
6
- Cell: (props: import("../Table.types").CellProps) => import("react").JSX.Element;
7
- Heading: (props: import("../Table.types").HeadingProps) => import("react").JSX.Element;
8
- Row: (props: import("../Table.types").RowProps) => import("react").JSX.Element;
9
- Body: (props: import("../Table.types").BodyProps) => import("react").JSX.Element;
10
- Head: (props: import("../Table.types").HeadProps) => import("react").JSX.Element;
6
+ Cell: (props: import("./..").TableCellProps) => import("react").JSX.Element;
7
+ Heading: (props: import("./..").TableHeadingProps) => import("react").JSX.Element;
8
+ Row: (props: import("./..").TableRowProps) => import("react").JSX.Element;
9
+ Body: (props: import("./..").TableBodyProps) => import("react").JSX.Element;
10
+ Head: (props: import("./..").TableHeadProps) => import("react").JSX.Element;
11
11
  };
12
12
  parameters: {
13
13
  iframe: {
@@ -1 +1 @@
1
- .root{--rs-p-h:var(--rs-text-field-gap);align-items:center;background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);display:flex;gap:var(--rs-text-field-gap);padding:calc(var(--rs-unit-x1) - 1px) calc(var(--rs-text-field-gap) - 1px);position:relative;row-gap:var(--rs-unit-x1);z-index:0}.root:has(label:active),.root:not(:has(button:focus,a:focus,[tabindex="0"]:focus)):focus-within{border-color:var(--rs-color-border-primary);box-shadow:0 0 0 1px var(--rs-color-border-primary)}.root.--multiline{flex-wrap:wrap}.root.--multiline .input{width:auto}.root.--rounded{border-radius:999px}.root.--rounded .affix:first-child,.root.--rounded .icon:first-child{padding-inline-start:var(--rs-unit-x1)}.root.--rounded .input:first-child{padding-inline-start:calc(var(--rs-text-field-gap) + var(--rs-unit-x1))}.input{background:none;border:none;box-sizing:border-box;color:var(--rs-color-foreground-neutral);flex-grow:1;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-regular);margin:calc(var(--rs-unit-x1) * -1) calc(var(--rs-text-field-gap) * -1);outline:none;padding-inline:var(--rs-text-field-gap);position:relative;width:100%;z-index:1}.input:-webkit-autofill{-webkit-background-clip:text;-webkit-text-fill-color:var(--rs-color-foreground-neutral)}.affix,.icon{cursor:text}.affix,.icon,.slot{align-items:center;display:flex;flex-shrink:0;min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x1) * 2);position:relative;z-index:5}.slot--position-end:last-child{margin-inline-end:calc(var(--rs-unit-x1) * -1)}.affix{color:var(--rs-color-foreground-neutral-faded)}.affix.affix--position-start{padding-inline-end:var(--rs-text-field-gap)}.affix.affix--position-start:after{border-inline-end:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-end:0;position:absolute}.affix.affix--position-end{padding-inline-start:var(--rs-text-field-gap)}.affix.affix--position-end:after{border-inline-start:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-start:0;position:absolute}.root.--disabled{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.--size-medium{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium .input{padding-block:var(--rs-unit-x2)}.--size-medium .affix,.--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)}.--size-large{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large .input{padding-block:var(--rs-unit-x3)}.--size-large .affix,.--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)}.--size-xlarge{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge .input{padding-block:var(--rs-unit-x4)}.--size-xlarge .affix,.--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)}.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)}@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-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium--m .input{padding-block:var(--rs-unit-x2)}.--size-medium--m .affix,.--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)}.--size-large--m{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large--m .input{padding-block:var(--rs-unit-x3)}.--size-large--m .affix,.--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)}.--size-xlarge--m{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge--m .input{padding-block:var(--rs-unit-x4)}.--size-xlarge--m .affix,.--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)}}@media (--rs-viewport-l ){.--size-medium--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium--l .input{padding-block:var(--rs-unit-x2)}.--size-medium--l .affix,.--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)}.--size-large--l{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large--l .input{padding-block:var(--rs-unit-x3)}.--size-large--l .affix,.--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)}.--size-xlarge--l{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge--l .input{padding-block:var(--rs-unit-x4)}.--size-xlarge--l .affix,.--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)}}@media (--rs-viewport-xl ){.--size-medium--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium--xl .input{padding-block:var(--rs-unit-x2)}.--size-medium--xl .affix,.--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)}.--size-large--xl{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large--xl .input{padding-block:var(--rs-unit-x3)}.--size-large--xl .affix,.--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)}.--size-xlarge--xl{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge--xl .input{padding-block:var(--rs-unit-x4)}.--size-xlarge--xl .affix,.--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)}}
1
+ .root{--rs-p-h:var(--rs-text-field-gap);align-items:center;background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);display:flex;gap:var(--rs-text-field-gap);padding:calc(var(--rs-unit-x1) - 1px) calc(var(--rs-text-field-gap) - 1px);position:relative;row-gap:var(--rs-unit-x1);z-index:0}.root.--focused,.root:has(label:active),.root:not(:has(button:focus,a:focus,[tabindex="0"]:focus)):focus-within{border-color:var(--rs-color-border-primary);box-shadow:0 0 0 1px var(--rs-color-border-primary)}.root.--multiline{flex-wrap:wrap}.root.--multiline .input{width:auto}.root.--rounded{border-radius:999px}.root.--rounded .affix:first-child,.root.--rounded .icon:first-child{padding-inline-start:var(--rs-unit-x1)}.root.--rounded .input:first-child{padding-inline-start:calc(var(--rs-text-field-gap) + var(--rs-unit-x1))}.input{background:none;border:none;box-sizing:border-box;color:var(--rs-color-foreground-neutral);flex-grow:1;font-family:var(--rs-font-family-body);font-weight:var(--rs-font-weight-regular);margin:calc(var(--rs-unit-x1) * -1) calc(var(--rs-text-field-gap) * -1);outline:none;padding-inline:var(--rs-text-field-gap);position:relative;width:100%;z-index:1}.input:-webkit-autofill{-webkit-background-clip:text;-webkit-text-fill-color:var(--rs-color-foreground-neutral)}.affix,.icon{cursor:text}.affix,.icon,.slot{align-items:center;display:flex;flex-shrink:0;min-height:calc(var(--rs-text-field-line-height) + var(--rs-unit-x1) * 2);position:relative;z-index:5}.slot--position-end:last-child{margin-inline-end:calc(var(--rs-unit-x1) * -1)}.affix{color:var(--rs-color-foreground-neutral-faded)}.affix.affix--position-start{padding-inline-end:var(--rs-text-field-gap)}.affix.affix--position-start:after{border-inline-end:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-end:0;position:absolute}.affix.affix--position-end{padding-inline-start:var(--rs-text-field-gap)}.affix.affix--position-end:after{border-inline-start:1px solid var(--rs-color-border-neutral-faded);content:"";inset-block:var(--rs-unit-x1);inset-inline-start:0;position:absolute}.root.--disabled{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled,.root.--disabled .input{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.--size-medium{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium .input{padding-block:var(--rs-unit-x2)}.--size-medium .affix,.--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)}.--size-large{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large .input{padding-block:var(--rs-unit-x3)}.--size-large .affix,.--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)}.--size-xlarge{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge .input{padding-block:var(--rs-unit-x4)}.--size-xlarge .affix,.--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)}.root.--variant-faded{background:var(--rs-color-background-neutral-faded);border-color:transparent}.root.--variant-faded.--focused,.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.--focused,.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.--focused,.root.--status-error:focus-within{border-color:var(--rs-color-border-primary)}@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-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium--m .input{padding-block:var(--rs-unit-x2)}.--size-medium--m .affix,.--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)}.--size-large--m{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large--m .input{padding-block:var(--rs-unit-x3)}.--size-large--m .affix,.--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)}.--size-xlarge--m{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge--m .input{padding-block:var(--rs-unit-x4)}.--size-xlarge--m .affix,.--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)}}@media (--rs-viewport-l ){.--size-medium--l{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium--l .input{padding-block:var(--rs-unit-x2)}.--size-medium--l .affix,.--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)}.--size-large--l{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large--l .input{padding-block:var(--rs-unit-x3)}.--size-large--l .affix,.--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)}.--size-xlarge--l{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge--l .input{padding-block:var(--rs-unit-x4)}.--size-xlarge--l .affix,.--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)}}@media (--rs-viewport-xl ){.--size-medium--xl{--rs-text-field-gap:var(--rs-unit-x2);--rs-text-field-line-height:var(--rs-line-height-body-3);border-radius:var(--rs-radius-small)}.--size-medium--xl .input{padding-block:var(--rs-unit-x2)}.--size-medium--xl .affix,.--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)}.--size-large--xl{--rs-text-field-gap:var(--rs-unit-x3);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-large--xl .input{padding-block:var(--rs-unit-x3)}.--size-large--xl .affix,.--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)}.--size-xlarge--xl{--rs-text-field-gap:var(--rs-unit-x4);--rs-text-field-line-height:var(--rs-line-height-body-2);border-radius:var(--rs-radius-medium)}.--size-xlarge--xl .input{padding-block:var(--rs-unit-x4)}.--size-xlarge--xl .affix,.--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)}}
@@ -145,7 +145,10 @@ const Color = () => {
145
145
  color: "inverted",
146
146
  title: "Hey!",
147
147
  icon: IconZap,
148
- actionsSlot: [<Button onClick={() => toast.hide(id)}>Close</Button>],
148
+ actionsSlot: [
149
+ <Button onClick={() => toast.hide(id)}>Undo</Button>,
150
+ <Button onClick={() => toast.hide(id)}>Hide</Button>,
151
+ ],
149
152
  });
150
153
  }}>
151
154
  Show toast
@@ -158,7 +161,10 @@ const Color = () => {
158
161
  color: "neutral",
159
162
  title: "Hey!",
160
163
  icon: IconZap,
161
- actionsSlot: [<Button onClick={() => toast.hide(id)}>Close</Button>],
164
+ actionsSlot: [
165
+ <Button onClick={() => toast.hide(id)}>Undo</Button>,
166
+ <Button onClick={() => toast.hide(id)}>Hide</Button>,
167
+ ],
162
168
  });
163
169
  }}>
164
170
  Show toast
@@ -171,7 +177,10 @@ const Color = () => {
171
177
  color: "primary",
172
178
  title: "Hey!",
173
179
  icon: IconZap,
174
- actionsSlot: [<Button onClick={() => toast.hide(id)}>Close</Button>],
180
+ actionsSlot: [
181
+ <Button onClick={() => toast.hide(id)}>Undo</Button>,
182
+ <Button onClick={() => toast.hide(id)}>Hide</Button>,
183
+ ],
175
184
  });
176
185
  }}>
177
186
  Show toast
@@ -184,7 +193,10 @@ const Color = () => {
184
193
  color: "positive",
185
194
  title: "Hey!",
186
195
  icon: IconZap,
187
- actionsSlot: [<Button onClick={() => toast.hide(id)}>Close</Button>],
196
+ actionsSlot: [
197
+ <Button onClick={() => toast.hide(id)}>Undo</Button>,
198
+ <Button onClick={() => toast.hide(id)}>Hide</Button>,
199
+ ],
188
200
  });
189
201
  }}>
190
202
  Show toast
@@ -197,7 +209,10 @@ const Color = () => {
197
209
  color: "critical",
198
210
  title: "Hey!",
199
211
  icon: IconZap,
200
- actionsSlot: [<Button onClick={() => toast.hide(id)}>Close</Button>],
212
+ actionsSlot: [
213
+ <Button onClick={() => toast.hide(id)}>Undo</Button>,
214
+ <Button onClick={() => toast.hide(id)}>Hide</Button>,
215
+ ],
201
216
  });
202
217
  }}>
203
218
  Show toast
@@ -211,8 +226,8 @@ const Color = () => {
211
226
  title: "Hey!",
212
227
  icon: IconZap,
213
228
  actionsSlot: [
214
- <Button onClick={() => toast.hide(id)}>Close</Button>,
215
- <Button onClick={() => toast.hide(id)}>Close</Button>,
229
+ <Button onClick={() => toast.hide(id)}>Undo</Button>,
230
+ <Button onClick={() => toast.hide(id)}>Hide</Button>,
216
231
  ],
217
232
  });
218
233
  }}>
@@ -33,7 +33,7 @@ export const defaultActive = {
33
33
  await userEvent.unhover(trigger);
34
34
  await waitFor(() => {
35
35
  expect(args.handleClose).toHaveBeenCalledTimes(1);
36
- expect(args.handleClose).toHaveBeenCalledWith();
36
+ expect(args.handleClose).toHaveBeenCalledWith({});
37
37
  expect(item).not.toBeInTheDocument();
38
38
  });
39
39
  },
@@ -1 +1 @@
1
- .content{--rs-flyout-gap:0;--rs-flyout-origin-x:50%;--rs-flyout-origin-y:50%;pointer-events:none;position:absolute}.content.--hover,.inner{pointer-events:all}.inner{opacity:0;transform:scale(.9) translateY(0);transform-origin:var(--rs-flyout-origin-x) var(--rs-flyout-origin-y);transition:1ms var(--rs-easing-accelerate)}.content.--width-trigger .inner{transform:scale(1) translateY(var(--rs-unit-x2))}.content.--position-top,.content.--position-top-end,.content.--position-top-start{--rs-flyout-origin-y:100%;padding-bottom:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom,.content.--position-bottom-end,.content.--position-bottom-start{--rs-flyout-origin-y:0%;padding-top:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom-start,.content.--position-top-start{--rs-flyout-origin-x:0%}.content.--position-bottom-end,.content.--position-top-end{--rs-flyout-origin-x:100%}.content.--position-start,.content.--position-start-bottom,.content.--position-start-top{--rs-flyout-origin-x:100%;padding-right:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end,.content.--position-end-bottom,.content.--position-end-top{--rs-flyout-origin-x:0%;padding-left:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end-top,.content.--position-start-top{--rs-flyout-origin-y:0%}.content.--position-end-bottom,.content.--position-start-bottom{--rs-flyout-origin-y:100%}.content.--visible .inner{opacity:1;transform:scale(1) translateY(0)}.content.--animated .inner{transition-duration:var(--rs-duration-rapid);transition-property:opacity,transform}.content.--animated.--visible .inner{transition-duration:var(--rs-duration-fast);transition-timing-function:var(--rs-easing-decelerate)}.content.--hover-disabled{pointer-events:none}
1
+ .content{--rs-flyout-gap:0;--rs-flyout-origin-x:50%;--rs-flyout-origin-y:50%;pointer-events:none;position:absolute}.content.--hover{pointer-events:all}.content.--hover-disabled,.content.--hover-disabled .inner{pointer-events:none}.inner{opacity:0;pointer-events:all;transform:scale(.9) translateY(0);transform-origin:var(--rs-flyout-origin-x) var(--rs-flyout-origin-y);transition:1ms var(--rs-easing-accelerate)}.content.--width-trigger .inner{transform:scale(1) translateY(var(--rs-unit-x2))}.content.--position-top,.content.--position-top-end,.content.--position-top-start{--rs-flyout-origin-y:100%;padding-bottom:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom,.content.--position-bottom-end,.content.--position-bottom-start{--rs-flyout-origin-y:0%;padding-top:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-bottom-start,.content.--position-top-start{--rs-flyout-origin-x:0%}.content.--position-bottom-end,.content.--position-top-end{--rs-flyout-origin-x:100%}.content.--position-start,.content.--position-start-bottom,.content.--position-start-top{--rs-flyout-origin-x:100%;padding-right:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end,.content.--position-end-bottom,.content.--position-end-top{--rs-flyout-origin-x:0%;padding-left:calc(var(--rs-unit-x1) * var(--rs-flyout-gap))}.content.--position-end-top,.content.--position-start-top{--rs-flyout-origin-y:0%}.content.--position-end-bottom,.content.--position-start-bottom{--rs-flyout-origin-y:100%}.content.--visible .inner{opacity:1;transform:scale(1) translateY(0)}.content.--animated .inner{transition-duration:var(--rs-duration-rapid);transition-property:opacity,transform}.content.--animated.--visible .inner{transition-duration:var(--rs-duration-fast);transition-timing-function:var(--rs-easing-decelerate)}
@@ -7,6 +7,12 @@ import type { TrapMode } from "../../../utilities/a11y";
7
7
  type XSide = "start" | "end";
8
8
  type YSide = "top" | "bottom";
9
9
  export type Side = XSide | YSide;
10
+ export type CloseReason = "escape-key" | "outside-click"
11
+ /**
12
+ * Keeping the item selection type here since DropdownMenu items use Flyout context
13
+ * and not a separate DropdownMenu context
14
+ */
15
+ | "item-selection" | "close-button";
10
16
  export type Position = `${YSide}` | `${YSide}-${XSide}` | `${XSide}` | `${XSide}-${YSide}`;
11
17
  export type Width = "trigger" | string;
12
18
  export type Options = {
@@ -31,7 +37,9 @@ export type FlyoutData = {
31
37
  position: Position;
32
38
  };
33
39
  export type UseFlyoutData = Pick<State, "styles" | "position" | "status"> & {
34
- updatePosition: () => void;
40
+ updatePosition: (args?: {
41
+ sync?: boolean;
42
+ }) => void;
35
43
  render: () => void;
36
44
  hide: () => void;
37
45
  remove: () => void;
@@ -86,7 +94,9 @@ type BaseProps = {
86
94
  originCoordinates?: G.Coordinates;
87
95
  children?: React.ReactNode;
88
96
  onOpen?: () => void;
89
- onClose?: () => void;
97
+ onClose?: (args: {
98
+ reason?: CloseReason;
99
+ }) => void;
90
100
  width?: Width;
91
101
  contentGap?: number;
92
102
  contentShift?: number;
@@ -117,8 +127,9 @@ export type ContextProps = {
117
127
  width?: Width;
118
128
  triggerElRef?: React.RefObject<HTMLButtonElement | null>;
119
129
  flyoutElRef: React.RefObject<HTMLDivElement | null>;
120
- handleClose: (options?: {
130
+ handleClose: (options: {
121
131
  closeParents?: boolean;
132
+ reason?: CloseReason;
122
133
  }) => void;
123
134
  handleOpen: () => void;
124
135
  handleMouseEnter: () => void;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
3
  import React from "react";
4
- import { classNames } from "../../../utilities/helpers.js";
4
+ import { classNames, throttleHandler } from "../../../utilities/helpers.js";
5
5
  import useIsomorphicLayoutEffect from "../../../hooks/useIsomorphicLayoutEffect.js";
6
6
  import Portal from "../Portal/index.js";
7
7
  import { findClosestRenderContainer } from "../../../utilities/dom/index.js";
@@ -10,9 +10,21 @@ import { useFlyoutContext, ContentProvider } from "./Flyout.context.js";
10
10
  import s from "./Flyout.module.css";
11
11
  const FlyoutContent = (props) => {
12
12
  const { children, className, attributes } = props;
13
- const { flyout, id, flyoutElRef, triggerElRef, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentGap, contentClassName, contentAttributes, trapFocusMode, disableContentHover, width, containerRef, isSubmenu, } = useFlyoutContext();
14
- const { styles, status, position } = flyout;
13
+ const { flyout, id, flyoutElRef, triggerElRef, handleClose, handleTransitionEnd, handleTransitionStart, triggerType, handleMouseEnter, handleMouseLeave, handleContentMouseDown, handleContentMouseUp, contentGap, contentClassName, contentAttributes, trapFocusMode, disableContentHover, width, containerRef, isSubmenu, } = useFlyoutContext();
14
+ const { styles, status, position, updatePosition } = flyout;
15
15
  const [mounted, setMounted] = React.useState(false);
16
+ const closestContainer = React.useMemo(() => {
17
+ if (!mounted)
18
+ return;
19
+ if (!triggerElRef)
20
+ return;
21
+ return findClosestRenderContainer({ el: triggerElRef.current });
22
+ }, [mounted, triggerElRef]);
23
+ const scrollableRef = (mounted && closestContainer?.el === document.body) ||
24
+ !closestContainer?.el ||
25
+ closestContainer.scrollable
26
+ ? undefined
27
+ : { current: closestContainer.el };
16
28
  useIsomorphicLayoutEffect(() => {
17
29
  setMounted(true);
18
30
  }, []);
@@ -26,6 +38,28 @@ const FlyoutContent = (props) => {
26
38
  el.addEventListener("transitionstart", handleTransitionStart);
27
39
  return () => el.removeEventListener("transitionstart", handleTransitionStart);
28
40
  }, [handleTransitionStart, flyoutElRef, status]);
41
+ React.useEffect(() => {
42
+ if (!closestContainer?.scrollable)
43
+ return;
44
+ const triggerEl = triggerElRef?.current;
45
+ const containerEl = closestContainer.el;
46
+ const handleScroll = throttleHandler(() => {
47
+ const triggerBounds = triggerEl?.getBoundingClientRect();
48
+ const containerBounds = containerEl.getBoundingClientRect();
49
+ if (triggerBounds &&
50
+ (triggerBounds.bottom < containerBounds.top ||
51
+ triggerBounds.right < containerBounds.left ||
52
+ triggerBounds.left > containerBounds.right ||
53
+ triggerBounds.top > containerBounds.bottom)) {
54
+ handleClose({});
55
+ }
56
+ else {
57
+ flyout.updatePosition({ sync: true });
58
+ }
59
+ }, 16);
60
+ closestContainer.el.addEventListener("scroll", handleScroll, { passive: true });
61
+ return () => closestContainer.el.removeEventListener("scroll", handleScroll);
62
+ }, [closestContainer, flyout, handleClose, triggerElRef]);
29
63
  if (status === "idle" || !mounted)
30
64
  return null;
31
65
  const contentClassNames = classNames(s.content, triggerType === "hover" && s["--hover"], status === "visible" && s["--visible"],
@@ -52,10 +86,6 @@ const FlyoutContent = (props) => {
52
86
  ...styles,
53
87
  "--rs-flyout-gap": contentGap,
54
88
  }, ref: flyoutElRef, onTransitionEnd: handleTransitionEnd, onMouseEnter: triggerType === "hover" ? handleMouseEnter : undefined, onMouseLeave: triggerType === "hover" ? handleMouseLeave : undefined, onMouseDown: handleContentMouseDown, onTouchStart: handleContentMouseDown, onMouseUp: handleContentMouseUp, onTouchEnd: handleContentMouseUp, children: _jsx("div", { role: role, ...attributes, id: id, "aria-modal": role === "dialog" ? true : undefined, style: contentAttributes?.style, className: innerClassNames, children: children }) }) }));
55
- const closestScrollable = triggerElRef && findClosestRenderContainer({ el: triggerElRef.current });
56
- const scrollableRef = closestScrollable === document.body || !closestScrollable
57
- ? undefined
58
- : { current: closestScrollable };
59
89
  return _jsx(Portal, { targetRef: containerRef || scrollableRef, children: content });
60
90
  };
61
91
  export default FlyoutContent;