@sovereignfs/ui 0.45.0 → 0.83.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/Accordion.module.css +1 -1
- package/dist/Alert.module.css +1 -1
- package/dist/AppsLauncher.module.css +96 -0
- package/dist/Avatar.module.css +1 -1
- package/dist/Badge.module.css +30 -7
- package/dist/BalanceChip.module.css +1 -1
- package/dist/Button.module.css +18 -2
- package/dist/Card.module.css +1 -1
- package/dist/CardTile.module.css +181 -0
- package/dist/CodeTextarea.module.css +1 -1
- package/dist/Collapsible.module.css +1 -1
- package/dist/ColorPicker.module.css +132 -0
- package/dist/Combobox.module.css +2 -2
- package/dist/Command.module.css +1 -1
- package/dist/ConfirmDialog.module.css +2 -2
- package/dist/ConsentPrompt.module.css +21 -0
- package/dist/DatePicker.module.css +1 -1
- package/dist/Dialog.module.css +130 -21
- package/dist/Drawer.module.css +36 -7
- package/dist/Header.module.css +62 -0
- package/dist/HeaderFooterLayout.module.css +21 -0
- package/dist/IconPicker.module.css +1 -1
- package/dist/Input.module.css +1 -1
- package/dist/Kbd.module.css +1 -1
- package/dist/LegalLinks.module.css +24 -0
- package/dist/Markdown.module.css +73 -0
- package/dist/Menu.module.css +1 -0
- package/dist/Message.module.css +1 -1
- package/dist/MessageScroller.module.css +12 -1
- package/dist/MobileAppsDrawer.module.css +82 -0
- package/dist/MobileFooter.module.css +73 -0
- package/dist/MobileHeader.module.css +76 -0
- package/dist/NavList.module.css +130 -0
- package/dist/NavTabs.module.css +1 -1
- package/dist/NotificationsPanel.module.css +258 -0
- package/dist/OverlayHeader.module.css +1 -1
- package/dist/PageContainer.module.css +82 -0
- package/dist/PageHeader.module.css +54 -0
- package/dist/PageLayout.module.css +51 -0
- package/dist/Popover.module.css +1 -1
- package/dist/QuantityStepper.module.css +1 -1
- package/dist/Resizable.module.css +3 -3
- package/dist/RootLayout.module.css +12 -0
- package/dist/SegmentedControl.module.css +1 -1
- package/dist/Select.module.css +1 -1
- package/dist/Sheet.module.css +4 -1
- package/dist/SplitPane.module.css +4 -4
- package/dist/StatusBadge.module.css +1 -1
- package/dist/StepStrip.module.css +53 -0
- package/dist/SuggestionInput.module.css +2 -2
- package/dist/SwipableMobileCarousel.module.css +64 -0
- package/dist/SwipableMobileCarouselDots.module.css +64 -0
- package/dist/SwipableMobileCarouselSlideParts.module.css +29 -0
- package/dist/SwipeStack.module.css +101 -0
- package/dist/SystemBanner.module.css +10 -0
- package/dist/Table.module.css +2 -2
- package/dist/Tabs.module.css +1 -1
- package/dist/TagInput.module.css +2 -2
- package/dist/Textarea.module.css +9 -1
- package/dist/ThreeColumnLayout.module.css +35 -0
- package/dist/Toast.module.css +62 -3
- package/dist/Tooltip.module.css +1 -1
- package/dist/UserMenu.module.css +90 -0
- package/dist/index.d.ts +1680 -30
- package/dist/index.js +4618 -1443
- package/dist/tokens/primitives.css +36 -0
- package/dist/tokens/semantic.css +32 -0
- package/dist/tokens/theme-presets.css +33 -0
- package/package.json +32 -12
- package/src/__tests__/package-json.test.ts +8 -0
- package/src/components/Accordion/Accordion.module.css +1 -1
- package/src/components/Alert/Alert.module.css +1 -1
- package/src/components/AppsLauncher/AppsLauncher.module.css +96 -0
- package/src/components/AppsLauncher/AppsLauncher.stories.tsx +58 -0
- package/src/components/AppsLauncher/AppsLauncher.tsx +117 -0
- package/src/components/AppsLauncher/__tests__/AppsLauncher.test.tsx +52 -0
- package/src/components/Avatar/Avatar.module.css +1 -1
- package/src/components/Badge/Badge.module.css +30 -7
- package/src/components/Badge/Badge.stories.tsx +16 -4
- package/src/components/Badge/Badge.tsx +8 -11
- package/src/components/Badge/__tests__/Badge.test.tsx +4 -2
- package/src/components/BalanceChip/BalanceChip.module.css +1 -1
- package/src/components/Button/Button.module.css +18 -2
- package/src/components/Card/Card.module.css +1 -1
- package/src/components/CardTile/CardTile.module.css +181 -0
- package/src/components/CardTile/CardTile.stories.tsx +86 -0
- package/src/components/CardTile/CardTile.tsx +128 -0
- package/src/components/CardTile/__tests__/CardTile.test.tsx +56 -0
- package/src/components/CodeTextarea/CodeTextarea.module.css +1 -1
- package/src/components/Collapsible/Collapsible.module.css +1 -1
- package/src/components/ColorPicker/ColorPicker.module.css +132 -0
- package/src/components/ColorPicker/ColorPicker.stories.tsx +80 -0
- package/src/components/ColorPicker/ColorPicker.tsx +157 -0
- package/src/components/ColorPicker/__tests__/ColorPicker.test.tsx +117 -0
- package/src/components/Combobox/Combobox.module.css +2 -2
- package/src/components/Command/Command.module.css +1 -1
- package/src/components/ConfirmDialog/ConfirmDialog.module.css +2 -2
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +28 -2
- package/src/components/ConfirmDialog/__tests__/ConfirmDialog.test.tsx +71 -3
- package/src/components/ConsentPrompt/ConsentPrompt.module.css +21 -0
- package/src/components/ConsentPrompt/ConsentPrompt.stories.tsx +31 -0
- package/src/components/ConsentPrompt/ConsentPrompt.tsx +66 -0
- package/src/components/ContextMenu/ContextMenu.tsx +1 -1
- package/src/components/DatePicker/DatePicker.module.css +1 -1
- package/src/components/DeviceOnlyGate/DeviceOnlyGate.tsx +58 -0
- package/src/components/DeviceOnlyGate/__tests__/DeviceOnlyGate.test.tsx +45 -0
- package/src/components/DeviceStorageKeyGate/DeviceStorageKeyGate.tsx +100 -0
- package/src/components/DeviceStorageKeyGate/__tests__/DeviceStorageKeyGate.test.tsx +119 -0
- package/src/components/Dialog/Dialog.module.css +130 -21
- package/src/components/Dialog/Dialog.stories.tsx +179 -2
- package/src/components/Dialog/Dialog.tsx +137 -94
- package/src/components/Dialog/__tests__/Dialog.test.tsx +190 -9
- package/src/components/DragHandleRow/DragHandleRow.tsx +2 -21
- package/src/components/Drawer/Drawer.module.css +36 -7
- package/src/components/Drawer/Drawer.stories.tsx +44 -0
- package/src/components/Drawer/Drawer.tsx +27 -66
- package/src/components/Drawer/__tests__/Drawer.test.tsx +55 -6
- package/src/components/GripIcon/GripIcon.tsx +27 -0
- package/src/components/Header/Header.module.css +62 -0
- package/src/components/Header/Header.stories.tsx +452 -0
- package/src/components/Header/Header.tsx +102 -0
- package/src/components/Header/__tests__/Header.test.tsx +104 -0
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.module.css +21 -0
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.stories.tsx +111 -0
- package/src/components/HeaderFooterLayout/HeaderFooterLayout.tsx +54 -0
- package/src/components/HeaderFooterLayout/__tests__/HeaderFooterLayout.test.tsx +58 -0
- package/src/components/Icon/icons/arrow-left-right.tsx +23 -0
- package/src/components/Icon/icons/bold.tsx +20 -0
- package/src/components/Icon/icons/calendar.tsx +4 -4
- package/src/components/Icon/icons/carrot.tsx +3 -3
- package/src/components/Icon/icons/circle-chevron-left.tsx +21 -0
- package/src/components/Icon/icons/code.tsx +21 -0
- package/src/components/Icon/icons/copy.tsx +21 -0
- package/src/components/Icon/icons/credit-card.tsx +21 -0
- package/src/components/Icon/icons/database.tsx +22 -0
- package/src/components/Icon/icons/download.tsx +22 -0
- package/src/components/Icon/icons/file-text.tsx +24 -0
- package/src/components/Icon/icons/folder-closed.tsx +21 -0
- package/src/components/Icon/icons/folder-open.tsx +20 -0
- package/src/components/Icon/icons/folder.tsx +20 -0
- package/src/components/Icon/icons/folders.tsx +21 -0
- package/src/components/Icon/icons/hat-glasses.tsx +24 -0
- package/src/components/Icon/icons/history.tsx +22 -0
- package/src/components/Icon/icons/inbox.tsx +21 -0
- package/src/components/Icon/icons/index.ts +169 -1
- package/src/components/Icon/icons/italic.tsx +22 -0
- package/src/components/Icon/icons/layers.tsx +22 -0
- package/src/components/Icon/icons/layout-dashboard.tsx +23 -0
- package/src/components/Icon/icons/layout-grid.tsx +23 -0
- package/src/components/Icon/icons/link.tsx +21 -0
- package/src/components/Icon/icons/list-ordered.tsx +25 -0
- package/src/components/Icon/icons/list.tsx +25 -0
- package/src/components/Icon/icons/luggage.tsx +24 -0
- package/src/components/Icon/icons/map-pin.tsx +21 -0
- package/src/components/Icon/icons/menu.tsx +22 -0
- package/src/components/Icon/icons/minus.tsx +20 -0
- package/src/components/Icon/icons/paint-bucket.tsx +23 -0
- package/src/components/Icon/icons/panel-left.tsx +21 -0
- package/src/components/Icon/icons/pin.tsx +21 -0
- package/src/components/Icon/icons/rectangle-ellipsis.tsx +23 -0
- package/src/components/Icon/icons/refresh-cw.tsx +23 -0
- package/src/components/Icon/icons/rotate-cw.tsx +21 -0
- package/src/components/Icon/icons/route.tsx +22 -0
- package/src/components/Icon/icons/send.tsx +21 -0
- package/src/components/Icon/icons/share-2.tsx +24 -0
- package/src/components/Icon/icons/sheet.tsx +24 -0
- package/src/components/Icon/icons/smartphone.tsx +21 -0
- package/src/components/Icon/icons/square-kanban.tsx +23 -0
- package/src/components/Icon/icons/table.tsx +23 -0
- package/src/components/Icon/icons/user-round-plus.tsx +23 -0
- package/src/components/Icon/icons/users.tsx +23 -0
- package/src/components/IconPicker/IconPicker.module.css +1 -1
- package/src/components/Input/Input.module.css +1 -1
- package/src/components/Input/Input.tsx +8 -2
- package/src/components/Kbd/Kbd.module.css +1 -1
- package/src/components/LegalLinks/LegalLinks.module.css +24 -0
- package/src/components/LegalLinks/LegalLinks.stories.tsx +22 -0
- package/src/components/LegalLinks/LegalLinks.tsx +40 -0
- package/src/components/Markdown/Markdown.module.css +73 -0
- package/src/components/Markdown/Markdown.stories.tsx +40 -0
- package/src/components/Markdown/Markdown.tsx +305 -0
- package/src/components/Markdown/__tests__/Markdown.test.tsx +144 -0
- package/src/components/Menu/Menu.module.css +1 -0
- package/src/components/Menu/Menu.tsx +72 -22
- package/src/components/Menu/__tests__/Menu.test.tsx +30 -0
- package/src/components/Menubar/Menubar.tsx +1 -1
- package/src/components/Message/Message.module.css +1 -1
- package/src/components/MessageScroller/MessageScroller.module.css +12 -1
- package/src/components/MessageScroller/MessageScroller.tsx +12 -0
- package/src/components/MobileAppsDrawer/MobileAppsDrawer.module.css +82 -0
- package/src/components/MobileAppsDrawer/MobileAppsDrawer.tsx +78 -0
- package/src/components/MobileAppsDrawer/__tests__/MobileAppsDrawer.test.tsx +80 -0
- package/src/components/MobileFooter/MobileFooter.module.css +73 -0
- package/src/components/MobileFooter/MobileFooter.stories.tsx +47 -0
- package/src/components/MobileFooter/MobileFooter.tsx +122 -0
- package/src/components/MobileFooter/__tests__/MobileFooter.test.tsx +129 -0
- package/src/components/MobileHeader/MobileHeader.module.css +76 -0
- package/src/components/MobileHeader/MobileHeader.stories.tsx +57 -0
- package/src/components/MobileHeader/MobileHeader.tsx +90 -0
- package/src/components/MobileHeader/__tests__/MobileHeader.test.tsx +113 -0
- package/src/components/NavList/NavList.module.css +130 -0
- package/src/components/NavList/NavList.tsx +136 -0
- package/src/components/NavList/__tests__/NavList.test.tsx +109 -0
- package/src/components/NavTabs/NavTabs.module.css +1 -1
- package/src/components/NavTabs/NavTabs.tsx +39 -11
- package/src/components/NotificationsPanel/NotificationsPanel.module.css +258 -0
- package/src/components/NotificationsPanel/NotificationsPanel.stories.tsx +61 -0
- package/src/components/NotificationsPanel/NotificationsPanel.tsx +187 -0
- package/src/components/NotificationsPanel/__tests__/NotificationsPanel.test.tsx +78 -0
- package/src/components/OfflineGate/OfflineGate.tsx +44 -0
- package/src/components/OfflineGate/__tests__/OfflineGate.test.tsx +66 -0
- package/src/components/OverlayHeader/OverlayHeader.module.css +1 -1
- package/src/components/OverlayHeader/OverlayHeader.tsx +19 -4
- package/src/components/OverlayHeader/__tests__/OverlayHeader.test.tsx +18 -0
- package/src/components/PageContainer/PageContainer.module.css +82 -0
- package/src/components/PageContainer/PageContainer.tsx +64 -0
- package/src/components/PageContainer/__tests__/PageContainer.test.tsx +70 -0
- package/src/components/PageHeader/PageHeader.module.css +54 -0
- package/src/components/PageHeader/PageHeader.tsx +157 -2
- package/src/components/PageHeader/__tests__/PageHeader.test.tsx +103 -0
- package/src/components/PageLayout/PageLayout.module.css +51 -0
- package/src/components/PageLayout/PageLayout.stories.tsx +73 -0
- package/src/components/PageLayout/PageLayout.tsx +51 -0
- package/src/components/PageLayout/__tests__/PageLayout.test.tsx +34 -0
- package/src/components/Popover/Popover.module.css +1 -1
- package/src/components/Popover/Popover.tsx +86 -4
- package/src/components/Popover/__tests__/Popover.test.tsx +165 -0
- package/src/components/QuantityStepper/QuantityStepper.module.css +1 -1
- package/src/components/Resizable/Resizable.module.css +3 -3
- package/src/components/ResponsiveSurface/ResponsiveSurface.tsx +24 -0
- package/src/components/ResponsiveSurface/__tests__/ResponsiveSurface.test.tsx +73 -0
- package/src/components/RootLayout/RootLayout.module.css +12 -0
- package/src/components/RootLayout/RootLayout.stories.tsx +125 -0
- package/src/components/RootLayout/RootLayout.tsx +185 -0
- package/src/components/RootLayout/__tests__/RootLayout.test.tsx +161 -0
- package/src/components/SegmentedControl/SegmentedControl.module.css +1 -1
- package/src/components/Select/Select.module.css +1 -1
- package/src/components/Sheet/Sheet.module.css +4 -1
- package/src/components/Sheet/Sheet.tsx +14 -56
- package/src/components/SplitPane/SplitPane.module.css +4 -4
- package/src/components/StatusBadge/StatusBadge.module.css +1 -1
- package/src/components/StepStrip/StepStrip.module.css +53 -0
- package/src/components/StepStrip/StepStrip.tsx +74 -0
- package/src/components/SuggestionInput/SuggestionInput.module.css +2 -2
- package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.module.css +64 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarousel.tsx +243 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlide.tsx +35 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideBody.tsx +42 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideFooter.tsx +18 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideHeader.tsx +21 -0
- package/src/components/SwipableMobileCarousel/SwipableMobileCarouselSlideParts.module.css +29 -0
- package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarousel.test.tsx +214 -0
- package/src/components/SwipableMobileCarousel/__tests__/SwipableMobileCarouselDevGuard.test.tsx +61 -0
- package/src/components/SwipableMobileCarousel/context.ts +13 -0
- package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.module.css +64 -0
- package/src/components/SwipableMobileCarouselDots/SwipableMobileCarouselDots.tsx +73 -0
- package/src/components/SwipableMobileCarouselDots/__tests__/SwipableMobileCarouselDots.test.tsx +63 -0
- package/src/components/SwipeStack/SwipeStack.module.css +101 -0
- package/src/components/SwipeStack/SwipeStack.tsx +199 -0
- package/src/components/SwipeStack/SwipeStackCard.tsx +22 -0
- package/src/components/SwipeStack/__tests__/SwipeStack.test.tsx +169 -0
- package/src/components/SystemBanner/SystemBanner.module.css +10 -0
- package/src/components/Table/Table.module.css +2 -2
- package/src/components/Tabs/Tabs.module.css +1 -1
- package/src/components/TagInput/TagInput.module.css +2 -2
- package/src/components/Textarea/Textarea.module.css +9 -1
- package/src/components/Textarea/Textarea.tsx +28 -5
- package/src/components/Textarea/__tests__/Textarea.test.tsx +23 -1
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.module.css +35 -0
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.stories.tsx +152 -0
- package/src/components/ThreeColumnLayout/ThreeColumnLayout.tsx +87 -0
- package/src/components/ThreeColumnLayout/__tests__/ThreeColumnLayout.test.tsx +78 -0
- package/src/components/Toast/Toast.module.css +62 -3
- package/src/components/Toast/Toast.stories.tsx +1 -1
- package/src/components/Tooltip/Tooltip.module.css +1 -1
- package/src/components/UserMenu/UserMenu.module.css +90 -0
- package/src/components/UserMenu/UserMenu.stories.tsx +49 -0
- package/src/components/UserMenu/UserMenu.tsx +132 -0
- package/src/components/UserMenu/__tests__/UserMenu.test.tsx +77 -0
- package/src/hooks/__tests__/useCarouselRouteSync.test.tsx +126 -0
- package/src/hooks/__tests__/useIsOffline.test.tsx +53 -0
- package/src/hooks/__tests__/useOfflineTileState.test.tsx +69 -0
- package/src/hooks/__tests__/usePublishShellChromeHeight.test.tsx +118 -0
- package/src/hooks/__tests__/useReorderSensors.test.ts +26 -0
- package/src/hooks/__tests__/useResponsiveLayout.test.tsx +87 -0
- package/src/hooks/__tests__/useSnapCarousel.test.tsx +175 -0
- package/src/hooks/__tests__/useSwipeReveal.test.tsx +110 -0
- package/src/hooks/__tests__/useSwipeStack.test.tsx +155 -0
- package/src/hooks/index.ts +27 -0
- package/src/hooks/useCarouselRouteSync.ts +92 -0
- package/src/hooks/useIsOffline.ts +41 -0
- package/src/hooks/useOfflineTileState.ts +45 -0
- package/src/hooks/usePublishShellChromeHeight.ts +96 -0
- package/src/hooks/useReorderSensors.ts +88 -0
- package/src/hooks/useResponsiveLayout.ts +36 -0
- package/src/hooks/useSnapCarousel.ts +284 -0
- package/src/hooks/useSwipeReveal.ts +107 -0
- package/src/hooks/useSwipeStack.ts +235 -0
- package/src/index.ts +124 -3
- package/src/overlay-shell.ts +159 -0
- package/src/stories/DesignSystemOverview.stories.tsx +933 -6
- package/src/stories/DeviceOnlyGate.stories.tsx +35 -0
- package/src/stories/DeviceStorageKeyGate.stories.tsx +57 -0
- package/src/stories/GripIcon.stories.tsx +29 -0
- package/src/stories/InteractionHooks.stories.tsx +483 -0
- package/src/stories/LayoutSystem.stories.tsx +639 -0
- package/src/stories/MenuEntries.stories.tsx +86 -0
- package/src/stories/MobilePatterns.stories.tsx +247 -2
- package/src/stories/NavList.stories.tsx +147 -0
- package/src/stories/NavTabs.stories.tsx +18 -0
- package/src/stories/OfflineGate.stories.tsx +42 -0
- package/src/stories/PageContainer.stories.tsx +82 -0
- package/src/stories/PageHeader.stories.tsx +65 -1
- package/src/stories/ResponsiveSurface.stories.tsx +47 -0
- package/src/stories/StepStrip.stories.tsx +76 -0
- package/src/stories/SwipableMobileCarousel.stories.tsx +362 -0
- package/src/stories/SwipeStack.stories.tsx +200 -0
- package/src/stories/Textarea.stories.tsx +12 -0
- package/src/stories/TokenGallery.stories.tsx +115 -0
- package/src/tokens/primitives.css +36 -0
- package/src/tokens/semantic.css +32 -0
- package/src/tokens/theme-presets.css +33 -0
- package/src/tokens/theme-presets.ts +72 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { cleanup, render, screen } from '@testing-library/react';
|
|
4
|
+
import { RootLayout } from '../RootLayout';
|
|
5
|
+
|
|
6
|
+
let matches = false;
|
|
7
|
+
|
|
8
|
+
function installMatchMedia() {
|
|
9
|
+
vi.stubGlobal(
|
|
10
|
+
'matchMedia',
|
|
11
|
+
vi.fn().mockImplementation((query: string) => ({
|
|
12
|
+
matches,
|
|
13
|
+
media: query,
|
|
14
|
+
addEventListener: vi.fn(),
|
|
15
|
+
removeEventListener: vi.fn(),
|
|
16
|
+
addListener: vi.fn(),
|
|
17
|
+
removeListener: vi.fn(),
|
|
18
|
+
dispatchEvent: vi.fn(),
|
|
19
|
+
})),
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('RootLayout', () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
matches = false;
|
|
26
|
+
installMatchMedia();
|
|
27
|
+
});
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
vi.unstubAllGlobals();
|
|
30
|
+
cleanup();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('plain: renders the single child on web and mobile', () => {
|
|
34
|
+
render(
|
|
35
|
+
<RootLayout variant="plain">
|
|
36
|
+
<span>Main</span>
|
|
37
|
+
</RootLayout>,
|
|
38
|
+
);
|
|
39
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
40
|
+
cleanup();
|
|
41
|
+
|
|
42
|
+
matches = true;
|
|
43
|
+
installMatchMedia();
|
|
44
|
+
render(
|
|
45
|
+
<RootLayout variant="plain">
|
|
46
|
+
<span>Main</span>
|
|
47
|
+
</RootLayout>,
|
|
48
|
+
);
|
|
49
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('sidebar: renders sidebar + main on web, main only on mobile', () => {
|
|
53
|
+
render(
|
|
54
|
+
<RootLayout variant="sidebar">
|
|
55
|
+
<nav>Sidebar</nav>
|
|
56
|
+
<main>Main</main>
|
|
57
|
+
</RootLayout>,
|
|
58
|
+
);
|
|
59
|
+
expect(screen.getByText('Sidebar')).toBeDefined();
|
|
60
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
61
|
+
cleanup();
|
|
62
|
+
|
|
63
|
+
matches = true;
|
|
64
|
+
installMatchMedia();
|
|
65
|
+
render(
|
|
66
|
+
<RootLayout variant="sidebar">
|
|
67
|
+
<nav>Sidebar</nav>
|
|
68
|
+
<main>Main</main>
|
|
69
|
+
</RootLayout>,
|
|
70
|
+
);
|
|
71
|
+
expect(screen.queryByText('Sidebar')).toBeNull();
|
|
72
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('header: renders header + main identically on web and mobile', () => {
|
|
76
|
+
render(
|
|
77
|
+
<RootLayout variant="header">
|
|
78
|
+
<header>Header</header>
|
|
79
|
+
<main>Main</main>
|
|
80
|
+
</RootLayout>,
|
|
81
|
+
);
|
|
82
|
+
expect(screen.getByText('Header')).toBeDefined();
|
|
83
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
84
|
+
cleanup();
|
|
85
|
+
|
|
86
|
+
matches = true;
|
|
87
|
+
installMatchMedia();
|
|
88
|
+
render(
|
|
89
|
+
<RootLayout variant="header">
|
|
90
|
+
<header>Header</header>
|
|
91
|
+
<main>Main</main>
|
|
92
|
+
</RootLayout>,
|
|
93
|
+
);
|
|
94
|
+
expect(screen.getByText('Header')).toBeDefined();
|
|
95
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('header: applies headerHeight on web and mobileHeaderHeight on mobile', () => {
|
|
99
|
+
render(
|
|
100
|
+
<RootLayout variant="header">
|
|
101
|
+
<header>Header</header>
|
|
102
|
+
<main>Main</main>
|
|
103
|
+
</RootLayout>,
|
|
104
|
+
);
|
|
105
|
+
expect(screen.getByText('Header').parentElement?.style.height).toBe('48px');
|
|
106
|
+
cleanup();
|
|
107
|
+
|
|
108
|
+
matches = true;
|
|
109
|
+
installMatchMedia();
|
|
110
|
+
render(
|
|
111
|
+
<RootLayout variant="header">
|
|
112
|
+
<header>Header</header>
|
|
113
|
+
<main>Main</main>
|
|
114
|
+
</RootLayout>,
|
|
115
|
+
);
|
|
116
|
+
expect(screen.getByText('Header').parentElement?.style.height).toBe('60px');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('shell: renders main only on web, header + main + footer on mobile', () => {
|
|
120
|
+
render(
|
|
121
|
+
<RootLayout variant="shell">
|
|
122
|
+
<header>Header</header>
|
|
123
|
+
<main>Main</main>
|
|
124
|
+
<footer>Footer</footer>
|
|
125
|
+
</RootLayout>,
|
|
126
|
+
);
|
|
127
|
+
expect(screen.queryByText('Header')).toBeNull();
|
|
128
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
129
|
+
expect(screen.queryByText('Footer')).toBeNull();
|
|
130
|
+
cleanup();
|
|
131
|
+
|
|
132
|
+
matches = true;
|
|
133
|
+
installMatchMedia();
|
|
134
|
+
render(
|
|
135
|
+
<RootLayout variant="shell">
|
|
136
|
+
<header>Header</header>
|
|
137
|
+
<main>Main</main>
|
|
138
|
+
<footer>Footer</footer>
|
|
139
|
+
</RootLayout>,
|
|
140
|
+
);
|
|
141
|
+
expect(screen.getByText('Header')).toBeDefined();
|
|
142
|
+
expect(screen.getByText('Main')).toBeDefined();
|
|
143
|
+
expect(screen.getByText('Footer')).toBeDefined();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('warns in development when the child count does not match the variant', () => {
|
|
147
|
+
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
|
|
148
|
+
|
|
149
|
+
render(
|
|
150
|
+
<RootLayout variant="sidebar">
|
|
151
|
+
<span>Only one child</span>
|
|
152
|
+
</RootLayout>,
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining('variant="sidebar"'));
|
|
156
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining('expects 2'));
|
|
157
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining('received 1'));
|
|
158
|
+
|
|
159
|
+
warn.mockRestore();
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
line-height: 1.5;
|
|
19
19
|
color: var(--sv-color-text-primary);
|
|
20
20
|
background-color: var(--sv-color-surface);
|
|
21
|
-
border:
|
|
21
|
+
border: var(--sv-border-width-hairline) solid var(--sv-color-border-strong);
|
|
22
22
|
border-radius: var(--sv-radius-md);
|
|
23
23
|
cursor: pointer;
|
|
24
24
|
/* Remove native OS chevron */
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/* Sheet — fills the same rect as a plugin's content area (between the shell's
|
|
2
2
|
* sticky header and footer nav — see --sv-shell-header-height /
|
|
3
|
-
* --sv-shell-footer-height, set by the shell
|
|
3
|
+
* --sv-shell-footer-height, set by the platform shell or, for a plugin that
|
|
4
|
+
* self-renders MobileHeader/MobileFooter instead (shellConfig.mobileHeader/
|
|
5
|
+
* mobileFooter: false), by that component itself — see
|
|
6
|
+
* usePublishShellChromeHeight), sliding in from an edge
|
|
4
7
|
* instead of Dialog's centered box or Drawer's partial-height sheet-over-
|
|
5
8
|
* scrim. z-index matches Dialog/Drawer's scrim so it layers consistently
|
|
6
9
|
* with any other overlay. No scrim of its own — see the component doc
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import { type ReactNode,
|
|
4
|
-
import { lockBodyScroll, unlockBodyScroll } from '../../scroll-lock';
|
|
3
|
+
import { type ReactNode, useRef } from 'react';
|
|
5
4
|
import { useMountTransition, usePrefersReducedMotion } from '../../motion';
|
|
5
|
+
import {
|
|
6
|
+
OVERLAY_MOTION_DURATION_MS,
|
|
7
|
+
useOverlayFocusCapture,
|
|
8
|
+
useOverlayKeyboardTrap,
|
|
9
|
+
useOverlayScrollLock,
|
|
10
|
+
} from '../../overlay-shell';
|
|
6
11
|
import { OverlayHeader } from '../OverlayHeader/OverlayHeader';
|
|
7
12
|
import styles from './Sheet.module.css';
|
|
8
13
|
|
|
@@ -36,13 +41,6 @@ export interface SheetProps {
|
|
|
36
41
|
children: ReactNode;
|
|
37
42
|
}
|
|
38
43
|
|
|
39
|
-
const FOCUSABLE =
|
|
40
|
-
'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
41
|
-
|
|
42
|
-
// Matches --sv-motion-duration-base (Sheet.module.css) — see Dialog.tsx's
|
|
43
|
-
// identical constant for why this stays a plain JS number.
|
|
44
|
-
const MOTION_DURATION_MS = 250;
|
|
45
|
-
|
|
46
44
|
/**
|
|
47
45
|
* Sheet — a full-page overlay that replaces a plugin's content area between
|
|
48
46
|
* the shell's fixed header and footer (RFC 0013's mobile chrome stays visible
|
|
@@ -71,55 +69,15 @@ export function Sheet({
|
|
|
71
69
|
children,
|
|
72
70
|
}: SheetProps) {
|
|
73
71
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
74
|
-
const previouslyFocused = useRef<HTMLElement | null>(null);
|
|
75
72
|
const reducedMotion = usePrefersReducedMotion();
|
|
76
|
-
const { mounted, phase } = useMountTransition(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
lockBodyScroll();
|
|
81
|
-
return unlockBodyScroll;
|
|
82
|
-
}, [mounted]);
|
|
83
|
-
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
if (!mounted) return;
|
|
86
|
-
previouslyFocused.current = document.activeElement as HTMLElement | null;
|
|
87
|
-
const panel = panelRef.current;
|
|
88
|
-
const first = panel?.querySelector<HTMLElement>(FOCUSABLE);
|
|
89
|
-
(first ?? panel)?.focus();
|
|
90
|
-
return () => previouslyFocused.current?.focus();
|
|
91
|
-
}, [mounted]);
|
|
73
|
+
const { mounted, phase } = useMountTransition(
|
|
74
|
+
open,
|
|
75
|
+
reducedMotion ? 0 : OVERLAY_MOTION_DURATION_MS,
|
|
76
|
+
);
|
|
92
77
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
if (e.key === 'Escape') {
|
|
97
|
-
e.stopPropagation();
|
|
98
|
-
onClose();
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (e.key !== 'Tab') return;
|
|
102
|
-
const panel = panelRef.current;
|
|
103
|
-
if (!panel) return;
|
|
104
|
-
const focusable = [...panel.querySelectorAll<HTMLElement>(FOCUSABLE)];
|
|
105
|
-
const first = focusable[0];
|
|
106
|
-
const last = focusable.at(-1);
|
|
107
|
-
if (!first || !last) {
|
|
108
|
-
e.preventDefault();
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const active = document.activeElement;
|
|
112
|
-
if (e.shiftKey && active === first) {
|
|
113
|
-
e.preventDefault();
|
|
114
|
-
last.focus();
|
|
115
|
-
} else if (!e.shiftKey && active === last) {
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
first.focus();
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
document.addEventListener('keydown', handleKeyDown);
|
|
121
|
-
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
122
|
-
}, [open, onClose]);
|
|
78
|
+
useOverlayScrollLock(mounted);
|
|
79
|
+
useOverlayFocusCapture(panelRef, mounted);
|
|
80
|
+
useOverlayKeyboardTrap(panelRef, open, onClose);
|
|
123
81
|
|
|
124
82
|
if (!mounted) return null;
|
|
125
83
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
minmax(0, calc(100% - var(--split-pane-primary-size, 50%)));
|
|
6
6
|
width: 100%;
|
|
7
7
|
min-height: 320px;
|
|
8
|
-
border:
|
|
8
|
+
border: var(--sv-border-width-hairline) solid var(--sv-color-border);
|
|
9
9
|
border-radius: var(--sv-radius-lg);
|
|
10
10
|
overflow: hidden;
|
|
11
11
|
background: var(--sv-color-surface);
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
.pane + .pane {
|
|
28
|
-
border-left:
|
|
28
|
+
border-left: var(--sv-border-width-hairline) solid var(--sv-color-border);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
.handle {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
min-width: 12px;
|
|
35
35
|
padding: 0;
|
|
36
36
|
border: 0;
|
|
37
|
-
border-inline:
|
|
37
|
+
border-inline: var(--sv-border-width-hairline) solid var(--sv-color-border);
|
|
38
38
|
cursor: col-resize;
|
|
39
39
|
background: var(--sv-color-surface-sunken);
|
|
40
40
|
}
|
|
@@ -79,7 +79,7 @@
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
.pane + .pane {
|
|
82
|
-
border-top:
|
|
82
|
+
border-top: var(--sv-border-width-hairline) solid var(--sv-color-border);
|
|
83
83
|
border-left: 0;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
min-height: 24px;
|
|
6
6
|
gap: var(--sv-space-1);
|
|
7
7
|
padding: 2px var(--sv-space-2);
|
|
8
|
-
border:
|
|
8
|
+
border: var(--sv-border-width-hairline) solid var(--sv-color-border);
|
|
9
9
|
border-radius: var(--sv-radius-full);
|
|
10
10
|
font-family: var(--sv-font-family);
|
|
11
11
|
font-size: var(--sv-font-size-xs);
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
.strip {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: stretch;
|
|
4
|
+
overflow-x: auto;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.step {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
flex-shrink: 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.connector {
|
|
14
|
+
width: var(--sv-space-4);
|
|
15
|
+
height: 2px;
|
|
16
|
+
flex-shrink: 0;
|
|
17
|
+
background: var(--sv-color-border);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.connectorDashed {
|
|
21
|
+
background-image: repeating-linear-gradient(
|
|
22
|
+
to right,
|
|
23
|
+
var(--sv-color-border) 0,
|
|
24
|
+
var(--sv-color-border) 4px,
|
|
25
|
+
transparent 4px,
|
|
26
|
+
transparent 7px
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.addChip {
|
|
31
|
+
all: unset;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
display: flex;
|
|
35
|
+
align-items: center;
|
|
36
|
+
gap: var(--sv-space-1);
|
|
37
|
+
padding: var(--sv-space-3) var(--sv-space-4);
|
|
38
|
+
border: var(--sv-border-width-hairline) dashed var(--sv-color-border);
|
|
39
|
+
border-radius: var(--sv-radius-lg);
|
|
40
|
+
color: var(--sv-color-text-muted);
|
|
41
|
+
font-size: var(--sv-font-size-sm);
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.addChip:hover {
|
|
46
|
+
background: var(--sv-color-surface-sunken);
|
|
47
|
+
color: var(--sv-color-text-primary);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.addChip:focus-visible {
|
|
51
|
+
outline: 2px solid var(--sv-color-focus-ring);
|
|
52
|
+
outline-offset: 2px;
|
|
53
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { Icon } from '../Icon/Icon';
|
|
3
|
+
import styles from './StepStrip.module.css';
|
|
4
|
+
|
|
5
|
+
export interface StepStripItem {
|
|
6
|
+
id: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface StepStripProps<T extends StepStripItem> {
|
|
10
|
+
items: T[];
|
|
11
|
+
activeId: string | null;
|
|
12
|
+
/** Full control over each chip's content, click handling, and (if needed) drag-reorder wiring. */
|
|
13
|
+
renderItem: (item: T, state: { isActive: boolean; index: number }) => ReactNode;
|
|
14
|
+
/** Trailing dashed "add" chip — omit to render the strip with no add affordance. */
|
|
15
|
+
onAdd?: () => void;
|
|
16
|
+
addLabel?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
'aria-label'?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* StepStrip — a horizontal, connected sequence of steps (a route or
|
|
23
|
+
* itinerary strip): ordered chips joined by a thin connector line, with an
|
|
24
|
+
* optional trailing dashed "add" chip. Purely presentational — it owns
|
|
25
|
+
* layout and the connector lines, nothing else.
|
|
26
|
+
*
|
|
27
|
+
* Each chip's content, active styling, and click handling are entirely up
|
|
28
|
+
* to `renderItem`; if a consumer needs drag-reorder, `renderItem` attaches
|
|
29
|
+
* its own dnd-kit `useSortable` ref/listeners to whatever it returns. This
|
|
30
|
+
* mirrors `DragHandleRow`'s existing split (DS owns chrome, consumer wires
|
|
31
|
+
* dnd-kit via passed-through props) generalized for a horizontal,
|
|
32
|
+
* handle-less strip where the whole rendered item — not a separate handle
|
|
33
|
+
* icon — is both the click target and the drag surface.
|
|
34
|
+
*/
|
|
35
|
+
export function StepStrip<T extends StepStripItem>({
|
|
36
|
+
items,
|
|
37
|
+
activeId,
|
|
38
|
+
renderItem,
|
|
39
|
+
onAdd,
|
|
40
|
+
addLabel = 'Add',
|
|
41
|
+
className,
|
|
42
|
+
'aria-label': ariaLabel,
|
|
43
|
+
}: StepStripProps<T>) {
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
className={[styles.strip, className].filter(Boolean).join(' ')}
|
|
47
|
+
role="list"
|
|
48
|
+
aria-label={ariaLabel}
|
|
49
|
+
>
|
|
50
|
+
{items.map((item, index) => (
|
|
51
|
+
<div key={item.id} className={styles.step} role="listitem">
|
|
52
|
+
{renderItem(item, { isActive: item.id === activeId, index })}
|
|
53
|
+
{(index < items.length - 1 || onAdd) && (
|
|
54
|
+
<div
|
|
55
|
+
className={[
|
|
56
|
+
styles.connector,
|
|
57
|
+
index === items.length - 1 ? styles.connectorDashed : '',
|
|
58
|
+
]
|
|
59
|
+
.filter(Boolean)
|
|
60
|
+
.join(' ')}
|
|
61
|
+
aria-hidden="true"
|
|
62
|
+
/>
|
|
63
|
+
)}
|
|
64
|
+
</div>
|
|
65
|
+
))}
|
|
66
|
+
{onAdd && (
|
|
67
|
+
<button type="button" className={styles.addChip} onClick={onAdd}>
|
|
68
|
+
<Icon name="plus" size="sm" aria-hidden={true} />
|
|
69
|
+
{addLabel}
|
|
70
|
+
</button>
|
|
71
|
+
)}
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
line-height: 1.5;
|
|
8
8
|
color: var(--sv-color-text-primary);
|
|
9
9
|
background-color: var(--sv-color-surface);
|
|
10
|
-
border:
|
|
10
|
+
border: var(--sv-border-width-hairline) solid var(--sv-color-border-strong);
|
|
11
11
|
border-radius: var(--sv-radius-md);
|
|
12
12
|
transition:
|
|
13
13
|
border-color 0.15s ease,
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
|
|
100
100
|
.divider {
|
|
101
101
|
margin: var(--sv-space-1) var(--sv-space-2);
|
|
102
|
-
border-top:
|
|
102
|
+
border-top: var(--sv-border-width-hairline) solid var(--sv-color-border);
|
|
103
103
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
.wrap {
|
|
2
|
+
position: relative;
|
|
3
|
+
height: 100%;
|
|
4
|
+
width: 100%;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.scroller {
|
|
8
|
+
height: 100%;
|
|
9
|
+
width: 100%;
|
|
10
|
+
display: flex;
|
|
11
|
+
overflow-x: auto;
|
|
12
|
+
overflow-y: hidden;
|
|
13
|
+
scroll-snap-type: x mandatory;
|
|
14
|
+
/* Momentum + rubber-banding come from the browser's native scroll physics —
|
|
15
|
+
no hand-rolled pointer/touch dragging. Deliberately NOT
|
|
16
|
+
-webkit-overflow-scrolling: touch: that legacy iOS <13 hint promotes its
|
|
17
|
+
element to its own compositing layer for GPU-accelerated momentum
|
|
18
|
+
scroll, and that layer's paint order relative to siblings/fixed
|
|
19
|
+
descendants elsewhere in the tree isn't always reliable on real iOS
|
|
20
|
+
Safari (confirmed via sovereign-tasks' and sovereign-shopper's own
|
|
21
|
+
carousels, which hit and fixed this exact bug — a position:fixed
|
|
22
|
+
overlay opened above the scroller painted BEHIND it instead of above).
|
|
23
|
+
Removing it doesn't disable momentum scrolling on any iOS version this
|
|
24
|
+
platform realistically targets. */
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.slide {
|
|
28
|
+
flex: 0 0 100%;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
min-width: 0;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
scroll-snap-align: start;
|
|
34
|
+
scroll-snap-stop: always;
|
|
35
|
+
/* Slide content is a flex column so Header/Footer stay their natural size
|
|
36
|
+
and Body (flex: 1 1 auto, min-height: 0) fills and scrolls the rest —
|
|
37
|
+
see SwipableMobileCarouselSlideParts.module.css. */
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-direction: column;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.indicatorSlot {
|
|
43
|
+
/* Overlays the bottom of .wrap rather than taking its own layout row —
|
|
44
|
+
matches both sovereign-tasks' and sovereign-shopper's existing dots
|
|
45
|
+
placement. Applied by the carousel itself around WHATEVER
|
|
46
|
+
renderIndicator returns (the default SwipableMobileCarouselDots or a
|
|
47
|
+
caller-supplied override) — a custom renderIndicator has no way to
|
|
48
|
+
import this module's locally-scoped class itself (CSS Modules classnames
|
|
49
|
+
aren't cross-file importable), so positioning must live here, not be
|
|
50
|
+
something each indicator implementation opts into. Previously this class
|
|
51
|
+
was only ever applied to the *default* indicator branch, which silently
|
|
52
|
+
left any custom renderIndicator unpositioned — a static, in-flow sibling
|
|
53
|
+
pushed below the full-height .scroller and clipped out of view instead
|
|
54
|
+
of overlaid on top of it. */
|
|
55
|
+
position: absolute;
|
|
56
|
+
left: 0;
|
|
57
|
+
right: 0;
|
|
58
|
+
bottom: var(--sv-space-3);
|
|
59
|
+
pointer-events: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.indicatorSlot > * {
|
|
63
|
+
pointer-events: auto;
|
|
64
|
+
}
|