@ankhorage/zora 25.8.11 → 25.8.13
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/CHANGELOG.md +12 -0
- package/README.md +2 -1
- package/dist/features/grid-interactions/adapters/inbound/GridInteractions.d.ts.map +1 -1
- package/dist/features/grid-interactions/adapters/inbound/GridInteractions.js +11 -2
- package/dist/features/grid-interactions/adapters/inbound/GridInteractions.js.map +1 -1
- package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.d.ts.map +1 -1
- package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.js +9 -2
- package/dist/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.js.map +1 -1
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.d.ts +2 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.d.ts.map +1 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.js +2 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.js.map +1 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.native.d.ts +4 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.native.d.ts.map +1 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.native.js +11 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.native.js.map +1 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.web.d.ts +4 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.web.d.ts.map +1 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.web.js +9 -0
- package/dist/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.web.js.map +1 -0
- package/dist/features/grid-interactions/application/createGridInteractionScrollLock.d.ts +5 -0
- package/dist/features/grid-interactions/application/createGridInteractionScrollLock.d.ts.map +1 -0
- package/dist/features/grid-interactions/application/createGridInteractionScrollLock.js +14 -0
- package/dist/features/grid-interactions/application/createGridInteractionScrollLock.js.map +1 -0
- package/dist/features/grid-view/adapters/inbound/GridView.d.ts.map +1 -1
- package/dist/features/grid-view/adapters/inbound/GridView.js +34 -30
- package/dist/features/grid-view/adapters/inbound/GridView.js.map +1 -1
- package/dist/features/grid-view/application/createGridScrollSync.d.ts +7 -0
- package/dist/features/grid-view/application/createGridScrollSync.d.ts.map +1 -0
- package/dist/features/grid-view/application/createGridScrollSync.js +141 -0
- package/dist/features/grid-view/application/createGridScrollSync.js.map +1 -0
- package/dist/features/grid-view/application/resolveScrollEventSource.d.ts +4 -0
- package/dist/features/grid-view/application/resolveScrollEventSource.d.ts.map +1 -0
- package/dist/features/grid-view/application/resolveScrollEventSource.js +8 -0
- package/dist/features/grid-view/application/resolveScrollEventSource.js.map +1 -0
- package/dist/features/grid-view/constants/scroll.d.ts +7 -0
- package/dist/features/grid-view/constants/scroll.d.ts.map +1 -0
- package/dist/features/grid-view/constants/scroll.js +7 -0
- package/dist/features/grid-view/constants/scroll.js.map +1 -0
- package/dist/features/layout/adapters/inbound/ScrollGestureLockContext.d.ts +5 -0
- package/dist/features/layout/adapters/inbound/ScrollGestureLockContext.d.ts.map +1 -0
- package/dist/features/layout/adapters/inbound/ScrollGestureLockContext.js +4 -0
- package/dist/features/layout/adapters/inbound/ScrollGestureLockContext.js.map +1 -0
- package/dist/features/layout/adapters/inbound/ScrollView.d.ts.map +1 -1
- package/dist/features/layout/adapters/inbound/ScrollView.js +11 -3
- package/dist/features/layout/adapters/inbound/ScrollView.js.map +1 -1
- package/dist/features/layout/adapters/inbound/useScrollGestureLock.d.ts +4 -0
- package/dist/features/layout/adapters/inbound/useScrollGestureLock.d.ts.map +1 -0
- package/dist/features/layout/adapters/inbound/useScrollGestureLock.js +8 -0
- package/dist/features/layout/adapters/inbound/useScrollGestureLock.js.map +1 -0
- package/dist/features/layout/public.d.ts +2 -1
- package/dist/features/layout/public.d.ts.map +1 -1
- package/dist/features/layout/public.js +1 -0
- package/dist/features/layout/public.js.map +1 -1
- package/dist/features/layout/utils/createScrollGestureLock.d.ts +4 -0
- package/dist/features/layout/utils/createScrollGestureLock.d.ts.map +1 -0
- package/dist/features/layout/utils/createScrollGestureLock.js +18 -0
- package/dist/features/layout/utils/createScrollGestureLock.js.map +1 -0
- package/dist/types/grid-interactions.d.ts +5 -0
- package/dist/types/grid-interactions.d.ts.map +1 -1
- package/dist/types/grid-interactions.js.map +1 -1
- package/dist/types/grid-view.d.ts +40 -0
- package/dist/types/grid-view.d.ts.map +1 -1
- package/dist/types/grid-view.js.map +1 -1
- package/dist/types/layout.d.ts +5 -0
- package/dist/types/layout.d.ts.map +1 -1
- package/dist/types/layout.js.map +1 -1
- package/package.json +2 -2
- package/src/features/grid-interactions/adapters/inbound/GridInteractions.scrollLock.test.tsx +265 -0
- package/src/features/grid-interactions/adapters/inbound/GridInteractions.test.tsx +70 -1
- package/src/features/grid-interactions/adapters/inbound/GridInteractions.tsx +12 -5
- package/src/features/grid-interactions/adapters/inbound/GridInteractionsKeyboardProxy.web.tsx +10 -1
- package/src/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.native.ts +17 -0
- package/src/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.ts +1 -0
- package/src/features/grid-interactions/adapters/inbound/useGridInteractionScrollLock.web.ts +11 -0
- package/src/features/grid-interactions/application/createGridInteractionScrollLock.test.ts +41 -0
- package/src/features/grid-interactions/application/createGridInteractionScrollLock.ts +18 -0
- package/src/features/grid-view/adapters/inbound/GridView.nativeScrollSync.test.tsx +186 -0
- package/src/features/grid-view/adapters/inbound/GridView.scrollSync.interaction.test.tsx +304 -0
- package/src/features/grid-view/adapters/inbound/GridView.tsx +49 -29
- package/src/features/grid-view/application/createGridScrollSync.test.ts +292 -0
- package/src/features/grid-view/application/createGridScrollSync.ts +169 -0
- package/src/features/grid-view/application/resolveScrollEventSource.test.ts +19 -0
- package/src/features/grid-view/application/resolveScrollEventSource.ts +12 -0
- package/src/features/grid-view/constants/scroll.ts +8 -0
- package/src/features/layout/adapters/inbound/ScrollGestureLockContext.ts +8 -0
- package/src/features/layout/adapters/inbound/ScrollView.test.tsx +234 -0
- package/src/features/layout/adapters/inbound/ScrollView.tsx +18 -2
- package/src/features/layout/adapters/inbound/useScrollGestureLock.ts +11 -0
- package/src/features/layout/public.ts +2 -0
- package/src/features/layout/utils/createScrollGestureLock.test.ts +34 -0
- package/src/features/layout/utils/createScrollGestureLock.ts +21 -0
- package/src/types/grid-interactions.ts +6 -0
- package/src/types/grid-view.ts +45 -0
- package/src/types/layout.ts +6 -0
- package/web-dist/chunks/{Accordion-v3rzy273.js → Accordion-11ej93t5.js} +3 -3
- package/web-dist/chunks/{Accordion-ddrn94v3.js → Accordion-1hbt9k69.js} +1 -1
- package/web-dist/chunks/{Accordion-wpk8dxqp.js → Accordion-26prtnm7.js} +1 -1
- package/web-dist/chunks/{Accordion-0q2wzjdd.js → Accordion-2jy53kzk.js} +2 -2
- package/web-dist/chunks/{Accordion-geah5s4f.js → Accordion-4yq92mxp.js} +1 -1
- package/web-dist/chunks/{Accordion-8pkw32q9.js → Accordion-5pr1wqe3.js} +1 -1
- package/web-dist/chunks/{Accordion-y3083394.js → Accordion-799z2zf6.js} +1 -1
- package/web-dist/chunks/{Accordion-hecpczme.js → Accordion-9aczb0k2.js} +2 -2
- package/web-dist/chunks/{Accordion-rctfgyfv.js → Accordion-a4pz3vjj.js} +1 -1
- package/web-dist/chunks/{Accordion-9jrxktne.js → Accordion-b337t2df.js} +1 -1
- package/web-dist/chunks/{Accordion-h4ekm5cp.js → Accordion-czcaf5x2.js} +1 -1
- package/web-dist/chunks/{Accordion-vbzjq3z8.js → Accordion-ep35792s.js} +44 -2
- package/web-dist/chunks/{Accordion-ts788t7b.js → Accordion-g08740h4.js} +1 -1
- package/web-dist/chunks/{Accordion-9ygakvwk.js → Accordion-g2aqhct0.js} +4 -4
- package/web-dist/chunks/{Accordion-p1ebrt17.js → Accordion-gn8ptzwb.js} +1 -1
- package/web-dist/chunks/{Accordion-sq7ya2ye.js → Accordion-h9brgsk8.js} +1 -1
- package/web-dist/chunks/{Accordion-ztw7zp6v.js → Accordion-m2hcc8g4.js} +2 -2
- package/web-dist/chunks/{Accordion-sdnzqktc.js → Accordion-m6mp8aea.js} +3 -3
- package/web-dist/chunks/{Accordion-vxg5sw01.js → Accordion-p7d5svfq.js} +1 -1
- package/web-dist/chunks/{Accordion-k9cxpg08.js → Accordion-rqhh2m5b.js} +3 -3
- package/web-dist/chunks/{Accordion-wcmrasqx.js → Accordion-rqr10gn4.js} +4 -4
- package/web-dist/chunks/{Accordion-hn43wt45.js → Accordion-t0k1cjca.js} +181 -29
- package/web-dist/chunks/{Accordion-w59y0jdf.js → Accordion-tyh8jj9d.js} +1 -1
- package/web-dist/chunks/{Accordion-dk0dtyc0.js → Accordion-vjcd5kxc.js} +1 -1
- package/web-dist/chunks/{Accordion-t5scffdr.js → Accordion-vkd002gw.js} +5 -5
- package/web-dist/chunks/{Accordion-r87xx7mg.js → Accordion-w87gvpbg.js} +1 -1
- package/web-dist/chunks/{Accordion-yexfbrzg.js → Accordion-wqyrrptg.js} +2 -2
- package/web-dist/chunks/{Accordion-c50pywj3.js → Accordion-y2pss5p0.js} +1 -1
- package/web-dist/components/accordion/Accordion.js +2 -2
- package/web-dist/components/accordion-item/AccordionItem.js +2 -2
- package/web-dist/components/app-bar/AppBar.js +4 -4
- package/web-dist/components/app-header/AppHeader.js +4 -4
- package/web-dist/components/app-shell/AppShell.js +1 -1
- package/web-dist/components/auth-screen/AuthScreen.js +6 -6
- package/web-dist/components/avatar/Avatar.js +2 -2
- package/web-dist/components/avatar-group/AvatarGroup.js +2 -2
- package/web-dist/components/barcode-scanner-view/BarcodeScannerView.js +6 -6
- package/web-dist/components/bottom-sheet/BottomSheet.js +2 -2
- package/web-dist/components/bottom-sheet-flat-list/BottomSheetFlatList.js +2 -2
- package/web-dist/components/bottom-sheet-scroll-view/BottomSheetScrollView.js +2 -2
- package/web-dist/components/bottom-sheet-section-list/BottomSheetSectionList.js +2 -2
- package/web-dist/components/bottom-sheet-view/BottomSheetView.js +2 -2
- package/web-dist/components/bottom-sheet-virtualized-list/BottomSheetVirtualizedList.js +2 -2
- package/web-dist/components/breadcrumbs/Breadcrumbs.js +2 -2
- package/web-dist/components/button/Button.js +2 -2
- package/web-dist/components/button-group/ButtonGroup.js +2 -2
- package/web-dist/components/camera-permission-view/CameraPermissionView.js +6 -6
- package/web-dist/components/card/Card.js +5 -5
- package/web-dist/components/chat-list-item/ChatListItem.js +3 -3
- package/web-dist/components/checkbox/Checkbox.js +2 -2
- package/web-dist/components/checkbox-group/CheckboxGroup.js +2 -2
- package/web-dist/components/chip/Chip.js +2 -2
- package/web-dist/components/chip-group/ChipGroup.js +2 -2
- package/web-dist/components/collection-editor/CollectionEditor.js +5 -5
- package/web-dist/components/content-rail/ContentRail.js +2 -2
- package/web-dist/components/data-table/DataTable.js +10 -10
- package/web-dist/components/date-picker/DatePicker.js +2 -2
- package/web-dist/components/dialog/Dialog.js +2 -2
- package/web-dist/components/divider/Divider.js +1 -1
- package/web-dist/components/empty-state/EmptyState.js +6 -6
- package/web-dist/components/explorer/Explorer.js +4 -4
- package/web-dist/components/field/Field.js +2 -2
- package/web-dist/components/file-explorer/FileExplorer.js +4 -4
- package/web-dist/components/flat-list/FlatList.js +3 -3
- package/web-dist/components/forgot-password-form/ForgotPasswordForm.js +6 -6
- package/web-dist/components/form/Form.js +4 -4
- package/web-dist/components/form-actions/FormActions.js +4 -4
- package/web-dist/components/form-error/FormError.js +4 -4
- package/web-dist/components/game/Game.js +2 -2
- package/web-dist/components/game-entity/GameEntity.js +2 -2
- package/web-dist/components/game-field/GameField.js +2 -2
- package/web-dist/components/game-input-zone/GameInputZone.js +2 -2
- package/web-dist/components/game-measurement-probe/GameMeasurementProbe.js +2 -2
- package/web-dist/components/game-overlay/GameOverlay.js +2 -2
- package/web-dist/components/gradient/Gradient.js +2 -2
- package/web-dist/components/gradient-renderer-provider/GradientRendererProvider.js +2 -2
- package/web-dist/components/grid/Grid.js +1 -1
- package/web-dist/components/grid-interactions/GridInteractions.js +33 -4
- package/web-dist/components/grid-view/GridView.js +1 -1
- package/web-dist/components/hero/Hero.js +5 -5
- package/web-dist/components/icon-button/IconButton.js +2 -2
- package/web-dist/components/image/Image.js +2 -2
- package/web-dist/components/list/List.js +3 -3
- package/web-dist/components/list-item/ListItem.js +3 -3
- package/web-dist/components/list-section/ListSection.js +3 -3
- package/web-dist/components/matrix-grid/MatrixGrid.js +1 -1
- package/web-dist/components/media-card/MediaCard.js +5 -5
- package/web-dist/components/media-explorer/MediaExplorer.js +4 -4
- package/web-dist/components/message-bubble/MessageBubble.js +3 -3
- package/web-dist/components/metric-card/MetricCard.js +5 -5
- package/web-dist/components/missing-element/MissingElement.js +1 -1
- package/web-dist/components/o-auth-provider-button/OAuthProviderButton.js +6 -6
- package/web-dist/components/o-auth-provider-list/OAuthProviderList.js +6 -6
- package/web-dist/components/otp-form/OtpForm.js +6 -6
- package/web-dist/components/pagination/Pagination.js +2 -2
- package/web-dist/components/palette-item/PaletteItem.js +5 -5
- package/web-dist/components/popover-menu/PopoverMenu.js +2 -2
- package/web-dist/components/post-card/PostCard.js +5 -5
- package/web-dist/components/product-card/ProductCard.js +5 -5
- package/web-dist/components/progress/Progress.js +2 -2
- package/web-dist/components/progress-ring/ProgressRing.js +2 -2
- package/web-dist/components/radio/Radio.js +2 -2
- package/web-dist/components/radio-group/RadioGroup.js +2 -2
- package/web-dist/components/rating/Rating.js +1 -1
- package/web-dist/components/reader/Reader.js +6 -6
- package/web-dist/components/scan-overlay/ScanOverlay.js +6 -6
- package/web-dist/components/screen/Screen.js +1 -1
- package/web-dist/components/screen-section/ScreenSection.js +2 -2
- package/web-dist/components/scroll-view/ScrollView.js +1 -1
- package/web-dist/components/search-input/SearchInput.js +3 -3
- package/web-dist/components/section-header/SectionHeader.js +2 -2
- package/web-dist/components/section-list/SectionList.js +3 -3
- package/web-dist/components/select/Select.js +2 -2
- package/web-dist/components/sign-in-form/SignInForm.js +6 -6
- package/web-dist/components/sign-up-form/SignUpForm.js +6 -6
- package/web-dist/components/skeleton/Skeleton.js +8 -8
- package/web-dist/components/skeleton-card/SkeletonCard.js +8 -8
- package/web-dist/components/skeleton-list/SkeletonList.js +8 -8
- package/web-dist/components/skeleton-text/SkeletonText.js +8 -8
- package/web-dist/components/spatial-grid/SpatialGrid.js +1 -1
- package/web-dist/components/text-input/TextInput.js +3 -3
- package/web-dist/components/tile-grid/TileGrid.js +1 -1
- package/web-dist/components/time-grid/TimeGrid.js +1 -1
- package/web-dist/components/time-picker/TimePicker.js +2 -2
- package/web-dist/components/timeline/Timeline.js +1 -1
- package/web-dist/components/toolbar/Toolbar.js +5 -5
- package/web-dist/components/tree-item/TreeItem.js +4 -4
- package/web-dist/components/uploader/Uploader.js +9 -9
- package/web-dist/components/view/View.js +1 -1
- package/web-dist/manifest.json +326 -326
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
// Renders the real ZORA ScrollView through react-native-web in a private happy-dom window.
|
|
2
|
+
// The module mocks below are process-wide in Bun, so this file relies on the repository's
|
|
3
|
+
// `bun test --isolate` script; DOM globals are restored in afterAll.
|
|
4
|
+
import { afterAll, expect, mock, test } from 'bun:test';
|
|
5
|
+
import { Window } from 'happy-dom';
|
|
6
|
+
import React, { act } from 'react';
|
|
7
|
+
import { createRoot } from 'react-dom/client';
|
|
8
|
+
|
|
9
|
+
import type { ScrollGestureLock } from '../../../../types/layout';
|
|
10
|
+
|
|
11
|
+
const browser = new Window();
|
|
12
|
+
const globalKeys = [
|
|
13
|
+
'window',
|
|
14
|
+
'document',
|
|
15
|
+
'Node',
|
|
16
|
+
'navigator',
|
|
17
|
+
'ShadowRoot',
|
|
18
|
+
'IS_REACT_ACT_ENVIRONMENT',
|
|
19
|
+
] as const;
|
|
20
|
+
const previousGlobals = globalKeys.map(
|
|
21
|
+
(key) => [key, Object.getOwnPropertyDescriptor(globalThis, key)] as const,
|
|
22
|
+
);
|
|
23
|
+
Object.assign(globalThis, {
|
|
24
|
+
IS_REACT_ACT_ENVIRONMENT: true,
|
|
25
|
+
Node: browser.Node,
|
|
26
|
+
ShadowRoot: browser.ShadowRoot,
|
|
27
|
+
document: browser.document,
|
|
28
|
+
navigator: browser.navigator,
|
|
29
|
+
window: browser,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const reactNativeWeb = await import('react-native-web');
|
|
33
|
+
await mock.module('react-native', () => reactNativeWeb);
|
|
34
|
+
// ZORA's ScrollView only needs Surface's ScrollView and ThemeScope; the real package would load
|
|
35
|
+
// native-only peers, so the DOM-capable react-native-web ScrollView stands in for the primitive.
|
|
36
|
+
await mock.module('@ankhorage/surface', () => ({
|
|
37
|
+
ScrollView: reactNativeWeb.ScrollView,
|
|
38
|
+
ThemeScope: ({ children }: { readonly children: React.ReactNode }) => children,
|
|
39
|
+
}));
|
|
40
|
+
const { ScrollView } = await import('./ScrollView');
|
|
41
|
+
const { useScrollGestureLock } = await import('./useScrollGestureLock');
|
|
42
|
+
|
|
43
|
+
afterAll(() => {
|
|
44
|
+
browser.close();
|
|
45
|
+
for (const [key, descriptor] of previousGlobals) {
|
|
46
|
+
if (descriptor) Object.defineProperty(globalThis, key, descriptor);
|
|
47
|
+
else Reflect.deleteProperty(globalThis, key);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
interface Mounted {
|
|
52
|
+
readonly deliveredScrolls: string[];
|
|
53
|
+
readonly locks: Map<string, ScrollGestureLock>;
|
|
54
|
+
readonly render: (element: React.ReactNode) => Promise<void>;
|
|
55
|
+
readonly swipe: (testID: string) => Promise<boolean>;
|
|
56
|
+
readonly unmount: () => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/*** Mounts elements in a fresh container and records which ScrollViews still receive scroll input. */
|
|
60
|
+
function mount(): Mounted {
|
|
61
|
+
const host = document.createElement('div');
|
|
62
|
+
document.body.append(host);
|
|
63
|
+
const root = createRoot(host);
|
|
64
|
+
const deliveredScrolls: string[] = [];
|
|
65
|
+
const locks = new Map<string, ScrollGestureLock>();
|
|
66
|
+
return {
|
|
67
|
+
deliveredScrolls,
|
|
68
|
+
locks,
|
|
69
|
+
render: (element) => act(() => Promise.resolve().then(() => root.render(element))),
|
|
70
|
+
// A disabled react-native-web ScrollView stops delivering wheel input to its handlers.
|
|
71
|
+
swipe: async (testID) => {
|
|
72
|
+
const target = host.querySelector<HTMLElement>(`[data-testid="${testID}"]`);
|
|
73
|
+
if (!target) throw new Error(`Missing ${testID}`);
|
|
74
|
+
const before = deliveredScrolls.length;
|
|
75
|
+
await act(() =>
|
|
76
|
+
Promise.resolve().then(() =>
|
|
77
|
+
target.dispatchEvent(new browser.Event('wheel', { bubbles: true })),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
// Bubbling may also reach an enabled ancestor, so only the scrolled ScrollView counts.
|
|
81
|
+
return deliveredScrolls.slice(before).includes(testID);
|
|
82
|
+
},
|
|
83
|
+
unmount: async () => {
|
|
84
|
+
await act(() => Promise.resolve().then(() => root.unmount()));
|
|
85
|
+
host.remove();
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/*** Renders a tracked ZORA ScrollView whose descendants can reach its gesture lock. */
|
|
91
|
+
function TrackedScrollView({
|
|
92
|
+
children,
|
|
93
|
+
id,
|
|
94
|
+
mounted,
|
|
95
|
+
scrollEnabled,
|
|
96
|
+
}: {
|
|
97
|
+
readonly children?: React.ReactNode;
|
|
98
|
+
readonly id: string;
|
|
99
|
+
readonly mounted: Mounted;
|
|
100
|
+
readonly scrollEnabled?: boolean;
|
|
101
|
+
}) {
|
|
102
|
+
return (
|
|
103
|
+
<ScrollView
|
|
104
|
+
scrollEnabled={scrollEnabled}
|
|
105
|
+
testID={id}
|
|
106
|
+
onWheel={() => mounted.deliveredScrolls.push(id)}
|
|
107
|
+
>
|
|
108
|
+
<LockProbe id={`${id}-lock`} mounted={mounted} />
|
|
109
|
+
{children}
|
|
110
|
+
</ScrollView>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/*** Publishes the nearest ScrollView gesture lock under a stable name. */
|
|
115
|
+
function LockProbe({ id, mounted }: { readonly id: string; readonly mounted: Mounted }) {
|
|
116
|
+
mounted.locks.set(id, useScrollGestureLock());
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/*** Acquires a lock inside React's act boundary so the ScrollView state update flushes. */
|
|
121
|
+
async function acquire(mounted: Mounted, id: string): Promise<() => Promise<void>> {
|
|
122
|
+
let release: (() => void) | undefined;
|
|
123
|
+
await act(() =>
|
|
124
|
+
Promise.resolve().then(() => {
|
|
125
|
+
release = mounted.locks.get(id)?.acquire();
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
return () =>
|
|
129
|
+
act(() =>
|
|
130
|
+
Promise.resolve().then(() => {
|
|
131
|
+
release?.();
|
|
132
|
+
}),
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
test('delivers scroll input to an unlocked ScrollView and suspends it while a descendant holds the lock', async () => {
|
|
137
|
+
const mounted = mount();
|
|
138
|
+
try {
|
|
139
|
+
await mounted.render(<TrackedScrollView id="page" mounted={mounted} />);
|
|
140
|
+
expect(await mounted.swipe('page')).toBe(true);
|
|
141
|
+
|
|
142
|
+
const release = await acquire(mounted, 'page-lock');
|
|
143
|
+
expect(await mounted.swipe('page')).toBe(false);
|
|
144
|
+
|
|
145
|
+
await release();
|
|
146
|
+
expect(await mounted.swipe('page')).toBe(true);
|
|
147
|
+
} finally {
|
|
148
|
+
await mounted.unmount();
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('suspends every ancestor ScrollView of a nested gesture and restores them together', async () => {
|
|
153
|
+
const mounted = mount();
|
|
154
|
+
try {
|
|
155
|
+
await mounted.render(
|
|
156
|
+
<TrackedScrollView id="outer" mounted={mounted}>
|
|
157
|
+
<TrackedScrollView id="inner" mounted={mounted} />
|
|
158
|
+
</TrackedScrollView>,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const release = await acquire(mounted, 'inner-lock');
|
|
162
|
+
expect(await mounted.swipe('inner')).toBe(false);
|
|
163
|
+
expect(await mounted.swipe('outer')).toBe(false);
|
|
164
|
+
|
|
165
|
+
await release();
|
|
166
|
+
expect(await mounted.swipe('inner')).toBe(true);
|
|
167
|
+
expect(await mounted.swipe('outer')).toBe(true);
|
|
168
|
+
} finally {
|
|
169
|
+
await mounted.unmount();
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
test('does not suspend sibling ScrollViews or the descendants of an outer ScrollView that did not lock', async () => {
|
|
174
|
+
const mounted = mount();
|
|
175
|
+
try {
|
|
176
|
+
await mounted.render(
|
|
177
|
+
<>
|
|
178
|
+
<TrackedScrollView id="left" mounted={mounted} />
|
|
179
|
+
<TrackedScrollView id="right" mounted={mounted} />
|
|
180
|
+
</>,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const release = await acquire(mounted, 'left-lock');
|
|
184
|
+
expect(await mounted.swipe('left')).toBe(false);
|
|
185
|
+
expect(await mounted.swipe('right')).toBe(true);
|
|
186
|
+
|
|
187
|
+
await release();
|
|
188
|
+
expect(await mounted.swipe('left')).toBe(true);
|
|
189
|
+
} finally {
|
|
190
|
+
await mounted.unmount();
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('keeps scrolling suspended until every simultaneous owner has released, and ignores double releases', async () => {
|
|
195
|
+
const mounted = mount();
|
|
196
|
+
try {
|
|
197
|
+
await mounted.render(<TrackedScrollView id="page" mounted={mounted} />);
|
|
198
|
+
|
|
199
|
+
const releaseFirst = await acquire(mounted, 'page-lock');
|
|
200
|
+
const releaseSecond = await acquire(mounted, 'page-lock');
|
|
201
|
+
await releaseFirst();
|
|
202
|
+
expect(await mounted.swipe('page')).toBe(false);
|
|
203
|
+
|
|
204
|
+
await releaseFirst();
|
|
205
|
+
expect(await mounted.swipe('page')).toBe(false);
|
|
206
|
+
|
|
207
|
+
await releaseSecond();
|
|
208
|
+
expect(await mounted.swipe('page')).toBe(true);
|
|
209
|
+
|
|
210
|
+
const releaseThird = await acquire(mounted, 'page-lock');
|
|
211
|
+
expect(await mounted.swipe('page')).toBe(false);
|
|
212
|
+
await releaseThird();
|
|
213
|
+
expect(await mounted.swipe('page')).toBe(true);
|
|
214
|
+
} finally {
|
|
215
|
+
await mounted.unmount();
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test('never re-enables a ScrollView that the caller disabled explicitly', async () => {
|
|
220
|
+
const mounted = mount();
|
|
221
|
+
try {
|
|
222
|
+
await mounted.render(<TrackedScrollView id="page" mounted={mounted} scrollEnabled={false} />);
|
|
223
|
+
expect(await mounted.swipe('page')).toBe(false);
|
|
224
|
+
|
|
225
|
+
const release = await acquire(mounted, 'page-lock');
|
|
226
|
+
await release();
|
|
227
|
+
expect(await mounted.swipe('page')).toBe(false);
|
|
228
|
+
|
|
229
|
+
await mounted.render(<TrackedScrollView id="page" mounted={mounted} scrollEnabled />);
|
|
230
|
+
expect(await mounted.swipe('page')).toBe(true);
|
|
231
|
+
} finally {
|
|
232
|
+
await mounted.unmount();
|
|
233
|
+
}
|
|
234
|
+
});
|
|
@@ -3,16 +3,32 @@ import React from 'react';
|
|
|
3
3
|
|
|
4
4
|
import type { ScrollViewProps } from '../../../../types/layout';
|
|
5
5
|
import { withZoraThemeScope } from '../../../theme/adapters/inbound/withZoraThemeScope';
|
|
6
|
+
import { createScrollGestureLock } from '../../utils/createScrollGestureLock';
|
|
7
|
+
import { ScrollGestureLockContext } from './ScrollGestureLockContext';
|
|
8
|
+
import { useScrollGestureLock } from './useScrollGestureLock';
|
|
6
9
|
|
|
7
10
|
/*** Adapts the token-aware Surface ScrollView primitive to ZORA theme scope. */
|
|
8
11
|
export const ScrollView = withZoraThemeScope(ScrollViewInner);
|
|
9
12
|
|
|
10
|
-
/*** Forwards ZORA scrolling props to the published Surface ScrollView boundary. */
|
|
13
|
+
/*** Forwards ZORA scrolling props to the published Surface ScrollView boundary and yields scrolling to active descendant gestures. */
|
|
11
14
|
function ScrollViewInner({
|
|
12
15
|
themeId: _themeId,
|
|
13
16
|
mode: _mode,
|
|
14
17
|
interactionPolicy: _interactionPolicy,
|
|
18
|
+
scrollEnabled = true,
|
|
15
19
|
...props
|
|
16
20
|
}: ScrollViewProps) {
|
|
17
|
-
|
|
21
|
+
const parentLock = useScrollGestureLock();
|
|
22
|
+
const [activeGestures, setActiveGestures] = React.useState(0);
|
|
23
|
+
const lock = React.useMemo(
|
|
24
|
+
() =>
|
|
25
|
+
createScrollGestureLock(parentLock, (delta) => setActiveGestures((count) => count + delta)),
|
|
26
|
+
[parentLock],
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<ScrollGestureLockContext.Provider value={lock}>
|
|
31
|
+
<SurfaceScrollView {...props} scrollEnabled={scrollEnabled && activeGestures === 0} />
|
|
32
|
+
</ScrollGestureLockContext.Provider>
|
|
33
|
+
);
|
|
18
34
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ScrollGestureLock } from '../../../../types/layout';
|
|
4
|
+
import { ScrollGestureLockContext } from './ScrollGestureLockContext';
|
|
5
|
+
|
|
6
|
+
const unlockedScrollGesture: ScrollGestureLock = { acquire: () => () => undefined };
|
|
7
|
+
|
|
8
|
+
/*** Resolves the nearest ZORA ScrollView lock, or an inert lock when no scroll container exists. */
|
|
9
|
+
export function useScrollGestureLock(): ScrollGestureLock {
|
|
10
|
+
return React.useContext(ScrollGestureLockContext) ?? unlockedScrollGesture;
|
|
11
|
+
}
|
|
@@ -3,6 +3,7 @@ export type {
|
|
|
3
3
|
DividerProps,
|
|
4
4
|
GridProps,
|
|
5
5
|
ScreenProps,
|
|
6
|
+
ScrollGestureLock,
|
|
6
7
|
ScrollViewProps,
|
|
7
8
|
ViewProps,
|
|
8
9
|
} from '../../types/layout';
|
|
@@ -11,4 +12,5 @@ export { Divider } from './adapters/inbound/Divider';
|
|
|
11
12
|
export { Grid } from './adapters/inbound/Grid';
|
|
12
13
|
export { Screen } from './adapters/inbound/Screen';
|
|
13
14
|
export { ScrollView } from './adapters/inbound/ScrollView';
|
|
15
|
+
export { useScrollGestureLock } from './adapters/inbound/useScrollGestureLock';
|
|
14
16
|
export { View } from './adapters/inbound/View';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import type { ScrollGestureLock } from '../../../types/layout';
|
|
4
|
+
import { createScrollGestureLock } from './createScrollGestureLock';
|
|
5
|
+
|
|
6
|
+
const inertParent: ScrollGestureLock = { acquire: () => () => undefined };
|
|
7
|
+
|
|
8
|
+
test('reports one active gesture per acquisition and releases each exactly once', () => {
|
|
9
|
+
const deltas: number[] = [];
|
|
10
|
+
const lock = createScrollGestureLock(inertParent, (delta) => deltas.push(delta));
|
|
11
|
+
|
|
12
|
+
const releaseFirst = lock.acquire();
|
|
13
|
+
const releaseSecond = lock.acquire();
|
|
14
|
+
releaseFirst();
|
|
15
|
+
releaseFirst();
|
|
16
|
+
releaseSecond();
|
|
17
|
+
|
|
18
|
+
expect(deltas).toEqual([1, 1, -1, -1]);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('suspends nested ancestor containers for the lifetime of the gesture', () => {
|
|
22
|
+
const outerDeltas: number[] = [];
|
|
23
|
+
const innerDeltas: number[] = [];
|
|
24
|
+
const outer = createScrollGestureLock(inertParent, (delta) => outerDeltas.push(delta));
|
|
25
|
+
const inner = createScrollGestureLock(outer, (delta) => innerDeltas.push(delta));
|
|
26
|
+
|
|
27
|
+
const release = inner.acquire();
|
|
28
|
+
expect(outerDeltas).toEqual([1]);
|
|
29
|
+
expect(innerDeltas).toEqual([1]);
|
|
30
|
+
release();
|
|
31
|
+
|
|
32
|
+
expect(outerDeltas).toEqual([1, -1]);
|
|
33
|
+
expect(innerDeltas).toEqual([1, -1]);
|
|
34
|
+
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ScrollGestureLock } from '../../../types/layout';
|
|
2
|
+
|
|
3
|
+
/*** Creates a lock that reports each held gesture to its scroll container and also suspends every ancestor container. */
|
|
4
|
+
export function createScrollGestureLock(
|
|
5
|
+
parent: ScrollGestureLock,
|
|
6
|
+
onActiveGesturesChange: (delta: 1 | -1) => void,
|
|
7
|
+
): ScrollGestureLock {
|
|
8
|
+
return {
|
|
9
|
+
acquire: () => {
|
|
10
|
+
const releaseParent = parent.acquire();
|
|
11
|
+
let released = false;
|
|
12
|
+
onActiveGesturesChange(1);
|
|
13
|
+
return () => {
|
|
14
|
+
if (released) return;
|
|
15
|
+
released = true;
|
|
16
|
+
onActiveGesturesChange(-1);
|
|
17
|
+
releaseParent();
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
@@ -70,3 +70,9 @@ export interface GridInteractionsController {
|
|
|
70
70
|
readonly keyDown: (key: string, pointer?: GridInteractionPointer) => boolean;
|
|
71
71
|
readonly update: (props: GridInteractionsControllerProps) => void;
|
|
72
72
|
}
|
|
73
|
+
|
|
74
|
+
/** Gesture-scoped ownership of ancestor scrolling for one interaction surface. */
|
|
75
|
+
export interface GridInteractionScrollLock {
|
|
76
|
+
readonly acquire: () => void;
|
|
77
|
+
readonly release: () => void;
|
|
78
|
+
}
|
package/src/types/grid-view.ts
CHANGED
|
@@ -68,3 +68,48 @@ export interface TileGridProps extends ZoraBaseProps {
|
|
|
68
68
|
onVisibleItemIdsChange?: (ids: readonly string[]) => void;
|
|
69
69
|
renderItem: (item: TileGridItem) => React.ReactNode;
|
|
70
70
|
}
|
|
71
|
+
|
|
72
|
+
/** The two independent native scroll axes that back a GridView viewport. */
|
|
73
|
+
export type GridScrollAxis = 'x' | 'y';
|
|
74
|
+
|
|
75
|
+
/** A physical native scroll position in pixels. */
|
|
76
|
+
export interface GridScrollPosition {
|
|
77
|
+
readonly x: number;
|
|
78
|
+
readonly y: number;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A programmatic native scroll request that GridView is still waiting to observe. */
|
|
82
|
+
export interface GridPendingScroll {
|
|
83
|
+
readonly animated: boolean;
|
|
84
|
+
readonly expiresAt: number;
|
|
85
|
+
readonly target: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Native capabilities and clock used by the programmatic-versus-user scroll arbiter. */
|
|
89
|
+
export interface GridScrollSyncOptions {
|
|
90
|
+
/** Requests a native scroll of one axis. */
|
|
91
|
+
readonly scrollTo: (axis: GridScrollAxis, offset: number, animated: boolean) => void;
|
|
92
|
+
/** Reports a genuine user scroll as the pixel displacement of the native offset. */
|
|
93
|
+
readonly onUserScroll: (axis: GridScrollAxis, displacement: number) => void;
|
|
94
|
+
/** Reconciles a late programmatic native frame without classifying it as a user pan. */
|
|
95
|
+
readonly onProgrammaticScroll: (axis: GridScrollAxis, displacement: number) => void;
|
|
96
|
+
readonly now?: () => number;
|
|
97
|
+
readonly schedule?: (callback: () => void, delay: number) => ReturnType<typeof setTimeout>;
|
|
98
|
+
readonly cancel?: (handle: ReturnType<typeof setTimeout>) => void;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Separates echoes of programmatic scrolls from user scrolling, independently per axis. */
|
|
102
|
+
export interface GridScrollSync {
|
|
103
|
+
/** True when the baseline already matches the position within native tolerance. */
|
|
104
|
+
readonly isCurrent: (position: GridScrollPosition) => boolean;
|
|
105
|
+
/** Moves native scrolling to a viewport-derived position. */
|
|
106
|
+
readonly request: (position: GridScrollPosition, animated: boolean) => void;
|
|
107
|
+
/** Routes one native scroll event. */
|
|
108
|
+
readonly scrolled: (axis: GridScrollAxis, offset: number) => void;
|
|
109
|
+
/** Hands an axis to the user, adopting the native offset at the start of their drag. */
|
|
110
|
+
readonly dragBegan: (axis: GridScrollAxis, offset: number) => void;
|
|
111
|
+
/** Adopts the final native offset when a programmatic or momentum scroll ends. */
|
|
112
|
+
readonly scrollEnded: (axis: GridScrollAxis, offset: number) => void;
|
|
113
|
+
/** Cancels every pending settle timer. */
|
|
114
|
+
readonly dispose: () => void;
|
|
115
|
+
}
|
package/src/types/layout.ts
CHANGED
|
@@ -30,3 +30,9 @@ export interface ScreenProps extends ZoraBaseProps {
|
|
|
30
30
|
scroll?: boolean;
|
|
31
31
|
width?: ZoraContentWidth;
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
/** Exclusive-gesture coordination between a ZORA scroll container and its descendant surfaces. */
|
|
35
|
+
export interface ScrollGestureLock {
|
|
36
|
+
/** Suspends scrolling until the returned release function runs; releasing twice is harmless. */
|
|
37
|
+
readonly acquire: () => () => void;
|
|
38
|
+
}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import {
|
|
3
3
|
Button2
|
|
4
|
-
} from "./Accordion-
|
|
4
|
+
} from "./Accordion-czcaf5x2.js";
|
|
5
5
|
import {
|
|
6
6
|
withZoraThemeScope
|
|
7
7
|
} from "./Accordion-vj1m2wck.js";
|
|
8
8
|
import {
|
|
9
9
|
View2
|
|
10
|
-
} from "./Accordion-
|
|
10
|
+
} from "./Accordion-ep35792s.js";
|
|
11
11
|
import {
|
|
12
12
|
Card2
|
|
13
|
-
} from "./Accordion-
|
|
13
|
+
} from "./Accordion-rqr10gn4.js";
|
|
14
14
|
import {
|
|
15
15
|
Text3
|
|
16
16
|
} from "./Accordion-9rnsg9pk.js";
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
View2,
|
|
16
16
|
Divider2
|
|
17
|
-
} from "./Accordion-
|
|
17
|
+
} from "./Accordion-ep35792s.js";
|
|
18
18
|
import {
|
|
19
19
|
Pressable
|
|
20
20
|
} from "./Accordion-nnv76yff.js";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "./Accordion-wyxmd0n0.js";
|
|
24
24
|
import {
|
|
25
25
|
SectionHeader2
|
|
26
|
-
} from "./Accordion-
|
|
26
|
+
} from "./Accordion-g08740h4.js";
|
|
27
27
|
import {
|
|
28
28
|
useZoraTheme2
|
|
29
29
|
} from "./Accordion-srjya6dz.js";
|
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
} from "./Accordion-vj1m2wck.js";
|
|
8
8
|
import {
|
|
9
9
|
View2
|
|
10
|
-
} from "./Accordion-
|
|
10
|
+
} from "./Accordion-ep35792s.js";
|
|
11
11
|
import {
|
|
12
12
|
Text3
|
|
13
13
|
} from "./Accordion-9rnsg9pk.js";
|
|
14
14
|
import {
|
|
15
15
|
Avatar2
|
|
16
|
-
} from "./Accordion-
|
|
16
|
+
} from "./Accordion-tyh8jj9d.js";
|
|
17
17
|
import {
|
|
18
18
|
Badge2
|
|
19
19
|
} from "./Accordion-xgxxg1hz.js";
|
|
@@ -251,6 +251,40 @@ function splitLayoutProps(props) {
|
|
|
251
251
|
};
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
// src/features/layout/adapters/inbound/ScrollView.tsx
|
|
255
|
+
import React4 from "react";
|
|
256
|
+
|
|
257
|
+
// src/features/layout/utils/createScrollGestureLock.ts
|
|
258
|
+
function createScrollGestureLock(parent, onActiveGesturesChange) {
|
|
259
|
+
return {
|
|
260
|
+
acquire: () => {
|
|
261
|
+
const releaseParent = parent.acquire();
|
|
262
|
+
let released = false;
|
|
263
|
+
onActiveGesturesChange(1);
|
|
264
|
+
return () => {
|
|
265
|
+
if (released)
|
|
266
|
+
return;
|
|
267
|
+
released = true;
|
|
268
|
+
onActiveGesturesChange(-1);
|
|
269
|
+
releaseParent();
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/features/layout/adapters/inbound/ScrollGestureLockContext.ts
|
|
276
|
+
import React2 from "react";
|
|
277
|
+
var ScrollGestureLockContext = React2.createContext(undefined);
|
|
278
|
+
|
|
279
|
+
// src/features/layout/adapters/inbound/useScrollGestureLock.ts
|
|
280
|
+
import React3 from "react";
|
|
281
|
+
var unlockedScrollGesture = { acquire: () => () => {
|
|
282
|
+
return;
|
|
283
|
+
} };
|
|
284
|
+
function useScrollGestureLock() {
|
|
285
|
+
return React3.useContext(ScrollGestureLockContext) ?? unlockedScrollGesture;
|
|
286
|
+
}
|
|
287
|
+
|
|
254
288
|
// src/features/layout/adapters/inbound/ScrollView.tsx
|
|
255
289
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
256
290
|
var ScrollView2 = withZoraThemeScope(ScrollViewInner);
|
|
@@ -258,10 +292,18 @@ function ScrollViewInner({
|
|
|
258
292
|
themeId: _themeId,
|
|
259
293
|
mode: _mode,
|
|
260
294
|
interactionPolicy: _interactionPolicy,
|
|
295
|
+
scrollEnabled = true,
|
|
261
296
|
...props
|
|
262
297
|
}) {
|
|
263
|
-
|
|
264
|
-
|
|
298
|
+
const parentLock = useScrollGestureLock();
|
|
299
|
+
const [activeGestures, setActiveGestures] = React4.useState(0);
|
|
300
|
+
const lock = React4.useMemo(() => createScrollGestureLock(parentLock, (delta) => setActiveGestures((count) => count + delta)), [parentLock]);
|
|
301
|
+
return /* @__PURE__ */ jsx7(ScrollGestureLockContext.Provider, {
|
|
302
|
+
value: lock,
|
|
303
|
+
children: /* @__PURE__ */ jsx7(ScrollView, {
|
|
304
|
+
...props,
|
|
305
|
+
scrollEnabled: scrollEnabled && activeGestures === 0
|
|
306
|
+
})
|
|
265
307
|
});
|
|
266
308
|
}
|
|
267
309
|
|
|
@@ -4,16 +4,16 @@ import {
|
|
|
4
4
|
} from "./Accordion-vj1m2wck.js";
|
|
5
5
|
import {
|
|
6
6
|
View2
|
|
7
|
-
} from "./Accordion-
|
|
7
|
+
} from "./Accordion-ep35792s.js";
|
|
8
8
|
import {
|
|
9
9
|
ButtonGroup2
|
|
10
|
-
} from "./Accordion-
|
|
10
|
+
} from "./Accordion-czcaf5x2.js";
|
|
11
11
|
import {
|
|
12
12
|
Card2
|
|
13
|
-
} from "./Accordion-
|
|
13
|
+
} from "./Accordion-rqr10gn4.js";
|
|
14
14
|
import {
|
|
15
15
|
List2
|
|
16
|
-
} from "./Accordion-
|
|
16
|
+
} from "./Accordion-2jy53kzk.js";
|
|
17
17
|
import {
|
|
18
18
|
useZoraTheme2
|
|
19
19
|
} from "./Accordion-srjya6dz.js";
|