@ankhorage/zora 25.5.0 → 25.6.2

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.
Files changed (106) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -1
  3. package/dist/capabilities/index.d.ts +2 -74
  4. package/dist/capabilities/index.d.ts.map +1 -1
  5. package/dist/capabilities/index.js +6158 -59
  6. package/dist/capabilities/index.js.map +118 -1
  7. package/dist/cli/index.d.ts +2 -74
  8. package/dist/cli/index.d.ts.map +1 -1
  9. package/dist/cli/index.js +2 -1
  10. package/dist/cli/index.js.map +1 -1
  11. package/dist/features/grid-view/adapters/inbound/GridView.d.ts +2 -7
  12. package/dist/features/grid-view/adapters/inbound/GridView.d.ts.map +1 -1
  13. package/dist/features/grid-view/adapters/inbound/GridView.js +309 -51
  14. package/dist/features/grid-view/adapters/inbound/GridView.js.map +1 -1
  15. package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts +1 -1
  16. package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts.map +1 -1
  17. package/dist/features/grid-view/adapters/inbound/TileGrid.js +11 -4
  18. package/dist/features/grid-view/adapters/inbound/TileGrid.js.map +1 -1
  19. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.d.ts +5 -0
  20. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.d.ts.map +1 -0
  21. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.js +59 -0
  22. package/dist/features/matrix-grid/adapters/inbound/MatrixGrid.js.map +1 -0
  23. package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.d.ts +7 -0
  24. package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.d.ts.map +1 -0
  25. package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.js +24 -0
  26. package/dist/features/matrix-grid/application/resolveMatrixGridContentSize.js.map +1 -0
  27. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.d.ts +5 -0
  28. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.d.ts.map +1 -0
  29. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.js +8 -0
  30. package/dist/features/matrix-grid/application/resolveMatrixGridSelection.js.map +1 -0
  31. package/dist/features/matrix-grid/meta.d.ts +11 -0
  32. package/dist/features/matrix-grid/meta.d.ts.map +1 -0
  33. package/dist/features/matrix-grid/meta.js +11 -0
  34. package/dist/features/matrix-grid/meta.js.map +1 -0
  35. package/dist/features/matrix-grid/public.d.ts +4 -0
  36. package/dist/features/matrix-grid/public.d.ts.map +1 -0
  37. package/dist/features/matrix-grid/public.js +3 -0
  38. package/dist/features/matrix-grid/public.js.map +1 -0
  39. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.d.ts.map +1 -1
  40. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js +2 -0
  41. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js.map +1 -1
  42. package/dist/features/registry/componentMeta.d.ts.map +1 -1
  43. package/dist/features/registry/componentMeta.js +2 -0
  44. package/dist/features/registry/componentMeta.js.map +1 -1
  45. package/dist/features/registry/createEventCapabilities.d.ts +4 -0
  46. package/dist/features/registry/createEventCapabilities.d.ts.map +1 -0
  47. package/dist/features/registry/createEventCapabilities.js +76 -0
  48. package/dist/features/registry/createEventCapabilities.js.map +1 -0
  49. package/dist/index.d.ts +2 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +1 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/types/grid-view.d.ts +18 -1
  54. package/dist/types/grid-view.d.ts.map +1 -1
  55. package/dist/types/grid-view.js.map +1 -1
  56. package/dist/types/matrix-grid.d.ts +23 -0
  57. package/dist/types/matrix-grid.d.ts.map +1 -0
  58. package/dist/types/matrix-grid.js +2 -0
  59. package/dist/types/matrix-grid.js.map +1 -0
  60. package/package.json +1822 -4
  61. package/src/capabilities/index.test.ts +87 -15
  62. package/src/capabilities/index.ts +5 -2
  63. package/src/cli/index.test.ts +5 -3
  64. package/src/cli/index.ts +5 -2
  65. package/src/features/grid-view/adapters/inbound/GridView.interaction.test.tsx +585 -0
  66. package/src/features/grid-view/adapters/inbound/GridView.test.tsx +74 -0
  67. package/src/features/grid-view/adapters/inbound/GridView.tsx +506 -77
  68. package/src/features/grid-view/adapters/inbound/TileGrid.tsx +26 -3
  69. package/src/features/matrix-grid/adapters/inbound/MatrixGrid.test.tsx +232 -0
  70. package/src/features/matrix-grid/adapters/inbound/MatrixGrid.tsx +142 -0
  71. package/src/features/matrix-grid/application/resolveMatrixGridContentSize.test.ts +32 -0
  72. package/src/features/matrix-grid/application/resolveMatrixGridContentSize.ts +28 -0
  73. package/src/features/matrix-grid/application/resolveMatrixGridSelection.test.ts +10 -0
  74. package/src/features/matrix-grid/application/resolveMatrixGridSelection.ts +15 -0
  75. package/src/features/matrix-grid/application/resolveMatrixGridVisibleCells.test.ts +35 -0
  76. package/src/features/matrix-grid/meta.ts +12 -0
  77. package/src/features/matrix-grid/public.ts +3 -0
  78. package/src/features/registry/ZORA_COMPONENT_REGISTRY.ts +2 -0
  79. package/src/features/registry/componentMeta.ts +2 -0
  80. package/src/features/registry/createEventCapabilities.ts +108 -0
  81. package/src/features/time-grid/adapters/inbound/TimeGrid.test.tsx +35 -8
  82. package/src/index.ts +2 -0
  83. package/src/structureOwnership.test.ts +5 -0
  84. package/src/types/grid-view.ts +27 -1
  85. package/src/types/matrix-grid.ts +29 -0
  86. package/web-dist/chunks/{Accordion-d6azgz09.js → Accordion-2r0gqk3x.js} +1 -1
  87. package/web-dist/chunks/Accordion-a6551mh4.js +515 -0
  88. package/web-dist/chunks/{Accordion-0my2z6qe.js → Accordion-bz04casa.js} +132 -3
  89. package/web-dist/chunks/{Accordion-7qfd4cb4.js → Accordion-jh72azm2.js} +1 -1
  90. package/web-dist/components/explorer/Explorer.js +2 -2
  91. package/web-dist/components/file-explorer/FileExplorer.js +2 -2
  92. package/web-dist/components/grid-line-overlay/GridLineOverlay.js +1 -1
  93. package/web-dist/components/grid-ruler/GridRuler.js +1 -1
  94. package/web-dist/components/grid-view/GridView.js +1 -1
  95. package/web-dist/components/matrix-grid/MatrixGrid.d.ts +3 -0
  96. package/web-dist/components/matrix-grid/MatrixGrid.js +153 -0
  97. package/web-dist/components/matrix-grid/index.d.ts +1 -0
  98. package/web-dist/components/matrix-grid/index.js +2 -0
  99. package/web-dist/components/media-explorer/MediaExplorer.js +2 -2
  100. package/web-dist/components/reader/Reader.js +1 -1
  101. package/web-dist/components/spatial-grid/SpatialGrid.js +1 -1
  102. package/web-dist/components/tile-grid/TileGrid.js +1 -1
  103. package/web-dist/components/time-grid/TimeGrid.js +2 -2
  104. package/web-dist/components/uploader/Uploader.js +2 -2
  105. package/web-dist/manifest.json +53 -24
  106. package/web-dist/chunks/Accordion-gxj5qbpr.js +0 -194
@@ -0,0 +1,515 @@
1
+ 'use client';
2
+ import {
3
+ getVisibleGridItems,
4
+ constrainViewport,
5
+ panViewport,
6
+ revealWorldRect,
7
+ worldToViewport,
8
+ zoomViewportAt
9
+ } from "./Accordion-bz04casa.js";
10
+ import {
11
+ require_cjs
12
+ } from "./Accordion-xgpzh4wq.js";
13
+ import {
14
+ __toESM
15
+ } from "./Accordion-nh0cs9hq.js";
16
+
17
+ // src/features/grid-view/adapters/inbound/GridView.tsx
18
+ var import_react_native = __toESM(require_cjs(), 1);
19
+ import React from "react";
20
+ import { jsx, jsxs } from "react/jsx-runtime";
21
+ function GridView2({
22
+ items,
23
+ contentWidth,
24
+ contentHeight,
25
+ width,
26
+ height,
27
+ viewport: controlledViewport,
28
+ defaultViewport,
29
+ viewportConstraints,
30
+ zoomLimits,
31
+ zoom = 1,
32
+ overscanPixels = 160,
33
+ focusedItemId,
34
+ revealPaddingPixels = 8,
35
+ interactionPolicy,
36
+ onViewportChange,
37
+ onVisibleItemIdsChange,
38
+ renderItem,
39
+ testID
40
+ }) {
41
+ const [uncontrolledViewport, setUncontrolledViewport] = React.useState(() => createInitialViewport(width, height, zoom, defaultViewport));
42
+ const horizontalScrollRef = React.useRef(null);
43
+ const verticalScrollRef = React.useRef(null);
44
+ const gridRef = React.useRef(null);
45
+ const scrollPositionRef = React.useRef({ x: 0, y: 0 });
46
+ const pinchGestureRef = React.useRef(undefined);
47
+ const pinchMeasurementRef = React.useRef(0);
48
+ const pinchSessionRef = React.useRef(0);
49
+ const viewportOriginRef = React.useRef({ x: 0, y: 0 });
50
+ const focusRevealProposalRef = React.useRef(undefined);
51
+ const focusRevealViewportRef = React.useRef(undefined);
52
+ const [isPinching, setIsPinching] = React.useState(false);
53
+ const constraints = React.useMemo(() => viewportConstraints ?? createContentConstraints(contentWidth, contentHeight), [contentHeight, contentWidth, viewportConstraints]);
54
+ const sourceViewport = controlledViewport ?? uncontrolledViewport;
55
+ const viewport = React.useMemo(() => constrainViewport({ ...sourceViewport, height, width }, constraints), [constraints, height, sourceViewport, width]);
56
+ const viewportRef = React.useRef(viewport);
57
+ const visibleItems = React.useMemo(() => getVisibleGridItems(items, viewport, overscanPixels), [items, overscanPixels, viewport]);
58
+ const viewportVisibleIds = React.useMemo(() => getVisibleGridItems(visibleItems, viewport).map((item) => item.id), [viewport, visibleItems]);
59
+ const focusedItem = items.find((item) => item.id === focusedItemId);
60
+ const focusedItemHeight = focusedItem?.height;
61
+ const focusedItemIdForReveal = focusedItem?.id;
62
+ const focusedItemWidth = focusedItem?.width;
63
+ const focusedItemX = focusedItem?.x;
64
+ const focusedItemY = focusedItem?.y;
65
+ const previousVisibleIdsRef = React.useRef([]);
66
+ const uncontrolled = controlledViewport === undefined;
67
+ const interactive = interactionPolicy !== "passive";
68
+ const publish = React.useCallback((nextViewport) => {
69
+ if (areViewportsEqual(viewportRef.current, nextViewport))
70
+ return;
71
+ viewportRef.current = nextViewport;
72
+ if (uncontrolled)
73
+ setUncontrolledViewport(nextViewport);
74
+ onViewportChange?.(nextViewport);
75
+ }, [onViewportChange, uncontrolled]);
76
+ const publishRef = React.useRef(publish);
77
+ const pan = (displacement) => publish(panViewport(viewportRef.current, displacement, constraints));
78
+ const zoomAt = (focalPoint, factor) => publish(zoomViewportAt(viewportRef.current, focalPoint, {
79
+ pixelsPerUnitX: viewportRef.current.pixelsPerUnitX * factor,
80
+ pixelsPerUnitY: viewportRef.current.pixelsPerUnitY * factor
81
+ }, zoomLimits, constraints));
82
+ React.useEffect(() => {
83
+ viewportRef.current = viewport;
84
+ }, [viewport]);
85
+ React.useEffect(() => {
86
+ publishRef.current = publish;
87
+ }, [publish]);
88
+ const refreshViewportOrigin = React.useCallback(() => {
89
+ gridRef.current?.measureInWindow((x, y) => {
90
+ viewportOriginRef.current = { x, y };
91
+ });
92
+ }, []);
93
+ const measurePinchGesture = React.useCallback((touches, session, onMeasured) => {
94
+ const measurement = pinchMeasurementRef.current + 1;
95
+ pinchMeasurementRef.current = measurement;
96
+ gridRef.current?.measureInWindow((x, y) => {
97
+ if (measurement !== pinchMeasurementRef.current || session !== pinchSessionRef.current) {
98
+ return;
99
+ }
100
+ viewportOriginRef.current = { x, y };
101
+ onMeasured(getPinchGesture(touches, width, height, { x, y }));
102
+ });
103
+ }, [height, width]);
104
+ React.useLayoutEffect(() => {
105
+ refreshViewportOrigin();
106
+ }, [height, refreshViewportOrigin, width]);
107
+ React.useEffect(() => () => {
108
+ pinchMeasurementRef.current += 1;
109
+ pinchSessionRef.current += 1;
110
+ }, []);
111
+ React.useEffect(() => {
112
+ if (!onVisibleItemIdsChange)
113
+ return;
114
+ const previous = previousVisibleIdsRef.current;
115
+ if (previous.length === viewportVisibleIds.length && previous.every((id, index) => id === viewportVisibleIds.at(index))) {
116
+ return;
117
+ }
118
+ previousVisibleIdsRef.current = viewportVisibleIds;
119
+ onVisibleItemIdsChange(viewportVisibleIds);
120
+ }, [onVisibleItemIdsChange, viewportVisibleIds]);
121
+ React.useEffect(() => {
122
+ const position = createScrollMapping(viewport, constraints);
123
+ const nextPosition = {
124
+ x: position.horizontal.position,
125
+ y: position.vertical.position
126
+ };
127
+ if (areScrollPositionsEqual(scrollPositionRef.current, nextPosition))
128
+ return;
129
+ scrollPositionRef.current = nextPosition;
130
+ const animated = focusRevealViewportRef.current !== undefined && areViewportsEqual(viewport, focusRevealViewportRef.current);
131
+ horizontalScrollRef.current?.scrollTo({ animated, x: nextPosition.x });
132
+ verticalScrollRef.current?.scrollTo({ animated, y: nextPosition.y });
133
+ if (animated)
134
+ focusRevealViewportRef.current = undefined;
135
+ }, [constraints, viewport]);
136
+ React.useEffect(() => {
137
+ if (focusedItemHeight === undefined || focusedItemIdForReveal === undefined || focusedItemWidth === undefined || focusedItemX === undefined || focusedItemY === undefined) {
138
+ focusRevealProposalRef.current = undefined;
139
+ return;
140
+ }
141
+ const sourceViewport = viewportRef.current;
142
+ const revealed = revealWorldRect(sourceViewport, {
143
+ height: focusedItemHeight,
144
+ width: focusedItemWidth,
145
+ x: focusedItemX,
146
+ y: focusedItemY
147
+ }, revealPaddingPixels, constraints);
148
+ if (isRepeatedControlledFocusRevealProposal({
149
+ controlled: !uncontrolled,
150
+ focusedItemId: focusedItemIdForReveal,
151
+ previous: focusRevealProposalRef.current,
152
+ sourceViewport,
153
+ viewport: revealed
154
+ })) {
155
+ return;
156
+ }
157
+ focusRevealProposalRef.current = {
158
+ focusedItemId: focusedItemIdForReveal,
159
+ sourceViewport,
160
+ viewport: revealed
161
+ };
162
+ focusRevealViewportRef.current = areViewportsEqual(sourceViewport, revealed) ? undefined : revealed;
163
+ publishRef.current(revealed);
164
+ }, [
165
+ constraints,
166
+ focusedItemHeight,
167
+ focusedItemIdForReveal,
168
+ focusedItemWidth,
169
+ focusedItemX,
170
+ focusedItemY,
171
+ revealPaddingPixels,
172
+ uncontrolled
173
+ ]);
174
+ const scrollMapping = createScrollMapping(viewport, constraints);
175
+ const syncScrollPosition = () => {
176
+ const nextMapping = createScrollMapping(viewportRef.current, constraints);
177
+ const nextPosition = {
178
+ x: nextMapping.horizontal.position,
179
+ y: nextMapping.vertical.position
180
+ };
181
+ scrollPositionRef.current = nextPosition;
182
+ horizontalScrollRef.current?.scrollTo({ animated: false, x: nextPosition.x });
183
+ verticalScrollRef.current?.scrollTo({ animated: false, y: nextPosition.y });
184
+ };
185
+ return /* @__PURE__ */ jsxs(import_react_native.View, {
186
+ ref: gridRef,
187
+ accessibilityLabel: "Interactive grid viewport",
188
+ onLayout: refreshViewportOrigin,
189
+ onTouchEnd: () => {
190
+ const wasPinching = pinchGestureRef.current !== undefined;
191
+ pinchMeasurementRef.current += 1;
192
+ pinchSessionRef.current += 1;
193
+ pinchGestureRef.current = undefined;
194
+ setIsPinching(false);
195
+ if (wasPinching)
196
+ syncScrollPosition();
197
+ },
198
+ onTouchCancel: () => {
199
+ const wasPinching = pinchGestureRef.current !== undefined;
200
+ pinchMeasurementRef.current += 1;
201
+ pinchSessionRef.current += 1;
202
+ pinchGestureRef.current = undefined;
203
+ setIsPinching(false);
204
+ if (wasPinching)
205
+ syncScrollPosition();
206
+ },
207
+ onTouchMove: (event) => {
208
+ if (!interactive)
209
+ return;
210
+ measurePinchGesture([...event.nativeEvent.touches], pinchSessionRef.current, (pinch) => {
211
+ const previous = pinchGestureRef.current;
212
+ pinchGestureRef.current = pinch;
213
+ setIsPinching(pinch !== undefined);
214
+ if (!pinch || !previous)
215
+ return;
216
+ zoomAt(pinch.focalPoint, pinch.distance / previous.distance);
217
+ });
218
+ },
219
+ onTouchStart: (event) => {
220
+ const session = pinchSessionRef.current + 1;
221
+ pinchSessionRef.current = session;
222
+ measurePinchGesture([...event.nativeEvent.touches], session, (pinch) => {
223
+ pinchGestureRef.current = pinch;
224
+ setIsPinching(pinch !== undefined);
225
+ });
226
+ },
227
+ style: { height, overflow: "hidden", width },
228
+ testID,
229
+ children: [
230
+ /* @__PURE__ */ jsx(import_react_native.ScrollView, {
231
+ ref: horizontalScrollRef,
232
+ testID: testID ? `${testID}-horizontal-scroll` : undefined,
233
+ horizontal: true,
234
+ scrollEnabled: interactive && !isPinching,
235
+ scrollEventThrottle: 16,
236
+ showsHorizontalScrollIndicator: true,
237
+ style: { height, width },
238
+ onScroll: (event) => {
239
+ if (pinchGestureRef.current)
240
+ return;
241
+ const { x } = event.nativeEvent.contentOffset;
242
+ const displacement = x - scrollPositionRef.current.x;
243
+ scrollPositionRef.current = { ...scrollPositionRef.current, x };
244
+ if (displacement !== 0)
245
+ pan({ x: -displacement, y: 0 });
246
+ },
247
+ children: /* @__PURE__ */ jsx(import_react_native.ScrollView, {
248
+ ref: verticalScrollRef,
249
+ testID: testID ? `${testID}-vertical-scroll` : undefined,
250
+ scrollEnabled: interactive && !isPinching,
251
+ scrollEventThrottle: 16,
252
+ showsVerticalScrollIndicator: true,
253
+ style: { height, width: scrollMapping.horizontal.contentSize },
254
+ onScroll: (event) => {
255
+ if (pinchGestureRef.current)
256
+ return;
257
+ const { y } = event.nativeEvent.contentOffset;
258
+ const displacement = y - scrollPositionRef.current.y;
259
+ scrollPositionRef.current = { ...scrollPositionRef.current, y };
260
+ if (displacement !== 0)
261
+ pan({ x: 0, y: -displacement });
262
+ },
263
+ children: /* @__PURE__ */ jsx(import_react_native.View, {
264
+ style: {
265
+ height: scrollMapping.vertical.contentSize,
266
+ width: scrollMapping.horizontal.contentSize
267
+ },
268
+ children: visibleItems.map((item) => {
269
+ const position = worldToViewport({ x: item.x, y: item.y }, { ...viewport, offsetX: 0, offsetY: 0 });
270
+ return /* @__PURE__ */ jsx(import_react_native.View, {
271
+ style: {
272
+ height: item.height * viewport.pixelsPerUnitY,
273
+ left: position.x + scrollMapping.horizontal.origin,
274
+ position: "absolute",
275
+ top: position.y + scrollMapping.vertical.origin,
276
+ width: item.width * viewport.pixelsPerUnitX
277
+ },
278
+ children: renderItem(item)
279
+ }, item.id);
280
+ })
281
+ })
282
+ })
283
+ }),
284
+ interactive ? /* @__PURE__ */ jsxs(import_react_native.View, {
285
+ accessibilityLabel: "Viewport controls",
286
+ style: controlsStyle,
287
+ children: [
288
+ /* @__PURE__ */ jsx(import_react_native.Pressable, {
289
+ accessibilityLabel: "Pan left",
290
+ accessibilityRole: "button",
291
+ onPress: () => pan({ x: 48, y: 0 }),
292
+ children: /* @__PURE__ */ jsx(import_react_native.Text, {
293
+ children: "←"
294
+ })
295
+ }),
296
+ /* @__PURE__ */ jsx(import_react_native.Pressable, {
297
+ accessibilityLabel: "Pan right",
298
+ accessibilityRole: "button",
299
+ onPress: () => pan({ x: -48, y: 0 }),
300
+ children: /* @__PURE__ */ jsx(import_react_native.Text, {
301
+ children: "→"
302
+ })
303
+ }),
304
+ /* @__PURE__ */ jsx(import_react_native.Pressable, {
305
+ accessibilityLabel: "Pan up",
306
+ accessibilityRole: "button",
307
+ onPress: () => pan({ x: 0, y: 48 }),
308
+ children: /* @__PURE__ */ jsx(import_react_native.Text, {
309
+ children: "↑"
310
+ })
311
+ }),
312
+ /* @__PURE__ */ jsx(import_react_native.Pressable, {
313
+ accessibilityLabel: "Pan down",
314
+ accessibilityRole: "button",
315
+ onPress: () => pan({ x: 0, y: -48 }),
316
+ children: /* @__PURE__ */ jsx(import_react_native.Text, {
317
+ children: "↓"
318
+ })
319
+ }),
320
+ /* @__PURE__ */ jsx(import_react_native.Pressable, {
321
+ accessibilityLabel: "Zoom in",
322
+ accessibilityRole: "button",
323
+ onPress: () => zoomAt({ x: width / 2, y: height / 2 }, 1.2),
324
+ children: /* @__PURE__ */ jsx(import_react_native.Text, {
325
+ children: "+"
326
+ })
327
+ }),
328
+ /* @__PURE__ */ jsx(import_react_native.Pressable, {
329
+ accessibilityLabel: "Zoom out",
330
+ accessibilityRole: "button",
331
+ onPress: () => zoomAt({ x: width / 2, y: height / 2 }, 1 / 1.2),
332
+ children: /* @__PURE__ */ jsx(import_react_native.Text, {
333
+ children: "−"
334
+ })
335
+ })
336
+ ]
337
+ }) : null
338
+ ]
339
+ });
340
+ }
341
+ var controlsStyle = { bottom: 8, gap: 4, position: "absolute", right: 8 };
342
+ function createInitialViewport(width, height, zoom, viewport) {
343
+ return {
344
+ height,
345
+ offsetX: viewport?.offsetX ?? 0,
346
+ offsetY: viewport?.offsetY ?? 0,
347
+ pixelsPerUnitX: viewport?.pixelsPerUnitX ?? zoom,
348
+ pixelsPerUnitY: viewport?.pixelsPerUnitY ?? zoom,
349
+ width
350
+ };
351
+ }
352
+ function createContentConstraints(contentWidth, contentHeight) {
353
+ return { world: { height: contentHeight, width: contentWidth, x: 0, y: 0 } };
354
+ }
355
+ function createScrollMapping(viewport, constraints) {
356
+ const horizontalMinimum = constrainViewport({ ...viewport, offsetX: -Number.MAX_SAFE_INTEGER }, constraints).offsetX;
357
+ const horizontalMaximum = constrainViewport({ ...viewport, offsetX: Number.MAX_SAFE_INTEGER }, constraints).offsetX;
358
+ const verticalMinimum = constrainViewport({ ...viewport, offsetY: -Number.MAX_SAFE_INTEGER }, constraints).offsetY;
359
+ const verticalMaximum = constrainViewport({ ...viewport, offsetY: Number.MAX_SAFE_INTEGER }, constraints).offsetY;
360
+ return {
361
+ horizontal: createScrollAxisMapping({
362
+ maximum: horizontalMaximum,
363
+ minimum: horizontalMinimum,
364
+ offset: viewport.offsetX,
365
+ scale: viewport.pixelsPerUnitX,
366
+ viewportSize: viewport.width
367
+ }),
368
+ vertical: createScrollAxisMapping({
369
+ maximum: verticalMaximum,
370
+ minimum: verticalMinimum,
371
+ offset: viewport.offsetY,
372
+ scale: viewport.pixelsPerUnitY,
373
+ viewportSize: viewport.height
374
+ })
375
+ };
376
+ }
377
+ function createScrollAxisMapping({
378
+ maximum,
379
+ minimum,
380
+ offset,
381
+ scale,
382
+ viewportSize
383
+ }) {
384
+ const range = (maximum - minimum) * scale;
385
+ return {
386
+ contentSize: viewportSize + range,
387
+ origin: -minimum * scale,
388
+ position: (offset - minimum) * scale
389
+ };
390
+ }
391
+ function areViewportsEqual(left, right) {
392
+ return left.width === right.width && left.height === right.height && left.offsetX === right.offsetX && left.offsetY === right.offsetY && left.pixelsPerUnitX === right.pixelsPerUnitX && left.pixelsPerUnitY === right.pixelsPerUnitY;
393
+ }
394
+ function areScrollPositionsEqual(left, right) {
395
+ return left.x === right.x && left.y === right.y;
396
+ }
397
+ function isRepeatedControlledFocusRevealProposal({
398
+ controlled,
399
+ focusedItemId,
400
+ previous,
401
+ sourceViewport,
402
+ viewport
403
+ }) {
404
+ return controlled && focusedItemId !== undefined && previous?.focusedItemId === focusedItemId && areViewportsEqual(previous.sourceViewport, sourceViewport) && areViewportsEqual(previous.viewport, viewport);
405
+ }
406
+ function getPinchGesture(touches, width, height, viewportOrigin) {
407
+ const [first, second] = touches;
408
+ if (!first || !second)
409
+ return;
410
+ const deltaX = second.pageX - first.pageX;
411
+ const deltaY = second.pageY - first.pageY;
412
+ const distance = Math.hypot(deltaX, deltaY);
413
+ if (!Number.isFinite(distance) || distance === 0)
414
+ return;
415
+ return {
416
+ distance,
417
+ focalPoint: {
418
+ x: Math.min(width, Math.max(0, (first.pageX + second.pageX) / 2 - viewportOrigin.x)),
419
+ y: Math.min(height, Math.max(0, (first.pageY + second.pageY) / 2 - viewportOrigin.y))
420
+ }
421
+ };
422
+ }
423
+
424
+ // src/features/grid-view/adapters/inbound/TileGrid.tsx
425
+ var import_react_native2 = __toESM(require_cjs(), 1);
426
+ import React2 from "react";
427
+
428
+ // src/features/grid-view/application/layoutTileGrid.ts
429
+ function layoutTileGrid(items, viewportWidth, tileSize, gap, zoom = 1) {
430
+ if (![viewportWidth, tileSize, gap, zoom].every(Number.isFinite) || viewportWidth < 0 || tileSize <= 0 || gap < 0 || zoom <= 0) {
431
+ throw new RangeError("Tile layout requires finite, nonnegative dimensions and positive scales.");
432
+ }
433
+ const columns = Math.max(1, Math.floor((viewportWidth / zoom + gap) / (tileSize + gap)));
434
+ const rows = Math.ceil(items.length / columns);
435
+ return {
436
+ columns,
437
+ width: columns * (tileSize + gap) - gap,
438
+ height: Math.max(0, rows * (tileSize + gap) - gap),
439
+ items: items.map((item, index) => ({
440
+ id: item.id,
441
+ x: index % columns * (tileSize + gap),
442
+ y: Math.floor(index / columns) * (tileSize + gap),
443
+ width: tileSize,
444
+ height: tileSize
445
+ }))
446
+ };
447
+ }
448
+
449
+ // src/features/grid-view/adapters/inbound/TileGrid.tsx
450
+ import { jsx as jsx2 } from "react/jsx-runtime";
451
+ function TileGrid2({
452
+ items,
453
+ width,
454
+ height = 440,
455
+ tileSize = 120,
456
+ gap = 12,
457
+ zoom = 1,
458
+ viewport,
459
+ defaultViewport,
460
+ viewportConstraints,
461
+ zoomLimits,
462
+ overscanPixels,
463
+ focusedItemId,
464
+ revealPaddingPixels,
465
+ onColumnsChange,
466
+ onViewportChange,
467
+ onVisibleItemIdsChange,
468
+ renderItem,
469
+ interactionPolicy,
470
+ testID
471
+ }) {
472
+ const [measuredWidth, setMeasuredWidth] = React2.useState(0);
473
+ const [uncontrolledPixelsPerUnitX, setUncontrolledPixelsPerUnitX] = React2.useState(() => defaultViewport?.pixelsPerUnitX ?? zoom);
474
+ const resolvedWidth = width ?? measuredWidth;
475
+ const pixelsPerUnitX = viewport?.pixelsPerUnitX ?? uncontrolledPixelsPerUnitX;
476
+ const layout = React2.useMemo(() => layoutTileGrid(items, resolvedWidth, tileSize, gap, pixelsPerUnitX), [gap, items, pixelsPerUnitX, resolvedWidth, tileSize]);
477
+ const itemLookup = React2.useMemo(() => new Map(items.map((item) => [item.id, item])), [items]);
478
+ React2.useEffect(() => {
479
+ if (resolvedWidth > 0)
480
+ onColumnsChange?.(layout.columns);
481
+ }, [layout.columns, onColumnsChange, resolvedWidth]);
482
+ const handleViewportChange = React2.useCallback((nextViewport) => {
483
+ if (viewport === undefined)
484
+ setUncontrolledPixelsPerUnitX(nextViewport.pixelsPerUnitX);
485
+ onViewportChange?.(nextViewport);
486
+ }, [onViewportChange, viewport]);
487
+ return /* @__PURE__ */ jsx2(import_react_native2.View, {
488
+ onLayout: (event) => setMeasuredWidth(event.nativeEvent.layout.width),
489
+ style: { width, height, overflow: "hidden" },
490
+ testID,
491
+ children: resolvedWidth > 0 ? /* @__PURE__ */ jsx2(GridView2, {
492
+ contentHeight: layout.height,
493
+ contentWidth: Math.max(resolvedWidth / pixelsPerUnitX, layout.width),
494
+ defaultViewport,
495
+ height,
496
+ focusedItemId,
497
+ interactionPolicy,
498
+ items: layout.items,
499
+ onVisibleItemIdsChange,
500
+ onViewportChange: handleViewportChange,
501
+ overscanPixels,
502
+ renderItem: (item) => {
503
+ const source = itemLookup.get(item.id);
504
+ return source ? renderItem(source) : null;
505
+ },
506
+ revealPaddingPixels,
507
+ width: resolvedWidth,
508
+ viewport,
509
+ viewportConstraints,
510
+ zoomLimits,
511
+ zoom
512
+ }) : null
513
+ });
514
+ }
515
+ export { GridView2, TileGrid2 };
@@ -109,6 +109,89 @@ function getLaneIntervalPlacement(lanes, interval) {
109
109
  return resolveLaneIntervalPlacement(interval, laneMetrics);
110
110
  }
111
111
 
112
+ // node_modules/@ankhorage/grid-view/dist/features/layout/utils/resolveMatrixCellPlacement.js
113
+ function resolveMatrixCellPlacement(cell, rows, columns) {
114
+ if (!cell.id) {
115
+ throw new RangeError("Matrix cells require a nonempty ID.");
116
+ }
117
+ const rowIndex = rows.indexes.get(cell.rowId);
118
+ const columnIndex = columns.indexes.get(cell.columnId);
119
+ if (rowIndex === undefined || columnIndex === undefined) {
120
+ throw new RangeError("Matrix cells must reference an existing row and column.");
121
+ }
122
+ return {
123
+ ...cell,
124
+ rowIndex,
125
+ columnIndex,
126
+ x: readGridAxisMetric(columns.offsets, columnIndex),
127
+ y: readGridAxisMetric(rows.offsets, rowIndex),
128
+ width: readGridAxisMetric(columns.sizes, columnIndex),
129
+ height: readGridAxisMetric(rows.sizes, rowIndex)
130
+ };
131
+ }
132
+
133
+ // node_modules/@ankhorage/grid-view/dist/features/layout/getVisibleMatrixCells.js
134
+ function getVisibleMatrixCells(layout, cells, viewport, overscanPixels = 0) {
135
+ const rows = createGridAxisMetrics(layout.rows);
136
+ const columns = createGridAxisMetrics(layout.columns);
137
+ validateUniqueIds(cells, "Matrix cells");
138
+ const bounds = getVisibleWorldBounds(viewport, overscanPixels);
139
+ const rowRange = getIntersectingRange(rows.offsets, rows.sizes, bounds.y, bounds.height);
140
+ const columnRange = getIntersectingRange(columns.offsets, columns.sizes, bounds.x, bounds.width);
141
+ if (rowRange === undefined || columnRange === undefined) {
142
+ return [];
143
+ }
144
+ return cells.flatMap((cell) => {
145
+ const placement = resolveMatrixCellPlacement(cell, rows, columns);
146
+ return placement.rowIndex >= rowRange.start && placement.rowIndex <= rowRange.end && placement.columnIndex >= columnRange.start && placement.columnIndex <= columnRange.end ? [placement] : [];
147
+ });
148
+ }
149
+ function validateUniqueIds(cells, label) {
150
+ const ids = new Set;
151
+ cells.forEach(({ id }) => {
152
+ if (ids.has(id)) {
153
+ throw new RangeError(`${label} require unique IDs.`);
154
+ }
155
+ ids.add(id);
156
+ });
157
+ }
158
+ function getIntersectingRange(offsets, sizes, start, extent) {
159
+ const end = start + extent;
160
+ const first = findFirstEndingAtOrAfter(offsets, sizes, start);
161
+ const last = findLastStartingAtOrBefore(offsets, end);
162
+ return first === undefined || last === undefined || first > last ? undefined : { start: first, end: last };
163
+ }
164
+ function findFirstEndingAtOrAfter(offsets, sizes, coordinate) {
165
+ let low = 0;
166
+ let high = offsets.length - 1;
167
+ let result;
168
+ while (low <= high) {
169
+ const middle = Math.floor((low + high) / 2);
170
+ if (readGridAxisMetric(offsets, middle) + readGridAxisMetric(sizes, middle) >= coordinate) {
171
+ result = middle;
172
+ high = middle - 1;
173
+ } else {
174
+ low = middle + 1;
175
+ }
176
+ }
177
+ return result;
178
+ }
179
+ function findLastStartingAtOrBefore(offsets, coordinate) {
180
+ let low = 0;
181
+ let high = offsets.length - 1;
182
+ let result;
183
+ while (low <= high) {
184
+ const middle = Math.floor((low + high) / 2);
185
+ if (readGridAxisMetric(offsets, middle) <= coordinate) {
186
+ result = middle;
187
+ low = middle + 1;
188
+ } else {
189
+ high = middle - 1;
190
+ }
191
+ }
192
+ return result;
193
+ }
194
+
112
195
  // node_modules/@ankhorage/grid-view/dist/features/viewport/constrainViewport.js
113
196
  function constrainViewport(viewport, constraints) {
114
197
  assertValidViewport(viewport);
@@ -143,6 +226,18 @@ function isAlignment(value) {
143
226
  return value === "start" || value === "center" || value === "end";
144
227
  }
145
228
 
229
+ // node_modules/@ankhorage/grid-view/dist/features/viewport/panViewport.js
230
+ function panViewport(viewport, displacement, constraints) {
231
+ if (![displacement.x, displacement.y].every(Number.isFinite)) {
232
+ throw new RangeError("Pan displacement must be finite.");
233
+ }
234
+ return constrainViewport({
235
+ ...viewport,
236
+ offsetX: viewport.offsetX - displacement.x / viewport.pixelsPerUnitX,
237
+ offsetY: viewport.offsetY - displacement.y / viewport.pixelsPerUnitY
238
+ }, constraints);
239
+ }
240
+
146
241
  // node_modules/@ankhorage/grid-view/dist/features/viewport/revealWorldRect.js
147
242
  function revealWorldRect(viewport, rect, paddingPixels = 0, constraints) {
148
243
  validateRevealInput(viewport, rect, paddingPixels);
@@ -192,6 +287,34 @@ function worldToViewport(point, viewport) {
192
287
  };
193
288
  }
194
289
 
290
+ // node_modules/@ankhorage/grid-view/dist/features/viewport/zoomViewportAt.js
291
+ function zoomViewportAt(viewport, focalPoint, nextScale, limits = {}, constraints) {
292
+ if (![focalPoint.x, focalPoint.y, nextScale.pixelsPerUnitX, nextScale.pixelsPerUnitY].every(Number.isFinite)) {
293
+ throw new RangeError("Focal points and scales must be finite.");
294
+ }
295
+ const focalWorld = viewportToWorld(focalPoint, viewport);
296
+ const x = constrainScale(nextScale.pixelsPerUnitX, limits.minX, limits.maxX);
297
+ const y = constrainScale(nextScale.pixelsPerUnitY, limits.minY, limits.maxY);
298
+ return constrainViewport({
299
+ ...viewport,
300
+ pixelsPerUnitX: x,
301
+ pixelsPerUnitY: y,
302
+ offsetX: focalWorld.x - focalPoint.x / x,
303
+ offsetY: focalWorld.y - focalPoint.y / y
304
+ }, constraints);
305
+ }
306
+ function constrainScale(scale, minimum, maximum) {
307
+ const min = minimum ?? Number.EPSILON;
308
+ const max = maximum ?? Infinity;
309
+ if (!Number.isFinite(min) || min <= 0 || maximum !== undefined && (!Number.isFinite(max) || max <= 0 || min > max)) {
310
+ throw new RangeError("Zoom limits must be finite positive ranges.");
311
+ }
312
+ if (scale <= 0) {
313
+ throw new RangeError("Viewport scales must be positive.");
314
+ }
315
+ return Math.max(min, Math.min(max, scale));
316
+ }
317
+
195
318
  // node_modules/@ankhorage/grid-view/dist/features/axes/getAxisCategoryTicks.js
196
319
  function getAxisCategoryTicks(viewport, axis, categories) {
197
320
  const bounds = getVisibleWorldBounds(viewport);
@@ -268,17 +391,23 @@ function adaptiveStep(minimum) {
268
391
  const multiplier = [1, 2, 5, 10].find((candidate) => candidate * magnitude >= minimum) ?? 10;
269
392
  return multiplier * magnitude;
270
393
  }
394
+ // node_modules/@ankhorage/grid-view/dist/features/layout/getMatrixCellPlacement.js
395
+ function getMatrixCellPlacement(layout, cell) {
396
+ const rows = createGridAxisMetrics(layout.rows);
397
+ const columns = createGridAxisMetrics(layout.columns);
398
+ return resolveMatrixCellPlacement(cell, rows, columns);
399
+ }
271
400
  // node_modules/@ankhorage/grid-view/dist/features/layout/getVisibleLaneIntervals.js
272
401
  function getVisibleLaneIntervals(lanes, intervals, viewport, overscanPixels = 0) {
273
402
  const laneMetrics = createGridAxisMetrics(lanes.map(({ id, height }) => ({ id, size: height })));
274
403
  const bounds = getVisibleWorldBounds(viewport, overscanPixels);
275
- validateUniqueIds(intervals);
404
+ validateUniqueIds2(intervals);
276
405
  return intervals.flatMap((interval) => {
277
406
  const placement = resolveLaneIntervalPlacement(interval, laneMetrics);
278
407
  return intersects(placement.x, placement.width, bounds.x, bounds.width) && intersects(placement.y, placement.height, bounds.y, bounds.height) ? [placement] : [];
279
408
  });
280
409
  }
281
- function validateUniqueIds(intervals) {
410
+ function validateUniqueIds2(intervals) {
282
411
  const ids = new Set;
283
412
  intervals.forEach(({ id }) => {
284
413
  if (ids.has(id)) {
@@ -290,4 +419,4 @@ function validateUniqueIds(intervals) {
290
419
  function intersects(firstStart, firstExtent, secondStart, secondExtent) {
291
420
  return firstStart <= secondStart + secondExtent && firstStart + firstExtent >= secondStart;
292
421
  }
293
- export { getAxisCategoryTicks, getAxisTicks, getVisibleGridItems, getLaneIntervalPlacement, getVisibleLaneIntervals, revealWorldRect, worldToViewport };
422
+ export { getAxisCategoryTicks, getAxisTicks, getVisibleGridItems, getLaneIntervalPlacement, getMatrixCellPlacement, getVisibleLaneIntervals, getVisibleMatrixCells, constrainViewport, panViewport, revealWorldRect, worldToViewport, zoomViewportAt };
@@ -6,7 +6,7 @@ import {
6
6
  getAxisCategoryTicks,
7
7
  getAxisTicks,
8
8
  worldToViewport
9
- } from "./Accordion-0my2z6qe.js";
9
+ } from "./Accordion-bz04casa.js";
10
10
  import {
11
11
  useZoraTheme2
12
12
  } from "./Accordion-srjya6dz.js";