@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,159 +0,0 @@
|
|
|
1
|
-
import { forwardRef, useContext } from 'react';
|
|
2
|
-
import { Slot } from '@radix-ui/react-slot';
|
|
3
|
-
import { DashFormContext, useEngineVisibility } from '@dashforge/ui-core';
|
|
4
|
-
import { cn } from '../../utils/cn.js';
|
|
5
|
-
import { useAccessState } from '../../hooks/useAccessState.js';
|
|
6
|
-
import { buttonVariants } from '../Button/button.variants.js';
|
|
7
|
-
import { Spinner } from '../Spinner/Spinner.js';
|
|
8
|
-
import type { SpinnerSize } from '../Spinner/spinner.types.js';
|
|
9
|
-
import {
|
|
10
|
-
ICON_BUTTON_BASE,
|
|
11
|
-
ICON_BUTTON_SIZE_OVERRIDES,
|
|
12
|
-
} from './iconButton.variants.js';
|
|
13
|
-
import type { IconButtonProps } from './iconButton.types.js';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Map IconButton size to Spinner size. Same mapping as Button —
|
|
17
|
-
* Spinner has 5 steps, the parent has 3.
|
|
18
|
-
*
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
function iconButtonSizeToSpinnerSize(size: 'sm' | 'md' | 'lg'): SpinnerSize {
|
|
22
|
-
return size === 'sm' ? 'xs' : size === 'lg' ? 'md' : 'sm';
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Dashforge TW IconButton — square, icon-only action button.
|
|
27
|
-
*
|
|
28
|
-
* Reuses `buttonVariants` 1:1 (same `variant` / `color` / `size` /
|
|
29
|
-
* `loading` axes) so every `<Button>` style maps to the equivalent
|
|
30
|
-
* `<IconButton>` with zero code duplication. The ONLY additions are:
|
|
31
|
-
*
|
|
32
|
-
* - `ICON_BUTTON_SIZE_OVERRIDES` — forces `w-N + px-0` so the button
|
|
33
|
-
* is square at every size token
|
|
34
|
-
* - `ICON_BUTTON_BASE` — `aspect-square inline-flex items-center
|
|
35
|
-
* justify-center` for layout
|
|
36
|
-
*
|
|
37
|
-
* Both additions are token-driven (spacing) or layout-primitive
|
|
38
|
-
* (geometry) — no hardcoded hex, no `dark:` variants.
|
|
39
|
-
*
|
|
40
|
-
* **`aria-label` is REQUIRED** at the type level — icon-only buttons
|
|
41
|
-
* are invisible to assistive tech without an explicit accessible
|
|
42
|
-
* name. The TypeScript compiler enforces this rather than relying on
|
|
43
|
-
* runtime warnings.
|
|
44
|
-
*
|
|
45
|
-
* RBAC integration mirrors `<Button>`: `access` with
|
|
46
|
-
* `onUnauthorized: 'hide' | 'disable' | 'readonly'`. No `visibleWhen`
|
|
47
|
-
* (mirror Button — buttons should disable, not hide, on
|
|
48
|
-
* state-driven unavailability; permission-driven hiding is `access`).
|
|
49
|
-
*
|
|
50
|
-
* @example
|
|
51
|
-
* ```tsx
|
|
52
|
-
* import { Trash2 } from 'lucide-react';
|
|
53
|
-
*
|
|
54
|
-
* <IconButton aria-label="Delete row" color="danger" onClick={onDelete}>
|
|
55
|
-
* <Trash2 size={20} />
|
|
56
|
-
* </IconButton>
|
|
57
|
-
*
|
|
58
|
-
* // Polymorphism via Radix Slot
|
|
59
|
-
* <IconButton asChild aria-label="Open settings" variant="ghost">
|
|
60
|
-
* <Link to="/settings"><SettingsIcon size={20} /></Link>
|
|
61
|
-
* </IconButton>
|
|
62
|
-
*
|
|
63
|
-
* // RBAC-gated
|
|
64
|
-
* <IconButton
|
|
65
|
-
* aria-label="Publish article"
|
|
66
|
-
* variant="solid"
|
|
67
|
-
* color="primary"
|
|
68
|
-
* access={{ resource: 'article', action: 'publish', onUnauthorized: 'disable' }}
|
|
69
|
-
* >
|
|
70
|
-
* <PublishIcon size={20} />
|
|
71
|
-
* </IconButton>
|
|
72
|
-
*
|
|
73
|
-
* // Loading swap
|
|
74
|
-
* <IconButton aria-label="Save" loading={isSaving}>
|
|
75
|
-
* <SaveIcon size={20} />
|
|
76
|
-
* </IconButton>
|
|
77
|
-
* ```
|
|
78
|
-
*/
|
|
79
|
-
export const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(
|
|
80
|
-
function IconButton(props, ref) {
|
|
81
|
-
const {
|
|
82
|
-
access,
|
|
83
|
-
visibleWhen,
|
|
84
|
-
disabled,
|
|
85
|
-
variant,
|
|
86
|
-
color,
|
|
87
|
-
size = 'md',
|
|
88
|
-
loading,
|
|
89
|
-
asChild,
|
|
90
|
-
sx,
|
|
91
|
-
className,
|
|
92
|
-
children,
|
|
93
|
-
...rest
|
|
94
|
-
} = props;
|
|
95
|
-
|
|
96
|
-
// Bridge — both hooks called unconditionally (rules-of-hooks).
|
|
97
|
-
const bridge = useContext(DashFormContext);
|
|
98
|
-
const isVisible = useEngineVisibility(bridge?.engine, visibleWhen);
|
|
99
|
-
const accessState = useAccessState(access);
|
|
100
|
-
if (!isVisible || !accessState.visible) return null;
|
|
101
|
-
|
|
102
|
-
// Effective disabled = explicit OR RBAC.disabled OR RBAC.readonly OR loading.
|
|
103
|
-
// Mirrors `<Button>` exactly — IconButton has no true read-only
|
|
104
|
-
// state, so RBAC readonly maps to disabled (same as MUI side).
|
|
105
|
-
const effectiveDisabled =
|
|
106
|
-
Boolean(disabled) ||
|
|
107
|
-
accessState.disabled ||
|
|
108
|
-
accessState.readonly ||
|
|
109
|
-
Boolean(loading);
|
|
110
|
-
|
|
111
|
-
const classes = cn(
|
|
112
|
-
buttonVariants({ variant, color, size, loading }),
|
|
113
|
-
ICON_BUTTON_SIZE_OVERRIDES[size],
|
|
114
|
-
ICON_BUTTON_BASE,
|
|
115
|
-
sx,
|
|
116
|
-
className
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
// `aria-busy` while loading — distinguishes "wait for action to
|
|
120
|
-
// finish" from "you can't do this" in screen-reader announcements.
|
|
121
|
-
const ariaBusy = loading ? true : undefined;
|
|
122
|
-
|
|
123
|
-
if (asChild) {
|
|
124
|
-
return (
|
|
125
|
-
<Slot
|
|
126
|
-
ref={ref}
|
|
127
|
-
className={classes}
|
|
128
|
-
data-disabled={effectiveDisabled || undefined}
|
|
129
|
-
aria-disabled={effectiveDisabled || undefined}
|
|
130
|
-
aria-busy={ariaBusy}
|
|
131
|
-
>
|
|
132
|
-
{children}
|
|
133
|
-
</Slot>
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<button
|
|
139
|
-
ref={ref}
|
|
140
|
-
type={rest.type ?? 'button'}
|
|
141
|
-
disabled={effectiveDisabled}
|
|
142
|
-
aria-busy={ariaBusy}
|
|
143
|
-
className={classes}
|
|
144
|
-
{...rest}
|
|
145
|
-
>
|
|
146
|
-
{loading ? (
|
|
147
|
-
<Spinner
|
|
148
|
-
size={iconButtonSizeToSpinnerSize(size)}
|
|
149
|
-
thickness="thick"
|
|
150
|
-
withTrack
|
|
151
|
-
label=""
|
|
152
|
-
/>
|
|
153
|
-
) : (
|
|
154
|
-
children
|
|
155
|
-
)}
|
|
156
|
-
</button>
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
);
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import type { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
2
|
-
import type { ClassValue } from 'tailwind-variants';
|
|
3
|
-
import type { Engine } from '@dashforge/ui-core';
|
|
4
|
-
import type { AccessRequirement } from '@dashforge/rbac';
|
|
5
|
-
import type { ButtonVariants } from '../Button/button.variants.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Props for `<IconButton>`.
|
|
9
|
-
*
|
|
10
|
-
* IconButton is the **icon-only variant of `<Button>`** — it reuses
|
|
11
|
-
* `buttonVariants` 1:1 (same `variant` × `color` × `size` × `loading`
|
|
12
|
-
* compound matrix) and adds:
|
|
13
|
-
*
|
|
14
|
-
* - Square geometry (width = height = size token, `aspect-square`)
|
|
15
|
-
* - Zero horizontal padding (no text to pad around)
|
|
16
|
-
* - **`aria-label` REQUIRED** at the type level — icon-only buttons
|
|
17
|
-
* are invisible to screen readers without an explicit label, so we
|
|
18
|
-
* enforce it via TypeScript rather than runtime warning.
|
|
19
|
-
*
|
|
20
|
-
* Notes on excluded props (deliberate parity with `<Button>`):
|
|
21
|
-
* - **No `slotProps`** — IconButton renders a single DOM element
|
|
22
|
-
* (`<button>` plus a transient loading swap); `className` + `sx`
|
|
23
|
-
* cover the override surface fully, matching Button.
|
|
24
|
-
* - **No `fullWidth`** — meaningless on an icon-sized button.
|
|
25
|
-
*
|
|
26
|
-
* As of 1.1.0 (Sprint 4.4 alignment), IconButton + Button both
|
|
27
|
-
* support `visibleWhen` — see prop docs below.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```tsx
|
|
31
|
-
* import { TrashIcon } from 'lucide-react';
|
|
32
|
-
*
|
|
33
|
-
* <IconButton aria-label="Delete row" color="danger" onClick={onDelete}>
|
|
34
|
-
* <TrashIcon size={20} />
|
|
35
|
-
* </IconButton>
|
|
36
|
-
*
|
|
37
|
-
* // Polymorphism via Radix Slot — wrap a router Link without nesting
|
|
38
|
-
* // a button inside an anchor.
|
|
39
|
-
* <IconButton asChild aria-label="Open settings" variant="ghost">
|
|
40
|
-
* <Link to="/settings"><SettingsIcon size={20} /></Link>
|
|
41
|
-
* </IconButton>
|
|
42
|
-
*
|
|
43
|
-
* // RBAC-gated
|
|
44
|
-
* <IconButton
|
|
45
|
-
* aria-label="Publish article"
|
|
46
|
-
* variant="solid"
|
|
47
|
-
* color="primary"
|
|
48
|
-
* access={{ resource: 'article', action: 'publish', onUnauthorized: 'disable' }}
|
|
49
|
-
* >
|
|
50
|
-
* <PublishIcon size={20} />
|
|
51
|
-
* </IconButton>
|
|
52
|
-
* ```
|
|
53
|
-
*/
|
|
54
|
-
export interface IconButtonProps
|
|
55
|
-
extends Omit<
|
|
56
|
-
ButtonHTMLAttributes<HTMLButtonElement>,
|
|
57
|
-
'color' | 'children'
|
|
58
|
-
>,
|
|
59
|
-
Pick<ButtonVariants, 'variant' | 'color' | 'size' | 'loading'> {
|
|
60
|
-
/**
|
|
61
|
-
* The icon — typically an SVG element from the consumer's icon
|
|
62
|
-
* library (Lucide / Phosphor / Tabler / inline SVG). A single
|
|
63
|
-
* `ReactNode` is expected.
|
|
64
|
-
*/
|
|
65
|
-
children: ReactNode;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Required at the type level — icon-only buttons MUST have an
|
|
69
|
-
* accessible name. Pass a short verb phrase describing the action
|
|
70
|
-
* (e.g. `"Delete row"`, `"Open settings"`, NOT `"Trash icon"`).
|
|
71
|
-
*/
|
|
72
|
-
'aria-label': string;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Render-as-child via Radix Slot — the resolved IconButton
|
|
76
|
-
* className is forwarded to the immediate child element, no
|
|
77
|
-
* `<button>` DOM is emitted. Useful for router `<Link>`s.
|
|
78
|
-
* Same contract as `<Button asChild>`.
|
|
79
|
-
*/
|
|
80
|
-
asChild?: boolean;
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* RBAC requirement. When the current subject doesn't satisfy the
|
|
84
|
-
* requirement, the button is hidden / disabled / read-only per
|
|
85
|
-
* `onUnauthorized`. Same contract as `<Button access>`.
|
|
86
|
-
*/
|
|
87
|
-
access?: AccessRequirement;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Reactive visibility predicate — same contract as `<Button>` and
|
|
91
|
-
* `<Chip>`. When the predicate returns `false`, the component
|
|
92
|
-
* renders `null`. Inside a `<DashForm>` it subscribes to engine
|
|
93
|
-
* state and re-evaluates on every change; outside a form, it's
|
|
94
|
-
* called with `null` engine (capture external state in closure).
|
|
95
|
-
*
|
|
96
|
-
* Added in 1.1.0 (Sprint 4.4 alignment) to keep IconButton in
|
|
97
|
-
* lockstep with Button.
|
|
98
|
-
*/
|
|
99
|
-
visibleWhen?: (engine: Engine) => boolean;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Root-element class shortcut (string or `clsx`-compatible value).
|
|
103
|
-
* Last-wins via `tailwind-merge` inside `cn()`.
|
|
104
|
-
*/
|
|
105
|
-
sx?: ClassValue;
|
|
106
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import type { ButtonVariants } from '../Button/button.variants.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* IconButton size overrides — applied ON TOP of `buttonVariants(...)`.
|
|
5
|
-
*
|
|
6
|
-
* Button's `size` axis sets `h-X` + `px-Y` (rectangular). For
|
|
7
|
-
* IconButton we need a SQUARE shape, so we:
|
|
8
|
-
* - zero out the horizontal padding (`px-0`)
|
|
9
|
-
* - set an explicit width that matches the height (`w-N` mirrors the
|
|
10
|
-
* `h-N` from Button's size variant)
|
|
11
|
-
*
|
|
12
|
-
* The `aspect-square` utility provides belt-and-braces in the edge
|
|
13
|
-
* case where Tailwind purges the explicit `w-N` (e.g., when the user
|
|
14
|
-
* passes `size` dynamically and the JIT can't statically see all
|
|
15
|
-
* combinations).
|
|
16
|
-
*
|
|
17
|
-
* Token propagation: `w-N` resolves to `var(--df-tw-spacing-N)`
|
|
18
|
-
* through `dashforgePreset()`, identical to how `h-N` works for
|
|
19
|
-
* Button. `patchTheme({ spacing: { 10: '2.75rem' } })` patches both
|
|
20
|
-
* Button height and IconButton size in lockstep.
|
|
21
|
-
*/
|
|
22
|
-
type IconButtonSize = NonNullable<ButtonVariants['size']>;
|
|
23
|
-
|
|
24
|
-
export const ICON_BUTTON_SIZE_OVERRIDES: Record<IconButtonSize, string> = {
|
|
25
|
-
sm: 'w-8 px-0',
|
|
26
|
-
md: 'w-10 px-0',
|
|
27
|
-
lg: 'w-12 px-0',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
/** Always-applied layout primitives — not token-driven (geometric CSS). */
|
|
31
|
-
export const ICON_BUTTON_BASE = 'aspect-square inline-flex items-center justify-center';
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
/**
|
|
3
|
-
* Performance + re-render budget tests for `<LeftNav>`.
|
|
4
|
-
*
|
|
5
|
-
* Layout sidebar is the most expensive layout primitive — it can
|
|
6
|
-
* easily host 50+ rows, each with RBAC checks. Guardrails:
|
|
7
|
-
*
|
|
8
|
-
* 1. Mount cost bounded for realistic + worst-case row counts.
|
|
9
|
-
* 2. `activeId` change only re-renders the rows that need re-styling
|
|
10
|
-
* (today: all rows re-render because we don't `React.memo` them,
|
|
11
|
-
* but the total time is still bounded).
|
|
12
|
-
* 3. Group expand/collapse only re-renders THAT group.
|
|
13
|
-
* 4. Toggling `collapsed` does not allocate per-item maps.
|
|
14
|
-
*/
|
|
15
|
-
import * as React from 'react';
|
|
16
|
-
import { describe, it, expect, afterEach } from 'vitest';
|
|
17
|
-
import {
|
|
18
|
-
render,
|
|
19
|
-
screen,
|
|
20
|
-
fireEvent,
|
|
21
|
-
cleanup,
|
|
22
|
-
} from '@testing-library/react';
|
|
23
|
-
import { LeftNav } from './LeftNav.js';
|
|
24
|
-
import type { LeftNavNode } from './leftNav.types.js';
|
|
25
|
-
|
|
26
|
-
void React;
|
|
27
|
-
afterEach(() => cleanup());
|
|
28
|
-
|
|
29
|
-
function makeFlatNav(n: number): LeftNavNode[] {
|
|
30
|
-
return Array.from({ length: n }, (_, i) => ({
|
|
31
|
-
id: `r${i}`,
|
|
32
|
-
label: `Row ${i}`,
|
|
33
|
-
href: `/r${i}`,
|
|
34
|
-
}));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function makeNestedNav(groups: number, perGroup: number): LeftNavNode[] {
|
|
38
|
-
return Array.from({ length: groups }, (_, g) => ({
|
|
39
|
-
kind: 'group' as const,
|
|
40
|
-
id: `g${g}`,
|
|
41
|
-
label: `Group ${g}`,
|
|
42
|
-
children: Array.from({ length: perGroup }, (_, i) => ({
|
|
43
|
-
id: `g${g}-r${i}`,
|
|
44
|
-
label: `Row ${i}`,
|
|
45
|
-
href: `/g${g}/r${i}`,
|
|
46
|
-
})),
|
|
47
|
-
}));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function withRenderCounter<P>(
|
|
51
|
-
Component: React.ComponentType<P>,
|
|
52
|
-
counterRef: { count: number }
|
|
53
|
-
): React.FC<P> {
|
|
54
|
-
return function Counted(props: P) {
|
|
55
|
-
counterRef.count++;
|
|
56
|
-
return <Component {...(props as P & object)} />;
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
describe('<LeftNav> performance', () => {
|
|
61
|
-
it('mounts a realistic 30-row flat nav in under 50ms', () => {
|
|
62
|
-
const items = makeFlatNav(30);
|
|
63
|
-
const t0 = performance.now();
|
|
64
|
-
render(<LeftNav items={items} />);
|
|
65
|
-
const t1 = performance.now();
|
|
66
|
-
expect(t1 - t0).toBeLessThan(50);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('mounts a 300-row flat nav in under 250ms', () => {
|
|
70
|
-
const items = makeFlatNav(300);
|
|
71
|
-
const t0 = performance.now();
|
|
72
|
-
render(<LeftNav items={items} />);
|
|
73
|
-
const t1 = performance.now();
|
|
74
|
-
expect(t1 - t0).toBeLessThan(250);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('mounts a 10×10 nested nav (100 leaf rows) in under 150ms', () => {
|
|
78
|
-
const items = makeNestedNav(10, 10);
|
|
79
|
-
const t0 = performance.now();
|
|
80
|
-
render(<LeftNav items={items} />);
|
|
81
|
-
const t1 = performance.now();
|
|
82
|
-
expect(t1 - t0).toBeLessThan(150);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it('toggles `collapsed` in under 100ms (30 rows)', () => {
|
|
86
|
-
const items = makeFlatNav(30);
|
|
87
|
-
const { rerender } = render(<LeftNav items={items} />);
|
|
88
|
-
const t0 = performance.now();
|
|
89
|
-
rerender(<LeftNav items={items} collapsed />);
|
|
90
|
-
const t1 = performance.now();
|
|
91
|
-
expect(t1 - t0).toBeLessThan(100);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
describe('<LeftNav> re-render budget', () => {
|
|
96
|
-
it('renders at most 2 times on mount (top-level wrapper)', () => {
|
|
97
|
-
const counter = { count: 0 };
|
|
98
|
-
const Counted = withRenderCounter(LeftNav, counter);
|
|
99
|
-
render(<Counted items={makeFlatNav(10)} />);
|
|
100
|
-
expect(counter.count).toBeLessThanOrEqual(2);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it('does NOT re-render the wrapper when a group expands locally', () => {
|
|
104
|
-
// Group state is local — flipping it must not bubble a re-render
|
|
105
|
-
// up to the LeftNav wrapper.
|
|
106
|
-
const counter = { count: 0 };
|
|
107
|
-
const Counted = withRenderCounter(LeftNav, counter);
|
|
108
|
-
render(<Counted items={makeNestedNav(2, 3)} />);
|
|
109
|
-
const baseline = counter.count;
|
|
110
|
-
const header = screen.getByRole('button', { name: /Group 0/ });
|
|
111
|
-
fireEvent.click(header);
|
|
112
|
-
fireEvent.click(header);
|
|
113
|
-
fireEvent.click(header);
|
|
114
|
-
expect(counter.count).toBe(baseline);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('does NOT re-render an unrelated sibling when collapsing the nav', () => {
|
|
118
|
-
const sibCount = { count: 0 };
|
|
119
|
-
const Sibling = () => {
|
|
120
|
-
sibCount.count++;
|
|
121
|
-
return <div data-testid="sib" />;
|
|
122
|
-
};
|
|
123
|
-
const Shell = ({ collapsed }: { collapsed: boolean }) => (
|
|
124
|
-
<div>
|
|
125
|
-
<LeftNav items={makeFlatNav(20)} collapsed={collapsed} />
|
|
126
|
-
<Sibling />
|
|
127
|
-
</div>
|
|
128
|
-
);
|
|
129
|
-
const { rerender } = render(<Shell collapsed={false} />);
|
|
130
|
-
const baseline = sibCount.count;
|
|
131
|
-
rerender(<Shell collapsed={true} />);
|
|
132
|
-
// 1 parent re-render → 1 sibling re-render. Allow 1 extra for
|
|
133
|
-
// React strict-mode or commit-phase double-invocation in dev.
|
|
134
|
-
expect(sibCount.count - baseline).toBeLessThanOrEqual(2);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('activeId change updates aria-current without throwing', () => {
|
|
138
|
-
const items = makeFlatNav(5);
|
|
139
|
-
const { rerender } = render(
|
|
140
|
-
<LeftNav items={items} activeId="r0" />
|
|
141
|
-
);
|
|
142
|
-
expect(
|
|
143
|
-
screen.getByRole('link', { name: 'Row 0' }).getAttribute('aria-current')
|
|
144
|
-
).toBe('page');
|
|
145
|
-
rerender(<LeftNav items={items} activeId="r3" />);
|
|
146
|
-
expect(
|
|
147
|
-
screen.getByRole('link', { name: 'Row 0' }).getAttribute('aria-current')
|
|
148
|
-
).toBeNull();
|
|
149
|
-
expect(
|
|
150
|
-
screen.getByRole('link', { name: 'Row 3' }).getAttribute('aria-current')
|
|
151
|
-
).toBe('page');
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('group expanded state is preserved across parent re-renders', () => {
|
|
155
|
-
// Local state inside `<NavGroupRow>` must survive a parent
|
|
156
|
-
// re-render. Without this, every `activeId` change would reset
|
|
157
|
-
// every group to its `defaultExpanded`, which would be terrible UX.
|
|
158
|
-
const items = makeNestedNav(2, 3);
|
|
159
|
-
const { container, rerender } = render(
|
|
160
|
-
<LeftNav items={items} activeId="g0-r0" />
|
|
161
|
-
);
|
|
162
|
-
// Collapse Group 0 — Group 0's first child href becomes invisible.
|
|
163
|
-
fireEvent.click(screen.getByRole('button', { name: /Group 0/ }));
|
|
164
|
-
const g0Child = () =>
|
|
165
|
-
container.querySelector('a[href="/g0/r0"]');
|
|
166
|
-
expect(g0Child()).toBeNull();
|
|
167
|
-
// Now change activeId to a row in Group 1.
|
|
168
|
-
rerender(<LeftNav items={items} activeId="g1-r0" />);
|
|
169
|
-
// Group 0 must STAY collapsed (local state survived parent re-render).
|
|
170
|
-
expect(g0Child()).toBeNull();
|
|
171
|
-
});
|
|
172
|
-
});
|