fluent-styles 1.61.0 → 1.62.1

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 (46) hide show
  1. package/README.md +592 -33
  2. package/lib/commonjs/index.js +24 -0
  3. package/lib/commonjs/index.js.map +1 -1
  4. package/lib/commonjs/tabBar/TabBar.js.map +1 -1
  5. package/lib/commonjs/table/index.js +650 -0
  6. package/lib/commonjs/table/index.js.map +1 -0
  7. package/lib/commonjs/table/usepaginatedquery.js +181 -0
  8. package/lib/commonjs/table/usepaginatedquery.js.map +1 -0
  9. package/lib/module/index.js +2 -0
  10. package/lib/module/index.js.map +1 -1
  11. package/lib/module/tabBar/TabBar.js.map +1 -1
  12. package/lib/module/table/index.js +644 -0
  13. package/lib/module/table/index.js.map +1 -0
  14. package/lib/module/table/usepaginatedquery.js +178 -0
  15. package/lib/module/table/usepaginatedquery.js.map +1 -0
  16. package/lib/typescript/header/index.d.ts +1 -3
  17. package/lib/typescript/header/index.d.ts.map +1 -1
  18. package/lib/typescript/icons/backArrow.d.ts +1 -1
  19. package/lib/typescript/icons/bellFill.d.ts +1 -1
  20. package/lib/typescript/icons/bellOutline.d.ts +1 -1
  21. package/lib/typescript/icons/checkmark.d.ts +1 -1
  22. package/lib/typescript/icons/delete.d.ts +1 -1
  23. package/lib/typescript/icons/downChevron.d.ts +1 -1
  24. package/lib/typescript/icons/error.d.ts +1 -1
  25. package/lib/typescript/icons/forwardArrow.d.ts +1 -1
  26. package/lib/typescript/icons/info.d.ts +1 -1
  27. package/lib/typescript/icons/leftChevron.d.ts +1 -1
  28. package/lib/typescript/icons/rightChevron.d.ts +1 -1
  29. package/lib/typescript/icons/save.d.ts +1 -1
  30. package/lib/typescript/icons/success.d.ts +1 -1
  31. package/lib/typescript/icons/upChevron.d.ts +1 -1
  32. package/lib/typescript/icons/warning.d.ts +1 -1
  33. package/lib/typescript/index.d.ts +2 -0
  34. package/lib/typescript/index.d.ts.map +1 -1
  35. package/lib/typescript/tabBar/TabBar.d.ts +2 -3
  36. package/lib/typescript/tabBar/TabBar.d.ts.map +1 -1
  37. package/lib/typescript/table/index.d.ts +107 -0
  38. package/lib/typescript/table/index.d.ts.map +1 -0
  39. package/lib/typescript/table/usepaginatedquery.d.ts +114 -0
  40. package/lib/typescript/table/usepaginatedquery.d.ts.map +1 -0
  41. package/lib/typescript/utiles/createIcon.d.ts +1 -1
  42. package/package.json +31 -41
  43. package/src/index.ts +2 -0
  44. package/src/tabBar/TabBar.tsx +1 -1
  45. package/src/table/index.tsx +843 -0
  46. package/src/table/usepaginatedquery.tsx +275 -0
@@ -0,0 +1,644 @@
1
+ "use strict";
2
+
3
+ import React, { useState, useCallback } from "react";
4
+ import { ScrollView, FlatList, useWindowDimensions } from "react-native";
5
+ import { Stack } from "../stack/index.js";
6
+ import { StyledText } from "../text/index.js";
7
+ import { StyledCheckBox } from "../checkBox/index.js";
8
+ import { StyledPressable } from "../pressable/index.js";
9
+ import { theme, palettes } from "../utiles/theme.js";
10
+
11
+ // ─── CompatNode ───────────────────────────────────────────────────────────────
12
+
13
+ // ─── Column definition ────────────────────────────────────────────────────────
14
+
15
+ // ─── Row data ─────────────────────────────────────────────────────────────────
16
+
17
+ // ─── Color tokens ─────────────────────────────────────────────────────────────
18
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
+ const DEFAULT_COLORS = {
20
+ background: palettes.white,
21
+ headerBg: theme.colors.gray[50],
22
+ headerText: theme.colors.gray[400],
23
+ rowBg: palettes.white,
24
+ rowAltBg: palettes.white,
25
+ rowHoverBg: theme.colors.gray[50],
26
+ selectedBg: palettes.indigo[50],
27
+ selectedBorder: palettes.indigo[200],
28
+ border: theme.colors.gray[100],
29
+ divider: theme.colors.gray[100],
30
+ text: theme.colors.gray[900],
31
+ subText: theme.colors.gray[400],
32
+ sortActive: theme.colors.gray[900],
33
+ sortInactive: theme.colors.gray[300],
34
+ checkboxChecked: theme.colors.gray[900],
35
+ emptyText: theme.colors.gray[400]
36
+ };
37
+
38
+ // ─── Props ────────────────────────────────────────────────────────────────────
39
+
40
+ // ─── Sort icon ────────────────────────────────────────────────────────────────
41
+
42
+ const SortIcon = ({
43
+ direction,
44
+ active,
45
+ color,
46
+ inactiveColor
47
+ }) => /*#__PURE__*/_jsxs(Stack, {
48
+ gap: 1,
49
+ marginLeft: 4,
50
+ children: [/*#__PURE__*/_jsx(StyledText, {
51
+ fontSize: 8,
52
+ lineHeight: 9,
53
+ color: active && direction === "asc" ? color : inactiveColor,
54
+ children: "\u25B2"
55
+ }), /*#__PURE__*/_jsx(StyledText, {
56
+ fontSize: 8,
57
+ lineHeight: 9,
58
+ color: active && direction === "desc" ? color : inactiveColor,
59
+ children: "\u25BC"
60
+ })]
61
+ });
62
+
63
+ // ─── Cell wrapper ─────────────────────────────────────────────────────────────
64
+
65
+ const Cell = ({
66
+ width,
67
+ align = "left",
68
+ children,
69
+ isFirst
70
+ }) => /*#__PURE__*/_jsx(Stack, {
71
+ flex: width ? undefined : 1,
72
+ width: width,
73
+ alignItems: align === "center" ? "center" : align === "right" ? "flex-end" : "flex-start",
74
+ paddingHorizontal: isFirst ? 16 : 12,
75
+ paddingVertical: 14,
76
+ justifyContent: "center",
77
+ children: children
78
+ });
79
+
80
+ // ─── StyledTable ──────────────────────────────────────────────────────────────
81
+
82
+ // ─── Card list (phone layout) ─────────────────────────────────────────────────
83
+
84
+ function CardList({
85
+ columns,
86
+ data,
87
+ selectable,
88
+ selectedIds,
89
+ onSelectionChange,
90
+ cardRender,
91
+ emptyText,
92
+ emptyNode,
93
+ pagination,
94
+ pageSize,
95
+ onRowPress,
96
+ colors: colorOverrides,
97
+ borderRadius
98
+ }) {
99
+ const c = {
100
+ ...DEFAULT_COLORS,
101
+ ...colorOverrides
102
+ };
103
+ const br = borderRadius ?? 16;
104
+
105
+ // internal selection
106
+ const [internalSelected, setInternalSelected] = React.useState([]);
107
+ const selectedIds_ = selectedIds ?? internalSelected;
108
+ const toggle = id => {
109
+ const next = selectedIds_.includes(id) ? selectedIds_.filter(s => s !== id) : [...selectedIds_, id];
110
+ setInternalSelected(next);
111
+ onSelectionChange?.(next);
112
+ };
113
+
114
+ // pagination
115
+ const [page, setPage] = React.useState(0);
116
+ const ps = pageSize ?? 10;
117
+ const totalPages = Math.ceil(data.length / ps);
118
+ const visible = pagination ? data.slice(page * ps, (page + 1) * ps) : data;
119
+ if (visible.length === 0) {
120
+ return /*#__PURE__*/_jsx(Stack, {
121
+ paddingVertical: 48,
122
+ alignItems: "center",
123
+ justifyContent: "center",
124
+ children: emptyNode ?? /*#__PURE__*/_jsx(StyledText, {
125
+ fontSize: 14,
126
+ color: c.emptyText,
127
+ children: emptyText ?? "No data"
128
+ })
129
+ });
130
+ }
131
+ return /*#__PURE__*/_jsxs(Stack, {
132
+ gap: 10,
133
+ children: [visible.map((row, idx) => {
134
+ const isSelected = selectedIds_.includes(row.id);
135
+ if (cardRender) {
136
+ return /*#__PURE__*/_jsx(React.Fragment, {
137
+ children: cardRender(row, idx, isSelected, selectable ? () => toggle(row.id) : undefined)
138
+ }, row.id);
139
+ }
140
+
141
+ // ── Default auto-card ─────────────────────────────────────────────
142
+ // Uses column definitions to render label: value pairs.
143
+ const [primary, ...rest] = columns;
144
+ return /*#__PURE__*/_jsxs(StyledPressable, {
145
+ onPress: () => onRowPress?.(row, idx),
146
+ disabled: !onRowPress && !selectable,
147
+ borderRadius: br,
148
+ borderWidth: 1,
149
+ borderColor: isSelected ? c.selectedBorder : c.border,
150
+ backgroundColor: isSelected ? c.selectedBg : c.rowBg,
151
+ borderLeftWidth: isSelected ? 3 : 1,
152
+ borderLeftColor: isSelected ? c.selectedBorder : c.border,
153
+ overflow: "hidden",
154
+ style: {
155
+ shadowColor: "#000",
156
+ shadowOffset: {
157
+ width: 0,
158
+ height: 1
159
+ },
160
+ shadowOpacity: 0.05,
161
+ shadowRadius: 4,
162
+ elevation: 1
163
+ },
164
+ children: [/*#__PURE__*/_jsxs(Stack, {
165
+ horizontal: true,
166
+ alignItems: "center",
167
+ justifyContent: "space-between",
168
+ paddingHorizontal: 14,
169
+ paddingVertical: 12,
170
+ borderBottomWidth: 1,
171
+ borderBottomColor: c.divider,
172
+ backgroundColor: c.headerBg,
173
+ children: [/*#__PURE__*/_jsx(Stack, {
174
+ flex: 1,
175
+ children: primary.render ? primary.render(row[primary.key], row, idx) : /*#__PURE__*/_jsx(StyledText, {
176
+ fontSize: 14,
177
+ fontWeight: "700",
178
+ color: c.text,
179
+ numberOfLines: 1,
180
+ children: row[primary.key]
181
+ })
182
+ }), selectable && /*#__PURE__*/_jsx(StyledCheckBox, {
183
+ checked: isSelected,
184
+ onCheck: () => toggle(row.id),
185
+ size: 18,
186
+ checkedColor: c.checkboxChecked
187
+ })]
188
+ }), /*#__PURE__*/_jsx(Stack, {
189
+ paddingHorizontal: 14,
190
+ paddingVertical: 10,
191
+ gap: 8,
192
+ children: rest.map(col => /*#__PURE__*/_jsxs(Stack, {
193
+ horizontal: true,
194
+ alignItems: "center",
195
+ justifyContent: "space-between",
196
+ gap: 8,
197
+ children: [/*#__PURE__*/_jsx(StyledText, {
198
+ fontSize: 12,
199
+ color: c.subText,
200
+ fontWeight: "500",
201
+ children: col.title
202
+ }), /*#__PURE__*/_jsx(Stack, {
203
+ alignItems: "flex-end",
204
+ children: col.render ? col.render(row[col.key], row, idx) : /*#__PURE__*/_jsx(StyledText, {
205
+ fontSize: 13,
206
+ color: c.text,
207
+ children: row[col.key] ?? "—"
208
+ })
209
+ })]
210
+ }, col.key))
211
+ })]
212
+ }, row.id);
213
+ }), pagination && totalPages > 1 && /*#__PURE__*/_jsxs(Stack, {
214
+ horizontal: true,
215
+ alignItems: "center",
216
+ justifyContent: "space-between",
217
+ paddingVertical: 4,
218
+ children: [/*#__PURE__*/_jsxs(StyledText, {
219
+ fontSize: 12,
220
+ color: c.subText,
221
+ children: [page * ps + 1, "\u2013", Math.min((page + 1) * ps, data.length), " of ", data.length]
222
+ }), /*#__PURE__*/_jsxs(Stack, {
223
+ horizontal: true,
224
+ gap: 6,
225
+ children: [/*#__PURE__*/_jsx(StyledPressable, {
226
+ onPress: () => setPage(p => Math.max(0, p - 1)),
227
+ disabled: page === 0,
228
+ paddingHorizontal: 12,
229
+ paddingVertical: 6,
230
+ borderRadius: 8,
231
+ borderWidth: 1,
232
+ borderColor: page === 0 ? c.border : c.sortActive,
233
+ opacity: page === 0 ? 0.4 : 1,
234
+ children: /*#__PURE__*/_jsx(StyledText, {
235
+ fontSize: 12,
236
+ fontWeight: "600",
237
+ color: c.text,
238
+ children: "\u2190 Prev"
239
+ })
240
+ }), /*#__PURE__*/_jsx(StyledPressable, {
241
+ onPress: () => setPage(p => Math.min(totalPages - 1, p + 1)),
242
+ disabled: page >= totalPages - 1,
243
+ paddingHorizontal: 12,
244
+ paddingVertical: 6,
245
+ borderRadius: 8,
246
+ borderWidth: 1,
247
+ borderColor: page >= totalPages - 1 ? c.border : c.sortActive,
248
+ opacity: page >= totalPages - 1 ? 0.4 : 1,
249
+ children: /*#__PURE__*/_jsx(StyledText, {
250
+ fontSize: 12,
251
+ fontWeight: "600",
252
+ color: c.text,
253
+ children: "Next \u2192"
254
+ })
255
+ })]
256
+ })]
257
+ })]
258
+ });
259
+ }
260
+ export function StyledTable({
261
+ columns,
262
+ data,
263
+ selectable = false,
264
+ selectedIds: controlledSelectedIds,
265
+ onSelectionChange,
266
+ sortKey: controlledSortKey,
267
+ sortDirection: controlledSortDir,
268
+ onSort,
269
+ pagination = false,
270
+ pageSize = 10,
271
+ striped = false,
272
+ showDivider = true,
273
+ scrollable = false,
274
+ emptyText = "No data",
275
+ emptyNode,
276
+ colors: colorOverrides,
277
+ borderRadius = 16,
278
+ bordered = true,
279
+ virtualized,
280
+ cardBreakpoint = 768,
281
+ forceTable,
282
+ forceCards,
283
+ cardRender,
284
+ externalPagination = false,
285
+ currentPage = 0,
286
+ totalPages: externalTotalPages,
287
+ totalCount,
288
+ onPageChange,
289
+ loading = false,
290
+ onRowPress
291
+ }) {
292
+ const {
293
+ width
294
+ } = useWindowDimensions();
295
+ const isCardMode = forceCards ? true : forceTable ? false : cardBreakpoint > 0 && width < cardBreakpoint;
296
+
297
+ // ── Card mode — render rows as stacked cards ─────────────────────────────
298
+ if (isCardMode) {
299
+ return /*#__PURE__*/_jsx(CardList, {
300
+ columns: columns,
301
+ data: data,
302
+ selectable: selectable,
303
+ selectedIds: controlledSelectedIds,
304
+ onSelectionChange: onSelectionChange,
305
+ cardRender: cardRender,
306
+ emptyText: emptyText,
307
+ emptyNode: emptyNode,
308
+ pagination: pagination,
309
+ pageSize: pageSize,
310
+ onRowPress: onRowPress,
311
+ colors: colorOverrides,
312
+ borderRadius: borderRadius
313
+ });
314
+ }
315
+ const c = {
316
+ ...DEFAULT_COLORS,
317
+ ...colorOverrides
318
+ };
319
+
320
+ // ── Internal selection state (uncontrolled fallback) ───────────────────
321
+ const [internalSelected, setInternalSelected] = useState([]);
322
+ const selectedIds = controlledSelectedIds ?? internalSelected;
323
+ const toggleRow = useCallback(id => {
324
+ const next = selectedIds.includes(id) ? selectedIds.filter(s => s !== id) : [...selectedIds, id];
325
+ setInternalSelected(next);
326
+ onSelectionChange?.(next);
327
+ }, [selectedIds, onSelectionChange]);
328
+ const toggleAll = useCallback(() => {
329
+ const allIds = data.map(r => r.id);
330
+ const allSelected = allIds.every(id => selectedIds.includes(id));
331
+ const next = allSelected ? [] : allIds;
332
+ setInternalSelected(next);
333
+ onSelectionChange?.(next);
334
+ }, [data, selectedIds, onSelectionChange]);
335
+ const allSelected = data.length > 0 && data.every(r => selectedIds.includes(r.id));
336
+
337
+ // ── Internal sort state (uncontrolled fallback) ────────────────────────
338
+ const [internalSortKey, setInternalSortKey] = useState(null);
339
+ const [internalSortDir, setInternalSortDir] = useState(null);
340
+ const activeSortKey = controlledSortKey ?? internalSortKey;
341
+ const activeSortDir = controlledSortDir ?? internalSortDir;
342
+ const handleSort = useCallback(key => {
343
+ const next = activeSortKey === key ? activeSortDir === "asc" ? "desc" : activeSortDir === "desc" ? null : "asc" : "asc";
344
+ setInternalSortKey(next === null ? null : key);
345
+ setInternalSortDir(next);
346
+ onSort?.(key, next);
347
+ }, [activeSortKey, activeSortDir, onSort]);
348
+
349
+ // ── Client-side sort (used when onSort not provided) ───────────────────
350
+ const sortedData = React.useMemo(() => {
351
+ if (!activeSortKey || !activeSortDir || onSort) return data;
352
+ return [...data].sort((a, b) => {
353
+ const av = a[activeSortKey];
354
+ const bv = b[activeSortKey];
355
+ const cmp = typeof av === "number" && typeof bv === "number" ? av - bv : String(av ?? "").localeCompare(String(bv ?? ""));
356
+ return activeSortDir === "asc" ? cmp : -cmp;
357
+ });
358
+ }, [data, activeSortKey, activeSortDir, onSort]);
359
+
360
+ // ── Pagination ────────────────────────────────────────────────────────
361
+ const [internalPage, setInternalPage] = useState(0);
362
+
363
+ // External mode: parent controls page + data
364
+ // Internal mode: we slice sortedData ourselves
365
+ const page = externalPagination ? currentPage : internalPage;
366
+ const totalPages = externalPagination ? externalTotalPages ?? 1 : Math.ceil(sortedData.length / pageSize);
367
+ const visibleData = externalPagination ? sortedData // parent already gave us just this page
368
+ : pagination ? sortedData.slice(page * pageSize, (page + 1) * pageSize) : sortedData;
369
+
370
+ // Auto-enable FlatList virtualisation for large unpaginated datasets
371
+ const useVirtualized = virtualized ?? (!pagination && !externalPagination && visibleData.length > 50);
372
+ const handlePageChange = p => {
373
+ if (externalPagination) {
374
+ onPageChange?.(p);
375
+ } else {
376
+ setInternalPage(p);
377
+ }
378
+ };
379
+
380
+ // Row count label
381
+ const rowStart = page * pageSize + 1;
382
+ const rowEnd = externalPagination ? totalCount != null ? Math.min(rowStart + visibleData.length - 1, totalCount) : rowStart + visibleData.length - 1 : Math.min((page + 1) * pageSize, sortedData.length);
383
+ const rowTotal = externalPagination ? totalCount ?? "?" : sortedData.length;
384
+
385
+ // ── Render ────────────────────────────────────────────────────────────
386
+ const tableContent = /*#__PURE__*/_jsxs(Stack, {
387
+ children: [/*#__PURE__*/_jsxs(Stack, {
388
+ horizontal: true,
389
+ backgroundColor: c.headerBg,
390
+ borderTopLeftRadius: borderRadius,
391
+ borderTopRightRadius: borderRadius,
392
+ borderBottomWidth: 1,
393
+ borderBottomColor: c.border,
394
+ children: [selectable && /*#__PURE__*/_jsx(Stack, {
395
+ width: 52,
396
+ paddingHorizontal: 16,
397
+ paddingVertical: 14,
398
+ alignItems: "center",
399
+ justifyContent: "center",
400
+ children: /*#__PURE__*/_jsx(StyledCheckBox, {
401
+ checked: allSelected,
402
+ onCheck: toggleAll,
403
+ size: 18,
404
+ checkedColor: c.checkboxChecked
405
+ })
406
+ }), columns.map((col, i) => /*#__PURE__*/_jsx(Cell, {
407
+ width: col.width,
408
+ align: col.align,
409
+ isFirst: i === 0 && !selectable,
410
+ children: /*#__PURE__*/_jsxs(StyledPressable, {
411
+ flexDirection: "row",
412
+ alignItems: "center",
413
+ onPress: col.sortable ? () => handleSort(col.key) : undefined,
414
+ disabled: !col.sortable,
415
+ children: [/*#__PURE__*/_jsx(StyledText, {
416
+ fontSize: 12,
417
+ fontWeight: "600",
418
+ color: c.headerText,
419
+ letterSpacing: 0.3,
420
+ children: col.title
421
+ }), col.sortable && /*#__PURE__*/_jsx(SortIcon, {
422
+ direction: activeSortDir,
423
+ active: activeSortKey === col.key,
424
+ color: c.sortActive,
425
+ inactiveColor: c.sortInactive
426
+ })]
427
+ })
428
+ }, col.key))]
429
+ }), visibleData.length === 0 ? /*#__PURE__*/_jsx(Stack, {
430
+ paddingVertical: 48,
431
+ alignItems: "center",
432
+ justifyContent: "center",
433
+ backgroundColor: c.rowBg,
434
+ borderBottomLeftRadius: borderRadius,
435
+ borderBottomRightRadius: borderRadius,
436
+ children: emptyNode ?? /*#__PURE__*/_jsx(StyledText, {
437
+ fontSize: 14,
438
+ color: c.emptyText,
439
+ children: emptyText
440
+ })
441
+ }) : useVirtualized ?
442
+ /*#__PURE__*/
443
+ // ── FlatList path — only mounts rows in the viewport ────────────
444
+ _jsx(FlatList, {
445
+ data: visibleData,
446
+ keyExtractor: row => String(row.id)
447
+ // Pass selectedIds + striped as extraData so FlatList knows to re-render
448
+ // when selection changes (FlatList only re-renders items whose key changes
449
+ // otherwise — extraData forces a full diff)
450
+ ,
451
+ extraData: [selectedIds, striped],
452
+ scrollEnabled: false // outer ScrollView handles scrolling
453
+ ,
454
+ renderItem: ({
455
+ item: row,
456
+ index: rowIndex
457
+ }) => {
458
+ const isSelected = selectedIds.includes(row.id);
459
+ const isLast = rowIndex === visibleData.length - 1;
460
+ const isAlt = striped && rowIndex % 2 !== 0;
461
+ const rowBg = isSelected ? c.selectedBg : isAlt ? c.rowAltBg : c.rowBg;
462
+ return /*#__PURE__*/_jsxs(StyledPressable, {
463
+ flexDirection: "row",
464
+ alignItems: "center",
465
+ backgroundColor: rowBg,
466
+ borderLeftWidth: isSelected ? 3 : 0,
467
+ borderLeftColor: isSelected ? c.selectedBorder : "transparent",
468
+ borderBottomWidth: showDivider && !isLast ? 1 : 0,
469
+ borderBottomColor: c.divider,
470
+ borderBottomLeftRadius: isLast ? borderRadius : 0,
471
+ borderBottomRightRadius: isLast ? borderRadius : 0,
472
+ onPress: () => onRowPress?.(row, rowIndex),
473
+ disabled: !onRowPress && !selectable,
474
+ children: [selectable && /*#__PURE__*/_jsx(Stack, {
475
+ width: 52,
476
+ paddingHorizontal: 16,
477
+ paddingVertical: 14,
478
+ alignItems: "center",
479
+ justifyContent: "center",
480
+ children: /*#__PURE__*/_jsx(StyledCheckBox, {
481
+ checked: isSelected,
482
+ onCheck: () => toggleRow(row.id),
483
+ size: 18,
484
+ checkedColor: c.checkboxChecked
485
+ })
486
+ }), columns.map((col, colIndex) => /*#__PURE__*/_jsx(Cell, {
487
+ width: col.width,
488
+ align: col.align,
489
+ isFirst: colIndex === 0 && !selectable,
490
+ children: col.render ? col.render(row[col.key], row, rowIndex) : /*#__PURE__*/_jsx(StyledText, {
491
+ fontSize: 14,
492
+ color: c.text,
493
+ numberOfLines: 1,
494
+ children: row[col.key] ?? "—"
495
+ })
496
+ }, col.key))]
497
+ });
498
+ }
499
+ }) :
500
+ // ── Stack.map path — simple, best for ≤ 50 rows ─────────────────
501
+ visibleData.map((row, rowIndex) => {
502
+ const isSelected = selectedIds.includes(row.id);
503
+ const isLast = rowIndex === visibleData.length - 1;
504
+ const isAlt = striped && rowIndex % 2 !== 0;
505
+ const rowBg = isSelected ? c.selectedBg : isAlt ? c.rowAltBg : c.rowBg;
506
+ return /*#__PURE__*/_jsxs(StyledPressable, {
507
+ flexDirection: "row",
508
+ alignItems: "center",
509
+ backgroundColor: rowBg,
510
+ borderLeftWidth: isSelected ? 3 : 0,
511
+ borderLeftColor: isSelected ? c.selectedBorder : "transparent",
512
+ borderBottomWidth: showDivider && !isLast ? 1 : 0,
513
+ borderBottomColor: c.divider,
514
+ borderBottomLeftRadius: isLast ? borderRadius : 0,
515
+ borderBottomRightRadius: isLast ? borderRadius : 0,
516
+ onPress: () => onRowPress?.(row, rowIndex),
517
+ disabled: !onRowPress && !selectable,
518
+ children: [selectable && /*#__PURE__*/_jsx(Stack, {
519
+ width: 52,
520
+ paddingHorizontal: 16,
521
+ paddingVertical: 14,
522
+ alignItems: "center",
523
+ justifyContent: "center",
524
+ children: /*#__PURE__*/_jsx(StyledCheckBox, {
525
+ checked: isSelected,
526
+ onCheck: () => toggleRow(row.id),
527
+ size: 18,
528
+ checkedColor: c.checkboxChecked
529
+ })
530
+ }), columns.map((col, colIndex) => /*#__PURE__*/_jsx(Cell, {
531
+ width: col.width,
532
+ align: col.align,
533
+ isFirst: colIndex === 0 && !selectable,
534
+ children: col.render ? col.render(row[col.key], row, rowIndex) : /*#__PURE__*/_jsx(StyledText, {
535
+ fontSize: 14,
536
+ color: c.text,
537
+ numberOfLines: 1,
538
+ children: row[col.key] ?? "—"
539
+ })
540
+ }, col.key))]
541
+ }, row.id);
542
+ }), (pagination || externalPagination) && totalPages > 1 && /*#__PURE__*/_jsxs(Stack, {
543
+ horizontal: true,
544
+ alignItems: "center",
545
+ justifyContent: "space-between",
546
+ paddingHorizontal: 16,
547
+ paddingVertical: 12,
548
+ borderTopWidth: 1,
549
+ borderTopColor: c.border,
550
+ backgroundColor: c.headerBg,
551
+ borderBottomLeftRadius: borderRadius,
552
+ borderBottomRightRadius: borderRadius,
553
+ children: [/*#__PURE__*/_jsxs(StyledText, {
554
+ fontSize: 12,
555
+ color: c.subText,
556
+ children: [rowStart, "\u2013", rowEnd, " of ", rowTotal]
557
+ }), /*#__PURE__*/_jsxs(Stack, {
558
+ horizontal: true,
559
+ gap: 6,
560
+ children: [Array.from({
561
+ length: totalPages
562
+ }, (_, i) => i).filter(i => i === 0 || i === totalPages - 1 || Math.abs(i - page) <= 1).reduce((acc, i, idx, arr) => {
563
+ if (idx > 0 && i - arr[idx - 1] > 1) acc.push("…");
564
+ acc.push(i);
565
+ return acc;
566
+ }, []).map((item, idx) => item === "…" ? /*#__PURE__*/_jsx(StyledText, {
567
+ fontSize: 12,
568
+ color: c.subText,
569
+ paddingHorizontal: 4,
570
+ children: "\u2026"
571
+ }, `ellipsis-${idx}`) : /*#__PURE__*/_jsx(StyledPressable, {
572
+ onPress: () => handlePageChange(item),
573
+ disabled: loading,
574
+ paddingHorizontal: 10,
575
+ paddingVertical: 6,
576
+ borderRadius: 8,
577
+ borderWidth: 1,
578
+ borderColor: page === item ? c.sortActive : c.border,
579
+ backgroundColor: page === item ? c.sortActive : "transparent",
580
+ children: /*#__PURE__*/_jsx(StyledText, {
581
+ fontSize: 12,
582
+ fontWeight: "600",
583
+ color: page === item ? c.background : c.text,
584
+ children: item + 1
585
+ })
586
+ }, item)), /*#__PURE__*/_jsx(StyledPressable, {
587
+ onPress: () => handlePageChange(Math.min(totalPages - 1, page + 1)),
588
+ disabled: page >= totalPages - 1 || loading,
589
+ paddingHorizontal: 12,
590
+ paddingVertical: 6,
591
+ borderRadius: 8,
592
+ borderWidth: 1,
593
+ borderColor: page >= totalPages - 1 ? c.border : c.sortActive,
594
+ opacity: page >= totalPages - 1 ? 0.4 : 1,
595
+ children: /*#__PURE__*/_jsx(StyledText, {
596
+ fontSize: 12,
597
+ fontWeight: "600",
598
+ color: c.text,
599
+ children: "\u2192"
600
+ })
601
+ })]
602
+ })]
603
+ }), loading && /*#__PURE__*/_jsx(Stack, {
604
+ position: "absolute",
605
+ top: 0,
606
+ left: 0,
607
+ right: 0,
608
+ bottom: 0,
609
+ backgroundColor: "rgba(255,255,255,0.7)",
610
+ alignItems: "center",
611
+ justifyContent: "center",
612
+ borderRadius: borderRadius,
613
+ children: /*#__PURE__*/_jsx(StyledText, {
614
+ fontSize: 13,
615
+ color: c.subText,
616
+ children: "Loading\u2026"
617
+ })
618
+ })]
619
+ });
620
+ return /*#__PURE__*/_jsx(Stack, {
621
+ borderRadius: borderRadius,
622
+ borderWidth: bordered ? 1 : 0,
623
+ borderColor: c.border,
624
+ overflow: "hidden",
625
+ backgroundColor: c.background,
626
+ style: bordered ? {
627
+ shadowColor: "#000",
628
+ shadowOffset: {
629
+ width: 0,
630
+ height: 1
631
+ },
632
+ shadowOpacity: 0.06,
633
+ shadowRadius: 8,
634
+ elevation: 2
635
+ } : undefined,
636
+ children: scrollable ? /*#__PURE__*/_jsx(ScrollView, {
637
+ horizontal: true,
638
+ showsHorizontalScrollIndicator: false,
639
+ children: tableContent
640
+ }) : tableContent
641
+ });
642
+ }
643
+ export default StyledTable;
644
+ //# sourceMappingURL=index.js.map