reshaped 3.3.13 → 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 (61) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/bundle.css +1 -1
  3. package/dist/bundle.d.ts +3 -0
  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 +2 -1
  9. package/dist/components/Carousel/Carousel.types.d.ts +1 -0
  10. package/dist/components/ContextMenu/ContextMenu.js +2 -2
  11. package/dist/components/ContextMenu/tests/ContextMenu.test.stories.js +1 -1
  12. package/dist/components/DropdownMenu/DropdownMenu.js +6 -1
  13. package/dist/components/DropdownMenu/tests/DropdownMenu.test.stories.js +2 -2
  14. package/dist/components/Popover/Popover.js +1 -1
  15. package/dist/components/Popover/tests/Popover.test.stories.js +4 -4
  16. package/dist/components/ProgressIndicator/ProgressIndicator.d.ts +3 -0
  17. package/dist/components/ProgressIndicator/ProgressIndicator.js +101 -0
  18. package/dist/components/ProgressIndicator/ProgressIndicator.module.css +1 -0
  19. package/dist/components/ProgressIndicator/ProgressIndicator.types.d.ts +9 -0
  20. package/dist/components/ProgressIndicator/ProgressIndicator.types.js +1 -0
  21. package/dist/components/ProgressIndicator/index.d.ts +2 -0
  22. package/dist/components/ProgressIndicator/index.js +1 -0
  23. package/dist/components/ProgressIndicator/tests/ProgressIndicator.stories.d.ts +19 -0
  24. package/dist/components/ProgressIndicator/tests/ProgressIndicator.stories.js +85 -0
  25. package/dist/components/Reshaped/Reshaped.js +4 -5
  26. package/dist/components/TextField/TextField.module.css +1 -1
  27. package/dist/components/Toast/tests/Toast.stories.js +22 -7
  28. package/dist/components/Tooltip/tests/Tooltip.test.stories.js +1 -1
  29. package/dist/components/_private/Flyout/Flyout.module.css +1 -1
  30. package/dist/components/_private/Flyout/Flyout.types.d.ts +14 -3
  31. package/dist/components/_private/Flyout/FlyoutContent.js +37 -7
  32. package/dist/components/_private/Flyout/FlyoutControlled.js +12 -11
  33. package/dist/components/_private/Flyout/FlyoutUncontrolled.js +3 -5
  34. package/dist/components/_private/Flyout/index.d.ts +1 -1
  35. package/dist/components/_private/Flyout/tests/Flyout.stories.d.ts +79 -13
  36. package/dist/components/_private/Flyout/tests/Flyout.stories.js +526 -280
  37. package/dist/components/_private/Flyout/useFlyout.js +9 -3
  38. package/dist/components/_private/Flyout/utilities/isFullyVisible.d.ts +3 -1
  39. package/dist/components/_private/Flyout/utilities/isFullyVisible.js +2 -2
  40. package/dist/hooks/_private/usePrevious.d.ts +2 -0
  41. package/dist/hooks/_private/usePrevious.js +17 -0
  42. package/dist/hooks/_private/useSingletonEnvironment.d.ts +1 -1
  43. package/dist/hooks/_private/useSingletonEnvironment.js +1 -1
  44. package/dist/hooks/_private/useSingletonKeyboardMode.d.ts +13 -2
  45. package/dist/hooks/_private/useSingletonKeyboardMode.js +48 -15
  46. package/dist/hooks/tests/useKeyboardMode.stories.d.ts +6 -0
  47. package/dist/hooks/tests/useKeyboardMode.stories.js +37 -0
  48. package/dist/hooks/useKeyboardMode.d.ts +7 -0
  49. package/dist/hooks/useKeyboardMode.js +13 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.js +2 -0
  52. package/dist/utilities/a11y/index.d.ts +1 -1
  53. package/dist/utilities/a11y/index.js +1 -1
  54. package/dist/utilities/a11y/keyboardMode.d.ts +2 -2
  55. package/dist/utilities/a11y/keyboardMode.js +2 -2
  56. package/dist/utilities/dom/find.d.ts +4 -1
  57. package/dist/utilities/dom/find.js +4 -4
  58. package/dist/utilities/scroll/lockStandard.js +1 -1
  59. package/package.json +3 -4
  60. package/dist/components/_private/Flyout/tests/Flyout.test.stories.d.ts +0 -28
  61. package/dist/components/_private/Flyout/tests/Flyout.test.stories.js +0 -205
@@ -33,7 +33,8 @@ const flyout = (args) => {
33
33
  const targetClone = flyoutEl.cloneNode(true);
34
34
  const baseUnit = getComputedStyle(flyoutEl).getPropertyValue("--rs-unit-x1");
35
35
  const unitModifier = baseUnit ? parseInt(baseUnit) : 0;
36
- const triggerBounds = passedTriggerBounds || triggerEl?.getBoundingClientRect();
36
+ const internalTriggerBounds = triggerEl?.getBoundingClientRect();
37
+ const triggerBounds = passedTriggerBounds || internalTriggerBounds;
37
38
  if (!triggerBounds)
38
39
  return;
39
40
  const resolvedTriggerBounds = getRectFromCoordinates(triggerBounds);
@@ -56,7 +57,12 @@ const flyout = (args) => {
56
57
  // Insert inside shadow root if possible to make sure styles are applied correctly
57
58
  (shadowRoot || document.body).appendChild(targetClone);
58
59
  const flyoutBounds = targetClone.getBoundingClientRect();
59
- const containerParent = container || (triggerEl ? findClosestRenderContainer({ el: triggerEl }) : document.body);
60
+ const closestRenderContainer = !container && triggerEl ? findClosestRenderContainer({ el: triggerEl }) : undefined;
61
+ const containerParent = container ||
62
+ // Only render inside non-scrollable container to make sure it doesn't get clipped by overflow auto
63
+ // We render those cases in the document root and then sync the position on scroll instead
64
+ (!closestRenderContainer?.scrollable ? closestRenderContainer?.el : undefined) ||
65
+ document.body;
60
66
  const containerBounds = containerParent.getBoundingClientRect();
61
67
  const scopeOffset = {
62
68
  top: containerBounds.top + document.documentElement.scrollTop - containerParent.scrollTop,
@@ -74,7 +80,7 @@ const flyout = (args) => {
74
80
  contentGap: contentGap * unitModifier,
75
81
  contentShift: contentShift * unitModifier,
76
82
  });
77
- const visible = isFullyVisible(tested);
83
+ const visible = isFullyVisible({ ...tested, container });
78
84
  const validPosition = visible || fallbackPositions?.length === 0;
79
85
  // Saving first try in case non of the options work
80
86
  if (validPosition || lastUsedFallback === currentPosition) {
@@ -2,5 +2,7 @@ import calculatePosition from "./calculatePosition";
2
2
  /**
3
3
  * Check if element visually fits on the screen
4
4
  */
5
- declare const isFullyVisible: (args: ReturnType<typeof calculatePosition>) => boolean;
5
+ declare const isFullyVisible: (args: ReturnType<typeof calculatePosition> & {
6
+ container?: HTMLElement | null;
7
+ }) => boolean;
6
8
  export default isFullyVisible;
@@ -2,8 +2,8 @@
2
2
  * Check if element visually fits on the screen
3
3
  */
4
4
  const isFullyVisible = (args) => {
5
- const { styles, scopeOffset } = args;
6
- const htmlEl = document.documentElement;
5
+ const { styles, scopeOffset, container } = args;
6
+ const htmlEl = container || document.documentElement;
7
7
  const pageLeft = htmlEl.scrollLeft;
8
8
  const pageRight = pageLeft + htmlEl.clientWidth;
9
9
  const pageTop = htmlEl.scrollTop;
@@ -0,0 +1,2 @@
1
+ declare const usePrevious: <T>(value?: T, clean?: boolean) => T;
2
+ export default usePrevious;
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import React from "react";
3
+ const copy = (value) => {
4
+ const valueIsDate = value instanceof Date;
5
+ if (valueIsDate)
6
+ return String(valueIsDate);
7
+ const string = JSON.stringify(value);
8
+ return JSON.parse(string);
9
+ };
10
+ const usePrevious = (value, clean = false) => {
11
+ const ref = React.useRef(clean ? copy(value) : value);
12
+ React.useEffect(() => {
13
+ ref.current = clean ? copy(value) : value;
14
+ }, [value, clean]);
15
+ return ref.current;
16
+ };
17
+ export default usePrevious;
@@ -5,5 +5,5 @@ type Context = {
5
5
  defaultViewport: G.Viewport;
6
6
  };
7
7
  export declare const SingletonEnvironmentContext: React.Context<Context>;
8
- export declare const useSingletonRTL: (defaultRTL?: boolean) => [boolean, React.Dispatch<React.SetStateAction<boolean>>];
8
+ export declare const useSingletonEnvironment: (defaultRTL?: boolean) => [boolean, React.Dispatch<React.SetStateAction<boolean>>];
9
9
  export {};
@@ -4,7 +4,7 @@ export const SingletonEnvironmentContext = React.createContext({
4
4
  rtl: [false, () => { }],
5
5
  defaultViewport: "s",
6
6
  });
7
- export const useSingletonRTL = (defaultRTL) => {
7
+ export const useSingletonEnvironment = (defaultRTL) => {
8
8
  const state = React.useState(defaultRTL || false);
9
9
  const [isRTL, setRTL] = state;
10
10
  /**
@@ -1,2 +1,13 @@
1
- declare const useSingletonKeyboardMode: () => void;
2
- export default useSingletonKeyboardMode;
1
+ import React from "react";
2
+ type ContextProps = {
3
+ disabledRef: React.RefObject<boolean> | null;
4
+ disable: () => void;
5
+ enable: () => void;
6
+ activate: () => void;
7
+ deactivate: () => void;
8
+ };
9
+ export declare const SingletonKeyboardModeContext: React.Context<ContextProps>;
10
+ export declare const SingletonKeyboardModeProvider: (props: {
11
+ children: React.ReactNode;
12
+ }) => import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -1,25 +1,58 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
1
3
  import React from "react";
2
4
  import * as keys from "../../constants/keys.js";
3
- import { enableKeyboardMode, disableKeyboardMode } from "../../utilities/a11y/index.js";
4
- const useSingletonKeyboardMode = () => {
5
+ import { activateKeyboardMode, deactivateKeyboardMode } from "../../utilities/a11y/index.js";
6
+ export const SingletonKeyboardModeContext = React.createContext({
7
+ disabledRef: null,
8
+ disable: () => { },
9
+ enable: () => { },
10
+ activate: () => { },
11
+ deactivate: () => { },
12
+ });
13
+ export const SingletonKeyboardModeProvider = (props) => {
14
+ const disabledRef = React.useRef(false);
15
+ const disable = React.useCallback(() => {
16
+ disabledRef.current = true;
17
+ }, []);
18
+ const enable = React.useCallback(() => {
19
+ disabledRef.current = false;
20
+ }, []);
21
+ const activate = React.useCallback(() => {
22
+ if (disabledRef.current)
23
+ return;
24
+ activateKeyboardMode();
25
+ }, []);
26
+ const deactivate = React.useCallback(() => {
27
+ if (disabledRef.current)
28
+ return;
29
+ deactivateKeyboardMode();
30
+ }, []);
31
+ const handleKeyDown = React.useCallback((e) => {
32
+ if (e.metaKey || e.altKey || e.ctrlKey)
33
+ return;
34
+ // Prevent focus ring from appearing when using mouse but closing with esc
35
+ if (e.key === keys.ESC)
36
+ return;
37
+ activate();
38
+ }, [activate]);
39
+ const handleClick = React.useCallback(() => {
40
+ deactivate();
41
+ }, [deactivate]);
5
42
  React.useEffect(() => {
6
- const handleKeyDown = (e) => {
7
- if (e.metaKey || e.altKey || e.ctrlKey)
8
- return;
9
- // Prevent focus ring from appearing when using mouse but closing with esc
10
- if (e.key === keys.ESC)
11
- return;
12
- enableKeyboardMode();
13
- };
14
- const handleClick = () => {
15
- disableKeyboardMode();
16
- };
17
43
  window.addEventListener("keydown", handleKeyDown);
18
44
  window.addEventListener("mousedown", handleClick);
19
45
  return () => {
20
46
  window.removeEventListener("keydown", handleKeyDown);
21
47
  window.removeEventListener("mousedown", handleClick);
22
48
  };
23
- }, []);
49
+ }, [handleClick, handleKeyDown]);
50
+ const value = React.useMemo(() => ({
51
+ disabledRef,
52
+ disable,
53
+ enable,
54
+ activate,
55
+ deactivate,
56
+ }), [disable, enable, activate, deactivate]);
57
+ return (_jsx(SingletonKeyboardModeContext.Provider, { value: value, children: props.children }));
24
58
  };
25
- export default useSingletonKeyboardMode;
@@ -0,0 +1,6 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ declare const _default: {
3
+ title: string;
4
+ };
5
+ export default _default;
6
+ export declare const base: StoryObj;
@@ -0,0 +1,37 @@
1
+ import { expect, userEvent } from "@storybook/test";
2
+ import Button from "../../components/Button/index.js";
3
+ import View from "../../components/View/index.js";
4
+ import useKeyboardMode from "../useKeyboardMode.js";
5
+ export default { title: "Hooks/useKeyboardMode" };
6
+ const Component = () => {
7
+ const { activate, deactivate, disable, enable } = useKeyboardMode();
8
+ return (<View direction="row" gap={2}>
9
+ <Button onClick={activate}>Activate</Button>
10
+ <Button onClick={deactivate}>Deactivate</Button>
11
+ <Button onClick={disable}>Disable</Button>
12
+ <Button onClick={enable}>Enable</Button>
13
+ </View>);
14
+ };
15
+ export const base = {
16
+ name: "base",
17
+ render: () => <Component />,
18
+ play: async ({ canvas }) => {
19
+ const attribute = "data-rs-keyboard";
20
+ const root = document.documentElement;
21
+ const activateTrigger = canvas.getAllByRole("button")[0];
22
+ const deactivateTrigger = canvas.getAllByRole("button")[1];
23
+ const disableTrigger = canvas.getAllByRole("button")[2];
24
+ const enableTrigger = canvas.getAllByRole("button")[3];
25
+ expect(root).not.toHaveAttribute(attribute);
26
+ await userEvent.click(activateTrigger);
27
+ expect(root).toHaveAttribute(attribute);
28
+ await userEvent.click(deactivateTrigger);
29
+ expect(root).not.toHaveAttribute(attribute);
30
+ await userEvent.click(disableTrigger);
31
+ await userEvent.click(activateTrigger);
32
+ expect(root).not.toHaveAttribute(attribute);
33
+ await userEvent.click(enableTrigger);
34
+ await userEvent.click(activateTrigger);
35
+ expect(root).toHaveAttribute(attribute);
36
+ },
37
+ };
@@ -0,0 +1,7 @@
1
+ declare const useKeyboardMode: () => {
2
+ enable: () => void;
3
+ disable: () => void;
4
+ activate: () => void;
5
+ deactivate: () => void;
6
+ };
7
+ export default useKeyboardMode;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import React from "react";
3
+ import { SingletonKeyboardModeContext } from "./_private/useSingletonKeyboardMode.js";
4
+ const useKeyboardMode = () => {
5
+ const singletonKeyboardMode = React.useContext(SingletonKeyboardModeContext);
6
+ return React.useMemo(() => ({
7
+ enable: singletonKeyboardMode.enable,
8
+ disable: singletonKeyboardMode.disable,
9
+ activate: singletonKeyboardMode.activate,
10
+ deactivate: singletonKeyboardMode.deactivate,
11
+ }), [singletonKeyboardMode]);
12
+ };
13
+ export default useKeyboardMode;
package/dist/index.d.ts CHANGED
@@ -73,6 +73,8 @@ export { default as Popover } from "./components/Popover";
73
73
  export type { PopoverProps, PopoverInstance } from "./components/Popover";
74
74
  export { default as Progress } from "./components/Progress";
75
75
  export type { ProgressProps } from "./components/Progress";
76
+ export { default as ProgressIndicator } from "./components/ProgressIndicator";
77
+ export type { ProgressIndicatorProps } from "./components/ProgressIndicator";
76
78
  export { default as Radio } from "./components/Radio";
77
79
  export type { RadioProps } from "./components/Radio";
78
80
  export { default as RadioGroup } from "./components/RadioGroup";
@@ -124,6 +126,7 @@ export { default as useToggle } from "./hooks/useToggle";
124
126
  export { default as useRTL } from "./hooks/useRTL";
125
127
  export { default as useIsomorphicLayoutEffect } from "./hooks/useIsomorphicLayoutEffect";
126
128
  export { default as useHotkeys } from "./hooks/useHotkeys";
129
+ export { default as useKeyboardMode } from "./hooks/useKeyboardMode";
127
130
  export { default as useResponsiveClientValue } from "./hooks/useResponsiveClientValue";
128
131
  /**
129
132
  * Utilities
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ export { default as Pagination } from "./components/Pagination/index.js";
37
37
  export { default as PinField } from "./components/PinField/index.js";
38
38
  export { default as Popover } from "./components/Popover/index.js";
39
39
  export { default as Progress } from "./components/Progress/index.js";
40
+ export { default as ProgressIndicator } from "./components/ProgressIndicator/index.js";
40
41
  export { default as Radio } from "./components/Radio/index.js";
41
42
  export { default as RadioGroup } from "./components/RadioGroup/index.js";
42
43
  export { default as Reshaped } from "./components/Reshaped/index.js";
@@ -67,6 +68,7 @@ export { default as useToggle } from "./hooks/useToggle.js";
67
68
  export { default as useRTL } from "./hooks/useRTL.js";
68
69
  export { default as useIsomorphicLayoutEffect } from "./hooks/useIsomorphicLayoutEffect.js";
69
70
  export { default as useHotkeys } from "./hooks/useHotkeys.js";
71
+ export { default as useKeyboardMode } from "./hooks/useKeyboardMode.js";
70
72
  export { default as useResponsiveClientValue } from "./hooks/useResponsiveClientValue.js";
71
73
  /**
72
74
  * Utilities
@@ -1,4 +1,4 @@
1
1
  export { focusableSelector, getActiveElement, focusNextElement, focusPreviousElement, focusFirstElement, focusLastElement, } from "./focus";
2
- export { enableKeyboardMode, disableKeyboardMode, checkKeyboardMode } from "./keyboardMode";
2
+ export { activateKeyboardMode, deactivateKeyboardMode, checkKeyboardMode } from "./keyboardMode";
3
3
  export { default as TrapFocus } from "./TrapFocus";
4
4
  export type { TrapMode, FocusableElement } from "./types";
@@ -1,3 +1,3 @@
1
1
  export { focusableSelector, getActiveElement, focusNextElement, focusPreviousElement, focusFirstElement, focusLastElement, } from "./focus.js";
2
- export { enableKeyboardMode, disableKeyboardMode, checkKeyboardMode } from "./keyboardMode.js";
2
+ export { activateKeyboardMode, deactivateKeyboardMode, checkKeyboardMode } from "./keyboardMode.js";
3
3
  export { default as TrapFocus } from "./TrapFocus.js";
@@ -1,3 +1,3 @@
1
- export declare const enableKeyboardMode: () => void;
2
- export declare const disableKeyboardMode: () => void;
1
+ export declare const activateKeyboardMode: () => void;
2
+ export declare const deactivateKeyboardMode: () => void;
3
3
  export declare const checkKeyboardMode: () => boolean;
@@ -1,8 +1,8 @@
1
1
  const keyboardModeAttribute = "data-rs-keyboard";
2
- export const enableKeyboardMode = () => {
2
+ export const activateKeyboardMode = () => {
3
3
  document.documentElement.setAttribute(keyboardModeAttribute, "true");
4
4
  };
5
- export const disableKeyboardMode = () => {
5
+ export const deactivateKeyboardMode = () => {
6
6
  document.documentElement.removeAttribute(keyboardModeAttribute);
7
7
  };
8
8
  export const checkKeyboardMode = () => {
@@ -7,4 +7,7 @@ export declare const findClosestRenderContainer: (args: {
7
7
  el: HTMLElement | null;
8
8
  iteration?: number;
9
9
  overflowOnly?: boolean;
10
- }) => HTMLElement;
10
+ }) => {
11
+ el: HTMLElement;
12
+ scrollable?: boolean;
13
+ };
@@ -23,13 +23,13 @@ export const findClosestRenderContainer = (args) => {
23
23
  if (iteration === 0) {
24
24
  const shadowRoot = getShadowRoot(el);
25
25
  if (shadowRoot?.firstElementChild)
26
- return shadowRoot.firstElementChild;
26
+ return { el: shadowRoot.firstElementChild };
27
27
  }
28
28
  if (el === document.body || !el)
29
- return document.body;
29
+ return { el: document.body };
30
30
  if (isScrollable && el.scrollHeight > el.clientHeight)
31
- return el;
31
+ return { el, scrollable: true };
32
32
  if (isFixed && !overflowOnly)
33
- return el;
33
+ return { el };
34
34
  return findClosestRenderContainer({ el: el.parentElement, iteration: iteration + 1 });
35
35
  };
@@ -5,7 +5,7 @@ const styleCache = new StyleCache();
5
5
  const lockStandardScroll = (args) => {
6
6
  let container = document.body;
7
7
  if (args.originEl)
8
- container = findClosestRenderContainer({ el: args.originEl });
8
+ container = findClosestRenderContainer({ el: args.originEl }).el;
9
9
  if (args.containerEl)
10
10
  container = args.containerEl;
11
11
  const rect = container.getBoundingClientRect();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "reshaped",
3
3
  "description": "Professionally crafted design system in React & Figma for building products of any scale and complexity",
4
- "version": "3.3.13",
4
+ "version": "3.4.0-rc.0",
5
5
  "license": "MIT",
6
6
  "email": "hello@reshaped.so",
7
7
  "homepage": "https://reshaped.so",
@@ -71,9 +71,8 @@
71
71
  "build:cjs": "tsc -p tsconfig.cjs.json && resolve-tspaths -p tsconfig.cjs.json && node ./bin/format-cjs-build.js",
72
72
  "build:css": "postcss \"src/**/*.css\" --dir dist --base src --config tools/build",
73
73
  "build:stories": "tsc -p tsconfig.stories.json && resolve-tspaths -p tsconfig.stories.json",
74
- "build:bundle:vite": "vite build",
75
- "build:bundle": "yarn build:bundle:vite && cp dist/index.d.ts dist/bundle.d.ts",
76
- "build:size": "yarn clean && yarn build:esm && yarn build:bundle:vite",
74
+ "build:bundle": "vite build && cp dist/index.d.ts dist/bundle.d.ts",
75
+ "build:size": "yarn clean && yarn build:esm && yarn build:bundle",
77
76
  "build:storybook": "storybook build -o dist/app --disable-telemetry",
78
77
  "build:chromatic": "STORYBOOK_ENV=chromatic storybook build",
79
78
  "release": "read -p 'Have you updated chromatic tests?' && yarn release:lib && yarn release:source && yarn build:storybook && yarn release:copy",
@@ -1,28 +0,0 @@
1
- import { StoryObj } from "@storybook/react";
2
- import { fn } from "@storybook/test";
3
- declare const _default: {
4
- title: string;
5
- };
6
- export default _default;
7
- export declare const defaultActive: StoryObj<{
8
- handleOpen: ReturnType<typeof fn>;
9
- handleClose: ReturnType<typeof fn>;
10
- }>;
11
- export declare const active: StoryObj<{
12
- handleOpen: ReturnType<typeof fn>;
13
- handleClose: ReturnType<typeof fn>;
14
- }>;
15
- export declare const activeFalse: StoryObj<{
16
- handleOpen: ReturnType<typeof fn>;
17
- handleClose: ReturnType<typeof fn>;
18
- }>;
19
- export declare const triggerType: StoryObj<{
20
- handleOpen: ReturnType<typeof fn>;
21
- handleClose: ReturnType<typeof fn>;
22
- }>;
23
- export declare const disabled: StoryObj<{
24
- handleOpen: ReturnType<typeof fn>;
25
- }>;
26
- export declare const containerRef: StoryObj;
27
- export declare const shadowDom: StoryObj;
28
- export declare const className: StoryObj;
@@ -1,205 +0,0 @@
1
- import { expect, fn, userEvent, within, waitFor } from "@storybook/test";
2
- import Flyout from "../index.js";
3
- import Button from "../../../Button/index.js";
4
- import Reshaped from "../../../Reshaped/index.js";
5
- import { useRef } from "react";
6
- import { createRoot } from "react-dom/client";
7
- import { sleep } from "../../../../utilities/helpers.js";
8
- export default {
9
- title: "Internal/Flyout/tests",
10
- };
11
- export const defaultActive = {
12
- name: "defaultActive, uncontrolled",
13
- args: {
14
- handleOpen: fn(),
15
- handleClose: fn(),
16
- },
17
- render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} defaultActive>
18
- <Flyout.Trigger>
19
- {(attributes) => <Button attributes={attributes}>Open</Button>}
20
- </Flyout.Trigger>
21
- <Flyout.Content>Content</Flyout.Content>
22
- </Flyout>),
23
- play: async ({ canvasElement, args }) => {
24
- const canvas = within(canvasElement.ownerDocument.body);
25
- const trigger = canvas.getAllByRole("button")[0];
26
- let item = canvas.getByText("Content");
27
- await sleep(500);
28
- await userEvent.click(document.body);
29
- await waitFor(() => {
30
- expect(args.handleClose).toHaveBeenCalledTimes(1);
31
- expect(args.handleClose).toHaveBeenCalledWith();
32
- expect(item).not.toBeInTheDocument();
33
- });
34
- await userEvent.click(trigger);
35
- await waitFor(() => {
36
- expect(args.handleOpen).toHaveBeenCalledTimes(1);
37
- expect(args.handleOpen).toHaveBeenCalledWith();
38
- });
39
- item = canvas.getByText("Content");
40
- expect(item).toBeInTheDocument();
41
- },
42
- };
43
- export const active = {
44
- name: "active, controlled",
45
- args: {
46
- handleOpen: fn(),
47
- handleClose: fn(),
48
- },
49
- render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} active>
50
- <Flyout.Trigger>
51
- {(attributes) => <Button attributes={attributes}>Open</Button>}
52
- </Flyout.Trigger>
53
- <Flyout.Content>Content</Flyout.Content>
54
- </Flyout>),
55
- play: async ({ canvasElement, args }) => {
56
- const canvas = within(canvasElement.ownerDocument.body);
57
- const item = canvas.getByText("Content");
58
- await userEvent.click(document.body);
59
- await waitFor(() => {
60
- expect(args.handleClose).toHaveBeenCalledTimes(1);
61
- expect(args.handleClose).toHaveBeenCalledWith();
62
- });
63
- expect(item).toBeInTheDocument();
64
- },
65
- };
66
- export const activeFalse = {
67
- name: "active false, controlled",
68
- args: {
69
- handleOpen: fn(),
70
- handleClose: fn(),
71
- },
72
- render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} active={false}>
73
- <Flyout.Trigger>
74
- {(attributes) => <Button attributes={attributes}>Open</Button>}
75
- </Flyout.Trigger>
76
- <Flyout.Content>Content</Flyout.Content>
77
- </Flyout>),
78
- play: async ({ canvasElement, args }) => {
79
- const canvas = within(canvasElement.ownerDocument.body);
80
- const trigger = canvas.getAllByRole("button")[0];
81
- await userEvent.click(trigger);
82
- await waitFor(() => {
83
- expect(args.handleOpen).toHaveBeenCalledTimes(1);
84
- expect(args.handleOpen).toHaveBeenCalledWith();
85
- });
86
- const item = canvas.queryByText("Content");
87
- expect(item).not.toBeInTheDocument();
88
- },
89
- };
90
- export const triggerType = {
91
- name: "triggerType hover",
92
- args: {
93
- handleOpen: fn(),
94
- handleClose: fn(),
95
- },
96
- render: (args) => (<Flyout onOpen={args.handleOpen} onClose={args.handleClose} triggerType="hover">
97
- <Flyout.Trigger>
98
- {(attributes) => <Button attributes={attributes}>Open</Button>}
99
- </Flyout.Trigger>
100
- <Flyout.Content>Content</Flyout.Content>
101
- </Flyout>),
102
- play: async ({ canvasElement, args }) => {
103
- const canvas = within(canvasElement.ownerDocument.body);
104
- const trigger = canvas.getAllByRole("button")[0];
105
- await userEvent.hover(trigger);
106
- await waitFor(() => {
107
- expect(args.handleOpen).toHaveBeenCalledTimes(1);
108
- expect(args.handleOpen).toHaveBeenCalledWith();
109
- });
110
- await userEvent.unhover(trigger);
111
- await waitFor(() => {
112
- expect(args.handleClose).toHaveBeenCalledTimes(1);
113
- expect(args.handleClose).toHaveBeenCalledWith();
114
- });
115
- },
116
- };
117
- export const disabled = {
118
- name: "disabled",
119
- args: {
120
- handleOpen: fn(),
121
- },
122
- render: () => (<div data-testid="root">
123
- <Flyout disabled>
124
- <Flyout.Trigger>
125
- {(attributes) => <Button attributes={attributes}>Open</Button>}
126
- </Flyout.Trigger>
127
- <Flyout.Content className="test-classname" attributes={{ "data-testid": "test-id" }}>
128
- Content
129
- </Flyout.Content>
130
- </Flyout>
131
- </div>),
132
- play: async ({ canvasElement, args }) => {
133
- const canvas = within(canvasElement.ownerDocument.body);
134
- const button = canvas.getAllByRole("button")[0];
135
- await userEvent.click(button);
136
- expect(args.handleOpen).toHaveBeenCalledTimes(0);
137
- },
138
- };
139
- export const containerRef = {
140
- name: "containerRef",
141
- render: () => {
142
- const portalRef = useRef(null);
143
- return (<div ref={portalRef} data-testid="test-id">
144
- <Flyout containerRef={portalRef} active>
145
- <Flyout.Trigger>
146
- {(attributes) => <Button attributes={attributes}>Trigger</Button>}
147
- </Flyout.Trigger>
148
- <Flyout.Content>Content</Flyout.Content>
149
- </Flyout>
150
- </div>);
151
- },
152
- play: async ({ canvasElement }) => {
153
- const canvas = within(canvasElement.ownerDocument.body);
154
- const containerEl = canvas.getByTestId("test-id");
155
- const contentEl = canvas.getByText("Content");
156
- expect(containerEl).toContainElement(contentEl);
157
- },
158
- };
159
- class CustomElement extends window.HTMLElement {
160
- constructor() {
161
- super();
162
- this.attachShadow({ mode: "open" });
163
- if (!this.shadowRoot)
164
- return;
165
- const root = createRoot(this.shadowRoot);
166
- root.render(<Reshaped>
167
- <Flyout active>
168
- <Flyout.Trigger>
169
- {(attributes) => <button {...attributes}>Trigger</button>}
170
- </Flyout.Trigger>
171
- <Flyout.Content>
172
- <div id="test-id"/>
173
- </Flyout.Content>
174
- </Flyout>
175
- </Reshaped>);
176
- }
177
- }
178
- window.customElements.define("custom-element-flyout", CustomElement);
179
- export const shadowDom = {
180
- name: "shadow DOM",
181
- // @ts-ignore
182
- render: () => <custom-element-flyout />,
183
- play: async () => {
184
- expect(document.querySelector("custom-element-flyout")?.shadowRoot?.querySelector(`#test-id`)).toBeTruthy();
185
- expect(document.body.querySelector(`#test-id`)).toBe(null);
186
- },
187
- };
188
- export const className = {
189
- name: "className, attributes",
190
- render: () => (<div data-testid="root">
191
- <Flyout active>
192
- <Flyout.Trigger>
193
- {(attributes) => <Button attributes={attributes}>Open</Button>}
194
- </Flyout.Trigger>
195
- <Flyout.Content className="test-classname" attributes={{ "data-testid": "test-id" }}>
196
- Content
197
- </Flyout.Content>
198
- </Flyout>
199
- </div>),
200
- play: async ({ canvasElement }) => {
201
- const canvas = within(canvasElement.ownerDocument.body);
202
- const menu = await canvas.findByTestId("test-id");
203
- expect(menu).toHaveClass("test-classname");
204
- },
205
- };