@dashforge/tw 1.1.0 → 1.1.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/CHANGELOG.md +21 -1
- package/dist/index.esm.js +1 -1
- package/dist/src/index.d.ts +1 -1
- package/package.json +8 -3
- package/.swcrc +0 -29
- package/A11Y.md +0 -130
- package/CONSUMER-VALIDATION.md +0 -130
- package/COVERAGE.md +0 -63
- package/PARITY.md +0 -481
- package/PERFORMANCE.md +0 -227
- package/REFINEMENT-NOTES.md +0 -50
- package/THEME-AUDIT.md +0 -174
- package/dashforge-tw-1.0.0.tgz +0 -0
- package/eslint.config.mjs +0 -62
- package/project.json +0 -15
- package/rollup.config.cjs +0 -16
- package/src/components/Accordion/Accordion.test.tsx +0 -95
- package/src/components/Accordion/Accordion.tsx +0 -97
- package/src/components/Accordion/accordion.types.ts +0 -66
- package/src/components/Accordion/accordion.variants.ts +0 -32
- package/src/components/Alert/Alert.test.tsx +0 -302
- package/src/components/Alert/Alert.tsx +0 -186
- package/src/components/Alert/alert.types.ts +0 -144
- package/src/components/Alert/alert.variants.ts +0 -71
- package/src/components/AppShell/AppShell.test.tsx +0 -223
- package/src/components/AppShell/AppShell.tsx +0 -239
- package/src/components/AppShell/appShell.types.ts +0 -49
- package/src/components/AppShell/appShell.variants.ts +0 -54
- package/src/components/AspectRatio/AspectRatio.test.tsx +0 -173
- package/src/components/AspectRatio/AspectRatio.tsx +0 -73
- package/src/components/AspectRatio/aspectRatio.types.ts +0 -54
- package/src/components/Autocomplete/Autocomplete.perf.test.tsx +0 -225
- package/src/components/Autocomplete/Autocomplete.test.tsx +0 -556
- package/src/components/Autocomplete/Autocomplete.tsx +0 -1069
- package/src/components/Autocomplete/autocomplete.types.ts +0 -198
- package/src/components/Autocomplete/autocomplete.variants.ts +0 -141
- package/src/components/Avatar/Avatar.test.tsx +0 -287
- package/src/components/Avatar/Avatar.tsx +0 -304
- package/src/components/Avatar/avatar.types.ts +0 -205
- package/src/components/Avatar/avatar.variants.ts +0 -194
- package/src/components/Badge/Badge.test.tsx +0 -385
- package/src/components/Badge/Badge.tsx +0 -174
- package/src/components/Badge/badge.types.ts +0 -154
- package/src/components/Badge/badge.variants.ts +0 -161
- package/src/components/Box/Box.test.tsx +0 -391
- package/src/components/Box/Box.tsx +0 -112
- package/src/components/Box/box.types.ts +0 -116
- package/src/components/Box/box.variants.ts +0 -230
- package/src/components/Breadcrumbs/Breadcrumbs.perf.test.tsx +0 -128
- package/src/components/Breadcrumbs/Breadcrumbs.test.tsx +0 -231
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +0 -203
- package/src/components/Breadcrumbs/breadcrumbs.types.ts +0 -87
- package/src/components/Breadcrumbs/breadcrumbs.variants.ts +0 -54
- package/src/components/Button/Button.test.tsx +0 -204
- package/src/components/Button/Button.tsx +0 -151
- package/src/components/Button/button.types.ts +0 -110
- package/src/components/Button/button.variants.ts +0 -159
- package/src/components/Calendar/Calendar.test.tsx +0 -75
- package/src/components/Calendar/Calendar.tsx +0 -264
- package/src/components/Calendar/calendar.types.ts +0 -65
- package/src/components/Calendar/calendar.variants.ts +0 -64
- package/src/components/Card/Card.test.tsx +0 -291
- package/src/components/Card/Card.tsx +0 -241
- package/src/components/Card/card.types.ts +0 -132
- package/src/components/Checkbox/Checkbox.test.tsx +0 -146
- package/src/components/Checkbox/Checkbox.tsx +0 -286
- package/src/components/Checkbox/checkbox.types.ts +0 -88
- package/src/components/Checkbox/checkbox.variants.ts +0 -68
- package/src/components/Chip/Chip.test.tsx +0 -316
- package/src/components/Chip/Chip.tsx +0 -224
- package/src/components/Chip/chip.types.ts +0 -128
- package/src/components/Chip/chip.variants.ts +0 -173
- package/src/components/ConfirmDialog/ConfirmDialog.perf.test.tsx +0 -172
- package/src/components/ConfirmDialog/ConfirmDialog.test.tsx +0 -311
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +0 -252
- package/src/components/ConfirmDialog/confirmDialog.types.ts +0 -70
- package/src/components/ConfirmDialog/confirmDialog.variants.ts +0 -76
- package/src/components/Container/Container.test.tsx +0 -209
- package/src/components/Container/Container.tsx +0 -74
- package/src/components/Container/container.types.ts +0 -45
- package/src/components/Container/container.variants.ts +0 -81
- package/src/components/DataGrid/DataGrid.perf.test.tsx +0 -114
- package/src/components/DataGrid/DataGrid.test.tsx +0 -1153
- package/src/components/DataGrid/DataGrid.tsx +0 -1282
- package/src/components/DataGrid/dataGrid.types.ts +0 -238
- package/src/components/DataGrid/dataGrid.variants.ts +0 -152
- package/src/components/DataGrid/filters/ColumnFilters.test.tsx +0 -330
- package/src/components/DataGrid/filters/ColumnFilters.tsx +0 -456
- package/src/components/DataGrid/reorder/useColumnReorder.test.ts +0 -130
- package/src/components/DataGrid/reorder/useColumnReorder.ts +0 -144
- package/src/components/DataGrid/resize/useColumnResize.test.ts +0 -144
- package/src/components/DataGrid/resize/useColumnResize.ts +0 -135
- package/src/components/DataGrid/visibility/ColumnVisibilityMenu.tsx +0 -186
- package/src/components/DatePicker/DatePicker.test.tsx +0 -76
- package/src/components/DatePicker/DatePicker.tsx +0 -305
- package/src/components/DatePicker/datePicker.types.ts +0 -77
- package/src/components/DatePicker/datePicker.variants.ts +0 -50
- package/src/components/DateRangePicker/DateRangePicker.test.tsx +0 -92
- package/src/components/DateRangePicker/DateRangePicker.tsx +0 -510
- package/src/components/DateRangePicker/dateRangePicker.types.ts +0 -74
- package/src/components/DateRangePicker/dateRangePicker.variants.ts +0 -101
- package/src/components/DateTimePicker/DateTimePicker.test.tsx +0 -78
- package/src/components/DateTimePicker/DateTimePicker.tsx +0 -347
- package/src/components/DateTimePicker/dateTimePicker.types.ts +0 -79
- package/src/components/DateTimePicker/dateTimePicker.variants.ts +0 -55
- package/src/components/Dialog/Dialog.test.tsx +0 -96
- package/src/components/Dialog/Dialog.tsx +0 -102
- package/src/components/Dialog/dialog.types.ts +0 -62
- package/src/components/Dialog/dialog.variants.ts +0 -66
- package/src/components/Divider/Divider.test.tsx +0 -243
- package/src/components/Divider/Divider.tsx +0 -140
- package/src/components/Divider/divider.types.ts +0 -52
- package/src/components/Divider/divider.variants.ts +0 -116
- package/src/components/Grid/Grid.test.tsx +0 -321
- package/src/components/Grid/Grid.tsx +0 -148
- package/src/components/Grid/grid.types.ts +0 -112
- package/src/components/Grid/grid.variants.ts +0 -133
- package/src/components/IconButton/IconButton.test.tsx +0 -367
- package/src/components/IconButton/IconButton.tsx +0 -159
- package/src/components/IconButton/iconButton.types.ts +0 -106
- package/src/components/IconButton/iconButton.variants.ts +0 -31
- package/src/components/LeftNav/LeftNav.perf.test.tsx +0 -172
- package/src/components/LeftNav/LeftNav.test.tsx +0 -302
- package/src/components/LeftNav/LeftNav.tsx +0 -330
- package/src/components/LeftNav/leftNav.types.ts +0 -120
- package/src/components/LeftNav/leftNav.variants.ts +0 -107
- package/src/components/Menu/Menu.test.tsx +0 -408
- package/src/components/Menu/Menu.tsx +0 -335
- package/src/components/Menu/menu.types.ts +0 -221
- package/src/components/Menu/menu.variants.ts +0 -132
- package/src/components/NumberField/NumberField.test.tsx +0 -83
- package/src/components/NumberField/NumberField.tsx +0 -321
- package/src/components/NumberField/numberField.types.ts +0 -72
- package/src/components/NumberField/numberField.variants.ts +0 -94
- package/src/components/OTPField/OTPField.test.tsx +0 -121
- package/src/components/OTPField/OTPField.tsx +0 -250
- package/src/components/OTPField/otpField.types.ts +0 -58
- package/src/components/OTPField/otpField.variants.ts +0 -72
- package/src/components/Pagination/Pagination.test.tsx +0 -314
- package/src/components/Pagination/Pagination.tsx +0 -277
- package/src/components/Pagination/pagination.helpers.ts +0 -102
- package/src/components/Pagination/pagination.types.ts +0 -117
- package/src/components/Pagination/pagination.variants.ts +0 -117
- package/src/components/Popover/Popover.test.tsx +0 -72
- package/src/components/Popover/Popover.tsx +0 -55
- package/src/components/Popover/popover.types.ts +0 -42
- package/src/components/Popover/popover.variants.ts +0 -24
- package/src/components/RadioGroup/RadioGroup.test.tsx +0 -140
- package/src/components/RadioGroup/RadioGroup.tsx +0 -283
- package/src/components/RadioGroup/radioGroup.types.ts +0 -85
- package/src/components/RadioGroup/radioGroup.variants.ts +0 -87
- package/src/components/Skeleton/Skeleton.test.tsx +0 -127
- package/src/components/Skeleton/Skeleton.tsx +0 -49
- package/src/components/Skeleton/skeleton.types.ts +0 -59
- package/src/components/Skeleton/skeleton.variants.ts +0 -87
- package/src/components/Snackbar/Snackbar.perf.test.tsx +0 -144
- package/src/components/Snackbar/Snackbar.test.tsx +0 -327
- package/src/components/Snackbar/Snackbar.tsx +0 -316
- package/src/components/Snackbar/snackbar.types.ts +0 -127
- package/src/components/Snackbar/snackbar.variants.ts +0 -81
- package/src/components/Spinner/Spinner.test.tsx +0 -199
- package/src/components/Spinner/Spinner.tsx +0 -158
- package/src/components/Spinner/spinner.types.ts +0 -113
- package/src/components/Spinner/spinner.variants.ts +0 -83
- package/src/components/Stack/Stack.test.tsx +0 -309
- package/src/components/Stack/Stack.tsx +0 -115
- package/src/components/Stack/stack.types.ts +0 -68
- package/src/components/Stack/stack.variants.ts +0 -80
- package/src/components/Switch/Switch.test.tsx +0 -131
- package/src/components/Switch/Switch.tsx +0 -158
- package/src/components/Switch/switch.types.ts +0 -36
- package/src/components/Switch/switch.variants.ts +0 -70
- package/src/components/Table/Table.perf.test.tsx +0 -81
- package/src/components/Table/Table.test.tsx +0 -674
- package/src/components/Table/Table.tsx +0 -863
- package/src/components/Table/cells/RenderButton.tsx +0 -23
- package/src/components/Table/cells/RenderChip.tsx +0 -37
- package/src/components/Table/cells/RenderText.tsx +0 -37
- package/src/components/Table/cells/RenderTwoLine.tsx +0 -34
- package/src/components/Table/cells/RowActionsMenu.tsx +0 -147
- package/src/components/Table/cells/cells.test.tsx +0 -247
- package/src/components/Table/cells/index.ts +0 -14
- package/src/components/Table/table.types.ts +0 -438
- package/src/components/Table/table.variants.ts +0 -207
- package/src/components/Tabs/Tabs.test.tsx +0 -145
- package/src/components/Tabs/Tabs.tsx +0 -77
- package/src/components/Tabs/tabs.types.ts +0 -55
- package/src/components/Tabs/tabs.variants.ts +0 -69
- package/src/components/Tabs/useTabs.ts +0 -167
- package/src/components/TextField/TextField.test.tsx +0 -198
- package/src/components/TextField/TextField.tsx +0 -245
- package/src/components/TextField/textField.types.ts +0 -90
- package/src/components/TextField/textField.variants.ts +0 -105
- package/src/components/Textarea/Textarea.test.tsx +0 -75
- package/src/components/Textarea/Textarea.tsx +0 -190
- package/src/components/Textarea/textarea.types.ts +0 -60
- package/src/components/Textarea/textarea.variants.ts +0 -85
- package/src/components/TimePicker/TimePicker.test.tsx +0 -65
- package/src/components/TimePicker/TimePicker.tsx +0 -274
- package/src/components/TimePicker/timePicker.types.ts +0 -69
- package/src/components/TimePicker/timePicker.variants.ts +0 -53
- package/src/components/Tooltip/Tooltip.test.tsx +0 -73
- package/src/components/Tooltip/Tooltip.tsx +0 -70
- package/src/components/Tooltip/tooltip.types.ts +0 -44
- package/src/components/Tooltip/tooltip.variants.ts +0 -28
- package/src/components/TopBar/TopBar.test.tsx +0 -129
- package/src/components/TopBar/TopBar.tsx +0 -66
- package/src/components/TopBar/topBar.types.ts +0 -42
- package/src/components/TopBar/topBar.variants.ts +0 -38
- package/src/components/Typography/Typography.test.tsx +0 -247
- package/src/components/Typography/Typography.tsx +0 -112
- package/src/components/Typography/typography.types.ts +0 -65
- package/src/components/Typography/typography.variants.ts +0 -130
- package/src/components/VisuallyHidden/VisuallyHidden.test.tsx +0 -86
- package/src/components/VisuallyHidden/VisuallyHidden.tsx +0 -59
- package/src/components/VisuallyHidden/visuallyHidden.types.ts +0 -45
- package/src/components/_shared/data/getNestedValue.test.ts +0 -50
- package/src/components/_shared/data/getNestedValue.ts +0 -32
- package/src/components/_shared/data/useColumnAutoDetect.test.ts +0 -123
- package/src/components/_shared/data/useColumnAutoDetect.ts +0 -100
- package/src/components/_shared/data/useControllableState.ts +0 -48
- package/src/components/_shared/data/useDebouncedValue.ts +0 -24
- package/src/components/_shared/data/useTableFilter.test.ts +0 -166
- package/src/components/_shared/data/useTableFilter.ts +0 -118
- package/src/components/_shared/data/useTableSearch.test.ts +0 -115
- package/src/components/_shared/data/useTableSearch.ts +0 -66
- package/src/components/_shared/data/useTableSelection.test.ts +0 -100
- package/src/components/_shared/data/useTableSelection.ts +0 -100
- package/src/components/_shared/data/useTableSort.test.ts +0 -150
- package/src/components/_shared/data/useTableSort.ts +0 -141
- package/src/components/_shared/data/useVirtualizer.test.ts +0 -158
- package/src/components/_shared/data/useVirtualizer.ts +0 -199
- package/src/components/_shared/resolveValidationState.ts +0 -60
- package/src/components/_shared/severity/index.ts +0 -33
- package/src/components/_shared/severity/severity.types.ts +0 -50
- package/src/components/_shared/severity/severityIcons.tsx +0 -104
- package/src/components/_shared/severity/severityVariants.test.ts +0 -136
- package/src/components/_shared/severity/severityVariants.ts +0 -115
- package/src/components/_shared/themeIdentity.test.ts +0 -113
- package/src/hooks/useAccessState.spec.tsx +0 -161
- package/src/hooks/useAccessState.ts +0 -81
- package/src/index.ts +0 -550
- package/src/utils/cn.spec.ts +0 -16
- package/src/utils/cn.ts +0 -29
- package/test-output/vitest/coverage/base.css +0 -224
- package/test-output/vitest/coverage/block-navigation.js +0 -87
- package/test-output/vitest/coverage/clover.xml +0 -2418
- package/test-output/vitest/coverage/coverage-final.json +0 -89
- package/test-output/vitest/coverage/favicon.png +0 -0
- package/test-output/vitest/coverage/index.html +0 -746
- package/test-output/vitest/coverage/prettify.css +0 -1
- package/test-output/vitest/coverage/prettify.js +0 -2
- package/test-output/vitest/coverage/sort-arrow-sprite.png +0 -0
- package/test-output/vitest/coverage/sorter.js +0 -210
- package/test-output/vitest/coverage/src/components/Accordion/Accordion.tsx.html +0 -376
- package/test-output/vitest/coverage/src/components/Accordion/accordion.variants.ts.html +0 -181
- package/test-output/vitest/coverage/src/components/Accordion/index.html +0 -131
- package/test-output/vitest/coverage/src/components/AppShell/AppShell.tsx.html +0 -802
- package/test-output/vitest/coverage/src/components/AppShell/appShell.variants.ts.html +0 -247
- package/test-output/vitest/coverage/src/components/AppShell/index.html +0 -131
- package/test-output/vitest/coverage/src/components/AspectRatio/AspectRatio.tsx.html +0 -304
- package/test-output/vitest/coverage/src/components/AspectRatio/index.html +0 -116
- package/test-output/vitest/coverage/src/components/Autocomplete/Autocomplete.tsx.html +0 -3292
- package/test-output/vitest/coverage/src/components/Autocomplete/autocomplete.variants.ts.html +0 -508
- package/test-output/vitest/coverage/src/components/Autocomplete/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Box/Box.tsx.html +0 -334
- package/test-output/vitest/coverage/src/components/Box/box.variants.ts.html +0 -775
- package/test-output/vitest/coverage/src/components/Box/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Breadcrumbs/Breadcrumbs.tsx.html +0 -694
- package/test-output/vitest/coverage/src/components/Breadcrumbs/breadcrumbs.variants.ts.html +0 -247
- package/test-output/vitest/coverage/src/components/Breadcrumbs/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Button/Button.tsx.html +0 -535
- package/test-output/vitest/coverage/src/components/Button/button.variants.ts.html +0 -562
- package/test-output/vitest/coverage/src/components/Button/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Checkbox/Checkbox.tsx.html +0 -943
- package/test-output/vitest/coverage/src/components/Checkbox/checkbox.variants.ts.html +0 -289
- package/test-output/vitest/coverage/src/components/Checkbox/index.html +0 -131
- package/test-output/vitest/coverage/src/components/ConfirmDialog/ConfirmDialog.tsx.html +0 -841
- package/test-output/vitest/coverage/src/components/ConfirmDialog/confirmDialog.variants.ts.html +0 -313
- package/test-output/vitest/coverage/src/components/ConfirmDialog/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Container/Container.tsx.html +0 -307
- package/test-output/vitest/coverage/src/components/Container/container.variants.ts.html +0 -328
- package/test-output/vitest/coverage/src/components/Container/index.html +0 -131
- package/test-output/vitest/coverage/src/components/DataGrid/DataGrid.tsx.html +0 -3937
- package/test-output/vitest/coverage/src/components/DataGrid/dataGrid.variants.ts.html +0 -541
- package/test-output/vitest/coverage/src/components/DataGrid/filters/ColumnFilters.tsx.html +0 -1453
- package/test-output/vitest/coverage/src/components/DataGrid/filters/index.html +0 -116
- package/test-output/vitest/coverage/src/components/DataGrid/index.html +0 -131
- package/test-output/vitest/coverage/src/components/DataGrid/reorder/index.html +0 -116
- package/test-output/vitest/coverage/src/components/DataGrid/reorder/useColumnReorder.ts.html +0 -517
- package/test-output/vitest/coverage/src/components/DataGrid/resize/index.html +0 -116
- package/test-output/vitest/coverage/src/components/DataGrid/resize/useColumnResize.ts.html +0 -490
- package/test-output/vitest/coverage/src/components/DataGrid/visibility/ColumnVisibilityMenu.tsx.html +0 -592
- package/test-output/vitest/coverage/src/components/DataGrid/visibility/index.html +0 -116
- package/test-output/vitest/coverage/src/components/DateTimePicker/DateTimePicker.tsx.html +0 -1042
- package/test-output/vitest/coverage/src/components/DateTimePicker/dateTimePicker.variants.ts.html +0 -337
- package/test-output/vitest/coverage/src/components/DateTimePicker/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Dialog/Dialog.tsx.html +0 -391
- package/test-output/vitest/coverage/src/components/Dialog/dialog.variants.ts.html +0 -283
- package/test-output/vitest/coverage/src/components/Dialog/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Divider/Divider.tsx.html +0 -505
- package/test-output/vitest/coverage/src/components/Divider/divider.variants.ts.html +0 -433
- package/test-output/vitest/coverage/src/components/Divider/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Grid/Grid.tsx.html +0 -529
- package/test-output/vitest/coverage/src/components/Grid/grid.variants.ts.html +0 -484
- package/test-output/vitest/coverage/src/components/Grid/index.html +0 -131
- package/test-output/vitest/coverage/src/components/LeftNav/LeftNav.tsx.html +0 -1075
- package/test-output/vitest/coverage/src/components/LeftNav/index.html +0 -131
- package/test-output/vitest/coverage/src/components/LeftNav/leftNav.variants.ts.html +0 -406
- package/test-output/vitest/coverage/src/components/NumberField/NumberField.tsx.html +0 -1048
- package/test-output/vitest/coverage/src/components/NumberField/index.html +0 -131
- package/test-output/vitest/coverage/src/components/NumberField/numberField.variants.ts.html +0 -367
- package/test-output/vitest/coverage/src/components/OTPField/OTPField.tsx.html +0 -835
- package/test-output/vitest/coverage/src/components/OTPField/index.html +0 -131
- package/test-output/vitest/coverage/src/components/OTPField/otpField.variants.ts.html +0 -301
- package/test-output/vitest/coverage/src/components/Pagination/Pagination.tsx.html +0 -916
- package/test-output/vitest/coverage/src/components/Pagination/index.html +0 -146
- package/test-output/vitest/coverage/src/components/Pagination/pagination.helpers.ts.html +0 -391
- package/test-output/vitest/coverage/src/components/Pagination/pagination.variants.ts.html +0 -436
- package/test-output/vitest/coverage/src/components/Popover/Popover.tsx.html +0 -250
- package/test-output/vitest/coverage/src/components/Popover/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Popover/popover.variants.ts.html +0 -157
- package/test-output/vitest/coverage/src/components/RadioGroup/RadioGroup.tsx.html +0 -934
- package/test-output/vitest/coverage/src/components/RadioGroup/index.html +0 -131
- package/test-output/vitest/coverage/src/components/RadioGroup/radioGroup.variants.ts.html +0 -346
- package/test-output/vitest/coverage/src/components/Skeleton/Skeleton.tsx.html +0 -232
- package/test-output/vitest/coverage/src/components/Skeleton/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Skeleton/skeleton.variants.ts.html +0 -346
- package/test-output/vitest/coverage/src/components/Snackbar/Snackbar.tsx.html +0 -979
- package/test-output/vitest/coverage/src/components/Snackbar/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Snackbar/snackbar.variants.ts.html +0 -307
- package/test-output/vitest/coverage/src/components/Stack/Stack.tsx.html +0 -430
- package/test-output/vitest/coverage/src/components/Stack/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Stack/stack.variants.ts.html +0 -325
- package/test-output/vitest/coverage/src/components/Switch/Switch.tsx.html +0 -559
- package/test-output/vitest/coverage/src/components/Switch/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Switch/switch.variants.ts.html +0 -295
- package/test-output/vitest/coverage/src/components/Table/Table.tsx.html +0 -2677
- package/test-output/vitest/coverage/src/components/Table/cells/RenderButton.tsx.html +0 -154
- package/test-output/vitest/coverage/src/components/Table/cells/RenderChip.tsx.html +0 -385
- package/test-output/vitest/coverage/src/components/Table/cells/RenderText.tsx.html +0 -196
- package/test-output/vitest/coverage/src/components/Table/cells/RenderTwoLine.tsx.html +0 -187
- package/test-output/vitest/coverage/src/components/Table/cells/RowActionsMenu.tsx.html +0 -526
- package/test-output/vitest/coverage/src/components/Table/cells/index.html +0 -191
- package/test-output/vitest/coverage/src/components/Table/cells/index.ts.html +0 -127
- package/test-output/vitest/coverage/src/components/Table/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Table/table.variants.ts.html +0 -706
- package/test-output/vitest/coverage/src/components/Tabs/Tabs.tsx.html +0 -283
- package/test-output/vitest/coverage/src/components/Tabs/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Tabs/tabs.variants.ts.html +0 -292
- package/test-output/vitest/coverage/src/components/TextField/TextField.tsx.html +0 -820
- package/test-output/vitest/coverage/src/components/TextField/index.html +0 -131
- package/test-output/vitest/coverage/src/components/TextField/textField.variants.ts.html +0 -400
- package/test-output/vitest/coverage/src/components/Textarea/Textarea.tsx.html +0 -655
- package/test-output/vitest/coverage/src/components/Textarea/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Textarea/textarea.variants.ts.html +0 -340
- package/test-output/vitest/coverage/src/components/Tooltip/Tooltip.tsx.html +0 -295
- package/test-output/vitest/coverage/src/components/Tooltip/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Tooltip/tooltip.variants.ts.html +0 -169
- package/test-output/vitest/coverage/src/components/TopBar/TopBar.tsx.html +0 -283
- package/test-output/vitest/coverage/src/components/TopBar/index.html +0 -131
- package/test-output/vitest/coverage/src/components/TopBar/topBar.variants.ts.html +0 -199
- package/test-output/vitest/coverage/src/components/Typography/Typography.tsx.html +0 -421
- package/test-output/vitest/coverage/src/components/Typography/index.html +0 -131
- package/test-output/vitest/coverage/src/components/Typography/typography.variants.ts.html +0 -436
- package/test-output/vitest/coverage/src/components/VisuallyHidden/VisuallyHidden.tsx.html +0 -262
- package/test-output/vitest/coverage/src/components/VisuallyHidden/index.html +0 -116
- package/test-output/vitest/coverage/src/components/_shared/data/getNestedValue.ts.html +0 -181
- package/test-output/vitest/coverage/src/components/_shared/data/index.html +0 -236
- package/test-output/vitest/coverage/src/components/_shared/data/useColumnAutoDetect.ts.html +0 -385
- package/test-output/vitest/coverage/src/components/_shared/data/useControllableState.ts.html +0 -229
- package/test-output/vitest/coverage/src/components/_shared/data/useDebouncedValue.ts.html +0 -157
- package/test-output/vitest/coverage/src/components/_shared/data/useTableFilter.ts.html +0 -439
- package/test-output/vitest/coverage/src/components/_shared/data/useTableSearch.ts.html +0 -283
- package/test-output/vitest/coverage/src/components/_shared/data/useTableSelection.ts.html +0 -385
- package/test-output/vitest/coverage/src/components/_shared/data/useTableSort.ts.html +0 -508
- package/test-output/vitest/coverage/src/components/_shared/data/useVirtualizer.ts.html +0 -682
- package/test-output/vitest/coverage/src/components/_shared/index.html +0 -116
- package/test-output/vitest/coverage/src/components/_shared/resolveValidationState.ts.html +0 -265
- package/test-output/vitest/coverage/src/hooks/index.html +0 -116
- package/test-output/vitest/coverage/src/hooks/useAccessState.ts.html +0 -328
- package/test-output/vitest/coverage/src/index.html +0 -116
- package/test-output/vitest/coverage/src/index.ts.html +0 -1153
- package/test-output/vitest/coverage/src/utils/cn.ts.html +0 -172
- package/test-output/vitest/coverage/src/utils/index.html +0 -116
- package/tsconfig.json +0 -13
- package/tsconfig.lib.json +0 -58
- package/tsconfig.spec.json +0 -34
- package/vite.config.ts +0 -33
- package/vitest.config.mts +0 -29
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ReactNode,
|
|
3
|
-
ComponentType,
|
|
4
|
-
AnchorHTMLAttributes,
|
|
5
|
-
Ref,
|
|
6
|
-
} from 'react';
|
|
7
|
-
import type { AccessRequirement } from '@dashforge/rbac';
|
|
8
|
-
import type { LeftNavVariants } from './leftNav.variants.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* One row in the LeftNav. May be either a clickable item OR a group
|
|
12
|
-
* (a header that owns nested children, optionally collapsible).
|
|
13
|
-
*/
|
|
14
|
-
export type LeftNavNode = LeftNavItem | LeftNavGroup;
|
|
15
|
-
|
|
16
|
-
export interface LeftNavItem {
|
|
17
|
-
kind?: 'item';
|
|
18
|
-
/** Stable id used for `activeId` matching + React keys. */
|
|
19
|
-
id: string;
|
|
20
|
-
label: ReactNode;
|
|
21
|
-
icon?: ReactNode;
|
|
22
|
-
/**
|
|
23
|
-
* Destination for navigation. Omit for a pure-callback item (use
|
|
24
|
-
* `onSelect`).
|
|
25
|
-
*/
|
|
26
|
-
href?: string;
|
|
27
|
-
/** Fired when the row is clicked (in addition to navigation). */
|
|
28
|
-
onSelect?: () => void;
|
|
29
|
-
/** Optional pill / counter rendered to the right of the label. */
|
|
30
|
-
badge?: ReactNode;
|
|
31
|
-
/** Per-item disabled flag. */
|
|
32
|
-
disabled?: boolean;
|
|
33
|
-
/** RBAC access requirement — hides / disables the row. */
|
|
34
|
-
access?: AccessRequirement;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export interface LeftNavGroup {
|
|
38
|
-
kind: 'group';
|
|
39
|
-
id: string;
|
|
40
|
-
label: ReactNode;
|
|
41
|
-
icon?: ReactNode;
|
|
42
|
-
children: LeftNavItem[];
|
|
43
|
-
/**
|
|
44
|
-
* Initial expanded state when used in uncontrolled mode. Default
|
|
45
|
-
* `true` (groups open by default — most app navs want immediate
|
|
46
|
-
* visibility).
|
|
47
|
-
*/
|
|
48
|
-
defaultExpanded?: boolean;
|
|
49
|
-
/** Controlled expanded state. Provide `onExpandedChange` to update. */
|
|
50
|
-
expanded?: boolean;
|
|
51
|
-
/** RBAC access requirement — hides / disables the whole group. */
|
|
52
|
-
access?: AccessRequirement;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Polymorphic link component prop. Defaults to `<a>`. Pass a
|
|
57
|
-
* router-aware component (react-router `Link`, Next `Link`) for SPA
|
|
58
|
-
* navigation.
|
|
59
|
-
*/
|
|
60
|
-
export type LeftNavLinkComponent = ComponentType<
|
|
61
|
-
AnchorHTMLAttributes<HTMLAnchorElement> & {
|
|
62
|
-
ref?: Ref<HTMLAnchorElement>;
|
|
63
|
-
}
|
|
64
|
-
>;
|
|
65
|
-
|
|
66
|
-
export interface LeftNavSlotProps {
|
|
67
|
-
root?: { className?: string };
|
|
68
|
-
brand?: { className?: string };
|
|
69
|
-
list?: { className?: string };
|
|
70
|
-
item?: { className?: string };
|
|
71
|
-
itemLink?: { className?: string };
|
|
72
|
-
itemActive?: { className?: string };
|
|
73
|
-
itemIcon?: { className?: string };
|
|
74
|
-
itemLabel?: { className?: string };
|
|
75
|
-
itemBadge?: { className?: string };
|
|
76
|
-
group?: { className?: string };
|
|
77
|
-
groupHeader?: { className?: string };
|
|
78
|
-
groupChildren?: { className?: string };
|
|
79
|
-
footer?: { className?: string };
|
|
80
|
-
collapseToggle?: { className?: string };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Props for `<LeftNav>`.
|
|
85
|
-
*
|
|
86
|
-
* Router-agnostic sidebar navigation. The consumer drives the active
|
|
87
|
-
* item via `activeId` (typically derived from the current route).
|
|
88
|
-
*
|
|
89
|
-
* Rail / drawer responsive behaviour is handled by `<AppShell>`; this
|
|
90
|
-
* component renders the actual nav content and exposes a `collapsed`
|
|
91
|
-
* prop for the icon-only "rail" rendering.
|
|
92
|
-
*/
|
|
93
|
-
export interface LeftNavProps extends LeftNavVariants {
|
|
94
|
-
items: LeftNavNode[];
|
|
95
|
-
/** Currently-active item id (highlight + `aria-current="page"`). */
|
|
96
|
-
activeId?: string;
|
|
97
|
-
/**
|
|
98
|
-
* Icon-only rail mode. When `true`, labels and group children are
|
|
99
|
-
* visually hidden (kept for screen readers via `sr-only`).
|
|
100
|
-
*/
|
|
101
|
-
collapsed?: boolean;
|
|
102
|
-
/** Fired when the user clicks the collapse-toggle button. */
|
|
103
|
-
onCollapseChange?: (collapsed: boolean) => void;
|
|
104
|
-
/** Fired when a group's expanded state changes (controlled or not). */
|
|
105
|
-
onGroupExpandedChange?: (groupId: string, expanded: boolean) => void;
|
|
106
|
-
/** Brand / logo node rendered at the top. */
|
|
107
|
-
brand?: ReactNode;
|
|
108
|
-
/** Footer node (e.g., user badge). */
|
|
109
|
-
footer?: ReactNode;
|
|
110
|
-
/** Override the link component. @default 'a' */
|
|
111
|
-
linkComponent?: LeftNavLinkComponent;
|
|
112
|
-
/** Visible label of the nav landmark. @default 'Main navigation' */
|
|
113
|
-
ariaLabel?: string;
|
|
114
|
-
/** Root className shortcut. */
|
|
115
|
-
sx?: string;
|
|
116
|
-
/** Per-slot className overrides. */
|
|
117
|
-
slotProps?: LeftNavSlotProps;
|
|
118
|
-
/** Show / hide the collapse toggle button. @default true */
|
|
119
|
-
showCollapseToggle?: boolean;
|
|
120
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
import { tv, type VariantProps } from 'tailwind-variants';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Tailwind-variants recipe for `<LeftNav>`.
|
|
5
|
-
*
|
|
6
|
-
* Slots:
|
|
7
|
-
* - `root` — `<nav>` landmark
|
|
8
|
-
* - `brand` — top brand/logo wrapper
|
|
9
|
-
* - `list` — `<ul>` containing items & groups
|
|
10
|
-
* - `item` — `<li>` wrapper
|
|
11
|
-
* - `itemLink` — clickable row (`<a>` or `<button>`)
|
|
12
|
-
* - `itemActive` — active state on the row
|
|
13
|
-
* - `itemIcon` — icon slot inside a row
|
|
14
|
-
* - `itemLabel` — text label slot
|
|
15
|
-
* - `itemBadge` — right-aligned pill
|
|
16
|
-
* - `group` — wrapper around a group header + children
|
|
17
|
-
* - `groupHeader` — clickable header row (`<button>`)
|
|
18
|
-
* - `groupChildren` — `<ul>` containing the group's items
|
|
19
|
-
* - `footer` — bottom slot (user badge, etc.)
|
|
20
|
-
* - `collapseToggle` — rail-mode toggle button
|
|
21
|
-
*/
|
|
22
|
-
export const leftNavVariants = tv({
|
|
23
|
-
slots: {
|
|
24
|
-
root: [
|
|
25
|
-
'flex flex-col h-full',
|
|
26
|
-
'bg-neutral-50 border-r border-neutral-200',
|
|
27
|
-
// Width transition (rail-mode toggle) — gated on
|
|
28
|
-
// prefers-reduced-motion (WCAG 2.3.3). The new width still
|
|
29
|
-
// applies, just without the animated tween.
|
|
30
|
-
'transition-[width] duration-200 motion-reduce:transition-none motion-reduce:duration-0',
|
|
31
|
-
],
|
|
32
|
-
brand: [
|
|
33
|
-
'flex items-center gap-2 px-3 h-14 shrink-0',
|
|
34
|
-
'border-b border-neutral-200 text-neutral-900 font-semibold',
|
|
35
|
-
],
|
|
36
|
-
list: 'flex flex-col gap-0.5 p-2 flex-1 overflow-y-auto list-none m-0',
|
|
37
|
-
item: 'list-none',
|
|
38
|
-
itemLink: [
|
|
39
|
-
'flex items-center gap-2 px-2 py-2 rounded-md',
|
|
40
|
-
'text-sm text-neutral-700 hover:bg-neutral-100',
|
|
41
|
-
'outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50',
|
|
42
|
-
'transition-colors w-full',
|
|
43
|
-
'aria-disabled:opacity-50 aria-disabled:cursor-not-allowed',
|
|
44
|
-
'aria-disabled:hover:bg-transparent',
|
|
45
|
-
// Defensive `no-underline` — Tailwind's preflight removes the
|
|
46
|
-
// default browser anchor underline globally, but environments
|
|
47
|
-
// that DISABLE preflight (e.g. our docs-lab, where the tw
|
|
48
|
-
// section coexists with MUI's chrome) get raw browser defaults
|
|
49
|
-
// back. Without this, `<a>` items in the nav render underlined
|
|
50
|
-
// in those contexts. Explicit `no-underline` + `hover:no-underline`
|
|
51
|
-
// keeps the appearance consistent regardless of preflight state.
|
|
52
|
-
'no-underline hover:no-underline',
|
|
53
|
-
],
|
|
54
|
-
itemActive: 'bg-primary-100 text-primary-900 font-medium',
|
|
55
|
-
itemIcon: 'shrink-0 w-5 h-5 flex items-center justify-center',
|
|
56
|
-
itemLabel: 'truncate flex-1 min-w-0 text-left',
|
|
57
|
-
itemBadge: [
|
|
58
|
-
'shrink-0 inline-flex items-center justify-center',
|
|
59
|
-
'px-1.5 h-5 rounded-full text-[10px] font-medium',
|
|
60
|
-
'bg-neutral-200 text-neutral-800',
|
|
61
|
-
],
|
|
62
|
-
group: 'flex flex-col gap-0.5',
|
|
63
|
-
groupHeader: [
|
|
64
|
-
'flex items-center gap-2 px-2 py-2 rounded-md',
|
|
65
|
-
'text-sm font-medium text-neutral-900 hover:bg-neutral-100',
|
|
66
|
-
'outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50',
|
|
67
|
-
'transition-colors w-full',
|
|
68
|
-
],
|
|
69
|
-
groupChildren: 'flex flex-col gap-0.5 pl-6 list-none m-0',
|
|
70
|
-
footer: [
|
|
71
|
-
'border-t border-neutral-200 p-3 shrink-0',
|
|
72
|
-
'flex items-center gap-2',
|
|
73
|
-
],
|
|
74
|
-
collapseToggle: [
|
|
75
|
-
'inline-flex items-center justify-center w-8 h-8 shrink-0',
|
|
76
|
-
'rounded-md text-neutral-600 hover:bg-neutral-100',
|
|
77
|
-
'outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50',
|
|
78
|
-
'transition-colors',
|
|
79
|
-
],
|
|
80
|
-
},
|
|
81
|
-
variants: {
|
|
82
|
-
width: {
|
|
83
|
-
sm: { root: 'w-48' },
|
|
84
|
-
md: { root: 'w-60' },
|
|
85
|
-
lg: { root: 'w-72' },
|
|
86
|
-
},
|
|
87
|
-
collapsed: {
|
|
88
|
-
true: {
|
|
89
|
-
root: 'w-14',
|
|
90
|
-
brand: 'justify-center px-0',
|
|
91
|
-
list: 'p-1 items-center',
|
|
92
|
-
itemLink: 'justify-center px-0 py-2.5',
|
|
93
|
-
itemLabel: 'sr-only',
|
|
94
|
-
itemBadge: 'hidden',
|
|
95
|
-
groupHeader: 'justify-center px-0',
|
|
96
|
-
groupChildren: 'hidden',
|
|
97
|
-
footer: 'justify-center px-0',
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
defaultVariants: {
|
|
102
|
-
width: 'md',
|
|
103
|
-
collapsed: false,
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
export type LeftNavVariants = VariantProps<typeof leftNavVariants>;
|
|
@@ -1,408 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { describe, it, expect, vi, afterEach } from 'vitest';
|
|
4
|
-
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
|
|
5
|
-
import { RbacProvider } from '@dashforge/rbac';
|
|
6
|
-
import type { RbacPolicy, Subject } from '@dashforge/rbac';
|
|
7
|
-
import {
|
|
8
|
-
Menu,
|
|
9
|
-
MenuContent,
|
|
10
|
-
MenuItem,
|
|
11
|
-
MenuLabel,
|
|
12
|
-
MenuSeparator,
|
|
13
|
-
MenuSkeleton,
|
|
14
|
-
MenuTrigger,
|
|
15
|
-
} from './Menu.js';
|
|
16
|
-
|
|
17
|
-
void React;
|
|
18
|
-
afterEach(() => cleanup());
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Unit tests for the Menu family.
|
|
22
|
-
*
|
|
23
|
-
* Testing strategy: open the menu via `defaultOpen={true}` instead
|
|
24
|
-
* of clicking the trigger. Radix DropdownMenu's open/close flow
|
|
25
|
-
* uses pointer events that don't translate cleanly to jsdom's
|
|
26
|
-
* `fireEvent.click` — and that logic is Radix's responsibility
|
|
27
|
-
* anyway (already covered by their tests). Our tests focus on:
|
|
28
|
-
* - Our `<MenuItem>` props (onClick / disabled / selected / color /
|
|
29
|
-
* icon / endIcon)
|
|
30
|
-
* - Bridge integration on `<MenuItem>` (access / visibleWhen)
|
|
31
|
-
* - Our wrapper components (`<MenuLabel>`, `<MenuSeparator>`,
|
|
32
|
-
* `<MenuSkeleton>`)
|
|
33
|
-
* - `closeOnItemClick` propagation
|
|
34
|
-
*
|
|
35
|
-
* NB: Radix DropdownMenu uses Portal — when `defaultOpen={true}`,
|
|
36
|
-
* the content renders to `document.body`. We assert via
|
|
37
|
-
* `screen.getByText` / `screen.getByRole` which scan the whole
|
|
38
|
-
* document.
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
const NO_ACCESS_POLICY: RbacPolicy = {
|
|
42
|
-
roles: [{ name: 'guest', permissions: [] }],
|
|
43
|
-
};
|
|
44
|
-
const ADMIN_POLICY: RbacPolicy = {
|
|
45
|
-
roles: [
|
|
46
|
-
{
|
|
47
|
-
name: 'admin',
|
|
48
|
-
permissions: [{ resource: '*', action: '*', effect: 'allow' }],
|
|
49
|
-
},
|
|
50
|
-
],
|
|
51
|
-
};
|
|
52
|
-
const guestSubject: Subject = { id: 'g', roles: ['guest'] };
|
|
53
|
-
const adminSubject: Subject = { id: 'a', roles: ['admin'] };
|
|
54
|
-
|
|
55
|
-
describe('<Menu>', () => {
|
|
56
|
-
describe('rendering', () => {
|
|
57
|
-
it('renders the trigger', () => {
|
|
58
|
-
render(
|
|
59
|
-
<Menu>
|
|
60
|
-
<MenuTrigger>
|
|
61
|
-
<button>Open</button>
|
|
62
|
-
</MenuTrigger>
|
|
63
|
-
<MenuContent>
|
|
64
|
-
<MenuItem>Item</MenuItem>
|
|
65
|
-
</MenuContent>
|
|
66
|
-
</Menu>
|
|
67
|
-
);
|
|
68
|
-
expect(screen.getByRole('button', { name: /open/i })).toBeTruthy();
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('does NOT render content when closed (lazy mount)', () => {
|
|
72
|
-
render(
|
|
73
|
-
<Menu>
|
|
74
|
-
<MenuTrigger>
|
|
75
|
-
<button>Open</button>
|
|
76
|
-
</MenuTrigger>
|
|
77
|
-
<MenuContent>
|
|
78
|
-
<MenuItem>Hidden item</MenuItem>
|
|
79
|
-
</MenuContent>
|
|
80
|
-
</Menu>
|
|
81
|
-
);
|
|
82
|
-
// Without defaultOpen, Radix Portal isn't mounted.
|
|
83
|
-
expect(screen.queryByText('Hidden item')).toBeNull();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('renders content when defaultOpen=true', () => {
|
|
87
|
-
render(
|
|
88
|
-
<Menu defaultOpen>
|
|
89
|
-
<MenuTrigger>
|
|
90
|
-
<button>Open</button>
|
|
91
|
-
</MenuTrigger>
|
|
92
|
-
<MenuContent>
|
|
93
|
-
<MenuItem>Visible item</MenuItem>
|
|
94
|
-
</MenuContent>
|
|
95
|
-
</Menu>
|
|
96
|
-
);
|
|
97
|
-
expect(screen.getByText('Visible item')).toBeTruthy();
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe('MenuItem rendering', () => {
|
|
102
|
-
it('renders icon prop', () => {
|
|
103
|
-
render(
|
|
104
|
-
<Menu defaultOpen>
|
|
105
|
-
<MenuTrigger>
|
|
106
|
-
<button>Open</button>
|
|
107
|
-
</MenuTrigger>
|
|
108
|
-
<MenuContent>
|
|
109
|
-
<MenuItem icon={<span data-testid="icon">i</span>}>
|
|
110
|
-
With icon
|
|
111
|
-
</MenuItem>
|
|
112
|
-
</MenuContent>
|
|
113
|
-
</Menu>
|
|
114
|
-
);
|
|
115
|
-
expect(screen.getByTestId('icon')).toBeTruthy();
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('renders endIcon prop', () => {
|
|
119
|
-
render(
|
|
120
|
-
<Menu defaultOpen>
|
|
121
|
-
<MenuTrigger>
|
|
122
|
-
<button>Open</button>
|
|
123
|
-
</MenuTrigger>
|
|
124
|
-
<MenuContent>
|
|
125
|
-
<MenuItem endIcon={<span data-testid="end">⌘K</span>}>
|
|
126
|
-
Command
|
|
127
|
-
</MenuItem>
|
|
128
|
-
</MenuContent>
|
|
129
|
-
</Menu>
|
|
130
|
-
);
|
|
131
|
-
expect(screen.getByTestId('end')).toBeTruthy();
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
it('renders the children as label', () => {
|
|
135
|
-
render(
|
|
136
|
-
<Menu defaultOpen>
|
|
137
|
-
<MenuTrigger>
|
|
138
|
-
<button>Open</button>
|
|
139
|
-
</MenuTrigger>
|
|
140
|
-
<MenuContent>
|
|
141
|
-
<MenuItem>My label</MenuItem>
|
|
142
|
-
</MenuContent>
|
|
143
|
-
</Menu>
|
|
144
|
-
);
|
|
145
|
-
expect(screen.getByText('My label')).toBeTruthy();
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
describe('MenuItem disabled', () => {
|
|
150
|
-
it('marks the item as disabled', () => {
|
|
151
|
-
render(
|
|
152
|
-
<Menu defaultOpen>
|
|
153
|
-
<MenuTrigger>
|
|
154
|
-
<button>Open</button>
|
|
155
|
-
</MenuTrigger>
|
|
156
|
-
<MenuContent>
|
|
157
|
-
<MenuItem disabled>Save</MenuItem>
|
|
158
|
-
</MenuContent>
|
|
159
|
-
</Menu>
|
|
160
|
-
);
|
|
161
|
-
const item = screen.getByText('Save').closest('[role="menuitem"]');
|
|
162
|
-
expect(item?.getAttribute('data-disabled')).not.toBeNull();
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
describe('MenuItem selected visual', () => {
|
|
167
|
-
it('applies primary bg classes when selected', () => {
|
|
168
|
-
render(
|
|
169
|
-
<Menu defaultOpen>
|
|
170
|
-
<MenuTrigger>
|
|
171
|
-
<button>Open</button>
|
|
172
|
-
</MenuTrigger>
|
|
173
|
-
<MenuContent>
|
|
174
|
-
<MenuItem selected>Theme: light</MenuItem>
|
|
175
|
-
</MenuContent>
|
|
176
|
-
</Menu>
|
|
177
|
-
);
|
|
178
|
-
const item = screen.getByText('Theme: light').closest('[role="menuitem"]');
|
|
179
|
-
expect(item?.className).toContain('bg-primary-50');
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('does NOT apply primary bg when not selected', () => {
|
|
183
|
-
render(
|
|
184
|
-
<Menu defaultOpen>
|
|
185
|
-
<MenuTrigger>
|
|
186
|
-
<button>Open</button>
|
|
187
|
-
</MenuTrigger>
|
|
188
|
-
<MenuContent>
|
|
189
|
-
<MenuItem>Theme: light</MenuItem>
|
|
190
|
-
</MenuContent>
|
|
191
|
-
</Menu>
|
|
192
|
-
);
|
|
193
|
-
const item = screen.getByText('Theme: light').closest('[role="menuitem"]');
|
|
194
|
-
expect(item?.className).not.toContain('bg-primary-50');
|
|
195
|
-
});
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
describe('MenuItem color="danger"', () => {
|
|
199
|
-
it('applies danger text class', () => {
|
|
200
|
-
render(
|
|
201
|
-
<Menu defaultOpen>
|
|
202
|
-
<MenuTrigger>
|
|
203
|
-
<button>Open</button>
|
|
204
|
-
</MenuTrigger>
|
|
205
|
-
<MenuContent>
|
|
206
|
-
<MenuItem color="danger">Delete</MenuItem>
|
|
207
|
-
</MenuContent>
|
|
208
|
-
</Menu>
|
|
209
|
-
);
|
|
210
|
-
const item = screen.getByText('Delete').closest('[role="menuitem"]');
|
|
211
|
-
expect(item?.className).toContain('text-danger-700');
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('default color does NOT apply danger class', () => {
|
|
215
|
-
render(
|
|
216
|
-
<Menu defaultOpen>
|
|
217
|
-
<MenuTrigger>
|
|
218
|
-
<button>Open</button>
|
|
219
|
-
</MenuTrigger>
|
|
220
|
-
<MenuContent>
|
|
221
|
-
<MenuItem>Default</MenuItem>
|
|
222
|
-
</MenuContent>
|
|
223
|
-
</Menu>
|
|
224
|
-
);
|
|
225
|
-
const item = screen.getByText('Default').closest('[role="menuitem"]');
|
|
226
|
-
expect(item?.className).not.toContain('text-danger-700');
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
describe('MenuItem access RBAC', () => {
|
|
231
|
-
it('hides the item for unauthorized subjects (onUnauthorized="hide")', () => {
|
|
232
|
-
render(
|
|
233
|
-
<RbacProvider policy={NO_ACCESS_POLICY} subject={guestSubject}>
|
|
234
|
-
<Menu defaultOpen>
|
|
235
|
-
<MenuTrigger>
|
|
236
|
-
<button>Open</button>
|
|
237
|
-
</MenuTrigger>
|
|
238
|
-
<MenuContent>
|
|
239
|
-
<MenuItem>Public</MenuItem>
|
|
240
|
-
<MenuItem
|
|
241
|
-
access={{
|
|
242
|
-
resource: 'admin',
|
|
243
|
-
action: 'manage',
|
|
244
|
-
onUnauthorized: 'hide',
|
|
245
|
-
}}
|
|
246
|
-
>
|
|
247
|
-
Admin-only
|
|
248
|
-
</MenuItem>
|
|
249
|
-
</MenuContent>
|
|
250
|
-
</Menu>
|
|
251
|
-
</RbacProvider>
|
|
252
|
-
);
|
|
253
|
-
expect(screen.getByText('Public')).toBeTruthy();
|
|
254
|
-
expect(screen.queryByText('Admin-only')).toBeNull();
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
it('renders for authorized subjects', () => {
|
|
258
|
-
render(
|
|
259
|
-
<RbacProvider policy={ADMIN_POLICY} subject={adminSubject}>
|
|
260
|
-
<Menu defaultOpen>
|
|
261
|
-
<MenuTrigger>
|
|
262
|
-
<button>Open</button>
|
|
263
|
-
</MenuTrigger>
|
|
264
|
-
<MenuContent>
|
|
265
|
-
<MenuItem
|
|
266
|
-
access={{
|
|
267
|
-
resource: 'admin',
|
|
268
|
-
action: 'manage',
|
|
269
|
-
onUnauthorized: 'hide',
|
|
270
|
-
}}
|
|
271
|
-
>
|
|
272
|
-
Admin-only
|
|
273
|
-
</MenuItem>
|
|
274
|
-
</MenuContent>
|
|
275
|
-
</Menu>
|
|
276
|
-
</RbacProvider>
|
|
277
|
-
);
|
|
278
|
-
expect(screen.getByText('Admin-only')).toBeTruthy();
|
|
279
|
-
});
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
describe('MenuItem visibleWhen', () => {
|
|
283
|
-
it('renders when predicate returns true', () => {
|
|
284
|
-
render(
|
|
285
|
-
<Menu defaultOpen>
|
|
286
|
-
<MenuTrigger>
|
|
287
|
-
<button>Open</button>
|
|
288
|
-
</MenuTrigger>
|
|
289
|
-
<MenuContent>
|
|
290
|
-
<MenuItem visibleWhen={() => true}>Shown</MenuItem>
|
|
291
|
-
</MenuContent>
|
|
292
|
-
</Menu>
|
|
293
|
-
);
|
|
294
|
-
expect(screen.getByText('Shown')).toBeTruthy();
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
it('returns null when predicate returns false', () => {
|
|
298
|
-
render(
|
|
299
|
-
<Menu defaultOpen>
|
|
300
|
-
<MenuTrigger>
|
|
301
|
-
<button>Open</button>
|
|
302
|
-
</MenuTrigger>
|
|
303
|
-
<MenuContent>
|
|
304
|
-
<MenuItem>Always shown</MenuItem>
|
|
305
|
-
<MenuItem visibleWhen={() => false}>Hidden</MenuItem>
|
|
306
|
-
</MenuContent>
|
|
307
|
-
</Menu>
|
|
308
|
-
);
|
|
309
|
-
expect(screen.getByText('Always shown')).toBeTruthy();
|
|
310
|
-
expect(screen.queryByText('Hidden')).toBeNull();
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
describe('MenuLabel + MenuSeparator', () => {
|
|
315
|
-
it('renders MenuLabel content', () => {
|
|
316
|
-
render(
|
|
317
|
-
<Menu defaultOpen>
|
|
318
|
-
<MenuTrigger>
|
|
319
|
-
<button>Open</button>
|
|
320
|
-
</MenuTrigger>
|
|
321
|
-
<MenuContent>
|
|
322
|
-
<MenuLabel>Section heading</MenuLabel>
|
|
323
|
-
<MenuItem>Item</MenuItem>
|
|
324
|
-
</MenuContent>
|
|
325
|
-
</Menu>
|
|
326
|
-
);
|
|
327
|
-
expect(screen.getByText('Section heading')).toBeTruthy();
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
it('renders MenuSeparator with role="separator"', () => {
|
|
331
|
-
const { baseElement } = render(
|
|
332
|
-
<Menu defaultOpen>
|
|
333
|
-
<MenuTrigger>
|
|
334
|
-
<button>Open</button>
|
|
335
|
-
</MenuTrigger>
|
|
336
|
-
<MenuContent>
|
|
337
|
-
<MenuItem>Above</MenuItem>
|
|
338
|
-
<MenuSeparator />
|
|
339
|
-
<MenuItem>Below</MenuItem>
|
|
340
|
-
</MenuContent>
|
|
341
|
-
</Menu>
|
|
342
|
-
);
|
|
343
|
-
const sep = baseElement.querySelector('[role="separator"]');
|
|
344
|
-
expect(sep).toBeTruthy();
|
|
345
|
-
});
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
describe('overrides — sx + className', () => {
|
|
349
|
-
it('applies sx to a MenuItem', () => {
|
|
350
|
-
render(
|
|
351
|
-
<Menu defaultOpen>
|
|
352
|
-
<MenuTrigger>
|
|
353
|
-
<button>Open</button>
|
|
354
|
-
</MenuTrigger>
|
|
355
|
-
<MenuContent>
|
|
356
|
-
<MenuItem sx="ring-2 ring-purple-500">x</MenuItem>
|
|
357
|
-
</MenuContent>
|
|
358
|
-
</Menu>
|
|
359
|
-
);
|
|
360
|
-
const item = screen.getByText('x').closest('[role="menuitem"]');
|
|
361
|
-
expect(item?.className).toContain('ring-purple-500');
|
|
362
|
-
});
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
// ─── MenuSkeleton — standalone tests (no Menu wrapper) ───────────
|
|
367
|
-
|
|
368
|
-
describe('<MenuSkeleton>', () => {
|
|
369
|
-
it('renders the default 3 placeholder rows', () => {
|
|
370
|
-
const { container } = render(<MenuSkeleton />);
|
|
371
|
-
// Each row is a div with the inline pulse classes; we match on
|
|
372
|
-
// the unique "h-3 flex-1 rounded-sm bg-neutral-200" inline bone.
|
|
373
|
-
const rows = container.querySelectorAll('.h-3.flex-1.rounded-sm');
|
|
374
|
-
expect(rows.length).toBe(3);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it('renders custom count', () => {
|
|
378
|
-
const { container } = render(<MenuSkeleton count={7} />);
|
|
379
|
-
const rows = container.querySelectorAll('.h-3.flex-1.rounded-sm');
|
|
380
|
-
expect(rows.length).toBe(7);
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
it('renders a skeleton heading when withHeading=true', () => {
|
|
384
|
-
const { container } = render(<MenuSkeleton withHeading />);
|
|
385
|
-
// Heading is the .uppercase wrapper (matches the MenuLabel style).
|
|
386
|
-
expect(container.querySelector('.uppercase')).toBeTruthy();
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
it('omits the heading by default', () => {
|
|
390
|
-
const { container } = render(<MenuSkeleton />);
|
|
391
|
-
expect(container.querySelector('.uppercase')).toBeNull();
|
|
392
|
-
});
|
|
393
|
-
|
|
394
|
-
it('has aria-hidden="true" (decorative)', () => {
|
|
395
|
-
const { container } = render(<MenuSkeleton />);
|
|
396
|
-
expect(container.firstElementChild?.getAttribute('aria-hidden')).toBe(
|
|
397
|
-
'true'
|
|
398
|
-
);
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
it('uses animate-pulse class (motion-reduce-safe)', () => {
|
|
402
|
-
const { container } = render(<MenuSkeleton />);
|
|
403
|
-
expect(container.firstElementChild?.className).toContain('animate-pulse');
|
|
404
|
-
expect(container.firstElementChild?.className).toContain(
|
|
405
|
-
'motion-reduce:animate-none'
|
|
406
|
-
);
|
|
407
|
-
});
|
|
408
|
-
});
|