@thangdevalone/meet-layout-grid-core 1.0.0 → 1.0.4

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.mjs CHANGED
@@ -35,6 +35,8 @@ function getGridItemDimensions({
35
35
  let h = 0;
36
36
  let a = 1;
37
37
  let b = 1;
38
+ const isPortrait = H > W;
39
+ const minCols = N >= 2 && isPortrait ? 2 : 1;
38
40
  const widths = [];
39
41
  for (let n = 1; n <= N; n++) {
40
42
  widths.push((W - s * (n - 1)) / n, (H - s * (n - 1)) / (n * r));
@@ -45,12 +47,27 @@ function getGridItemDimensions({
45
47
  h = w * r;
46
48
  a = Math.floor((W + s) / (w + s));
47
49
  b = Math.floor((H + s) / (h + s));
50
+ if (a < minCols && N >= minCols) {
51
+ continue;
52
+ }
48
53
  if (a * b >= N) {
49
- a = Math.ceil(N / b);
54
+ a = Math.max(minCols, Math.ceil(N / b));
50
55
  b = Math.ceil(N / a);
51
56
  break;
52
57
  }
53
58
  }
59
+ if (a < minCols && N >= minCols) {
60
+ a = minCols;
61
+ b = Math.ceil(N / a);
62
+ w = (W - s * (a - 1)) / a;
63
+ h = w * r;
64
+ const requiredHeight = b * h + (b - 1) * s;
65
+ if (requiredHeight > H) {
66
+ const scale = H / requiredHeight;
67
+ h = h * scale;
68
+ w = h / r;
69
+ }
70
+ }
54
71
  return { width: w, height: h, rows: b, cols: a };
55
72
  }
56
73
  function createGridItemPositioner({
@@ -67,21 +84,23 @@ function createGridItemPositioner({
67
84
  let firstLeft = (W - (w * cols + (cols - 1) * gap)) / 2;
68
85
  const topAdd = h + gap;
69
86
  const leftAdd = w + gap;
70
- let col = 0;
71
- let row = 0;
72
87
  const incompleteRowCols = count % cols;
88
+ const lastRowStartIndex = incompleteRowCols > 0 ? count - incompleteRowCols : count - cols;
73
89
  function getPosition(index) {
74
- const remaining = count - index;
75
- if (remaining === incompleteRowCols && incompleteRowCols > 0) {
76
- firstLeft = (W - (w * remaining + (remaining - 1) * gap)) / 2;
90
+ const row = Math.floor(index / cols);
91
+ const col = index % cols;
92
+ const isInLastRow = incompleteRowCols > 0 && index >= lastRowStartIndex;
93
+ let leftOffset = firstLeft;
94
+ if (isInLastRow) {
95
+ const lastRowItemCount = incompleteRowCols;
96
+ const colInLastRow = index - lastRowStartIndex;
97
+ leftOffset = (W - (w * lastRowItemCount + (lastRowItemCount - 1) * gap)) / 2;
98
+ const top2 = firstTop + row * topAdd;
99
+ const left2 = leftOffset + colInLastRow * leftAdd;
100
+ return { top: top2, left: left2 };
77
101
  }
78
102
  const top = firstTop + row * topAdd;
79
- const left = firstLeft + col * leftAdd;
80
- col++;
81
- if ((index + 1) % cols === 0) {
82
- row++;
83
- col = 0;
84
- }
103
+ const left = leftOffset + col * leftAdd;
85
104
  return { top, left };
86
105
  }
87
106
  return getPosition;
@@ -110,13 +129,25 @@ function createGrid({ aspectRatio, count, dimensions, gap }) {
110
129
  };
111
130
  }
112
131
  function createSidebarGrid(options) {
113
- const { dimensions, gap, aspectRatio, count, sidebarPosition = "right", sidebarRatio = 0.25, pinnedIndex = 0 } = options;
132
+ const { dimensions, gap, aspectRatio, count, sidebarPosition = "right", sidebarRatio = 0.25, pinnedIndex = 0, maxVisibleOthers = 0, currentOthersPage = 0 } = options;
114
133
  if (count === 0) {
115
134
  return createEmptyMeetGridResult("sidebar");
116
135
  }
136
+ if (count === 1) {
137
+ const grid = createGrid({ ...options, count: 1 });
138
+ const pagination2 = createDefaultPagination(1);
139
+ return {
140
+ ...grid,
141
+ layoutMode: "sidebar",
142
+ getItemDimensions: () => ({ width: grid.width, height: grid.height }),
143
+ isMainItem: () => true,
144
+ pagination: pagination2,
145
+ isItemVisible: () => true
146
+ };
147
+ }
117
148
  const { width: W, height: H } = dimensions;
118
149
  const ratio = getAspectRatio(aspectRatio);
119
- const isVertical = sidebarPosition === "bottom";
150
+ const isVertical = sidebarPosition === "bottom" || sidebarPosition === "top";
120
151
  let mainWidth;
121
152
  let mainHeight;
122
153
  let sidebarWidth;
@@ -138,125 +169,285 @@ function createSidebarGrid(options) {
138
169
  mainItemHeight = mainHeight;
139
170
  mainItemWidth = mainItemHeight / ratio;
140
171
  }
141
- const sidebarCount = count - 1;
142
- let thumbWidth;
143
- let thumbHeight;
144
- if (sidebarCount > 0) {
172
+ const totalOthers = count - 1;
173
+ const visibleOthers = maxVisibleOthers > 0 ? Math.min(maxVisibleOthers, totalOthers) : totalOthers;
174
+ const othersTotalPages = maxVisibleOthers > 0 ? Math.ceil(totalOthers / maxVisibleOthers) : 1;
175
+ const safeCurrentOthersPage = Math.min(currentOthersPage, Math.max(0, othersTotalPages - 1));
176
+ const startOthersIndex = safeCurrentOthersPage * maxVisibleOthers;
177
+ const endOthersIndex = Math.min(startOthersIndex + visibleOthers, totalOthers);
178
+ const itemsOnPage = endOthersIndex - startOthersIndex;
179
+ const hiddenCount = totalOthers - itemsOnPage;
180
+ let thumbCols = 1;
181
+ let thumbRows = 1;
182
+ let thumbWidth = 0;
183
+ let thumbHeight = 0;
184
+ if (visibleOthers > 0) {
185
+ let bestArea = 0;
145
186
  if (isVertical) {
146
- thumbWidth = Math.min((sidebarWidth - (sidebarCount - 1) * gap) / sidebarCount, sidebarHeight / ratio);
147
- thumbHeight = thumbWidth * ratio;
187
+ for (let cols = 1; cols <= visibleOthers; cols++) {
188
+ const rows = Math.ceil(visibleOthers / cols);
189
+ const maxTileW = (sidebarWidth - (cols - 1) * gap) / cols;
190
+ const maxTileH = (sidebarHeight - (rows - 1) * gap) / rows;
191
+ let tileW = maxTileW;
192
+ let tileH = tileW * ratio;
193
+ if (tileH > maxTileH) {
194
+ tileH = maxTileH;
195
+ tileW = tileH / ratio;
196
+ }
197
+ if (tileW * tileH > bestArea) {
198
+ bestArea = tileW * tileH;
199
+ thumbCols = cols;
200
+ thumbRows = rows;
201
+ thumbWidth = tileW;
202
+ thumbHeight = tileH;
203
+ }
204
+ }
148
205
  } else {
149
- thumbHeight = Math.min((sidebarHeight - (sidebarCount - 1) * gap) / sidebarCount, sidebarWidth / ratio);
150
- thumbWidth = thumbHeight / ratio;
206
+ for (let rows = 1; rows <= visibleOthers; rows++) {
207
+ const cols = Math.ceil(visibleOthers / rows);
208
+ const maxTileH = (sidebarHeight - (rows - 1) * gap) / rows;
209
+ const maxTileW = (sidebarWidth - (cols - 1) * gap) / cols;
210
+ let tileH = maxTileH;
211
+ let tileW = tileH / ratio;
212
+ if (tileW > maxTileW) {
213
+ tileW = maxTileW;
214
+ tileH = tileW * ratio;
215
+ }
216
+ if (tileW * tileH > bestArea) {
217
+ bestArea = tileW * tileH;
218
+ thumbCols = cols;
219
+ thumbRows = rows;
220
+ thumbWidth = tileW;
221
+ thumbHeight = tileH;
222
+ }
223
+ }
151
224
  }
152
- } else {
153
- thumbWidth = 0;
154
- thumbHeight = 0;
155
225
  }
156
226
  const positions = [];
157
- const mainLeft = isVertical ? gap + (mainWidth - mainItemWidth) / 2 : sidebarPosition === "left" ? sidebarWidth + gap * 2 + (mainWidth - mainItemWidth) / 2 : gap + (mainWidth - mainItemWidth) / 2;
158
- const mainTop = isVertical ? gap + (mainHeight - mainItemHeight) / 2 : gap + (mainHeight - mainItemHeight) / 2;
227
+ let mainLeft;
228
+ let mainTop;
229
+ if (isVertical) {
230
+ mainLeft = gap + (mainWidth - mainItemWidth) / 2;
231
+ mainTop = sidebarPosition === "top" ? sidebarHeight + gap * 2 + (mainHeight - mainItemHeight) / 2 : gap + (mainHeight - mainItemHeight) / 2;
232
+ } else {
233
+ mainLeft = sidebarPosition === "left" ? sidebarWidth + gap * 2 + (mainWidth - mainItemWidth) / 2 : gap + (mainWidth - mainItemWidth) / 2;
234
+ mainTop = gap + (mainHeight - mainItemHeight) / 2;
235
+ }
159
236
  positions[pinnedIndex] = {
160
237
  position: { top: mainTop, left: mainLeft },
161
238
  dimensions: { width: mainItemWidth, height: mainItemHeight }
162
239
  };
240
+ const totalGridWidth = thumbCols * thumbWidth + (thumbCols - 1) * gap;
241
+ const totalGridHeight = thumbRows * thumbHeight + (thumbRows - 1) * gap;
242
+ let gridStartLeft;
243
+ let gridStartTop;
244
+ if (isVertical) {
245
+ gridStartLeft = gap + (sidebarWidth - totalGridWidth) / 2;
246
+ gridStartTop = sidebarPosition === "top" ? gap + (sidebarHeight - totalGridHeight) / 2 : mainHeight + gap * 2 + (sidebarHeight - totalGridHeight) / 2;
247
+ } else {
248
+ gridStartLeft = sidebarPosition === "left" ? gap + (sidebarWidth - totalGridWidth) / 2 : mainWidth + gap * 2 + (sidebarWidth - totalGridWidth) / 2;
249
+ gridStartTop = gap + (sidebarHeight - totalGridHeight) / 2;
250
+ }
163
251
  let sidebarIndex = 0;
164
252
  for (let i = 0; i < count; i++) {
165
253
  if (i === pinnedIndex)
166
254
  continue;
167
- let left;
168
- let top;
169
- if (isVertical) {
170
- const totalThumbWidth = sidebarCount * thumbWidth + (sidebarCount - 1) * gap;
171
- const startLeft = gap + (sidebarWidth - totalThumbWidth) / 2;
172
- left = startLeft + sidebarIndex * (thumbWidth + gap);
173
- top = mainHeight + gap * 2;
255
+ const isInVisibleRange = sidebarIndex >= startOthersIndex && sidebarIndex < endOthersIndex;
256
+ if (isInVisibleRange) {
257
+ const pageRelativeIndex = sidebarIndex - startOthersIndex;
258
+ const row = Math.floor(pageRelativeIndex / thumbCols);
259
+ const col = pageRelativeIndex % thumbCols;
260
+ const itemsInLastRow = itemsOnPage % thumbCols || thumbCols;
261
+ let rowLeft = gridStartLeft;
262
+ const lastRowIndex = Math.ceil(itemsOnPage / thumbCols) - 1;
263
+ if (row === lastRowIndex && itemsInLastRow < thumbCols) {
264
+ const rowWidth = itemsInLastRow * thumbWidth + (itemsInLastRow - 1) * gap;
265
+ if (isVertical) {
266
+ rowLeft = gap + (sidebarWidth - rowWidth) / 2;
267
+ } else {
268
+ rowLeft = (sidebarPosition === "left" ? gap : mainWidth + gap * 2) + (sidebarWidth - rowWidth) / 2;
269
+ }
270
+ }
271
+ positions[i] = {
272
+ position: {
273
+ top: gridStartTop + row * (thumbHeight + gap),
274
+ left: rowLeft + col * (thumbWidth + gap)
275
+ },
276
+ dimensions: { width: thumbWidth, height: thumbHeight }
277
+ };
174
278
  } else {
175
- left = sidebarPosition === "left" ? gap : mainWidth + gap * 2;
176
- const totalThumbHeight = sidebarCount * thumbHeight + (sidebarCount - 1) * gap;
177
- const startTop = gap + (sidebarHeight - totalThumbHeight) / 2;
178
- top = startTop + sidebarIndex * (thumbHeight + gap);
279
+ positions[i] = {
280
+ position: { top: -9999, left: -9999 },
281
+ dimensions: { width: 0, height: 0 }
282
+ };
179
283
  }
180
- positions[i] = {
181
- position: { top, left },
182
- dimensions: { width: thumbWidth, height: thumbHeight }
183
- };
184
284
  sidebarIndex++;
185
285
  }
286
+ const pagination = {
287
+ enabled: maxVisibleOthers > 0 && totalOthers > maxVisibleOthers,
288
+ currentPage: safeCurrentOthersPage,
289
+ totalPages: othersTotalPages,
290
+ itemsOnPage,
291
+ startIndex: startOthersIndex,
292
+ endIndex: endOthersIndex
293
+ };
186
294
  return {
187
295
  width: mainItemWidth,
188
296
  height: mainItemHeight,
189
- rows: isVertical ? 2 : 1,
190
- cols: isVertical ? 1 : 2,
297
+ rows: isVertical ? 1 + thumbRows : thumbRows,
298
+ cols: isVertical ? thumbCols : 1 + thumbCols,
191
299
  layoutMode: "sidebar",
192
300
  getPosition: (index) => positions[index]?.position ?? { top: 0, left: 0 },
193
301
  getItemDimensions: (index) => positions[index]?.dimensions ?? { width: 0, height: 0 },
194
- isMainItem: (index) => index === pinnedIndex
302
+ isMainItem: (index) => index === pinnedIndex,
303
+ pagination,
304
+ isItemVisible: (index) => {
305
+ if (index === pinnedIndex)
306
+ return true;
307
+ let sIdx = 0;
308
+ for (let i = 0; i < index; i++) {
309
+ if (i !== pinnedIndex)
310
+ sIdx++;
311
+ }
312
+ return sIdx >= startOthersIndex && sIdx < endOthersIndex;
313
+ },
314
+ // Extra info
315
+ hiddenCount
195
316
  };
196
317
  }
197
318
  function createSpeakerGrid(options) {
198
- const { dimensions, gap, aspectRatio, count, speakerIndex = 0 } = options;
319
+ const { dimensions, gap, aspectRatio, count, speakerIndex = 0, maxVisibleOthers = 0, currentOthersPage = 0 } = options;
199
320
  if (count === 0) {
200
321
  return createEmptyMeetGridResult("speaker");
201
322
  }
202
323
  if (count === 1) {
203
324
  const grid = createGrid({ ...options, count: 1 });
325
+ const pagination2 = createDefaultPagination(1);
204
326
  return {
205
327
  ...grid,
206
328
  layoutMode: "speaker",
207
329
  getItemDimensions: () => ({ width: grid.width, height: grid.height }),
208
- isMainItem: () => true
330
+ isMainItem: () => true,
331
+ pagination: pagination2,
332
+ isItemVisible: () => true
209
333
  };
210
334
  }
211
335
  const { width: W, height: H } = dimensions;
212
336
  const ratio = getAspectRatio(aspectRatio);
213
- const speakerHeight = (H - gap * 3) * 0.65;
214
- const othersHeight = (H - gap * 3) * 0.35;
337
+ const totalOthers = count - 1;
338
+ const visibleOthers = maxVisibleOthers > 0 ? Math.min(maxVisibleOthers, totalOthers) : totalOthers;
339
+ const othersTotalPages = maxVisibleOthers > 0 ? Math.ceil(totalOthers / maxVisibleOthers) : 1;
340
+ const safeCurrentOthersPage = Math.min(currentOthersPage, Math.max(0, othersTotalPages - 1));
341
+ const startOthersIndex = safeCurrentOthersPage * maxVisibleOthers;
342
+ const endOthersIndex = Math.min(startOthersIndex + visibleOthers, totalOthers);
343
+ const itemsOnPage = endOthersIndex - startOthersIndex;
344
+ const hiddenCount = totalOthers - itemsOnPage;
345
+ const speakerAreaHeight = (H - gap * 3) * 0.65;
346
+ const othersAreaHeight = (H - gap * 3) * 0.35;
347
+ const othersAreaWidth = W - gap * 2;
215
348
  let speakerW = W - gap * 2;
216
349
  let speakerH = speakerW * ratio;
217
- if (speakerH > speakerHeight) {
218
- speakerH = speakerHeight;
350
+ if (speakerH > speakerAreaHeight) {
351
+ speakerH = speakerAreaHeight;
219
352
  speakerW = speakerH / ratio;
220
353
  }
221
- const othersCount = count - 1;
222
- let otherW = Math.min((W - gap * 2 - (othersCount - 1) * gap) / othersCount, othersHeight / ratio);
223
- let otherH = otherW * ratio;
224
- if (otherH > othersHeight) {
225
- otherH = othersHeight;
226
- otherW = otherH / ratio;
354
+ let bestCols = 1;
355
+ let bestTileW = 0;
356
+ let bestTileH = 0;
357
+ if (visibleOthers > 0) {
358
+ for (let cols = 1; cols <= visibleOthers; cols++) {
359
+ const rows = Math.ceil(visibleOthers / cols);
360
+ const maxTileW = (othersAreaWidth - (cols - 1) * gap) / cols;
361
+ const maxTileH = (othersAreaHeight - (rows - 1) * gap) / rows;
362
+ let tileW = maxTileW;
363
+ let tileH = tileW * ratio;
364
+ if (tileH > maxTileH) {
365
+ tileH = maxTileH;
366
+ tileW = tileH / ratio;
367
+ }
368
+ if (tileW * tileH > bestTileW * bestTileH) {
369
+ bestCols = cols;
370
+ bestTileW = tileW;
371
+ bestTileH = tileH;
372
+ }
373
+ }
227
374
  }
375
+ const otherCols = bestCols;
376
+ const otherRows = Math.ceil(visibleOthers / otherCols) || 1;
377
+ const otherW = bestTileW;
378
+ const otherH = bestTileH;
228
379
  const positions = [];
229
380
  positions[speakerIndex] = {
230
381
  position: {
231
- top: gap + (speakerHeight - speakerH) / 2,
382
+ top: gap + (speakerAreaHeight - speakerH) / 2,
232
383
  left: gap + (W - gap * 2 - speakerW) / 2
233
384
  },
234
385
  dimensions: { width: speakerW, height: speakerH }
235
386
  };
236
- const totalOthersWidth = othersCount * otherW + (othersCount - 1) * gap;
237
- const startLeft = gap + (W - gap * 2 - totalOthersWidth) / 2;
387
+ const totalGridWidth = otherCols * otherW + (otherCols - 1) * gap;
388
+ const totalGridHeight = otherRows * otherH + (otherRows - 1) * gap;
389
+ const gridStartLeft = gap + (othersAreaWidth - totalGridWidth) / 2;
390
+ const gridStartTop = speakerAreaHeight + gap * 2 + (othersAreaHeight - totalGridHeight) / 2;
238
391
  let otherIndex = 0;
239
392
  for (let i = 0; i < count; i++) {
240
393
  if (i === speakerIndex)
241
394
  continue;
242
- positions[i] = {
243
- position: {
244
- top: speakerHeight + gap * 2 + (othersHeight - otherH) / 2,
245
- left: startLeft + otherIndex * (otherW + gap)
246
- },
247
- dimensions: { width: otherW, height: otherH }
248
- };
395
+ const isInVisibleRange = otherIndex >= startOthersIndex && otherIndex < endOthersIndex;
396
+ if (isInVisibleRange) {
397
+ const pageRelativeIndex = otherIndex - startOthersIndex;
398
+ const row = Math.floor(pageRelativeIndex / otherCols);
399
+ const col = pageRelativeIndex % otherCols;
400
+ const lastRowIndex = Math.ceil(itemsOnPage / otherCols) - 1;
401
+ const itemsInLastRow = itemsOnPage % otherCols || otherCols;
402
+ let rowStartLeft = gridStartLeft;
403
+ if (row === lastRowIndex && itemsInLastRow < otherCols) {
404
+ const rowWidth = itemsInLastRow * otherW + (itemsInLastRow - 1) * gap;
405
+ rowStartLeft = gap + (othersAreaWidth - rowWidth) / 2;
406
+ }
407
+ positions[i] = {
408
+ position: {
409
+ top: gridStartTop + row * (otherH + gap),
410
+ left: rowStartLeft + col * (otherW + gap)
411
+ },
412
+ dimensions: { width: otherW, height: otherH }
413
+ };
414
+ } else {
415
+ positions[i] = {
416
+ position: { top: -9999, left: -9999 },
417
+ dimensions: { width: 0, height: 0 }
418
+ };
419
+ }
249
420
  otherIndex++;
250
421
  }
422
+ const pagination = {
423
+ enabled: maxVisibleOthers > 0 && totalOthers > maxVisibleOthers,
424
+ currentPage: safeCurrentOthersPage,
425
+ totalPages: othersTotalPages,
426
+ itemsOnPage,
427
+ startIndex: startOthersIndex,
428
+ endIndex: endOthersIndex
429
+ };
251
430
  return {
252
431
  width: speakerW,
253
432
  height: speakerH,
254
- rows: 2,
255
- cols: othersCount,
433
+ rows: 1 + otherRows,
434
+ cols: otherCols,
256
435
  layoutMode: "speaker",
257
436
  getPosition: (index) => positions[index]?.position ?? { top: 0, left: 0 },
258
437
  getItemDimensions: (index) => positions[index]?.dimensions ?? { width: 0, height: 0 },
259
- isMainItem: (index) => index === speakerIndex
438
+ isMainItem: (index) => index === speakerIndex,
439
+ pagination,
440
+ isItemVisible: (index) => {
441
+ if (index === speakerIndex)
442
+ return true;
443
+ let sIdx = 0;
444
+ for (let i = 0; i < index; i++) {
445
+ if (i !== speakerIndex)
446
+ sIdx++;
447
+ }
448
+ return sIdx >= startOthersIndex && sIdx < endOthersIndex;
449
+ },
450
+ hiddenCount
260
451
  };
261
452
  }
262
453
  function createSpotlightGrid(options) {
@@ -273,6 +464,7 @@ function createSpotlightGrid(options) {
273
464
  top: gap + (H - gap * 2 - spotHeight) / 2,
274
465
  left: gap + (W - gap * 2 - spotWidth) / 2
275
466
  };
467
+ const pagination = createDefaultPagination(1);
276
468
  return {
277
469
  width: spotWidth,
278
470
  height: spotHeight,
@@ -281,7 +473,36 @@ function createSpotlightGrid(options) {
281
473
  layoutMode: "spotlight",
282
474
  getPosition: (index) => index === pinnedIndex ? position : { top: -9999, left: -9999 },
283
475
  getItemDimensions: (index) => index === pinnedIndex ? { width: spotWidth, height: spotHeight } : { width: 0, height: 0 },
284
- isMainItem: (index) => index === pinnedIndex
476
+ isMainItem: (index) => index === pinnedIndex,
477
+ pagination,
478
+ isItemVisible: (index) => index === pinnedIndex
479
+ };
480
+ }
481
+ function createDefaultPagination(count) {
482
+ return {
483
+ enabled: false,
484
+ currentPage: 0,
485
+ totalPages: 1,
486
+ itemsOnPage: count,
487
+ startIndex: 0,
488
+ endIndex: count
489
+ };
490
+ }
491
+ function createPaginationInfo(count, maxItemsPerPage, currentPage) {
492
+ if (!maxItemsPerPage || maxItemsPerPage <= 0 || maxItemsPerPage >= count) {
493
+ return createDefaultPagination(count);
494
+ }
495
+ const totalPages = Math.ceil(count / maxItemsPerPage);
496
+ const page = Math.min(Math.max(0, currentPage ?? 0), totalPages - 1);
497
+ const startIndex = page * maxItemsPerPage;
498
+ const endIndex = Math.min(startIndex + maxItemsPerPage, count);
499
+ return {
500
+ enabled: true,
501
+ currentPage: page,
502
+ totalPages,
503
+ itemsOnPage: endIndex - startIndex,
504
+ startIndex,
505
+ endIndex
285
506
  };
286
507
  }
287
508
  function createEmptyMeetGridResult(layoutMode) {
@@ -293,7 +514,9 @@ function createEmptyMeetGridResult(layoutMode) {
293
514
  layoutMode,
294
515
  getPosition: () => ({ top: 0, left: 0 }),
295
516
  getItemDimensions: () => ({ width: 0, height: 0 }),
296
- isMainItem: () => false
517
+ isMainItem: () => false,
518
+ pagination: createDefaultPagination(0),
519
+ isItemVisible: () => false
297
520
  };
298
521
  }
299
522
  function createMeetGrid(options) {
@@ -310,12 +533,31 @@ function createMeetGrid(options) {
310
533
  return createSidebarGrid(options);
311
534
  case "gallery":
312
535
  default: {
313
- const grid = createGrid(options);
536
+ const { maxItemsPerPage, currentPage, pinnedIndex, sidebarPosition = "right" } = options;
537
+ if (pinnedIndex !== void 0 && pinnedIndex >= 0 && pinnedIndex < count) {
538
+ return createSidebarGrid({ ...options, sidebarPosition });
539
+ }
540
+ const pagination = createPaginationInfo(count, maxItemsPerPage, currentPage);
541
+ const effectiveCount = pagination.enabled ? pagination.itemsOnPage : count;
542
+ const grid = createGrid({ ...options, count: effectiveCount });
543
+ const getPosition = (index) => {
544
+ if (!pagination.enabled) {
545
+ return grid.getPosition(index);
546
+ }
547
+ const pageRelativeIndex = index - pagination.startIndex;
548
+ if (pageRelativeIndex < 0 || pageRelativeIndex >= pagination.itemsOnPage) {
549
+ return { top: -9999, left: -9999 };
550
+ }
551
+ return grid.getPosition(pageRelativeIndex);
552
+ };
314
553
  return {
315
554
  ...grid,
316
555
  layoutMode: "gallery",
556
+ getPosition,
317
557
  getItemDimensions: () => ({ width: grid.width, height: grid.height }),
318
- isMainItem: () => false
558
+ isMainItem: () => false,
559
+ pagination,
560
+ isItemVisible: (index) => index >= pagination.startIndex && index < pagination.endIndex
319
561
  };
320
562
  }
321
563
  }
package/package.json CHANGED
@@ -1,49 +1,50 @@
1
- {
2
- "name": "@thangdevalone/meet-layout-grid-core",
3
- "version": "1.0.0",
4
- "description": "Core grid calculation logic for meet-layout-grid",
5
- "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/index.mjs",
8
- "types": "./dist/index.d.ts",
9
- "exports": {
10
- ".": {
11
- "import": {
12
- "types": "./dist/index.d.mts",
13
- "default": "./dist/index.mjs"
14
- },
15
- "require": {
16
- "types": "./dist/index.d.cts",
17
- "default": "./dist/index.cjs"
18
- }
19
- }
20
- },
21
- "files": [
22
- "dist"
23
- ],
24
- "scripts": {
25
- "build": "unbuild",
26
- "dev": "unbuild --watch",
27
- "clean": "rimraf dist",
28
- "test": "vitest run",
29
- "test:watch": "vitest"
30
- },
31
- "keywords": [
32
- "grid",
33
- "responsive",
34
- "meeting",
35
- "video",
36
- "layout"
37
- ],
38
- "author": "ThangDevAlone",
39
- "license": "MIT",
40
- "repository": {
41
- "type": "git",
42
- "url": "https://github.com/thangdevalone/meet-layout-grid"
43
- },
44
- "devDependencies": {
45
- "unbuild": "^2.0.0",
46
- "vitest": "^1.0.0",
47
- "rimraf": "^5.0.0"
48
- }
49
- }
1
+ {
2
+ "name": "@thangdevalone/meet-layout-grid-core",
3
+ "version": "1.0.4",
4
+ "description": "Core grid calculation logic for meet-layout-grid",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.mts",
13
+ "default": "./dist/index.mjs"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "files": [
22
+ "dist"
23
+ ],
24
+ "keywords": [
25
+ "grid",
26
+ "responsive",
27
+ "meeting",
28
+ "video",
29
+ "layout"
30
+ ],
31
+ "author": "ThangDevAlone",
32
+ "license": "MIT",
33
+ "homepage": "https://github.com/thangdevalone/meet-layout-grid#readme",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/thangdevalone/meet-layout-grid"
37
+ },
38
+ "devDependencies": {
39
+ "unbuild": "^2.0.0",
40
+ "vitest": "^1.0.0",
41
+ "rimraf": "^5.0.0"
42
+ },
43
+ "scripts": {
44
+ "build": "unbuild",
45
+ "dev": "unbuild --watch",
46
+ "clean": "rimraf dist",
47
+ "test": "vitest run",
48
+ "test:watch": "vitest"
49
+ }
50
+ }