@multiplatform.one/components 7.83.2 → 7.84.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.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.native.js.map +1 -1
- package/dist/cjs/Button.native.js.map +1 -1
- package/dist/cjs/Card.native.js.map +1 -1
- package/dist/cjs/CardFooter.native.js.map +1 -1
- package/dist/cjs/CardHeader.native.js.map +1 -1
- package/dist/cjs/Carousel/index.cjs +11 -9
- package/dist/cjs/Carousel/index.native.js +15 -13
- package/dist/cjs/Carousel/index.native.js.map +1 -1
- package/dist/cjs/CheckGlyph/MenuCheckColumn.native.js.map +1 -1
- package/dist/cjs/CheckGlyph/index.native.js.map +1 -1
- package/dist/cjs/Chip/index.native.js.map +1 -1
- package/dist/cjs/Collapsible.native.js.map +1 -1
- package/dist/cjs/ContextMenu/index.native.js.map +1 -1
- package/dist/cjs/CopyField/CopyMenuButton.cjs +1 -3
- package/dist/cjs/CopyField/CopyMenuButton.native.js +2 -4
- package/dist/cjs/CopyField/CopyMenuButton.native.js.map +1 -1
- package/dist/cjs/CopyField/index.native.js.map +1 -1
- package/dist/cjs/Dialog.native.js.map +1 -1
- package/dist/cjs/Diff/diff.native.js.map +1 -1
- package/dist/cjs/Diff/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/DropdownMenu/menuSettle.native.js.map +1 -1
- package/dist/cjs/ElapsedProgress/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/Kbd/index.native.js.map +1 -1
- package/dist/cjs/Kbd/keys.native.js.map +1 -1
- package/dist/cjs/Lightbox/MediaControl.native.js.map +1 -1
- package/dist/cjs/Lightbox/index.gnome.native.js.map +1 -1
- package/dist/cjs/Lightbox/index.native.js +1 -1
- package/dist/cjs/Lightbox/shared.native.js.map +1 -1
- package/dist/cjs/Lightbox/useLightbox.native.js.map +1 -1
- package/dist/cjs/MachineLiteral/index.native.js.map +1 -1
- package/dist/cjs/Material/index.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.cjs +1 -1
- package/dist/cjs/Meter/meter.native.js +1 -1
- package/dist/cjs/Meter/meter.native.js.map +1 -1
- package/dist/cjs/OverflowRow/index.native.js +1 -1
- package/dist/cjs/OverflowRow/index.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/Popover.native.js +1 -1
- package/dist/cjs/Popover.native.js.map +1 -1
- package/dist/cjs/ProgressSteps/index.native.js.map +1 -1
- package/dist/cjs/Quote/index.native.js.map +1 -1
- package/dist/cjs/SchemeToggle/index.native.js +1 -1
- package/dist/cjs/SchemeToggle/index.native.js.map +1 -1
- package/dist/cjs/ScrollView/revealFocusedField.native.js.map +1 -1
- package/dist/cjs/Separator/index.native.js.map +1 -1
- package/dist/cjs/Sheet.native.js.map +1 -1
- package/dist/cjs/SheetModal/SheetHeader.native.js.map +1 -1
- package/dist/cjs/SheetModal/SheetNavigation.native.js.map +1 -1
- package/dist/cjs/SheetModal/detents.native.js.map +1 -1
- package/dist/cjs/SheetModal/index.cjs +33 -5
- package/dist/cjs/SheetModal/useSheetFrameFocus.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.native.js.map +1 -1
- package/dist/cjs/SortableList/useSortableRows.native.js.map +1 -1
- package/dist/cjs/SortableList/useUserOrder.native.js.map +1 -1
- package/dist/cjs/Tabs/index.native.js +1 -1
- package/dist/cjs/Tabs/index.native.js.map +1 -1
- package/dist/cjs/Text.native.js.map +1 -1
- package/dist/cjs/ThemePresetPicker/index.native.js +2 -2
- package/dist/cjs/ThemePresetPicker/index.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 +2 -2
- 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.native.js.map +1 -1
- package/dist/cjs/actions/DangerSection.native.js.map +1 -1
- package/dist/cjs/actions/DestructiveAction.native.js.map +1 -1
- package/dist/cjs/actions/HeaderActions.native.js +2 -2
- package/dist/cjs/actions/HeaderActions.native.js.map +1 -1
- package/dist/cjs/actions/StandardAction.native.js +1 -1
- package/dist/cjs/actions/StandardAction.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/appShell/AppShell.native.js +1 -1
- package/dist/cjs/appShell/AppShell.native.js.map +1 -1
- package/dist/cjs/appShell/BottomChromeClearance.native.js.map +1 -1
- package/dist/cjs/appShell/Dock.native.js.map +1 -1
- package/dist/cjs/appShell/MpoTabHost.native.js.map +1 -1
- package/dist/cjs/appShell/ScopeMenu.native.js +1 -1
- package/dist/cjs/appShell/ScopeMenu.native.js.map +1 -1
- package/dist/cjs/appShell/SettingsSplit.native.js +1 -1
- package/dist/cjs/appShell/SettingsSplit.native.js.map +1 -1
- package/dist/cjs/appShell/Springboard.native.js +1 -1
- package/dist/cjs/appShell/Springboard.native.js.map +1 -1
- package/dist/cjs/appShell/SystemBar.native.js.map +1 -1
- package/dist/cjs/appShell/TabBar.cjs +1 -1
- package/dist/cjs/appShell/TabBar.native.js +2 -2
- package/dist/cjs/appShell/TabBar.native.js.map +1 -1
- package/dist/cjs/appShell/TabHost.native.js +52 -5
- package/dist/cjs/appShell/TabHost.native.js.map +1 -1
- package/dist/cjs/appShell/appTile.native.js +1 -1
- package/dist/cjs/appShell/appTile.native.js.map +1 -1
- package/dist/cjs/appShell/bottomChrome.native.js.map +1 -1
- package/dist/cjs/appShell/index.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/ChartDataView.native.js +2 -2
- package/dist/cjs/charts/ChartDataView.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/chartHeight.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.native.js.map +1 -1
- package/dist/cjs/code/CodeBlock/index.native.js +7 -7
- package/dist/cjs/code/CodeBlock/index.native.js.map +1 -1
- package/dist/cjs/code/HighlightedCode/index.native.js.map +1 -1
- package/dist/cjs/code/Highlighter/houseSyntaxTheme.native.js.map +1 -1
- package/dist/cjs/code/Highlighter/index.native.js.map +1 -1
- package/dist/cjs/code/Highlighter/namedGroupMatchAll.native.js.map +1 -1
- package/dist/cjs/code/LogView.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/formLayouts/FormLayouts.native.js +1 -1
- package/dist/cjs/formLayouts/FormLayouts.native.js.map +1 -1
- package/dist/cjs/formLayouts/PreferencePanel.native.js +2 -2
- package/dist/cjs/formLayouts/PreferencePanel.native.js.map +1 -1
- package/dist/cjs/formLayouts/index.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/hooks/useHoldCue.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/framing.native.js.map +1 -1
- package/dist/cjs/images/Image/index.native.js +1 -1
- package/dist/cjs/images/Image/mediaRadius.native.js.map +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 +39 -39
- package/dist/cjs/index.native.js.map +1 -1
- 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 +1 -1
- package/dist/cjs/layouts/EmptyState.native.js.map +1 -1
- package/dist/cjs/layouts/IdentityPlate.native.js.map +1 -1
- package/dist/cjs/layouts/KeyboardAvoidingWrapper/behavior.native.js.map +1 -1
- package/dist/cjs/layouts/PageTemplates.cjs +15 -12
- package/dist/cjs/layouts/PageTemplates.native.js +16 -13
- 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/StatusDot.native.js.map +1 -1
- package/dist/cjs/layouts/StatusGlyphStrip.native.js +1 -1
- package/dist/cjs/layouts/StatusGlyphStrip.native.js.map +1 -1
- package/dist/cjs/layouts/ViewSwitcher.cjs +12 -2
- package/dist/cjs/layouts/ViewSwitcher.native.js +15 -2
- 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/barTitleSpan.native.js.map +1 -1
- package/dist/cjs/layouts/bottomAccessory.cjs +25 -13
- package/dist/cjs/layouts/bottomAccessory.native.js +29 -13
- package/dist/cjs/layouts/bottomAccessory.native.js.map +1 -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.cjs +44 -6
- package/dist/cjs/layouts/page.native.js +50 -8
- package/dist/cjs/layouts/page.native.js.map +1 -1
- package/dist/cjs/layouts/pageHeadingScope.native.js.map +1 -1
- package/dist/cjs/layouts/screenScroll.native.js.map +1 -1
- package/dist/cjs/layouts/shellSidebarSlot.native.js.map +1 -1
- package/dist/cjs/layouts/sidebar.native.js +1 -1
- package/dist/cjs/layouts/sidebar.native.js.map +1 -1
- package/dist/cjs/layouts/tags.native.js +2 -2
- 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 +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/restoreRetries.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/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.native.js +1 -1
- 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 +1 -1
- package/dist/cjs/views/Calendar.native.js.map +1 -1
- package/dist/cjs/views/Dashboard.native.js +2 -2
- package/dist/cjs/views/Dashboard.native.js.map +1 -1
- package/dist/cjs/views/Gantt.native.js +2 -2
- package/dist/cjs/views/Gantt.native.js.map +1 -1
- package/dist/cjs/views/GanttDateGrip.native.js.map +1 -1
- package/dist/cjs/views/ImageGrid.native.js +2 -2
- package/dist/cjs/views/ImageGrid.native.js.map +1 -1
- package/dist/cjs/views/Kanban.native.js +1 -1
- package/dist/cjs/views/List.native.js.map +1 -1
- package/dist/cjs/views/ListGroup.native.js.map +1 -1
- package/dist/cjs/views/ListRow.native.js.map +1 -1
- package/dist/cjs/views/Matrix.native.js +2 -2
- package/dist/cjs/views/Matrix.native.js.map +1 -1
- package/dist/cjs/views/ReportBuilder.native.js +2 -2
- package/dist/cjs/views/ReportBuilder.native.js.map +1 -1
- package/dist/cjs/views/ShortcutCard.native.js.map +1 -1
- package/dist/cjs/views/TreeView.native.js.map +1 -1
- package/dist/cjs/views/calendarMath.native.js.map +1 -1
- package/dist/cjs/views/ganttIntervals.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/matrixMath.native.js.map +1 -1
- package/dist/cjs/views/sameNameScope.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/cjs/views/treeViewReveal.native.js.map +1 -1
- package/dist/cjs/views/usePageFlowLoadMore.native.js.map +1 -1
- package/dist/cjs/views/widgetChrome.native.js.map +1 -1
- package/dist/esm/Carousel/index.mjs +12 -10
- package/dist/esm/Carousel/index.mjs.map +1 -1
- package/dist/esm/Carousel/index.native.js +13 -11
- package/dist/esm/Carousel/index.native.js.map +1 -1
- package/dist/esm/CopyField/CopyMenuButton.mjs +1 -3
- package/dist/esm/CopyField/CopyMenuButton.mjs.map +1 -1
- package/dist/esm/CopyField/CopyMenuButton.native.js +1 -3
- package/dist/esm/CopyField/CopyMenuButton.native.js.map +1 -1
- package/dist/esm/Meter/meter.mjs +1 -1
- package/dist/esm/Meter/meter.mjs.map +1 -1
- package/dist/esm/Meter/meter.native.js +1 -1
- package/dist/esm/Meter/meter.native.js.map +1 -1
- package/dist/esm/SheetModal/index.mjs +34 -6
- package/dist/esm/SheetModal/index.mjs.map +1 -1
- package/dist/esm/appShell/TabBar.mjs +2 -2
- package/dist/esm/appShell/TabBar.mjs.map +1 -1
- package/dist/esm/appShell/TabBar.native.js +2 -2
- package/dist/esm/appShell/TabBar.native.js.map +1 -1
- package/dist/esm/appShell/TabHost.native.js +53 -9
- package/dist/esm/appShell/TabHost.native.js.map +1 -1
- package/dist/esm/layouts/PageTemplates.mjs +16 -13
- package/dist/esm/layouts/PageTemplates.mjs.map +1 -1
- package/dist/esm/layouts/PageTemplates.native.js +17 -14
- package/dist/esm/layouts/PageTemplates.native.js.map +1 -1
- package/dist/esm/layouts/ViewSwitcher.mjs +12 -2
- package/dist/esm/layouts/ViewSwitcher.mjs.map +1 -1
- package/dist/esm/layouts/ViewSwitcher.native.js +15 -2
- package/dist/esm/layouts/ViewSwitcher.native.js.map +1 -1
- package/dist/esm/layouts/bottomAccessory.mjs +26 -15
- package/dist/esm/layouts/bottomAccessory.mjs.map +1 -1
- package/dist/esm/layouts/bottomAccessory.native.js +30 -15
- package/dist/esm/layouts/bottomAccessory.native.js.map +1 -1
- package/dist/esm/layouts/page.mjs +44 -8
- package/dist/esm/layouts/page.mjs.map +1 -1
- package/dist/esm/layouts/page.native.js +48 -8
- package/dist/esm/layouts/page.native.js.map +1 -1
- package/dist/jsx/Carousel/index.mjs +12 -10
- package/dist/jsx/Carousel/index.mjs.map +1 -1
- package/dist/jsx/Carousel/index.native.js +12 -10
- package/dist/jsx/Carousel/index.native.js.map +1 -1
- package/dist/jsx/CopyField/CopyMenuButton.mjs +1 -3
- package/dist/jsx/CopyField/CopyMenuButton.mjs.map +1 -1
- package/dist/jsx/CopyField/CopyMenuButton.native.js +1 -3
- package/dist/jsx/CopyField/CopyMenuButton.native.js.map +1 -1
- package/dist/jsx/Meter/meter.mjs +1 -1
- package/dist/jsx/Meter/meter.mjs.map +1 -1
- package/dist/jsx/Meter/meter.native.js +1 -1
- package/dist/jsx/Meter/meter.native.js.map +1 -1
- package/dist/jsx/SheetModal/index.mjs +34 -6
- package/dist/jsx/SheetModal/index.mjs.map +1 -1
- package/dist/jsx/appShell/TabBar.mjs +2 -2
- package/dist/jsx/appShell/TabBar.mjs.map +1 -1
- package/dist/jsx/appShell/TabBar.native.js +1 -1
- package/dist/jsx/appShell/TabBar.native.js.map +1 -1
- package/dist/jsx/appShell/TabHost.native.js +52 -5
- package/dist/jsx/appShell/TabHost.native.js.map +1 -1
- package/dist/jsx/feedback/NotifyHost.native.js +1 -1
- package/dist/jsx/formLayouts/PreferencePanel.native.js +1 -1
- package/dist/jsx/index.native.js +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/PageTemplates.mjs +16 -13
- package/dist/jsx/layouts/PageTemplates.mjs.map +1 -1
- package/dist/jsx/layouts/PageTemplates.native.js +16 -13
- package/dist/jsx/layouts/PageTemplates.native.js.map +1 -1
- package/dist/jsx/layouts/ViewSwitcher.mjs +12 -2
- package/dist/jsx/layouts/ViewSwitcher.mjs.map +1 -1
- package/dist/jsx/layouts/ViewSwitcher.native.js +15 -2
- package/dist/jsx/layouts/ViewSwitcher.native.js.map +1 -1
- package/dist/jsx/layouts/bottomAccessory.mjs +26 -15
- package/dist/jsx/layouts/bottomAccessory.mjs.map +1 -1
- package/dist/jsx/layouts/bottomAccessory.native.js +29 -13
- package/dist/jsx/layouts/bottomAccessory.native.js.map +1 -1
- package/dist/jsx/layouts/page.mjs +44 -8
- package/dist/jsx/layouts/page.mjs.map +1 -1
- package/dist/jsx/layouts/page.native.js +48 -6
- package/dist/jsx/layouts/page.native.js.map +1 -1
- package/package.json +11 -11
- package/src/Carousel/Carousel.native.spec.tsx +25 -8
- package/src/Carousel/index.tsx +18 -11
- package/src/CopyField/CopyMenuButton.spec.tsx +2 -0
- package/src/CopyField/CopyMenuButton.tsx +1 -8
- package/src/Meter/Meter.spec.tsx +5 -4
- package/src/Meter/meter.ts +6 -4
- package/src/SheetModal/SheetModal.regularWidth.spec.tsx +87 -0
- package/src/SheetModal/index.tsx +52 -5
- package/src/Text.stories.tsx +13 -0
- package/src/appShell/TabBar.spec.tsx +10 -4
- package/src/appShell/TabBar.tsx +4 -8
- package/src/appShell/TabHost.native.spec.tsx +109 -1
- package/src/appShell/TabHost.native.tsx +84 -13
- package/src/icons/themedButtonInk.spec.tsx +117 -0
- package/src/layouts/DensePageLayout.spec.tsx +105 -0
- package/src/layouts/PageTemplates.tsx +14 -11
- package/src/layouts/Screen.chromeClearance.spec.tsx +28 -0
- package/src/layouts/ViewSwitcher.native-press.spec.tsx +55 -0
- package/src/layouts/ViewSwitcher.tsx +13 -2
- package/src/layouts/bottomAccessory.tsx +40 -15
- package/src/layouts/page.tsx +73 -19
- package/src/layouts/pageTitleOneLine.spec.tsx +42 -0
- package/src/layouts/pushedPageTitle.spec.tsx +116 -0
- package/types/Carousel/index.d.ts.map +1 -1
- package/types/CopyField/CopyMenuButton.d.ts.map +1 -1
- package/types/Meter/meter.d.ts +6 -4
- package/types/Meter/meter.d.ts.map +1 -1
- package/types/SheetModal/index.d.ts.map +1 -1
- package/types/appShell/TabBar.d.ts.map +1 -1
- package/types/appShell/TabHost.native.d.ts +13 -1
- package/types/appShell/TabHost.native.d.ts.map +1 -1
- package/types/layouts/PageTemplates.d.ts.map +1 -1
- package/types/layouts/ViewSwitcher.d.ts.map +1 -1
- package/types/layouts/bottomAccessory.d.ts +6 -1
- package/types/layouts/bottomAccessory.d.ts.map +1 -1
- package/types/layouts/page.d.ts +16 -1
- package/types/layouts/page.d.ts.map +1 -1
package/src/Meter/meter.ts
CHANGED
|
@@ -23,9 +23,11 @@ export type MeterLayout = "adjacent" | "inline" | "bare";
|
|
|
23
23
|
export const METER_RADIUS_CLASS = "DEFAULT" as const;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Zone paint — theme
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* Zone paint — theme tokens, never raw brand or the accent solid. ok carries
|
|
27
|
+
* no verdict (DG-FB-06), so it is the plain fill on a track Progress paints:
|
|
28
|
+
* the theme's accent ink, `formSelectedColors.trackFill` (LC-172, FZ-8044).
|
|
29
|
+
* warn/critical are the same step-9 solid / step-11 ink channel Progress uses
|
|
30
|
+
* (DG-FB-05).
|
|
29
31
|
*
|
|
30
32
|
* MPO-154: ok carries no `value`. Under no verdict the readout is ordinary
|
|
31
33
|
* secondary text, so its ink is `knobProps.textAccentColor` — a static
|
|
@@ -33,7 +35,7 @@ export const METER_RADIUS_CLASS = "DEFAULT" as const;
|
|
|
33
35
|
* and it pinned the readout dim at `textAccent: high`.
|
|
34
36
|
*/
|
|
35
37
|
export const METER_ZONE_PAINT = {
|
|
36
|
-
ok: { fill: "$
|
|
38
|
+
ok: { fill: "$accentColor" },
|
|
37
39
|
warn: { fill: "$orange9", value: "$orange11" },
|
|
38
40
|
critical: { fill: "$red9", value: "$red11" },
|
|
39
41
|
} as const;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FZ-8939 (LC-266): the web SheetModal at regular width is the native
|
|
3
|
+
* panel's twin (FZ-8116). On a desktop window the Tier 2 cells
|
|
4
|
+
* `components-sheetframe--default` and `components-formlayouts--sign-in-in-sheet`
|
|
5
|
+
* drew the sheet as a band across the whole window. It is a bottom panel
|
|
6
|
+
* SHEET_PANEL_WIDTH wide, centred, with the scrim showing on both sides, and a
|
|
7
|
+
* press beside it dismisses. At compact width it stays the full-width sheet.
|
|
8
|
+
*/
|
|
9
|
+
import { SHEET_PANEL_WIDTH } from "@multiplatform.one/forms";
|
|
10
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
11
|
+
import { act, cleanup, fireEvent, waitFor } from "@testing-library/react";
|
|
12
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
13
|
+
import { Text } from "tamagui";
|
|
14
|
+
import { SheetModal } from "./index";
|
|
15
|
+
|
|
16
|
+
// The DOM under test reports no window width of its own, so the window is
|
|
17
|
+
// set here, as the native regular-width spec does.
|
|
18
|
+
const screen = vi.hoisted(() => ({ width: 1280, height: 800 }));
|
|
19
|
+
vi.mock("tamagui", async (importOriginal) => ({
|
|
20
|
+
...(await importOriginal<typeof import("tamagui")>()),
|
|
21
|
+
useWindowDimensions: () => ({ ...screen, scale: 1, fontScale: 1 }),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
function setWindowWidth(width: number) {
|
|
25
|
+
screen.width = width;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
cleanup();
|
|
30
|
+
screen.width = 1280;
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
async function openAt(width: number) {
|
|
34
|
+
setWindowWidth(width);
|
|
35
|
+
const onOpenChange = vi.fn();
|
|
36
|
+
const view = renderWithProviders(
|
|
37
|
+
<SheetModal open onOpenChange={onOpenChange}>
|
|
38
|
+
<Text>Sign in</Text>
|
|
39
|
+
</SheetModal>,
|
|
40
|
+
);
|
|
41
|
+
// tamagui draws a cover under the frame with the frame's own props; the
|
|
42
|
+
// frame is the one that is not the cover.
|
|
43
|
+
let frame: HTMLElement | null = null;
|
|
44
|
+
await waitFor(() => {
|
|
45
|
+
frame = document.querySelector('[role="dialog"]:not([data-sheet-cover])');
|
|
46
|
+
expect(frame).not.toBeNull();
|
|
47
|
+
});
|
|
48
|
+
return { view, frame: frame as unknown as HTMLElement, onOpenChange };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const atoms = (node: Element) => String(node.className).split(/\s+/).filter(Boolean);
|
|
52
|
+
|
|
53
|
+
describe("SheetModal web at regular width (FZ-8939, LC-266)", () => {
|
|
54
|
+
it("is a centred panel capped at the panel width on a desktop window", async () => {
|
|
55
|
+
const { frame } = await openAt(1280);
|
|
56
|
+
expect(frame.getAttribute("data-sheet-form")).toBe("panel");
|
|
57
|
+
const width = frame.style.width || atoms(frame).find((a) => a.startsWith("_w-")) || "";
|
|
58
|
+
expect(width).toContain(`${SHEET_PANEL_WIDTH}px`);
|
|
59
|
+
expect(atoms(frame).some((a) => a === "_als-center")).toBe(true);
|
|
60
|
+
// A panel keeps its side edges; the compact band drops them.
|
|
61
|
+
expect(atoms(frame)).not.toContain("_blw-0px");
|
|
62
|
+
expect(atoms(frame)).not.toContain("_brw-0px");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("dismisses on a press beside the panel, not on a press inside it", async () => {
|
|
66
|
+
const { frame, onOpenChange } = await openAt(1280);
|
|
67
|
+
await act(async () => {
|
|
68
|
+
fireEvent.click(frame);
|
|
69
|
+
});
|
|
70
|
+
expect(onOpenChange).not.toHaveBeenCalled();
|
|
71
|
+
await act(async () => {
|
|
72
|
+
fireEvent.click(frame.parentElement as HTMLElement);
|
|
73
|
+
});
|
|
74
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("stays the full-width bottom sheet at phone width", async () => {
|
|
78
|
+
const { frame, onOpenChange } = await openAt(390);
|
|
79
|
+
expect(frame.getAttribute("data-sheet-form")).toBe("bottom");
|
|
80
|
+
expect(atoms(frame)).toContain("_blw-0px");
|
|
81
|
+
expect(atoms(frame)).toContain("_brw-0px");
|
|
82
|
+
await act(async () => {
|
|
83
|
+
fireEvent.click(frame.parentElement as HTMLElement);
|
|
84
|
+
});
|
|
85
|
+
expect(onOpenChange).not.toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
});
|
package/src/SheetModal/index.tsx
CHANGED
|
@@ -15,7 +15,12 @@ import {
|
|
|
15
15
|
transitionProps,
|
|
16
16
|
useResolvedKnobs,
|
|
17
17
|
} from "@multiplatform.one/theme";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
OverlayStackProvider,
|
|
20
|
+
overlaySizeClass,
|
|
21
|
+
sheetPanelWidth,
|
|
22
|
+
useOverlayZIndex,
|
|
23
|
+
} from "@multiplatform.one/forms";
|
|
19
24
|
import { useEffect, useId, useRef, type ReactNode } from "react";
|
|
20
25
|
import { isWeb, Sheet, View, useWindowDimensions } from "tamagui";
|
|
21
26
|
import { OverlayTitleIdContext } from "../actions/StandardAction";
|
|
@@ -69,6 +74,47 @@ const IN_DIALOG_REGION = { inDialogRegion: true } as const;
|
|
|
69
74
|
const fillSlot = { flex: 1, minHeight: 0 } as const;
|
|
70
75
|
const nonShrinking = { flexShrink: 0 } as const;
|
|
71
76
|
|
|
77
|
+
/** A compact sheet spans the window: only its top edge meets the page. */
|
|
78
|
+
const bottomEdges = { borderLeftWidth: 0, borderRightWidth: 0, borderBottomWidth: 0 } as const;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* LC-266 (FZ-8939): at regular width the sheet is the native panel's twin, a
|
|
82
|
+
* bottom panel `sheetPanelWidth` wide and centred with the scrim on both
|
|
83
|
+
* sides. Its side edges stay, so it reads as a panel rather than a band.
|
|
84
|
+
*/
|
|
85
|
+
function regularPanel(windowWidth: number) {
|
|
86
|
+
return {
|
|
87
|
+
width: sheetPanelWidth(windowWidth),
|
|
88
|
+
alignSelf: "center",
|
|
89
|
+
borderBottomWidth: 0,
|
|
90
|
+
} as const;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The sheet's frame sits in a window-wide band that tamagui's pan responder
|
|
95
|
+
* owns, so a press on the band beside a regular-width panel never reaches the
|
|
96
|
+
* scrim. A press that lands on the band itself, not inside the panel or the
|
|
97
|
+
* grabber, is a press outside the sheet, and dismisses it (LC-266).
|
|
98
|
+
*/
|
|
99
|
+
function useBandDismiss(
|
|
100
|
+
enabled: boolean,
|
|
101
|
+
frameRef: { current: HTMLElement | null },
|
|
102
|
+
onDismiss: () => void,
|
|
103
|
+
) {
|
|
104
|
+
const onDismissRef = useRef(onDismiss);
|
|
105
|
+
onDismissRef.current = onDismiss;
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!isWeb || !enabled) return;
|
|
108
|
+
const band = frameRef.current?.parentElement;
|
|
109
|
+
if (!band) return;
|
|
110
|
+
const onClick = (event: MouseEvent) => {
|
|
111
|
+
if (event.target === band) onDismissRef.current();
|
|
112
|
+
};
|
|
113
|
+
band.addEventListener("click", onClick);
|
|
114
|
+
return () => band.removeEventListener("click", onClick);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
72
118
|
/** LC-71: the sheet frame is not a control. Auto-focus must not paint a ring. */
|
|
73
119
|
const frameRingReset = {
|
|
74
120
|
outlineWidth: 0,
|
|
@@ -112,7 +158,8 @@ export function SheetModal({
|
|
|
112
158
|
/>
|
|
113
159
|
) : null;
|
|
114
160
|
const snap = resolveWebSnap({ snapPoint, fill });
|
|
115
|
-
const { height: windowHeight } = useWindowDimensions();
|
|
161
|
+
const { height: windowHeight, width: windowWidth } = useWindowDimensions();
|
|
162
|
+
const regular = overlaySizeClass(windowWidth) === "regular";
|
|
116
163
|
const { knobProps } = useResolvedKnobs();
|
|
117
164
|
const sheetZIndex = useOverlayZIndex("sheet");
|
|
118
165
|
const transition = knobProps.motion.slide.transition;
|
|
@@ -120,6 +167,7 @@ export function SheetModal({
|
|
|
120
167
|
|
|
121
168
|
useSheetFrameFocus(open, frameRef);
|
|
122
169
|
useSheetEscapeDismiss(open, () => onOpenChange(false));
|
|
170
|
+
useBandDismiss(open && regular, frameRef, () => onOpenChange(false));
|
|
123
171
|
|
|
124
172
|
return (
|
|
125
173
|
<Sheet
|
|
@@ -147,6 +195,7 @@ export function SheetModal({
|
|
|
147
195
|
role: "dialog",
|
|
148
196
|
"aria-modal": true,
|
|
149
197
|
"aria-labelledby": headerContent ? titleId : undefined,
|
|
198
|
+
"data-sheet-form": regular ? "panel" : "bottom",
|
|
150
199
|
} as Record<string, unknown>)}
|
|
151
200
|
{...knobProps.gap}
|
|
152
201
|
{...(snap.snapPointsMode === "fit"
|
|
@@ -154,9 +203,7 @@ export function SheetModal({
|
|
|
154
203
|
: null)}
|
|
155
204
|
borderBottomLeftRadius={0}
|
|
156
205
|
borderBottomRightRadius={0}
|
|
157
|
-
|
|
158
|
-
borderRightWidth={0}
|
|
159
|
-
borderBottomWidth={0}
|
|
206
|
+
{...(regular ? regularPanel(windowWidth) : bottomEdges)}
|
|
160
207
|
overflow="hidden"
|
|
161
208
|
{...frameRingReset}
|
|
162
209
|
>
|
package/src/Text.stories.tsx
CHANGED
|
@@ -71,6 +71,19 @@ export const FontWeightFlip: Story = {
|
|
|
71
71
|
),
|
|
72
72
|
};
|
|
73
73
|
|
|
74
|
+
export const InterFaces: Story = {
|
|
75
|
+
name: "Inter faces (400 to 800)",
|
|
76
|
+
render: () => (
|
|
77
|
+
<YStack gap="$2" maxWidth={520}>
|
|
78
|
+
{(["400", "500", "600", "700", "800"] as const).map((weight) => (
|
|
79
|
+
<SizableText key={weight} size="$6" fontWeight={weight}>
|
|
80
|
+
{weight} Hamburgefonstiv 0123
|
|
81
|
+
</SizableText>
|
|
82
|
+
))}
|
|
83
|
+
</YStack>
|
|
84
|
+
),
|
|
85
|
+
};
|
|
86
|
+
|
|
74
87
|
const digitPresets = {
|
|
75
88
|
Default: defaultPreset,
|
|
76
89
|
Bold: boldPreset,
|
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
Preset,
|
|
11
11
|
createDefaultThemeConfig,
|
|
12
12
|
normalizeToHex,
|
|
13
|
-
|
|
13
|
+
useActiveTabInk,
|
|
14
14
|
useGlyphColor,
|
|
15
|
+
useIdentityInkOnSurface,
|
|
15
16
|
} from "@multiplatform.one/theme";
|
|
16
17
|
import { act, cleanup, fireEvent, renderHook, screen } from "@testing-library/react";
|
|
17
18
|
import fs from "node:fs";
|
|
@@ -67,9 +68,10 @@ function probeItems(seen: Record<string, GlyphProps>): TabBarItem[] {
|
|
|
67
68
|
];
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
const expected: { accent?: string; secondary?: string; primary?: string } = {};
|
|
71
|
+
const expected: { accent?: string; secondary?: string; primary?: string; identity?: string } = {};
|
|
71
72
|
function InkProbe() {
|
|
72
|
-
expected.accent =
|
|
73
|
+
expected.accent = useActiveTabInk();
|
|
74
|
+
expected.identity = useIdentityInkOnSurface();
|
|
73
75
|
expected.secondary = useGlyphColor(tabBarInactiveInk);
|
|
74
76
|
expected.primary = useGlyphColor("$color");
|
|
75
77
|
return null;
|
|
@@ -152,9 +154,13 @@ describe("TabBar (LC-150 TAB-BAR-ANATOMY)", () => {
|
|
|
152
154
|
});
|
|
153
155
|
}
|
|
154
156
|
|
|
155
|
-
it(`${scheme}, no hue: the active tab is the
|
|
157
|
+
it(`${scheme}, no hue: the active tab is the neutral accent's ink, bold mono, never grey`, () => {
|
|
156
158
|
const seen = renderBar(scheme, "/");
|
|
157
159
|
expect(expected.accent).toBeTruthy();
|
|
160
|
+
// The house accent is the neutral inverse: the active tab is the same
|
|
161
|
+
// ink the system bar draws, never the grey accent-ramp step (Round 54).
|
|
162
|
+
expect(expected.accent).toBe(expected.identity);
|
|
163
|
+
expect(expected.accent).not.toBe(expected.secondary);
|
|
158
164
|
expect(seen["/"]).toMatchObject({ color: expected.accent, weight: "fill" });
|
|
159
165
|
expect(seen["/moves"]).toMatchObject({ color: expected.secondary, weight: "regular" });
|
|
160
166
|
});
|
package/src/appShell/TabBar.tsx
CHANGED
|
@@ -10,14 +10,10 @@
|
|
|
10
10
|
* (`useBottomChromeInset`), so the last row clears it. The bottom accessory
|
|
11
11
|
* (LC-174, e.g. a pager) floats as its own smaller capsule above it. A theme
|
|
12
12
|
* changes the colours only: the active item is the theme's accent as
|
|
13
|
-
* readable ink
|
|
14
|
-
* ink.
|
|
13
|
+
* readable ink (`useActiveTabInk`, the same pick as the system tab bar's) on
|
|
14
|
+
* an accent-wash pill, inactive items are the secondary text ink.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
useAccentOnSurface,
|
|
18
|
-
useAccentTintedSurface,
|
|
19
|
-
useGlyphColor,
|
|
20
|
-
} from "@multiplatform.one/theme";
|
|
16
|
+
import { useAccentTintedSurface, useActiveTabInk, useGlyphColor } from "@multiplatform.one/theme";
|
|
21
17
|
import { zIndex } from "@multiplatform.one/forms";
|
|
22
18
|
import { isWeb } from "@multiplatform.one/platform";
|
|
23
19
|
import { type ComponentType, type ReactNode, useEffect, useState } from "react";
|
|
@@ -134,7 +130,7 @@ function TabBarButton({
|
|
|
134
130
|
onPress?: () => void;
|
|
135
131
|
testID: string;
|
|
136
132
|
}) {
|
|
137
|
-
const accent =
|
|
133
|
+
const accent = useActiveTabInk();
|
|
138
134
|
const wash = useAccentTintedSurface();
|
|
139
135
|
const secondaryInk = useGlyphColor(tabBarInactiveInk);
|
|
140
136
|
const ink = active ? accent : secondaryInk;
|
|
@@ -8,6 +8,12 @@ import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
|
8
8
|
import { cleanup, fireEvent, screen } from "@testing-library/react";
|
|
9
9
|
import type { ReactNode } from "react";
|
|
10
10
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
11
|
+
import {
|
|
12
|
+
BottomAccessoryHost,
|
|
13
|
+
BottomAccessoryScope,
|
|
14
|
+
BottomAccessory,
|
|
15
|
+
createBottomAccessoryStore,
|
|
16
|
+
} from "../layouts/bottomAccessory";
|
|
11
17
|
import { useBottomChromeInset } from "./bottomChrome";
|
|
12
18
|
import type { TabBarItem } from "./TabBar";
|
|
13
19
|
import {
|
|
@@ -18,7 +24,10 @@ import {
|
|
|
18
24
|
itemsHaveNativeIcons,
|
|
19
25
|
nativeIconFor,
|
|
20
26
|
nativeTabBarHeight,
|
|
27
|
+
nativeTabsAccessoryComponent,
|
|
28
|
+
nativeTabsAccessoryHeight,
|
|
21
29
|
nativeTabsPlatforms,
|
|
30
|
+
resolveNativeAccessory,
|
|
22
31
|
resolveNativeTabs,
|
|
23
32
|
} from "./TabHost.native";
|
|
24
33
|
|
|
@@ -49,9 +58,12 @@ const items: TabBarItem[] = [
|
|
|
49
58
|
];
|
|
50
59
|
|
|
51
60
|
const fakeTabs: NativeTabs = {
|
|
52
|
-
Host: ({ children, onNativeFocusChange, tabBarHidden }) => (
|
|
61
|
+
Host: ({ children, onNativeFocusChange, tabBarHidden, bottomAccessory }) => (
|
|
53
62
|
<div data-testid="native-host" data-hidden={String(Boolean(tabBarHidden))}>
|
|
54
63
|
{children}
|
|
64
|
+
{bottomAccessory ? (
|
|
65
|
+
<aside data-testid="native-bottom-accessory">{bottomAccessory("regular")}</aside>
|
|
66
|
+
) : null}
|
|
55
67
|
<button
|
|
56
68
|
type="button"
|
|
57
69
|
data-testid="native-press-moves"
|
|
@@ -271,3 +283,99 @@ describe("TabHost fallback", () => {
|
|
|
271
283
|
expect(screen.queryByTestId("tab-bar")).toBeNull();
|
|
272
284
|
});
|
|
273
285
|
});
|
|
286
|
+
|
|
287
|
+
describe("bottom accessory under the system bar (FZ-7995, LC-174)", () => {
|
|
288
|
+
const registered = [...["RNSTabsHost", "RNSTabsScreen"], nativeTabsAccessoryComponent];
|
|
289
|
+
|
|
290
|
+
it("hosts it on iOS 26 when the binary carries the accessory view", () => {
|
|
291
|
+
expect(
|
|
292
|
+
resolveNativeAccessory(
|
|
293
|
+
sources(registered, () => ({})),
|
|
294
|
+
"ios",
|
|
295
|
+
"26.0",
|
|
296
|
+
),
|
|
297
|
+
).toBe(true);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it("keeps the page's slot before iOS 26, on a binary without the view, off iOS, or when the probe throws", () => {
|
|
301
|
+
expect(
|
|
302
|
+
resolveNativeAccessory(
|
|
303
|
+
sources(registered, () => ({})),
|
|
304
|
+
"ios",
|
|
305
|
+
"18.5",
|
|
306
|
+
),
|
|
307
|
+
).toBe(false);
|
|
308
|
+
expect(
|
|
309
|
+
resolveNativeAccessory(
|
|
310
|
+
sources(["RNSTabsHost", "RNSTabsScreen"], () => ({})),
|
|
311
|
+
"ios",
|
|
312
|
+
"26.1",
|
|
313
|
+
),
|
|
314
|
+
).toBe(false);
|
|
315
|
+
expect(
|
|
316
|
+
resolveNativeAccessory(
|
|
317
|
+
sources(registered, () => ({})),
|
|
318
|
+
"android",
|
|
319
|
+
36,
|
|
320
|
+
),
|
|
321
|
+
).toBe(false);
|
|
322
|
+
const throws = () => {
|
|
323
|
+
throw new Error("unavailable");
|
|
324
|
+
};
|
|
325
|
+
expect(resolveNativeAccessory({ hasComponent: throws }, "ios", "26.0")).toBe(false);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
function renderWithPager(hostsAccessory: boolean, pushed = false) {
|
|
329
|
+
const activeKey = pushed ? undefined : "/moves";
|
|
330
|
+
const store = createBottomAccessoryStore();
|
|
331
|
+
return renderWithProviders(
|
|
332
|
+
<NativeTabHost
|
|
333
|
+
tabs={fakeTabs}
|
|
334
|
+
items={items}
|
|
335
|
+
activeKey={activeKey}
|
|
336
|
+
onTabPress={vi.fn()}
|
|
337
|
+
hostsAccessory={hostsAccessory}
|
|
338
|
+
>
|
|
339
|
+
<BottomAccessoryScope store={store}>
|
|
340
|
+
<div data-testid="page">
|
|
341
|
+
<BottomAccessory>
|
|
342
|
+
<span data-testid="pager">1–15 of 900</span>
|
|
343
|
+
</BottomAccessory>
|
|
344
|
+
</div>
|
|
345
|
+
<BottomAccessoryHost store={store} />
|
|
346
|
+
</BottomAccessoryScope>
|
|
347
|
+
<Inset />
|
|
348
|
+
</NativeTabHost>,
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
it("moves the page's pager into the system bar's accessory and clears it", () => {
|
|
353
|
+
renderWithPager(true);
|
|
354
|
+
const accessory = screen.getByTestId("native-bottom-accessory");
|
|
355
|
+
expect(accessory.contains(screen.getByTestId("pager"))).toBe(true);
|
|
356
|
+
expect(screen.getByTestId("native-tab-accessory")).toBeTruthy();
|
|
357
|
+
expect(document.querySelector('[data-bottom-accessory="slot"]')).toBeNull();
|
|
358
|
+
expect(Number(screen.getByTestId("inset").textContent)).toBeGreaterThanOrEqual(
|
|
359
|
+
nativeTabBarHeight + nativeTabsAccessoryHeight,
|
|
360
|
+
);
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
it("falls back to the page's slot, standing on the bar, where the system bar cannot host it", () => {
|
|
364
|
+
renderWithPager(false);
|
|
365
|
+
expect(screen.queryByTestId("native-bottom-accessory")).toBeNull();
|
|
366
|
+
const slot = document.querySelector('[data-bottom-accessory="slot"]');
|
|
367
|
+
expect(slot?.contains(screen.getByTestId("pager"))).toBe(true);
|
|
368
|
+
expect(screen.getByTestId("bottom-accessory-lift")).toBeTruthy();
|
|
369
|
+
const inset = Number(screen.getByTestId("inset").textContent);
|
|
370
|
+
expect(inset).toBeGreaterThanOrEqual(nativeTabBarHeight);
|
|
371
|
+
expect(inset).toBeLessThan(nativeTabBarHeight + nativeTabsAccessoryHeight);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("returns the pager to the slot on a pushed screen, where the bar is hidden", () => {
|
|
375
|
+
renderWithPager(true, true);
|
|
376
|
+
expect(screen.queryByTestId("native-bottom-accessory")).toBeNull();
|
|
377
|
+
const slot = document.querySelector('[data-bottom-accessory="slot"]');
|
|
378
|
+
expect(slot?.contains(screen.getByTestId("pager"))).toBe(true);
|
|
379
|
+
expect(screen.queryByTestId("bottom-accessory-lift")).toBeNull();
|
|
380
|
+
});
|
|
381
|
+
});
|
|
@@ -15,21 +15,23 @@
|
|
|
15
15
|
* (Material bottom navigation, PNG template icons) is built and switched off
|
|
16
16
|
* until an Android build proves it (FZ-8140).
|
|
17
17
|
*
|
|
18
|
+
* A page's bottom accessory (LC-174, e.g. a DataTable pager) rides the
|
|
19
|
+
* system bar too: on iOS 26, where the binary carries RNSTabsBottomAccessory,
|
|
20
|
+
* it is UITabBarController's bottom accessory, the system's own glass capsule
|
|
21
|
+
* above the bar (FZ-7995). Anywhere else it stays in the page's slot, which
|
|
22
|
+
* sits above the bar.
|
|
23
|
+
*
|
|
18
24
|
* The bar's clearance is the inset this host publishes, as with the MPO
|
|
19
25
|
* TabBar, so a Screen pads by it whether or not it scrolls. Each tab screen
|
|
20
26
|
* leaves its scroll view's inset adjustment off: react-native-screens would
|
|
21
27
|
* otherwise flip the first scroll view to `automatic`, and UIKit would add
|
|
22
28
|
* the bar's height a second time (FZ-8640).
|
|
23
29
|
*/
|
|
24
|
-
import {
|
|
25
|
-
useAccentTintedSurface,
|
|
26
|
-
useGlyphColor,
|
|
27
|
-
useIdentityInkOnSurface,
|
|
28
|
-
} from "@multiplatform.one/theme";
|
|
30
|
+
import { useAccentTintedSurface, useActiveTabInk, useGlyphColor } from "@multiplatform.one/theme";
|
|
29
31
|
import { type ComponentType, type ReactNode, useEffect, useRef, useState } from "react";
|
|
30
32
|
import { type ImageSourcePropType, Platform, UIManager } from "react-native";
|
|
31
|
-
import { YStack } from "tamagui";
|
|
32
|
-
import { setBottomChromeInset } from "./bottomChrome";
|
|
33
|
+
import { XStack, YStack } from "tamagui";
|
|
34
|
+
import { setBottomChromeInset, setFloatingBarMounted, useBottomAccessory } from "./bottomChrome";
|
|
33
35
|
import { useBottomInset } from "./bottomInset";
|
|
34
36
|
import { type TabBarItem, tabBarInactiveInk } from "./TabBar";
|
|
35
37
|
import { MpoTabHost, type TabHostProps } from "./MpoTabHost";
|
|
@@ -42,6 +44,12 @@ export const nativeTabsComponents = ["RNSTabsHost", "RNSTabsScreen"] as const;
|
|
|
42
44
|
/** Points the system tab bar covers above the home-indicator band. */
|
|
43
45
|
export const nativeTabBarHeight = 49;
|
|
44
46
|
|
|
47
|
+
/** The Fabric component behind UITabBarController's bottom accessory (iOS 26). */
|
|
48
|
+
export const nativeTabsAccessoryComponent = "RNSTabsBottomAccessory";
|
|
49
|
+
|
|
50
|
+
/** Points the bottom accessory's capsule adds above the system bar, its gap included. */
|
|
51
|
+
export const nativeTabsAccessoryHeight = 56;
|
|
52
|
+
|
|
45
53
|
type ImageIcon = { type: "imageSource"; imageSource: ImageSourcePropType };
|
|
46
54
|
type IconProp = { ios?: { type: "sfSymbol"; name: string }; android?: ImageIcon };
|
|
47
55
|
|
|
@@ -66,6 +74,7 @@ export interface NativeTabs {
|
|
|
66
74
|
tabBarBackgroundColor?: string;
|
|
67
75
|
tabBarItemActiveIndicatorColor?: string;
|
|
68
76
|
experimentalControlNavigationStateInJS?: boolean;
|
|
77
|
+
bottomAccessory?: (environment: "regular" | "inline") => ReactNode;
|
|
69
78
|
onNativeFocusChange?: (event: { nativeEvent: { tabKey: string } }) => void;
|
|
70
79
|
}>;
|
|
71
80
|
Screen: ComponentType<{
|
|
@@ -107,13 +116,39 @@ export function resolveNativeTabs(
|
|
|
107
116
|
}
|
|
108
117
|
}
|
|
109
118
|
|
|
119
|
+
/**
|
|
120
|
+
* True when the system bar can host the page's bottom accessory: iOS 26 or
|
|
121
|
+
* later (UITabAccessory) and a binary that carries react-native-screens'
|
|
122
|
+
* accessory view. Otherwise the accessory stays in the page's slot.
|
|
123
|
+
*/
|
|
124
|
+
export function resolveNativeAccessory(
|
|
125
|
+
sources: Pick<NativeTabsSources, "hasComponent">,
|
|
126
|
+
os: string,
|
|
127
|
+
version: string | number,
|
|
128
|
+
): boolean {
|
|
129
|
+
if (os !== "ios" || Number.parseInt(String(version), 10) < 26) return false;
|
|
130
|
+
try {
|
|
131
|
+
return sources.hasComponent(nativeTabsAccessoryComponent);
|
|
132
|
+
} catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
110
137
|
let cached: NativeTabs | null | undefined;
|
|
138
|
+
let cachedAccessory: boolean | undefined;
|
|
111
139
|
|
|
112
140
|
function loadNativeTabs(): NativeTabs | null {
|
|
113
141
|
if (cached === undefined) cached = resolveNativeTabs(appSources, Platform.OS);
|
|
114
142
|
return cached;
|
|
115
143
|
}
|
|
116
144
|
|
|
145
|
+
function loadNativeAccessory(): boolean {
|
|
146
|
+
if (cachedAccessory === undefined) {
|
|
147
|
+
cachedAccessory = resolveNativeAccessory(appSources, Platform.OS, Platform.Version);
|
|
148
|
+
}
|
|
149
|
+
return cachedAccessory;
|
|
150
|
+
}
|
|
151
|
+
|
|
117
152
|
/** True when every item names the glyph this platform's system bar draws. */
|
|
118
153
|
export function itemsHaveNativeIcons(items: readonly TabBarItem[], os = "ios"): boolean {
|
|
119
154
|
const glyph = (item: TabBarItem) =>
|
|
@@ -130,15 +165,31 @@ export function nativeIconFor(item: TabBarItem): IconProp {
|
|
|
130
165
|
};
|
|
131
166
|
}
|
|
132
167
|
|
|
168
|
+
/** The accessory's content inside the system capsule: one centred row. */
|
|
169
|
+
function NativeAccessoryContent({ children }: { children: ReactNode }) {
|
|
170
|
+
return (
|
|
171
|
+
<XStack
|
|
172
|
+
flex={1}
|
|
173
|
+
alignItems="center"
|
|
174
|
+
justifyContent="center"
|
|
175
|
+
paddingHorizontal="$3"
|
|
176
|
+
data-testid="native-tab-accessory"
|
|
177
|
+
>
|
|
178
|
+
{children}
|
|
179
|
+
</XStack>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
133
183
|
export function NativeTabHost({
|
|
134
184
|
tabs,
|
|
135
185
|
items,
|
|
136
186
|
activeKey,
|
|
137
187
|
onTabPress,
|
|
138
188
|
children,
|
|
139
|
-
|
|
189
|
+
hostsAccessory = false,
|
|
190
|
+
}: TabHostProps & { tabs: NativeTabs; hostsAccessory?: boolean }) {
|
|
140
191
|
const { Host, Screen } = tabs;
|
|
141
|
-
const accent =
|
|
192
|
+
const accent = useActiveTabInk();
|
|
142
193
|
const ink = useGlyphColor(tabBarInactiveInk);
|
|
143
194
|
const surface = useGlyphColor("$color2");
|
|
144
195
|
const indicator = useAccentTintedSurface();
|
|
@@ -147,11 +198,28 @@ export function NativeTabHost({
|
|
|
147
198
|
const lastKey = useRef(activeKey ?? items[0]?.key);
|
|
148
199
|
if (activeKey) lastKey.current = activeKey;
|
|
149
200
|
const focusedKey = lastKey.current;
|
|
201
|
+
const hosting = hostsAccessory && Boolean(activeKey);
|
|
202
|
+
const pageAccessory = useBottomAccessory();
|
|
203
|
+
const accessory = hosting ? pageAccessory : null;
|
|
150
204
|
|
|
151
205
|
useEffect(() => {
|
|
152
|
-
setBottomChromeInset(
|
|
153
|
-
|
|
154
|
-
|
|
206
|
+
setBottomChromeInset(
|
|
207
|
+
id,
|
|
208
|
+
activeKey
|
|
209
|
+
? nativeTabBarHeight + deviceInset + (accessory ? nativeTabsAccessoryHeight : 0)
|
|
210
|
+
: null,
|
|
211
|
+
);
|
|
212
|
+
}, [activeKey, accessory, deviceInset, id]);
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
setFloatingBarMounted(id, hosting);
|
|
215
|
+
}, [hosting, id]);
|
|
216
|
+
useEffect(
|
|
217
|
+
() => () => {
|
|
218
|
+
setBottomChromeInset(id, null);
|
|
219
|
+
setFloatingBarMounted(id, false);
|
|
220
|
+
},
|
|
221
|
+
[id],
|
|
222
|
+
);
|
|
155
223
|
|
|
156
224
|
return (
|
|
157
225
|
<Host
|
|
@@ -164,6 +232,9 @@ export function NativeTabHost({
|
|
|
164
232
|
tabBarBackgroundColor={surface}
|
|
165
233
|
tabBarItemActiveIndicatorColor={indicator}
|
|
166
234
|
experimentalControlNavigationStateInJS
|
|
235
|
+
bottomAccessory={
|
|
236
|
+
accessory ? () => <NativeAccessoryContent>{accessory}</NativeAccessoryContent> : undefined
|
|
237
|
+
}
|
|
167
238
|
onNativeFocusChange={(event) => {
|
|
168
239
|
const key = event.nativeEvent.tabKey;
|
|
169
240
|
if (key !== activeKey) onTabPress(key);
|
|
@@ -199,5 +270,5 @@ export function NativeTabHost({
|
|
|
199
270
|
export function TabHost(props: TabHostProps) {
|
|
200
271
|
const tabs = loadNativeTabs();
|
|
201
272
|
if (!tabs || !itemsHaveNativeIcons(props.items, Platform.OS)) return <MpoTabHost {...props} />;
|
|
202
|
-
return <NativeTabHost tabs={tabs} {...props} />;
|
|
273
|
+
return <NativeTabHost tabs={tabs} hostsAccessory={loadNativeAccessory()} {...props} />;
|
|
203
274
|
}
|