@thangdevalone/meet-layout-grid-core 1.0.9 → 1.1.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.
package/dist/index.cjs CHANGED
@@ -18,6 +18,212 @@ function parseAspectRatio(ratio) {
18
18
  }
19
19
  return { widthRatio: width, heightRatio: height };
20
20
  }
21
+ function calculateContentDimensions(cellDimensions, itemRatio, defaultRatio) {
22
+ const { width: cellW, height: cellH } = cellDimensions;
23
+ const effectiveRatio = itemRatio ?? (defaultRatio ? defaultRatio : void 0);
24
+ if (!effectiveRatio || effectiveRatio === "fill" || effectiveRatio === "auto") {
25
+ return {
26
+ width: cellW,
27
+ height: cellH,
28
+ offsetTop: 0,
29
+ offsetLeft: 0
30
+ };
31
+ }
32
+ const ratio = getAspectRatio(effectiveRatio);
33
+ let contentW = cellW;
34
+ let contentH = contentW * ratio;
35
+ if (contentH > cellH) {
36
+ contentH = cellH;
37
+ contentW = contentH / ratio;
38
+ }
39
+ const offsetTop = (cellH - contentH) / 2;
40
+ const offsetLeft = (cellW - contentW) / 2;
41
+ return {
42
+ width: contentW,
43
+ height: contentH,
44
+ offsetTop,
45
+ offsetLeft
46
+ };
47
+ }
48
+ function createGetItemContentDimensions(getItemDimensions, itemAspectRatios, defaultRatio) {
49
+ return (index, itemRatio) => {
50
+ const cellDimensions = getItemDimensions(index);
51
+ const effectiveRatio = itemRatio ?? itemAspectRatios?.[index] ?? defaultRatio;
52
+ return calculateContentDimensions(cellDimensions, effectiveRatio, defaultRatio);
53
+ };
54
+ }
55
+ function calculateFlexLayout(options) {
56
+ const { dimensions, count, aspectRatio, gap, itemAspectRatios, preferHorizontal } = options;
57
+ if (count === 0 || dimensions.width === 0 || dimensions.height === 0) {
58
+ return [];
59
+ }
60
+ const containerWidth = dimensions.width - gap * 2;
61
+ const containerHeight = dimensions.height - gap * 2;
62
+ const getItemAspectValue = (index) => {
63
+ const itemRatio = itemAspectRatios?.[index] ?? aspectRatio;
64
+ if (!itemRatio || itemRatio === "fill" || itemRatio === "auto") {
65
+ return 16 / 9;
66
+ }
67
+ const parsed = parseAspectRatio(itemRatio);
68
+ return parsed ? parsed.widthRatio / parsed.heightRatio : 16 / 9;
69
+ };
70
+ const aspectValues = [];
71
+ for (let i = 0; i < count; i++) {
72
+ aspectValues.push(getItemAspectValue(i));
73
+ }
74
+ const avgAspect = aspectValues.reduce((a, b) => a + b, 0) / count;
75
+ const containerAspect = containerWidth / containerHeight;
76
+ let numRows;
77
+ if (preferHorizontal) {
78
+ const sumAspects = aspectValues.reduce((a, b) => a + b, 0);
79
+ const singleRowHeight = containerWidth / sumAspects;
80
+ if (singleRowHeight <= containerHeight) {
81
+ numRows = 1;
82
+ } else {
83
+ numRows = Math.ceil(Math.sqrt(count * containerHeight / containerWidth / avgAspect));
84
+ numRows = Math.max(1, Math.min(count, numRows));
85
+ }
86
+ } else {
87
+ numRows = Math.round(Math.sqrt(count / (containerAspect / avgAspect)));
88
+ numRows = Math.max(1, Math.min(count, numRows));
89
+ }
90
+ const itemsPerRow = Math.ceil(count / numRows);
91
+ const rows = [];
92
+ for (let i = 0; i < count; i += itemsPerRow) {
93
+ const row = [];
94
+ for (let j = i; j < Math.min(i + itemsPerRow, count); j++) {
95
+ row.push(j);
96
+ }
97
+ rows.push(row);
98
+ }
99
+ const rowHeights = [];
100
+ for (const row of rows) {
101
+ const sumAspects = row.reduce((sum, idx) => sum + aspectValues[idx], 0);
102
+ const totalGapWidth = (row.length - 1) * gap;
103
+ const height = (containerWidth - totalGapWidth) / sumAspects;
104
+ rowHeights.push(height);
105
+ }
106
+ const totalGapHeight = (rows.length - 1) * gap;
107
+ const totalNaturalHeight = rowHeights.reduce((a, b) => a + b, 0);
108
+ const scale = Math.min(1, (containerHeight - totalGapHeight) / totalNaturalHeight);
109
+ for (let i = 0; i < rowHeights.length; i++) {
110
+ rowHeights[i] *= scale;
111
+ }
112
+ const totalScaledHeight = rowHeights.reduce((a, b) => a + b, 0) + totalGapHeight;
113
+ const verticalOffset = (containerHeight - totalScaledHeight) / 2;
114
+ const items = [];
115
+ let currentTop = gap + verticalOffset;
116
+ for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
117
+ const row = rows[rowIndex];
118
+ const rowHeight = rowHeights[rowIndex];
119
+ let rowWidth = 0;
120
+ for (const idx of row) {
121
+ rowWidth += rowHeight * aspectValues[idx];
122
+ }
123
+ rowWidth += (row.length - 1) * gap;
124
+ const horizontalOffset = (containerWidth - rowWidth) / 2;
125
+ let currentLeft = gap + horizontalOffset;
126
+ for (const itemIndex of row) {
127
+ const aspect = aspectValues[itemIndex];
128
+ const itemWidth = rowHeight * aspect;
129
+ items[itemIndex] = {
130
+ index: itemIndex,
131
+ width: itemWidth,
132
+ height: rowHeight,
133
+ left: currentLeft,
134
+ top: currentTop,
135
+ row: rowIndex,
136
+ widthFactor: aspect
137
+ };
138
+ currentLeft += itemWidth + gap;
139
+ }
140
+ currentTop += rowHeight + gap;
141
+ }
142
+ return items;
143
+ }
144
+ function calculateFlexStrip(options) {
145
+ const { dimensions, count, aspectRatio, gap, itemAspectRatios, direction, offset = { left: 0, top: 0 } } = options;
146
+ if (count === 0 || dimensions.width === 0 || dimensions.height === 0) {
147
+ return [];
148
+ }
149
+ const stripWidth = dimensions.width;
150
+ const stripHeight = dimensions.height;
151
+ const getItemAspectValue = (index) => {
152
+ const itemRatio = itemAspectRatios?.[index] ?? aspectRatio;
153
+ if (!itemRatio || itemRatio === "fill" || itemRatio === "auto") {
154
+ return 16 / 9;
155
+ }
156
+ const parsed = parseAspectRatio(itemRatio);
157
+ return parsed ? parsed.widthRatio / parsed.heightRatio : 16 / 9;
158
+ };
159
+ const aspectValues = [];
160
+ for (let i = 0; i < count; i++) {
161
+ aspectValues.push(getItemAspectValue(i));
162
+ }
163
+ const items = [];
164
+ if (direction === "horizontal") {
165
+ const availableHeight = stripHeight;
166
+ const totalGaps = (count - 1) * gap;
167
+ let totalNaturalWidth = 0;
168
+ for (let i = 0; i < count; i++) {
169
+ totalNaturalWidth += availableHeight * aspectValues[i];
170
+ }
171
+ totalNaturalWidth += totalGaps;
172
+ let scale = (stripWidth - totalGaps) / (totalNaturalWidth - totalGaps);
173
+ scale = Math.min(scale, 2);
174
+ const itemHeight = availableHeight * scale;
175
+ let scaledTotalWidth = totalGaps;
176
+ for (let i = 0; i < count; i++) {
177
+ scaledTotalWidth += itemHeight * aspectValues[i];
178
+ }
179
+ let currentLeft = offset.left + (stripWidth - scaledTotalWidth) / 2;
180
+ const itemTop = offset.top + (stripHeight - itemHeight) / 2;
181
+ for (let i = 0; i < count; i++) {
182
+ const itemWidth = itemHeight * aspectValues[i];
183
+ items[i] = {
184
+ index: i,
185
+ width: itemWidth,
186
+ height: itemHeight,
187
+ left: currentLeft,
188
+ top: itemTop,
189
+ row: 0,
190
+ widthFactor: aspectValues[i]
191
+ };
192
+ currentLeft += itemWidth + gap;
193
+ }
194
+ } else {
195
+ const availableWidth = stripWidth;
196
+ const totalGaps = (count - 1) * gap;
197
+ let totalNaturalHeight = 0;
198
+ for (let i = 0; i < count; i++) {
199
+ totalNaturalHeight += availableWidth / aspectValues[i];
200
+ }
201
+ totalNaturalHeight += totalGaps;
202
+ let scale = (stripHeight - totalGaps) / (totalNaturalHeight - totalGaps);
203
+ scale = Math.min(scale, 2);
204
+ const itemWidth = availableWidth * scale;
205
+ let scaledTotalHeight = totalGaps;
206
+ for (let i = 0; i < count; i++) {
207
+ scaledTotalHeight += itemWidth / aspectValues[i];
208
+ }
209
+ let currentTop = offset.top + (stripHeight - scaledTotalHeight) / 2;
210
+ const itemLeft = offset.left + (stripWidth - itemWidth) / 2;
211
+ for (let i = 0; i < count; i++) {
212
+ const itemHeight = itemWidth / aspectValues[i];
213
+ items[i] = {
214
+ index: i,
215
+ width: itemWidth,
216
+ height: itemHeight,
217
+ left: itemLeft,
218
+ top: currentTop,
219
+ row: i,
220
+ widthFactor: aspectValues[i]
221
+ };
222
+ currentTop += itemHeight + gap;
223
+ }
224
+ }
225
+ return items;
226
+ }
21
227
  function getGridItemDimensions({
22
228
  count,
23
229
  dimensions,
@@ -37,8 +243,7 @@ function getGridItemDimensions({
37
243
  let h = 0;
38
244
  let a = 1;
39
245
  let b = 1;
40
- const isPortrait = H > W;
41
- const minCols = N >= 2 && isPortrait ? 2 : 1;
246
+ const minCols = 1;
42
247
  const widths = [];
43
248
  for (let n = 1; n <= N; n++) {
44
249
  widths.push((W - s * (n - 1)) / n, (H - s * (n - 1)) / (n * r));
@@ -131,20 +336,30 @@ function createGrid({ aspectRatio, count, dimensions, gap }) {
131
336
  };
132
337
  }
133
338
  function createSidebarGrid(options) {
134
- const { dimensions, gap, aspectRatio, count, sidebarPosition = "right", sidebarRatio = 0.25, pinnedIndex = 0, maxVisibleOthers = 0, currentOthersPage = 0 } = options;
339
+ const { dimensions, gap, aspectRatio, count, sidebarPosition = "right", sidebarRatio = 0.25, pinnedIndex = 0, maxVisible = 0, currentVisiblePage = 0, flexLayout = false, itemAspectRatios } = options;
135
340
  if (count === 0) {
136
341
  return createEmptyMeetGridResult("sidebar");
137
342
  }
138
343
  if (count === 1) {
139
- const grid = createGrid({ ...options, count: 1 });
344
+ const { width: W2, height: H2 } = dimensions;
345
+ const mainWidth2 = W2 - gap * 2;
346
+ const mainHeight2 = H2 - gap * 2;
347
+ const getItemDimensions2 = () => ({ width: mainWidth2, height: mainHeight2 });
140
348
  const pagination2 = createDefaultPagination(1);
141
349
  return {
142
- ...grid,
350
+ width: mainWidth2,
351
+ height: mainHeight2,
352
+ rows: 1,
353
+ cols: 1,
143
354
  layoutMode: "sidebar",
144
- getItemDimensions: () => ({ width: grid.width, height: grid.height }),
355
+ getPosition: () => ({ top: gap, left: gap }),
356
+ getItemDimensions: getItemDimensions2,
145
357
  isMainItem: () => true,
146
358
  pagination: pagination2,
147
- isItemVisible: () => true
359
+ isItemVisible: () => true,
360
+ hiddenCount: 0,
361
+ getLastVisibleOthersIndex: () => -1,
362
+ getItemContentDimensions: createGetItemContentDimensions(getItemDimensions2, options.itemAspectRatios, aspectRatio)
148
363
  };
149
364
  }
150
365
  const { width: W, height: H } = dimensions;
@@ -155,76 +370,84 @@ function createSidebarGrid(options) {
155
370
  let sidebarWidth;
156
371
  let sidebarHeight;
157
372
  if (isVertical) {
158
- mainHeight = H * (1 - sidebarRatio) - gap;
159
- mainWidth = W - gap * 2;
160
- sidebarHeight = H * sidebarRatio - gap;
161
- sidebarWidth = W - gap * 2;
373
+ const totalOthersCalc = count - 1;
374
+ const visibleOthersCalc = maxVisible > 0 ? Math.min(maxVisible, totalOthersCalc) : totalOthersCalc;
375
+ const baseSidebarW = W - gap * 2;
376
+ const targetRatio = 1 / ratio;
377
+ const isPortraitMode = H > W * 1.2;
378
+ const maxSidebarRatio = isPortraitMode ? 0.45 : 0.38;
379
+ const minSidebarRatio = isPortraitMode ? 0.25 : 0.18;
380
+ const minThumbH = isPortraitMode ? 70 : 60;
381
+ let bestSidebarH = 0;
382
+ let bestThumbArea = 0;
383
+ const maxRows = Math.min(3, visibleOthersCalc || 1);
384
+ for (let rows = 1; rows <= maxRows; rows++) {
385
+ const cols = Math.ceil((visibleOthersCalc || 1) / rows);
386
+ const thumbW = (baseSidebarW - (cols - 1) * gap) / cols;
387
+ const thumbH = thumbW / targetRatio;
388
+ const requiredSidebarH = rows * thumbH + (rows - 1) * gap + gap * 2;
389
+ const sidebarRatioCalc = requiredSidebarH / H;
390
+ if (sidebarRatioCalc > maxSidebarRatio + 0.05 || thumbH < minThumbH)
391
+ continue;
392
+ const thumbArea = thumbW * thumbH;
393
+ if (thumbArea > bestThumbArea) {
394
+ bestThumbArea = thumbArea;
395
+ bestSidebarH = requiredSidebarH;
396
+ }
397
+ }
398
+ if (bestSidebarH === 0) {
399
+ bestSidebarH = H * (isPortraitMode ? 0.3 : 0.25);
400
+ }
401
+ if (bestSidebarH / H < minSidebarRatio)
402
+ bestSidebarH = H * minSidebarRatio;
403
+ else if (bestSidebarH / H > maxSidebarRatio)
404
+ bestSidebarH = H * maxSidebarRatio;
405
+ sidebarHeight = bestSidebarH;
406
+ sidebarWidth = baseSidebarW;
407
+ mainHeight = H - sidebarHeight - gap * 3;
408
+ mainWidth = baseSidebarW;
162
409
  } else {
163
- mainWidth = W * (1 - sidebarRatio) - gap * 2;
164
- mainHeight = H - gap * 2;
165
- sidebarWidth = W * sidebarRatio - gap;
166
- sidebarHeight = H - gap * 2;
167
- }
168
- let mainItemWidth = mainWidth;
169
- let mainItemHeight = mainItemWidth * ratio;
170
- if (mainItemHeight > mainHeight) {
171
- mainItemHeight = mainHeight;
172
- mainItemWidth = mainItemHeight / ratio;
410
+ const totalOthersCalc = count - 1;
411
+ const visibleOthersCalc = maxVisible > 0 ? Math.min(maxVisible, totalOthersCalc) : totalOthersCalc;
412
+ const baseSidebarH = H - gap * 2;
413
+ let bestSidebarW = W * sidebarRatio - gap;
414
+ let bestScore = 0;
415
+ const maxCols = Math.min(3, visibleOthersCalc || 1);
416
+ for (let cols = 1; cols <= maxCols; cols++) {
417
+ const rows = Math.ceil((visibleOthersCalc || 1) / cols);
418
+ const thumbH = (baseSidebarH - (rows - 1) * gap) / rows;
419
+ const thumbW = thumbH / ratio;
420
+ const requiredSidebarW = cols * thumbW + (cols - 1) * gap + gap * 2;
421
+ const sidebarRatioTest = requiredSidebarW / W;
422
+ const thumbArea = thumbW * thumbH;
423
+ const mainAreaBonus = (1 - sidebarRatioTest) * 0.5;
424
+ const score = thumbArea * (1 + mainAreaBonus);
425
+ if (sidebarRatioTest >= 0.12 && sidebarRatioTest <= 0.4 && score > bestScore) {
426
+ bestSidebarW = requiredSidebarW;
427
+ bestScore = score;
428
+ }
429
+ }
430
+ if (bestSidebarW / W < 0.12)
431
+ bestSidebarW = W * 0.15;
432
+ else if (bestSidebarW / W > 0.4)
433
+ bestSidebarW = W * 0.35;
434
+ sidebarWidth = bestSidebarW;
435
+ sidebarHeight = baseSidebarH;
436
+ mainWidth = W - sidebarWidth - gap * 2;
437
+ mainHeight = baseSidebarH;
173
438
  }
439
+ const mainItemWidth = mainWidth;
440
+ const mainItemHeight = mainHeight;
174
441
  const totalOthers = count - 1;
175
- const visibleOthers = maxVisibleOthers > 0 ? Math.min(maxVisibleOthers, totalOthers) : totalOthers;
176
- const othersTotalPages = maxVisibleOthers > 0 ? Math.ceil(totalOthers / maxVisibleOthers) : 1;
177
- const safeCurrentOthersPage = Math.min(currentOthersPage, Math.max(0, othersTotalPages - 1));
178
- const startOthersIndex = safeCurrentOthersPage * maxVisibleOthers;
442
+ const visibleOthers = maxVisible > 0 ? Math.min(maxVisible, totalOthers) : totalOthers;
443
+ const othersTotalPages = maxVisible > 0 ? Math.ceil(totalOthers / maxVisible) : 1;
444
+ const safeCurrentVisiblePage = Math.min(currentVisiblePage, Math.max(0, othersTotalPages - 1));
445
+ const startOthersIndex = safeCurrentVisiblePage * (maxVisible > 0 ? maxVisible : totalOthers);
179
446
  const endOthersIndex = Math.min(startOthersIndex + visibleOthers, totalOthers);
180
447
  const itemsOnPage = endOthersIndex - startOthersIndex;
181
- const hiddenCount = totalOthers - itemsOnPage;
182
- let thumbCols = 1;
183
- let thumbRows = 1;
184
- let thumbWidth = 0;
185
- let thumbHeight = 0;
186
- if (visibleOthers > 0) {
187
- let bestArea = 0;
188
- if (isVertical) {
189
- for (let cols = 1; cols <= visibleOthers; cols++) {
190
- const rows = Math.ceil(visibleOthers / cols);
191
- const maxTileW = (sidebarWidth - (cols - 1) * gap) / cols;
192
- const maxTileH = (sidebarHeight - (rows - 1) * gap) / rows;
193
- let tileW = maxTileW;
194
- let tileH = tileW * ratio;
195
- if (tileH > maxTileH) {
196
- tileH = maxTileH;
197
- tileW = tileH / ratio;
198
- }
199
- if (tileW * tileH > bestArea) {
200
- bestArea = tileW * tileH;
201
- thumbCols = cols;
202
- thumbRows = rows;
203
- thumbWidth = tileW;
204
- thumbHeight = tileH;
205
- }
206
- }
207
- } else {
208
- for (let rows = 1; rows <= visibleOthers; rows++) {
209
- const cols = Math.ceil(visibleOthers / rows);
210
- const maxTileH = (sidebarHeight - (rows - 1) * gap) / rows;
211
- const maxTileW = (sidebarWidth - (cols - 1) * gap) / cols;
212
- let tileH = maxTileH;
213
- let tileW = tileH / ratio;
214
- if (tileW > maxTileW) {
215
- tileW = maxTileW;
216
- tileH = tileW * ratio;
217
- }
218
- if (tileW * tileH > bestArea) {
219
- bestArea = tileW * tileH;
220
- thumbCols = cols;
221
- thumbRows = rows;
222
- thumbWidth = tileW;
223
- thumbHeight = tileH;
224
- }
225
- }
226
- }
227
- }
448
+ const isPaginationMode = othersTotalPages > 1;
449
+ const isActivelyPaginating = isPaginationMode && currentVisiblePage > 0;
450
+ const hiddenCount = isActivelyPaginating ? 0 : totalOthers > itemsOnPage ? totalOthers - itemsOnPage + 1 : 0;
228
451
  const positions = [];
229
452
  let mainLeft;
230
453
  let mainTop;
@@ -239,68 +462,200 @@ function createSidebarGrid(options) {
239
462
  position: { top: mainTop, left: mainLeft },
240
463
  dimensions: { width: mainItemWidth, height: mainItemHeight }
241
464
  };
242
- const totalGridWidth = thumbCols * thumbWidth + (thumbCols - 1) * gap;
243
- const totalGridHeight = thumbRows * thumbHeight + (thumbRows - 1) * gap;
244
- let gridStartLeft;
245
- let gridStartTop;
465
+ let sidebarOffsetLeft;
466
+ let sidebarOffsetTop;
246
467
  if (isVertical) {
247
- gridStartLeft = gap + (sidebarWidth - totalGridWidth) / 2;
248
- gridStartTop = sidebarPosition === "top" ? gap + (sidebarHeight - totalGridHeight) / 2 : mainHeight + gap * 2 + (sidebarHeight - totalGridHeight) / 2;
468
+ sidebarOffsetLeft = gap;
469
+ sidebarOffsetTop = sidebarPosition === "top" ? gap : mainHeight + gap * 2;
249
470
  } else {
250
- gridStartLeft = sidebarPosition === "left" ? gap + (sidebarWidth - totalGridWidth) / 2 : mainWidth + gap * 2 + (sidebarWidth - totalGridWidth) / 2;
251
- gridStartTop = gap + (sidebarHeight - totalGridHeight) / 2;
471
+ sidebarOffsetLeft = sidebarPosition === "left" ? gap : mainWidth + gap * 2;
472
+ sidebarOffsetTop = gap;
252
473
  }
253
- let sidebarIndex = 0;
254
- for (let i = 0; i < count; i++) {
255
- if (i === pinnedIndex)
256
- continue;
257
- const isInVisibleRange = sidebarIndex >= startOthersIndex && sidebarIndex < endOthersIndex;
258
- if (isInVisibleRange) {
259
- const pageRelativeIndex = sidebarIndex - startOthersIndex;
260
- const row = Math.floor(pageRelativeIndex / thumbCols);
261
- const col = pageRelativeIndex % thumbCols;
262
- const itemsInLastRow = itemsOnPage % thumbCols || thumbCols;
263
- let rowLeft = gridStartLeft;
264
- const lastRowIndex = Math.ceil(itemsOnPage / thumbCols) - 1;
265
- if (row === lastRowIndex && itemsInLastRow < thumbCols) {
266
- const rowWidth = itemsInLastRow * thumbWidth + (itemsInLastRow - 1) * gap;
267
- if (isVertical) {
268
- rowLeft = gap + (sidebarWidth - rowWidth) / 2;
269
- } else {
270
- rowLeft = (sidebarPosition === "left" ? gap : mainWidth + gap * 2) + (sidebarWidth - rowWidth) / 2;
271
- }
474
+ if (flexLayout && itemAspectRatios && itemsOnPage > 0) {
475
+ const othersAspectRatios = [];
476
+ const originalIndices = [];
477
+ let othersIdx = 0;
478
+ for (let i = 0; i < count; i++) {
479
+ if (i === pinnedIndex)
480
+ continue;
481
+ if (othersIdx >= startOthersIndex && othersIdx < endOthersIndex) {
482
+ othersAspectRatios.push(itemAspectRatios[i]);
483
+ originalIndices.push(i);
272
484
  }
273
- positions[i] = {
485
+ othersIdx++;
486
+ }
487
+ const flexItems = calculateFlexLayout({
488
+ dimensions: { width: sidebarWidth + gap * 2, height: sidebarHeight + gap * 2 },
489
+ count: itemsOnPage,
490
+ aspectRatio,
491
+ gap,
492
+ itemAspectRatios: othersAspectRatios,
493
+ preferHorizontal: isVertical
494
+ // bottom/top sidebars should use horizontal layout
495
+ });
496
+ for (let i = 0; i < flexItems.length; i++) {
497
+ const originalIndex = originalIndices[i];
498
+ const flexItem = flexItems[i];
499
+ positions[originalIndex] = {
274
500
  position: {
275
- top: gridStartTop + row * (thumbHeight + gap),
276
- left: rowLeft + col * (thumbWidth + gap)
501
+ top: flexItem.top + sidebarOffsetTop - gap,
502
+ left: flexItem.left + sidebarOffsetLeft - gap
277
503
  },
278
- dimensions: { width: thumbWidth, height: thumbHeight }
504
+ dimensions: { width: flexItem.width, height: flexItem.height }
279
505
  };
506
+ }
507
+ let sidebarIndex = 0;
508
+ for (let i = 0; i < count; i++) {
509
+ if (i === pinnedIndex)
510
+ continue;
511
+ const isInVisibleRange = sidebarIndex >= startOthersIndex && sidebarIndex < endOthersIndex;
512
+ if (!isInVisibleRange) {
513
+ positions[i] = {
514
+ position: { top: -9999, left: -9999 },
515
+ dimensions: { width: 0, height: 0 }
516
+ };
517
+ }
518
+ sidebarIndex++;
519
+ }
520
+ } else {
521
+ let thumbCols = 1;
522
+ let thumbRows = 1;
523
+ let thumbWidth = 0;
524
+ let thumbHeight = 0;
525
+ if (visibleOthers > 0) {
526
+ if (isVertical) {
527
+ let bestScore = -1;
528
+ for (let cols = 1; cols <= visibleOthers; cols++) {
529
+ const rows = Math.ceil(visibleOthers / cols);
530
+ const maxTileW = (sidebarWidth - (cols - 1) * gap) / cols;
531
+ const maxTileH = (sidebarHeight - (rows - 1) * gap) / rows;
532
+ let tileW = maxTileW;
533
+ let tileH = tileW * ratio;
534
+ if (tileH > maxTileH) {
535
+ tileH = maxTileH;
536
+ tileW = tileH / ratio;
537
+ }
538
+ const area = tileW * tileH;
539
+ const itemRatio = tileW / tileH;
540
+ const idealRatio = 16 / 9;
541
+ const ratioScore = 1 / (1 + Math.abs(Math.log(itemRatio / idealRatio)));
542
+ const colsMultiplier = cols >= rows ? 1.5 : 0.5;
543
+ const score = area * ratioScore * colsMultiplier;
544
+ if (score > bestScore) {
545
+ bestScore = score;
546
+ thumbCols = cols;
547
+ thumbRows = rows;
548
+ thumbWidth = tileW;
549
+ thumbHeight = tileH;
550
+ }
551
+ }
552
+ } else {
553
+ let bestScore = -1;
554
+ const targetRatio = 1 / ratio;
555
+ for (let rows = 1; rows <= visibleOthers; rows++) {
556
+ const cols = Math.ceil(visibleOthers / rows);
557
+ const maxTileH = (sidebarHeight - (rows - 1) * gap) / rows;
558
+ const idealTileW = maxTileH * targetRatio;
559
+ const maxTileW = (sidebarWidth - (cols - 1) * gap) / cols;
560
+ let tileW, tileH;
561
+ if (idealTileW <= maxTileW) {
562
+ tileW = idealTileW;
563
+ tileH = maxTileH;
564
+ } else {
565
+ tileW = maxTileW;
566
+ tileH = tileW / targetRatio;
567
+ }
568
+ const area = tileW * tileH * visibleOthers;
569
+ const score = area;
570
+ if (score > bestScore) {
571
+ bestScore = score;
572
+ thumbCols = cols;
573
+ thumbRows = rows;
574
+ thumbWidth = tileW;
575
+ thumbHeight = tileH;
576
+ }
577
+ }
578
+ }
579
+ }
580
+ const totalGridWidth = thumbCols * thumbWidth + (thumbCols - 1) * gap;
581
+ const totalGridHeight = thumbRows * thumbHeight + (thumbRows - 1) * gap;
582
+ let gridStartLeft;
583
+ let gridStartTop;
584
+ if (isVertical) {
585
+ gridStartLeft = gap + (sidebarWidth - totalGridWidth) / 2;
586
+ gridStartTop = sidebarPosition === "top" ? gap + (sidebarHeight - totalGridHeight) / 2 : mainHeight + gap * 2 + (sidebarHeight - totalGridHeight) / 2;
280
587
  } else {
281
- positions[i] = {
282
- position: { top: -9999, left: -9999 },
283
- dimensions: { width: 0, height: 0 }
284
- };
588
+ gridStartLeft = sidebarPosition === "left" ? gap + (sidebarWidth - totalGridWidth) / 2 : mainWidth + gap * 2 + (sidebarWidth - totalGridWidth) / 2;
589
+ gridStartTop = gap + (sidebarHeight - totalGridHeight) / 2;
590
+ }
591
+ let sidebarIndex = 0;
592
+ for (let i = 0; i < count; i++) {
593
+ if (i === pinnedIndex)
594
+ continue;
595
+ const isInVisibleRange = sidebarIndex >= startOthersIndex && sidebarIndex < endOthersIndex;
596
+ if (isInVisibleRange) {
597
+ const pageRelativeIndex = sidebarIndex - startOthersIndex;
598
+ const row = Math.floor(pageRelativeIndex / thumbCols);
599
+ const col = pageRelativeIndex % thumbCols;
600
+ const itemsInLastRow = itemsOnPage % thumbCols || thumbCols;
601
+ let rowLeft = gridStartLeft;
602
+ const lastRowIndex = Math.ceil(itemsOnPage / thumbCols) - 1;
603
+ if (row === lastRowIndex && itemsInLastRow < thumbCols) {
604
+ const rowWidth = itemsInLastRow * thumbWidth + (itemsInLastRow - 1) * gap;
605
+ if (isVertical) {
606
+ rowLeft = gap + (sidebarWidth - rowWidth) / 2;
607
+ } else {
608
+ rowLeft = (sidebarPosition === "left" ? gap : mainWidth + gap * 2) + (sidebarWidth - rowWidth) / 2;
609
+ }
610
+ }
611
+ positions[i] = {
612
+ position: {
613
+ top: gridStartTop + row * (thumbHeight + gap),
614
+ left: rowLeft + col * (thumbWidth + gap)
615
+ },
616
+ dimensions: { width: thumbWidth, height: thumbHeight }
617
+ };
618
+ } else {
619
+ positions[i] = {
620
+ position: { top: -9999, left: -9999 },
621
+ dimensions: { width: 0, height: 0 }
622
+ };
623
+ }
624
+ sidebarIndex++;
285
625
  }
286
- sidebarIndex++;
287
626
  }
288
627
  const pagination = {
289
- enabled: maxVisibleOthers > 0 && totalOthers > maxVisibleOthers,
290
- currentPage: safeCurrentOthersPage,
628
+ enabled: maxVisible > 0 && totalOthers > maxVisible,
629
+ currentPage: safeCurrentVisiblePage,
291
630
  totalPages: othersTotalPages,
292
631
  itemsOnPage,
293
632
  startIndex: startOthersIndex,
294
633
  endIndex: endOthersIndex
295
634
  };
635
+ const getItemDimensions = (index) => positions[index]?.dimensions ?? { width: 0, height: 0 };
636
+ const getLastVisibleOthersIndex = () => {
637
+ if (itemsOnPage === 0)
638
+ return -1;
639
+ let othersIdx = 0;
640
+ let lastVisibleOriginalIdx = -1;
641
+ for (let i = 0; i < count; i++) {
642
+ if (i === pinnedIndex)
643
+ continue;
644
+ if (othersIdx >= startOthersIndex && othersIdx < endOthersIndex) {
645
+ lastVisibleOriginalIdx = i;
646
+ }
647
+ othersIdx++;
648
+ }
649
+ return lastVisibleOriginalIdx;
650
+ };
296
651
  return {
297
652
  width: mainItemWidth,
298
653
  height: mainItemHeight,
299
- rows: isVertical ? 1 + thumbRows : thumbRows,
300
- cols: isVertical ? thumbCols : 1 + thumbCols,
654
+ rows: isVertical ? 2 : 1,
655
+ cols: isVertical ? 1 : 2,
301
656
  layoutMode: "sidebar",
302
657
  getPosition: (index) => positions[index]?.position ?? { top: 0, left: 0 },
303
- getItemDimensions: (index) => positions[index]?.dimensions ?? { width: 0, height: 0 },
658
+ getItemDimensions,
304
659
  isMainItem: (index) => index === pinnedIndex,
305
660
  pagination,
306
661
  isItemVisible: (index) => {
@@ -313,160 +668,36 @@ function createSidebarGrid(options) {
313
668
  }
314
669
  return sIdx >= startOthersIndex && sIdx < endOthersIndex;
315
670
  },
316
- // Extra info
317
- hiddenCount
318
- };
319
- }
320
- function createSpeakerGrid(options) {
321
- const { dimensions, gap, aspectRatio, count, speakerIndex = 0, maxVisibleOthers = 0, currentOthersPage = 0 } = options;
322
- if (count === 0) {
323
- return createEmptyMeetGridResult("speaker");
324
- }
325
- if (count === 1) {
326
- const grid = createGrid({ ...options, count: 1 });
327
- const pagination2 = createDefaultPagination(1);
328
- return {
329
- ...grid,
330
- layoutMode: "speaker",
331
- getItemDimensions: () => ({ width: grid.width, height: grid.height }),
332
- isMainItem: () => true,
333
- pagination: pagination2,
334
- isItemVisible: () => true
335
- };
336
- }
337
- const { width: W, height: H } = dimensions;
338
- const ratio = getAspectRatio(aspectRatio);
339
- const totalOthers = count - 1;
340
- const visibleOthers = maxVisibleOthers > 0 ? Math.min(maxVisibleOthers, totalOthers) : totalOthers;
341
- const othersTotalPages = maxVisibleOthers > 0 ? Math.ceil(totalOthers / maxVisibleOthers) : 1;
342
- const safeCurrentOthersPage = Math.min(currentOthersPage, Math.max(0, othersTotalPages - 1));
343
- const startOthersIndex = safeCurrentOthersPage * maxVisibleOthers;
344
- const endOthersIndex = Math.min(startOthersIndex + visibleOthers, totalOthers);
345
- const itemsOnPage = endOthersIndex - startOthersIndex;
346
- const hiddenCount = totalOthers - itemsOnPage;
347
- const speakerAreaHeight = (H - gap * 3) * 0.65;
348
- const othersAreaHeight = (H - gap * 3) * 0.35;
349
- const othersAreaWidth = W - gap * 2;
350
- let speakerW = W - gap * 2;
351
- let speakerH = speakerW * ratio;
352
- if (speakerH > speakerAreaHeight) {
353
- speakerH = speakerAreaHeight;
354
- speakerW = speakerH / ratio;
355
- }
356
- let bestCols = 1;
357
- let bestTileW = 0;
358
- let bestTileH = 0;
359
- if (visibleOthers > 0) {
360
- for (let cols = 1; cols <= visibleOthers; cols++) {
361
- const rows = Math.ceil(visibleOthers / cols);
362
- const maxTileW = (othersAreaWidth - (cols - 1) * gap) / cols;
363
- const maxTileH = (othersAreaHeight - (rows - 1) * gap) / rows;
364
- let tileW = maxTileW;
365
- let tileH = tileW * ratio;
366
- if (tileH > maxTileH) {
367
- tileH = maxTileH;
368
- tileW = tileH / ratio;
369
- }
370
- if (tileW * tileH > bestTileW * bestTileH) {
371
- bestCols = cols;
372
- bestTileW = tileW;
373
- bestTileH = tileH;
374
- }
375
- }
376
- }
377
- const otherCols = bestCols;
378
- const otherRows = Math.ceil(visibleOthers / otherCols) || 1;
379
- const otherW = bestTileW;
380
- const otherH = bestTileH;
381
- const positions = [];
382
- positions[speakerIndex] = {
383
- position: {
384
- top: gap + (speakerAreaHeight - speakerH) / 2,
385
- left: gap + (W - gap * 2 - speakerW) / 2
386
- },
387
- dimensions: { width: speakerW, height: speakerH }
388
- };
389
- const totalGridWidth = otherCols * otherW + (otherCols - 1) * gap;
390
- const totalGridHeight = otherRows * otherH + (otherRows - 1) * gap;
391
- const gridStartLeft = gap + (othersAreaWidth - totalGridWidth) / 2;
392
- const gridStartTop = speakerAreaHeight + gap * 2 + (othersAreaHeight - totalGridHeight) / 2;
393
- let otherIndex = 0;
394
- for (let i = 0; i < count; i++) {
395
- if (i === speakerIndex)
396
- continue;
397
- const isInVisibleRange = otherIndex >= startOthersIndex && otherIndex < endOthersIndex;
398
- if (isInVisibleRange) {
399
- const pageRelativeIndex = otherIndex - startOthersIndex;
400
- const row = Math.floor(pageRelativeIndex / otherCols);
401
- const col = pageRelativeIndex % otherCols;
402
- const lastRowIndex = Math.ceil(itemsOnPage / otherCols) - 1;
403
- const itemsInLastRow = itemsOnPage % otherCols || otherCols;
404
- let rowStartLeft = gridStartLeft;
405
- if (row === lastRowIndex && itemsInLastRow < otherCols) {
406
- const rowWidth = itemsInLastRow * otherW + (itemsInLastRow - 1) * gap;
407
- rowStartLeft = gap + (othersAreaWidth - rowWidth) / 2;
408
- }
409
- positions[i] = {
410
- position: {
411
- top: gridStartTop + row * (otherH + gap),
412
- left: rowStartLeft + col * (otherW + gap)
413
- },
414
- dimensions: { width: otherW, height: otherH }
415
- };
416
- } else {
417
- positions[i] = {
418
- position: { top: -9999, left: -9999 },
419
- dimensions: { width: 0, height: 0 }
420
- };
421
- }
422
- otherIndex++;
423
- }
424
- const pagination = {
425
- enabled: maxVisibleOthers > 0 && totalOthers > maxVisibleOthers,
426
- currentPage: safeCurrentOthersPage,
427
- totalPages: othersTotalPages,
428
- itemsOnPage,
429
- startIndex: startOthersIndex,
430
- endIndex: endOthersIndex
431
- };
432
- return {
433
- width: speakerW,
434
- height: speakerH,
435
- rows: 1 + otherRows,
436
- cols: otherCols,
437
- layoutMode: "speaker",
438
- getPosition: (index) => positions[index]?.position ?? { top: 0, left: 0 },
439
- getItemDimensions: (index) => positions[index]?.dimensions ?? { width: 0, height: 0 },
440
- isMainItem: (index) => index === speakerIndex,
441
- pagination,
442
- isItemVisible: (index) => {
443
- if (index === speakerIndex)
444
- return true;
445
- let sIdx = 0;
446
- for (let i = 0; i < index; i++) {
447
- if (i !== speakerIndex)
448
- sIdx++;
449
- }
450
- return sIdx >= startOthersIndex && sIdx < endOthersIndex;
451
- },
452
- hiddenCount
671
+ hiddenCount,
672
+ getLastVisibleOthersIndex,
673
+ getItemContentDimensions: createGetItemContentDimensions(getItemDimensions, options.itemAspectRatios, aspectRatio)
453
674
  };
454
675
  }
455
676
  function createSpotlightGrid(options) {
456
- const { dimensions, gap, aspectRatio, pinnedIndex = 0 } = options;
677
+ const { dimensions, gap, aspectRatio, pinnedIndex = 0, flexLayout = false, itemAspectRatios } = options;
457
678
  const { width: W, height: H } = dimensions;
458
- const ratio = getAspectRatio(aspectRatio);
459
- let spotWidth = W - gap * 2;
460
- let spotHeight = spotWidth * ratio;
461
- if (spotHeight > H - gap * 2) {
679
+ const itemRatio = flexLayout && itemAspectRatios?.[pinnedIndex];
680
+ const shouldFill = itemRatio === "fill" || itemRatio === "auto";
681
+ let spotWidth;
682
+ let spotHeight;
683
+ if (shouldFill) {
684
+ spotWidth = W - gap * 2;
462
685
  spotHeight = H - gap * 2;
463
- spotWidth = spotHeight / ratio;
686
+ } else {
687
+ const ratio = itemRatio ? getAspectRatio(itemRatio) : getAspectRatio(aspectRatio);
688
+ spotWidth = W - gap * 2;
689
+ spotHeight = spotWidth * ratio;
690
+ if (spotHeight > H - gap * 2) {
691
+ spotHeight = H - gap * 2;
692
+ spotWidth = spotHeight / ratio;
693
+ }
464
694
  }
465
695
  const position = {
466
696
  top: gap + (H - gap * 2 - spotHeight) / 2,
467
697
  left: gap + (W - gap * 2 - spotWidth) / 2
468
698
  };
469
699
  const pagination = createDefaultPagination(1);
700
+ const getItemDimensions = (index) => index === pinnedIndex ? { width: spotWidth, height: spotHeight } : { width: 0, height: 0 };
470
701
  return {
471
702
  width: spotWidth,
472
703
  height: spotHeight,
@@ -474,10 +705,13 @@ function createSpotlightGrid(options) {
474
705
  cols: 1,
475
706
  layoutMode: "spotlight",
476
707
  getPosition: (index) => index === pinnedIndex ? position : { top: -9999, left: -9999 },
477
- getItemDimensions: (index) => index === pinnedIndex ? { width: spotWidth, height: spotHeight } : { width: 0, height: 0 },
708
+ getItemDimensions,
478
709
  isMainItem: (index) => index === pinnedIndex,
479
710
  pagination,
480
- isItemVisible: (index) => index === pinnedIndex
711
+ isItemVisible: (index) => index === pinnedIndex,
712
+ hiddenCount: 0,
713
+ getLastVisibleOthersIndex: () => -1,
714
+ getItemContentDimensions: createGetItemContentDimensions(getItemDimensions, options.itemAspectRatios, aspectRatio)
481
715
  };
482
716
  }
483
717
  function createDefaultPagination(count) {
@@ -508,6 +742,7 @@ function createPaginationInfo(count, maxItemsPerPage, currentPage) {
508
742
  };
509
743
  }
510
744
  function createEmptyMeetGridResult(layoutMode) {
745
+ const getItemDimensions = () => ({ width: 0, height: 0 });
511
746
  return {
512
747
  width: 0,
513
748
  height: 0,
@@ -515,51 +750,129 @@ function createEmptyMeetGridResult(layoutMode) {
515
750
  cols: 0,
516
751
  layoutMode,
517
752
  getPosition: () => ({ top: 0, left: 0 }),
518
- getItemDimensions: () => ({ width: 0, height: 0 }),
753
+ getItemDimensions,
519
754
  isMainItem: () => false,
520
755
  pagination: createDefaultPagination(0),
521
- isItemVisible: () => false
756
+ isItemVisible: () => false,
757
+ hiddenCount: 0,
758
+ getLastVisibleOthersIndex: () => -1,
759
+ getItemContentDimensions: () => ({ width: 0, height: 0, offsetTop: 0, offsetLeft: 0 })
522
760
  };
523
761
  }
524
762
  function createMeetGrid(options) {
525
- const { layoutMode = "gallery", count } = options;
763
+ const { layoutMode = "gallery", count, flexLayout = false } = options;
526
764
  if (count === 0) {
527
765
  return createEmptyMeetGridResult(layoutMode);
528
766
  }
529
767
  switch (layoutMode) {
530
768
  case "spotlight":
531
769
  return createSpotlightGrid(options);
532
- case "speaker":
533
- return createSpeakerGrid(options);
534
770
  case "sidebar":
535
771
  return createSidebarGrid(options);
536
772
  case "gallery":
537
773
  default: {
538
- const { maxItemsPerPage, currentPage, pinnedIndex, sidebarPosition = "right" } = options;
774
+ const { maxItemsPerPage, currentPage, pinnedIndex, sidebarPosition = "right", dimensions, maxVisible = 0 } = options;
539
775
  if (pinnedIndex !== void 0 && pinnedIndex >= 0 && pinnedIndex < count) {
540
- return createSidebarGrid({ ...options, sidebarPosition });
776
+ const isPortrait = dimensions.width < dimensions.height;
777
+ const effectiveSidebarPosition = isPortrait ? "bottom" : sidebarPosition;
778
+ return createSidebarGrid({ ...options, sidebarPosition: effectiveSidebarPosition });
779
+ }
780
+ let visibleCount = count;
781
+ let hiddenCount = 0;
782
+ let startIndex = 0;
783
+ let endIndex = count;
784
+ if (maxItemsPerPage && maxItemsPerPage > 0) {
785
+ const pagination2 = createPaginationInfo(count, maxItemsPerPage, currentPage);
786
+ visibleCount = pagination2.itemsOnPage;
787
+ startIndex = pagination2.startIndex;
788
+ endIndex = pagination2.endIndex;
789
+ } else if (maxVisible > 0 && count > maxVisible) {
790
+ visibleCount = maxVisible;
791
+ hiddenCount = count - maxVisible + 1;
792
+ startIndex = 0;
793
+ endIndex = maxVisible;
794
+ }
795
+ const pagination = maxItemsPerPage && maxItemsPerPage > 0 ? createPaginationInfo(count, maxItemsPerPage, currentPage) : {
796
+ enabled: false,
797
+ currentPage: 0,
798
+ totalPages: 1,
799
+ itemsOnPage: visibleCount,
800
+ startIndex,
801
+ endIndex
802
+ };
803
+ const effectiveCount = visibleCount;
804
+ if (flexLayout && options.itemAspectRatios) {
805
+ const pageItemRatios = options.itemAspectRatios.slice(startIndex, startIndex + effectiveCount);
806
+ const flexItems = calculateFlexLayout({
807
+ dimensions: options.dimensions,
808
+ count: effectiveCount,
809
+ aspectRatio: options.aspectRatio,
810
+ gap: options.gap,
811
+ itemAspectRatios: pageItemRatios
812
+ });
813
+ const getPosition2 = (index) => {
814
+ const relativeIndex = index - startIndex;
815
+ if (relativeIndex < 0 || relativeIndex >= effectiveCount) {
816
+ return { top: -9999, left: -9999 };
817
+ }
818
+ const item = flexItems[relativeIndex];
819
+ return item ? { top: item.top, left: item.left } : { top: -9999, left: -9999 };
820
+ };
821
+ const getItemDimensions2 = (index) => {
822
+ const relativeIndex = index - startIndex;
823
+ if (relativeIndex < 0 || relativeIndex >= effectiveCount) {
824
+ return { width: 0, height: 0 };
825
+ }
826
+ const item = flexItems[relativeIndex];
827
+ return item ? { width: item.width, height: item.height } : { width: 0, height: 0 };
828
+ };
829
+ const getItemContentDimensions = (index) => {
830
+ const dims = getItemDimensions2(index);
831
+ return {
832
+ width: dims.width,
833
+ height: dims.height,
834
+ offsetTop: 0,
835
+ offsetLeft: 0
836
+ };
837
+ };
838
+ const lastVisibleIndex2 = endIndex - 1;
839
+ return {
840
+ width: flexItems[0]?.width ?? 0,
841
+ height: flexItems[0]?.height ?? 0,
842
+ rows: Math.max(...flexItems.map((i) => i.row)) + 1,
843
+ cols: flexItems.filter((i) => i.row === 0).length,
844
+ layoutMode: "gallery",
845
+ getPosition: getPosition2,
846
+ getItemDimensions: getItemDimensions2,
847
+ isMainItem: () => false,
848
+ pagination,
849
+ isItemVisible: (index) => index >= startIndex && index < endIndex,
850
+ hiddenCount,
851
+ getLastVisibleOthersIndex: () => hiddenCount > 0 ? lastVisibleIndex2 : -1,
852
+ getItemContentDimensions
853
+ };
541
854
  }
542
- const pagination = createPaginationInfo(count, maxItemsPerPage, currentPage);
543
- const effectiveCount = pagination.enabled ? pagination.itemsOnPage : count;
544
855
  const grid = createGrid({ ...options, count: effectiveCount });
545
856
  const getPosition = (index) => {
546
- if (!pagination.enabled) {
547
- return grid.getPosition(index);
548
- }
549
- const pageRelativeIndex = index - pagination.startIndex;
550
- if (pageRelativeIndex < 0 || pageRelativeIndex >= pagination.itemsOnPage) {
857
+ const relativeIndex = index - startIndex;
858
+ if (relativeIndex < 0 || relativeIndex >= effectiveCount) {
551
859
  return { top: -9999, left: -9999 };
552
860
  }
553
- return grid.getPosition(pageRelativeIndex);
861
+ return grid.getPosition(relativeIndex);
554
862
  };
863
+ const getItemDimensions = () => ({ width: grid.width, height: grid.height });
864
+ const lastVisibleIndex = endIndex - 1;
555
865
  return {
556
866
  ...grid,
557
867
  layoutMode: "gallery",
558
868
  getPosition,
559
- getItemDimensions: () => ({ width: grid.width, height: grid.height }),
869
+ getItemDimensions,
560
870
  isMainItem: () => false,
561
871
  pagination,
562
- isItemVisible: (index) => index >= pagination.startIndex && index < pagination.endIndex
872
+ isItemVisible: (index) => index >= startIndex && index < endIndex,
873
+ hiddenCount,
874
+ getLastVisibleOthersIndex: () => hiddenCount > 0 ? lastVisibleIndex : -1,
875
+ getItemContentDimensions: createGetItemContentDimensions(getItemDimensions, options.itemAspectRatios, options.aspectRatio)
563
876
  };
564
877
  }
565
878
  }
@@ -581,6 +894,9 @@ function getSpringConfig(preset = "smooth") {
581
894
  };
582
895
  }
583
896
 
897
+ exports.calculateContentDimensions = calculateContentDimensions;
898
+ exports.calculateFlexLayout = calculateFlexLayout;
899
+ exports.calculateFlexStrip = calculateFlexStrip;
584
900
  exports.createGrid = createGrid;
585
901
  exports.createGridItemPositioner = createGridItemPositioner;
586
902
  exports.createMeetGrid = createMeetGrid;