@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/LICENSE +44 -0
- package/README.md +95 -95
- package/dist/index.cjs +316 -74
- package/dist/index.d.cts +31 -2
- package/dist/index.d.mts +31 -2
- package/dist/index.d.ts +197 -168
- package/dist/index.mjs +316 -74
- package/package.json +50 -49
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
|
|
75
|
-
|
|
76
|
-
|
|
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 =
|
|
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
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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
|
-
|
|
147
|
-
|
|
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
|
-
|
|
150
|
-
|
|
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
|
-
|
|
158
|
-
|
|
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
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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 ?
|
|
190
|
-
cols: isVertical ?
|
|
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
|
|
214
|
-
const
|
|
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 >
|
|
218
|
-
speakerH =
|
|
350
|
+
if (speakerH > speakerAreaHeight) {
|
|
351
|
+
speakerH = speakerAreaHeight;
|
|
219
352
|
speakerW = speakerH / ratio;
|
|
220
353
|
}
|
|
221
|
-
|
|
222
|
-
let
|
|
223
|
-
let
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
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 + (
|
|
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
|
|
237
|
-
const
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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:
|
|
255
|
-
cols:
|
|
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
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
+
}
|