@multiplatform.one/components 7.6.3 → 7.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/Accordion/index.native.js +1 -1
- package/dist/cjs/Accordion/index.native.js.map +1 -1
- package/dist/cjs/Alert/index.cjs +13 -29
- package/dist/cjs/Alert/index.native.js +17 -37
- package/dist/cjs/Alert/index.native.js.map +1 -1
- package/dist/cjs/AnimateHeight/index.native.js.map +1 -1
- package/dist/cjs/Avatar/getInitials.native.js.map +1 -1
- package/dist/cjs/Avatar/index.native.js.map +1 -1
- package/dist/cjs/Badge/index.cjs +4 -3
- package/dist/cjs/Badge/index.native.js +7 -6
- package/dist/cjs/Badge/index.native.js.map +1 -1
- package/dist/cjs/Button.native.js.map +1 -1
- package/dist/cjs/Card.cjs +1 -9
- package/dist/cjs/Card.native.js +2 -7
- package/dist/cjs/Card.native.js.map +1 -1
- package/dist/cjs/CardFooter.cjs +1 -9
- package/dist/cjs/CardFooter.native.js +2 -7
- package/dist/cjs/CardFooter.native.js.map +1 -1
- package/dist/cjs/CardHeader.cjs +1 -9
- package/dist/cjs/CardHeader.native.js +2 -7
- package/dist/cjs/CardHeader.native.js.map +1 -1
- package/dist/cjs/Carousel/index.native.js +1 -1
- package/dist/cjs/Carousel/index.native.js.map +1 -1
- package/dist/cjs/Chip/index.native.js.map +1 -1
- package/dist/cjs/ContextMenu/index.native.js.map +1 -1
- package/dist/cjs/CopyField/index.native.js.map +1 -1
- package/dist/cjs/DotIndicator/index.native.js.map +1 -1
- package/dist/cjs/DropdownMenu/index.native.js.map +1 -1
- package/dist/cjs/ErrorBoundary/index.native.js.map +1 -1
- package/dist/cjs/Heading.native.js.map +1 -1
- package/dist/cjs/Meter/index.native.js +1 -1
- package/dist/cjs/Meter/index.native.js.map +1 -1
- package/dist/cjs/Meter/meter.native.js.map +1 -1
- package/dist/cjs/Pagination.native.js +1 -1
- package/dist/cjs/Pagination.native.js.map +1 -1
- package/dist/cjs/ProgressSteps/index.cjs +13 -6
- package/dist/cjs/ProgressSteps/index.native.js +14 -6
- package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
- package/dist/cjs/Quote/index.native.js.map +1 -1
- package/dist/cjs/Separator/index.native.js.map +1 -1
- package/dist/cjs/SheetModal/detents.cjs +46 -0
- package/dist/cjs/SheetModal/detents.native.js +54 -0
- package/dist/cjs/SheetModal/detents.native.js.map +1 -0
- package/dist/cjs/SheetModal/index.native.js +8 -11
- package/dist/cjs/SheetModal/index.native.js.map +1 -1
- package/dist/cjs/Skeleton/index.native.js.map +1 -1
- package/dist/cjs/SkipLink/index.native.js.map +1 -1
- package/dist/cjs/SortableList/SortableHandle.native.js.map +1 -1
- package/dist/cjs/SortableList/index.cjs +1 -1
- package/dist/cjs/SortableList/index.native.js +1 -1
- package/dist/cjs/SortableList/index.native.js.map +1 -1
- package/dist/cjs/SortableList/useSortableRows.native.js.map +1 -1
- package/dist/cjs/Tabs/index.native.js.map +1 -1
- package/dist/cjs/Text.native.js.map +1 -1
- package/dist/cjs/Toast/index.native.js.map +1 -1
- package/dist/cjs/Toast/store.native.js.map +1 -1
- package/dist/cjs/Tooltip/nativePress.native.js.map +1 -1
- package/dist/cjs/Tooltip/tooltipShared.native.js.map +1 -1
- package/dist/cjs/TreeSelect/index.native.js +1 -1
- package/dist/cjs/TreeSelect/index.native.js.map +1 -1
- package/dist/cjs/TreeSelect/treeSelectModel.native.js.map +1 -1
- package/dist/cjs/Video/PlayerChrome.native.js.map +1 -1
- package/dist/cjs/Video/VideoFrame.native.js.map +1 -1
- package/dist/cjs/Video/types.native.js.map +1 -1
- package/dist/cjs/Wheel/index.native.js.map +1 -1
- package/dist/cjs/Wizard/index.native.js +2 -2
- package/dist/cjs/Wizard/index.native.js.map +1 -1
- package/dist/cjs/actions/ActionBar.cjs +3 -1
- package/dist/cjs/actions/ActionBar.native.js +11 -2
- package/dist/cjs/actions/ActionBar.native.js.map +1 -1
- package/dist/cjs/actions/DestructiveAction.native.js.map +1 -1
- package/dist/cjs/actions/devWarn.native.js.map +1 -1
- package/dist/cjs/actions/index.native.js.map +1 -1
- package/dist/cjs/actions/severity.native.js.map +1 -1
- package/dist/cjs/charts/Axis.native.js.map +1 -1
- package/dist/cjs/charts/BarChart.native.js.map +1 -1
- package/dist/cjs/charts/ChartSurface.native.js.map +1 -1
- package/dist/cjs/charts/LineChart.native.js.map +1 -1
- package/dist/cjs/charts/PieChart.native.js.map +1 -1
- package/dist/cjs/charts/Sparkline.native.js.map +1 -1
- package/dist/cjs/charts/accessibility.native.js.map +1 -1
- package/dist/cjs/charts/composeChart.native.js.map +1 -1
- package/dist/cjs/charts/index.native.js.map +1 -1
- package/dist/cjs/charts/math.native.js.map +1 -1
- package/dist/cjs/charts/series.native.js.map +1 -1
- package/dist/cjs/charts/svg.native.js.map +1 -1
- package/dist/cjs/charts/types.native.js.map +1 -1
- package/dist/cjs/charts/useChartTheme.native.js.map +1 -1
- package/dist/cjs/code/Code/index.cjs +2 -15
- package/dist/cjs/code/Code/index.native.js +3 -13
- package/dist/cjs/code/Code/index.native.js.map +1 -1
- package/dist/cjs/code/CodeBlock/index.native.js +6 -6
- package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
- package/dist/cjs/code/HighlightedCode/index.cjs +0 -5
- package/dist/cjs/code/HighlightedCode/index.native.js +0 -5
- package/dist/cjs/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/cjs/code/Highlighter/index.native.js.map +1 -1
- package/dist/cjs/code/Pre/index.native.js.map +1 -1
- package/dist/cjs/code/index.native.js +5 -5
- package/dist/cjs/code/index.native.js.map +1 -1
- package/dist/cjs/componentColors.native.js.map +1 -1
- package/dist/cjs/feedback/ConfirmDialog.native.js.map +1 -1
- package/dist/cjs/feedback/NotifyHost.native.js +2 -2
- package/dist/cjs/feedback/NotifyHost.native.js.map +1 -1
- package/dist/cjs/feedback/copy.native.js.map +1 -1
- package/dist/cjs/feedback/index.native.js.map +1 -1
- package/dist/cjs/feedback/notify.native.js.map +1 -1
- package/dist/cjs/feedback/route.native.js.map +1 -1
- package/dist/cjs/feedback/store.native.js.map +1 -1
- package/dist/cjs/hooks/index.native.js +1 -1
- package/dist/cjs/hooks/index.native.js.map +1 -1
- package/dist/cjs/hooks/useClipboard.native.js.map +1 -1
- package/dist/cjs/hooks/useDocumentTitle.native.js.map +1 -1
- package/dist/cjs/icons/CheckRegular.native.js.map +1 -1
- package/dist/cjs/icons/MinusRegular.native.js.map +1 -1
- package/dist/cjs/icons/index.native.js.map +1 -1
- package/dist/cjs/icons/lucide.native.js.map +1 -1
- package/dist/cjs/icons/themed.native.js.map +1 -1
- package/dist/cjs/images/Image/ImageFrame.native.js +1 -1
- package/dist/cjs/images/Image/ImageFrame.native.js.map +1 -1
- package/dist/cjs/images/Image/index.native.js +1 -1
- package/dist/cjs/images/Image/shared.native.js +1 -1
- package/dist/cjs/images/Image/shared.native.js.map +1 -1
- package/dist/cjs/images/Image/types.native.js.map +1 -1
- package/dist/cjs/images/index.native.js.map +1 -1
- package/dist/cjs/index.native.js +29 -29
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/knobImmuneExports.cjs +8 -0
- package/dist/cjs/knobImmuneExports.native.js +8 -0
- package/dist/cjs/knobImmuneExports.native.js.map +1 -1
- package/dist/cjs/layouts/AsyncBoundary.native.js +2 -2
- package/dist/cjs/layouts/AsyncBoundary.native.js.map +1 -1
- package/dist/cjs/layouts/Debug/index.native.js.map +1 -1
- package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
- package/dist/cjs/layouts/KeyboardAvoidingWrapper/behavior.native.js.map +1 -1
- package/dist/cjs/layouts/PageTemplates.native.js.map +1 -1
- package/dist/cjs/layouts/PaneScaffold.native.js.map +1 -1
- package/dist/cjs/layouts/SafeAreaWrapper/insets.native.js.map +1 -1
- package/dist/cjs/layouts/ViewSwitcher.native.js.map +1 -1
- package/dist/cjs/layouts/attachments.native.js +1 -1
- package/dist/cjs/layouts/attachments.native.js.map +1 -1
- package/dist/cjs/layouts/breadcrumbs.cjs +3 -1
- package/dist/cjs/layouts/breadcrumbs.native.js +3 -1
- package/dist/cjs/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/cjs/layouts/index.native.js +3 -3
- package/dist/cjs/layouts/index.native.js.map +1 -1
- package/dist/cjs/layouts/page.native.js.map +1 -1
- package/dist/cjs/layouts/pageHeadingScope.native.js.map +1 -1
- package/dist/cjs/layouts/sidebar.native.js.map +1 -1
- package/dist/cjs/layouts/tags.native.js +1 -1
- package/dist/cjs/layouts/tags.native.js.map +1 -1
- package/dist/cjs/layouts/timeline.native.js +2 -2
- package/dist/cjs/layouts/timeline.native.js.map +1 -1
- package/dist/cjs/layouts/toolbar.native.js.map +1 -1
- package/dist/cjs/shared/actionScan.native.js.map +1 -1
- package/dist/cjs/shared/i18n.native.js.map +1 -1
- package/dist/cjs/shared/t.native.js.map +1 -1
- package/dist/cjs/shared/textRidesText.native.js.map +1 -1
- package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/cjs/shared/useReturnFocusOnClose.native.js.map +1 -1
- package/dist/cjs/surfaces.native.js +1 -1
- package/dist/cjs/surfaces.native.js.map +1 -1
- package/dist/cjs/tamagui.cjs +5 -0
- package/dist/cjs/tamagui.native.js +5 -0
- package/dist/cjs/tamagui.native.js.map +1 -1
- package/dist/cjs/testSetup.native.js.map +1 -1
- package/dist/cjs/utils/setTinted.native.js.map +1 -1
- package/dist/cjs/utils/unwrapText.native.js.map +1 -1
- package/dist/cjs/views/Calendar.native.js.map +1 -1
- package/dist/cjs/views/Dashboard.cjs +3 -3
- package/dist/cjs/views/Dashboard.native.js +4 -4
- package/dist/cjs/views/Dashboard.native.js.map +1 -1
- package/dist/cjs/views/Gantt.native.js +1 -1
- package/dist/cjs/views/Gantt.native.js.map +1 -1
- package/dist/cjs/views/ImageGrid.native.js +1 -1
- package/dist/cjs/views/ImageGrid.native.js.map +1 -1
- package/dist/cjs/views/List.cjs +4 -5
- package/dist/cjs/views/List.native.js +4 -5
- package/dist/cjs/views/List.native.js.map +1 -1
- package/dist/cjs/views/ReportBuilder.native.js +1 -1
- package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
- package/dist/cjs/views/TreeView.cjs +4 -1
- package/dist/cjs/views/TreeView.native.js +3 -0
- package/dist/cjs/views/TreeView.native.js.map +1 -1
- package/dist/cjs/views/calendarMath.native.js.map +1 -1
- package/dist/cjs/views/ganttMath.native.js.map +1 -1
- package/dist/cjs/views/index.native.js +1 -1
- package/dist/cjs/views/index.native.js.map +1 -1
- package/dist/cjs/views/kanbanDnd.native.js.map +1 -1
- package/dist/cjs/views/treeViewDnd.native.js.map +1 -1
- package/dist/cjs/views/treeViewLayout.native.js.map +1 -1
- package/dist/cjs/views/treeViewMotion.native.js.map +1 -1
- package/dist/esm/Alert/index.mjs +14 -31
- package/dist/esm/Alert/index.mjs.map +1 -1
- package/dist/esm/Alert/index.native.js +36 -57
- package/dist/esm/Alert/index.native.js.map +1 -1
- package/dist/esm/Badge/index.mjs +4 -3
- package/dist/esm/Badge/index.mjs.map +1 -1
- package/dist/esm/Badge/index.native.js +7 -6
- package/dist/esm/Badge/index.native.js.map +1 -1
- package/dist/esm/Card.mjs +3 -11
- package/dist/esm/Card.mjs.map +1 -1
- package/dist/esm/Card.native.js +7 -12
- package/dist/esm/Card.native.js.map +1 -1
- package/dist/esm/CardFooter.mjs +3 -11
- package/dist/esm/CardFooter.mjs.map +1 -1
- package/dist/esm/CardFooter.native.js +6 -11
- package/dist/esm/CardFooter.native.js.map +1 -1
- package/dist/esm/CardHeader.mjs +3 -11
- package/dist/esm/CardHeader.mjs.map +1 -1
- package/dist/esm/CardHeader.native.js +6 -11
- package/dist/esm/CardHeader.native.js.map +1 -1
- package/dist/esm/ProgressSteps/index.mjs +14 -7
- package/dist/esm/ProgressSteps/index.mjs.map +1 -1
- package/dist/esm/ProgressSteps/index.native.js +15 -7
- package/dist/esm/ProgressSteps/index.native.js.map +1 -1
- package/dist/esm/SheetModal/detents.mjs +19 -0
- package/dist/esm/SheetModal/detents.mjs.map +1 -0
- package/dist/esm/SheetModal/detents.native.js +24 -0
- package/dist/esm/SheetModal/detents.native.js.map +1 -0
- package/dist/esm/SheetModal/index.mjs.map +1 -1
- package/dist/esm/SheetModal/index.native.js +7 -10
- package/dist/esm/SheetModal/index.native.js.map +1 -1
- package/dist/esm/SortableList/index.mjs +1 -1
- package/dist/esm/SortableList/index.mjs.map +1 -1
- package/dist/esm/SortableList/index.native.js +1 -1
- package/dist/esm/SortableList/index.native.js.map +1 -1
- package/dist/esm/actions/ActionBar.mjs +6 -4
- package/dist/esm/actions/ActionBar.mjs.map +1 -1
- package/dist/esm/actions/ActionBar.native.js +13 -4
- package/dist/esm/actions/ActionBar.native.js.map +1 -1
- package/dist/esm/code/Code/index.mjs +2 -15
- package/dist/esm/code/Code/index.mjs.map +1 -1
- package/dist/esm/code/Code/index.native.js +6 -16
- package/dist/esm/code/Code/index.native.js.map +1 -1
- package/dist/esm/code/HighlightedCode/index.mjs +0 -5
- package/dist/esm/code/HighlightedCode/index.mjs.map +1 -1
- package/dist/esm/code/HighlightedCode/index.native.js +0 -5
- package/dist/esm/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/esm/knobImmuneExports.mjs +8 -0
- package/dist/esm/knobImmuneExports.mjs.map +1 -1
- package/dist/esm/knobImmuneExports.native.js +8 -0
- package/dist/esm/knobImmuneExports.native.js.map +1 -1
- package/dist/esm/layouts/breadcrumbs.mjs +3 -1
- package/dist/esm/layouts/breadcrumbs.mjs.map +1 -1
- package/dist/esm/layouts/breadcrumbs.native.js +3 -1
- package/dist/esm/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/esm/tamagui.mjs +3 -2
- package/dist/esm/tamagui.mjs.map +1 -1
- package/dist/esm/tamagui.native.js +3 -2
- package/dist/esm/tamagui.native.js.map +1 -1
- package/dist/esm/views/Dashboard.mjs +3 -3
- package/dist/esm/views/Dashboard.mjs.map +1 -1
- package/dist/esm/views/Dashboard.native.js +3 -3
- package/dist/esm/views/Dashboard.native.js.map +1 -1
- package/dist/esm/views/List.mjs +4 -5
- package/dist/esm/views/List.mjs.map +1 -1
- package/dist/esm/views/List.native.js +4 -5
- package/dist/esm/views/List.native.js.map +1 -1
- package/dist/esm/views/TreeView.mjs +4 -1
- package/dist/esm/views/TreeView.mjs.map +1 -1
- package/dist/esm/views/TreeView.native.js +3 -0
- package/dist/esm/views/TreeView.native.js.map +1 -1
- package/dist/jsx/Alert/index.mjs +14 -31
- package/dist/jsx/Alert/index.mjs.map +1 -1
- package/dist/jsx/Alert/index.native.js +17 -37
- package/dist/jsx/Alert/index.native.js.map +1 -1
- package/dist/jsx/Badge/index.mjs +4 -3
- package/dist/jsx/Badge/index.mjs.map +1 -1
- package/dist/jsx/Badge/index.native.js +7 -6
- package/dist/jsx/Badge/index.native.js.map +1 -1
- package/dist/jsx/Card.mjs +3 -11
- package/dist/jsx/Card.mjs.map +1 -1
- package/dist/jsx/Card.native.js +2 -7
- package/dist/jsx/Card.native.js.map +1 -1
- package/dist/jsx/CardFooter.mjs +3 -11
- package/dist/jsx/CardFooter.mjs.map +1 -1
- package/dist/jsx/CardFooter.native.js +2 -7
- package/dist/jsx/CardFooter.native.js.map +1 -1
- package/dist/jsx/CardHeader.mjs +3 -11
- package/dist/jsx/CardHeader.mjs.map +1 -1
- package/dist/jsx/CardHeader.native.js +2 -7
- package/dist/jsx/CardHeader.native.js.map +1 -1
- package/dist/jsx/ProgressSteps/index.mjs +14 -7
- package/dist/jsx/ProgressSteps/index.mjs.map +1 -1
- package/dist/jsx/ProgressSteps/index.native.js +14 -6
- package/dist/jsx/ProgressSteps/index.native.js.map +1 -1
- package/dist/jsx/SheetModal/detents.mjs +19 -0
- package/dist/jsx/SheetModal/detents.mjs.map +1 -0
- package/dist/jsx/SheetModal/detents.native.js +54 -0
- package/dist/jsx/SheetModal/detents.native.js.map +1 -0
- package/dist/jsx/SheetModal/index.mjs.map +1 -1
- package/dist/jsx/SheetModal/index.native.js +8 -11
- package/dist/jsx/SheetModal/index.native.js.map +1 -1
- package/dist/jsx/SortableList/index.mjs +1 -1
- package/dist/jsx/SortableList/index.mjs.map +1 -1
- package/dist/jsx/SortableList/index.native.js +1 -1
- package/dist/jsx/SortableList/index.native.js.map +1 -1
- package/dist/jsx/actions/ActionBar.mjs +6 -4
- package/dist/jsx/actions/ActionBar.mjs.map +1 -1
- package/dist/jsx/actions/ActionBar.native.js +11 -2
- package/dist/jsx/actions/ActionBar.native.js.map +1 -1
- package/dist/jsx/code/Code/index.mjs +2 -15
- package/dist/jsx/code/Code/index.mjs.map +1 -1
- package/dist/jsx/code/Code/index.native.js +3 -13
- package/dist/jsx/code/Code/index.native.js.map +1 -1
- package/dist/jsx/code/CodeBlock/index.native.js +1 -1
- package/dist/jsx/code/HighlightedCode/index.mjs +0 -5
- package/dist/jsx/code/HighlightedCode/index.mjs.map +1 -1
- package/dist/jsx/code/HighlightedCode/index.native.js +0 -5
- package/dist/jsx/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/jsx/code/index.native.js +1 -1
- package/dist/jsx/feedback/NotifyHost.native.js +1 -1
- package/dist/jsx/index.native.js +1 -1
- package/dist/jsx/knobImmuneExports.mjs +8 -0
- package/dist/jsx/knobImmuneExports.mjs.map +1 -1
- package/dist/jsx/knobImmuneExports.native.js +8 -0
- package/dist/jsx/knobImmuneExports.native.js.map +1 -1
- package/dist/jsx/layouts/AsyncBoundary.native.js +1 -1
- package/dist/jsx/layouts/AsyncBoundary.native.js.map +1 -1
- package/dist/jsx/layouts/breadcrumbs.mjs +3 -1
- package/dist/jsx/layouts/breadcrumbs.mjs.map +1 -1
- package/dist/jsx/layouts/breadcrumbs.native.js +3 -1
- package/dist/jsx/layouts/breadcrumbs.native.js.map +1 -1
- package/dist/jsx/tamagui.mjs +3 -2
- package/dist/jsx/tamagui.mjs.map +1 -1
- package/dist/jsx/tamagui.native.js +5 -0
- package/dist/jsx/tamagui.native.js.map +1 -1
- package/dist/jsx/views/Dashboard.mjs +3 -3
- package/dist/jsx/views/Dashboard.mjs.map +1 -1
- package/dist/jsx/views/Dashboard.native.js +3 -3
- package/dist/jsx/views/Dashboard.native.js.map +1 -1
- package/dist/jsx/views/List.mjs +4 -5
- package/dist/jsx/views/List.mjs.map +1 -1
- package/dist/jsx/views/List.native.js +4 -5
- package/dist/jsx/views/List.native.js.map +1 -1
- package/dist/jsx/views/TreeView.mjs +4 -1
- package/dist/jsx/views/TreeView.mjs.map +1 -1
- package/dist/jsx/views/TreeView.native.js +3 -0
- package/dist/jsx/views/TreeView.native.js.map +1 -1
- package/package.json +9 -9
- package/src/Alert/index.tsx +9 -4
- package/src/AnimateHeight/AnimateHeight.stories.spec.tsx +37 -0
- package/src/AnimateHeight/AnimateHeight.stories.tsx +95 -0
- package/src/Avatar/Avatar.spec.tsx +4 -1
- package/src/Badge/Badge.spec.tsx +10 -11
- package/src/Badge/index.tsx +7 -6
- package/src/Button.spec.tsx +26 -15
- package/src/Card.tsx +8 -3
- package/src/CardFooter.spec.tsx +1 -1
- package/src/CardFooter.tsx +6 -3
- package/src/CardHeader.spec.tsx +1 -1
- package/src/CardHeader.tsx +6 -3
- package/src/Chip/Chip.spec.tsx +1 -1
- package/src/Pagination.spec.tsx +1 -1
- package/src/ProgressSteps/ProgressSteps.spec.tsx +29 -2
- package/src/ProgressSteps/index.tsx +21 -7
- package/src/SheetModal/SheetModal.spec.tsx +88 -0
- package/src/SheetModal/SheetModal.stories.spec.tsx +54 -0
- package/src/SheetModal/SheetModal.stories.tsx +109 -0
- package/src/SheetModal/detents.ts +55 -0
- package/src/SheetModal/index.native.tsx +13 -12
- package/src/SheetModal/index.tsx +5 -2
- package/src/Skeleton/Skeleton.spec.tsx +1 -1
- package/src/SortableList/SortableList.spec.tsx +41 -0
- package/src/SortableList/SortableList.stories.tsx +35 -2
- package/src/SortableList/index.tsx +1 -1
- package/src/TreeSelect/TreeSelect.stories.tsx +76 -1
- package/src/Wheel/Wheel.spec.tsx +1 -1
- package/src/actions/ActionBar.stories.spec.tsx +45 -0
- package/src/actions/ActionBar.stories.tsx +161 -0
- package/src/actions/ActionBar.tsx +8 -1
- package/src/charts/Axis.stories.spec.tsx +86 -0
- package/src/charts/Axis.stories.tsx +186 -0
- package/src/charts/ChartSurface.stories.spec.tsx +43 -0
- package/src/charts/ChartSurface.stories.tsx +148 -0
- package/src/code/Code/code.spec.tsx +27 -1
- package/src/code/Code/index.tsx +9 -2
- package/src/code/HighlightedCode/index.tsx +0 -1
- package/src/code/highlightedCode.spec.tsx +10 -1
- package/src/knobImmuneExports.ts +11 -0
- package/src/layouts/AsyncBoundary.spec.tsx +1 -1
- package/src/layouts/breadcrumbs.spec.tsx +17 -0
- package/src/layouts/breadcrumbs.tsx +19 -2
- package/src/layouts/tags.r7.spec.tsx +3 -1
- package/src/tamagui.ts +8 -0
- package/src/views/Dashboard.tsx +3 -3
- package/src/views/List.spec.tsx +42 -1
- package/src/views/List.tsx +6 -5
- package/src/views/TreeView.spec.tsx +26 -0
- package/src/views/TreeView.tsx +3 -0
- package/types/Alert/index.d.ts.map +1 -1
- package/types/Badge/index.d.ts.map +1 -1
- package/types/Card.d.ts.map +1 -1
- package/types/CardFooter.d.ts.map +1 -1
- package/types/CardHeader.d.ts.map +1 -1
- package/types/ProgressSteps/index.d.ts.map +1 -1
- package/types/SheetModal/detents.d.ts +38 -0
- package/types/SheetModal/detents.d.ts.map +1 -0
- package/types/SheetModal/index.d.ts +1 -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/actions/ActionBar.d.ts.map +1 -1
- package/types/code/Code/index.d.ts.map +1 -1
- package/types/code/HighlightedCode/index.d.ts.map +1 -1
- package/types/knobImmuneExports.d.ts.map +1 -1
- package/types/layouts/breadcrumbs.d.ts +7 -1
- package/types/layouts/breadcrumbs.d.ts.map +1 -1
- package/types/tamagui.d.ts +3 -1
- package/types/tamagui.d.ts.map +1 -1
- package/types/views/List.d.ts.map +1 -1
- package/types/views/TreeView.d.ts.map +1 -1
package/src/CardFooter.tsx
CHANGED
|
@@ -14,16 +14,19 @@ import { wrapBareTextChildren } from "./shared/textRidesText";
|
|
|
14
14
|
export type CardFooterProps = ViewProps & { children?: ReactNode };
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Tamagui styled hosts drop JSX `data-*` (Toast gallery hole)
|
|
18
|
-
* `dataSet
|
|
17
|
+
* Tamagui styled hosts drop JSX `data-*` on native (Toast gallery hole), so
|
|
18
|
+
* native needs the RN `dataSet` map. On web, spreading `dataSet` onto a DOM
|
|
19
|
+
* host is a React invalid-prop warning (`dataSet` → `dataset`). jsdom and
|
|
20
|
+
* Storybook keep kebab `data-*`, so web writes those only.
|
|
19
21
|
*/
|
|
20
22
|
function hostData(attrs: Record<string, string>): Record<string, unknown> {
|
|
23
|
+
if (process.env.TAMAGUI_TARGET !== "native") return attrs;
|
|
21
24
|
const dataSet: Record<string, string> = {};
|
|
22
25
|
for (const [key, value] of Object.entries(attrs)) {
|
|
23
26
|
const camel = key.replace(/^data-/, "").replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
|
|
24
27
|
dataSet[camel] = value;
|
|
25
28
|
}
|
|
26
|
-
return {
|
|
29
|
+
return { dataSet };
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
export function CardFooter({ children, ...props }: CardFooterProps) {
|
package/src/CardHeader.spec.tsx
CHANGED
|
@@ -28,7 +28,7 @@ describe("CardHeader named exports", () => {
|
|
|
28
28
|
expect(Card.Header).toBe(CardHeader);
|
|
29
29
|
const mod = await import("./CardHeader");
|
|
30
30
|
expect(mod.CardHeader).toBe(CardHeader);
|
|
31
|
-
expect(mod
|
|
31
|
+
expect("default" in mod).toBe(false);
|
|
32
32
|
});
|
|
33
33
|
});
|
|
34
34
|
|
package/src/CardHeader.tsx
CHANGED
|
@@ -14,16 +14,19 @@ import { wrapBareTextChildren } from "./shared/textRidesText";
|
|
|
14
14
|
export type CardHeaderProps = ViewProps & { children?: ReactNode };
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
* Tamagui styled hosts drop JSX `data-*` (Toast gallery hole)
|
|
18
|
-
* `dataSet
|
|
17
|
+
* Tamagui styled hosts drop JSX `data-*` on native (Toast gallery hole), so
|
|
18
|
+
* native needs the RN `dataSet` map. On web, spreading `dataSet` onto a DOM
|
|
19
|
+
* host is a React invalid-prop warning (`dataSet` → `dataset`). jsdom and
|
|
20
|
+
* Storybook keep kebab `data-*`, so web writes those only.
|
|
19
21
|
*/
|
|
20
22
|
function hostData(attrs: Record<string, string>): Record<string, unknown> {
|
|
23
|
+
if (process.env.TAMAGUI_TARGET !== "native") return attrs;
|
|
21
24
|
const dataSet: Record<string, string> = {};
|
|
22
25
|
for (const [key, value] of Object.entries(attrs)) {
|
|
23
26
|
const camel = key.replace(/^data-/, "").replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
|
|
24
27
|
dataSet[camel] = value;
|
|
25
28
|
}
|
|
26
|
-
return {
|
|
29
|
+
return { dataSet };
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
export function CardHeader({ children, ...props }: CardHeaderProps) {
|
package/src/Chip/Chip.spec.tsx
CHANGED
|
@@ -150,7 +150,7 @@ describe("Chip", () => {
|
|
|
150
150
|
expect(mod.chipTone).toBe(chipTone);
|
|
151
151
|
expect(typeof mod.chipIconSize).toBe("function");
|
|
152
152
|
expect(chipIconSize("$3")).toBeGreaterThan(0);
|
|
153
|
-
expect(mod
|
|
153
|
+
expect("default" in mod).toBe(false);
|
|
154
154
|
});
|
|
155
155
|
|
|
156
156
|
it("label TEXT NODE weight is 400, never 500/600", () => {
|
package/src/Pagination.spec.tsx
CHANGED
|
@@ -163,7 +163,7 @@ describe("Pagination design-law (MPO-60)", () => {
|
|
|
163
163
|
const mod = await import("./Pagination");
|
|
164
164
|
expect(mod.Pagination).toBe(Pagination);
|
|
165
165
|
expect(mod.getPaginationItems).toBeTypeOf("function");
|
|
166
|
-
expect(mod
|
|
166
|
+
expect("default" in mod).toBe(false);
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
it("LC-68: animation none publishes data-animation=none (no quick fallback)", () => {
|
|
@@ -52,6 +52,18 @@ describe("ProgressSteps", () => {
|
|
|
52
52
|
expect(current.className).toContain("_bg-accentBackg");
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
+
it("walks the current fill off the dark mid-solid so the numeral can clear 4.5", () => {
|
|
56
|
+
const { container } = render(
|
|
57
|
+
<TamaguiProvider config={houseConfig} defaultTheme="dark" disableInjectCSS>
|
|
58
|
+
<ProgressSteps steps={steps} current={1} />
|
|
59
|
+
</TamaguiProvider>,
|
|
60
|
+
);
|
|
61
|
+
const current = container.querySelector('[aria-current="step"]') as HTMLElement;
|
|
62
|
+
expect(current).toBeTruthy();
|
|
63
|
+
expect(current.className).toMatch(/_bg-accent/);
|
|
64
|
+
expect(current.className).not.toContain("_bg-accentBackg");
|
|
65
|
+
});
|
|
66
|
+
|
|
55
67
|
it("calls onStepChange when jumping back to a completed step", () => {
|
|
56
68
|
const onStepChange = vi.fn();
|
|
57
69
|
const { container } = renderWithProviders(
|
|
@@ -110,10 +122,25 @@ describe("ProgressSteps", () => {
|
|
|
110
122
|
expect(target.getAttribute("data-press-min")).toBe("44");
|
|
111
123
|
});
|
|
112
124
|
|
|
113
|
-
it("
|
|
125
|
+
it("declares the marker R-PILL and tracks the borderWidth knob for the ring", () => {
|
|
126
|
+
const { container } = renderWithProviders(<ProgressSteps steps={steps} current={1} />);
|
|
127
|
+
const marker = container.querySelector("[data-nested-px]") as HTMLElement;
|
|
128
|
+
expect(marker.getAttribute("data-radius-class")).toBe("R-PILL");
|
|
129
|
+
expect(marker.getAttribute("data-radius-part")).toBe("ProgressSteps marker");
|
|
130
|
+
// Default knobs: borderWidth medium = 1. The previous 2px pin is gone.
|
|
131
|
+
const upcoming = container.querySelector('[data-step-state="upcoming"]') as HTMLElement;
|
|
132
|
+
expect(upcoming.getAttribute("data-marker-ring")).toBe("1");
|
|
133
|
+
const current = container.querySelector('[data-step-state="current"]') as HTMLElement;
|
|
134
|
+
expect(current.getAttribute("data-marker-ring")).toBe("1");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("keeps nested marker size on the size channel under compact (LC-76)", () => {
|
|
114
138
|
const { container } = renderWithProviders(<ProgressSteps steps={steps} current={0} compact />);
|
|
139
|
+
const root = container.querySelector('[role="list"]') as HTMLElement;
|
|
140
|
+
expect(root.getAttribute("data-density")).toBe("compact");
|
|
115
141
|
const marker = container.querySelector("[data-nested-px]") as HTMLElement;
|
|
116
|
-
|
|
142
|
+
// Compact steps space only — nestedControl follows size (medium = 32).
|
|
143
|
+
expect(marker.getAttribute("data-nested-px")).toBe("32");
|
|
117
144
|
});
|
|
118
145
|
|
|
119
146
|
it("hides visible step labels when labels is hidden", () => {
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
MIN_PRESS_TARGET,
|
|
4
4
|
ensureKeyboardModalityTracking,
|
|
5
5
|
pressTargetHitSlop,
|
|
6
|
+
radiusClassProps,
|
|
7
|
+
useAaSolidFill,
|
|
6
8
|
useReadableTextOn,
|
|
7
9
|
useResolvedKnobs,
|
|
8
10
|
wasKeyboardFocus,
|
|
@@ -76,8 +78,11 @@ const Marker = styled(View, {
|
|
|
76
78
|
name: "ProgressStepMarker",
|
|
77
79
|
alignItems: "center",
|
|
78
80
|
justifyContent: "center",
|
|
79
|
-
borderWidth: 2,
|
|
80
81
|
flexShrink: 0,
|
|
82
|
+
// R-PILL (D-09 / LC-60): the numbered disc is a circle at every radius
|
|
83
|
+
// stop — the knob moves size, never shape. Not K1 (Progress/Meter rails).
|
|
84
|
+
...radiusClassProps("R-PILL", "ProgressSteps marker"),
|
|
85
|
+
borderRadius: 1000,
|
|
81
86
|
});
|
|
82
87
|
|
|
83
88
|
const StepButton = styled(View, {
|
|
@@ -148,14 +153,18 @@ export function ProgressSteps({
|
|
|
148
153
|
);
|
|
149
154
|
if (isWeb) ensureKeyboardModalityTracking();
|
|
150
155
|
const [kbFocusIndex, setKbFocusIndex] = useState<number | null>(null);
|
|
151
|
-
// LC-05: current marker rides
|
|
152
|
-
// paper/ink from luminance rather than an assumed white glyph.
|
|
153
|
-
|
|
156
|
+
// LC-05: current marker rides an accent solid; completed/error fills pick
|
|
157
|
+
// paper/ink from luminance rather than an assumed white glyph. The stock
|
|
158
|
+
// dark `$accentBackground` tops out at 4.02:1 against either scheme
|
|
159
|
+
// anchor, under the in-repo 4.5 text floor, so the current fill walks to
|
|
160
|
+
// the nearest accent solid that can carry the numeral.
|
|
161
|
+
const currentFill = useAaSolidFill(componentColors.indicator.selected);
|
|
162
|
+
const onSelected = useReadableTextOn(currentFill);
|
|
154
163
|
const onCompleted = useReadableTextOn(componentColors.indicator.completed);
|
|
155
164
|
const onError = useReadableTextOn("$red9");
|
|
156
165
|
const { px: markerPx, hitSlop, box: nestedBox } = splitNestedControl(knobProps.nestedControl);
|
|
157
166
|
const markerIconSize = Math.max(12, Math.round(markerPx * 0.45));
|
|
158
|
-
const
|
|
167
|
+
const ringWidth = knobProps.borderRadius.borderWidth ?? 0;
|
|
159
168
|
const connectorThickness = 2;
|
|
160
169
|
const pressOutset = Math.max(0, Math.ceil((MIN_PRESS_TARGET - markerPx) / 2));
|
|
161
170
|
const interactive = !!onStepChange && allowJump;
|
|
@@ -192,7 +201,7 @@ export function ProgressSteps({
|
|
|
192
201
|
: kind === "completed"
|
|
193
202
|
? componentColors.indicator.completed
|
|
194
203
|
: kind === "current"
|
|
195
|
-
?
|
|
204
|
+
? currentFill
|
|
196
205
|
: "transparent";
|
|
197
206
|
const markerBorder = kind === "upcoming" ? componentColors.indicator.track : markerBg;
|
|
198
207
|
const markerFg =
|
|
@@ -207,15 +216,20 @@ export function ProgressSteps({
|
|
|
207
216
|
step.description ?? (step.optional && kind !== "error" ? t("Optional") : null);
|
|
208
217
|
const connectorFill =
|
|
209
218
|
index < current ? componentColors.indicator.completed : componentColors.indicator.track;
|
|
219
|
+
// Upcoming is outlined-by-state: chromeless `borderWidth:none` would
|
|
220
|
+
// erase the empty disc, so it keeps the OUTLINED-HAIRLINE floor.
|
|
221
|
+
const markerRing = kind === "upcoming" ? Math.max(ringWidth, 0.5) : ringWidth;
|
|
210
222
|
|
|
211
223
|
const marker = (
|
|
212
224
|
<Marker
|
|
213
225
|
{...nestedBox}
|
|
214
|
-
borderRadius={
|
|
226
|
+
borderRadius={1000}
|
|
227
|
+
borderWidth={markerRing}
|
|
215
228
|
backgroundColor={markerBg}
|
|
216
229
|
borderColor={markerBorder}
|
|
217
230
|
data-nested-px={markerPx}
|
|
218
231
|
data-step-state={kind}
|
|
232
|
+
data-marker-ring={markerRing}
|
|
219
233
|
transition={knobProps.transition}
|
|
220
234
|
{...(state === "current"
|
|
221
235
|
? ({ "aria-current": "step" } as Record<string, unknown>)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { mediumDetent, minSheetHeight, resolveSheetDetents } from "./detents";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* MPO-68 AC-4 — "SheetModal's snapPoint prop either drives a detent or is
|
|
6
|
+
* removed". It drives one. These lock that in, because it has already been
|
|
7
|
+
* lost once: 184746910 (MPO-71) rewrote the detents block from a pre-MPO-68
|
|
8
|
+
* copy and dropped the snapPoint push, leaving the prop declared, documented
|
|
9
|
+
* and passed by four callers while doing nothing on device.
|
|
10
|
+
*
|
|
11
|
+
* Geometry under test is a pure height list, largest first. The component's
|
|
12
|
+
* PanResponder turns each height h into a resting translate of `travel - h`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const travel = 600;
|
|
16
|
+
|
|
17
|
+
describe("resolveSheetDetents", () => {
|
|
18
|
+
it("a plain sheet has exactly one rest: fully expanded", () => {
|
|
19
|
+
expect(resolveSheetDetents({ travel })).toEqual([600]);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("REGRESSION: snapPoint creates a detent instead of being ignored", () => {
|
|
23
|
+
// The bug this spec exists for: main returned [600] here.
|
|
24
|
+
expect(resolveSheetDetents({ travel, snapPoint: 85 })).toEqual([600, 510]);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("reads snapPoint as a percent of the full height, matching the web Sheet", () => {
|
|
28
|
+
expect(resolveSheetDetents({ travel, snapPoint: 50 })).toEqual([600, 300]);
|
|
29
|
+
expect(resolveSheetDetents({ travel, snapPoint: 60 })).toEqual([600, 360]);
|
|
30
|
+
expect(resolveSheetDetents({ travel, snapPoint: 92 })).toEqual([600, 552]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("honours the four heights real callers pass", () => {
|
|
34
|
+
// CommandPalette 92, list-tools-sheet 85, ListThemePlayground 85,
|
|
35
|
+
// Toast.stories 70 — every one of these was a no-op on device.
|
|
36
|
+
for (const snapPoint of [92, 85, 70]) {
|
|
37
|
+
const detents = resolveSheetDetents({ travel, snapPoint });
|
|
38
|
+
expect(detents).toContain(Math.round(travel * (snapPoint / 100)));
|
|
39
|
+
expect(detents.length).toBeGreaterThan(1);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("a scrollable sheet keeps its half-open detent", () => {
|
|
44
|
+
expect(resolveSheetDetents({ travel, scrollable: true })).toEqual([
|
|
45
|
+
600,
|
|
46
|
+
Math.round(travel * mediumDetent),
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("scrollable and snapPoint stack, largest first, no duplicates", () => {
|
|
51
|
+
// 600 expanded, 330 medium, 510 from snapPoint.
|
|
52
|
+
expect(resolveSheetDetents({ travel, scrollable: true, snapPoint: 85 })).toEqual([
|
|
53
|
+
600, 510, 330,
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("dedupes a snapPoint that lands on a detent already present", () => {
|
|
58
|
+
expect(resolveSheetDetents({ travel, snapPoint: 100 })).toEqual([600]);
|
|
59
|
+
expect(resolveSheetDetents({ travel, scrollable: true, snapPoint: 55 })).toEqual([600, 330]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("clamps a snapPoint above 100 to fully expanded", () => {
|
|
63
|
+
expect(resolveSheetDetents({ travel, snapPoint: 140 })).toEqual([600]);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("drops a detent shorter than the floor rather than resting near-dismissed", () => {
|
|
67
|
+
// 600 * 0.10 = 60, well under minSheetHeight.
|
|
68
|
+
expect(resolveSheetDetents({ travel, snapPoint: 10 })).toEqual([600]);
|
|
69
|
+
expect(minSheetHeight).toBe(180);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("a sheet shorter than the floor still keeps its own full height", () => {
|
|
73
|
+
expect(resolveSheetDetents({ travel: 120, scrollable: true, snapPoint: 85 })).toEqual([120]);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("ignores a snapPoint that is not a usable number", () => {
|
|
77
|
+
for (const snapPoint of [0, -20, Number.NaN, Number.POSITIVE_INFINITY]) {
|
|
78
|
+
expect(resolveSheetDetents({ travel, snapPoint })).toEqual([600]);
|
|
79
|
+
}
|
|
80
|
+
expect(resolveSheetDetents({ travel, snapPoint: undefined })).toEqual([600]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("always returns descending heights, so the pan release can scan in order", () => {
|
|
84
|
+
const detents = resolveSheetDetents({ travel, scrollable: true, snapPoint: 40 });
|
|
85
|
+
expect(detents).toEqual([...detents].sort((a, b) => b - a));
|
|
86
|
+
expect(new Set(detents).size).toBe(detents.length);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SheetModal was the harness inside SheetFrame.stories and had no title of its
|
|
3
|
+
* own, so the gallery listed the frame and not the sheet (MPO-193). These
|
|
4
|
+
* mount every exported story so an unrenderable one fails here, not in the
|
|
5
|
+
* Kitchen Sink.
|
|
6
|
+
*
|
|
7
|
+
* Presence is asserted by accessible NAME, not by counting dialogs: tamagui's
|
|
8
|
+
* Sheet keeps its portal in the tree either side of `open`, and happy-dom runs
|
|
9
|
+
* no animation, so `role="dialog"` matches more than one node whatever the
|
|
10
|
+
* open state is.
|
|
11
|
+
*/
|
|
12
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
13
|
+
import { cleanup, screen } from "@testing-library/react";
|
|
14
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
15
|
+
import meta, { Default, OpenOnMount, Scrollable, TallDetent } from "./SheetModal.stories";
|
|
16
|
+
|
|
17
|
+
afterEach(cleanup);
|
|
18
|
+
|
|
19
|
+
describe("SheetModal stories", () => {
|
|
20
|
+
it("declares the Components/SheetModal title against the component", () => {
|
|
21
|
+
expect(meta.title).toBe("Components/SheetModal");
|
|
22
|
+
expect(meta.component).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("every exported story mounts its trigger", () => {
|
|
26
|
+
for (const story of [Default, Scrollable, TallDetent, OpenOnMount]) {
|
|
27
|
+
renderWithProviders(<>{story.render?.({} as never, {} as never)}</>);
|
|
28
|
+
expect(screen.getAllByText("Open sheet").length).toBeGreaterThan(0);
|
|
29
|
+
cleanup();
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("the sheet frame is a labelled modal dialog", () => {
|
|
34
|
+
renderWithProviders(<>{OpenOnMount.render?.({} as never, {} as never)}</>);
|
|
35
|
+
// tamagui renders the sheet through a portal AND inline, so the frame
|
|
36
|
+
// appears more than once with the same accessible name; every copy has to
|
|
37
|
+
// carry the modal semantics.
|
|
38
|
+
const frames = screen.getAllByRole("dialog", { name: "Move to project" });
|
|
39
|
+
expect(frames.length).toBeGreaterThan(0);
|
|
40
|
+
for (const frame of frames) expect(frame.getAttribute("aria-modal")).toBe("true");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("the action row inside the sheet carries cancel and primary", () => {
|
|
44
|
+
renderWithProviders(<>{OpenOnMount.render?.({} as never, {} as never)}</>);
|
|
45
|
+
expect(screen.getAllByText("Cancel").length).toBeGreaterThan(0);
|
|
46
|
+
expect(screen.getAllByText("Move").length).toBeGreaterThan(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("the scrollable story fills the body with rows", () => {
|
|
50
|
+
renderWithProviders(<>{Scrollable.render?.({} as never, {} as never)}</>);
|
|
51
|
+
expect(screen.getAllByText("Project 1").length).toBeGreaterThan(0);
|
|
52
|
+
expect(screen.getAllByText("Project 30").length).toBeGreaterThan(0);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Button } from "@multiplatform.one/forms";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Paragraph, SizableText, YStack } from "tamagui";
|
|
5
|
+
import { ActionBar } from "../actions/ActionBar";
|
|
6
|
+
import { SheetModal } from "./index";
|
|
7
|
+
|
|
8
|
+
function Harness({
|
|
9
|
+
scrollable = false,
|
|
10
|
+
snapPoint,
|
|
11
|
+
startOpen = false,
|
|
12
|
+
}: {
|
|
13
|
+
scrollable?: boolean;
|
|
14
|
+
snapPoint?: number;
|
|
15
|
+
startOpen?: boolean;
|
|
16
|
+
}) {
|
|
17
|
+
const [open, setOpen] = useState(startOpen);
|
|
18
|
+
return (
|
|
19
|
+
<YStack minHeight={480} gap="$3">
|
|
20
|
+
<Button onPress={() => setOpen(true)}>Open sheet</Button>
|
|
21
|
+
<Paragraph size="$2">
|
|
22
|
+
Dismiss by tapping the scrim, dragging to the bottom, or pressing Escape.
|
|
23
|
+
</Paragraph>
|
|
24
|
+
<SheetModal
|
|
25
|
+
open={open}
|
|
26
|
+
onOpenChange={setOpen}
|
|
27
|
+
scrollable={scrollable}
|
|
28
|
+
{...(snapPoint === undefined ? {} : { snapPoint })}
|
|
29
|
+
header={<SizableText fontWeight="600">Move to project</SizableText>}
|
|
30
|
+
>
|
|
31
|
+
{scrollable ? (
|
|
32
|
+
<YStack gap="$2">
|
|
33
|
+
{Array.from({ length: 30 }).map((_, index) => (
|
|
34
|
+
<Paragraph key={index}>Project {index + 1}</Paragraph>
|
|
35
|
+
))}
|
|
36
|
+
</YStack>
|
|
37
|
+
) : (
|
|
38
|
+
<YStack gap="$3">
|
|
39
|
+
<Paragraph>
|
|
40
|
+
The sheet is a dialog region, so the action row inside it caps at two actions.
|
|
41
|
+
</Paragraph>
|
|
42
|
+
<ActionBar
|
|
43
|
+
cancel={
|
|
44
|
+
<Button chromeless onPress={() => setOpen(false)}>
|
|
45
|
+
Cancel
|
|
46
|
+
</Button>
|
|
47
|
+
}
|
|
48
|
+
primary={
|
|
49
|
+
<Button accent onPress={() => setOpen(false)}>
|
|
50
|
+
Move
|
|
51
|
+
</Button>
|
|
52
|
+
}
|
|
53
|
+
/>
|
|
54
|
+
</YStack>
|
|
55
|
+
)}
|
|
56
|
+
</SheetModal>
|
|
57
|
+
</YStack>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const meta: Meta<typeof SheetModal> = {
|
|
62
|
+
title: "Components/SheetModal",
|
|
63
|
+
component: SheetModal,
|
|
64
|
+
parameters: {
|
|
65
|
+
status: { type: "beta" },
|
|
66
|
+
layout: "fullscreen",
|
|
67
|
+
docs: {
|
|
68
|
+
description: {
|
|
69
|
+
component:
|
|
70
|
+
"Modal bottom sheet. Anatomy follows the Apple HIG sheet (grabber, percent detent, swipe to dismiss) with Radix Dialog semantics: `role=dialog`, `aria-modal`, focus moved in, trapped, and returned on close, and Escape dismissal wired here because tamagui's Sheet has no key handling of its own. The frame opens a dialog region, so an ActionBar inside it inherits the two-action cap. Web renders tamagui's Sheet; the native twin is an RN Modal, because a raw Sheet cannot re-present from a trigger tap on device.",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
argTypes: {
|
|
75
|
+
snapPoint: { control: { type: "range", min: 30, max: 95, step: 5 } },
|
|
76
|
+
scrollable: { control: "boolean" },
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export default meta;
|
|
80
|
+
|
|
81
|
+
type Story = StoryObj<typeof SheetModal>;
|
|
82
|
+
|
|
83
|
+
export const Default: Story = {
|
|
84
|
+
name: "Main",
|
|
85
|
+
render: () => <Harness />,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const Scrollable: Story = {
|
|
89
|
+
name: "Scrollable body",
|
|
90
|
+
render: () => <Harness scrollable />,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const TallDetent: Story = {
|
|
94
|
+
name: "Tall detent",
|
|
95
|
+
parameters: {
|
|
96
|
+
docs: {
|
|
97
|
+
description: {
|
|
98
|
+
story:
|
|
99
|
+
"`snapPoint` is a percent of travel. 92 is the tallest height real callers pass (the command palette); every one of those was a no-op on device until the detent resolver landed.",
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
render: () => <Harness snapPoint={92} />,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const OpenOnMount: Story = {
|
|
107
|
+
name: "Open",
|
|
108
|
+
render: () => <Harness startOpen />,
|
|
109
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SheetModal detent geometry — the pure half, split out so it can be specced
|
|
3
|
+
* without standing up a React Native renderer.
|
|
4
|
+
*
|
|
5
|
+
* A detent is a VISIBLE HEIGHT in points. The native sheet's `translateY`
|
|
6
|
+
* measures DOWN from fully-expanded, so a detent of `h` rests at `travel - h`,
|
|
7
|
+
* and `travel` itself is the fully-expanded sheet.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** Smallest height a native sheet is ever laid out at. */
|
|
11
|
+
export const minSheetHeight = 180;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Half-open detent for a sheet that owns a scrollport, as a fraction of its
|
|
15
|
+
* full height. Mirrors FloatingPanel so both native sheets drag alike.
|
|
16
|
+
*/
|
|
17
|
+
export const mediumDetent = 0.55;
|
|
18
|
+
|
|
19
|
+
export interface ResolveSheetDetentsOptions {
|
|
20
|
+
/** Full (expanded) height of the sheet, in points. */
|
|
21
|
+
travel: number;
|
|
22
|
+
/** The sheet owns a scrollport, so a half-open rest is meaningful. */
|
|
23
|
+
scrollable?: boolean;
|
|
24
|
+
/** Percent detent from the caller — the same prop the web Sheet takes. */
|
|
25
|
+
snapPoint?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The heights the sheet is allowed to rest at, largest first.
|
|
30
|
+
*
|
|
31
|
+
* MPO-68: `snapPoint` is a percent on the web Sheet (`snapPoints={[snapPoint]}`).
|
|
32
|
+
* Native honours the same prop by turning that percent into a detent, so a
|
|
33
|
+
* caller that writes `snapPoint={85}` gets an 85%-height rest on both twins
|
|
34
|
+
* rather than the prop being silently dropped on device.
|
|
35
|
+
*
|
|
36
|
+
* Anything shorter than `minSheetHeight` is discarded, because a sheet that
|
|
37
|
+
* rests below that is indistinguishable from a dismissed one. A sheet whose
|
|
38
|
+
* full height is already under the floor keeps its own height, otherwise it
|
|
39
|
+
* would have no detents at all.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveSheetDetents({
|
|
42
|
+
travel,
|
|
43
|
+
scrollable,
|
|
44
|
+
snapPoint,
|
|
45
|
+
}: ResolveSheetDetentsOptions): number[] {
|
|
46
|
+
const points = [travel];
|
|
47
|
+
if (scrollable) {
|
|
48
|
+
points.push(Math.round(travel * mediumDetent));
|
|
49
|
+
}
|
|
50
|
+
if (typeof snapPoint === "number" && Number.isFinite(snapPoint) && snapPoint > 0) {
|
|
51
|
+
points.push(Math.round(travel * (Math.min(snapPoint, 100) / 100)));
|
|
52
|
+
}
|
|
53
|
+
const floor = Math.min(minSheetHeight, travel);
|
|
54
|
+
return Array.from(new Set(points.filter((h) => h >= floor))).sort((a, b) => b - a);
|
|
55
|
+
}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
useWindowDimensions,
|
|
25
25
|
} from "react-native";
|
|
26
26
|
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
27
|
+
import { minSheetHeight, resolveSheetDetents } from "./detents";
|
|
27
28
|
import { useTranslation } from "../shared/i18n";
|
|
28
29
|
import { useKeyboardInset } from "../shared/useKeyboardInset";
|
|
29
30
|
import { View, YStack } from "tamagui";
|
|
@@ -36,10 +37,6 @@ const sheetMaxHeightRatio = 0.85;
|
|
|
36
37
|
const bottomInset = Platform.OS === "ios" ? 24 : 16;
|
|
37
38
|
// Backdrop left visible above the sheet, so the scrim stays tappable.
|
|
38
39
|
const backdropStrip = 48;
|
|
39
|
-
const minSheetHeight = 180;
|
|
40
|
-
// Half-open detent for a sheet that owns a scrollport, as a fraction of its
|
|
41
|
-
// full height. Mirrors FloatingPanel so both native sheets drag alike.
|
|
42
|
-
const mediumDetent = 0.55;
|
|
43
40
|
// Released more than this far below the smallest detent, the sheet dismisses.
|
|
44
41
|
const dismissThreshold = 56;
|
|
45
42
|
const IN_DIALOG_REGION = { inDialogRegion: true } as const;
|
|
@@ -49,7 +46,7 @@ export function SheetModal({
|
|
|
49
46
|
onOpenChange,
|
|
50
47
|
children,
|
|
51
48
|
header,
|
|
52
|
-
snapPoint
|
|
49
|
+
snapPoint,
|
|
53
50
|
scrollable,
|
|
54
51
|
}: SheetModalProps) {
|
|
55
52
|
const { t } = useTranslation();
|
|
@@ -95,16 +92,20 @@ export function SheetModal({
|
|
|
95
92
|
*
|
|
96
93
|
* translateY measures DOWN from fully-expanded: 0 is the sheet at full
|
|
97
94
|
* height, `travel` is fully off-screen.
|
|
95
|
+
*
|
|
96
|
+
* The detent heights themselves live in ./detents.ts, pure, so the geometry
|
|
97
|
+
* is specced without a native renderer. 184746910 (MPO-71) rewrote this
|
|
98
|
+
* block from a pre-MPO-68 copy and silently dropped the `snapPoint` push,
|
|
99
|
+
* leaving the prop declared, documented and passed by four callers while
|
|
100
|
+
* doing nothing on device. Keep the math in one place so a rewrite of the
|
|
101
|
+
* animation cannot take the geometry with it again.
|
|
98
102
|
*/
|
|
99
103
|
const [measuredHeight, setMeasuredHeight] = useState(0);
|
|
100
104
|
const travel = measuredHeight || maxHeight;
|
|
101
|
-
const detents = useMemo(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
);
|
|
106
|
-
return Array.from(new Set(points)).sort((a, b) => b - a);
|
|
107
|
-
}, [scrollable, travel]);
|
|
105
|
+
const detents = useMemo(
|
|
106
|
+
() => resolveSheetDetents({ travel, scrollable, snapPoint }),
|
|
107
|
+
[travel, scrollable, snapPoint],
|
|
108
|
+
);
|
|
108
109
|
|
|
109
110
|
/*
|
|
110
111
|
* MPO-71 — park the sheet OFF-SCREEN before the modal ever presents.
|
package/src/SheetModal/index.tsx
CHANGED
|
@@ -21,7 +21,7 @@ export interface SheetModalProps {
|
|
|
21
21
|
children?: ReactNode;
|
|
22
22
|
/** Fixed content above the (scrollable) body, e.g. the sheet title. */
|
|
23
23
|
header?: ReactNode;
|
|
24
|
-
/** Percent snap point
|
|
24
|
+
/** Percent snap point. Web: the Sheet's snap point. Native: a drag detent. */
|
|
25
25
|
snapPoint?: number;
|
|
26
26
|
/** Wrap children in the sheet's scroll container. */
|
|
27
27
|
scrollable?: boolean;
|
|
@@ -59,7 +59,10 @@ function useSheetFrameFocus(open: boolean, frameRef: RefObject<HTMLElement | nul
|
|
|
59
59
|
if (!target || !target.isConnected) return;
|
|
60
60
|
const ae = document.activeElement;
|
|
61
61
|
const dropped =
|
|
62
|
-
!ae ||
|
|
62
|
+
!ae ||
|
|
63
|
+
ae === document.body ||
|
|
64
|
+
ae === document.documentElement ||
|
|
65
|
+
!!frameRef.current?.contains(ae);
|
|
63
66
|
if (dropped) {
|
|
64
67
|
target.focus({
|
|
65
68
|
preventScroll: true,
|
|
@@ -22,7 +22,7 @@ function radiusClasses(el: Element): string[] {
|
|
|
22
22
|
|
|
23
23
|
describe("Skeleton named exports", () => {
|
|
24
24
|
it("serves named exports only (no default) and keeps the namespace statics", () => {
|
|
25
|
-
expect(SkeletonExports
|
|
25
|
+
expect("default" in SkeletonExports).toBe(false);
|
|
26
26
|
expect(SkeletonExports.Skeleton).toBe(Skeleton);
|
|
27
27
|
expect(SkeletonExports.SkeletonText).toBe(SkeletonText);
|
|
28
28
|
expect(SkeletonExports.SkeletonCircle).toBe(SkeletonCircle);
|