@12-apps/ui 1.4.1 → 1.5.1
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/package.json +17 -8
- package/src/button/index.ts +1 -0
- package/src/social-login-button/index.ts +1 -0
- package/src/{social-login-button.tsx → social-login-button/social-login-button.tsx} +5 -5
- package/src/user-avatar/index.ts +1 -0
- package/src/{user-avatar.tsx → user-avatar/user-avatar.tsx} +4 -4
- package/eslint.config.js +0 -77
- package/src/__tests__/data-grid.test.tsx +0 -125
- package/src/__tests__/package-wiring.test.ts +0 -41
- package/src/__tests__/setup.ts +0 -1
- package/src/__tests__/social-login-button.test.tsx +0 -186
- package/src/__tests__/user-avatar.test.tsx +0 -195
- package/src/__tests__/viewport.test.ts +0 -50
- package/src/components/command/__tests__/command.test.tsx +0 -112
- package/src/components/data-display/Alert/Alert.stories.tsx +0 -559
- package/src/components/data-display/Alert/Alert.test.stories.tsx +0 -707
- package/src/components/data-display/AlertDialog/AlertDialog.stories.tsx +0 -362
- package/src/components/data-display/AlertDialog/AlertDialog.test.stories.tsx +0 -753
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.stories.tsx +0 -230
- package/src/components/data-display/AsyncStateContainer/AsyncStateContainer.test.stories.tsx +0 -270
- package/src/components/data-display/Avatar/Avatar.stories.tsx +0 -721
- package/src/components/data-display/Avatar/Avatar.test.stories.tsx +0 -822
- package/src/components/data-display/Badge/Badge.stories.tsx +0 -1134
- package/src/components/data-display/Badge/Badge.test.stories.tsx +0 -1194
- package/src/components/data-display/Banner/Banner.stories.tsx +0 -528
- package/src/components/data-display/Banner/Banner.test.stories.tsx +0 -503
- package/src/components/data-display/Carousel/Carousel.stories.tsx +0 -607
- package/src/components/data-display/Carousel/Carousel.test.stories.tsx +0 -691
- package/src/components/data-display/Chart/Chart.stories.tsx +0 -568
- package/src/components/data-display/Chart/Chart.test.stories.tsx +0 -174
- package/src/components/data-display/Chart/SpecChart.stories.tsx +0 -150
- package/src/components/data-display/Chart/SpecChart.test.stories.tsx +0 -56
- package/src/components/data-display/Chart/__tests__/SpecChart.test.tsx +0 -60
- package/src/components/data-display/Chart/__tests__/chart-format.test.ts +0 -43
- package/src/components/data-display/Chart/__tests__/chart-spec.test.ts +0 -119
- package/src/components/data-display/Chip/Chip.stories.tsx +0 -252
- package/src/components/data-display/Chip/Chip.test.stories.tsx +0 -266
- package/src/components/data-display/DataGrid/DataGrid.stories.tsx +0 -515
- package/src/components/data-display/DataGrid/DataGrid.test.stories.tsx +0 -653
- package/src/components/data-display/DataViews/__tests__/DataViewsGrid.test.tsx +0 -271
- package/src/components/data-display/DataViews/__tests__/DataViewsTableBase.test.tsx +0 -134
- package/src/components/data-display/DataViews/__tests__/SaveViewModal.test.tsx +0 -83
- package/src/components/data-display/DataViews/__tests__/data-views-filter.test.ts +0 -115
- package/src/components/data-display/DataViews/__tests__/data-views-preview.test.ts +0 -53
- package/src/components/data-display/DataViews/__tests__/range-pill.test.tsx +0 -114
- package/src/components/data-display/DataViews/base-card.stories.tsx +0 -136
- package/src/components/data-display/DescriptionItem/DescriptionItem.stories.tsx +0 -254
- package/src/components/data-display/EmptyState/EmptyState.stories.tsx +0 -282
- package/src/components/data-display/EmptyState/EmptyState.test.stories.tsx +0 -441
- package/src/components/data-display/ErrorState/ErrorState.stories.tsx +0 -110
- package/src/components/data-display/ErrorState/ErrorState.test.stories.tsx +0 -133
- package/src/components/data-display/HoverCard/HoverCard.stories.tsx +0 -650
- package/src/components/data-display/HoverCard/HoverCard.test.stories.tsx +0 -929
- package/src/components/data-display/InteractiveTooltip/InteractiveTooltip.stories.tsx +0 -411
- package/src/components/data-display/LazyImage/LazyImage.stories.tsx +0 -387
- package/src/components/data-display/Lightbox/Lightbox.stories.tsx +0 -315
- package/src/components/data-display/Lightbox/Lightbox.test.stories.tsx +0 -598
- package/src/components/data-display/LoadingState/LoadingState.stories.tsx +0 -124
- package/src/components/data-display/LoadingState/LoadingState.test.stories.tsx +0 -99
- package/src/components/data-display/MapPreview/MapPreview.stories.tsx +0 -458
- package/src/components/data-display/MapPreview/MapPreview.test.stories.tsx +0 -394
- package/src/components/data-display/Popover/Popover.stories.tsx +0 -295
- package/src/components/data-display/Popover/Popover.test.stories.tsx +0 -1162
- package/src/components/data-display/Progress/Progress.stories.tsx +0 -481
- package/src/components/data-display/Progress/Progress.test.stories.tsx +0 -2070
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.stories.tsx +0 -160
- package/src/components/data-display/SectionOnboarding/SectionOnboarding.test.stories.tsx +0 -190
- package/src/components/data-display/Sheet/Sheet.stories.tsx +0 -883
- package/src/components/data-display/Sheet/Sheet.test.stories.tsx +0 -1101
- package/src/components/data-display/StatCard/StatCard.stories.tsx +0 -167
- package/src/components/data-display/StatCard/StatCard.test.stories.tsx +0 -240
- package/src/components/data-display/Stepper/Stepper.stories.tsx +0 -540
- package/src/components/data-display/Stepper/Stepper.test.stories.tsx +0 -600
- package/src/components/data-display/Table/Table.stories.tsx +0 -803
- package/src/components/data-display/Table/Table.test.stories.tsx +0 -369
- package/src/components/data-display/Timeline/Timeline.stories.tsx +0 -442
- package/src/components/data-display/Timeline/Timeline.test.stories.tsx +0 -930
- package/src/components/data-display/TimingDiagram/TimingDiagram.stories.tsx +0 -475
- package/src/components/data-display/TimingDiagram/TimingDiagram.test.stories.tsx +0 -734
- package/src/components/data-display/Tooltip/Tooltip.stories.tsx +0 -468
- package/src/components/data-display/Tooltip/Tooltip.test.stories.tsx +0 -1154
- package/src/components/feedback/ConfirmAction/ConfirmAction.stories.tsx +0 -146
- package/src/components/feedback/ConfirmAction/ConfirmAction.test.stories.tsx +0 -114
- package/src/components/feedback/ConfirmAction/__tests__/confirm-action.test.tsx +0 -288
- package/src/components/feedback/Dialog/Dialog.stories.tsx +0 -833
- package/src/components/feedback/Dialog/Dialog.test.stories.tsx +0 -955
- package/src/components/feedback/Dialog/__tests__/dialog-content-spacing.test.tsx +0 -66
- package/src/components/feedback/Modal/Modal.stories.tsx +0 -765
- package/src/components/feedback/Modal/Modal.test.stories.tsx +0 -251
- package/src/components/feedback/Sonner/Sonner.stories.tsx +0 -698
- package/src/components/feedback/Sonner/Sonner.test.stories.tsx +0 -896
- package/src/components/feedback/StackedModal/StackedModal.stories.tsx +0 -1783
- package/src/components/feedback/StackedModal/StackedModal.test.stories.tsx +0 -975
- package/src/components/feedback/StackedModal/__tests__/stacked-modal-viewport.test.tsx +0 -104
- package/src/components/feedback/Toast/Toast.stories.tsx +0 -548
- package/src/components/feedback/Toast/Toast.test.stories.tsx +0 -834
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.stories.tsx +0 -691
- package/src/components/feedback/TutorialOverlay/TutorialOverlay.test.stories.tsx +0 -634
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.stories.tsx +0 -665
- package/src/components/form/AddressAutocomplete/AddressAutocomplete.test.stories.tsx +0 -727
- package/src/components/form/Autocomplete/Autocomplete.stories.tsx +0 -715
- package/src/components/form/Autocomplete/Autocomplete.test.stories.tsx +0 -825
- package/src/components/form/Button/Button.stories.tsx +0 -365
- package/src/components/form/Button/Button.test.stories.tsx +0 -607
- package/src/components/form/Calendar/Calendar.stories.tsx +0 -349
- package/src/components/form/Calendar/Calendar.test.stories.tsx +0 -464
- package/src/components/form/CepField/CepField.stories.tsx +0 -138
- package/src/components/form/CepField/CepField.test.stories.tsx +0 -281
- package/src/components/form/Checkbox/Checkbox.stories.tsx +0 -265
- package/src/components/form/Checkbox/Checkbox.test.stories.tsx +0 -181
- package/src/components/form/CodeEditor/CodeEditor.stories.tsx +0 -871
- package/src/components/form/CodeEditor/CodeEditor.test.stories.tsx +0 -574
- package/src/components/form/Command/Command.stories.tsx +0 -580
- package/src/components/form/Command/Command.test.stories.tsx +0 -215
- package/src/components/form/CreatableSelect/CreatableSelect.stories.tsx +0 -112
- package/src/components/form/CreatableSelect/CreatableSelect.test.stories.tsx +0 -134
- package/src/components/form/Form/Form.stories.tsx +0 -687
- package/src/components/form/Form/Form.test.stories.tsx +0 -601
- package/src/components/form/Input/Input.stories.tsx +0 -260
- package/src/components/form/Input/Input.test.stories.tsx +0 -1191
- package/src/components/form/InputOTP/InputOTP.stories.tsx +0 -774
- package/src/components/form/InputOTP/InputOTP.test.stories.tsx +0 -588
- package/src/components/form/Label/Label.stories.tsx +0 -473
- package/src/components/form/Label/Label.test.stories.tsx +0 -909
- package/src/components/form/Menubar/Menubar.stories.tsx +0 -472
- package/src/components/form/Menubar/Menubar.test.stories.tsx +0 -584
- package/src/components/form/PasswordStrength/PasswordStrength.stories.tsx +0 -562
- package/src/components/form/PasswordStrength/PasswordStrength.test.stories.tsx +0 -327
- package/src/components/form/PhoneInput/PhoneInput.stories.tsx +0 -495
- package/src/components/form/PhoneInput/PhoneInput.test.stories.tsx +0 -666
- package/src/components/form/RadioGroup/RadioGroup.stories.tsx +0 -518
- package/src/components/form/RadioGroup/RadioGroup.test.stories.tsx +0 -685
- package/src/components/form/RichTextEditor/RichTextEditor.stories.tsx +0 -261
- package/src/components/form/RichTextEditor/RichTextEditor.test.stories.tsx +0 -491
- package/src/components/form/SearchPalette/SearchPalette.stories.tsx +0 -135
- package/src/components/form/Select/Select.stories.tsx +0 -364
- package/src/components/form/Select/Select.test.stories.tsx +0 -985
- package/src/components/form/Slider/Slider.stories.tsx +0 -418
- package/src/components/form/Slider/Slider.test.stories.tsx +0 -1042
- package/src/components/form/Switch/Switch.stories.tsx +0 -697
- package/src/components/form/Switch/Switch.test.stories.tsx +0 -597
- package/src/components/form/Textarea/Textarea.stories.tsx +0 -473
- package/src/components/form/Textarea/Textarea.test.stories.tsx +0 -702
- package/src/components/form/Toggle/Toggle.stories.tsx +0 -638
- package/src/components/form/Toggle/Toggle.test.stories.tsx +0 -1159
- package/src/components/form/ToggleGroup/ToggleGroup.stories.tsx +0 -617
- package/src/components/form/ToggleGroup/ToggleGroup.test.stories.tsx +0 -918
- package/src/components/form/UploadButton/UploadButton.stories.tsx +0 -367
- package/src/components/form/UploadButton/UploadButton.test.stories.tsx +0 -573
- package/src/components/form/total-form/total-form.test.tsx +0 -214
- package/src/components/layout/Accordion/Accordion.stories.tsx +0 -694
- package/src/components/layout/Accordion/Accordion.test.stories.tsx +0 -1344
- package/src/components/layout/Card/Card.stories.tsx +0 -591
- package/src/components/layout/Card/Card.test.stories.tsx +0 -1134
- package/src/components/layout/CardGrid/__tests__/CardGrid.test.tsx +0 -92
- package/src/components/layout/Collapsible/Collapsible.stories.tsx +0 -180
- package/src/components/layout/Collapsible/Collapsible.test.stories.tsx +0 -308
- package/src/components/layout/Container/Container.stories.tsx +0 -557
- package/src/components/layout/Container/Container.test.stories.tsx +0 -745
- package/src/components/layout/ContentToolbar/ContentToolbar.stories.tsx +0 -129
- package/src/components/layout/ContentToolbar/ContentToolbar.test.stories.tsx +0 -251
- package/src/components/layout/ContentToolbar/__tests__/ColumnsMenu.test.tsx +0 -39
- package/src/components/layout/ContentToolbar/__tests__/MultiSelectDropdown.test.tsx +0 -131
- package/src/components/layout/ContentToolbar/__tests__/SavedViewsMenu.test.tsx +0 -99
- package/src/components/layout/Dashboard/Dashboard.stories.tsx +0 -104
- package/src/components/layout/Dashboard/Dashboard.test.stories.tsx +0 -190
- package/src/components/layout/Drawer/Drawer.stories.tsx +0 -658
- package/src/components/layout/Drawer/Drawer.test.stories.tsx +0 -1343
- package/src/components/layout/Resizable/Resizable.stories.tsx +0 -1039
- package/src/components/layout/Resizable/Resizable.test.stories.tsx +0 -750
- package/src/components/layout/ScrollArea/ScrollArea.stories.tsx +0 -651
- package/src/components/layout/ScrollArea/ScrollArea.test.stories.tsx +0 -619
- package/src/components/layout/Separator/Separator.stories.tsx +0 -563
- package/src/components/layout/Separator/Separator.test.stories.tsx +0 -518
- package/src/components/layout/SettingsLayout/SettingsLayout.stories.tsx +0 -192
- package/src/components/layout/SettingsLayout/SettingsLayout.test.stories.tsx +0 -175
- package/src/components/layout/Sidebar/Sidebar.stories.tsx +0 -609
- package/src/components/layout/Sidebar/Sidebar.test.stories.tsx +0 -1324
- package/src/components/layout/Skeleton/Skeleton.stories.tsx +0 -689
- package/src/components/layout/Skeleton/Skeleton.test.stories.tsx +0 -521
- package/src/components/layout/Spacer/Spacer.stories.tsx +0 -502
- package/src/components/layout/Spacer/Spacer.test.stories.tsx +0 -472
- package/src/components/layout/TableFilter/TableFilter.stories.tsx +0 -82
- package/src/components/layout/TableFilter/TableFilter.test.stories.tsx +0 -87
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.stories.tsx +0 -638
- package/src/components/navigation/Breadcrumbs/Breadcrumbs.test.stories.tsx +0 -1008
- package/src/components/navigation/CommandPalette/CommandPalette.stories.tsx +0 -386
- package/src/components/navigation/CommandPalette/CommandPalette.test.stories.tsx +0 -435
- package/src/components/navigation/ContextMenu/ContextMenu.stories.tsx +0 -614
- package/src/components/navigation/ContextMenu/ContextMenu.test.stories.tsx +0 -845
- package/src/components/navigation/DropdownMenu/DropdownMenu.stories.tsx +0 -578
- package/src/components/navigation/DropdownMenu/DropdownMenu.test.stories.tsx +0 -660
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.stories.tsx +0 -516
- package/src/components/navigation/NavigationMenu/stories/NavigationMenu.test.stories.tsx +0 -935
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuHorizontal.stories.tsx +0 -501
- package/src/components/navigation/NavigationMenu/stories/NavigationMenuVertical.stories.tsx +0 -453
- package/src/components/navigation/Pagination/Pagination.stories.tsx +0 -602
- package/src/components/navigation/Pagination/Pagination.test.stories.tsx +0 -520
- package/src/components/navigation/Tabs/Tabs.stories.tsx +0 -1004
- package/src/components/navigation/Tabs/Tabs.test.stories.tsx +0 -1225
- package/src/components/typography/Blockquote/Blockquote.stories.tsx +0 -359
- package/src/components/typography/Blockquote/Blockquote.test.stories.tsx +0 -432
- package/src/components/typography/Code/Code.stories.tsx +0 -686
- package/src/components/typography/Code/Code.test.stories.tsx +0 -703
- package/src/components/typography/Heading/Heading.stories.tsx +0 -451
- package/src/components/typography/Heading/Heading.test.stories.tsx +0 -830
- package/src/components/typography/Paragraph/Paragraph.stories.tsx +0 -280
- package/src/components/typography/Paragraph/Paragraph.test.stories.tsx +0 -231
- package/src/components/typography/Text/Text.stories.tsx +0 -359
- package/src/components/typography/Text/Text.test.stories.tsx +0 -762
- package/src/components/utility/AnimatedIcon/AnimatedIcon.stories.tsx +0 -945
- package/src/components/utility/AnimatedIcon/AnimatedIcon.test.stories.tsx +0 -603
- package/src/components/utility/AspectRatio/AspectRatio.stories.tsx +0 -414
- package/src/components/utility/AspectRatio/AspectRatio.test.stories.tsx +0 -859
- package/src/components/utility/InfiniteScroll/InfiniteScroll.stories.tsx +0 -620
- package/src/components/utility/InfiniteScroll/InfiniteScroll.test.stories.tsx +0 -361
- package/src/components/utility/InstallPrompt/InstallPrompt.stories.tsx +0 -118
- package/src/components/utility/InstallPrompt/InstallPrompt.test.stories.tsx +0 -83
- package/src/components/utility/InstallPrompt/__tests__/InstallPrompt.ios.test.tsx +0 -65
- package/src/components/utility/InstallPrompt/__tests__/usePwaInstall.test.tsx +0 -271
- package/src/components/utility/Portal/Portal.stories.tsx +0 -340
- package/src/components/utility/Portal/Portal.test.stories.tsx +0 -2086
- package/src/components/utility/Transition/Transition.stories.tsx +0 -493
- package/src/components/utility/Transition/Transition.test.stories.tsx +0 -854
- package/src/components/utility/VirtualList/VirtualList.stories.tsx +0 -1073
- package/src/components/utility/VirtualList/VirtualList.test.stories.tsx +0 -1085
- package/src/components/utility/WorkflowStep/WorkflowStep.stories.tsx +0 -431
- package/src/components/utility/WorkflowStep/WorkflowStep.test.stories.tsx +0 -364
- /package/src/{button.tsx → button/button.tsx} +0 -0
|
@@ -1,845 +0,0 @@
|
|
|
1
|
-
import Archive from '@mui/icons-material/Archive';
|
|
2
|
-
import ContentCopy from '@mui/icons-material/ContentCopy';
|
|
3
|
-
import ContentCut from '@mui/icons-material/ContentCut';
|
|
4
|
-
import ContentPaste from '@mui/icons-material/ContentPaste';
|
|
5
|
-
import Delete from '@mui/icons-material/Delete';
|
|
6
|
-
import Edit from '@mui/icons-material/Edit';
|
|
7
|
-
import Settings from '@mui/icons-material/Settings';
|
|
8
|
-
import Share from '@mui/icons-material/Share';
|
|
9
|
-
import Star from '@mui/icons-material/Star';
|
|
10
|
-
import { Box, Paper, Typography } from '@mui/material';
|
|
11
|
-
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
12
|
-
import { expect, fn,userEvent, waitFor, within } from 'storybook/test';
|
|
13
|
-
|
|
14
|
-
import { ContextMenu } from './ContextMenu';
|
|
15
|
-
import type { ContextMenuItem } from './ContextMenu.types';
|
|
16
|
-
|
|
17
|
-
const meta: Meta<typeof ContextMenu> = {
|
|
18
|
-
title: 'Navigation/ContextMenu/Tests',
|
|
19
|
-
component: ContextMenu,
|
|
20
|
-
parameters: {
|
|
21
|
-
layout: 'centered',
|
|
22
|
-
chromatic: { disableSnapshot: false },
|
|
23
|
-
},
|
|
24
|
-
tags: ['autodocs', 'test', 'component:ContextMenu'],
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export default meta;
|
|
28
|
-
type Story = StoryObj<typeof meta>;
|
|
29
|
-
|
|
30
|
-
// Test helper function to simulate right-click
|
|
31
|
-
const rightClick = async (element: HTMLElement) => {
|
|
32
|
-
// Simulate right-click more simply
|
|
33
|
-
await userEvent.pointer([
|
|
34
|
-
{ target: element, keys: '[MouseRight>]' },
|
|
35
|
-
{ target: element, keys: '[/MouseRight]' },
|
|
36
|
-
]);
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// Basic menu items for testing
|
|
40
|
-
const testMenuItems: ContextMenuItem[] = [
|
|
41
|
-
{
|
|
42
|
-
id: 'copy',
|
|
43
|
-
label: 'Copy',
|
|
44
|
-
icon: <ContentCopy />,
|
|
45
|
-
shortcut: 'Ctrl+C',
|
|
46
|
-
onClick: fn(),
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: 'paste',
|
|
50
|
-
label: 'Paste',
|
|
51
|
-
icon: <ContentPaste />,
|
|
52
|
-
shortcut: 'Ctrl+V',
|
|
53
|
-
onClick: fn(),
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
id: 'cut',
|
|
57
|
-
label: 'Cut',
|
|
58
|
-
icon: <ContentCut />,
|
|
59
|
-
shortcut: 'Ctrl+X',
|
|
60
|
-
onClick: fn(),
|
|
61
|
-
},
|
|
62
|
-
];
|
|
63
|
-
|
|
64
|
-
// Complex menu items for advanced testing
|
|
65
|
-
const complexMenuItems: ContextMenuItem[] = [
|
|
66
|
-
{
|
|
67
|
-
id: 'header1',
|
|
68
|
-
type: 'header',
|
|
69
|
-
label: 'File Actions',
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
id: 'edit',
|
|
73
|
-
label: 'Edit',
|
|
74
|
-
icon: <Edit />,
|
|
75
|
-
shortcut: 'F2',
|
|
76
|
-
color: 'primary',
|
|
77
|
-
onClick: fn(),
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
id: 'share',
|
|
81
|
-
label: 'Share',
|
|
82
|
-
icon: <Share />,
|
|
83
|
-
color: 'info',
|
|
84
|
-
onClick: fn(),
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
id: 'divider1',
|
|
88
|
-
type: 'divider',
|
|
89
|
-
label: '', // Required by interface but not used for dividers
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
id: 'header2',
|
|
93
|
-
type: 'header',
|
|
94
|
-
label: 'Danger Zone',
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
id: 'archive',
|
|
98
|
-
label: 'Archive',
|
|
99
|
-
icon: <Archive />,
|
|
100
|
-
color: 'warning',
|
|
101
|
-
onClick: fn(),
|
|
102
|
-
},
|
|
103
|
-
{
|
|
104
|
-
id: 'delete',
|
|
105
|
-
label: 'Delete',
|
|
106
|
-
icon: <Delete />,
|
|
107
|
-
dangerous: true,
|
|
108
|
-
onClick: fn(),
|
|
109
|
-
},
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
// Menu with disabled items
|
|
113
|
-
const mixedMenuItems: ContextMenuItem[] = [
|
|
114
|
-
{
|
|
115
|
-
id: 'enabled',
|
|
116
|
-
label: 'Enabled Item',
|
|
117
|
-
icon: <Star />,
|
|
118
|
-
onClick: fn(),
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
id: 'disabled',
|
|
122
|
-
label: 'Disabled Item',
|
|
123
|
-
icon: <Settings />,
|
|
124
|
-
disabled: true,
|
|
125
|
-
onClick: fn(),
|
|
126
|
-
},
|
|
127
|
-
];
|
|
128
|
-
|
|
129
|
-
export const BasicInteraction: Story = {
|
|
130
|
-
render: () => (
|
|
131
|
-
<Box
|
|
132
|
-
sx={{
|
|
133
|
-
width: 300,
|
|
134
|
-
height: 200,
|
|
135
|
-
display: 'flex',
|
|
136
|
-
alignItems: 'center',
|
|
137
|
-
justifyContent: 'center',
|
|
138
|
-
border: '2px dashed',
|
|
139
|
-
borderColor: 'divider',
|
|
140
|
-
borderRadius: 2,
|
|
141
|
-
backgroundColor: 'background.paper',
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
<ContextMenu items={testMenuItems}>
|
|
145
|
-
<Typography variant="body2" color="text.secondary" data-testid="context-trigger">
|
|
146
|
-
Right-click to test basic interaction
|
|
147
|
-
</Typography>
|
|
148
|
-
</ContextMenu>
|
|
149
|
-
</Box>
|
|
150
|
-
),
|
|
151
|
-
play: async ({ canvasElement }) => {
|
|
152
|
-
const canvas = within(canvasElement);
|
|
153
|
-
const trigger = canvas.getByTestId('context-trigger');
|
|
154
|
-
|
|
155
|
-
// Test right-click opens menu
|
|
156
|
-
await rightClick(trigger);
|
|
157
|
-
|
|
158
|
-
// Menu is in a portal, use document body
|
|
159
|
-
const body = within(document.body);
|
|
160
|
-
await waitFor(() => {
|
|
161
|
-
const menu = document.body.querySelector('[role="menu"]');
|
|
162
|
-
expect(menu).toBeInTheDocument();
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
// Test menu items are present
|
|
166
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
167
|
-
expect(body.getByText('Paste')).toBeInTheDocument();
|
|
168
|
-
expect(body.getByText('Cut')).toBeInTheDocument();
|
|
169
|
-
|
|
170
|
-
// Test menu item click
|
|
171
|
-
const copyItem = body.getByText('Copy');
|
|
172
|
-
await userEvent.click(copyItem);
|
|
173
|
-
|
|
174
|
-
// Verify onClick was called and menu closed
|
|
175
|
-
expect(testMenuItems[0].onClick).toHaveBeenCalled();
|
|
176
|
-
|
|
177
|
-
// Menu should be closed
|
|
178
|
-
await waitFor(() => {
|
|
179
|
-
expect(body.queryByText('Copy')).not.toBeInTheDocument();
|
|
180
|
-
});
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
export const KeyboardNavigation: Story = {
|
|
185
|
-
render: () => (
|
|
186
|
-
<Box
|
|
187
|
-
sx={{
|
|
188
|
-
width: 300,
|
|
189
|
-
height: 200,
|
|
190
|
-
display: 'flex',
|
|
191
|
-
alignItems: 'center',
|
|
192
|
-
justifyContent: 'center',
|
|
193
|
-
border: '2px solid',
|
|
194
|
-
borderColor: 'primary.main',
|
|
195
|
-
borderRadius: 2,
|
|
196
|
-
backgroundColor: 'background.paper',
|
|
197
|
-
}}
|
|
198
|
-
>
|
|
199
|
-
<ContextMenu items={testMenuItems}>
|
|
200
|
-
<Typography variant="body2" color="text.primary" data-testid="keyboard-trigger">
|
|
201
|
-
Keyboard navigation test
|
|
202
|
-
</Typography>
|
|
203
|
-
</ContextMenu>
|
|
204
|
-
</Box>
|
|
205
|
-
),
|
|
206
|
-
play: async ({ canvasElement }) => {
|
|
207
|
-
const canvas = within(canvasElement);
|
|
208
|
-
const trigger = canvas.getByTestId('keyboard-trigger');
|
|
209
|
-
|
|
210
|
-
// Open context menu
|
|
211
|
-
await rightClick(trigger);
|
|
212
|
-
|
|
213
|
-
// Menu is in a portal, use document body
|
|
214
|
-
const body = within(document.body);
|
|
215
|
-
await waitFor(() => {
|
|
216
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Test keyboard navigation
|
|
220
|
-
const menu = body.getByRole('menu');
|
|
221
|
-
expect(menu).toBeInTheDocument();
|
|
222
|
-
|
|
223
|
-
// Test Escape key closes menu
|
|
224
|
-
await userEvent.keyboard('{Escape}');
|
|
225
|
-
await waitFor(() => {
|
|
226
|
-
expect(body.queryByText('Copy')).not.toBeInTheDocument();
|
|
227
|
-
});
|
|
228
|
-
},
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
export const ScreenReader: Story = {
|
|
232
|
-
render: () => (
|
|
233
|
-
<Box
|
|
234
|
-
sx={{
|
|
235
|
-
width: 300,
|
|
236
|
-
height: 200,
|
|
237
|
-
display: 'flex',
|
|
238
|
-
alignItems: 'center',
|
|
239
|
-
justifyContent: 'center',
|
|
240
|
-
border: '2px solid',
|
|
241
|
-
borderColor: 'success.main',
|
|
242
|
-
borderRadius: 2,
|
|
243
|
-
backgroundColor: 'background.paper',
|
|
244
|
-
}}
|
|
245
|
-
>
|
|
246
|
-
<ContextMenu items={testMenuItems}>
|
|
247
|
-
<Typography variant="body2" color="text.primary" data-testid="screen-reader-trigger">
|
|
248
|
-
Screen reader accessibility test
|
|
249
|
-
</Typography>
|
|
250
|
-
</ContextMenu>
|
|
251
|
-
</Box>
|
|
252
|
-
),
|
|
253
|
-
play: async ({ canvasElement }) => {
|
|
254
|
-
const canvas = within(canvasElement);
|
|
255
|
-
const trigger = canvas.getByTestId('screen-reader-trigger');
|
|
256
|
-
|
|
257
|
-
// Open context menu
|
|
258
|
-
await rightClick(trigger);
|
|
259
|
-
|
|
260
|
-
// Menu is in a portal, use document body
|
|
261
|
-
|
|
262
|
-
const body = within(document.body);
|
|
263
|
-
|
|
264
|
-
await waitFor(() => {
|
|
265
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// Test ARIA attributes
|
|
269
|
-
const menu = body.getByRole('menu');
|
|
270
|
-
expect(menu).toHaveAttribute('role', 'menu');
|
|
271
|
-
|
|
272
|
-
// Test menu items have proper roles
|
|
273
|
-
const menuItems = body.getAllByRole('menuitem');
|
|
274
|
-
expect(menuItems).toHaveLength(testMenuItems.length);
|
|
275
|
-
|
|
276
|
-
// Verify each menu item is accessible
|
|
277
|
-
menuItems.forEach((item, index) => {
|
|
278
|
-
expect(item).toHaveAttribute('role', 'menuitem');
|
|
279
|
-
expect(item).toHaveTextContent(testMenuItems[index].label);
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
// Close menu
|
|
283
|
-
await userEvent.keyboard('{Escape}');
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
export const FocusManagement: Story = {
|
|
288
|
-
render: () => (
|
|
289
|
-
<Box
|
|
290
|
-
sx={{
|
|
291
|
-
width: 300,
|
|
292
|
-
height: 200,
|
|
293
|
-
display: 'flex',
|
|
294
|
-
alignItems: 'center',
|
|
295
|
-
justifyContent: 'center',
|
|
296
|
-
border: '2px solid',
|
|
297
|
-
borderColor: 'info.main',
|
|
298
|
-
borderRadius: 2,
|
|
299
|
-
backgroundColor: 'background.paper',
|
|
300
|
-
}}
|
|
301
|
-
>
|
|
302
|
-
<ContextMenu items={mixedMenuItems}>
|
|
303
|
-
<Typography variant="body2" color="text.primary" data-testid="focus-trigger">
|
|
304
|
-
Focus management test
|
|
305
|
-
</Typography>
|
|
306
|
-
</ContextMenu>
|
|
307
|
-
</Box>
|
|
308
|
-
),
|
|
309
|
-
play: async ({ canvasElement }) => {
|
|
310
|
-
const canvas = within(canvasElement);
|
|
311
|
-
const trigger = canvas.getByTestId('focus-trigger');
|
|
312
|
-
|
|
313
|
-
// Open context menu
|
|
314
|
-
await rightClick(trigger);
|
|
315
|
-
|
|
316
|
-
// Menu is in a portal, use document body
|
|
317
|
-
|
|
318
|
-
const body = within(document.body);
|
|
319
|
-
|
|
320
|
-
await waitFor(() => {
|
|
321
|
-
expect(body.getByText('Enabled Item')).toBeInTheDocument();
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
// Test that disabled items cannot receive focus
|
|
325
|
-
const enabledItem = body.getByText('Enabled Item');
|
|
326
|
-
const disabledItem = body.getByText('Disabled Item');
|
|
327
|
-
|
|
328
|
-
// MUI uses aria-disabled for menu items
|
|
329
|
-
expect(enabledItem.closest('[aria-disabled="true"]')).toBeNull();
|
|
330
|
-
expect(disabledItem.closest('[aria-disabled="true"]')).not.toBeNull();
|
|
331
|
-
|
|
332
|
-
// Test tab navigation skips disabled items
|
|
333
|
-
await userEvent.tab();
|
|
334
|
-
await waitFor(() => expect(document.activeElement).not.toBe(disabledItem));
|
|
335
|
-
|
|
336
|
-
// Close menu
|
|
337
|
-
await userEvent.keyboard('{Escape}');
|
|
338
|
-
},
|
|
339
|
-
};
|
|
340
|
-
|
|
341
|
-
export const ResponsiveDesign: Story = {
|
|
342
|
-
parameters: {
|
|
343
|
-
viewport: {
|
|
344
|
-
viewports: {
|
|
345
|
-
mobile: { name: 'Mobile', styles: { width: '375px', height: '667px' } },
|
|
346
|
-
tablet: { name: 'Tablet', styles: { width: '768px', height: '1024px' } },
|
|
347
|
-
desktop: { name: 'Desktop', styles: { width: '1440px', height: '900px' } },
|
|
348
|
-
},
|
|
349
|
-
defaultViewport: 'mobile',
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
render: () => (
|
|
353
|
-
<Box
|
|
354
|
-
sx={{
|
|
355
|
-
width: '100%',
|
|
356
|
-
height: '100vh',
|
|
357
|
-
display: 'flex',
|
|
358
|
-
alignItems: 'center',
|
|
359
|
-
justifyContent: 'center',
|
|
360
|
-
backgroundColor: 'background.default',
|
|
361
|
-
p: 2,
|
|
362
|
-
}}
|
|
363
|
-
>
|
|
364
|
-
<ContextMenu items={testMenuItems}>
|
|
365
|
-
<Paper
|
|
366
|
-
elevation={2}
|
|
367
|
-
sx={{
|
|
368
|
-
width: 250,
|
|
369
|
-
height: 150,
|
|
370
|
-
display: 'flex',
|
|
371
|
-
alignItems: 'center',
|
|
372
|
-
justifyContent: 'center',
|
|
373
|
-
cursor: 'context-menu',
|
|
374
|
-
}}
|
|
375
|
-
data-testid="responsive-trigger"
|
|
376
|
-
>
|
|
377
|
-
<Typography variant="body2" color="text.primary" textAlign="center">
|
|
378
|
-
Responsive context menu test
|
|
379
|
-
<br />
|
|
380
|
-
Right-click to test positioning
|
|
381
|
-
</Typography>
|
|
382
|
-
</Paper>
|
|
383
|
-
</ContextMenu>
|
|
384
|
-
</Box>
|
|
385
|
-
),
|
|
386
|
-
play: async ({ canvasElement }) => {
|
|
387
|
-
const canvas = within(canvasElement);
|
|
388
|
-
const trigger = canvas.getByTestId('responsive-trigger');
|
|
389
|
-
|
|
390
|
-
// Test context menu opens on different viewports
|
|
391
|
-
await rightClick(trigger);
|
|
392
|
-
|
|
393
|
-
// Menu is in a portal, use document body
|
|
394
|
-
|
|
395
|
-
const body = within(document.body);
|
|
396
|
-
|
|
397
|
-
await waitFor(() => {
|
|
398
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
// The menu opens and is visible. Overflow-against-the-viewport is deliberately
|
|
402
|
-
// NOT asserted here: it reads window/document dimensions, so the result depends
|
|
403
|
-
// on the runner's screen size rather than on the component. That belongs in a
|
|
404
|
-
// visual or e2e check pinned to a fixed viewport.
|
|
405
|
-
const menu = body.getByRole('menu');
|
|
406
|
-
expect(menu).toBeVisible();
|
|
407
|
-
|
|
408
|
-
// Close menu
|
|
409
|
-
await userEvent.keyboard('{Escape}');
|
|
410
|
-
},
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
export const ThemeVariations: Story = {
|
|
414
|
-
render: () => (
|
|
415
|
-
<Box sx={{ display: 'flex', gap: 3, flexWrap: 'wrap' }}>
|
|
416
|
-
{(['default', 'glass', 'dark'] as const).map((variant) => (
|
|
417
|
-
<Box
|
|
418
|
-
key={variant}
|
|
419
|
-
sx={{
|
|
420
|
-
width: 200,
|
|
421
|
-
height: 150,
|
|
422
|
-
display: 'flex',
|
|
423
|
-
alignItems: 'center',
|
|
424
|
-
justifyContent: 'center',
|
|
425
|
-
border: '1px solid',
|
|
426
|
-
borderColor: 'divider',
|
|
427
|
-
borderRadius: 2,
|
|
428
|
-
backgroundColor:
|
|
429
|
-
variant === 'glass'
|
|
430
|
-
? 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'
|
|
431
|
-
: 'background.paper',
|
|
432
|
-
color: variant === 'glass' ? 'white' : 'text.primary',
|
|
433
|
-
}}
|
|
434
|
-
>
|
|
435
|
-
<ContextMenu items={testMenuItems} variant={variant}>
|
|
436
|
-
<Typography
|
|
437
|
-
variant="caption"
|
|
438
|
-
textAlign="center"
|
|
439
|
-
data-testid={`theme-trigger-${variant}`}
|
|
440
|
-
>
|
|
441
|
-
{variant.charAt(0).toUpperCase() + variant.slice(1)} Theme
|
|
442
|
-
<br />
|
|
443
|
-
Right-click to test
|
|
444
|
-
</Typography>
|
|
445
|
-
</ContextMenu>
|
|
446
|
-
</Box>
|
|
447
|
-
))}
|
|
448
|
-
</Box>
|
|
449
|
-
),
|
|
450
|
-
play: async ({ canvasElement }) => {
|
|
451
|
-
const canvas = within(canvasElement);
|
|
452
|
-
|
|
453
|
-
// Test each theme variant
|
|
454
|
-
for (const variant of ['default', 'glass', 'dark'] as const) {
|
|
455
|
-
const trigger = canvas.getByTestId(`theme-trigger-${variant}`);
|
|
456
|
-
|
|
457
|
-
await rightClick(trigger);
|
|
458
|
-
|
|
459
|
-
// Menu is in a portal, use document body
|
|
460
|
-
|
|
461
|
-
const body = within(document.body);
|
|
462
|
-
|
|
463
|
-
await waitFor(() => {
|
|
464
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
// Verify menu is rendered with correct variant styling
|
|
468
|
-
const menu = body.getByRole('menu');
|
|
469
|
-
expect(menu).toBeInTheDocument();
|
|
470
|
-
|
|
471
|
-
// Close menu before testing next variant
|
|
472
|
-
await userEvent.keyboard('{Escape}');
|
|
473
|
-
await waitFor(() => {
|
|
474
|
-
expect(body.queryByText('Copy')).not.toBeInTheDocument();
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
},
|
|
478
|
-
};
|
|
479
|
-
|
|
480
|
-
export const VisualStates: Story = {
|
|
481
|
-
render: () => (
|
|
482
|
-
<Box sx={{ display: 'flex', gap: 3, flexDirection: 'column' }}>
|
|
483
|
-
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
|
484
|
-
{(['sm', 'md', 'lg'] as const).map((size) => (
|
|
485
|
-
<Box
|
|
486
|
-
key={size}
|
|
487
|
-
sx={{
|
|
488
|
-
width: 150,
|
|
489
|
-
height: 100,
|
|
490
|
-
display: 'flex',
|
|
491
|
-
alignItems: 'center',
|
|
492
|
-
justifyContent: 'center',
|
|
493
|
-
border: '1px solid',
|
|
494
|
-
borderColor: 'primary.main',
|
|
495
|
-
borderRadius: 1,
|
|
496
|
-
backgroundColor: 'background.paper',
|
|
497
|
-
}}
|
|
498
|
-
>
|
|
499
|
-
<ContextMenu items={testMenuItems} size={size}>
|
|
500
|
-
<Typography variant="caption" color="primary" data-testid={`size-trigger-${size}`}>
|
|
501
|
-
Size: {size.toUpperCase()}
|
|
502
|
-
</Typography>
|
|
503
|
-
</ContextMenu>
|
|
504
|
-
</Box>
|
|
505
|
-
))}
|
|
506
|
-
</Box>
|
|
507
|
-
|
|
508
|
-
<Box
|
|
509
|
-
sx={{
|
|
510
|
-
width: 200,
|
|
511
|
-
height: 100,
|
|
512
|
-
display: 'flex',
|
|
513
|
-
alignItems: 'center',
|
|
514
|
-
justifyContent: 'center',
|
|
515
|
-
border: '1px solid',
|
|
516
|
-
borderColor: 'action.disabled',
|
|
517
|
-
borderRadius: 1,
|
|
518
|
-
backgroundColor: 'action.disabledBackground',
|
|
519
|
-
opacity: 0.6,
|
|
520
|
-
}}
|
|
521
|
-
>
|
|
522
|
-
<ContextMenu items={testMenuItems} disabled>
|
|
523
|
-
<Typography variant="caption" color="text.disabled" data-testid="disabled-trigger">
|
|
524
|
-
Disabled State
|
|
525
|
-
</Typography>
|
|
526
|
-
</ContextMenu>
|
|
527
|
-
</Box>
|
|
528
|
-
</Box>
|
|
529
|
-
),
|
|
530
|
-
play: async ({ canvasElement }) => {
|
|
531
|
-
const canvas = within(canvasElement);
|
|
532
|
-
|
|
533
|
-
// Test different sizes
|
|
534
|
-
for (const size of ['sm', 'md', 'lg'] as const) {
|
|
535
|
-
const trigger = canvas.getByTestId(`size-trigger-${size}`);
|
|
536
|
-
|
|
537
|
-
await rightClick(trigger);
|
|
538
|
-
|
|
539
|
-
// Menu is in a portal, use document body
|
|
540
|
-
|
|
541
|
-
const body = within(document.body);
|
|
542
|
-
|
|
543
|
-
await waitFor(() => {
|
|
544
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
545
|
-
});
|
|
546
|
-
|
|
547
|
-
// Verify menu items have correct size styling
|
|
548
|
-
const menuItems = body.getAllByRole('menuitem');
|
|
549
|
-
expect(menuItems.length).toBeGreaterThan(0);
|
|
550
|
-
|
|
551
|
-
await userEvent.keyboard('{Escape}');
|
|
552
|
-
await waitFor(() => {
|
|
553
|
-
expect(body.queryByText('Copy')).not.toBeInTheDocument();
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// Test disabled state
|
|
558
|
-
const disabledTrigger = canvas.getByTestId('disabled-trigger');
|
|
559
|
-
await rightClick(disabledTrigger);
|
|
560
|
-
|
|
561
|
-
// Menu should not open when disabled
|
|
562
|
-
await new Promise((resolve) => window.setTimeout(resolve, 100));
|
|
563
|
-
const bodyForDisabled = within(document.body);
|
|
564
|
-
await waitFor(() => expect(bodyForDisabled.queryByText('Copy')).not.toBeInTheDocument());
|
|
565
|
-
},
|
|
566
|
-
};
|
|
567
|
-
|
|
568
|
-
export const Performance: Story = {
|
|
569
|
-
render: () => (
|
|
570
|
-
<Box
|
|
571
|
-
sx={{
|
|
572
|
-
width: 300,
|
|
573
|
-
height: 200,
|
|
574
|
-
display: 'flex',
|
|
575
|
-
alignItems: 'center',
|
|
576
|
-
justifyContent: 'center',
|
|
577
|
-
border: '2px solid',
|
|
578
|
-
borderColor: 'warning.main',
|
|
579
|
-
borderRadius: 2,
|
|
580
|
-
backgroundColor: 'background.paper',
|
|
581
|
-
}}
|
|
582
|
-
>
|
|
583
|
-
<ContextMenu items={complexMenuItems}>
|
|
584
|
-
<Typography variant="body2" color="text.primary" data-testid="performance-trigger">
|
|
585
|
-
Performance test with complex menu
|
|
586
|
-
</Typography>
|
|
587
|
-
</ContextMenu>
|
|
588
|
-
</Box>
|
|
589
|
-
),
|
|
590
|
-
play: async ({ canvasElement }) => {
|
|
591
|
-
const canvas = within(canvasElement);
|
|
592
|
-
const trigger = canvas.getByTestId('performance-trigger');
|
|
593
|
-
|
|
594
|
-
const startTime = window.performance.now();
|
|
595
|
-
|
|
596
|
-
// Test menu opens quickly
|
|
597
|
-
await rightClick(trigger);
|
|
598
|
-
|
|
599
|
-
// Menu is in a portal, use document body
|
|
600
|
-
|
|
601
|
-
const body = within(document.body);
|
|
602
|
-
|
|
603
|
-
await waitFor(() => {
|
|
604
|
-
expect(body.getByText('Edit')).toBeInTheDocument();
|
|
605
|
-
});
|
|
606
|
-
|
|
607
|
-
const openTime = window.performance.now() - startTime;
|
|
608
|
-
|
|
609
|
-
// Menu should open within reasonable time (< 100ms in test environment)
|
|
610
|
-
expect(openTime).toBeLessThan(1000);
|
|
611
|
-
|
|
612
|
-
// Verify complex menu structure renders correctly
|
|
613
|
-
expect(body.getByText('File Actions')).toBeInTheDocument();
|
|
614
|
-
expect(body.getByText('Danger Zone')).toBeInTheDocument();
|
|
615
|
-
expect(body.getByText('Edit')).toBeInTheDocument();
|
|
616
|
-
expect(body.getByText('Share')).toBeInTheDocument();
|
|
617
|
-
expect(body.getByText('Archive')).toBeInTheDocument();
|
|
618
|
-
expect(body.getByText('Delete')).toBeInTheDocument();
|
|
619
|
-
|
|
620
|
-
// Test quick close
|
|
621
|
-
const closeStartTime = window.performance.now();
|
|
622
|
-
await userEvent.keyboard('{Escape}');
|
|
623
|
-
await waitFor(() => {
|
|
624
|
-
expect(body.queryByText('Edit')).not.toBeInTheDocument();
|
|
625
|
-
});
|
|
626
|
-
const closeTime = window.performance.now() - closeStartTime;
|
|
627
|
-
|
|
628
|
-
expect(closeTime).toBeLessThan(1000);
|
|
629
|
-
},
|
|
630
|
-
};
|
|
631
|
-
|
|
632
|
-
export const EdgeCases: Story = {
|
|
633
|
-
render: () => (
|
|
634
|
-
<Box sx={{ display: 'flex', gap: 3, flexDirection: 'column' }}>
|
|
635
|
-
<Box
|
|
636
|
-
sx={{
|
|
637
|
-
width: 200,
|
|
638
|
-
height: 100,
|
|
639
|
-
display: 'flex',
|
|
640
|
-
alignItems: 'center',
|
|
641
|
-
justifyContent: 'center',
|
|
642
|
-
border: '1px solid',
|
|
643
|
-
borderColor: 'error.main',
|
|
644
|
-
borderRadius: 1,
|
|
645
|
-
backgroundColor: 'background.paper',
|
|
646
|
-
}}
|
|
647
|
-
>
|
|
648
|
-
<ContextMenu items={[]}>
|
|
649
|
-
<Typography variant="caption" color="error" data-testid="empty-menu-trigger">
|
|
650
|
-
Empty Menu
|
|
651
|
-
</Typography>
|
|
652
|
-
</ContextMenu>
|
|
653
|
-
</Box>
|
|
654
|
-
|
|
655
|
-
<Box
|
|
656
|
-
sx={{
|
|
657
|
-
width: 200,
|
|
658
|
-
height: 100,
|
|
659
|
-
display: 'flex',
|
|
660
|
-
alignItems: 'center',
|
|
661
|
-
justifyContent: 'center',
|
|
662
|
-
border: '1px solid',
|
|
663
|
-
borderColor: 'warning.main',
|
|
664
|
-
borderRadius: 1,
|
|
665
|
-
backgroundColor: 'background.paper',
|
|
666
|
-
}}
|
|
667
|
-
>
|
|
668
|
-
<ContextMenu
|
|
669
|
-
items={[
|
|
670
|
-
{
|
|
671
|
-
id: 'long-text',
|
|
672
|
-
label: 'This is a very long menu item text that should handle overflow properly',
|
|
673
|
-
icon: <Edit />,
|
|
674
|
-
shortcut: 'Ctrl+Shift+Alt+Super+L',
|
|
675
|
-
onClick: fn(),
|
|
676
|
-
},
|
|
677
|
-
]}
|
|
678
|
-
>
|
|
679
|
-
<Typography variant="caption" color="warning.main" data-testid="long-text-trigger">
|
|
680
|
-
Long Text Test
|
|
681
|
-
</Typography>
|
|
682
|
-
</ContextMenu>
|
|
683
|
-
</Box>
|
|
684
|
-
|
|
685
|
-
<Box
|
|
686
|
-
sx={{
|
|
687
|
-
width: 200,
|
|
688
|
-
height: 100,
|
|
689
|
-
display: 'flex',
|
|
690
|
-
alignItems: 'center',
|
|
691
|
-
justifyContent: 'center',
|
|
692
|
-
border: '1px solid',
|
|
693
|
-
borderColor: 'info.main',
|
|
694
|
-
borderRadius: 1,
|
|
695
|
-
backgroundColor: 'background.paper',
|
|
696
|
-
}}
|
|
697
|
-
>
|
|
698
|
-
<ContextMenu
|
|
699
|
-
items={[
|
|
700
|
-
{
|
|
701
|
-
id: 'special-chars',
|
|
702
|
-
label: 'Special chars: àáâãäåæçèéêë ñòóôõö ùúûüý',
|
|
703
|
-
icon: <Settings />,
|
|
704
|
-
onClick: fn(),
|
|
705
|
-
},
|
|
706
|
-
]}
|
|
707
|
-
>
|
|
708
|
-
<Typography variant="caption" color="info.main" data-testid="special-chars-trigger">
|
|
709
|
-
Special Characters
|
|
710
|
-
</Typography>
|
|
711
|
-
</ContextMenu>
|
|
712
|
-
</Box>
|
|
713
|
-
</Box>
|
|
714
|
-
),
|
|
715
|
-
play: async ({ canvasElement }) => {
|
|
716
|
-
const canvas = within(canvasElement);
|
|
717
|
-
|
|
718
|
-
// Test empty menu
|
|
719
|
-
const emptyTrigger = canvas.getByTestId('empty-menu-trigger');
|
|
720
|
-
await rightClick(emptyTrigger);
|
|
721
|
-
|
|
722
|
-
// Should handle empty menu gracefully
|
|
723
|
-
await new Promise((resolve) => window.setTimeout(resolve, 100));
|
|
724
|
-
const menu = canvas.queryByRole('menu');
|
|
725
|
-
if (menu) {
|
|
726
|
-
const menuItems = canvas.queryAllByRole('menuitem');
|
|
727
|
-
expect(menuItems).toHaveLength(0);
|
|
728
|
-
await userEvent.keyboard('{Escape}');
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
// Test long text
|
|
732
|
-
const longTextTrigger = canvas.getByTestId('long-text-trigger');
|
|
733
|
-
await rightClick(longTextTrigger);
|
|
734
|
-
const bodyForLongText = within(document.body);
|
|
735
|
-
await waitFor(() => {
|
|
736
|
-
expect(bodyForLongText.getByText(/This is a very long menu item text/)).toBeInTheDocument();
|
|
737
|
-
});
|
|
738
|
-
await userEvent.keyboard('{Escape}');
|
|
739
|
-
|
|
740
|
-
// Test special characters
|
|
741
|
-
const specialCharsTrigger = canvas.getByTestId('special-chars-trigger');
|
|
742
|
-
await rightClick(specialCharsTrigger);
|
|
743
|
-
const bodyForSpecialChars = within(document.body);
|
|
744
|
-
await waitFor(() => {
|
|
745
|
-
expect(bodyForSpecialChars.getByText(/Special chars: àáâãäåæçèéêë/)).toBeInTheDocument();
|
|
746
|
-
});
|
|
747
|
-
await userEvent.keyboard('{Escape}');
|
|
748
|
-
},
|
|
749
|
-
};
|
|
750
|
-
|
|
751
|
-
export const Integration: Story = {
|
|
752
|
-
render: () => (
|
|
753
|
-
<Box sx={{ display: 'flex', gap: 2, flexDirection: 'column' }}>
|
|
754
|
-
<Paper elevation={2} sx={{ p: 2 }}>
|
|
755
|
-
<Typography variant="h6" gutterBottom>
|
|
756
|
-
Multiple Context Menus Integration
|
|
757
|
-
</Typography>
|
|
758
|
-
<Box sx={{ display: 'flex', gap: 2 }}>
|
|
759
|
-
<ContextMenu items={testMenuItems} variant="default">
|
|
760
|
-
<Box
|
|
761
|
-
sx={{
|
|
762
|
-
width: 100,
|
|
763
|
-
height: 60,
|
|
764
|
-
border: '1px solid',
|
|
765
|
-
borderColor: 'primary.main',
|
|
766
|
-
borderRadius: 1,
|
|
767
|
-
display: 'flex',
|
|
768
|
-
alignItems: 'center',
|
|
769
|
-
justifyContent: 'center',
|
|
770
|
-
cursor: 'context-menu',
|
|
771
|
-
}}
|
|
772
|
-
data-testid="integration-trigger-1"
|
|
773
|
-
>
|
|
774
|
-
<Typography variant="caption">Menu 1</Typography>
|
|
775
|
-
</Box>
|
|
776
|
-
</ContextMenu>
|
|
777
|
-
|
|
778
|
-
<ContextMenu items={complexMenuItems} variant="glass">
|
|
779
|
-
<Box
|
|
780
|
-
sx={{
|
|
781
|
-
width: 100,
|
|
782
|
-
height: 60,
|
|
783
|
-
border: '1px solid',
|
|
784
|
-
borderColor: 'secondary.main',
|
|
785
|
-
borderRadius: 1,
|
|
786
|
-
display: 'flex',
|
|
787
|
-
alignItems: 'center',
|
|
788
|
-
justifyContent: 'center',
|
|
789
|
-
cursor: 'context-menu',
|
|
790
|
-
}}
|
|
791
|
-
data-testid="integration-trigger-2"
|
|
792
|
-
>
|
|
793
|
-
<Typography variant="caption">Menu 2</Typography>
|
|
794
|
-
</Box>
|
|
795
|
-
</ContextMenu>
|
|
796
|
-
</Box>
|
|
797
|
-
</Paper>
|
|
798
|
-
</Box>
|
|
799
|
-
),
|
|
800
|
-
play: async ({ canvasElement }) => {
|
|
801
|
-
const canvas = within(canvasElement);
|
|
802
|
-
const body = within(document.body);
|
|
803
|
-
|
|
804
|
-
// Test first context menu
|
|
805
|
-
const trigger1 = canvas.getByTestId('integration-trigger-1');
|
|
806
|
-
await rightClick(trigger1);
|
|
807
|
-
await waitFor(() => {
|
|
808
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
809
|
-
});
|
|
810
|
-
await userEvent.keyboard('{Escape}');
|
|
811
|
-
|
|
812
|
-
// Test second context menu
|
|
813
|
-
const trigger2 = canvas.getByTestId('integration-trigger-2');
|
|
814
|
-
await rightClick(trigger2);
|
|
815
|
-
await waitFor(() => {
|
|
816
|
-
expect(body.getByText('Edit')).toBeInTheDocument();
|
|
817
|
-
});
|
|
818
|
-
await userEvent.keyboard('{Escape}');
|
|
819
|
-
|
|
820
|
-
// Test that both menus work independently
|
|
821
|
-
await rightClick(trigger1);
|
|
822
|
-
await waitFor(() => {
|
|
823
|
-
expect(body.getByText('Copy')).toBeInTheDocument();
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
// Close first menu
|
|
827
|
-
await userEvent.keyboard('{Escape}');
|
|
828
|
-
await waitFor(() => {
|
|
829
|
-
expect(body.queryByText('Copy')).not.toBeInTheDocument();
|
|
830
|
-
});
|
|
831
|
-
|
|
832
|
-
// Open second menu
|
|
833
|
-
await rightClick(trigger2);
|
|
834
|
-
await waitFor(() => {
|
|
835
|
-
expect(body.getByText('Edit')).toBeInTheDocument();
|
|
836
|
-
});
|
|
837
|
-
|
|
838
|
-
// Verify second menu is open and first is closed. The 'Copy' item was present
|
|
839
|
-
// before this interaction, so its removal is awaited rather than asserted flat.
|
|
840
|
-
expect(body.getByText('Edit')).toBeInTheDocument();
|
|
841
|
-
await waitFor(() => expect(body.queryByText('Copy')).not.toBeInTheDocument());
|
|
842
|
-
|
|
843
|
-
await userEvent.keyboard('{Escape}');
|
|
844
|
-
},
|
|
845
|
-
};
|