@commercetools/nimbus 0.0.1 → 0.0.3-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1412 -0
- package/dist/index.js +22451 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +27 -0
- package/dist/index.umd.cjs.map +1 -0
- package/package.json +74 -40
- package/.storybook/apca-check/index.ts +0 -150
- package/.storybook/main.ts +0 -64
- package/.storybook/preview.tsx +0 -92
- package/.storybook/vitest.setup.ts +0 -13
- package/docs/architecture-decisions/adr-0001-consumer-component-apis.md +0 -177
- package/docs/architecture-decisions/adr-0002-compound-component-extraction.md +0 -82
- package/src/components/accordion/accordion-context.tsx +0 -17
- package/src/components/accordion/accordion.mdx +0 -172
- package/src/components/accordion/accordion.recipe.tsx +0 -98
- package/src/components/accordion/accordion.slots.tsx +0 -39
- package/src/components/accordion/accordion.stories.tsx +0 -188
- package/src/components/accordion/accordion.tsx +0 -16
- package/src/components/accordion/accordion.types.tsx +0 -54
- package/src/components/accordion/components/accordion-content.tsx +0 -28
- package/src/components/accordion/components/accordion-group.tsx +0 -27
- package/src/components/accordion/components/accordion-header.tsx +0 -63
- package/src/components/accordion/components/accordion-item.tsx +0 -87
- package/src/components/accordion/index.ts +0 -2
- package/src/components/alert/alert.mdx +0 -92
- package/src/components/alert/alert.recipe.tsx +0 -65
- package/src/components/alert/alert.slots.tsx +0 -46
- package/src/components/alert/alert.stories.tsx +0 -308
- package/src/components/alert/alert.tsx +0 -18
- package/src/components/alert/alert.types.tsx +0 -70
- package/src/components/alert/components/alert.actions.tsx +0 -27
- package/src/components/alert/components/alert.description.tsx +0 -27
- package/src/components/alert/components/alert.dismiss-button.tsx +0 -41
- package/src/components/alert/components/alert.root.tsx +0 -92
- package/src/components/alert/components/alert.title.tsx +0 -29
- package/src/components/alert/index.ts +0 -2
- package/src/components/avatar/avatar.mdx +0 -80
- package/src/components/avatar/avatar.recipe.tsx +0 -36
- package/src/components/avatar/avatar.slots.tsx +0 -16
- package/src/components/avatar/avatar.stories.tsx +0 -136
- package/src/components/avatar/avatar.tsx +0 -34
- package/src/components/avatar/avatar.types.ts +0 -33
- package/src/components/avatar/index.ts +0 -2
- package/src/components/badge/badge.mdx +0 -91
- package/src/components/badge/badge.recipe.tsx +0 -72
- package/src/components/badge/badge.slots.tsx +0 -8
- package/src/components/badge/badge.stories.tsx +0 -124
- package/src/components/badge/badge.tsx +0 -35
- package/src/components/badge/badge.types.tsx +0 -40
- package/src/components/badge/index.ts +0 -2
- package/src/components/bleed/bleed.tsx +0 -1
- package/src/components/bleed/index.ts +0 -1
- package/src/components/box/box.mdx +0 -115
- package/src/components/box/box.stories.tsx +0 -71
- package/src/components/box/box.tsx +0 -11
- package/src/components/box/index.ts +0 -1
- package/src/components/button/button.mdx +0 -169
- package/src/components/button/button.recipe.ts +0 -185
- package/src/components/button/button.slots.tsx +0 -45
- package/src/components/button/button.stories.tsx +0 -369
- package/src/components/button/button.tsx +0 -37
- package/src/components/button/button.types.ts +0 -14
- package/src/components/button/index.ts +0 -2
- package/src/components/card/card.mdx +0 -92
- package/src/components/card/card.recipe.tsx +0 -71
- package/src/components/card/card.slots.tsx +0 -50
- package/src/components/card/card.stories.tsx +0 -175
- package/src/components/card/card.tsx +0 -9
- package/src/components/card/card.types.ts +0 -22
- package/src/components/card/components/card.content.tsx +0 -29
- package/src/components/card/components/card.header.tsx +0 -28
- package/src/components/card/components/card.root.tsx +0 -62
- package/src/components/card/index.ts +0 -2
- package/src/components/checkbox/checkbox.mdx +0 -78
- package/src/components/checkbox/checkbox.recipe.tsx +0 -116
- package/src/components/checkbox/checkbox.slots.tsx +0 -33
- package/src/components/checkbox/checkbox.stories.tsx +0 -200
- package/src/components/checkbox/checkbox.tsx +0 -77
- package/src/components/checkbox/checkbox.types.tsx +0 -22
- package/src/components/checkbox/index.ts +0 -2
- package/src/components/code/code.mdx +0 -17
- package/src/components/code/code.recipe.ts +0 -63
- package/src/components/code/code.tsx +0 -1
- package/src/components/code/index.ts +0 -1
- package/src/components/dialog/dialog.mdx +0 -20
- package/src/components/dialog/dialog.recipe.ts +0 -254
- package/src/components/dialog/dialog.tsx +0 -61
- package/src/components/dialog/index.ts +0 -1
- package/src/components/em/em.mdx +0 -17
- package/src/components/em/em.tsx +0 -1
- package/src/components/em/index.ts +0 -1
- package/src/components/flex/flex.mdx +0 -41
- package/src/components/flex/flex.tsx +0 -1
- package/src/components/flex/index.ts +0 -1
- package/src/components/grid/grid.mdx +0 -156
- package/src/components/grid/grid.stories.tsx +0 -151
- package/src/components/grid/grid.tsx +0 -29
- package/src/components/grid/index.ts +0 -1
- package/src/components/heading/heading.mdx +0 -23
- package/src/components/heading/heading.recipe.ts +0 -49
- package/src/components/heading/heading.tsx +0 -1
- package/src/components/heading/index.ts +0 -1
- package/src/components/highlight/highlight.mdx +0 -18
- package/src/components/highlight/highlight.tsx +0 -1
- package/src/components/highlight/index.ts +0 -1
- package/src/components/icon-button/icon-button.mdx +0 -98
- package/src/components/icon-button/icon-button.stories.tsx +0 -188
- package/src/components/icon-button/icon-button.tsx +0 -21
- package/src/components/icon-button/icon-button.types.tsx +0 -10
- package/src/components/icon-button/index.ts +0 -2
- package/src/components/index.ts +0 -33
- package/src/components/input/index.ts +0 -1
- package/src/components/input/input.mdx +0 -20
- package/src/components/input/input.recipe.ts +0 -95
- package/src/components/input/input.tsx +0 -1
- package/src/components/input-group/index.ts +0 -1
- package/src/components/input-group/input-group.mdx +0 -20
- package/src/components/input-group/input-group.tsx +0 -44
- package/src/components/kbd/index.ts +0 -1
- package/src/components/kbd/kbd.mdx +0 -18
- package/src/components/kbd/kbd.recipe.ts +0 -57
- package/src/components/kbd/kbd.tsx +0 -1
- package/src/components/link/index.ts +0 -2
- package/src/components/link/link.mdx +0 -77
- package/src/components/link/link.recipe.ts +0 -52
- package/src/components/link/link.slots.tsx +0 -29
- package/src/components/link/link.stories.tsx +0 -204
- package/src/components/link/link.tsx +0 -38
- package/src/components/link/link.types.tsx +0 -26
- package/src/components/list/index.ts +0 -1
- package/src/components/list/list.mdx +0 -18
- package/src/components/list/list.recipe.ts +0 -68
- package/src/components/list/list.tsx +0 -9
- package/src/components/loading-spinner/index.ts +0 -2
- package/src/components/loading-spinner/loading-spinner.mdx +0 -92
- package/src/components/loading-spinner/loading-spinner.recipe.tsx +0 -70
- package/src/components/loading-spinner/loading-spinner.slots.tsx +0 -38
- package/src/components/loading-spinner/loading-spinner.stories.tsx +0 -97
- package/src/components/loading-spinner/loading-spinner.tsx +0 -50
- package/src/components/loading-spinner/loading-spinner.types.tsx +0 -21
- package/src/components/nimbus-provider/color-mode.tsx +0 -32
- package/src/components/nimbus-provider/index.ts +0 -2
- package/src/components/nimbus-provider/nimbus-provider.mdx +0 -21
- package/src/components/nimbus-provider/nimbus-provider.tsx +0 -51
- package/src/components/select/components/select.clear-button.tsx +0 -31
- package/src/components/select/components/select.option-group.tsx +0 -48
- package/src/components/select/components/select.option.tsx +0 -21
- package/src/components/select/components/select.options.tsx +0 -23
- package/src/components/select/components/select.root.tsx +0 -81
- package/src/components/select/index.ts +0 -2
- package/src/components/select/select.mdx +0 -170
- package/src/components/select/select.recipe.tsx +0 -216
- package/src/components/select/select.slots.tsx +0 -58
- package/src/components/select/select.stories.tsx +0 -841
- package/src/components/select/select.tsx +0 -18
- package/src/components/select/select.types.tsx +0 -37
- package/src/components/simple-grid/index.ts +0 -1
- package/src/components/simple-grid/simple-grid.mdx +0 -133
- package/src/components/simple-grid/simple-grid.stories.tsx +0 -143
- package/src/components/simple-grid/simple-grid.tsx +0 -31
- package/src/components/stack/index.ts +0 -1
- package/src/components/stack/stack.mdx +0 -88
- package/src/components/stack/stack.stories.tsx +0 -82
- package/src/components/stack/stack.tsx +0 -15
- package/src/components/table/index.ts +0 -1
- package/src/components/table/table.mdx +0 -23
- package/src/components/table/table.recipe.ts +0 -170
- package/src/components/table/table.tsx +0 -43
- package/src/components/text/index.ts +0 -1
- package/src/components/text/text.mdx +0 -244
- package/src/components/text/text.tsx +0 -23
- package/src/components/text-input/index.ts +0 -2
- package/src/components/text-input/text-input.mdx +0 -118
- package/src/components/text-input/text-input.recipe.tsx +0 -68
- package/src/components/text-input/text-input.slots.tsx +0 -24
- package/src/components/text-input/text-input.stories.tsx +0 -282
- package/src/components/text-input/text-input.tsx +0 -39
- package/src/components/text-input/text-input.types.ts +0 -7
- package/src/components/toggle-button-group/components/toggle-button-group.button.tsx +0 -14
- package/src/components/toggle-button-group/components/toggle-button-group.root.tsx +0 -15
- package/src/components/toggle-button-group/index.ts +0 -2
- package/src/components/toggle-button-group/toggle-button-group.mdx +0 -94
- package/src/components/toggle-button-group/toggle-button-group.recipe.tsx +0 -64
- package/src/components/toggle-button-group/toggle-button-group.slots.tsx +0 -26
- package/src/components/toggle-button-group/toggle-button-group.stories.tsx +0 -311
- package/src/components/toggle-button-group/toggle-button-group.tsx +0 -12
- package/src/components/toggle-button-group/toggle-button-group.types.tsx +0 -62
- package/src/components/tooltip/index.ts +0 -4
- package/src/components/tooltip/make-element-focusable.stories.tsx +0 -56
- package/src/components/tooltip/make-element-focusable.tsx +0 -57
- package/src/components/tooltip/tooltip-trigger.stories.tsx +0 -157
- package/src/components/tooltip/tooltip-trigger.tsx +0 -15
- package/src/components/tooltip/tooltip.mdx +0 -48
- package/src/components/tooltip/tooltip.recipe.ts +0 -26
- package/src/components/tooltip/tooltip.slots.ts +0 -35
- package/src/components/tooltip/tooltip.stories.tsx +0 -139
- package/src/components/tooltip/tooltip.tsx +0 -31
- package/src/components/tooltip/tooltip.types.ts +0 -44
- package/src/components/visually-hidden/index.ts +0 -1
- package/src/components/visually-hidden/visually-hidden.mdx +0 -61
- package/src/components/visually-hidden/visually-hidden.stories.tsx +0 -124
- package/src/components/visually-hidden/visually-hidden.tsx +0 -18
- package/src/docs/accessibility.mdx +0 -21
- package/src/docs/background.mdx +0 -154
- package/src/docs/border.mdx +0 -226
- package/src/docs/changelog.mdx +0 -17
- package/src/docs/components-layout.mdx +0 -22
- package/src/docs/components.mdx +0 -17
- package/src/docs/data-display.mdx +0 -23
- package/src/docs/display.mdx +0 -55
- package/src/docs/effects.mdx +0 -73
- package/src/docs/feedback.mdx +0 -22
- package/src/docs/filters.mdx +0 -268
- package/src/docs/flex-and-grid.mdx +0 -445
- package/src/docs/forms.mdx +0 -22
- package/src/docs/generated/index.mdx +0 -16
- package/src/docs/getting-started.mdx +0 -17
- package/src/docs/home.mdx +0 -56
- package/src/docs/hooks.mdx +0 -16
- package/src/docs/inputs.mdx +0 -21
- package/src/docs/installation.mdx +0 -60
- package/src/docs/interactivity.mdx +0 -278
- package/src/docs/known-issues.mdx +0 -19
- package/src/docs/layout.mdx +0 -301
- package/src/docs/list.mdx +0 -82
- package/src/docs/markdown.mdx +0 -234
- package/src/docs/media.mdx +0 -22
- package/src/docs/naivgation.mdx +0 -22
- package/src/docs/playground.mdx +0 -16
- package/src/docs/rfcs-component-structure-rfcs.mdx +0 -17
- package/src/docs/rfcs-component-structure.mdx +0 -74
- package/src/docs/rfcs-hook-structure.mdx +0 -59
- package/src/docs/sizing.mdx +0 -210
- package/src/docs/spacing.mdx +0 -193
- package/src/docs/style-props-typography.mdx +0 -373
- package/src/docs/style-props.mdx +0 -15
- package/src/docs/svg.mdx +0 -58
- package/src/docs/tables.mdx +0 -95
- package/src/docs/toc.mdx +0 -39
- package/src/docs/tokens/animations.mdx +0 -68
- package/src/docs/tokens/aspect-ratios.mdx +0 -21
- package/src/docs/tokens/blurs.mdx +0 -20
- package/src/docs/tokens/borders.mdx +0 -25
- package/src/docs/tokens/breakpoints.mdx +0 -35
- package/src/docs/tokens/colors.mdx +0 -86
- package/src/docs/tokens/cursors.mdx +0 -21
- package/src/docs/tokens/radii.mdx +0 -23
- package/src/docs/tokens/shadows.mdx +0 -21
- package/src/docs/tokens/sizes.mdx +0 -54
- package/src/docs/tokens/spacing.mdx +0 -35
- package/src/docs/tokens/typography.mdx +0 -61
- package/src/docs/tokens/z-indices.mdx +0 -23
- package/src/docs/tokens-other.mdx +0 -17
- package/src/docs/tokens.mdx +0 -16
- package/src/docs/transforms.mdx +0 -150
- package/src/docs/transitions.mdx +0 -164
- package/src/docs/typography.mdx +0 -17
- package/src/docs/utilities.mdx +0 -17
- package/src/hooks/index.ts +0 -2
- package/src/hooks/use-copy-to-clipboard/use-copy-to-clipboard.mdx +0 -54
- package/src/hooks/use-copy-to-clipboard/use-copy-to-clipboard.ts +0 -1
- package/src/hooks/use-hotkeys/use-hotkeys.mdx +0 -48
- package/src/hooks/use-hotkeys/use-hotkeys.stories.tsx +0 -69
- package/src/hooks/use-hotkeys/use-hotkeys.ts +0 -1
- package/src/index.ts +0 -3
- package/src/test/utils.tsx +0 -20
- package/src/theme/animation-styles.ts +0 -52
- package/src/theme/breakpoints.ts +0 -32
- package/src/theme/global-css.ts +0 -53
- package/src/theme/index.ts +0 -35
- package/src/theme/keyframes.ts +0 -192
- package/src/theme/layer-styles.ts +0 -12
- package/src/theme/recipes/index.ts +0 -21
- package/src/theme/semantic-tokens/colors.ts +0 -55
- package/src/theme/semantic-tokens/index.ts +0 -9
- package/src/theme/semantic-tokens/radii.ts +0 -3
- package/src/theme/semantic-tokens/shadows.ts +0 -4
- package/src/theme/slot-recipes/index.ts +0 -15
- package/src/theme/text-styles.ts +0 -8
- package/src/theme/tokens/animations.ts +0 -4
- package/src/theme/tokens/aspect-ratios.ts +0 -5
- package/src/theme/tokens/blurs.ts +0 -5
- package/src/theme/tokens/borders.ts +0 -4
- package/src/theme/tokens/colors.ts +0 -8
- package/src/theme/tokens/cursor.ts +0 -4
- package/src/theme/tokens/durations.ts +0 -4
- package/src/theme/tokens/easings.ts +0 -4
- package/src/theme/tokens/font-sizes.ts +0 -4
- package/src/theme/tokens/font-weights.ts +0 -4
- package/src/theme/tokens/fonts.ts +0 -4
- package/src/theme/tokens/index.ts +0 -57
- package/src/theme/tokens/letter-spacings.ts +0 -24
- package/src/theme/tokens/line-heights.ts +0 -4
- package/src/theme/tokens/radii.ts +0 -4
- package/src/theme/tokens/sizes.ts +0 -120
- package/src/theme/tokens/spacing.ts +0 -4
- package/src/theme/tokens/z-index.ts +0 -4
- package/src/utils/extractStyleProps.ts +0 -26
- package/src/utils/fixedForwardRef.ts +0 -17
- package/tsconfig.json +0 -38
- package/vite.config.ts +0 -54
- package/vitest.config.ts +0 -50
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import { ToggleButtonGroup } from "./toggle-button-group";
|
|
3
|
-
import { Stack } from "../stack";
|
|
4
|
-
import { userEvent, within, expect, fn } from "@storybook/test";
|
|
5
|
-
import { SentimentSatisfied as DemoIcon } from "@commercetools/nimbus-icons";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Storybook metadata configuration
|
|
9
|
-
*/
|
|
10
|
-
const meta: Meta<typeof ToggleButtonGroup.Root> = {
|
|
11
|
-
title: "components/ToggleButtonGroup",
|
|
12
|
-
component: ToggleButtonGroup.Root,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default meta;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Story type for TypeScript support
|
|
19
|
-
*/
|
|
20
|
-
type Story = StoryObj<typeof ToggleButtonGroup.Root>;
|
|
21
|
-
|
|
22
|
-
const defaultChildren = (
|
|
23
|
-
<>
|
|
24
|
-
<ToggleButtonGroup.Button id="left">Left</ToggleButtonGroup.Button>
|
|
25
|
-
<ToggleButtonGroup.Button id="center">Center</ToggleButtonGroup.Button>
|
|
26
|
-
<ToggleButtonGroup.Button id="right">Right</ToggleButtonGroup.Button>
|
|
27
|
-
</>
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
type ToggleButtonGroupSize = "md" | "xs"; // Replace with actual derived type if possible
|
|
31
|
-
type ToggleButtonGroupTone = "primary" | "critical" | "neutral"; // Replace with actual derived type
|
|
32
|
-
|
|
33
|
-
const sizes: ToggleButtonGroupSize[] = ["md", "xs"];
|
|
34
|
-
const tones: ToggleButtonGroupTone[] = ["primary", "critical", "neutral"];
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Base story
|
|
38
|
-
*
|
|
39
|
-
* Demonstrates the most basic implementation with interaction tests.
|
|
40
|
-
*/
|
|
41
|
-
export const Base: Story = {
|
|
42
|
-
args: {
|
|
43
|
-
size: "md",
|
|
44
|
-
tone: "primary",
|
|
45
|
-
children: defaultChildren,
|
|
46
|
-
onSelectionChange: fn(),
|
|
47
|
-
"aria-label": "Test Button Group",
|
|
48
|
-
},
|
|
49
|
-
play: async ({ canvasElement, args, step }) => {
|
|
50
|
-
const canvas = within(canvasElement);
|
|
51
|
-
// Get the group by its accessible name
|
|
52
|
-
const group = canvas.getByRole("radiogroup", {
|
|
53
|
-
name: /Test Button Group/i,
|
|
54
|
-
});
|
|
55
|
-
const buttons = within(group).getAllByRole("radio");
|
|
56
|
-
const [leftButton, centerButton, rightButton] = buttons;
|
|
57
|
-
const onSelectionChange = args.onSelectionChange as ReturnType<typeof fn>;
|
|
58
|
-
|
|
59
|
-
await step("Initial Rendering", async () => {
|
|
60
|
-
await expect(group).toBeInTheDocument();
|
|
61
|
-
await expect(buttons).toHaveLength(3);
|
|
62
|
-
// RAC ToggleButton uses aria-checked for selection state
|
|
63
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false");
|
|
64
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "false");
|
|
65
|
-
await expect(rightButton).toHaveAttribute("aria-checked", "false");
|
|
66
|
-
await expect(onSelectionChange).not.toHaveBeenCalled();
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
await step(
|
|
70
|
-
"Keyboard Navigation (Tab into group, Arrows between buttons)",
|
|
71
|
-
async () => {
|
|
72
|
-
await userEvent.tab(); // Tab into the group (focuses the first button)
|
|
73
|
-
await expect(leftButton).toHaveFocus();
|
|
74
|
-
|
|
75
|
-
await userEvent.keyboard("{ArrowRight}");
|
|
76
|
-
await expect(centerButton).toHaveFocus();
|
|
77
|
-
|
|
78
|
-
await userEvent.keyboard("{ArrowRight}");
|
|
79
|
-
await expect(rightButton).toHaveFocus();
|
|
80
|
-
|
|
81
|
-
await userEvent.keyboard("{ArrowLeft}");
|
|
82
|
-
await expect(centerButton).toHaveFocus();
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
await step("Keyboard Selection (Space)", async () => {
|
|
87
|
-
// centerButton currently has focus
|
|
88
|
-
await userEvent.keyboard("{ }"); // Press Space
|
|
89
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "true");
|
|
90
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false"); // Should deselect others in single-select mode
|
|
91
|
-
await expect(onSelectionChange).toHaveBeenCalledTimes(1);
|
|
92
|
-
|
|
93
|
-
// Select another button
|
|
94
|
-
await userEvent.keyboard("{ArrowLeft}"); // Move focus to leftButton
|
|
95
|
-
await expect(leftButton).toHaveFocus();
|
|
96
|
-
await userEvent.keyboard("{ }"); // Press Space
|
|
97
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "true");
|
|
98
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "false");
|
|
99
|
-
await expect(onSelectionChange).toHaveBeenCalledTimes(2);
|
|
100
|
-
|
|
101
|
-
// Deselect by pressing again (common toggle behavior)
|
|
102
|
-
await userEvent.keyboard("{ }"); // Press Space
|
|
103
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false");
|
|
104
|
-
await expect(onSelectionChange).toHaveBeenCalledTimes(3);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Reset selection for next step
|
|
108
|
-
await userEvent.click(leftButton); // Click to select 'left'
|
|
109
|
-
onSelectionChange.mockClear(); // Clear mock history
|
|
110
|
-
|
|
111
|
-
await step("Mouse Selection", async () => {
|
|
112
|
-
await userEvent.click(rightButton);
|
|
113
|
-
await expect(rightButton).toHaveAttribute("aria-checked", "true");
|
|
114
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false");
|
|
115
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "false");
|
|
116
|
-
await expect(onSelectionChange).toHaveBeenCalledTimes(1);
|
|
117
|
-
|
|
118
|
-
// Click again to deselect
|
|
119
|
-
await userEvent.click(rightButton);
|
|
120
|
-
await expect(rightButton).toHaveAttribute("aria-checked", "false");
|
|
121
|
-
await expect(onSelectionChange).toHaveBeenCalledTimes(2);
|
|
122
|
-
});
|
|
123
|
-
},
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Disabled Group Story
|
|
128
|
-
*
|
|
129
|
-
* Tests behavior when the entire group is disabled, with one button visually selected.
|
|
130
|
-
*/
|
|
131
|
-
export const DisabledGroup: Story = {
|
|
132
|
-
args: {
|
|
133
|
-
...Base.args, // Reuse args from Base
|
|
134
|
-
isDisabled: true,
|
|
135
|
-
selectedKeys: ["center"], // Set the middle button as initially selected
|
|
136
|
-
onSelectionChange: fn(),
|
|
137
|
-
"aria-label": "Disabled Test Group",
|
|
138
|
-
},
|
|
139
|
-
play: async ({ canvasElement, args, step }) => {
|
|
140
|
-
const canvas = within(canvasElement);
|
|
141
|
-
const group = canvas.getByRole("radiogroup", {
|
|
142
|
-
name: /Disabled Test Group/i,
|
|
143
|
-
});
|
|
144
|
-
const buttons = within(group).getAllByRole("radio");
|
|
145
|
-
const [leftButton, centerButton, rightButton] = buttons;
|
|
146
|
-
const onSelectionChange = args.onSelectionChange as ReturnType<typeof fn>;
|
|
147
|
-
|
|
148
|
-
await step("Initial Render shows default selection visually", async () => {
|
|
149
|
-
// Check that the defaultValue is reflected in aria-checked state
|
|
150
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "true");
|
|
151
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false");
|
|
152
|
-
await expect(rightButton).toHaveAttribute("aria-checked", "false");
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
await step("Buttons are functionally disabled", async () => {
|
|
156
|
-
await expect(leftButton).toBeDisabled();
|
|
157
|
-
await expect(centerButton).toBeDisabled();
|
|
158
|
-
await expect(rightButton).toBeDisabled();
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
await step("Cannot focus buttons via keyboard", async () => {
|
|
162
|
-
// Try tabbing - focus should skip the disabled group
|
|
163
|
-
await userEvent.tab();
|
|
164
|
-
await expect(leftButton).not.toHaveFocus();
|
|
165
|
-
await expect(centerButton).not.toHaveFocus();
|
|
166
|
-
await expect(rightButton).not.toHaveFocus();
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
await step("Cannot change selection via click", async () => {
|
|
170
|
-
// Click the selected button
|
|
171
|
-
await userEvent.click(centerButton);
|
|
172
|
-
// State should not change
|
|
173
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "true");
|
|
174
|
-
await expect(onSelectionChange).not.toHaveBeenCalled();
|
|
175
|
-
|
|
176
|
-
// Click a non-selected button
|
|
177
|
-
await userEvent.click(leftButton);
|
|
178
|
-
// State should not change
|
|
179
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false");
|
|
180
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "true"); // Still selected
|
|
181
|
-
await expect(onSelectionChange).not.toHaveBeenCalled();
|
|
182
|
-
});
|
|
183
|
-
},
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Default Selection Story
|
|
188
|
-
*
|
|
189
|
-
* Tests behavior when a value is pre-selected.
|
|
190
|
-
*/
|
|
191
|
-
export const DefaultSelection: Story = {
|
|
192
|
-
args: {
|
|
193
|
-
...Base.args, // Reuse args from Base
|
|
194
|
-
selectedKeys: ["center"], // Set the middle button as initially selected
|
|
195
|
-
onSelectionChange: fn(), // Ensure separate mock for this story
|
|
196
|
-
"aria-label": "Default Selection Test Group",
|
|
197
|
-
},
|
|
198
|
-
play: async ({ canvasElement, args, step }) => {
|
|
199
|
-
const canvas = within(canvasElement);
|
|
200
|
-
const group = canvas.getByRole("radiogroup", {
|
|
201
|
-
name: /Default Selection Test Group/i,
|
|
202
|
-
});
|
|
203
|
-
const buttons = within(group).getAllByRole("radio");
|
|
204
|
-
const [leftButton, centerButton, rightButton] = buttons;
|
|
205
|
-
const onSelectionChange = args.onSelectionChange as ReturnType<typeof fn>;
|
|
206
|
-
|
|
207
|
-
await step("Initial Render shows default selection", async () => {
|
|
208
|
-
await expect(centerButton).toHaveAttribute("aria-checked", "true");
|
|
209
|
-
await expect(leftButton).toHaveAttribute("aria-checked", "false");
|
|
210
|
-
await expect(rightButton).toHaveAttribute("aria-checked", "false");
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
await step("Can change selection via click", async () => {
|
|
214
|
-
await userEvent.click(leftButton);
|
|
215
|
-
// await expect(leftButton).toHaveAttribute("aria-checked", "true");
|
|
216
|
-
// await expect(centerButton).toHaveAttribute("aria-checked", "false");
|
|
217
|
-
await expect(onSelectionChange).toHaveBeenCalledTimes(1);
|
|
218
|
-
await expect(onSelectionChange).toHaveBeenLastCalledWith(
|
|
219
|
-
new Set(["left"])
|
|
220
|
-
);
|
|
221
|
-
});
|
|
222
|
-
},
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Showcase Sizes - Minimal test focusing on rendering
|
|
227
|
-
*/
|
|
228
|
-
export const Sizes: Story = {
|
|
229
|
-
render: (args) => (
|
|
230
|
-
<Stack direction="row" gap="400" alignItems="center">
|
|
231
|
-
{sizes.map((size) => (
|
|
232
|
-
<ToggleButtonGroup.Root
|
|
233
|
-
key={size}
|
|
234
|
-
{...args}
|
|
235
|
-
size={size}
|
|
236
|
-
aria-label={`Size ${size} Group`}
|
|
237
|
-
>
|
|
238
|
-
{defaultChildren}
|
|
239
|
-
</ToggleButtonGroup.Root>
|
|
240
|
-
))}
|
|
241
|
-
</Stack>
|
|
242
|
-
),
|
|
243
|
-
args: {
|
|
244
|
-
onSelectionChange: fn(), // Add mock even if not testing interaction heavily here
|
|
245
|
-
},
|
|
246
|
-
play: async ({ canvasElement, step }) => {
|
|
247
|
-
const canvas = within(canvasElement);
|
|
248
|
-
// Simple check: ensure both groups render
|
|
249
|
-
await step("Render groups for each size", async () => {
|
|
250
|
-
const groups = canvas.getAllByRole("radiogroup");
|
|
251
|
-
await expect(groups).toHaveLength(sizes.length);
|
|
252
|
-
// Optionally check a button exists in each
|
|
253
|
-
await expect(
|
|
254
|
-
within(groups[0]).getAllByRole("radio").length
|
|
255
|
-
).toBeGreaterThan(0);
|
|
256
|
-
await expect(
|
|
257
|
-
within(groups[1]).getAllByRole("radio").length
|
|
258
|
-
).toBeGreaterThan(0);
|
|
259
|
-
});
|
|
260
|
-
},
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Showcase Tones - Minimal test focusing on rendering
|
|
265
|
-
*/
|
|
266
|
-
export const Tones: Story = {
|
|
267
|
-
render: (args) => (
|
|
268
|
-
<Stack>
|
|
269
|
-
{tones.map((tone) => (
|
|
270
|
-
<ToggleButtonGroup.Root
|
|
271
|
-
key={tone}
|
|
272
|
-
{...args}
|
|
273
|
-
tone={tone}
|
|
274
|
-
aria-label={`Tone ${tone} Group`}
|
|
275
|
-
>
|
|
276
|
-
<ToggleButtonGroup.Button id="left">
|
|
277
|
-
<DemoIcon />
|
|
278
|
-
</ToggleButtonGroup.Button>
|
|
279
|
-
<ToggleButtonGroup.Button id="center">
|
|
280
|
-
<DemoIcon />
|
|
281
|
-
</ToggleButtonGroup.Button>
|
|
282
|
-
<ToggleButtonGroup.Button id="right">
|
|
283
|
-
<DemoIcon />
|
|
284
|
-
</ToggleButtonGroup.Button>
|
|
285
|
-
</ToggleButtonGroup.Root>
|
|
286
|
-
))}
|
|
287
|
-
</Stack>
|
|
288
|
-
),
|
|
289
|
-
args: {
|
|
290
|
-
size: "md",
|
|
291
|
-
onSelectionChange: fn(),
|
|
292
|
-
},
|
|
293
|
-
play: async ({ canvasElement, step }) => {
|
|
294
|
-
const canvas = within(canvasElement);
|
|
295
|
-
// Ensure all groups render
|
|
296
|
-
await step("Render groups for each tone", async () => {
|
|
297
|
-
const groups = canvas.getAllByRole("radiogroup");
|
|
298
|
-
await expect(groups).toHaveLength(tones.length);
|
|
299
|
-
// Optionally check a button exists in each
|
|
300
|
-
await expect(
|
|
301
|
-
within(groups[0]).getAllByRole("radio").length
|
|
302
|
-
).toBeGreaterThan(0);
|
|
303
|
-
await expect(
|
|
304
|
-
within(groups[1]).getAllByRole("radio").length
|
|
305
|
-
).toBeGreaterThan(0);
|
|
306
|
-
await expect(
|
|
307
|
-
within(groups[2]).getAllByRole("radio").length
|
|
308
|
-
).toBeGreaterThan(0);
|
|
309
|
-
});
|
|
310
|
-
},
|
|
311
|
-
};
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { ToggleButtonGroupRoot } from "./components/toggle-button-group.root";
|
|
2
|
-
import { ToggleButtonGroupButton } from "./components/toggle-button-group.button";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* ToggleButtonGroup
|
|
6
|
-
* ============================================================
|
|
7
|
-
* To group multiple `Button` components together, visually and logically, representing a set of related actions.
|
|
8
|
-
*/
|
|
9
|
-
export const ToggleButtonGroup = {
|
|
10
|
-
Root: ToggleButtonGroupRoot,
|
|
11
|
-
Button: ToggleButtonGroupButton,
|
|
12
|
-
};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
HTMLChakraProps,
|
|
3
|
-
RecipeProps,
|
|
4
|
-
RecipeVariantProps,
|
|
5
|
-
} from "@chakra-ui/react";
|
|
6
|
-
import { buttonGroupRecipe } from "./toggle-button-group.recipe";
|
|
7
|
-
import type {
|
|
8
|
-
AriaToggleButtonGroupProps,
|
|
9
|
-
AriaToggleButtonProps,
|
|
10
|
-
} from "react-aria";
|
|
11
|
-
import {
|
|
12
|
-
ToggleButton as RacToggleButton,
|
|
13
|
-
ToggleButtonGroup as RacToggleButtonGroup,
|
|
14
|
-
} from "react-aria-components";
|
|
15
|
-
import type {
|
|
16
|
-
ForwardRefExoticComponent,
|
|
17
|
-
PropsWithChildren,
|
|
18
|
-
RefAttributes,
|
|
19
|
-
} from "react";
|
|
20
|
-
|
|
21
|
-
// ============================================================
|
|
22
|
-
// Root Component (`<ToggleButtonGroup>`)
|
|
23
|
-
// ============================================================
|
|
24
|
-
|
|
25
|
-
/** Base Chakra styling props for the root `div` slot. */
|
|
26
|
-
type ToggleButtonGroupRootSlotProps = HTMLChakraProps<
|
|
27
|
-
"div",
|
|
28
|
-
RecipeProps<"div">
|
|
29
|
-
>;
|
|
30
|
-
|
|
31
|
-
/** Combined props for the root element (Chakra styles + Aria behavior + Recipe variants). */
|
|
32
|
-
type ToggleButtonGroupRootProps = ToggleButtonGroupRootSlotProps &
|
|
33
|
-
AriaToggleButtonGroupProps &
|
|
34
|
-
RecipeVariantProps<typeof buttonGroupRecipe>;
|
|
35
|
-
|
|
36
|
-
/** Final external props for the `<ToggleButtonGroup>` component, including `children`. */
|
|
37
|
-
export type ToggleButtonGroupProps =
|
|
38
|
-
PropsWithChildren<ToggleButtonGroupRootProps>;
|
|
39
|
-
|
|
40
|
-
/** Type signature for the main `ToggleButtonGroup` component (using `forwardRef`). */
|
|
41
|
-
export type ToggleButtonGroupRootComponent = ForwardRefExoticComponent<
|
|
42
|
-
ToggleButtonGroupProps & RefAttributes<typeof RacToggleButtonGroup>
|
|
43
|
-
>;
|
|
44
|
-
|
|
45
|
-
// ============================================================
|
|
46
|
-
// Button Sub-Component (`<ToggleButtonGroup.Button>`)
|
|
47
|
-
// ============================================================
|
|
48
|
-
|
|
49
|
-
/** Base Chakra styling props for the `button` slot. */
|
|
50
|
-
type ToggleButtonGroupButtonSlotProps = HTMLChakraProps<
|
|
51
|
-
"button",
|
|
52
|
-
RecipeProps<"button">
|
|
53
|
-
>;
|
|
54
|
-
|
|
55
|
-
/** Combined props for the button element (Chakra styles + Aria behavior). */
|
|
56
|
-
export type ToggleButtonGroupButtonProps = ToggleButtonGroupButtonSlotProps &
|
|
57
|
-
AriaToggleButtonProps;
|
|
58
|
-
|
|
59
|
-
/** Type signature for the `ToggleButtonGroup.Button` sub-component (using `forwardRef`). */
|
|
60
|
-
export type ToggleButtonGroupButtonComponent = ForwardRefExoticComponent<
|
|
61
|
-
ToggleButtonGroupButtonProps & RefAttributes<typeof RacToggleButton>
|
|
62
|
-
>;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { createRef } from "react";
|
|
2
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
-
import { within, expect } from "@storybook/test";
|
|
4
|
-
import { Tooltip, TooltipTrigger, MakeElementFocusable } from "@/components";
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof MakeElementFocusable> = {
|
|
7
|
-
title: "components/Tooltip/MakeElementFocusable",
|
|
8
|
-
component: MakeElementFocusable,
|
|
9
|
-
render: (args) => (
|
|
10
|
-
<TooltipTrigger delay={0} closeDelay={0}>
|
|
11
|
-
<MakeElementFocusable {...args} />
|
|
12
|
-
<Tooltip>Demo Tooltip</Tooltip>
|
|
13
|
-
</TooltipTrigger>
|
|
14
|
-
),
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default meta;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Story type for TypeScript support
|
|
21
|
-
* StoryObj provides type checking for our story configurations
|
|
22
|
-
*/
|
|
23
|
-
//TODO: figure out props table for this component
|
|
24
|
-
type Story = StoryObj<typeof MakeElementFocusable>;
|
|
25
|
-
|
|
26
|
-
// TODO: how much do we want to test react-aria-components?
|
|
27
|
-
const elementRef = createRef<HTMLElement>();
|
|
28
|
-
export const Base: Story = {
|
|
29
|
-
args: {
|
|
30
|
-
children: <button>custom button</button>,
|
|
31
|
-
ref: elementRef,
|
|
32
|
-
},
|
|
33
|
-
play: async ({ canvasElement, step }) => {
|
|
34
|
-
// need to get the parent node in order to have the tooltip portal in scope
|
|
35
|
-
const canvas = within(
|
|
36
|
-
(canvasElement.parentNode as HTMLElement) ?? canvasElement
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
await step(
|
|
40
|
-
"it renders a tooltip with the proper text when child is custom component",
|
|
41
|
-
async () => {
|
|
42
|
-
const button = canvas.getByRole("button", { name: "custom button" });
|
|
43
|
-
button.click();
|
|
44
|
-
button.focus();
|
|
45
|
-
await canvas.findByRole("tooltip", {
|
|
46
|
-
name: "Demo Tooltip",
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
await step("it forwards a ref to the custom element", async () => {
|
|
51
|
-
const button = canvas.getByRole("button", { name: "custom button" });
|
|
52
|
-
|
|
53
|
-
await expect(elementRef.current).toBe(button);
|
|
54
|
-
});
|
|
55
|
-
},
|
|
56
|
-
};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
cloneElement,
|
|
3
|
-
forwardRef,
|
|
4
|
-
useRef,
|
|
5
|
-
type PropsWithChildren,
|
|
6
|
-
isValidElement,
|
|
7
|
-
} from "react";
|
|
8
|
-
import {
|
|
9
|
-
mergeProps,
|
|
10
|
-
useObjectRef,
|
|
11
|
-
useFocusable,
|
|
12
|
-
type FocusableOptions,
|
|
13
|
-
} from "react-aria";
|
|
14
|
-
|
|
15
|
-
import { mergeRefs } from "@chakra-ui/react";
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* MakeElementFocusable
|
|
19
|
-
* ============================================================
|
|
20
|
-
* A helper component that adds props from `react-aria`s `useFocusable` hook
|
|
21
|
-
* to its child so that it can be used as a trigger element for a `Tooltip`
|
|
22
|
-
*
|
|
23
|
-
* Caveats:
|
|
24
|
-
* - Using non-interactive elements as tooltip triggers is against ARIA best-practices,
|
|
25
|
-
* it is your responsibility to ensure that the underlying trigger element handles
|
|
26
|
-
* focus and hover interactions correctly for keyboard-only users
|
|
27
|
-
*
|
|
28
|
-
* Features:
|
|
29
|
-
* - allows forwarding refs to the underlying DOM element
|
|
30
|
-
* - accepts all native html 'HTMLElement' attributes (including aria- & data-attributes)
|
|
31
|
-
*
|
|
32
|
-
* Further Context:
|
|
33
|
-
* - [React Aria Components Tooltip Documentation](https://react-spectrum.adobe.com/react-aria/Tooltip.html)
|
|
34
|
-
* - [React Aria Components Issue re:Tooltip with custom trigger](https://github.com/adobe/react-spectrum/issues/5733#issuecomment-1918691983)
|
|
35
|
-
* - [ARIA Tooltip Pattern](https://www.w3.org/TR/wai-aria-1.2/#tooltip)
|
|
36
|
-
*/
|
|
37
|
-
export const MakeElementFocusable = forwardRef<
|
|
38
|
-
HTMLElement,
|
|
39
|
-
PropsWithChildren<FocusableOptions<HTMLElement>>
|
|
40
|
-
>(function MakeElementFocusable(props, forwardedRef) {
|
|
41
|
-
const localRef = useRef<HTMLElement>(null);
|
|
42
|
-
const ref = useObjectRef(mergeRefs(localRef, forwardedRef));
|
|
43
|
-
const { focusableProps } = useFocusable(props, ref);
|
|
44
|
-
if (isValidElement(props.children)) {
|
|
45
|
-
return cloneElement(
|
|
46
|
-
props.children,
|
|
47
|
-
mergeProps(
|
|
48
|
-
focusableProps,
|
|
49
|
-
props.children.props as PropsWithChildren<
|
|
50
|
-
FocusableOptions<HTMLElement>
|
|
51
|
-
>,
|
|
52
|
-
{ ref: ref }
|
|
53
|
-
)
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
MakeElementFocusable.displayName = "MakeElementFocusable";
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
-
import { within, expect, fn } from "@storybook/test";
|
|
3
|
-
import { Tooltip, TooltipTrigger, Button } from "@/components";
|
|
4
|
-
|
|
5
|
-
const meta: Meta<typeof TooltipTrigger> = {
|
|
6
|
-
title: "components/tooltip/TooltipTrigger",
|
|
7
|
-
component: TooltipTrigger,
|
|
8
|
-
render: (args) => (
|
|
9
|
-
<TooltipTrigger {...args}>
|
|
10
|
-
<Button>hover/focus me</Button>
|
|
11
|
-
<Tooltip>Demo Tooltip</Tooltip>
|
|
12
|
-
</TooltipTrigger>
|
|
13
|
-
),
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export default meta;
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Story type for TypeScript support
|
|
20
|
-
* StoryObj provides type checking for our story configurations
|
|
21
|
-
*/
|
|
22
|
-
//TODO: each component is in its own file so that the props table gets built for it,
|
|
23
|
-
// is there a better way for declaring compound components such as this one?
|
|
24
|
-
type Story = StoryObj<typeof TooltipTrigger>;
|
|
25
|
-
|
|
26
|
-
// TODO: how much do we want to test react-aria-components?
|
|
27
|
-
export const Base: Story = {
|
|
28
|
-
args: {},
|
|
29
|
-
play: async ({ canvasElement, step }) => {
|
|
30
|
-
// need to get the parent node in order to have the tooltip portal in scope
|
|
31
|
-
const canvas = within(
|
|
32
|
-
(canvasElement.parentNode as HTMLElement) ?? canvasElement
|
|
33
|
-
);
|
|
34
|
-
await step("it renders a tooltip with the proper text", async () => {
|
|
35
|
-
const button = canvas.getByRole("button", { name: "hover/focus me" });
|
|
36
|
-
button.click();
|
|
37
|
-
button.focus();
|
|
38
|
-
await canvas.findByRole("tooltip", {
|
|
39
|
-
name: "Demo Tooltip",
|
|
40
|
-
});
|
|
41
|
-
});
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export const Delay: Story = {
|
|
46
|
-
args: {
|
|
47
|
-
delay: 0,
|
|
48
|
-
},
|
|
49
|
-
play: async ({ canvasElement, step }) => {
|
|
50
|
-
// need to get the parent node in order to have the tooltip portal in scope
|
|
51
|
-
const canvas = within(
|
|
52
|
-
(canvasElement.parentNode as HTMLElement) ?? canvasElement
|
|
53
|
-
);
|
|
54
|
-
await step("it renders a tooltip immediately when delay is 0", async () => {
|
|
55
|
-
const button = canvas.getByRole("button", { name: "hover/focus me" });
|
|
56
|
-
button.click();
|
|
57
|
-
button.focus();
|
|
58
|
-
await canvas.findByRole("tooltip", {
|
|
59
|
-
name: "Demo Tooltip",
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
},
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const isOpen: Story = {
|
|
66
|
-
args: {
|
|
67
|
-
isOpen: true,
|
|
68
|
-
},
|
|
69
|
-
play: async ({ canvasElement, step }) => {
|
|
70
|
-
// need to get the parent node in order to have the tooltip portal in scope
|
|
71
|
-
const canvas = within(
|
|
72
|
-
(canvasElement.parentNode as HTMLElement) ?? canvasElement
|
|
73
|
-
);
|
|
74
|
-
await step("it renders tooltip on mount when isOpen is true", async () => {
|
|
75
|
-
await canvas.findByRole("tooltip", {
|
|
76
|
-
name: "Demo Tooltip",
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
await step(
|
|
80
|
-
"it does not hide tooltip on blur when isOpen is true",
|
|
81
|
-
async () => {
|
|
82
|
-
await canvas.findByRole("tooltip", {
|
|
83
|
-
name: "Demo Tooltip",
|
|
84
|
-
});
|
|
85
|
-
const button = canvas.getByRole("button", { name: "hover/focus me" });
|
|
86
|
-
button.click();
|
|
87
|
-
button.focus();
|
|
88
|
-
button.blur();
|
|
89
|
-
await canvas.findByRole("tooltip", {
|
|
90
|
-
name: "Demo Tooltip",
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
);
|
|
94
|
-
},
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
export const defaultOpen: Story = {
|
|
98
|
-
args: {
|
|
99
|
-
defaultOpen: true,
|
|
100
|
-
},
|
|
101
|
-
play: async ({ canvasElement, step }) => {
|
|
102
|
-
// need to get the parent node in order to have the tooltip portal in scope
|
|
103
|
-
const canvas = within(
|
|
104
|
-
(canvasElement.parentNode as HTMLElement) ?? canvasElement
|
|
105
|
-
);
|
|
106
|
-
await step(
|
|
107
|
-
"it renders tooltip on mount when defaultOpen is true",
|
|
108
|
-
async () => {
|
|
109
|
-
await canvas.findByRole("tooltip", {
|
|
110
|
-
name: "Demo Tooltip",
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
);
|
|
114
|
-
await step(
|
|
115
|
-
"it does not hide tooltip on blur when isOpen is true",
|
|
116
|
-
async () => {
|
|
117
|
-
await canvas.findByRole("tooltip", {
|
|
118
|
-
name: "Demo Tooltip",
|
|
119
|
-
});
|
|
120
|
-
const button = canvas.getByRole("button", { name: "hover/focus me" });
|
|
121
|
-
button.click();
|
|
122
|
-
button.focus();
|
|
123
|
-
button.blur();
|
|
124
|
-
await new Promise((resolve) => setTimeout(resolve, 1));
|
|
125
|
-
await expect(
|
|
126
|
-
canvas.queryByRole("tooltip", {
|
|
127
|
-
name: "Demo Tooltip",
|
|
128
|
-
})
|
|
129
|
-
).not.toBeInTheDocument();
|
|
130
|
-
}
|
|
131
|
-
);
|
|
132
|
-
},
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
export const onOpenChange: Story = {
|
|
136
|
-
args: {
|
|
137
|
-
onOpenChange: fn(),
|
|
138
|
-
},
|
|
139
|
-
play: async ({ canvasElement, args, step }) => {
|
|
140
|
-
// need to get the parent node in order to have the tooltip portal in scope
|
|
141
|
-
const canvas = within(
|
|
142
|
-
(canvasElement.parentNode as HTMLElement) ?? canvasElement
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
await step(
|
|
146
|
-
"it should call onOpenChange when entering and exiting",
|
|
147
|
-
async () => {
|
|
148
|
-
const button = canvas.getByRole("button", { name: "hover/focus me" });
|
|
149
|
-
button.click();
|
|
150
|
-
button.focus();
|
|
151
|
-
await expect(args.onOpenChange).toHaveBeenCalledTimes(1);
|
|
152
|
-
button.blur();
|
|
153
|
-
await expect(args.onOpenChange).toHaveBeenCalledTimes(2);
|
|
154
|
-
}
|
|
155
|
-
);
|
|
156
|
-
},
|
|
157
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { TooltipTrigger as RATooltipTrigger } from "react-aria-components";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* TooltipTrigger
|
|
5
|
-
* ============================================================
|
|
6
|
-
* TooltipTrigger wraps around a trigger element and a Tooltip.
|
|
7
|
-
* It handles opening and closing the Tooltip when the user hovers over or focuses the trigger,
|
|
8
|
-
* and positioning the Tooltip relative to the trigger.
|
|
9
|
-
*
|
|
10
|
-
* Directly exported from `react-aria-components`
|
|
11
|
-
* - [React Aria Components Tooltip Documentation](https://react-spectrum.adobe.com/react-aria/Tooltip.html)
|
|
12
|
-
*/
|
|
13
|
-
export const TooltipTrigger = RATooltipTrigger;
|
|
14
|
-
// @ts-expect-error displaynames can be set on component instances, necessary for pretty react-live output
|
|
15
|
-
TooltipTrigger.displayName = "TooltipTrigger";
|