@ankhorage/zora 25.5.0 → 25.6.0

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 (36) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +2 -1
  3. package/dist/features/grid-view/adapters/inbound/GridView.d.ts +2 -7
  4. package/dist/features/grid-view/adapters/inbound/GridView.d.ts.map +1 -1
  5. package/dist/features/grid-view/adapters/inbound/GridView.js +309 -51
  6. package/dist/features/grid-view/adapters/inbound/GridView.js.map +1 -1
  7. package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts +1 -1
  8. package/dist/features/grid-view/adapters/inbound/TileGrid.d.ts.map +1 -1
  9. package/dist/features/grid-view/adapters/inbound/TileGrid.js +11 -4
  10. package/dist/features/grid-view/adapters/inbound/TileGrid.js.map +1 -1
  11. package/dist/types/grid-view.d.ts +18 -1
  12. package/dist/types/grid-view.d.ts.map +1 -1
  13. package/dist/types/grid-view.js.map +1 -1
  14. package/package.json +1 -1
  15. package/src/features/grid-view/adapters/inbound/GridView.interaction.test.tsx +585 -0
  16. package/src/features/grid-view/adapters/inbound/GridView.test.tsx +74 -0
  17. package/src/features/grid-view/adapters/inbound/GridView.tsx +506 -77
  18. package/src/features/grid-view/adapters/inbound/TileGrid.tsx +26 -3
  19. package/src/features/time-grid/adapters/inbound/TimeGrid.test.tsx +35 -8
  20. package/src/types/grid-view.ts +27 -1
  21. package/web-dist/chunks/{Accordion-0my2z6qe.js → Accordion-ebghcyzj.js} +41 -1
  22. package/web-dist/chunks/{Accordion-d6azgz09.js → Accordion-f43jba23.js} +1 -1
  23. package/web-dist/chunks/Accordion-q8exgc3h.js +515 -0
  24. package/web-dist/chunks/{Accordion-7qfd4cb4.js → Accordion-szar8dt5.js} +1 -1
  25. package/web-dist/components/explorer/Explorer.js +2 -2
  26. package/web-dist/components/file-explorer/FileExplorer.js +2 -2
  27. package/web-dist/components/grid-line-overlay/GridLineOverlay.js +1 -1
  28. package/web-dist/components/grid-ruler/GridRuler.js +1 -1
  29. package/web-dist/components/grid-view/GridView.js +1 -1
  30. package/web-dist/components/media-explorer/MediaExplorer.js +2 -2
  31. package/web-dist/components/spatial-grid/SpatialGrid.js +1 -1
  32. package/web-dist/components/tile-grid/TileGrid.js +1 -1
  33. package/web-dist/components/time-grid/TimeGrid.js +2 -2
  34. package/web-dist/components/uploader/Uploader.js +2 -2
  35. package/web-dist/manifest.json +24 -24
  36. 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-ebghcyzj.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 };
@@ -6,7 +6,7 @@ import {
6
6
  getAxisCategoryTicks,
7
7
  getAxisTicks,
8
8
  worldToViewport
9
- } from "./Accordion-0my2z6qe.js";
9
+ } from "./Accordion-ebghcyzj.js";
10
10
  import {
11
11
  useZoraTheme2
12
12
  } from "./Accordion-srjya6dz.js";
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import"../../chunks/Accordion-gxj5qbpr.js";
2
+ import"../../chunks/Accordion-q8exgc3h.js";
3
3
  import"../../chunks/Accordion-bfzeab9x.js";
4
4
  import"../../chunks/Accordion-6wrr910w.js";
5
5
  import"../../chunks/Accordion-8f0nekwe.js";
@@ -14,7 +14,7 @@ import {
14
14
  Explorer2,
15
15
  FileExplorer2,
16
16
  MediaExplorer2
17
- } from "../../chunks/Accordion-d6azgz09.js";
17
+ } from "../../chunks/Accordion-f43jba23.js";
18
18
  import"../../chunks/Accordion-bff0p3x4.js";
19
19
  import"../../chunks/Accordion-srjya6dz.js";
20
20
  import"../../chunks/Accordion-184r2r82.js";
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import"../../chunks/Accordion-gxj5qbpr.js";
2
+ import"../../chunks/Accordion-q8exgc3h.js";
3
3
  import"../../chunks/Accordion-bfzeab9x.js";
4
4
  import"../../chunks/Accordion-6wrr910w.js";
5
5
  import"../../chunks/Accordion-8f0nekwe.js";
@@ -14,7 +14,7 @@ import {
14
14
  Explorer2,
15
15
  FileExplorer2,
16
16
  MediaExplorer2
17
- } from "../../chunks/Accordion-d6azgz09.js";
17
+ } from "../../chunks/Accordion-f43jba23.js";
18
18
  import"../../chunks/Accordion-bff0p3x4.js";
19
19
  import"../../chunks/Accordion-srjya6dz.js";
20
20
  import"../../chunks/Accordion-184r2r82.js";
@@ -4,7 +4,7 @@ import"../../chunks/Accordion-42jfy1a1.js";
4
4
  import {
5
5
  GridLineOverlay2,
6
6
  GridRuler2
7
- } from "../../chunks/Accordion-7qfd4cb4.js";
7
+ } from "../../chunks/Accordion-szar8dt5.js";
8
8
  import"../../chunks/Accordion-srjya6dz.js";
9
9
  import"../../chunks/Accordion-xgpzh4wq.js";
10
10
  export {
@@ -4,7 +4,7 @@ import"../../chunks/Accordion-42jfy1a1.js";
4
4
  import {
5
5
  GridLineOverlay2,
6
6
  GridRuler2
7
- } from "../../chunks/Accordion-7qfd4cb4.js";
7
+ } from "../../chunks/Accordion-szar8dt5.js";
8
8
  import"../../chunks/Accordion-srjya6dz.js";
9
9
  import"../../chunks/Accordion-xgpzh4wq.js";
10
10
  export {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  GridView2,
4
4
  TileGrid2
5
- } from "../../chunks/Accordion-gxj5qbpr.js";
5
+ } from "../../chunks/Accordion-q8exgc3h.js";
6
6
  import"../../chunks/Accordion-xgpzh4wq.js";
7
7
  export {
8
8
  GridView2 as GridView,
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import"../../chunks/Accordion-gxj5qbpr.js";
2
+ import"../../chunks/Accordion-q8exgc3h.js";
3
3
  import"../../chunks/Accordion-bfzeab9x.js";
4
4
  import"../../chunks/Accordion-6wrr910w.js";
5
5
  import"../../chunks/Accordion-8f0nekwe.js";
@@ -14,7 +14,7 @@ import {
14
14
  Explorer2,
15
15
  FileExplorer2,
16
16
  MediaExplorer2
17
- } from "../../chunks/Accordion-d6azgz09.js";
17
+ } from "../../chunks/Accordion-f43jba23.js";
18
18
  import"../../chunks/Accordion-bff0p3x4.js";
19
19
  import"../../chunks/Accordion-srjya6dz.js";
20
20
  import"../../chunks/Accordion-184r2r82.js";
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import {
3
3
  GridView2
4
- } from "../../chunks/Accordion-gxj5qbpr.js";
4
+ } from "../../chunks/Accordion-q8exgc3h.js";
5
5
  import {
6
6
  require_cjs
7
7
  } from "../../chunks/Accordion-xgpzh4wq.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  GridView2,
4
4
  TileGrid2
5
- } from "../../chunks/Accordion-gxj5qbpr.js";
5
+ } from "../../chunks/Accordion-q8exgc3h.js";
6
6
  import"../../chunks/Accordion-xgpzh4wq.js";
7
7
  export {
8
8
  GridView2 as GridView,
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
  import {
3
3
  GridView2
4
- } from "../../chunks/Accordion-gxj5qbpr.js";
4
+ } from "../../chunks/Accordion-q8exgc3h.js";
5
5
  import {
6
6
  getLaneIntervalPlacement,
7
7
  getVisibleLaneIntervals
8
- } from "../../chunks/Accordion-0my2z6qe.js";
8
+ } from "../../chunks/Accordion-ebghcyzj.js";
9
9
  import {
10
10
  require_cjs
11
11
  } from "../../chunks/Accordion-xgpzh4wq.js";
@@ -25,7 +25,7 @@ import {
25
25
  import {
26
26
  Text3
27
27
  } from "../../chunks/Accordion-9w8wg9mf.js";
28
- import"../../chunks/Accordion-gxj5qbpr.js";
28
+ import"../../chunks/Accordion-q8exgc3h.js";
29
29
  import {
30
30
  Icon2
31
31
  } from "../../chunks/Accordion-b96evb46.js";
@@ -34,7 +34,7 @@ import {
34
34
  } from "../../chunks/Accordion-a4cma5b6.js";
35
35
  import {
36
36
  Explorer2
37
- } from "../../chunks/Accordion-d6azgz09.js";
37
+ } from "../../chunks/Accordion-f43jba23.js";
38
38
  import"../../chunks/Accordion-40tenzcg.js";
39
39
  import"../../chunks/Accordion-45nc4bte.js";
40
40
  import {