@multiplatform.one/components 7.10.0 → 7.15.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 +100 -2
- package/dist/cjs/Accordion/index.cjs +2 -6
- package/dist/cjs/Accordion/index.native.js +2 -6
- package/dist/cjs/Accordion/index.native.js.map +1 -1
- package/dist/cjs/AnimateHeight/index.cjs +1 -3
- package/dist/cjs/AnimateHeight/index.native.js +1 -3
- package/dist/cjs/AnimateHeight/index.native.js.map +1 -1
- package/dist/cjs/Chip/index.cjs +8 -1
- package/dist/cjs/Chip/index.native.js +8 -1
- package/dist/cjs/Chip/index.native.js.map +1 -1
- package/dist/cjs/SheetModal/index.cjs +22 -3
- package/dist/cjs/SheetModal/index.native.js +115 -27
- package/dist/cjs/SheetModal/index.native.js.map +1 -1
- package/dist/cjs/Tabs/index.cjs +35 -18
- package/dist/cjs/Tabs/index.native.js +39 -18
- package/dist/cjs/Tabs/index.native.js.map +1 -1
- package/dist/cjs/Text.cjs +2 -0
- package/dist/cjs/Text.native.js +2 -0
- package/dist/cjs/Text.native.js.map +1 -1
- package/dist/cjs/TreeSelect/index.cjs +55 -52
- package/dist/cjs/TreeSelect/index.native.js +55 -52
- package/dist/cjs/TreeSelect/index.native.js.map +1 -1
- package/dist/cjs/Video/PlayerChrome.cjs +3 -9
- package/dist/cjs/Video/PlayerChrome.native.js +3 -9
- package/dist/cjs/Video/PlayerChrome.native.js.map +1 -1
- package/dist/cjs/code/Code/index.cjs +6 -0
- package/dist/cjs/code/Code/index.native.js +7 -4
- package/dist/cjs/code/Code/index.native.js.map +1 -1
- package/dist/cjs/code/CodeBlock/index.cjs +4 -5
- package/dist/cjs/code/CodeBlock/index.native.js +4 -5
- package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
- package/dist/cjs/icons/themed.cjs +2 -1
- package/dist/cjs/icons/themed.native.js +2 -1
- package/dist/cjs/icons/themed.native.js.map +1 -1
- package/dist/cjs/knobImmuneExports.cjs +3 -3
- package/dist/cjs/knobImmuneExports.native.js +3 -3
- package/dist/cjs/layouts/PaneScaffold.cjs +70 -42
- package/dist/cjs/layouts/PaneScaffold.native.js +75 -48
- package/dist/cjs/layouts/PaneScaffold.native.js.map +1 -1
- package/dist/cjs/layouts/page.cjs +2 -1
- package/dist/cjs/layouts/page.native.js +2 -1
- package/dist/cjs/layouts/page.native.js.map +1 -1
- package/dist/cjs/layouts/sidebar.cjs +1 -3
- package/dist/cjs/layouts/sidebar.native.js +1 -3
- package/dist/cjs/layouts/sidebar.native.js.map +1 -1
- package/dist/cjs/layouts/tags.native.js.map +1 -1
- package/dist/cjs/surfaces.cjs +0 -32
- package/dist/cjs/surfaces.native.js +0 -32
- package/dist/cjs/surfaces.native.js.map +1 -1
- package/dist/cjs/views/List.cjs +1 -3
- package/dist/cjs/views/List.native.js +1 -3
- package/dist/cjs/views/List.native.js.map +1 -1
- package/dist/cjs/views/Matrix.cjs +568 -0
- package/dist/cjs/views/Matrix.native.js +612 -0
- package/dist/cjs/views/Matrix.native.js.map +1 -0
- package/dist/cjs/views/TreeView.cjs +175 -43
- package/dist/cjs/views/TreeView.native.js +181 -46
- package/dist/cjs/views/TreeView.native.js.map +1 -1
- package/dist/cjs/views/ganttMath.cjs +2 -0
- package/dist/cjs/views/ganttMath.native.js +2 -0
- package/dist/cjs/views/ganttMath.native.js.map +1 -1
- package/dist/cjs/views/index.cjs +16 -0
- package/dist/cjs/views/index.native.js +16 -0
- package/dist/cjs/views/index.native.js.map +1 -1
- package/dist/cjs/views/matrixMath.cjs +157 -0
- package/dist/cjs/views/matrixMath.native.js +229 -0
- package/dist/cjs/views/matrixMath.native.js.map +1 -0
- package/dist/esm/Accordion/index.mjs +3 -7
- package/dist/esm/Accordion/index.mjs.map +1 -1
- package/dist/esm/Accordion/index.native.js +3 -7
- package/dist/esm/Accordion/index.native.js.map +1 -1
- package/dist/esm/AnimateHeight/index.mjs +2 -4
- package/dist/esm/AnimateHeight/index.mjs.map +1 -1
- package/dist/esm/AnimateHeight/index.native.js +2 -4
- package/dist/esm/AnimateHeight/index.native.js.map +1 -1
- package/dist/esm/Avatar/getInitials.native.js.map +1 -1
- package/dist/esm/Avatar/index.native.js.map +1 -1
- package/dist/esm/Badge/index.native.js.map +1 -1
- package/dist/esm/Button.native.js.map +1 -1
- package/dist/esm/Carousel/index.native.js.map +1 -1
- package/dist/esm/Chip/index.mjs +9 -2
- package/dist/esm/Chip/index.mjs.map +1 -1
- package/dist/esm/Chip/index.native.js +9 -2
- package/dist/esm/Chip/index.native.js.map +1 -1
- package/dist/esm/Collapsible.native.js.map +1 -1
- package/dist/esm/ContextMenu/index.native.js.map +1 -1
- package/dist/esm/CopyField/index.native.js.map +1 -1
- package/dist/esm/DotIndicator/index.native.js.map +1 -1
- package/dist/esm/DropdownMenu/index.native.js.map +1 -1
- package/dist/esm/ErrorBoundary/index.native.js.map +1 -1
- package/dist/esm/Heading.native.js.map +1 -1
- package/dist/esm/Meter/index.native.js.map +1 -1
- package/dist/esm/Meter/meter.native.js.map +1 -1
- package/dist/esm/Pagination.native.js.map +1 -1
- package/dist/esm/ProgressSteps/index.native.js.map +1 -1
- package/dist/esm/Quote/index.native.js.map +1 -1
- package/dist/esm/Separator/index.native.js.map +1 -1
- package/dist/esm/SheetModal/detents.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 +117 -29
- package/dist/esm/SheetModal/index.native.js.map +1 -1
- package/dist/esm/Skeleton/index.native.js.map +1 -1
- package/dist/esm/SkipLink/index.native.js.map +1 -1
- package/dist/esm/SortableList/SortableHandle.native.js.map +1 -1
- package/dist/esm/SortableList/index.native.js.map +1 -1
- package/dist/esm/SortableList/useSortableRows.native.js.map +1 -1
- package/dist/esm/Tabs/index.mjs +36 -19
- package/dist/esm/Tabs/index.mjs.map +1 -1
- package/dist/esm/Tabs/index.native.js +40 -19
- package/dist/esm/Tabs/index.native.js.map +1 -1
- package/dist/esm/Text.mjs +3 -1
- package/dist/esm/Text.mjs.map +1 -1
- package/dist/esm/Text.native.js +3 -1
- package/dist/esm/Text.native.js.map +1 -1
- package/dist/esm/Toast/index.native.js.map +1 -1
- package/dist/esm/Toast/store.native.js.map +1 -1
- package/dist/esm/Tooltip/nativePress.native.js.map +1 -1
- package/dist/esm/Tooltip/tooltipShared.native.js.map +1 -1
- package/dist/esm/TreeSelect/index.mjs +56 -53
- package/dist/esm/TreeSelect/index.mjs.map +1 -1
- package/dist/esm/TreeSelect/index.native.js +56 -53
- package/dist/esm/TreeSelect/index.native.js.map +1 -1
- package/dist/esm/TreeSelect/treeSelectModel.native.js.map +1 -1
- package/dist/esm/Video/PlayerChrome.mjs +4 -10
- package/dist/esm/Video/PlayerChrome.mjs.map +1 -1
- package/dist/esm/Video/PlayerChrome.native.js +4 -10
- package/dist/esm/Video/PlayerChrome.native.js.map +1 -1
- package/dist/esm/Video/VideoFrame.native.js.map +1 -1
- package/dist/esm/Video/types.native.js.map +1 -1
- package/dist/esm/Wheel/index.native.js.map +1 -1
- package/dist/esm/Wizard/index.native.js.map +1 -1
- package/dist/esm/actions/ActionBar.native.js.map +1 -1
- package/dist/esm/actions/DestructiveAction.native.js.map +1 -1
- package/dist/esm/actions/devWarn.native.js.map +1 -1
- package/dist/esm/actions/index.native.js.map +1 -1
- package/dist/esm/actions/severity.native.js.map +1 -1
- package/dist/esm/charts/Axis.native.js.map +1 -1
- package/dist/esm/charts/BarChart.native.js.map +1 -1
- package/dist/esm/charts/ChartDataView.native.js.map +1 -1
- package/dist/esm/charts/ChartSurface.native.js.map +1 -1
- package/dist/esm/charts/LineChart.native.js.map +1 -1
- package/dist/esm/charts/PieChart.native.js.map +1 -1
- package/dist/esm/charts/Sparkline.native.js.map +1 -1
- package/dist/esm/charts/accessibility.native.js.map +1 -1
- package/dist/esm/charts/composeChart.native.js.map +1 -1
- package/dist/esm/charts/index.native.js.map +1 -1
- package/dist/esm/charts/math.native.js.map +1 -1
- package/dist/esm/charts/series.native.js.map +1 -1
- package/dist/esm/charts/svg.native.js.map +1 -1
- package/dist/esm/charts/types.native.js.map +1 -1
- package/dist/esm/charts/useChartTheme.native.js.map +1 -1
- package/dist/esm/code/Code/index.mjs +6 -0
- package/dist/esm/code/Code/index.mjs.map +1 -1
- package/dist/esm/code/Code/index.native.js +10 -7
- package/dist/esm/code/Code/index.native.js.map +1 -1
- package/dist/esm/code/CodeBlock/index.mjs +5 -6
- package/dist/esm/code/CodeBlock/index.mjs.map +1 -1
- package/dist/esm/code/CodeBlock/index.native.js +5 -6
- package/dist/esm/code/CodeBlock/index.native.js.map +1 -1
- package/dist/esm/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/esm/code/Highlighter/index.native.js.map +1 -1
- package/dist/esm/code/Pre/index.native.js.map +1 -1
- package/dist/esm/code/index.native.js.map +1 -1
- package/dist/esm/componentColors.native.js.map +1 -1
- package/dist/esm/feedback/ConfirmDialog.native.js.map +1 -1
- package/dist/esm/feedback/NotifyHost.native.js.map +1 -1
- package/dist/esm/feedback/copy.native.js.map +1 -1
- package/dist/esm/feedback/index.native.js.map +1 -1
- package/dist/esm/feedback/notify.native.js.map +1 -1
- package/dist/esm/feedback/route.native.js.map +1 -1
- package/dist/esm/feedback/store.native.js.map +1 -1
- package/dist/esm/hooks/index.native.js.map +1 -1
- package/dist/esm/hooks/useClipboard.native.js.map +1 -1
- package/dist/esm/hooks/useDocumentTitle.native.js.map +1 -1
- package/dist/esm/icons/CheckRegular.native.js.map +1 -1
- package/dist/esm/icons/MinusRegular.native.js.map +1 -1
- package/dist/esm/icons/index.native.js.map +1 -1
- package/dist/esm/icons/lucide.native.js.map +1 -1
- package/dist/esm/icons/themed.mjs +3 -2
- package/dist/esm/icons/themed.mjs.map +1 -1
- package/dist/esm/icons/themed.native.js +3 -2
- package/dist/esm/icons/themed.native.js.map +1 -1
- package/dist/esm/images/Image/ImageFrame.native.js.map +1 -1
- package/dist/esm/images/Image/shared.native.js.map +1 -1
- package/dist/esm/images/Image/types.native.js.map +1 -1
- package/dist/esm/images/index.native.js.map +1 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/knobImmuneExports.mjs +3 -3
- package/dist/esm/knobImmuneExports.native.js +3 -3
- package/dist/esm/knobImmuneExports.native.js.map +1 -1
- package/dist/esm/layouts/AsyncBoundary.native.js.map +1 -1
- package/dist/esm/layouts/Debug/index.native.js.map +1 -1
- package/dist/esm/layouts/EmptyState.native.js.map +1 -1
- package/dist/esm/layouts/KeyboardAvoidingWrapper/behavior.native.js.map +1 -1
- package/dist/esm/layouts/PageTemplates.native.js.map +1 -1
- package/dist/esm/layouts/PaneScaffold.mjs +70 -42
- package/dist/esm/layouts/PaneScaffold.mjs.map +1 -1
- package/dist/esm/layouts/PaneScaffold.native.js +75 -48
- package/dist/esm/layouts/PaneScaffold.native.js.map +1 -1
- package/dist/esm/layouts/SafeAreaWrapper/insets.native.js.map +1 -1
- package/dist/esm/layouts/ViewSwitcher.native.js.map +1 -1
- package/dist/esm/layouts/attachments.native.js.map +1 -1
- package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/esm/layouts/index.native.js.map +1 -1
- package/dist/esm/layouts/page.mjs +3 -2
- package/dist/esm/layouts/page.mjs.map +1 -1
- package/dist/esm/layouts/page.native.js +3 -2
- package/dist/esm/layouts/page.native.js.map +1 -1
- package/dist/esm/layouts/pageHeadingScope.native.js.map +1 -1
- package/dist/esm/layouts/sidebar.mjs +2 -4
- package/dist/esm/layouts/sidebar.mjs.map +1 -1
- package/dist/esm/layouts/sidebar.native.js +2 -4
- package/dist/esm/layouts/sidebar.native.js.map +1 -1
- package/dist/esm/layouts/tags.mjs.map +1 -1
- package/dist/esm/layouts/tags.native.js.map +1 -1
- package/dist/esm/layouts/timeline.native.js.map +1 -1
- package/dist/esm/layouts/toolbar.native.js.map +1 -1
- package/dist/esm/shared/actionScan.native.js.map +1 -1
- package/dist/esm/shared/i18n.native.js.map +1 -1
- package/dist/esm/shared/t.native.js.map +1 -1
- package/dist/esm/shared/textRidesText.native.js.map +1 -1
- package/dist/esm/shared/useReturnFocusOnClose.native.js.map +1 -1
- package/dist/esm/surfaces.mjs +1 -33
- package/dist/esm/surfaces.mjs.map +1 -1
- package/dist/esm/surfaces.native.js +1 -33
- package/dist/esm/surfaces.native.js.map +1 -1
- package/dist/esm/tamagui.native.js.map +1 -1
- package/dist/esm/testSetup.native.js.map +1 -1
- package/dist/esm/utils/setTinted.native.js.map +1 -1
- package/dist/esm/utils/unwrapText.native.js.map +1 -1
- package/dist/esm/views/Calendar.native.js.map +1 -1
- package/dist/esm/views/Dashboard.native.js.map +1 -1
- package/dist/esm/views/Gantt.native.js.map +1 -1
- package/dist/esm/views/ImageGrid.native.js.map +1 -1
- package/dist/esm/views/List.mjs +2 -4
- package/dist/esm/views/List.mjs.map +1 -1
- package/dist/esm/views/List.native.js +2 -4
- package/dist/esm/views/List.native.js.map +1 -1
- package/dist/esm/views/Matrix.mjs +543 -0
- package/dist/esm/views/Matrix.mjs.map +1 -0
- package/dist/esm/views/Matrix.native.js +573 -0
- package/dist/esm/views/Matrix.native.js.map +1 -0
- package/dist/esm/views/ReportBuilder.native.js.map +1 -1
- package/dist/esm/views/TreeView.mjs +175 -43
- package/dist/esm/views/TreeView.mjs.map +1 -1
- package/dist/esm/views/TreeView.native.js +181 -46
- package/dist/esm/views/TreeView.native.js.map +1 -1
- package/dist/esm/views/calendarMath.native.js.map +1 -1
- package/dist/esm/views/ganttMath.mjs +1 -1
- package/dist/esm/views/ganttMath.mjs.map +1 -1
- package/dist/esm/views/ganttMath.native.js +1 -1
- package/dist/esm/views/ganttMath.native.js.map +1 -1
- package/dist/esm/views/index.mjs +4 -2
- package/dist/esm/views/index.mjs.map +1 -1
- package/dist/esm/views/index.native.js +4 -2
- package/dist/esm/views/index.native.js.map +1 -1
- package/dist/esm/views/kanbanDnd.native.js.map +1 -1
- package/dist/esm/views/matrixMath.mjs +122 -0
- package/dist/esm/views/matrixMath.mjs.map +1 -0
- package/dist/esm/views/matrixMath.native.js +191 -0
- package/dist/esm/views/matrixMath.native.js.map +1 -0
- package/dist/esm/views/treeViewDnd.native.js.map +1 -1
- package/dist/esm/views/treeViewLayout.native.js.map +1 -1
- package/dist/esm/views/treeViewMotion.native.js.map +1 -1
- package/dist/esm/views/treeViewReveal.native.js.map +1 -1
- package/dist/jsx/Accordion/index.mjs +3 -7
- package/dist/jsx/Accordion/index.mjs.map +1 -1
- package/dist/jsx/Accordion/index.native.js +2 -6
- package/dist/jsx/Accordion/index.native.js.map +1 -1
- package/dist/jsx/AnimateHeight/index.mjs +2 -4
- package/dist/jsx/AnimateHeight/index.mjs.map +1 -1
- package/dist/jsx/AnimateHeight/index.native.js +1 -3
- package/dist/jsx/AnimateHeight/index.native.js.map +1 -1
- package/dist/jsx/Chip/index.mjs +9 -2
- package/dist/jsx/Chip/index.mjs.map +1 -1
- package/dist/jsx/Chip/index.native.js +8 -1
- package/dist/jsx/Chip/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 +115 -27
- package/dist/jsx/SheetModal/index.native.js.map +1 -1
- package/dist/jsx/Tabs/index.mjs +36 -19
- package/dist/jsx/Tabs/index.mjs.map +1 -1
- package/dist/jsx/Tabs/index.native.js +39 -18
- package/dist/jsx/Tabs/index.native.js.map +1 -1
- package/dist/jsx/Text.mjs +3 -1
- package/dist/jsx/Text.mjs.map +1 -1
- package/dist/jsx/Text.native.js +2 -0
- package/dist/jsx/Text.native.js.map +1 -1
- package/dist/jsx/TreeSelect/index.mjs +56 -53
- package/dist/jsx/TreeSelect/index.mjs.map +1 -1
- package/dist/jsx/TreeSelect/index.native.js +55 -52
- package/dist/jsx/TreeSelect/index.native.js.map +1 -1
- package/dist/jsx/Video/PlayerChrome.mjs +4 -10
- package/dist/jsx/Video/PlayerChrome.mjs.map +1 -1
- package/dist/jsx/Video/PlayerChrome.native.js +3 -9
- package/dist/jsx/Video/PlayerChrome.native.js.map +1 -1
- package/dist/jsx/code/Code/index.mjs +6 -0
- package/dist/jsx/code/Code/index.mjs.map +1 -1
- package/dist/jsx/code/Code/index.native.js +7 -4
- package/dist/jsx/code/Code/index.native.js.map +1 -1
- package/dist/jsx/code/CodeBlock/index.mjs +5 -6
- package/dist/jsx/code/CodeBlock/index.mjs.map +1 -1
- package/dist/jsx/code/CodeBlock/index.native.js +4 -5
- package/dist/jsx/code/CodeBlock/index.native.js.map +1 -1
- package/dist/jsx/icons/themed.mjs +3 -2
- package/dist/jsx/icons/themed.mjs.map +1 -1
- package/dist/jsx/icons/themed.native.js +2 -1
- package/dist/jsx/icons/themed.native.js.map +1 -1
- package/dist/jsx/knobImmuneExports.mjs +3 -3
- package/dist/jsx/knobImmuneExports.native.js +3 -3
- package/dist/jsx/layouts/PaneScaffold.mjs +70 -42
- package/dist/jsx/layouts/PaneScaffold.mjs.map +1 -1
- package/dist/jsx/layouts/PaneScaffold.native.js +75 -48
- package/dist/jsx/layouts/PaneScaffold.native.js.map +1 -1
- package/dist/jsx/layouts/page.mjs +3 -2
- package/dist/jsx/layouts/page.mjs.map +1 -1
- package/dist/jsx/layouts/page.native.js +2 -1
- package/dist/jsx/layouts/page.native.js.map +1 -1
- package/dist/jsx/layouts/sidebar.mjs +2 -4
- package/dist/jsx/layouts/sidebar.mjs.map +1 -1
- package/dist/jsx/layouts/sidebar.native.js +1 -3
- package/dist/jsx/layouts/sidebar.native.js.map +1 -1
- package/dist/jsx/layouts/tags.mjs.map +1 -1
- package/dist/jsx/layouts/tags.native.js.map +1 -1
- package/dist/jsx/surfaces.mjs +1 -33
- package/dist/jsx/surfaces.mjs.map +1 -1
- package/dist/jsx/surfaces.native.js +0 -32
- package/dist/jsx/surfaces.native.js.map +1 -1
- package/dist/jsx/views/List.mjs +2 -4
- package/dist/jsx/views/List.mjs.map +1 -1
- package/dist/jsx/views/List.native.js +1 -3
- package/dist/jsx/views/List.native.js.map +1 -1
- package/dist/jsx/views/Matrix.mjs +543 -0
- package/dist/jsx/views/Matrix.mjs.map +1 -0
- package/dist/jsx/views/Matrix.native.js +612 -0
- package/dist/jsx/views/Matrix.native.js.map +1 -0
- package/dist/jsx/views/TreeView.mjs +175 -43
- package/dist/jsx/views/TreeView.mjs.map +1 -1
- package/dist/jsx/views/TreeView.native.js +181 -46
- package/dist/jsx/views/TreeView.native.js.map +1 -1
- package/dist/jsx/views/ganttMath.mjs +1 -1
- package/dist/jsx/views/ganttMath.mjs.map +1 -1
- package/dist/jsx/views/ganttMath.native.js +2 -0
- package/dist/jsx/views/ganttMath.native.js.map +1 -1
- package/dist/jsx/views/index.mjs +4 -2
- package/dist/jsx/views/index.mjs.map +1 -1
- package/dist/jsx/views/index.native.js +16 -0
- package/dist/jsx/views/index.native.js.map +1 -1
- package/dist/jsx/views/matrixMath.mjs +122 -0
- package/dist/jsx/views/matrixMath.mjs.map +1 -0
- package/dist/jsx/views/matrixMath.native.js +229 -0
- package/dist/jsx/views/matrixMath.native.js.map +1 -0
- package/package.json +12 -12
- package/src/Accordion/Accordion.spec.tsx +20 -0
- package/src/Accordion/index.tsx +8 -4
- package/src/AnimateHeight/index.tsx +143 -142
- package/src/Chip/Chip.borderLadder.spec.tsx +54 -0
- package/src/Chip/Chip.pressSlop.spec.tsx +57 -0
- package/src/Chip/index.tsx +15 -1
- package/src/Heading.native.spec.tsx +1 -1
- package/src/Separator/index.tsx +3 -3
- package/src/SheetModal/SheetModal.detentLayout.spec.tsx +173 -0
- 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/SheetModal.touch.spec.tsx +63 -0
- package/src/SheetModal/index.native.tsx +143 -21
- package/src/SheetModal/index.tsx +40 -3
- package/src/Tabs/Tabs.hydration.spec.tsx +123 -0
- 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 +45 -15
- package/src/Text.spec.tsx +32 -2
- package/src/Text.tsx +7 -6
- package/src/Toast/Toast.spec.tsx +50 -0
- package/src/Tooltip/Tooltip.spec.tsx +55 -2
- package/src/TreeSelect/TreeSelect.spec.tsx +15 -15
- package/src/TreeSelect/index.tsx +53 -50
- package/src/Video/PlayerChrome.tsx +4 -3
- package/src/Wheel/Wheel.spec.tsx +4 -4
- package/src/adjacency.l1.spec.tsx +175 -0
- package/src/code/Code/code.spec.tsx +2 -19
- package/src/code/Code/index.tsx +0 -6
- package/src/code/CodeBlock/index.tsx +5 -3
- package/src/code/highlightedCode.spec.tsx +2 -2
- package/src/code/hostProps.spec.tsx +55 -0
- package/src/icons/themed.hydration.spec.tsx +60 -0
- package/src/icons/themed.tsx +3 -6
- package/src/knobImmuneExports.ts +3 -3
- package/src/layouts/PaneScaffold.spec.tsx +148 -2
- package/src/layouts/PaneScaffold.stories.tsx +33 -1
- package/src/layouts/PaneScaffold.tsx +101 -48
- package/src/layouts/page.designLaw.spec.tsx +20 -0
- package/src/layouts/page.tsx +2 -0
- package/src/layouts/sidebar.tsx +2 -3
- package/src/layouts/tags.tsx +2 -1
- package/src/overlayElevation.spec.tsx +39 -51
- package/src/surfaces.spec.tsx +13 -10
- package/src/surfaces.tsx +4 -33
- package/src/tamagui.spec.ts +4 -3
- package/src/textAccentSecondary.spec.tsx +100 -2
- package/src/views/List.tsx +2 -1
- package/src/views/Matrix.spec.tsx +339 -0
- package/src/views/Matrix.stories.spec.tsx +68 -0
- package/src/views/Matrix.stories.tsx +153 -0
- package/src/views/Matrix.tsx +738 -0
- package/src/views/TreeView.reveal.spec.tsx +7 -0
- package/src/views/TreeView.reveal.stories.tsx +134 -0
- package/src/views/TreeView.scroll-index.spec.tsx +246 -0
- package/src/views/TreeView.scroll.spec.tsx +711 -50
- package/src/views/TreeView.tsx +230 -49
- package/src/views/ganttMath.ts +4 -2
- package/src/views/index.ts +30 -0
- package/src/views/matrixMath.spec.ts +237 -0
- package/src/views/matrixMath.ts +251 -0
- package/src/views/views.spec.tsx +3 -1
- package/types/Accordion/index.d.ts.map +1 -1
- package/types/AnimateHeight/index.d.ts.map +1 -1
- package/types/Chip/index.d.ts.map +1 -1
- package/types/Separator/index.d.ts +3 -3
- 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/Text.d.ts.map +1 -1
- package/types/TreeSelect/index.d.ts.map +1 -1
- package/types/Video/PlayerChrome.d.ts.map +1 -1
- package/types/code/Code/index.d.ts.map +1 -1
- package/types/code/CodeBlock/index.d.ts.map +1 -1
- package/types/icons/themed.d.ts.map +1 -1
- package/types/layouts/PaneScaffold.d.ts +14 -1
- package/types/layouts/PaneScaffold.d.ts.map +1 -1
- package/types/layouts/page.d.ts.map +1 -1
- package/types/layouts/sidebar.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/List.d.ts.map +1 -1
- package/types/views/Matrix.d.ts +102 -0
- package/types/views/Matrix.d.ts.map +1 -0
- package/types/views/TreeView.d.ts +10 -1
- package/types/views/TreeView.d.ts.map +1 -1
- package/types/views/ganttMath.d.ts +4 -0
- package/types/views/ganttMath.d.ts.map +1 -1
- package/types/views/index.d.ts +3 -1
- package/types/views/index.d.ts.map +1 -1
- package/types/views/matrixMath.d.ts +114 -0
- package/types/views/matrixMath.d.ts.map +1 -0
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Paragraph as FixtureText,
|
|
3
|
+
ScrollView,
|
|
4
|
+
SheetModal as PublicSheetModal,
|
|
5
|
+
XStack,
|
|
6
|
+
YStack as FixtureStack,
|
|
7
|
+
type TamaguiElement,
|
|
8
|
+
} from "@multiplatform.one/components";
|
|
9
|
+
import { Button, Input } from "@multiplatform.one/forms";
|
|
2
10
|
import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
|
|
3
|
-
import { useState } from "react";
|
|
11
|
+
import { useRef, useState } from "react";
|
|
12
|
+
import { Platform, useWindowDimensions, type LayoutChangeEvent } from "react-native";
|
|
4
13
|
import { Paragraph, SizableText, YStack } from "tamagui";
|
|
5
14
|
import { ActionBar } from "../actions/ActionBar";
|
|
6
15
|
import { SheetModal } from "./index";
|
|
@@ -107,3 +116,267 @@ export const OpenOnMount: Story = {
|
|
|
107
116
|
name: "Open",
|
|
108
117
|
render: () => <Harness startOpen />,
|
|
109
118
|
};
|
|
119
|
+
|
|
120
|
+
type Bounds = { x: number; y: number; width: number; height: number };
|
|
121
|
+
type Reading<T> = T | "unmeasured" | "unavailable" | "invalid";
|
|
122
|
+
type FixtureMode = "subject" | "control-240";
|
|
123
|
+
type FixtureReadings = {
|
|
124
|
+
frameLayout: Reading<Bounds>;
|
|
125
|
+
toolbarLayout: Reading<Bounds>;
|
|
126
|
+
viewportLayout: Reading<Bounds>;
|
|
127
|
+
scrollLayout: Reading<Bounds>;
|
|
128
|
+
frameWindow: Reading<Bounds>;
|
|
129
|
+
viewportWindow: Reading<Bounds>;
|
|
130
|
+
scrollWindow: Reading<Bounds>;
|
|
131
|
+
tailWindow: Reading<Bounds>;
|
|
132
|
+
content: Reading<{ width: number; height: number }>;
|
|
133
|
+
offset: Reading<{ x: number; y: number }>;
|
|
134
|
+
sampleWindow: ReturnType<typeof useWindowDimensions> | "unmeasured";
|
|
135
|
+
sample: number;
|
|
136
|
+
tailPresses: number;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
function emptyReadings(): FixtureReadings {
|
|
140
|
+
return {
|
|
141
|
+
frameLayout: "unmeasured",
|
|
142
|
+
toolbarLayout: "unmeasured",
|
|
143
|
+
viewportLayout: "unmeasured",
|
|
144
|
+
scrollLayout: "unmeasured",
|
|
145
|
+
frameWindow: "unmeasured",
|
|
146
|
+
viewportWindow: "unmeasured",
|
|
147
|
+
scrollWindow: "unmeasured",
|
|
148
|
+
tailWindow: "unmeasured",
|
|
149
|
+
content: "unmeasured",
|
|
150
|
+
offset: "unmeasured",
|
|
151
|
+
sampleWindow: "unmeasured",
|
|
152
|
+
sample: 0,
|
|
153
|
+
tailPresses: 0,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function bounds(x: number, y: number, width: number, height: number): Reading<Bounds> {
|
|
158
|
+
return [x, y, width, height].every(Number.isFinite) && width >= 0 && height >= 0
|
|
159
|
+
? { x, y, width, height }
|
|
160
|
+
: "invalid";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function OwnedBodyFixture({ measured }: { measured: boolean }) {
|
|
164
|
+
const window = useWindowDimensions();
|
|
165
|
+
const [open, setOpen] = useState(false);
|
|
166
|
+
const [mode, setMode] = useState<FixtureMode>("subject");
|
|
167
|
+
const [fill, setFill] = useState(false);
|
|
168
|
+
const [readings, setReadings] = useState(emptyReadings);
|
|
169
|
+
const active = useRef(false);
|
|
170
|
+
const generation = useRef(0);
|
|
171
|
+
const sample = useRef(0);
|
|
172
|
+
const frameRef = useRef<TamaguiElement>(null);
|
|
173
|
+
const viewportRef = useRef<TamaguiElement>(null);
|
|
174
|
+
const scrollRef = useRef<React.ComponentRef<typeof ScrollView>>(null);
|
|
175
|
+
const tailRef = useRef<TamaguiElement>(null);
|
|
176
|
+
const presentation = generation.current;
|
|
177
|
+
const kind = measured ? "measured" : "scroll";
|
|
178
|
+
|
|
179
|
+
function present(nextMode: FixtureMode, nextFill = false) {
|
|
180
|
+
generation.current += 1;
|
|
181
|
+
sample.current = 0;
|
|
182
|
+
active.current = true;
|
|
183
|
+
setMode(nextMode);
|
|
184
|
+
setFill(nextFill);
|
|
185
|
+
setReadings(emptyReadings());
|
|
186
|
+
setOpen(true);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function close() {
|
|
190
|
+
active.current = false;
|
|
191
|
+
setOpen(false);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function record(patch: Partial<FixtureReadings>) {
|
|
195
|
+
if (!active.current || generation.current !== presentation) return;
|
|
196
|
+
setReadings((previous) => {
|
|
197
|
+
const next = { ...previous, ...patch };
|
|
198
|
+
return JSON.stringify(next) === JSON.stringify(previous) ? previous : next;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function onLayout(key: "frameLayout" | "toolbarLayout" | "viewportLayout" | "scrollLayout") {
|
|
203
|
+
return ({ nativeEvent: { layout } }: LayoutChangeEvent) =>
|
|
204
|
+
record({ [key]: bounds(layout.x, layout.y, layout.width, layout.height) });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function measureBounds() {
|
|
208
|
+
const currentSample = ++sample.current;
|
|
209
|
+
record({
|
|
210
|
+
sample: currentSample,
|
|
211
|
+
frameWindow: "unmeasured",
|
|
212
|
+
viewportWindow: "unmeasured",
|
|
213
|
+
scrollWindow: "unmeasured",
|
|
214
|
+
tailWindow: "unmeasured",
|
|
215
|
+
sampleWindow: { ...window },
|
|
216
|
+
});
|
|
217
|
+
for (const [key, node] of [
|
|
218
|
+
["frameWindow", frameRef.current],
|
|
219
|
+
["viewportWindow", viewportRef.current],
|
|
220
|
+
["scrollWindow", scrollRef.current?.getNativeScrollRef?.()],
|
|
221
|
+
["tailWindow", tailRef.current],
|
|
222
|
+
] as const) {
|
|
223
|
+
if (!node || typeof node.measureInWindow !== "function") {
|
|
224
|
+
record({ [key]: "unavailable" });
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
node.measureInWindow((x, y, width, height) => {
|
|
228
|
+
if (sample.current === currentSample) record({ [key]: bounds(x, y, width, height) });
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const viewport = readings.viewportLayout;
|
|
234
|
+
const showRows = !measured || (typeof viewport === "object" && viewport.height > 0);
|
|
235
|
+
const height = (value: Reading<Bounds>) => (typeof value === "object" ? value.height : value);
|
|
236
|
+
const diagnostics = {
|
|
237
|
+
kind,
|
|
238
|
+
mode,
|
|
239
|
+
fill,
|
|
240
|
+
open,
|
|
241
|
+
presentation,
|
|
242
|
+
platform: Platform.OS,
|
|
243
|
+
window,
|
|
244
|
+
sheetFrameWindow: "unavailable: SheetModal has no public frame ref",
|
|
245
|
+
...readings,
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<FixtureStack gap="$3" padding="$3">
|
|
250
|
+
<FixtureText>{measured ? "Owned measured viewport" : "Owned ScrollView"}</FixtureText>
|
|
251
|
+
<Button onPress={() => present("subject")}>Open flex subject</Button>
|
|
252
|
+
<Button onPress={() => present("subject", true)}>Open flex subject (fill)</Button>
|
|
253
|
+
<Button onPress={() => present("control-240")}>Open 240pt control</Button>
|
|
254
|
+
<FixtureText>
|
|
255
|
+
Measure after the sheet settles. Close it to read the captured bounds below. Repeat after
|
|
256
|
+
dragging, scrolling, rotating or using the keyboard. A declared size is not a measurement.
|
|
257
|
+
</FixtureText>
|
|
258
|
+
<FixtureText testID="owned-sheet-readings" selectable>
|
|
259
|
+
{JSON.stringify(diagnostics, null, 2)}
|
|
260
|
+
</FixtureText>
|
|
261
|
+
<PublicSheetModal
|
|
262
|
+
open={open}
|
|
263
|
+
onOpenChange={(next) => {
|
|
264
|
+
if (!next) close();
|
|
265
|
+
}}
|
|
266
|
+
snapPoint={88}
|
|
267
|
+
scrollable={false}
|
|
268
|
+
fill={fill}
|
|
269
|
+
header={
|
|
270
|
+
<FixtureStack gap="$1" flexShrink={0}>
|
|
271
|
+
<FixtureText numberOfLines={1}>
|
|
272
|
+
{kind} / {mode} / fill {fill ? "on" : "off"}
|
|
273
|
+
</FixtureText>
|
|
274
|
+
<FixtureText numberOfLines={1}>
|
|
275
|
+
Body {height(readings.frameLayout)} / toolbar {height(readings.toolbarLayout)} /
|
|
276
|
+
viewport {height(viewport)}
|
|
277
|
+
</FixtureText>
|
|
278
|
+
<FixtureText numberOfLines={1}>
|
|
279
|
+
Offset {typeof readings.offset === "object" ? readings.offset.y : readings.offset} /
|
|
280
|
+
tail presses {readings.tailPresses}
|
|
281
|
+
</FixtureText>
|
|
282
|
+
<XStack gap="$2">
|
|
283
|
+
<Button flex={1} onPress={measureBounds}>
|
|
284
|
+
Measure bounds
|
|
285
|
+
</Button>
|
|
286
|
+
<Button flex={1} onPress={close}>
|
|
287
|
+
Close fixture
|
|
288
|
+
</Button>
|
|
289
|
+
</XStack>
|
|
290
|
+
</FixtureStack>
|
|
291
|
+
}
|
|
292
|
+
>
|
|
293
|
+
<FixtureStack
|
|
294
|
+
key={presentation}
|
|
295
|
+
ref={frameRef}
|
|
296
|
+
testID="owned-sheet-frame"
|
|
297
|
+
collapsable={false}
|
|
298
|
+
minHeight={0}
|
|
299
|
+
minWidth={0}
|
|
300
|
+
{...(mode === "control-240" ? { height: 240, flexGrow: 0, flexShrink: 0 } : { flex: 1 })}
|
|
301
|
+
onLayout={onLayout("frameLayout")}
|
|
302
|
+
>
|
|
303
|
+
<FixtureStack
|
|
304
|
+
testID="owned-sheet-toolbar"
|
|
305
|
+
collapsable={false}
|
|
306
|
+
flexShrink={0}
|
|
307
|
+
onLayout={onLayout("toolbarLayout")}
|
|
308
|
+
>
|
|
309
|
+
<FixtureText>Records toolbar</FixtureText>
|
|
310
|
+
</FixtureStack>
|
|
311
|
+
<FixtureStack
|
|
312
|
+
ref={viewportRef}
|
|
313
|
+
testID="owned-sheet-viewport"
|
|
314
|
+
collapsable={false}
|
|
315
|
+
flex={1}
|
|
316
|
+
minHeight={0}
|
|
317
|
+
minWidth={0}
|
|
318
|
+
onLayout={onLayout("viewportLayout")}
|
|
319
|
+
>
|
|
320
|
+
{showRows && (
|
|
321
|
+
<ScrollView
|
|
322
|
+
ref={scrollRef}
|
|
323
|
+
testID="owned-sheet-scroll"
|
|
324
|
+
flex={1}
|
|
325
|
+
minHeight={0}
|
|
326
|
+
keyboardShouldPersistTaps="handled"
|
|
327
|
+
scrollEventThrottle={32}
|
|
328
|
+
onLayout={onLayout("scrollLayout")}
|
|
329
|
+
onContentSizeChange={(width, height) =>
|
|
330
|
+
record({
|
|
331
|
+
content:
|
|
332
|
+
[width, height].every(Number.isFinite) && width >= 0 && height >= 0
|
|
333
|
+
? { width, height }
|
|
334
|
+
: "invalid",
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
onScroll={({ nativeEvent: { contentOffset } }) =>
|
|
338
|
+
record({
|
|
339
|
+
offset: [contentOffset.x, contentOffset.y].every(Number.isFinite)
|
|
340
|
+
? { x: contentOffset.x, y: contentOffset.y }
|
|
341
|
+
: "invalid",
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
>
|
|
345
|
+
<FixtureStack gap="$2">
|
|
346
|
+
<Input label="Keyboard probe" placeholder="Generic text only" />
|
|
347
|
+
{Array.from({ length: 60 }, (_, index) => (
|
|
348
|
+
<FixtureStack key={index} gap="$1" paddingVertical="$2">
|
|
349
|
+
<FixtureText>Record {index + 1}</FixtureText>
|
|
350
|
+
{Array.from({ length: 1 + (index % 4) }, (_, line) => (
|
|
351
|
+
<FixtureText key={line}>
|
|
352
|
+
Generic detail {line + 1} for this record.
|
|
353
|
+
</FixtureText>
|
|
354
|
+
))}
|
|
355
|
+
</FixtureStack>
|
|
356
|
+
))}
|
|
357
|
+
<FixtureStack ref={tailRef} testID="owned-sheet-tail" collapsable={false}>
|
|
358
|
+
<Button onPress={() => record({ tailPresses: readings.tailPresses + 1 })}>
|
|
359
|
+
Activate Record 60
|
|
360
|
+
</Button>
|
|
361
|
+
</FixtureStack>
|
|
362
|
+
</FixtureStack>
|
|
363
|
+
</ScrollView>
|
|
364
|
+
)}
|
|
365
|
+
</FixtureStack>
|
|
366
|
+
</FixtureStack>
|
|
367
|
+
</PublicSheetModal>
|
|
368
|
+
</FixtureStack>
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
export const OwnedMeasuredViewport: Story = {
|
|
373
|
+
name: "Owned measured viewport",
|
|
374
|
+
argTypes: { snapPoint: { control: false }, scrollable: { control: false } },
|
|
375
|
+
render: () => <OwnedBodyFixture measured />,
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
export const OwnedScrollView: Story = {
|
|
379
|
+
name: "Owned ScrollView",
|
|
380
|
+
argTypes: { snapPoint: { control: false }, scrollable: { control: false } },
|
|
381
|
+
render: () => <OwnedBodyFixture measured={false} />,
|
|
382
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-299: an owned ScrollView inside the native sheet never scrolled on
|
|
3
|
+
* the iOS simulator, while the same swipe scrolled the Combobox sheet.
|
|
4
|
+
*
|
|
5
|
+
* On native, tamagui turns a press or focus-visible pseudo into a JS
|
|
6
|
+
* responder claim (`onStartShouldSetResponder` returning true). A surface
|
|
7
|
+
* holding that claim takes every touch that starts on plain content inside
|
|
8
|
+
* it, and a responder ancestor stops the ScrollView's own pan.
|
|
9
|
+
*/
|
|
10
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
11
|
+
import { cleanup } from "@testing-library/react";
|
|
12
|
+
import { afterEach, expect, it, vi } from "vitest";
|
|
13
|
+
import { Text } from "tamagui";
|
|
14
|
+
import { SheetModal } from "./index.native";
|
|
15
|
+
|
|
16
|
+
const stacks = vi.hoisted(() => new Map<string, Record<string, unknown>>());
|
|
17
|
+
|
|
18
|
+
vi.mock("react-native-web", async (importOriginal) => ({
|
|
19
|
+
...(await importOriginal<typeof import("react-native")>()),
|
|
20
|
+
ActionSheetIOS: undefined,
|
|
21
|
+
Modal: ({ children }: { children: import("react").ReactNode }) => children,
|
|
22
|
+
}));
|
|
23
|
+
vi.mock("tamagui", async (importOriginal) => {
|
|
24
|
+
const actual = await importOriginal<typeof import("tamagui")>();
|
|
25
|
+
const React = await import("react");
|
|
26
|
+
const YStack = React.forwardRef((props: Record<string, unknown>, ref) => {
|
|
27
|
+
if (typeof props.testID === "string") stacks.set(props.testID, props);
|
|
28
|
+
return React.createElement(actual.YStack as never, { ...props, ref });
|
|
29
|
+
});
|
|
30
|
+
return { ...actual, YStack };
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
cleanup();
|
|
35
|
+
stacks.clear();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const claimsResponder = [
|
|
39
|
+
"pressStyle",
|
|
40
|
+
"focusStyle",
|
|
41
|
+
"focusVisibleStyle",
|
|
42
|
+
"onPress",
|
|
43
|
+
"onPressIn",
|
|
44
|
+
"onPressOut",
|
|
45
|
+
"onLongPress",
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
it("keeps every native sheet stack out of the touch responder", () => {
|
|
49
|
+
for (const fill of [false, true]) {
|
|
50
|
+
renderWithProviders(
|
|
51
|
+
<SheetModal open onOpenChange={() => {}} fill={fill} scrollable>
|
|
52
|
+
<Text>row</Text>
|
|
53
|
+
</SheetModal>,
|
|
54
|
+
);
|
|
55
|
+
for (const id of ["sheet-modal-surface", "sheet-modal-content"]) {
|
|
56
|
+
const stack = stacks.get(id);
|
|
57
|
+
expect(stack, id).toBeDefined();
|
|
58
|
+
for (const key of claimsResponder) expect(stack, `${id} ${key}`).not.toHaveProperty(key);
|
|
59
|
+
}
|
|
60
|
+
cleanup();
|
|
61
|
+
stacks.clear();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
@@ -10,7 +10,15 @@
|
|
|
10
10
|
* height with a large-detent cap. LC-71: the frame is not a control.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
useCallback,
|
|
15
|
+
useContext,
|
|
16
|
+
useEffect,
|
|
17
|
+
useLayoutEffect,
|
|
18
|
+
useMemo,
|
|
19
|
+
useRef,
|
|
20
|
+
useState,
|
|
21
|
+
} from "react";
|
|
14
22
|
import {
|
|
15
23
|
Animated,
|
|
16
24
|
Easing,
|
|
@@ -23,6 +31,7 @@ import {
|
|
|
23
31
|
View as RNView,
|
|
24
32
|
useWindowDimensions,
|
|
25
33
|
} from "react-native";
|
|
34
|
+
import { SafeAreaInsetsContext, initialWindowMetrics } from "react-native-safe-area-context";
|
|
26
35
|
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
27
36
|
import { minSheetHeight, resolveSheetDetents } from "./detents";
|
|
28
37
|
import { useTranslation } from "../shared/i18n";
|
|
@@ -40,6 +49,14 @@ const backdropStrip = 48;
|
|
|
40
49
|
// Released more than this far below the smallest detent, the sheet dismisses.
|
|
41
50
|
const dismissThreshold = 56;
|
|
42
51
|
const IN_DIALOG_REGION = { inDialogRegion: true } as const;
|
|
52
|
+
/*
|
|
53
|
+
* MPO-299 fill: an owned viewport bootstraps from zero unless EVERY link
|
|
54
|
+
* between the capped frame and the body gives way at once — frame height,
|
|
55
|
+
* surface, padded stack, body slot. Opening only the outer one keeps the
|
|
56
|
+
* measured-zero failure, so these are applied together or not at all.
|
|
57
|
+
*/
|
|
58
|
+
const fillSlot = { flex: 1, minHeight: 0 } as const;
|
|
59
|
+
const nonShrinking = { flexShrink: 0 } as const;
|
|
43
60
|
|
|
44
61
|
export function SheetModal({
|
|
45
62
|
open,
|
|
@@ -48,11 +65,13 @@ export function SheetModal({
|
|
|
48
65
|
header,
|
|
49
66
|
snapPoint,
|
|
50
67
|
scrollable,
|
|
68
|
+
fill = false,
|
|
51
69
|
}: SheetModalProps) {
|
|
52
70
|
const { t } = useTranslation();
|
|
53
71
|
const { knobProps } = useResolvedKnobs();
|
|
54
72
|
const { height: windowHeight } = useWindowDimensions();
|
|
55
73
|
const keyboardInset = useKeyboardInset();
|
|
74
|
+
const topInset = useContext(SafeAreaInsetsContext)?.top ?? initialWindowMetrics?.insets.top ?? 0;
|
|
56
75
|
const [backdropArmed, setBackdropArmed] = useState(false);
|
|
57
76
|
const armTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
58
77
|
|
|
@@ -62,11 +81,12 @@ export function SheetModal({
|
|
|
62
81
|
if (backdropArmed) close();
|
|
63
82
|
}, [backdropArmed, close]);
|
|
64
83
|
|
|
65
|
-
// MPO-64: the sheet ends above the keyboard rather than running under it
|
|
84
|
+
// MPO-64: the sheet ends above the keyboard rather than running under it,
|
|
85
|
+
// and below the status bar with a strip of backdrop still showing.
|
|
66
86
|
const available = Math.max(0, windowHeight - keyboardInset);
|
|
67
87
|
const maxHeight = Math.max(
|
|
68
88
|
minSheetHeight,
|
|
69
|
-
Math.round(Math.min(windowHeight * sheetMaxHeightRatio, available - backdropStrip)),
|
|
89
|
+
Math.round(Math.min(windowHeight * sheetMaxHeightRatio, available - topInset - backdropStrip)),
|
|
70
90
|
);
|
|
71
91
|
|
|
72
92
|
/*
|
|
@@ -118,8 +138,59 @@ export function SheetModal({
|
|
|
118
138
|
const presentationRef = useRef(0);
|
|
119
139
|
const activeRef = useRef(false);
|
|
120
140
|
|
|
141
|
+
/*
|
|
142
|
+
* MPO-68 / MPO-299: a sheet at rest below full height is LAID OUT at that
|
|
143
|
+
* height. Translating a full-height frame down pushed its bottom off the
|
|
144
|
+
* screen, or under the keyboard, and the scroll owner inside still measured
|
|
145
|
+
* the full height, so the tail could never be scrolled into view.
|
|
146
|
+
*
|
|
147
|
+
* `frameCap` rides the same Animated.View as `translateY`, so the swap
|
|
148
|
+
* between "full height, translated" and "detent height, at 0" lands in one
|
|
149
|
+
* commit and the top edge does not move. `restHeightRef` is null at full
|
|
150
|
+
* height; a gesture always runs uncapped, in `travel` coordinates.
|
|
151
|
+
*/
|
|
152
|
+
const frameCap = useRef(new Animated.Value(maxHeight)).current;
|
|
153
|
+
const maxHeightRef = useRef(maxHeight);
|
|
154
|
+
const restHeightRef = useRef<number | null>(null);
|
|
155
|
+
// The last uncapped layout, and whether it filled the max height. A capped
|
|
156
|
+
// frame measures only its cap, so when the keyboard moves the max height
|
|
157
|
+
// under a resting sheet, its full height is re-derived from these.
|
|
158
|
+
const naturalRef = useRef(0);
|
|
159
|
+
const filledRef = useRef(false);
|
|
160
|
+
|
|
161
|
+
useLayoutEffect(() => {
|
|
162
|
+
maxHeightRef.current = maxHeight;
|
|
163
|
+
const rest = restHeightRef.current;
|
|
164
|
+
frameCap.setValue(rest === null ? maxHeight : Math.min(maxHeight, rest));
|
|
165
|
+
if (rest !== null && naturalRef.current > 0) {
|
|
166
|
+
setMeasuredHeight(filledRef.current ? maxHeight : Math.min(naturalRef.current, maxHeight));
|
|
167
|
+
}
|
|
168
|
+
}, [frameCap, maxHeight]);
|
|
169
|
+
|
|
170
|
+
const restAt = useCallback(
|
|
171
|
+
(height: number) => {
|
|
172
|
+
restHeightRef.current = height;
|
|
173
|
+
frameCap.setValue(Math.min(maxHeightRef.current, height));
|
|
174
|
+
restRef.current = 0;
|
|
175
|
+
translateY.setValue(0);
|
|
176
|
+
},
|
|
177
|
+
[frameCap, translateY],
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const releaseRest = useCallback(() => {
|
|
181
|
+
const rest = restHeightRef.current;
|
|
182
|
+
if (rest === null) return;
|
|
183
|
+
restHeightRef.current = null;
|
|
184
|
+
const offset = Math.max(0, travelRef.current - Math.min(maxHeightRef.current, rest));
|
|
185
|
+
frameCap.setValue(maxHeightRef.current);
|
|
186
|
+
restRef.current = offset;
|
|
187
|
+
translateY.setValue(offset);
|
|
188
|
+
}, [frameCap, translateY]);
|
|
189
|
+
|
|
121
190
|
const settleTo = useCallback(
|
|
122
|
-
(
|
|
191
|
+
(height: number, velocity = 0) => {
|
|
192
|
+
const presentation = presentationRef.current;
|
|
193
|
+
const toValue = Math.max(0, travelRef.current - height);
|
|
123
194
|
restRef.current = toValue;
|
|
124
195
|
Animated.spring(translateY, {
|
|
125
196
|
toValue,
|
|
@@ -132,9 +203,12 @@ export function SheetModal({
|
|
|
132
203
|
// Modal does not advance on the New Architecture, and the drag path
|
|
133
204
|
// already writes this value from JS.
|
|
134
205
|
useNativeDriver: false,
|
|
135
|
-
}).start()
|
|
206
|
+
}).start(({ finished }) => {
|
|
207
|
+
if (!finished || toValue === 0) return;
|
|
208
|
+
if (activeRef.current && presentation === presentationRef.current) restAt(height);
|
|
209
|
+
});
|
|
136
210
|
},
|
|
137
|
-
[translateY],
|
|
211
|
+
[restAt, translateY],
|
|
138
212
|
);
|
|
139
213
|
|
|
140
214
|
const dismiss = useCallback(
|
|
@@ -162,10 +236,15 @@ export function SheetModal({
|
|
|
162
236
|
PanResponder.create({
|
|
163
237
|
onStartShouldSetPanResponder: () => true,
|
|
164
238
|
onMoveShouldSetPanResponder: (_evt, g) => Math.abs(g.dy) > 2,
|
|
239
|
+
// Lifting a rest cap can scroll the list inside, and a scroll lets
|
|
240
|
+
// any ancestor ScrollView the finger started under claim the touch,
|
|
241
|
+
// ending the drag and blurring a focused input on release.
|
|
242
|
+
onPanResponderTerminationRequest: () => false,
|
|
165
243
|
onPanResponderGrant: () => {
|
|
166
244
|
translateY.stopAnimation((value) => {
|
|
167
245
|
if (typeof value === "number" && Number.isFinite(value)) restRef.current = value;
|
|
168
246
|
});
|
|
247
|
+
releaseRest();
|
|
169
248
|
},
|
|
170
249
|
onPanResponderMove: (_evt, g) => {
|
|
171
250
|
const next = restRef.current + g.dy;
|
|
@@ -190,11 +269,11 @@ export function SheetModal({
|
|
|
190
269
|
best = height;
|
|
191
270
|
}
|
|
192
271
|
}
|
|
193
|
-
settleTo(
|
|
272
|
+
settleTo(best, g.vy);
|
|
194
273
|
},
|
|
195
|
-
onPanResponderTerminate: () => settleTo(restRef.current),
|
|
274
|
+
onPanResponderTerminate: () => settleTo(travelRef.current - restRef.current),
|
|
196
275
|
}),
|
|
197
|
-
[dismiss, settleTo, translateY],
|
|
276
|
+
[dismiss, releaseRest, settleTo, translateY],
|
|
198
277
|
);
|
|
199
278
|
|
|
200
279
|
/*
|
|
@@ -237,6 +316,8 @@ export function SheetModal({
|
|
|
237
316
|
useEffect(() => {
|
|
238
317
|
presentationRef.current += 1;
|
|
239
318
|
activeRef.current = open;
|
|
319
|
+
restHeightRef.current = null;
|
|
320
|
+
frameCap.setValue(maxHeightRef.current);
|
|
240
321
|
if (open) {
|
|
241
322
|
enter();
|
|
242
323
|
} else {
|
|
@@ -256,7 +337,7 @@ export function SheetModal({
|
|
|
256
337
|
}
|
|
257
338
|
translateY.stopAnimation();
|
|
258
339
|
};
|
|
259
|
-
}, [open, enter, translateY]);
|
|
340
|
+
}, [open, enter, frameCap, translateY]);
|
|
260
341
|
|
|
261
342
|
return (
|
|
262
343
|
<Modal
|
|
@@ -278,31 +359,43 @@ export function SheetModal({
|
|
|
278
359
|
</Pressable>
|
|
279
360
|
<Animated.View
|
|
280
361
|
onLayout={(e) => {
|
|
362
|
+
if (restHeightRef.current !== null) return;
|
|
281
363
|
const h = Math.round(e.nativeEvent.layout.height);
|
|
282
|
-
if (h
|
|
364
|
+
if (h <= 0) return;
|
|
365
|
+
naturalRef.current = h;
|
|
366
|
+
filledRef.current = h >= maxHeightRef.current - 1;
|
|
367
|
+
if (h !== measuredHeight) setMeasuredHeight(h);
|
|
283
368
|
}}
|
|
369
|
+
testID="sheet-modal-frame"
|
|
284
370
|
style={{
|
|
285
371
|
// MPO-64: flex children default to flexShrink 0, so without this
|
|
286
372
|
// the sheet cannot give way to the keyboard.
|
|
287
373
|
flexShrink: 1,
|
|
288
374
|
minHeight: 0,
|
|
289
|
-
maxHeight,
|
|
375
|
+
maxHeight: frameCap,
|
|
376
|
+
// The cap is already keyboard- and window-aware; fill only asks
|
|
377
|
+
// for it as a definite height rather than an upper bound.
|
|
378
|
+
...(fill ? { height: frameCap } : null),
|
|
290
379
|
transform: [{ translateY }],
|
|
291
380
|
}}
|
|
292
381
|
>
|
|
293
382
|
<YStack
|
|
383
|
+
testID="sheet-modal-surface"
|
|
294
384
|
{...knobProps.surface}
|
|
295
385
|
{...knobProps.borderRadius}
|
|
296
386
|
borderBottomLeftRadius={0}
|
|
297
387
|
borderBottomRightRadius={0}
|
|
298
388
|
elevation={knobProps.elevation}
|
|
299
389
|
maxHeight={maxHeight}
|
|
390
|
+
flexShrink={1}
|
|
391
|
+
minHeight={0}
|
|
392
|
+
{...(fill ? fillSlot : null)}
|
|
300
393
|
paddingTop="$2"
|
|
301
394
|
paddingBottom={keyboardInset > 0 ? 8 : bottomInset}
|
|
302
395
|
overflow="hidden"
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
396
|
+
// No focus or press pseudo on this surface: on native tamagui
|
|
397
|
+
// turns one into a touch-responder claim, and a responder here
|
|
398
|
+
// takes every drag from the ScrollView inside (MPO-299).
|
|
306
399
|
accessibilityViewIsModal
|
|
307
400
|
onAccessibilityEscape={close}
|
|
308
401
|
>
|
|
@@ -316,11 +409,13 @@ export function SheetModal({
|
|
|
316
409
|
{...panResponder.panHandlers}
|
|
317
410
|
accessibilityRole="adjustable"
|
|
318
411
|
accessibilityLabel={t("Drag to resize")}
|
|
412
|
+
testID="sheet-modal-grabber"
|
|
319
413
|
style={{
|
|
320
414
|
alignSelf: "stretch",
|
|
321
415
|
alignItems: "center",
|
|
322
416
|
paddingTop: 3,
|
|
323
417
|
paddingBottom: 11,
|
|
418
|
+
...(fill ? nonShrinking : null),
|
|
324
419
|
}}
|
|
325
420
|
>
|
|
326
421
|
<View
|
|
@@ -334,17 +429,44 @@ export function SheetModal({
|
|
|
334
429
|
</RNView>
|
|
335
430
|
<DialogRegionContext.Provider value={IN_DIALOG_REGION}>
|
|
336
431
|
<YStack
|
|
432
|
+
testID="sheet-modal-content"
|
|
337
433
|
padding={knobProps.panelPadding.padding}
|
|
338
434
|
gap={knobProps.gap.gap}
|
|
339
435
|
flexShrink={1}
|
|
436
|
+
{...(fill ? fillSlot : null)}
|
|
340
437
|
>
|
|
341
|
-
{
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
{
|
|
345
|
-
|
|
438
|
+
{fill ? (
|
|
439
|
+
<>
|
|
440
|
+
{header ? <RNView style={nonShrinking}>{header}</RNView> : null}
|
|
441
|
+
<RNView testID="sheet-modal-body" style={fillSlot}>
|
|
442
|
+
{scrollable ? (
|
|
443
|
+
<RNScrollView
|
|
444
|
+
testID="sheet-modal-scroll"
|
|
445
|
+
style={fillSlot}
|
|
446
|
+
keyboardShouldPersistTaps="handled"
|
|
447
|
+
>
|
|
448
|
+
{children}
|
|
449
|
+
</RNScrollView>
|
|
450
|
+
) : (
|
|
451
|
+
children
|
|
452
|
+
)}
|
|
453
|
+
</RNView>
|
|
454
|
+
</>
|
|
346
455
|
) : (
|
|
347
|
-
|
|
456
|
+
<>
|
|
457
|
+
{header}
|
|
458
|
+
{scrollable ? (
|
|
459
|
+
<RNScrollView
|
|
460
|
+
testID="sheet-modal-scroll"
|
|
461
|
+
style={{ flexGrow: 0 }}
|
|
462
|
+
keyboardShouldPersistTaps="handled"
|
|
463
|
+
>
|
|
464
|
+
{children}
|
|
465
|
+
</RNScrollView>
|
|
466
|
+
) : (
|
|
467
|
+
children
|
|
468
|
+
)}
|
|
469
|
+
</>
|
|
348
470
|
)}
|
|
349
471
|
</YStack>
|
|
350
472
|
</DialogRegionContext.Provider>
|