@multiplatform.one/components 7.8.0 → 7.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/dist/cjs/Accordion/index.cjs +3 -3
- package/dist/cjs/Accordion/index.native.js +4 -4
- package/dist/cjs/Accordion/index.native.js.map +1 -1
- package/dist/cjs/Chip/index.cjs +1 -1
- package/dist/cjs/Chip/index.native.js +1 -1
- package/dist/cjs/Chip/index.native.js.map +1 -1
- package/dist/cjs/ContextMenu/index.cjs +3 -3
- package/dist/cjs/ContextMenu/index.native.js +3 -3
- package/dist/cjs/ContextMenu/index.native.js.map +1 -1
- package/dist/cjs/DropdownMenu/index.cjs +3 -3
- package/dist/cjs/DropdownMenu/index.native.js +3 -3
- package/dist/cjs/DropdownMenu/index.native.js.map +1 -1
- package/dist/cjs/Meter/index.cjs +3 -2
- package/dist/cjs/Meter/index.native.js +3 -2
- package/dist/cjs/Meter/index.native.js.map +1 -1
- package/dist/cjs/Meter/meter.cjs +1 -2
- package/dist/cjs/Meter/meter.native.js +1 -2
- package/dist/cjs/Meter/meter.native.js.map +1 -1
- package/dist/cjs/Pagination.cjs +2 -2
- package/dist/cjs/Pagination.native.js +2 -2
- package/dist/cjs/Pagination.native.js.map +1 -1
- package/dist/cjs/ProgressSteps/index.cjs +3 -3
- package/dist/cjs/ProgressSteps/index.native.js +3 -3
- package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
- package/dist/cjs/Quote/index.cjs +1 -2
- package/dist/cjs/Quote/index.native.js +1 -2
- package/dist/cjs/Quote/index.native.js.map +1 -1
- package/dist/cjs/SheetModal/index.cjs +22 -3
- package/dist/cjs/SheetModal/index.native.js +50 -10
- package/dist/cjs/SheetModal/index.native.js.map +1 -1
- package/dist/cjs/Tabs/index.cjs +34 -13
- package/dist/cjs/Tabs/index.native.js +38 -13
- package/dist/cjs/Tabs/index.native.js.map +1 -1
- package/dist/cjs/Toast/index.cjs +4 -5
- package/dist/cjs/Toast/index.native.js +4 -5
- package/dist/cjs/Toast/index.native.js.map +1 -1
- package/dist/cjs/TreeSelect/index.cjs +46 -7
- package/dist/cjs/TreeSelect/index.native.js +58 -7
- package/dist/cjs/TreeSelect/index.native.js.map +1 -1
- package/dist/cjs/charts/PieChart.cjs +1 -2
- package/dist/cjs/charts/PieChart.native.js +1 -2
- package/dist/cjs/charts/PieChart.native.js.map +1 -1
- package/dist/cjs/code/HighlightedCode/index.cjs +1 -1
- package/dist/cjs/code/HighlightedCode/index.native.js +1 -1
- package/dist/cjs/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/cjs/componentColors.cjs +6 -4
- package/dist/cjs/componentColors.native.js +6 -4
- package/dist/cjs/componentColors.native.js.map +1 -1
- package/dist/cjs/images/Image/ImageFrame.cjs +4 -2
- package/dist/cjs/images/Image/ImageFrame.native.js +4 -2
- package/dist/cjs/images/Image/ImageFrame.native.js.map +1 -1
- package/dist/cjs/layouts/AsyncBoundary.cjs +1 -2
- package/dist/cjs/layouts/AsyncBoundary.native.js +1 -2
- package/dist/cjs/layouts/AsyncBoundary.native.js.map +1 -1
- package/dist/cjs/layouts/EmptyState.cjs +6 -2
- package/dist/cjs/layouts/EmptyState.native.js +10 -6
- package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
- package/dist/cjs/layouts/attachments.cjs +4 -4
- package/dist/cjs/layouts/attachments.native.js +4 -4
- package/dist/cjs/layouts/attachments.native.js.map +1 -1
- package/dist/cjs/layouts/breadcrumbs.cjs +1 -2
- package/dist/cjs/layouts/breadcrumbs.native.js +1 -2
- package/dist/cjs/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/cjs/layouts/page.cjs +2 -2
- package/dist/cjs/layouts/page.native.js +2 -2
- package/dist/cjs/layouts/page.native.js.map +1 -1
- package/dist/cjs/layouts/sidebar.cjs +2 -2
- package/dist/cjs/layouts/sidebar.native.js +2 -2
- package/dist/cjs/layouts/sidebar.native.js.map +1 -1
- package/dist/cjs/layouts/tags.cjs +6 -7
- package/dist/cjs/layouts/tags.native.js +6 -9
- package/dist/cjs/layouts/tags.native.js.map +1 -1
- package/dist/cjs/layouts/timeline.cjs +5 -5
- package/dist/cjs/layouts/timeline.native.js +5 -5
- package/dist/cjs/layouts/timeline.native.js.map +1 -1
- package/dist/cjs/surfaces.cjs +1 -0
- package/dist/cjs/surfaces.native.js +1 -0
- package/dist/cjs/surfaces.native.js.map +1 -1
- package/dist/cjs/views/Calendar.cjs +11 -8
- package/dist/cjs/views/Calendar.native.js +11 -8
- package/dist/cjs/views/Calendar.native.js.map +1 -1
- package/dist/cjs/views/Dashboard.cjs +6 -6
- package/dist/cjs/views/Dashboard.native.js +7 -7
- package/dist/cjs/views/Dashboard.native.js.map +1 -1
- package/dist/cjs/views/Gantt.cjs +3 -3
- package/dist/cjs/views/Gantt.native.js +3 -3
- package/dist/cjs/views/Gantt.native.js.map +1 -1
- package/dist/cjs/views/Kanban.cjs +2 -2
- package/dist/cjs/views/Kanban.native.js +2 -2
- package/dist/cjs/views/Kanban.native.js.map +1 -1
- package/dist/cjs/views/ReportBuilder.cjs +4 -4
- package/dist/cjs/views/ReportBuilder.native.js +4 -4
- package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
- package/dist/cjs/views/TreeView.cjs +248 -19
- package/dist/cjs/views/TreeView.native.js +264 -20
- package/dist/cjs/views/TreeView.native.js.map +1 -1
- package/dist/cjs/views/treeViewReveal.cjs +55 -0
- package/dist/cjs/views/treeViewReveal.native.js +80 -0
- package/dist/cjs/views/treeViewReveal.native.js.map +1 -0
- package/dist/esm/Accordion/index.mjs +3 -3
- package/dist/esm/Accordion/index.mjs.map +1 -1
- package/dist/esm/Accordion/index.native.js +4 -4
- package/dist/esm/Accordion/index.native.js.map +1 -1
- package/dist/esm/Chip/index.mjs +1 -1
- package/dist/esm/Chip/index.mjs.map +1 -1
- package/dist/esm/Chip/index.native.js +1 -1
- package/dist/esm/Chip/index.native.js.map +1 -1
- package/dist/esm/ContextMenu/index.mjs +3 -3
- package/dist/esm/ContextMenu/index.mjs.map +1 -1
- package/dist/esm/ContextMenu/index.native.js +3 -3
- package/dist/esm/ContextMenu/index.native.js.map +1 -1
- package/dist/esm/DropdownMenu/index.mjs +3 -3
- package/dist/esm/DropdownMenu/index.mjs.map +1 -1
- package/dist/esm/DropdownMenu/index.native.js +3 -3
- package/dist/esm/DropdownMenu/index.native.js.map +1 -1
- package/dist/esm/Meter/index.mjs +3 -2
- package/dist/esm/Meter/index.mjs.map +1 -1
- package/dist/esm/Meter/index.native.js +3 -2
- package/dist/esm/Meter/index.native.js.map +1 -1
- package/dist/esm/Meter/meter.mjs +1 -2
- package/dist/esm/Meter/meter.mjs.map +1 -1
- package/dist/esm/Meter/meter.native.js +1 -2
- package/dist/esm/Meter/meter.native.js.map +1 -1
- package/dist/esm/Pagination.mjs +2 -2
- package/dist/esm/Pagination.mjs.map +1 -1
- package/dist/esm/Pagination.native.js +2 -2
- package/dist/esm/Pagination.native.js.map +1 -1
- package/dist/esm/ProgressSteps/index.mjs +3 -3
- package/dist/esm/ProgressSteps/index.mjs.map +1 -1
- package/dist/esm/ProgressSteps/index.native.js +3 -3
- package/dist/esm/ProgressSteps/index.native.js.map +1 -1
- package/dist/esm/Quote/index.mjs +1 -2
- package/dist/esm/Quote/index.mjs.map +1 -1
- package/dist/esm/Quote/index.native.js +1 -2
- package/dist/esm/Quote/index.native.js.map +1 -1
- package/dist/esm/SheetModal/index.mjs +22 -3
- package/dist/esm/SheetModal/index.mjs.map +1 -1
- package/dist/esm/SheetModal/index.native.js +51 -11
- package/dist/esm/SheetModal/index.native.js.map +1 -1
- package/dist/esm/Tabs/index.mjs +34 -13
- package/dist/esm/Tabs/index.mjs.map +1 -1
- package/dist/esm/Tabs/index.native.js +38 -13
- package/dist/esm/Tabs/index.native.js.map +1 -1
- package/dist/esm/Toast/index.mjs +4 -5
- package/dist/esm/Toast/index.mjs.map +1 -1
- package/dist/esm/Toast/index.native.js +4 -5
- package/dist/esm/Toast/index.native.js.map +1 -1
- package/dist/esm/TreeSelect/index.mjs +46 -7
- package/dist/esm/TreeSelect/index.mjs.map +1 -1
- package/dist/esm/TreeSelect/index.native.js +58 -7
- package/dist/esm/TreeSelect/index.native.js.map +1 -1
- package/dist/esm/charts/PieChart.mjs +1 -2
- package/dist/esm/charts/PieChart.mjs.map +1 -1
- package/dist/esm/charts/PieChart.native.js +1 -2
- package/dist/esm/charts/PieChart.native.js.map +1 -1
- package/dist/esm/code/HighlightedCode/index.mjs +1 -1
- package/dist/esm/code/HighlightedCode/index.mjs.map +1 -1
- package/dist/esm/code/HighlightedCode/index.native.js +1 -1
- package/dist/esm/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/esm/componentColors.mjs +6 -4
- package/dist/esm/componentColors.mjs.map +1 -1
- package/dist/esm/componentColors.native.js +6 -4
- package/dist/esm/componentColors.native.js.map +1 -1
- package/dist/esm/images/Image/ImageFrame.mjs +4 -2
- package/dist/esm/images/Image/ImageFrame.mjs.map +1 -1
- package/dist/esm/images/Image/ImageFrame.native.js +4 -2
- package/dist/esm/images/Image/ImageFrame.native.js.map +1 -1
- package/dist/esm/layouts/AsyncBoundary.mjs +1 -2
- package/dist/esm/layouts/AsyncBoundary.mjs.map +1 -1
- package/dist/esm/layouts/AsyncBoundary.native.js +1 -2
- package/dist/esm/layouts/AsyncBoundary.native.js.map +1 -1
- package/dist/esm/layouts/EmptyState.mjs +7 -3
- package/dist/esm/layouts/EmptyState.mjs.map +1 -1
- package/dist/esm/layouts/EmptyState.native.js +11 -7
- package/dist/esm/layouts/EmptyState.native.js.map +1 -1
- package/dist/esm/layouts/attachments.mjs +4 -4
- package/dist/esm/layouts/attachments.mjs.map +1 -1
- package/dist/esm/layouts/attachments.native.js +4 -4
- package/dist/esm/layouts/attachments.native.js.map +1 -1
- package/dist/esm/layouts/breadcrumbs.mjs +1 -2
- package/dist/esm/layouts/breadcrumbs.mjs.map +1 -1
- package/dist/esm/layouts/breadcrumbs.native.js +1 -2
- package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/esm/layouts/page.mjs +2 -2
- package/dist/esm/layouts/page.mjs.map +1 -1
- package/dist/esm/layouts/page.native.js +2 -2
- package/dist/esm/layouts/page.native.js.map +1 -1
- package/dist/esm/layouts/sidebar.mjs +2 -2
- package/dist/esm/layouts/sidebar.mjs.map +1 -1
- package/dist/esm/layouts/sidebar.native.js +2 -2
- package/dist/esm/layouts/sidebar.native.js.map +1 -1
- package/dist/esm/layouts/tags.mjs +6 -7
- package/dist/esm/layouts/tags.mjs.map +1 -1
- package/dist/esm/layouts/tags.native.js +6 -9
- package/dist/esm/layouts/tags.native.js.map +1 -1
- package/dist/esm/layouts/timeline.mjs +5 -5
- package/dist/esm/layouts/timeline.mjs.map +1 -1
- package/dist/esm/layouts/timeline.native.js +5 -5
- package/dist/esm/layouts/timeline.native.js.map +1 -1
- package/dist/esm/surfaces.mjs +1 -0
- package/dist/esm/surfaces.mjs.map +1 -1
- package/dist/esm/surfaces.native.js +1 -0
- package/dist/esm/surfaces.native.js.map +1 -1
- package/dist/esm/views/Calendar.mjs +11 -8
- package/dist/esm/views/Calendar.mjs.map +1 -1
- package/dist/esm/views/Calendar.native.js +11 -8
- package/dist/esm/views/Calendar.native.js.map +1 -1
- package/dist/esm/views/Dashboard.mjs +6 -6
- package/dist/esm/views/Dashboard.mjs.map +1 -1
- package/dist/esm/views/Dashboard.native.js +7 -7
- package/dist/esm/views/Dashboard.native.js.map +1 -1
- package/dist/esm/views/Gantt.mjs +3 -3
- package/dist/esm/views/Gantt.mjs.map +1 -1
- package/dist/esm/views/Gantt.native.js +3 -3
- package/dist/esm/views/Gantt.native.js.map +1 -1
- package/dist/esm/views/Kanban.mjs +2 -2
- package/dist/esm/views/Kanban.mjs.map +1 -1
- package/dist/esm/views/Kanban.native.js +2 -2
- package/dist/esm/views/Kanban.native.js.map +1 -1
- package/dist/esm/views/ReportBuilder.mjs +4 -4
- package/dist/esm/views/ReportBuilder.mjs.map +1 -1
- package/dist/esm/views/ReportBuilder.native.js +4 -4
- package/dist/esm/views/ReportBuilder.native.js.map +1 -1
- package/dist/esm/views/TreeView.mjs +249 -20
- package/dist/esm/views/TreeView.mjs.map +1 -1
- package/dist/esm/views/TreeView.native.js +265 -21
- package/dist/esm/views/TreeView.native.js.map +1 -1
- package/dist/esm/views/treeViewReveal.mjs +29 -0
- package/dist/esm/views/treeViewReveal.mjs.map +1 -0
- package/dist/esm/views/treeViewReveal.native.js +51 -0
- package/dist/esm/views/treeViewReveal.native.js.map +1 -0
- package/dist/jsx/Accordion/index.mjs +3 -3
- package/dist/jsx/Accordion/index.mjs.map +1 -1
- package/dist/jsx/Accordion/index.native.js +4 -4
- package/dist/jsx/Accordion/index.native.js.map +1 -1
- package/dist/jsx/Chip/index.mjs +1 -1
- package/dist/jsx/Chip/index.mjs.map +1 -1
- package/dist/jsx/Chip/index.native.js +1 -1
- package/dist/jsx/Chip/index.native.js.map +1 -1
- package/dist/jsx/ContextMenu/index.mjs +3 -3
- package/dist/jsx/ContextMenu/index.mjs.map +1 -1
- package/dist/jsx/ContextMenu/index.native.js +3 -3
- package/dist/jsx/ContextMenu/index.native.js.map +1 -1
- package/dist/jsx/DropdownMenu/index.mjs +3 -3
- package/dist/jsx/DropdownMenu/index.mjs.map +1 -1
- package/dist/jsx/DropdownMenu/index.native.js +3 -3
- package/dist/jsx/DropdownMenu/index.native.js.map +1 -1
- package/dist/jsx/Meter/index.mjs +3 -2
- package/dist/jsx/Meter/index.mjs.map +1 -1
- package/dist/jsx/Meter/index.native.js +3 -2
- package/dist/jsx/Meter/index.native.js.map +1 -1
- package/dist/jsx/Meter/meter.mjs +1 -2
- package/dist/jsx/Meter/meter.mjs.map +1 -1
- package/dist/jsx/Meter/meter.native.js +1 -2
- package/dist/jsx/Meter/meter.native.js.map +1 -1
- package/dist/jsx/Pagination.mjs +2 -2
- package/dist/jsx/Pagination.mjs.map +1 -1
- package/dist/jsx/Pagination.native.js +2 -2
- package/dist/jsx/Pagination.native.js.map +1 -1
- package/dist/jsx/ProgressSteps/index.mjs +3 -3
- package/dist/jsx/ProgressSteps/index.mjs.map +1 -1
- package/dist/jsx/ProgressSteps/index.native.js +3 -3
- package/dist/jsx/ProgressSteps/index.native.js.map +1 -1
- package/dist/jsx/Quote/index.mjs +1 -2
- package/dist/jsx/Quote/index.mjs.map +1 -1
- package/dist/jsx/Quote/index.native.js +1 -2
- package/dist/jsx/Quote/index.native.js.map +1 -1
- package/dist/jsx/SheetModal/index.mjs +22 -3
- package/dist/jsx/SheetModal/index.mjs.map +1 -1
- package/dist/jsx/SheetModal/index.native.js +50 -10
- package/dist/jsx/SheetModal/index.native.js.map +1 -1
- package/dist/jsx/Tabs/index.mjs +34 -13
- package/dist/jsx/Tabs/index.mjs.map +1 -1
- package/dist/jsx/Tabs/index.native.js +38 -13
- package/dist/jsx/Tabs/index.native.js.map +1 -1
- package/dist/jsx/Toast/index.mjs +4 -5
- package/dist/jsx/Toast/index.mjs.map +1 -1
- package/dist/jsx/Toast/index.native.js +4 -5
- package/dist/jsx/Toast/index.native.js.map +1 -1
- package/dist/jsx/TreeSelect/index.mjs +46 -7
- package/dist/jsx/TreeSelect/index.mjs.map +1 -1
- package/dist/jsx/TreeSelect/index.native.js +58 -7
- package/dist/jsx/TreeSelect/index.native.js.map +1 -1
- package/dist/jsx/charts/PieChart.mjs +1 -2
- package/dist/jsx/charts/PieChart.mjs.map +1 -1
- package/dist/jsx/charts/PieChart.native.js +1 -2
- package/dist/jsx/charts/PieChart.native.js.map +1 -1
- package/dist/jsx/code/HighlightedCode/index.mjs +1 -1
- package/dist/jsx/code/HighlightedCode/index.mjs.map +1 -1
- package/dist/jsx/code/HighlightedCode/index.native.js +1 -1
- package/dist/jsx/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/jsx/componentColors.mjs +6 -4
- package/dist/jsx/componentColors.mjs.map +1 -1
- package/dist/jsx/componentColors.native.js +6 -4
- package/dist/jsx/componentColors.native.js.map +1 -1
- package/dist/jsx/images/Image/ImageFrame.mjs +4 -2
- package/dist/jsx/images/Image/ImageFrame.mjs.map +1 -1
- package/dist/jsx/images/Image/ImageFrame.native.js +4 -2
- package/dist/jsx/images/Image/ImageFrame.native.js.map +1 -1
- package/dist/jsx/layouts/AsyncBoundary.mjs +1 -2
- package/dist/jsx/layouts/AsyncBoundary.mjs.map +1 -1
- package/dist/jsx/layouts/AsyncBoundary.native.js +1 -2
- package/dist/jsx/layouts/AsyncBoundary.native.js.map +1 -1
- package/dist/jsx/layouts/EmptyState.mjs +7 -3
- package/dist/jsx/layouts/EmptyState.mjs.map +1 -1
- package/dist/jsx/layouts/EmptyState.native.js +10 -6
- package/dist/jsx/layouts/EmptyState.native.js.map +1 -1
- package/dist/jsx/layouts/attachments.mjs +4 -4
- package/dist/jsx/layouts/attachments.mjs.map +1 -1
- package/dist/jsx/layouts/attachments.native.js +4 -4
- package/dist/jsx/layouts/attachments.native.js.map +1 -1
- package/dist/jsx/layouts/breadcrumbs.mjs +1 -2
- package/dist/jsx/layouts/breadcrumbs.mjs.map +1 -1
- package/dist/jsx/layouts/breadcrumbs.native.js +1 -2
- package/dist/jsx/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/jsx/layouts/page.mjs +2 -2
- package/dist/jsx/layouts/page.mjs.map +1 -1
- package/dist/jsx/layouts/page.native.js +2 -2
- package/dist/jsx/layouts/page.native.js.map +1 -1
- package/dist/jsx/layouts/sidebar.mjs +2 -2
- package/dist/jsx/layouts/sidebar.mjs.map +1 -1
- package/dist/jsx/layouts/sidebar.native.js +2 -2
- package/dist/jsx/layouts/sidebar.native.js.map +1 -1
- package/dist/jsx/layouts/tags.mjs +6 -7
- package/dist/jsx/layouts/tags.mjs.map +1 -1
- package/dist/jsx/layouts/tags.native.js +6 -9
- package/dist/jsx/layouts/tags.native.js.map +1 -1
- package/dist/jsx/layouts/timeline.mjs +5 -5
- package/dist/jsx/layouts/timeline.mjs.map +1 -1
- package/dist/jsx/layouts/timeline.native.js +5 -5
- package/dist/jsx/layouts/timeline.native.js.map +1 -1
- package/dist/jsx/surfaces.mjs +1 -0
- package/dist/jsx/surfaces.mjs.map +1 -1
- package/dist/jsx/surfaces.native.js +1 -0
- package/dist/jsx/surfaces.native.js.map +1 -1
- package/dist/jsx/views/Calendar.mjs +11 -8
- package/dist/jsx/views/Calendar.mjs.map +1 -1
- package/dist/jsx/views/Calendar.native.js +11 -8
- package/dist/jsx/views/Calendar.native.js.map +1 -1
- package/dist/jsx/views/Dashboard.mjs +6 -6
- package/dist/jsx/views/Dashboard.mjs.map +1 -1
- package/dist/jsx/views/Dashboard.native.js +7 -7
- package/dist/jsx/views/Dashboard.native.js.map +1 -1
- package/dist/jsx/views/Gantt.mjs +3 -3
- package/dist/jsx/views/Gantt.mjs.map +1 -1
- package/dist/jsx/views/Gantt.native.js +3 -3
- package/dist/jsx/views/Gantt.native.js.map +1 -1
- package/dist/jsx/views/Kanban.mjs +2 -2
- package/dist/jsx/views/Kanban.mjs.map +1 -1
- package/dist/jsx/views/Kanban.native.js +2 -2
- package/dist/jsx/views/Kanban.native.js.map +1 -1
- package/dist/jsx/views/ReportBuilder.mjs +4 -4
- package/dist/jsx/views/ReportBuilder.mjs.map +1 -1
- package/dist/jsx/views/ReportBuilder.native.js +4 -4
- package/dist/jsx/views/ReportBuilder.native.js.map +1 -1
- package/dist/jsx/views/TreeView.mjs +249 -20
- package/dist/jsx/views/TreeView.mjs.map +1 -1
- package/dist/jsx/views/TreeView.native.js +264 -20
- package/dist/jsx/views/TreeView.native.js.map +1 -1
- package/dist/jsx/views/treeViewReveal.mjs +29 -0
- package/dist/jsx/views/treeViewReveal.mjs.map +1 -0
- package/dist/jsx/views/treeViewReveal.native.js +80 -0
- package/dist/jsx/views/treeViewReveal.native.js.map +1 -0
- package/package.json +11 -11
- package/src/Accordion/index.tsx +4 -6
- package/src/Chip/index.tsx +1 -1
- package/src/ContextMenu/index.tsx +3 -3
- package/src/DropdownMenu/index.tsx +3 -3
- package/src/Meter/Meter.spec.tsx +12 -4
- package/src/Meter/index.tsx +3 -2
- package/src/Meter/meter.ts +6 -1
- package/src/Pagination.tsx +2 -2
- package/src/ProgressSteps/index.tsx +3 -3
- package/src/Quote/index.tsx +1 -3
- package/src/SheetModal/SheetModal.fill.spec.tsx +147 -0
- package/src/SheetModal/SheetModal.ownedBody.spec.tsx +200 -0
- package/src/SheetModal/SheetModal.stories.spec.tsx +23 -2
- package/src/SheetModal/SheetModal.stories.tsx +275 -2
- package/src/SheetModal/index.native.tsx +50 -6
- package/src/SheetModal/index.tsx +40 -3
- package/src/Tabs/Tabs.lifecycle.spec.tsx +123 -0
- package/src/Tabs/Tabs.measurement.spec.tsx +186 -0
- package/src/Tabs/Tabs.stories.tsx +43 -0
- package/src/Tabs/index.tsx +44 -15
- package/src/Toast/Toast.spec.tsx +120 -48
- package/src/Toast/index.tsx +5 -3
- package/src/TreeSelect/index.tsx +61 -1
- package/src/charts/PieChart.tsx +1 -2
- package/src/code/HighlightedCode/index.tsx +1 -1
- package/src/componentColors.ts +6 -4
- package/src/images/Image/ImageFrame.tsx +2 -2
- package/src/layouts/AsyncBoundary.tsx +1 -2
- package/src/layouts/EmptyState.spec.tsx +58 -1
- package/src/layouts/EmptyState.tsx +11 -7
- package/src/layouts/KeyboardAvoidingWrapper/KeyboardAvoidingWrapper.stories.tsx +3 -3
- package/src/layouts/PaneScaffold.stories.tsx +3 -8
- package/src/layouts/SafeAreaWrapper/SafeAreaWrapper.stories.tsx +3 -3
- package/src/layouts/attachments.tsx +4 -4
- package/src/layouts/breadcrumbs.tsx +1 -2
- package/src/layouts/page.tsx +2 -2
- package/src/layouts/sidebar.tsx +2 -2
- package/src/layouts/tags-trigger.spec.tsx +32 -0
- package/src/layouts/tags.tsx +7 -9
- package/src/layouts/timeline.tsx +5 -5
- package/src/surfaces.spec.tsx +97 -3
- package/src/surfaces.tsx +4 -2
- package/src/textAccentSecondary.spec.tsx +187 -0
- package/src/views/Calendar.tsx +9 -8
- package/src/views/Dashboard.tsx +13 -8
- package/src/views/Gantt.tsx +3 -3
- package/src/views/Kanban.native.tsx +2 -2
- package/src/views/Kanban.tsx +2 -2
- package/src/views/ReportBuilder.tsx +4 -4
- package/src/views/TreeView.reveal.spec.tsx +174 -0
- package/src/views/TreeView.reveal.stories.tsx +249 -0
- package/src/views/TreeView.scroll-index.spec.tsx +246 -0
- package/src/views/TreeView.scroll.spec.tsx +857 -0
- package/src/views/TreeView.spec.tsx +1 -1
- package/src/views/TreeView.tsx +353 -29
- package/src/views/treeViewReveal.spec.ts +83 -0
- package/src/views/treeViewReveal.ts +45 -0
- package/src/views/views.spec.tsx +13 -12
- package/types/Accordion/index.d.ts.map +1 -1
- package/types/Meter/index.d.ts.map +1 -1
- package/types/Meter/meter.d.ts +5 -1
- package/types/Meter/meter.d.ts.map +1 -1
- package/types/Quote/index.d.ts.map +1 -1
- package/types/SheetModal/index.d.ts +8 -1
- package/types/SheetModal/index.d.ts.map +1 -1
- package/types/SheetModal/index.native.d.ts +1 -1
- package/types/SheetModal/index.native.d.ts.map +1 -1
- package/types/Tabs/index.d.ts.map +1 -1
- package/types/Toast/index.d.ts.map +1 -1
- package/types/TreeSelect/index.d.ts +9 -1
- package/types/TreeSelect/index.d.ts.map +1 -1
- package/types/charts/PieChart.d.ts.map +1 -1
- package/types/componentColors.d.ts +1 -4
- package/types/componentColors.d.ts.map +1 -1
- package/types/images/Image/ImageFrame.d.ts.map +1 -1
- package/types/layouts/AsyncBoundary.d.ts.map +1 -1
- package/types/layouts/EmptyState.d.ts.map +1 -1
- package/types/layouts/breadcrumbs.d.ts.map +1 -1
- package/types/layouts/tags.d.ts.map +1 -1
- package/types/surfaces.d.ts.map +1 -1
- package/types/views/Calendar.d.ts.map +1 -1
- package/types/views/Dashboard.d.ts +7 -3
- package/types/views/Dashboard.d.ts.map +1 -1
- package/types/views/TreeView.d.ts +19 -1
- package/types/views/TreeView.d.ts.map +1 -1
- package/types/views/treeViewReveal.d.ts +11 -0
- package/types/views/treeViewReveal.d.ts.map +1 -0
|
@@ -92,7 +92,7 @@ describe("TreeView knob wiring", () => {
|
|
|
92
92
|
expect(tree.getAttribute("data-fill")).toBe("transparent");
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
it("row labels are T-VALUE primary ink, never
|
|
95
|
+
it("row labels are T-VALUE primary ink, never a secondary ramp step", () => {
|
|
96
96
|
expect(treeViewSource).not.toMatch(/componentColors\.text\.(secondary|muted)/);
|
|
97
97
|
expect(treeViewSource).toMatch(
|
|
98
98
|
/color=\{isSelected && onAccentLabel \? onAccentLabel : "\$color"\}/,
|
package/src/views/TreeView.tsx
CHANGED
|
@@ -35,7 +35,7 @@ import React, {
|
|
|
35
35
|
type ReactNode,
|
|
36
36
|
} from "react";
|
|
37
37
|
import { useTranslation } from "../shared/i18n";
|
|
38
|
-
import { Text, View, XStack, YStack, type YStackProps } from "tamagui";
|
|
38
|
+
import { Text, View, XStack, YStack, isWeb, type YStackProps } from "tamagui";
|
|
39
39
|
import { autoScrollVelocity } from "./kanbanDnd";
|
|
40
40
|
import {
|
|
41
41
|
applyTreeMove,
|
|
@@ -54,6 +54,7 @@ import {
|
|
|
54
54
|
type TreeDropTarget,
|
|
55
55
|
} from "./treeViewDnd";
|
|
56
56
|
import { diffVisibleRows, flattenVisibleIds, isEmptyDiff } from "./treeViewMotion";
|
|
57
|
+
import { treeRevealExpansion, treeRevealOffset } from "./treeViewReveal";
|
|
57
58
|
import {
|
|
58
59
|
TREE_LIFT_SHADOW,
|
|
59
60
|
treeDefaultHeight,
|
|
@@ -133,8 +134,20 @@ export interface TreeViewProps<T = unknown> extends Omit<YStackProps, "children"
|
|
|
133
134
|
overscan?: number;
|
|
134
135
|
/** Height of the scrollable container in pixels */
|
|
135
136
|
height?: number;
|
|
137
|
+
/** Initial vertical offset in layout pixels, restored once after usable list layout. */
|
|
138
|
+
initialScrollOffset?: number;
|
|
139
|
+
/** Observed, bounded vertical offset. Does not report unacknowledged scroll commands. */
|
|
140
|
+
onScrollOffsetChange?: (offset: number) => void;
|
|
136
141
|
/** Message shown when there are no nodes */
|
|
137
142
|
emptyMessage?: string;
|
|
143
|
+
/** Controlled expansion; takes precedence over initial expansion props. */
|
|
144
|
+
expandedIds?: string[];
|
|
145
|
+
/** Next complete expansion set from a user toggle or explicit reveal. */
|
|
146
|
+
onExpandedIdsChange?: (ids: string[]) => void;
|
|
147
|
+
/** Expand ancestors and reveal this row. Change requestId to reveal the same ID again. */
|
|
148
|
+
revealRequest?: { id: string; requestId: number };
|
|
149
|
+
/** Called once when the current reveal target is measured, mounted and visible. */
|
|
150
|
+
onRevealComplete?: (request: { id: string; requestId: number }) => void;
|
|
138
151
|
/** Initially expanded node IDs (wins over expandByDefault when provided) */
|
|
139
152
|
defaultExpandedIds?: string[];
|
|
140
153
|
/** Expand every branch on initial load */
|
|
@@ -291,8 +304,14 @@ export function TreeView<T = unknown>({
|
|
|
291
304
|
estimateSize: estimateSizeProp,
|
|
292
305
|
overscan = 10,
|
|
293
306
|
height: heightProp,
|
|
307
|
+
initialScrollOffset,
|
|
308
|
+
onScrollOffsetChange,
|
|
294
309
|
emptyMessage: emptyMessageProp,
|
|
295
310
|
defaultExpandedIds,
|
|
311
|
+
expandedIds: controlledExpandedIds,
|
|
312
|
+
onExpandedIdsChange,
|
|
313
|
+
revealRequest,
|
|
314
|
+
onRevealComplete,
|
|
296
315
|
expandByDefault = false,
|
|
297
316
|
display = "default",
|
|
298
317
|
showExpansionArrows = true,
|
|
@@ -339,6 +358,31 @@ export function TreeView<T = unknown>({
|
|
|
339
358
|
const treeId = useId();
|
|
340
359
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
341
360
|
const flashListRef = useRef<FlashListRef<FlatNode<T>>>(null);
|
|
361
|
+
const initialScroll = useRef<
|
|
362
|
+
| {
|
|
363
|
+
offset: number;
|
|
364
|
+
attempted?: { target: number; width: number; height: number; contentHeight: number };
|
|
365
|
+
}
|
|
366
|
+
| undefined
|
|
367
|
+
>(
|
|
368
|
+
initialScrollOffset === undefined
|
|
369
|
+
? undefined
|
|
370
|
+
: { offset: Number.isFinite(initialScrollOffset) ? Math.max(0, initialScrollOffset) : 0 },
|
|
371
|
+
);
|
|
372
|
+
const cancelInitialScroll = useCallback(() => {
|
|
373
|
+
initialScroll.current = undefined;
|
|
374
|
+
}, []);
|
|
375
|
+
const hasNodes = nodes.length > 0;
|
|
376
|
+
const listInstance = useMemo(
|
|
377
|
+
() => ({ hasNodes, attached: false, loaded: false, indexScrollRequested: false, offset: 0 }),
|
|
378
|
+
[hasNodes],
|
|
379
|
+
);
|
|
380
|
+
const scrollActive = useRef(true);
|
|
381
|
+
const lastReportedOffset = useRef<number | undefined>(undefined);
|
|
382
|
+
const offsetCallback = useRef(onScrollOffsetChange);
|
|
383
|
+
useLayoutEffect(() => {
|
|
384
|
+
offsetCallback.current = onScrollOffsetChange;
|
|
385
|
+
}, [onScrollOffsetChange]);
|
|
342
386
|
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
343
387
|
// LC-71: ring is a React flag, not a render-time wasKeyboardFocus() read —
|
|
344
388
|
// Tab-away/Tab-back with the same activedescendant must still re-paint.
|
|
@@ -357,12 +401,25 @@ export function TreeView<T = unknown>({
|
|
|
357
401
|
const handleContainerBlur = useCallback(() => {
|
|
358
402
|
setKeyboardRing(false);
|
|
359
403
|
}, []);
|
|
360
|
-
const [
|
|
404
|
+
const [internalExpandedIds, setInternalExpandedIds] = useState<Set<string>>(() => {
|
|
361
405
|
if (defaultExpandedIds) return new Set(defaultExpandedIds);
|
|
362
406
|
if (expandByDefault) return collectBranchIds(nodes);
|
|
363
407
|
return new Set();
|
|
364
408
|
});
|
|
365
409
|
|
|
410
|
+
const expandedIds = useMemo(
|
|
411
|
+
() =>
|
|
412
|
+
controlledExpandedIds === undefined ? internalExpandedIds : new Set(controlledExpandedIds),
|
|
413
|
+
[controlledExpandedIds, internalExpandedIds],
|
|
414
|
+
);
|
|
415
|
+
const setExpandedIds = useCallback(
|
|
416
|
+
(next: ReadonlySet<string>) => {
|
|
417
|
+
if (controlledExpandedIds === undefined) setInternalExpandedIds(new Set(next));
|
|
418
|
+
onExpandedIdsChange?.([...next]);
|
|
419
|
+
},
|
|
420
|
+
[controlledExpandedIds, onExpandedIdsChange],
|
|
421
|
+
);
|
|
422
|
+
|
|
366
423
|
// ── Expand/collapse motion (FLIP + enter fade; Axiom 4) ────────────────
|
|
367
424
|
const [motion, setMotion] = useState<TreeMotion | null>(null);
|
|
368
425
|
const rowHeights = useRef(new Map<string, number>());
|
|
@@ -373,30 +430,37 @@ export function TreeView<T = unknown>({
|
|
|
373
430
|
|
|
374
431
|
const toggleNode = useCallback(
|
|
375
432
|
(node: TreeNode<T>) => {
|
|
433
|
+
cancelInitialScroll();
|
|
376
434
|
const next = new Set(expandedIds);
|
|
377
435
|
if (next.has(node.id)) {
|
|
378
436
|
next.delete(node.id);
|
|
379
437
|
} else {
|
|
380
438
|
next.add(node.id);
|
|
381
439
|
}
|
|
382
|
-
// Mount never animates and `animation: none` / reduced motion skips
|
|
383
|
-
// the machine entirely — the toggle then renders in one jump.
|
|
384
|
-
if (transition) {
|
|
385
|
-
const diff = diffVisibleRows(
|
|
386
|
-
flattenVisibleIds(nodes, expandedIds),
|
|
387
|
-
flattenVisibleIds(nodes, next),
|
|
388
|
-
getRowHeight,
|
|
389
|
-
);
|
|
390
|
-
setMotion(isEmptyDiff(diff) ? null : { phase: "armed", ...diff });
|
|
391
|
-
} else {
|
|
392
|
-
setMotion(null);
|
|
393
|
-
}
|
|
394
440
|
setExpandedIds(next);
|
|
395
441
|
onNodeToggle?.(node);
|
|
396
442
|
},
|
|
397
|
-
[expandedIds,
|
|
443
|
+
[expandedIds, setExpandedIds, onNodeToggle, cancelInitialScroll],
|
|
398
444
|
);
|
|
399
445
|
|
|
446
|
+
const previousExpandedIds = useRef(expandedIds);
|
|
447
|
+
useLayoutEffect(() => {
|
|
448
|
+
const previous = previousExpandedIds.current;
|
|
449
|
+
previousExpandedIds.current = expandedIds;
|
|
450
|
+
if (previous.size === expandedIds.size && [...previous].every((id) => expandedIds.has(id)))
|
|
451
|
+
return;
|
|
452
|
+
if (transition) {
|
|
453
|
+
const diff = diffVisibleRows(
|
|
454
|
+
flattenVisibleIds(nodes, previous),
|
|
455
|
+
flattenVisibleIds(nodes, expandedIds),
|
|
456
|
+
getRowHeight,
|
|
457
|
+
);
|
|
458
|
+
setMotion(isEmptyDiff(diff) ? null : { phase: "armed", ...diff });
|
|
459
|
+
} else {
|
|
460
|
+
setMotion(null);
|
|
461
|
+
}
|
|
462
|
+
}, [expandedIds, nodes, transition, getRowHeight]);
|
|
463
|
+
|
|
400
464
|
// Release the FLIP one frame after the armed styles paint so the tween
|
|
401
465
|
// runs from the previous layout to the new one.
|
|
402
466
|
useLayoutEffect(() => {
|
|
@@ -432,13 +496,243 @@ export function TreeView<T = unknown>({
|
|
|
432
496
|
return result;
|
|
433
497
|
}, [nodes, expandedIds]);
|
|
434
498
|
|
|
499
|
+
const revealIntent = useRef<
|
|
500
|
+
| {
|
|
501
|
+
id: string;
|
|
502
|
+
requestId: number;
|
|
503
|
+
complete: boolean;
|
|
504
|
+
notifiedExpansion?: ReadonlySet<string>;
|
|
505
|
+
}
|
|
506
|
+
| undefined
|
|
507
|
+
>(undefined);
|
|
508
|
+
const scrollFrame = useRef<number | undefined>(undefined);
|
|
509
|
+
const scrollStep = useRef<() => void>(() => {});
|
|
510
|
+
const renderedRows = useRef(new Set<string>());
|
|
511
|
+
const scrollBounds = useCallback(() => {
|
|
512
|
+
const list = flashListRef.current;
|
|
513
|
+
if (!scrollActive.current || !listInstance.attached || !listInstance.loaded || !list) return;
|
|
514
|
+
if (isWeb) {
|
|
515
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
516
|
+
if (!rect || !(rect.width > 0) || !(rect.height > 0)) return;
|
|
517
|
+
}
|
|
518
|
+
const viewport = list.getWindowSize();
|
|
519
|
+
const contentHeight = list.getChildContainerDimensions().height + list.getFirstItemOffset();
|
|
520
|
+
if (
|
|
521
|
+
!Number.isFinite(viewport.width) ||
|
|
522
|
+
viewport.width <= 0 ||
|
|
523
|
+
!Number.isFinite(viewport.height) ||
|
|
524
|
+
viewport.height <= 0 ||
|
|
525
|
+
!Number.isFinite(contentHeight) ||
|
|
526
|
+
contentHeight <= 0
|
|
527
|
+
)
|
|
528
|
+
return;
|
|
529
|
+
return {
|
|
530
|
+
list,
|
|
531
|
+
width: viewport.width,
|
|
532
|
+
height: viewport.height,
|
|
533
|
+
contentHeight,
|
|
534
|
+
maxOffset: Math.max(0, contentHeight - viewport.height),
|
|
535
|
+
};
|
|
536
|
+
}, [listInstance]);
|
|
537
|
+
const observeOffset = useCallback(
|
|
538
|
+
(offset: number, fromEvent = false) => {
|
|
539
|
+
if (!scrollActive.current || !listInstance.attached || !Number.isFinite(offset)) return;
|
|
540
|
+
if (
|
|
541
|
+
fromEvent &&
|
|
542
|
+
initialScroll.current?.attempted === undefined &&
|
|
543
|
+
offset !== listInstance.offset
|
|
544
|
+
) {
|
|
545
|
+
cancelInitialScroll();
|
|
546
|
+
}
|
|
547
|
+
listInstance.offset = offset;
|
|
548
|
+
const bounds = scrollBounds();
|
|
549
|
+
if (!bounds) return;
|
|
550
|
+
const bounded = Math.max(0, Math.min(offset, bounds.maxOffset));
|
|
551
|
+
const initial = initialScroll.current;
|
|
552
|
+
if (initial) {
|
|
553
|
+
const target = Math.min(initial.offset, bounds.maxOffset);
|
|
554
|
+
if (initial.attempted ? Math.abs(bounded - target) >= 1 : bounded !== target) return;
|
|
555
|
+
initialScroll.current = undefined;
|
|
556
|
+
}
|
|
557
|
+
if (offsetCallback.current && lastReportedOffset.current !== bounded) {
|
|
558
|
+
lastReportedOffset.current = bounded;
|
|
559
|
+
offsetCallback.current(bounded);
|
|
560
|
+
}
|
|
561
|
+
},
|
|
562
|
+
[cancelInitialScroll, scrollBounds, listInstance],
|
|
563
|
+
);
|
|
564
|
+
const scheduleScroll = useCallback(() => {
|
|
565
|
+
if (!scrollActive.current || !listInstance.attached || scrollFrame.current !== undefined)
|
|
566
|
+
return;
|
|
567
|
+
if (
|
|
568
|
+
!initialScroll.current &&
|
|
569
|
+
(!revealIntent.current || revealIntent.current.complete) &&
|
|
570
|
+
!offsetCallback.current
|
|
571
|
+
)
|
|
572
|
+
return;
|
|
573
|
+
scrollFrame.current = requestAnimationFrame(() => {
|
|
574
|
+
scrollFrame.current = undefined;
|
|
575
|
+
if (listInstance.attached) scrollStep.current();
|
|
576
|
+
});
|
|
577
|
+
}, [listInstance]);
|
|
578
|
+
const attachList = useCallback(
|
|
579
|
+
(list: FlashListRef<FlatNode<T>> | null) => {
|
|
580
|
+
flashListRef.current = list;
|
|
581
|
+
listInstance.attached = list !== null;
|
|
582
|
+
if (!list) {
|
|
583
|
+
listInstance.loaded = false;
|
|
584
|
+
if (initialScroll.current) initialScroll.current.attempted = undefined;
|
|
585
|
+
if (scrollFrame.current !== undefined) cancelAnimationFrame(scrollFrame.current);
|
|
586
|
+
scrollFrame.current = undefined;
|
|
587
|
+
}
|
|
588
|
+
},
|
|
589
|
+
[listInstance],
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
useLayoutEffect(() => {
|
|
593
|
+
scrollActive.current = true;
|
|
594
|
+
return () => {
|
|
595
|
+
scrollActive.current = false;
|
|
596
|
+
revealIntent.current = undefined;
|
|
597
|
+
if (scrollFrame.current !== undefined) cancelAnimationFrame(scrollFrame.current);
|
|
598
|
+
scrollFrame.current = undefined;
|
|
599
|
+
};
|
|
600
|
+
}, []);
|
|
601
|
+
|
|
602
|
+
useLayoutEffect(() => {
|
|
603
|
+
if (!revealRequest) {
|
|
604
|
+
revealIntent.current = undefined;
|
|
605
|
+
} else if (
|
|
606
|
+
revealIntent.current?.id !== revealRequest.id ||
|
|
607
|
+
revealIntent.current?.requestId !== revealRequest.requestId
|
|
608
|
+
) {
|
|
609
|
+
cancelInitialScroll();
|
|
610
|
+
revealIntent.current = { ...revealRequest, complete: false };
|
|
611
|
+
}
|
|
612
|
+
const step = () => {
|
|
613
|
+
const currentList = flashListRef.current;
|
|
614
|
+
if (currentList) {
|
|
615
|
+
// Index preparation changes FlashList's getter before transport completes.
|
|
616
|
+
// Once requested, only delivered events can advance this list's observation.
|
|
617
|
+
observeOffset(
|
|
618
|
+
listInstance.indexScrollRequested
|
|
619
|
+
? listInstance.offset
|
|
620
|
+
: currentList.getAbsoluteLastScrollOffset(),
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
if (!scrollActive.current) return;
|
|
624
|
+
if (scrollStep.current !== step) {
|
|
625
|
+
scheduleScroll();
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const intent = revealIntent.current;
|
|
629
|
+
if (!intent || intent.complete) {
|
|
630
|
+
const initial = initialScroll.current;
|
|
631
|
+
const bounds = scrollBounds();
|
|
632
|
+
if (!initial || !bounds || flatNodes.length === 0) return;
|
|
633
|
+
const target = Math.min(initial.offset, bounds.maxOffset);
|
|
634
|
+
const attempted = initial.attempted;
|
|
635
|
+
if (
|
|
636
|
+
!attempted ||
|
|
637
|
+
attempted.target !== target ||
|
|
638
|
+
attempted.width !== bounds.width ||
|
|
639
|
+
attempted.height !== bounds.height ||
|
|
640
|
+
attempted.contentHeight !== bounds.contentHeight
|
|
641
|
+
) {
|
|
642
|
+
initial.attempted = {
|
|
643
|
+
target,
|
|
644
|
+
width: bounds.width,
|
|
645
|
+
height: bounds.height,
|
|
646
|
+
contentHeight: bounds.contentHeight,
|
|
647
|
+
};
|
|
648
|
+
bounds.list.scrollToOffset({ offset: target, animated: false });
|
|
649
|
+
}
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const next = treeRevealExpansion(nodes, expandedIds, intent.id);
|
|
653
|
+
if (!next) return;
|
|
654
|
+
if (next !== expandedIds) {
|
|
655
|
+
const notified = intent.notifiedExpansion;
|
|
656
|
+
if (!notified || notified.size !== next.size || [...next].some((id) => !notified.has(id))) {
|
|
657
|
+
intent.notifiedExpansion = next;
|
|
658
|
+
setExpandedIds(next);
|
|
659
|
+
}
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
if (motion) {
|
|
663
|
+
setMotion(null);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
const list = flashListRef.current;
|
|
667
|
+
const index = flatNodes.findIndex((item) => item.node.id === intent.id);
|
|
668
|
+
if (!list || index < 0) return;
|
|
669
|
+
if (isWeb) {
|
|
670
|
+
const rect = containerRef.current?.getBoundingClientRect();
|
|
671
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return;
|
|
672
|
+
}
|
|
673
|
+
const viewport = list.getWindowSize();
|
|
674
|
+
if (viewport.width <= 0) return;
|
|
675
|
+
const layout = list.getLayout(index);
|
|
676
|
+
if (!layout) return;
|
|
677
|
+
const offset = listInstance.indexScrollRequested
|
|
678
|
+
? listInstance.offset
|
|
679
|
+
: list.getAbsoluteLastScrollOffset();
|
|
680
|
+
const top = layout.y + list.getFirstItemOffset();
|
|
681
|
+
const nextOffset = treeRevealOffset(
|
|
682
|
+
{ y: top, height: layout.height },
|
|
683
|
+
offset,
|
|
684
|
+
viewport.height,
|
|
685
|
+
);
|
|
686
|
+
if (nextOffset === undefined) return;
|
|
687
|
+
if (Math.abs(nextOffset - offset) < 1) {
|
|
688
|
+
let visible = top < offset + viewport.height && top + layout.height > offset;
|
|
689
|
+
if (!listInstance.indexScrollRequested) {
|
|
690
|
+
const range = list.computeVisibleIndices();
|
|
691
|
+
visible = visible && index >= range.startIndex && index <= range.endIndex;
|
|
692
|
+
}
|
|
693
|
+
if (
|
|
694
|
+
revealIntent.current === intent &&
|
|
695
|
+
layout.isHeightMeasured &&
|
|
696
|
+
renderedRows.current.has(intent.id) &&
|
|
697
|
+
visible
|
|
698
|
+
) {
|
|
699
|
+
intent.complete = true;
|
|
700
|
+
onRevealComplete?.({ id: intent.id, requestId: intent.requestId });
|
|
701
|
+
}
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
// FlashList's scrollToIndex has uncancellable delayed steps. Immediate offsets
|
|
705
|
+
// let the next layout/scroll event correct estimates using only the latest intent.
|
|
706
|
+
list.scrollToOffset({ offset: nextOffset, animated: false });
|
|
707
|
+
};
|
|
708
|
+
scrollStep.current = step;
|
|
709
|
+
scheduleScroll();
|
|
710
|
+
}, [
|
|
711
|
+
nodes,
|
|
712
|
+
expandedIds,
|
|
713
|
+
setExpandedIds,
|
|
714
|
+
flatNodes,
|
|
715
|
+
revealRequest?.id,
|
|
716
|
+
revealRequest?.requestId,
|
|
717
|
+
onRevealComplete,
|
|
718
|
+
height,
|
|
719
|
+
motion,
|
|
720
|
+
scheduleScroll,
|
|
721
|
+
cancelInitialScroll,
|
|
722
|
+
observeOffset,
|
|
723
|
+
scrollBounds,
|
|
724
|
+
listInstance,
|
|
725
|
+
]);
|
|
726
|
+
|
|
435
727
|
const scrollToIndex = useCallback(
|
|
436
728
|
(index: number) => {
|
|
437
729
|
if (index >= 0 && index < flatNodes.length) {
|
|
730
|
+
cancelInitialScroll();
|
|
731
|
+
listInstance.indexScrollRequested = true;
|
|
438
732
|
flashListRef.current?.scrollToIndex({ index, animated: true });
|
|
439
733
|
}
|
|
440
734
|
},
|
|
441
|
-
[flatNodes.length],
|
|
735
|
+
[flatNodes.length, cancelInitialScroll, listInstance],
|
|
442
736
|
);
|
|
443
737
|
|
|
444
738
|
const focusRow = useCallback(
|
|
@@ -732,6 +1026,7 @@ export function TreeView<T = unknown>({
|
|
|
732
1026
|
if (!container?.getBoundingClientRect) return false;
|
|
733
1027
|
const session = treeKeyboardLift(nodes, flat.node.id);
|
|
734
1028
|
if (!session) return false;
|
|
1029
|
+
cancelInitialScroll();
|
|
735
1030
|
const rowRect = rowEl.getBoundingClientRect();
|
|
736
1031
|
const containerRect = container.getBoundingClientRect();
|
|
737
1032
|
grabOffsetRef.current = { x: clientX - rowRect.left, y: clientY - rowRect.top };
|
|
@@ -759,7 +1054,7 @@ export function TreeView<T = unknown>({
|
|
|
759
1054
|
startAutoScroll();
|
|
760
1055
|
return true;
|
|
761
1056
|
},
|
|
762
|
-
[announce, nodes, startAutoScroll],
|
|
1057
|
+
[announce, nodes, startAutoScroll, cancelInitialScroll],
|
|
763
1058
|
);
|
|
764
1059
|
|
|
765
1060
|
const handleDragHandlePointerDown = useCallback(
|
|
@@ -906,6 +1201,7 @@ export function TreeView<T = unknown>({
|
|
|
906
1201
|
if (!flat) return false;
|
|
907
1202
|
const session = treeKeyboardLift(nodes, flat.node.id);
|
|
908
1203
|
if (!session) return false;
|
|
1204
|
+
cancelInitialScroll();
|
|
909
1205
|
const ui: TreeDragUi<T> = {
|
|
910
1206
|
mode: "keyboard",
|
|
911
1207
|
node: flat.node,
|
|
@@ -923,7 +1219,16 @@ export function TreeView<T = unknown>({
|
|
|
923
1219
|
dragUiRef.current = ui;
|
|
924
1220
|
announce(describeTreeDragState("lift", session, nodes, flat.node.label));
|
|
925
1221
|
return true;
|
|
926
|
-
}, [
|
|
1222
|
+
}, [
|
|
1223
|
+
announce,
|
|
1224
|
+
canReorder,
|
|
1225
|
+
dndRows,
|
|
1226
|
+
flatNodes,
|
|
1227
|
+
focusedIndex,
|
|
1228
|
+
getRowHeight,
|
|
1229
|
+
nodes,
|
|
1230
|
+
cancelInitialScroll,
|
|
1231
|
+
]);
|
|
927
1232
|
|
|
928
1233
|
const moveKeyboardDrag = useCallback(
|
|
929
1234
|
(direction: "up" | "down" | "left" | "right"): boolean => {
|
|
@@ -1153,16 +1458,28 @@ export function TreeView<T = unknown>({
|
|
|
1153
1458
|
onFocus={handleContainerFocus}
|
|
1154
1459
|
onBlur={handleContainerBlur}
|
|
1155
1460
|
onKeyDown={handleTreeKeyDown}
|
|
1461
|
+
onLayout={scheduleScroll}
|
|
1462
|
+
{...(isWeb && { onWheel: cancelInitialScroll, onPointerDown: cancelInitialScroll })}
|
|
1156
1463
|
position="relative"
|
|
1157
1464
|
style={{
|
|
1158
1465
|
height,
|
|
1159
1466
|
}}
|
|
1160
1467
|
>
|
|
1161
1468
|
<FlashList
|
|
1162
|
-
ref={
|
|
1469
|
+
ref={attachList}
|
|
1163
1470
|
data={flatNodes}
|
|
1164
1471
|
drawDistance={overscan * estimateSize}
|
|
1165
1472
|
keyExtractor={(item) => item.node.id}
|
|
1473
|
+
onLoad={() => {
|
|
1474
|
+
if (!scrollActive.current || !listInstance.attached) return;
|
|
1475
|
+
listInstance.loaded = true;
|
|
1476
|
+
scheduleScroll();
|
|
1477
|
+
}}
|
|
1478
|
+
onCommitLayoutEffect={scheduleScroll}
|
|
1479
|
+
onContentSizeChange={scheduleScroll}
|
|
1480
|
+
onScrollBeginDrag={() => {
|
|
1481
|
+
if (scrollActive.current && listInstance.attached) cancelInitialScroll();
|
|
1482
|
+
}}
|
|
1166
1483
|
extraData={{
|
|
1167
1484
|
focused: effectiveFocused,
|
|
1168
1485
|
selectedId,
|
|
@@ -1173,16 +1490,17 @@ export function TreeView<T = unknown>({
|
|
|
1173
1490
|
keyboardRing,
|
|
1174
1491
|
collapsedSelectedAncestors,
|
|
1175
1492
|
}}
|
|
1176
|
-
{
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
}
|
|
1493
|
+
onScroll={(e: any) => {
|
|
1494
|
+
if (!scrollActive.current || !listInstance.attached) return;
|
|
1495
|
+
const y = e?.nativeEvent?.contentOffset?.y;
|
|
1496
|
+
if (typeof y === "number" && Number.isFinite(y)) {
|
|
1497
|
+
scrollOffsetRef.current = y;
|
|
1498
|
+
if (dragUiRef.current) setDragScrollY(y);
|
|
1499
|
+
observeOffset(y, true);
|
|
1500
|
+
}
|
|
1501
|
+
scheduleScroll();
|
|
1502
|
+
}}
|
|
1503
|
+
scrollEventThrottle={16}
|
|
1186
1504
|
renderItem={({ item, index }) => {
|
|
1187
1505
|
const { node, depth, hasChildren, isExpanded } = item;
|
|
1188
1506
|
const isFocused = effectiveFocused === index;
|
|
@@ -1239,6 +1557,11 @@ export function TreeView<T = unknown>({
|
|
|
1239
1557
|
// Remount when a recycled cell switches nodes so state fills
|
|
1240
1558
|
// and the caret never tween across two different rows.
|
|
1241
1559
|
key={node.id}
|
|
1560
|
+
ref={(row) => {
|
|
1561
|
+
if (row) renderedRows.current.add(node.id);
|
|
1562
|
+
else renderedRows.current.delete(node.id);
|
|
1563
|
+
scheduleScroll();
|
|
1564
|
+
}}
|
|
1242
1565
|
id={`${treeId}-node-${index}`}
|
|
1243
1566
|
{...{ "data-treeview-row": node.id }}
|
|
1244
1567
|
{...(isDropParent && { "data-treeview-drop-parent": "true" })}
|
|
@@ -1265,6 +1588,7 @@ export function TreeView<T = unknown>({
|
|
|
1265
1588
|
onLayout={(e: any) => {
|
|
1266
1589
|
const h = e?.nativeEvent?.layout?.height;
|
|
1267
1590
|
if (typeof h === "number" && h > 0) rowHeights.current.set(node.id, h);
|
|
1591
|
+
scheduleScroll();
|
|
1268
1592
|
}}
|
|
1269
1593
|
backgroundColor={
|
|
1270
1594
|
// Nest-into parent highlight wins while a drag is active
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { treeRevealExpansion, treeRevealOffset } from "./treeViewReveal";
|
|
3
|
+
|
|
4
|
+
const nodes = [
|
|
5
|
+
{
|
|
6
|
+
id: "folders",
|
|
7
|
+
children: [
|
|
8
|
+
{
|
|
9
|
+
id: "archive",
|
|
10
|
+
children: Array.from({ length: 500 }, (_, index) => ({ id: `item-${index}` })),
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
{ id: "other", children: [{ id: "other-item" }] },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe("tree reveal ancestors", () => {
|
|
18
|
+
it("finds the exact last leaf of a 500-item branch and preserves unrelated expansion", () => {
|
|
19
|
+
const expanded = new Set(["other"]);
|
|
20
|
+
expect(treeRevealExpansion(nodes, expanded, "item-499")).toEqual(
|
|
21
|
+
new Set(["other", "folders", "archive"]),
|
|
22
|
+
);
|
|
23
|
+
expect(expanded).toEqual(new Set(["other"]));
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("does not expand the target branch itself", () => {
|
|
27
|
+
expect(treeRevealExpansion(nodes, new Set(), "archive")).toEqual(new Set(["folders"]));
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("preserves the set when the target is already exposed", () => {
|
|
31
|
+
const expanded = new Set(["folders", "archive"]);
|
|
32
|
+
expect(treeRevealExpansion(nodes, expanded, "item-499")).toBe(expanded);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("does not substitute a prefix, ancestor or similarly named leaf for a missing ID", () => {
|
|
36
|
+
expect(treeRevealExpansion(nodes, new Set(), "item-500")).toBeUndefined();
|
|
37
|
+
expect(treeRevealExpansion(nodes, new Set(), "item")).toBeUndefined();
|
|
38
|
+
expect(treeRevealExpansion([], new Set(), "folders")).toBeUndefined();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("reveals a root without expanding its children", () => {
|
|
42
|
+
const expanded = new Set<string>();
|
|
43
|
+
expect(treeRevealExpansion(nodes, expanded, "folders")).toBe(expanded);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("tree reveal measured offsets", () => {
|
|
48
|
+
it("uses the actual layout of a distant variable-height row, not index times an estimate", () => {
|
|
49
|
+
const heights = Array.from({ length: 500 }, (_, index) => (index % 2 === 0 ? 32 : 80));
|
|
50
|
+
const y = heights.slice(0, 499).reduce((sum, height) => sum + height, 0);
|
|
51
|
+
expect(y).toBe(27920);
|
|
52
|
+
expect(treeRevealOffset({ y, height: heights[499] }, 0, 240)).toBe(27760);
|
|
53
|
+
expect(treeRevealOffset({ y, height: heights[499] }, 27760, 240)).toBe(27760);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("corrects again when virtualization replaces an estimate with a taller measurement", () => {
|
|
57
|
+
expect(treeRevealOffset({ y: 27920, height: 32 }, 0, 240)).toBe(27712);
|
|
58
|
+
expect(treeRevealOffset({ y: 27920, height: 80 }, 27712, 240)).toBe(27760);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("leaves a fully visible row in place", () => {
|
|
62
|
+
expect(treeRevealOffset({ y: 300, height: 80 }, 250, 240)).toBe(250);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("reveals a row above the viewport at its top", () => {
|
|
66
|
+
expect(treeRevealOffset({ y: 120, height: 80 }, 250, 240)).toBe(120);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("aligns the top of a row taller than the viewport without oscillating", () => {
|
|
70
|
+
expect(treeRevealOffset({ y: 120, height: 300 }, 250, 240)).toBe(120);
|
|
71
|
+
expect(treeRevealOffset({ y: 120, height: 300 }, 120, 240)).toBe(120);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it.each([
|
|
75
|
+
[{ y: 20, height: 32 }, 0, 0],
|
|
76
|
+
[{ y: 20, height: 0 }, 0, 240],
|
|
77
|
+
[{ y: Number.NaN, height: 32 }, 0, 240],
|
|
78
|
+
[{ y: 20, height: 32 }, Number.NaN, 240],
|
|
79
|
+
[{ y: 20, height: 32 }, 0, Number.POSITIVE_INFINITY],
|
|
80
|
+
])("waits for usable geometry: %o, %s, %s", (layout, offset, height) => {
|
|
81
|
+
expect(treeRevealOffset(layout, offset, height)).toBeUndefined();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
interface RevealTreeNode {
|
|
2
|
+
id: string;
|
|
3
|
+
children?: readonly RevealTreeNode[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function treeRevealExpansion(
|
|
7
|
+
nodes: readonly RevealTreeNode[],
|
|
8
|
+
expandedIds: ReadonlySet<string>,
|
|
9
|
+
targetId: string,
|
|
10
|
+
): ReadonlySet<string> | undefined {
|
|
11
|
+
const ancestors: string[] = [];
|
|
12
|
+
const find = (items: readonly RevealTreeNode[]): boolean => {
|
|
13
|
+
for (const node of items) {
|
|
14
|
+
if (node.id === targetId) return true;
|
|
15
|
+
if (node.children?.length) {
|
|
16
|
+
ancestors.push(node.id);
|
|
17
|
+
if (find(node.children)) return true;
|
|
18
|
+
ancestors.pop();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return false;
|
|
22
|
+
};
|
|
23
|
+
if (!find(nodes)) return undefined;
|
|
24
|
+
if (ancestors.every((id) => expandedIds.has(id))) return expandedIds;
|
|
25
|
+
return new Set([...expandedIds, ...ancestors]);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function treeRevealOffset(
|
|
29
|
+
layout: { y: number; height: number },
|
|
30
|
+
offset: number,
|
|
31
|
+
viewportHeight: number,
|
|
32
|
+
): number | undefined {
|
|
33
|
+
if (
|
|
34
|
+
![layout.y, layout.height, offset, viewportHeight].every(Number.isFinite) ||
|
|
35
|
+
viewportHeight <= 0 ||
|
|
36
|
+
layout.height <= 0
|
|
37
|
+
) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (layout.height > viewportHeight || layout.y < offset) return Math.max(0, layout.y);
|
|
41
|
+
if (layout.y + layout.height > offset + viewportHeight) {
|
|
42
|
+
return Math.max(0, layout.y + layout.height - viewportHeight);
|
|
43
|
+
}
|
|
44
|
+
return offset;
|
|
45
|
+
}
|