@thangnqdev/ui 0.1.2 → 0.2.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/LICENSE +21 -0
- package/README.md +54 -206
- package/dist/bento/index.cjs.map +1 -1
- package/dist/bento/index.js +2 -2
- package/dist/bento/styles.css +2 -46
- package/dist/buttons/index.cjs +111 -18
- package/dist/buttons/index.cjs.map +1 -1
- package/dist/buttons/index.d.cts +1 -1
- package/dist/buttons/index.d.ts +1 -1
- package/dist/buttons/index.js +3 -3
- package/dist/buttons/styles.css +2 -6
- package/dist/{chunk-4S6L5V7X.js → chunk-2YJBW4E2.js} +2 -2
- package/dist/chunk-2YJBW4E2.js.map +1 -0
- package/dist/{chunk-F5Q7BTMH.js → chunk-4CRFNALF.js} +1011 -556
- package/dist/chunk-4CRFNALF.js.map +1 -0
- package/dist/{chunk-LWFRUJRU.js → chunk-4MS6ZHFQ.js} +225 -41
- package/dist/chunk-4MS6ZHFQ.js.map +1 -0
- package/dist/{chunk-2OXZK6IP.js → chunk-77KTYOMQ.js} +3 -3
- package/dist/chunk-77KTYOMQ.js.map +1 -0
- package/dist/{chunk-IABPUCAQ.js → chunk-ADO3SVUA.js} +2 -2
- package/dist/chunk-ADO3SVUA.js.map +1 -0
- package/dist/{chunk-GXI2H5XA.js → chunk-D7FB3TCA.js} +3 -3
- package/dist/chunk-D7FB3TCA.js.map +1 -0
- package/dist/chunk-DSEL7ELZ.js +314 -0
- package/dist/chunk-DSEL7ELZ.js.map +1 -0
- package/dist/{chunk-KJRBRTQE.js → chunk-EXFR2BFJ.js} +37 -28
- package/dist/chunk-EXFR2BFJ.js.map +1 -0
- package/dist/{chunk-PF4ZHGVW.js → chunk-GXWB6BSY.js} +116 -23
- package/dist/chunk-GXWB6BSY.js.map +1 -0
- package/dist/{chunk-66VWUJEI.js → chunk-I2FQBMVW.js} +3 -3
- package/dist/chunk-I2FQBMVW.js.map +1 -0
- package/dist/{chunk-EU2LPUYP.js → chunk-I5O2WCGF.js} +3 -3
- package/dist/chunk-I5O2WCGF.js.map +1 -0
- package/dist/{chunk-ATYGDTMK.js → chunk-ME4XILG5.js} +5 -5
- package/dist/chunk-ME4XILG5.js.map +1 -0
- package/dist/{chunk-5FZ6ZFII.js → chunk-PC5SZFZC.js} +373 -150
- package/dist/chunk-PC5SZFZC.js.map +1 -0
- package/dist/{chunk-C4SUXMI3.js → chunk-S6XJMYME.js} +3 -3
- package/dist/chunk-S6XJMYME.js.map +1 -0
- package/dist/{chunk-A7P3O5Z5.js → chunk-V52JOSDF.js} +3 -3
- package/dist/chunk-V52JOSDF.js.map +1 -0
- package/dist/{chunk-NFVONJUK.js → chunk-W5WNWTQC.js} +455 -211
- package/dist/chunk-W5WNWTQC.js.map +1 -0
- package/dist/{chunk-WAFHC4DQ.js → chunk-YJ64RI7J.js} +3 -3
- package/dist/chunk-YJ64RI7J.js.map +1 -0
- package/dist/chunk-YOCGBORV.js +155 -0
- package/dist/chunk-YOCGBORV.js.map +1 -0
- package/dist/chunk-ZEDXARXW.js +96 -0
- package/dist/chunk-ZEDXARXW.js.map +1 -0
- package/dist/components.css +2 -0
- package/dist/core/index.cjs +33 -24
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +2 -2
- package/dist/core/styles.css +2 -134
- package/dist/data-display/index.cjs +770 -247
- package/dist/data-display/index.cjs.map +1 -1
- package/dist/data-display/index.d.cts +1 -1
- package/dist/data-display/index.d.ts +1 -1
- package/dist/data-display/index.js +5 -4
- package/dist/data-display/styles.css +2 -4
- package/dist/feedback/index.cjs.map +1 -1
- package/dist/feedback/index.js +2 -2
- package/dist/feedback/styles.css +2 -4
- package/dist/forms/index.cjs +1211 -459
- package/dist/forms/index.cjs.map +1 -1
- package/dist/forms/index.d.cts +1 -1
- package/dist/forms/index.d.ts +1 -1
- package/dist/forms/index.js +8 -8
- package/dist/forms/styles.css +2 -6
- package/dist/glass/index.cjs.map +1 -1
- package/dist/glass/index.js +2 -2
- package/dist/glass/styles.css +2 -81
- package/dist/{index-D6fE7w-b.d.cts → index-BGt_hecO.d.cts} +1 -0
- package/dist/{index-D6fE7w-b.d.ts → index-BGt_hecO.d.ts} +1 -0
- package/dist/{index-DzcWh1Hs.d.cts → index-BtDvpZCf.d.cts} +7 -0
- package/dist/{index-DzcWh1Hs.d.ts → index-BtDvpZCf.d.ts} +7 -0
- package/dist/{index-Cle6QzQl.d.ts → index-COX1sBUN.d.ts} +27 -3
- package/dist/{index-BkRqGNG1.d.ts → index-Cg8MuP7u.d.cts} +40 -13
- package/dist/{index-BkRqGNG1.d.cts → index-Cg8MuP7u.d.ts} +40 -13
- package/dist/{index-CenuF_P2.d.ts → index-DHkPRTvE.d.cts} +39 -8
- package/dist/{index-CenuF_P2.d.cts → index-DHkPRTvE.d.ts} +39 -8
- package/dist/{index-TyK-Ldpy.d.cts → index-Du_oht9k.d.cts} +27 -3
- package/dist/index.cjs +2481 -917
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +19 -19
- package/dist/layout/index.cjs.map +1 -1
- package/dist/layout/index.js +2 -2
- package/dist/layout/styles.css +2 -8
- package/dist/navigation/index.cjs +288 -48
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +1 -1
- package/dist/navigation/index.d.ts +1 -1
- package/dist/navigation/index.js +6 -6
- package/dist/navigation/styles.css +2 -4
- package/dist/overlays/index.cjs +566 -229
- package/dist/overlays/index.cjs.map +1 -1
- package/dist/overlays/index.d.cts +1 -1
- package/dist/overlays/index.d.ts +1 -1
- package/dist/overlays/index.js +7 -7
- package/dist/overlays/styles.css +2 -8
- package/dist/reset.css +45 -0
- package/dist/styles.css +1 -1
- package/dist/tokens.css +11 -0
- package/dist/typography/index.cjs.map +1 -1
- package/dist/typography/index.js +4 -4
- package/dist/typography/styles.css +2 -5
- package/llms.txt +211 -113
- package/package.json +160 -116
- package/src/bento/BentoCard.tsx +140 -140
- package/src/bento/BentoGrid.tsx +50 -50
- package/src/bento/index.ts +2 -2
- package/src/bento/tokens.css +46 -46
- package/src/buttons/Button.tsx +104 -104
- package/src/buttons/ButtonGroup.tsx +43 -43
- package/src/buttons/IconButton.tsx +79 -79
- package/src/buttons/SplitButton.tsx +186 -86
- package/src/buttons/ToggleButton.tsx +157 -157
- package/src/buttons/index.ts +5 -5
- package/src/buttons/tokens.css +6 -6
- package/src/core/ThemeProvider.tsx +135 -123
- package/src/core/index.ts +2 -2
- package/src/core/tokens.css +134 -134
- package/src/data-display/Accordion.tsx +147 -147
- package/src/data-display/Avatar.tsx +134 -134
- package/src/data-display/Card.tsx +112 -112
- package/src/data-display/Chip.tsx +74 -74
- package/src/data-display/DataTablePro.tsx +299 -121
- package/src/data-display/StatCard.tsx +60 -60
- package/src/data-display/Table.tsx +74 -74
- package/src/data-display/Timeline.tsx +62 -62
- package/src/data-display/TreeView.tsx +243 -104
- package/src/data-display/tokens.css +4 -4
- package/src/feedback/Alert.tsx +80 -80
- package/src/feedback/EmptyState.tsx +45 -45
- package/src/feedback/Skeleton.tsx +66 -66
- package/src/feedback/Spinner.tsx +65 -65
- package/src/feedback/index.ts +5 -5
- package/src/feedback/tokens.css +4 -4
- package/src/forms/Checkbox.tsx +149 -69
- package/src/forms/CheckboxGroup.tsx +76 -29
- package/src/forms/Combobox.tsx +172 -28
- package/src/forms/DatePicker.tsx +385 -81
- package/src/forms/FileUpload.tsx +51 -7
- package/src/forms/FormField.tsx +115 -115
- package/src/forms/Input.tsx +151 -151
- package/src/forms/NumberInput.tsx +34 -20
- package/src/forms/PasswordInput.tsx +35 -35
- package/src/forms/PinInput.tsx +139 -125
- package/src/forms/Radio.tsx +142 -142
- package/src/forms/RangeSlider.tsx +237 -111
- package/src/forms/SearchInput.tsx +34 -34
- package/src/forms/Select.tsx +103 -103
- package/src/forms/Slider.tsx +85 -85
- package/src/forms/Textarea.tsx +114 -114
- package/src/forms/tokens.css +6 -6
- package/src/glass/GlassButton.tsx +59 -59
- package/src/glass/GlassCard.tsx +71 -71
- package/src/glass/index.ts +3 -3
- package/src/glass/tokens.css +81 -81
- package/src/index.ts +26 -26
- package/src/layout/AspectRatio.tsx +39 -39
- package/src/layout/Container.tsx +53 -53
- package/src/layout/Divider.tsx +61 -61
- package/src/layout/Flex.tsx +79 -79
- package/src/layout/Grid.tsx +124 -124
- package/src/layout/PageLayout.tsx +59 -59
- package/src/layout/Section.tsx +47 -47
- package/src/layout/Spacer.tsx +30 -30
- package/src/layout/Stack.tsx +88 -88
- package/src/layout/tokens.css +8 -8
- package/src/navigation/Breadcrumb.tsx +73 -73
- package/src/navigation/CommandPalette.tsx +142 -142
- package/src/navigation/DropdownMenu.tsx +244 -160
- package/src/navigation/Pagination.tsx +114 -114
- package/src/navigation/Stepper.tsx +93 -93
- package/src/navigation/Tabs.tsx +265 -133
- package/src/navigation/index.ts +6 -6
- package/src/navigation/tokens.css +4 -4
- package/src/overlays/AlertDialog.tsx +63 -54
- package/src/overlays/BottomSheet.tsx +30 -10
- package/src/overlays/ContextMenu.tsx +51 -9
- package/src/overlays/Drawer.tsx +160 -145
- package/src/overlays/FocusTrap.tsx +122 -49
- package/src/overlays/Modal.tsx +296 -219
- package/src/overlays/Popover.tsx +55 -25
- package/src/overlays/Portal.tsx +23 -23
- package/src/overlays/Toast.tsx +175 -137
- package/src/overlays/Tooltip.tsx +125 -100
- package/src/overlays/tokens.css +8 -8
- package/src/registry/components.ts +1368 -0
- package/src/styles/components.css +39 -0
- package/src/styles/index.css +2 -93
- package/src/styles/reset.css +45 -0
- package/src/styles/tokens.css +11 -2
- package/src/typography/Blockquote.tsx +32 -32
- package/src/typography/Code.tsx +89 -89
- package/src/typography/Heading.tsx +56 -56
- package/src/typography/Kbd.tsx +25 -25
- package/src/typography/Label.tsx +47 -47
- package/src/typography/Link.tsx +56 -56
- package/src/typography/Text.tsx +62 -62
- package/src/typography/index.ts +7 -7
- package/src/typography/tokens.css +5 -5
- package/src/utils/cn.ts +6 -6
- package/src/utils/scroll-lock.ts +19 -0
- package/src/utils/useControllableState.ts +54 -0
- package/ui-contract.json +192 -35
- package/dist/chunk-2OXZK6IP.js.map +0 -1
- package/dist/chunk-4S6L5V7X.js.map +0 -1
- package/dist/chunk-5FZ6ZFII.js.map +0 -1
- package/dist/chunk-66VWUJEI.js.map +0 -1
- package/dist/chunk-A7P3O5Z5.js.map +0 -1
- package/dist/chunk-ATYGDTMK.js.map +0 -1
- package/dist/chunk-C4SUXMI3.js.map +0 -1
- package/dist/chunk-EU2LPUYP.js.map +0 -1
- package/dist/chunk-F5Q7BTMH.js.map +0 -1
- package/dist/chunk-GXI2H5XA.js.map +0 -1
- package/dist/chunk-H3LCNPMC.js +0 -101
- package/dist/chunk-H3LCNPMC.js.map +0 -1
- package/dist/chunk-IABPUCAQ.js.map +0 -1
- package/dist/chunk-KJRBRTQE.js.map +0 -1
- package/dist/chunk-LBUBXUYQ.js +0 -40
- package/dist/chunk-LBUBXUYQ.js.map +0 -1
- package/dist/chunk-LWFRUJRU.js.map +0 -1
- package/dist/chunk-NFVONJUK.js.map +0 -1
- package/dist/chunk-PF4ZHGVW.js.map +0 -1
- package/dist/chunk-WAFHC4DQ.js.map +0 -1
- package/dist/chunk-X76KBH4Y.js +0 -71
- package/dist/chunk-X76KBH4Y.js.map +0 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { chipVariants, Chip } from './chunk-
|
|
2
|
-
import { Button } from './chunk-
|
|
3
|
-
import { __export, cn } from './chunk-
|
|
4
|
-
import React9, { forwardRef, useState, createContext, useContext, useMemo,
|
|
1
|
+
import { chipVariants, Chip, Checkbox } from './chunk-DSEL7ELZ.js';
|
|
2
|
+
import { Button } from './chunk-I2FQBMVW.js';
|
|
3
|
+
import { __export, cn } from './chunk-2YJBW4E2.js';
|
|
4
|
+
import React9, { forwardRef, useState, createContext, useContext, useMemo, useEffect, useRef } from 'react';
|
|
5
5
|
import { cva } from 'class-variance-authority';
|
|
6
6
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
7
|
-
import { ChevronDown, ArrowUpRight, ArrowDownRight, Minus, Search, Download, ChevronUp, ChevronsUpDown, ChevronLeft, ChevronRight, FolderOpen, Folder, FileCode, Image, FileText } from 'lucide-react';
|
|
7
|
+
import { ChevronDown, ArrowUpRight, ArrowDownRight, Minus, Search, Download, Loader2, ChevronUp, ChevronsUpDown, ChevronLeft, ChevronRight, FolderOpen, Folder, FileCode, Image, FileText } from 'lucide-react';
|
|
8
8
|
|
|
9
9
|
// src/data-display/index.ts
|
|
10
10
|
var data_display_exports = {};
|
|
@@ -433,79 +433,183 @@ function DataTablePro({
|
|
|
433
433
|
searchable = true,
|
|
434
434
|
searchPlaceholder = "Search all records...",
|
|
435
435
|
selectable = true,
|
|
436
|
+
selectedKeys: controlledSelectedKeys,
|
|
437
|
+
defaultSelectedKeys = [],
|
|
436
438
|
onSelectionChange,
|
|
437
439
|
pageSize: initialPageSize = 10,
|
|
438
440
|
pageSizeOptions = [5, 10, 25, 50],
|
|
439
441
|
title,
|
|
440
442
|
description,
|
|
441
443
|
actions,
|
|
442
|
-
className
|
|
444
|
+
className,
|
|
445
|
+
loading = false,
|
|
446
|
+
// Multi-column sorting
|
|
447
|
+
multiSort = true,
|
|
448
|
+
sorting: controlledSorting,
|
|
449
|
+
defaultSorting = [],
|
|
450
|
+
onSortingChange,
|
|
451
|
+
// Server-side / manual mode props
|
|
452
|
+
manualPagination = false,
|
|
453
|
+
manualSorting = false,
|
|
454
|
+
manualFiltering = false,
|
|
455
|
+
pageIndex: controlledPageIndex,
|
|
456
|
+
pageCount: controlledPageCount,
|
|
457
|
+
totalCount: controlledTotalCount,
|
|
458
|
+
onPaginationChange,
|
|
459
|
+
searchQuery: controlledSearchQuery,
|
|
460
|
+
onSearchChange,
|
|
461
|
+
onSelectAllDataset,
|
|
462
|
+
emptyText = "No matching records found."
|
|
443
463
|
}) {
|
|
444
|
-
const [
|
|
445
|
-
const
|
|
446
|
-
const [
|
|
447
|
-
const [
|
|
448
|
-
const [
|
|
449
|
-
const
|
|
464
|
+
const [internalSearch, setInternalSearch] = useState("");
|
|
465
|
+
const search = controlledSearchQuery !== void 0 ? controlledSearchQuery : internalSearch;
|
|
466
|
+
const [internalSorting, setInternalSorting] = useState(defaultSorting);
|
|
467
|
+
const currentSorting = controlledSorting !== void 0 ? controlledSorting ?? [] : internalSorting;
|
|
468
|
+
const [internalCurrentPage, setInternalCurrentPage] = useState(1);
|
|
469
|
+
const currentPage = controlledPageIndex !== void 0 ? controlledPageIndex : internalCurrentPage;
|
|
470
|
+
const [internalPageSize, setInternalPageSize] = useState(initialPageSize);
|
|
471
|
+
const pageSize = internalPageSize;
|
|
472
|
+
const [internalSelectedKeys, setInternalSelectedKeys] = useState(defaultSelectedKeys);
|
|
473
|
+
const isSelectedControlled = controlledSelectedKeys !== void 0;
|
|
474
|
+
const selectedKeys = isSelectedControlled ? controlledSelectedKeys : internalSelectedKeys;
|
|
475
|
+
const handleSelectionUpdate = (nextKeys) => {
|
|
476
|
+
if (!isSelectedControlled) {
|
|
477
|
+
setInternalSelectedKeys(nextKeys);
|
|
478
|
+
}
|
|
479
|
+
onSelectionChange?.(nextKeys);
|
|
480
|
+
};
|
|
450
481
|
const filteredData = useMemo(() => {
|
|
451
|
-
if (!search.trim()) return data;
|
|
482
|
+
if (manualFiltering || !search.trim()) return data;
|
|
452
483
|
const q = search.toLowerCase();
|
|
453
484
|
return data.filter((row) => {
|
|
454
|
-
return
|
|
485
|
+
return columns.some((col) => {
|
|
486
|
+
const val = col.accessor ? col.accessor(row) : row[col.key];
|
|
455
487
|
if (val === null || val === void 0) return false;
|
|
456
488
|
return String(val).toLowerCase().includes(q);
|
|
457
489
|
});
|
|
458
490
|
});
|
|
459
|
-
}, [data, search]);
|
|
491
|
+
}, [data, search, columns, manualFiltering]);
|
|
460
492
|
const sortedData = useMemo(() => {
|
|
461
|
-
if (
|
|
462
|
-
const col = columns.find((c) => c.key === sortKey);
|
|
493
|
+
if (manualSorting || currentSorting.length === 0) return filteredData;
|
|
463
494
|
return [...filteredData].sort((a, b) => {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
495
|
+
for (const { key, direction } of currentSorting) {
|
|
496
|
+
const col = columns.find((c) => c.key === key);
|
|
497
|
+
let comp = 0;
|
|
498
|
+
if (col?.sortComparator) {
|
|
499
|
+
comp = col.sortComparator(a, b);
|
|
500
|
+
} else {
|
|
501
|
+
const valA = col?.accessor ? col.accessor(a) : a[key];
|
|
502
|
+
const valB = col?.accessor ? col.accessor(b) : b[key];
|
|
503
|
+
if (valA === valB) continue;
|
|
504
|
+
if (valA === null || valA === void 0) return 1;
|
|
505
|
+
if (valB === null || valB === void 0) return -1;
|
|
506
|
+
comp = valA < valB ? -1 : 1;
|
|
507
|
+
}
|
|
508
|
+
if (comp !== 0) {
|
|
509
|
+
return direction === "asc" ? comp : -comp;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return 0;
|
|
471
513
|
});
|
|
472
|
-
}, [filteredData,
|
|
473
|
-
const
|
|
514
|
+
}, [filteredData, currentSorting, columns, manualSorting]);
|
|
515
|
+
const totalItems = controlledTotalCount !== void 0 ? controlledTotalCount : sortedData.length;
|
|
516
|
+
const totalPages = controlledPageCount !== void 0 ? Math.max(1, controlledPageCount) : Math.max(1, Math.ceil(totalItems / pageSize));
|
|
517
|
+
useEffect(() => {
|
|
518
|
+
if (!manualPagination && currentPage > totalPages && totalPages > 0) {
|
|
519
|
+
setInternalCurrentPage(totalPages);
|
|
520
|
+
onPaginationChange?.(totalPages, pageSize);
|
|
521
|
+
}
|
|
522
|
+
}, [totalPages, currentPage, manualPagination, pageSize, onPaginationChange]);
|
|
474
523
|
const paginatedData = useMemo(() => {
|
|
524
|
+
if (manualPagination) return data;
|
|
475
525
|
const start = (currentPage - 1) * pageSize;
|
|
476
526
|
return sortedData.slice(start, start + pageSize);
|
|
477
|
-
}, [sortedData, currentPage, pageSize]);
|
|
478
|
-
const handleSort = (key) => {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
527
|
+
}, [data, sortedData, currentPage, pageSize, manualPagination]);
|
|
528
|
+
const handleSort = (key, e) => {
|
|
529
|
+
const isShift = e?.shiftKey || false;
|
|
530
|
+
let nextSorting = [...currentSorting];
|
|
531
|
+
const existingIdx = nextSorting.findIndex((s) => s.key === key);
|
|
532
|
+
if (isShift && multiSort) {
|
|
533
|
+
if (existingIdx >= 0) {
|
|
534
|
+
if (nextSorting[existingIdx].direction === "asc") {
|
|
535
|
+
nextSorting[existingIdx] = { key, direction: "desc" };
|
|
536
|
+
} else {
|
|
537
|
+
nextSorting.splice(existingIdx, 1);
|
|
538
|
+
}
|
|
482
539
|
} else {
|
|
483
|
-
|
|
484
|
-
setSortDirection("asc");
|
|
540
|
+
nextSorting.push({ key, direction: "asc" });
|
|
485
541
|
}
|
|
486
542
|
} else {
|
|
487
|
-
|
|
488
|
-
|
|
543
|
+
if (existingIdx >= 0 && nextSorting.length === 1) {
|
|
544
|
+
if (nextSorting[0].direction === "asc") {
|
|
545
|
+
nextSorting = [{ key, direction: "desc" }];
|
|
546
|
+
} else {
|
|
547
|
+
nextSorting = [];
|
|
548
|
+
}
|
|
549
|
+
} else {
|
|
550
|
+
nextSorting = [{ key, direction: "asc" }];
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (controlledSorting === void 0) {
|
|
554
|
+
setInternalSorting(nextSorting);
|
|
489
555
|
}
|
|
556
|
+
onSortingChange?.(nextSorting);
|
|
490
557
|
};
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
558
|
+
const handlePageChange = (newPage) => {
|
|
559
|
+
const clamped = Math.max(1, Math.min(totalPages, newPage));
|
|
560
|
+
if (controlledPageIndex === void 0) {
|
|
561
|
+
setInternalCurrentPage(clamped);
|
|
562
|
+
}
|
|
563
|
+
onPaginationChange?.(clamped, pageSize);
|
|
564
|
+
};
|
|
565
|
+
const handlePageSizeChange = (newSize) => {
|
|
566
|
+
setInternalPageSize(newSize);
|
|
567
|
+
if (controlledPageIndex === void 0) {
|
|
568
|
+
setInternalCurrentPage(1);
|
|
569
|
+
}
|
|
570
|
+
onPaginationChange?.(1, newSize);
|
|
571
|
+
};
|
|
572
|
+
const handleSearchChange = (query) => {
|
|
573
|
+
if (controlledSearchQuery === void 0) {
|
|
574
|
+
setInternalSearch(query);
|
|
575
|
+
if (controlledPageIndex === void 0) {
|
|
576
|
+
setInternalCurrentPage(1);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
onSearchChange?.(query);
|
|
580
|
+
};
|
|
581
|
+
const currentPageKeys = useMemo(() => paginatedData.map(keyExtractor), [paginatedData, keyExtractor]);
|
|
582
|
+
const isAllCurrentPageSelected = currentPageKeys.length > 0 && currentPageKeys.every((k) => selectedKeys.includes(k));
|
|
583
|
+
const isSomeCurrentPageSelected = currentPageKeys.some((k) => selectedKeys.includes(k)) && !isAllCurrentPageSelected;
|
|
584
|
+
const toggleSelectAllCurrentPage = () => {
|
|
585
|
+
if (isAllCurrentPageSelected) {
|
|
586
|
+
const next = selectedKeys.filter((k) => !currentPageKeys.includes(k));
|
|
587
|
+
handleSelectionUpdate(next);
|
|
495
588
|
} else {
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
onSelectionChange?.(allKeys);
|
|
589
|
+
const combined = Array.from(/* @__PURE__ */ new Set([...selectedKeys, ...currentPageKeys]));
|
|
590
|
+
handleSelectionUpdate(combined);
|
|
499
591
|
}
|
|
500
592
|
};
|
|
501
593
|
const toggleSelectRow = (key) => {
|
|
502
594
|
const next = selectedKeys.includes(key) ? selectedKeys.filter((k) => k !== key) : [...selectedKeys, key];
|
|
503
|
-
|
|
504
|
-
|
|
595
|
+
handleSelectionUpdate(next);
|
|
596
|
+
};
|
|
597
|
+
const canSelectAllDataset = !manualPagination || typeof onSelectAllDataset === "function";
|
|
598
|
+
const selectAllDataset = () => {
|
|
599
|
+
if (manualPagination) {
|
|
600
|
+
onSelectAllDataset?.();
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const allKeys = sortedData.map(keyExtractor);
|
|
604
|
+
handleSelectionUpdate(allKeys);
|
|
605
|
+
};
|
|
606
|
+
const clearSelection = () => {
|
|
607
|
+
handleSelectionUpdate([]);
|
|
505
608
|
};
|
|
506
609
|
const exportCSV = () => {
|
|
610
|
+
const exportRows = manualPagination ? data : sortedData;
|
|
507
611
|
const headers = columns.map((c) => typeof c.header === "string" ? c.header : c.key);
|
|
508
|
-
const rows =
|
|
612
|
+
const rows = exportRows.map(
|
|
509
613
|
(row) => columns.map((c) => {
|
|
510
614
|
const val = c.accessor ? c.accessor(row) : row[c.key];
|
|
511
615
|
return `"${String(val ?? "").replace(/"/g, '""')}"`;
|
|
@@ -520,7 +624,6 @@ function DataTablePro({
|
|
|
520
624
|
link.click();
|
|
521
625
|
document.body.removeChild(link);
|
|
522
626
|
};
|
|
523
|
-
const isAllSelected = paginatedData.length > 0 && selectedKeys.length === paginatedData.length;
|
|
524
627
|
return /* @__PURE__ */ jsxs("div", { className: cn("w-full space-y-4", className), children: [
|
|
525
628
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4", children: [
|
|
526
629
|
(title || description) && /* @__PURE__ */ jsxs("div", { children: [
|
|
@@ -536,10 +639,7 @@ function DataTablePro({
|
|
|
536
639
|
type: "text",
|
|
537
640
|
placeholder: searchPlaceholder,
|
|
538
641
|
value: search,
|
|
539
|
-
onChange: (e) =>
|
|
540
|
-
setSearch(e.target.value);
|
|
541
|
-
setCurrentPage(1);
|
|
542
|
-
},
|
|
642
|
+
onChange: (e) => handleSearchChange(e.target.value),
|
|
543
643
|
className: "w-full h-8 pl-8 pr-3 text-xs rounded-xl bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] hover:border-[var(--ui-border-strong)] focus:outline-none focus:ring-2 focus:ring-[var(--ui-primary)]/40 text-[var(--ui-text-primary)] placeholder:text-[var(--ui-text-muted)] transition-all shadow-inner"
|
|
544
644
|
}
|
|
545
645
|
)
|
|
@@ -548,83 +648,110 @@ function DataTablePro({
|
|
|
548
648
|
actions
|
|
549
649
|
] })
|
|
550
650
|
] }),
|
|
551
|
-
selectedKeys.length > 0 && /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 rounded-xl bg-[var(--ui-primary)]/15 border border-[var(--ui-primary)]/30 flex items-center justify-between animate-in fade-in duration-200", children: [
|
|
552
|
-
/* @__PURE__ */
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
651
|
+
selectedKeys.length > 0 && /* @__PURE__ */ jsxs("div", { className: "px-4 py-2 rounded-xl bg-[var(--ui-primary)]/15 border border-[var(--ui-primary)]/30 flex flex-wrap items-center justify-between gap-2 animate-in fade-in duration-200", children: [
|
|
652
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs font-semibold text-[var(--ui-primary)]", children: [
|
|
653
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
654
|
+
"Selected ",
|
|
655
|
+
selectedKeys.length,
|
|
656
|
+
" records"
|
|
657
|
+
] }),
|
|
658
|
+
canSelectAllDataset && selectedKeys.length < totalItems && /* @__PURE__ */ jsxs(
|
|
659
|
+
"button",
|
|
660
|
+
{
|
|
661
|
+
type: "button",
|
|
662
|
+
onClick: selectAllDataset,
|
|
663
|
+
className: "underline hover:text-[var(--ui-primary)]/80 cursor-pointer font-bold ml-1",
|
|
664
|
+
children: [
|
|
665
|
+
"Select all ",
|
|
666
|
+
totalItems,
|
|
667
|
+
" records"
|
|
668
|
+
]
|
|
669
|
+
}
|
|
670
|
+
)
|
|
671
|
+
] }),
|
|
559
672
|
/* @__PURE__ */ jsx(
|
|
560
673
|
Button,
|
|
561
674
|
{
|
|
562
675
|
size: "xs",
|
|
563
676
|
variant: "ghost",
|
|
564
677
|
className: "text-xs text-rose-500 hover:text-rose-600 hover:bg-rose-500/10",
|
|
565
|
-
onClick:
|
|
566
|
-
setSelectedKeys([]);
|
|
567
|
-
onSelectionChange?.([]);
|
|
568
|
-
},
|
|
678
|
+
onClick: clearSelection,
|
|
569
679
|
children: "Clear Selection"
|
|
570
680
|
}
|
|
571
681
|
)
|
|
572
682
|
] }),
|
|
573
|
-
/* @__PURE__ */
|
|
574
|
-
/* @__PURE__ */ jsx(
|
|
575
|
-
|
|
576
|
-
|
|
683
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-full overflow-x-auto rounded-2xl border border-[var(--ui-border-default)] bg-[var(--ui-bg-surface)] shadow-sm", children: [
|
|
684
|
+
loading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 z-20 bg-[var(--ui-bg-surface)]/60 backdrop-blur-xs flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "w-6 h-6 animate-spin text-[var(--ui-primary)]" }) }),
|
|
685
|
+
/* @__PURE__ */ jsxs(Table, { children: [
|
|
686
|
+
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
|
|
687
|
+
selectable && /* @__PURE__ */ jsx(TableHead, { className: "w-10 px-4", children: /* @__PURE__ */ jsx(
|
|
688
|
+
Checkbox,
|
|
689
|
+
{
|
|
690
|
+
checked: isAllCurrentPageSelected,
|
|
691
|
+
indeterminate: isSomeCurrentPageSelected,
|
|
692
|
+
onCheckedChange: toggleSelectAllCurrentPage,
|
|
693
|
+
"aria-label": "Select all on page"
|
|
694
|
+
}
|
|
695
|
+
) }),
|
|
696
|
+
columns.map((col) => {
|
|
697
|
+
const sortIndex = currentSorting.findIndex((s) => s.key === col.key);
|
|
698
|
+
const sortRule = sortIndex >= 0 ? currentSorting[sortIndex] : null;
|
|
699
|
+
return /* @__PURE__ */ jsx(
|
|
700
|
+
TableHead,
|
|
701
|
+
{
|
|
702
|
+
style: { width: col.width },
|
|
703
|
+
onClick: (e) => col.sortable !== false && handleSort(col.key, e),
|
|
704
|
+
className: cn(
|
|
705
|
+
col.sortable !== false && "cursor-pointer select-none hover:text-[var(--ui-text-primary)] transition-colors"
|
|
706
|
+
),
|
|
707
|
+
children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
708
|
+
/* @__PURE__ */ jsx("span", { children: col.header }),
|
|
709
|
+
col.sortable !== false && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-0.5 text-[var(--ui-text-muted)]", children: [
|
|
710
|
+
sortRule ? sortRule.direction === "asc" ? /* @__PURE__ */ jsx(ChevronUp, { className: "w-3.5 h-3.5 text-[var(--ui-primary)] font-bold" }) : /* @__PURE__ */ jsx(ChevronDown, { className: "w-3.5 h-3.5 text-[var(--ui-primary)] font-bold" }) : /* @__PURE__ */ jsx(ChevronsUpDown, { className: "w-3 h-3 opacity-40" }),
|
|
711
|
+
currentSorting.length > 1 && sortIndex >= 0 && /* @__PURE__ */ jsx("span", { className: "text-[10px] font-mono font-bold text-[var(--ui-primary)]", children: sortIndex + 1 })
|
|
712
|
+
] })
|
|
713
|
+
] })
|
|
714
|
+
},
|
|
715
|
+
col.key
|
|
716
|
+
);
|
|
717
|
+
})
|
|
718
|
+
] }) }),
|
|
719
|
+
/* @__PURE__ */ jsx(TableBody, { children: paginatedData.length === 0 ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(
|
|
720
|
+
TableCell,
|
|
577
721
|
{
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
className: "rounded border-[var(--ui-border-default)] text-[var(--ui-primary)] focus:ring-[var(--ui-primary)] cursor-pointer"
|
|
722
|
+
colSpan: columns.length + (selectable ? 1 : 0),
|
|
723
|
+
className: "h-32 text-center text-xs text-[var(--ui-text-muted)]",
|
|
724
|
+
children: emptyText
|
|
582
725
|
}
|
|
583
|
-
) }),
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
type: "checkbox",
|
|
613
|
-
checked: isSelected,
|
|
614
|
-
onChange: () => toggleSelectRow(key),
|
|
615
|
-
className: "rounded border-[var(--ui-border-default)] text-[var(--ui-primary)] focus:ring-[var(--ui-primary)] cursor-pointer"
|
|
616
|
-
}
|
|
617
|
-
) }),
|
|
618
|
-
columns.map((col) => {
|
|
619
|
-
const cellContent = col.render ? col.render(row, rowIdx) : col.accessor ? col.accessor(row) : row[col.key];
|
|
620
|
-
return /* @__PURE__ */ jsx(TableCell, { children: cellContent }, col.key);
|
|
621
|
-
})
|
|
622
|
-
]
|
|
623
|
-
},
|
|
624
|
-
key
|
|
625
|
-
);
|
|
626
|
-
}) })
|
|
627
|
-
] }) }),
|
|
726
|
+
) }) : paginatedData.map((row, rowIdx) => {
|
|
727
|
+
const key = keyExtractor(row);
|
|
728
|
+
const isSelected = selectedKeys.includes(key);
|
|
729
|
+
return /* @__PURE__ */ jsxs(
|
|
730
|
+
TableRow,
|
|
731
|
+
{
|
|
732
|
+
"data-state": isSelected ? "selected" : void 0,
|
|
733
|
+
className: cn(isSelected && "bg-[var(--ui-primary)]/10"),
|
|
734
|
+
children: [
|
|
735
|
+
selectable && /* @__PURE__ */ jsx(TableCell, { className: "w-10 px-4", children: /* @__PURE__ */ jsx(
|
|
736
|
+
Checkbox,
|
|
737
|
+
{
|
|
738
|
+
checked: isSelected,
|
|
739
|
+
onCheckedChange: () => toggleSelectRow(key),
|
|
740
|
+
"aria-label": `Select row ${key}`
|
|
741
|
+
}
|
|
742
|
+
) }),
|
|
743
|
+
columns.map((col) => {
|
|
744
|
+
const val = col.accessor ? col.accessor(row) : row[col.key];
|
|
745
|
+
const cellContent = col.render ? col.render(row, rowIdx, val) : val;
|
|
746
|
+
return /* @__PURE__ */ jsx(TableCell, { children: cellContent }, col.key);
|
|
747
|
+
})
|
|
748
|
+
]
|
|
749
|
+
},
|
|
750
|
+
key
|
|
751
|
+
);
|
|
752
|
+
}) })
|
|
753
|
+
] })
|
|
754
|
+
] }),
|
|
628
755
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-3 px-1 text-xs text-[var(--ui-text-muted)] font-mono", children: [
|
|
629
756
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
630
757
|
/* @__PURE__ */ jsx("span", { children: "Rows per page:" }),
|
|
@@ -632,21 +759,18 @@ function DataTablePro({
|
|
|
632
759
|
"select",
|
|
633
760
|
{
|
|
634
761
|
value: pageSize,
|
|
635
|
-
onChange: (e) =>
|
|
636
|
-
setPageSize(Number(e.target.value));
|
|
637
|
-
setCurrentPage(1);
|
|
638
|
-
},
|
|
762
|
+
onChange: (e) => handlePageSizeChange(Number(e.target.value)),
|
|
639
763
|
className: "px-2 py-1 rounded-lg bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] text-[var(--ui-text-primary)] font-mono text-xs focus:outline-none",
|
|
640
764
|
children: pageSizeOptions.map((opt) => /* @__PURE__ */ jsx("option", { value: opt, children: opt }, opt))
|
|
641
765
|
}
|
|
642
766
|
),
|
|
643
767
|
/* @__PURE__ */ jsxs("span", { className: "text-[var(--ui-text-muted)]", children: [
|
|
644
768
|
"Showing ",
|
|
645
|
-
Math.min((currentPage - 1) * pageSize + 1,
|
|
769
|
+
totalItems === 0 ? 0 : Math.min((currentPage - 1) * pageSize + 1, totalItems),
|
|
646
770
|
"\u2013",
|
|
647
|
-
Math.min(currentPage * pageSize,
|
|
771
|
+
Math.min(currentPage * pageSize, totalItems),
|
|
648
772
|
" of ",
|
|
649
|
-
|
|
773
|
+
totalItems
|
|
650
774
|
] })
|
|
651
775
|
] }),
|
|
652
776
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -655,8 +779,9 @@ function DataTablePro({
|
|
|
655
779
|
{
|
|
656
780
|
size: "xs",
|
|
657
781
|
variant: "outline",
|
|
658
|
-
disabled: currentPage
|
|
659
|
-
onClick: () =>
|
|
782
|
+
disabled: currentPage <= 1 || loading,
|
|
783
|
+
onClick: () => handlePageChange(currentPage - 1),
|
|
784
|
+
"aria-label": "Previous page",
|
|
660
785
|
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "w-3.5 h-3.5" })
|
|
661
786
|
}
|
|
662
787
|
),
|
|
@@ -670,8 +795,9 @@ function DataTablePro({
|
|
|
670
795
|
{
|
|
671
796
|
size: "xs",
|
|
672
797
|
variant: "outline",
|
|
673
|
-
disabled: currentPage
|
|
674
|
-
onClick: () =>
|
|
798
|
+
disabled: currentPage >= totalPages || loading,
|
|
799
|
+
onClick: () => handlePageChange(currentPage + 1),
|
|
800
|
+
"aria-label": "Next page",
|
|
675
801
|
children: /* @__PURE__ */ jsx(ChevronRight, { className: "w-3.5 h-3.5" })
|
|
676
802
|
}
|
|
677
803
|
)
|
|
@@ -679,100 +805,218 @@ function DataTablePro({
|
|
|
679
805
|
] })
|
|
680
806
|
] });
|
|
681
807
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
return
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
808
|
+
var TreeView = forwardRef(
|
|
809
|
+
({
|
|
810
|
+
data,
|
|
811
|
+
selectedId,
|
|
812
|
+
defaultExpandedIds,
|
|
813
|
+
onSelect,
|
|
814
|
+
onExpandedChange,
|
|
815
|
+
className,
|
|
816
|
+
"aria-label": ariaLabel = "Tree View"
|
|
817
|
+
}, ref) => {
|
|
818
|
+
const initialExpanded = useMemo(() => {
|
|
819
|
+
if (defaultExpandedIds) return new Set(defaultExpandedIds);
|
|
820
|
+
const set = /* @__PURE__ */ new Set();
|
|
821
|
+
const collect = (items) => {
|
|
822
|
+
for (const it of items) {
|
|
823
|
+
if (it.defaultExpanded) set.add(it.id);
|
|
824
|
+
if (it.children) collect(it.children);
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
collect(data);
|
|
828
|
+
return set;
|
|
829
|
+
}, [data, defaultExpandedIds]);
|
|
830
|
+
const [expandedSet, setExpandedSet] = useState(initialExpanded);
|
|
831
|
+
const [focusedId, setFocusedId] = useState(null);
|
|
832
|
+
const itemRefs = useRef(/* @__PURE__ */ new Map());
|
|
833
|
+
const focusNode = (id) => {
|
|
834
|
+
setFocusedId(id);
|
|
835
|
+
const el = itemRefs.current.get(id);
|
|
836
|
+
if (el) {
|
|
837
|
+
el.focus();
|
|
838
|
+
}
|
|
839
|
+
};
|
|
840
|
+
const toggleExpand = (id) => {
|
|
841
|
+
setExpandedSet((prev) => {
|
|
842
|
+
const next = new Set(prev);
|
|
843
|
+
if (next.has(id)) next.delete(id);
|
|
844
|
+
else next.add(id);
|
|
845
|
+
onExpandedChange?.(Array.from(next));
|
|
846
|
+
return next;
|
|
847
|
+
});
|
|
848
|
+
};
|
|
849
|
+
const expandNode = (id) => {
|
|
850
|
+
if (!expandedSet.has(id)) {
|
|
851
|
+
setExpandedSet((prev) => {
|
|
852
|
+
const next = new Set(prev).add(id);
|
|
853
|
+
onExpandedChange?.(Array.from(next));
|
|
854
|
+
return next;
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
const collapseNode = (id) => {
|
|
859
|
+
if (expandedSet.has(id)) {
|
|
860
|
+
setExpandedSet((prev) => {
|
|
861
|
+
const next = new Set(prev);
|
|
862
|
+
next.delete(id);
|
|
863
|
+
onExpandedChange?.(Array.from(next));
|
|
864
|
+
return next;
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
const visibleList = useMemo(() => {
|
|
869
|
+
const list = [];
|
|
870
|
+
const traverse = (items, level, parentId) => {
|
|
871
|
+
for (const item of items) {
|
|
872
|
+
const hasChildren = Boolean(item.children && item.children.length > 0);
|
|
873
|
+
list.push({ item, level, parentId, hasChildren });
|
|
874
|
+
if (hasChildren && expandedSet.has(item.id)) {
|
|
875
|
+
traverse(item.children, level + 1, item.id);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
traverse(data, 0, null);
|
|
880
|
+
return list;
|
|
881
|
+
}, [data, expandedSet]);
|
|
882
|
+
const handleKeyDown = (e) => {
|
|
883
|
+
if (visibleList.length === 0) return;
|
|
884
|
+
const currentIdx = focusedId ? visibleList.findIndex((f) => f.item.id === focusedId) : 0;
|
|
885
|
+
const currentFlat = visibleList[currentIdx] || visibleList[0];
|
|
886
|
+
if (e.key === "ArrowDown") {
|
|
887
|
+
e.preventDefault();
|
|
888
|
+
const nextIdx = Math.min(visibleList.length - 1, currentIdx + 1);
|
|
889
|
+
focusNode(visibleList[nextIdx].item.id);
|
|
890
|
+
} else if (e.key === "ArrowUp") {
|
|
891
|
+
e.preventDefault();
|
|
892
|
+
const prevIdx = Math.max(0, currentIdx - 1);
|
|
893
|
+
focusNode(visibleList[prevIdx].item.id);
|
|
894
|
+
} else if (e.key === "ArrowRight") {
|
|
895
|
+
e.preventDefault();
|
|
896
|
+
if (currentFlat.hasChildren) {
|
|
897
|
+
if (!expandedSet.has(currentFlat.item.id)) {
|
|
898
|
+
expandNode(currentFlat.item.id);
|
|
899
|
+
} else {
|
|
900
|
+
const nextIdx = currentIdx + 1;
|
|
901
|
+
if (nextIdx < visibleList.length) {
|
|
902
|
+
focusNode(visibleList[nextIdx].item.id);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
} else if (e.key === "ArrowLeft") {
|
|
907
|
+
e.preventDefault();
|
|
908
|
+
if (currentFlat.hasChildren && expandedSet.has(currentFlat.item.id)) {
|
|
909
|
+
collapseNode(currentFlat.item.id);
|
|
910
|
+
} else if (currentFlat.parentId) {
|
|
911
|
+
focusNode(currentFlat.parentId);
|
|
912
|
+
}
|
|
913
|
+
} else if (e.key === "Home") {
|
|
914
|
+
e.preventDefault();
|
|
915
|
+
focusNode(visibleList[0].item.id);
|
|
916
|
+
} else if (e.key === "End") {
|
|
917
|
+
e.preventDefault();
|
|
918
|
+
focusNode(visibleList[visibleList.length - 1].item.id);
|
|
919
|
+
} else if (e.key === "Enter" || e.key === " ") {
|
|
920
|
+
e.preventDefault();
|
|
921
|
+
if (currentFlat) {
|
|
922
|
+
if (currentFlat.hasChildren) {
|
|
923
|
+
toggleExpand(currentFlat.item.id);
|
|
924
|
+
}
|
|
925
|
+
onSelect?.(currentFlat.item);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
const getIcon = (item, hasChildren, isExpanded) => {
|
|
930
|
+
if (item.icon) return item.icon;
|
|
931
|
+
if (hasChildren) {
|
|
932
|
+
return isExpanded ? /* @__PURE__ */ jsx(FolderOpen, { className: "w-4 h-4 text-amber-500 shrink-0" }) : /* @__PURE__ */ jsx(Folder, { className: "w-4 h-4 text-amber-500 shrink-0" });
|
|
933
|
+
}
|
|
934
|
+
if (item.label.endsWith(".tsx") || item.label.endsWith(".ts") || item.label.endsWith(".js")) {
|
|
935
|
+
return /* @__PURE__ */ jsx(FileCode, { className: "w-4 h-4 text-blue-500 shrink-0" });
|
|
936
|
+
}
|
|
937
|
+
if (item.label.endsWith(".png") || item.label.endsWith(".jpg") || item.label.endsWith(".svg")) {
|
|
938
|
+
return /* @__PURE__ */ jsx(Image, { className: "w-4 h-4 text-purple-500 shrink-0" });
|
|
939
|
+
}
|
|
940
|
+
return /* @__PURE__ */ jsx(FileText, { className: "w-4 h-4 text-[var(--ui-text-muted)] shrink-0" });
|
|
941
|
+
};
|
|
942
|
+
const renderNodes = (items, level) => {
|
|
943
|
+
return items.map((item, index) => {
|
|
944
|
+
const hasChildren = Boolean(item.children && item.children.length > 0);
|
|
945
|
+
const isExpanded = expandedSet.has(item.id);
|
|
946
|
+
const isSelected = selectedId === item.id;
|
|
947
|
+
const isFocused = focusedId === item.id || !focusedId && level === 0 && index === 0;
|
|
948
|
+
return /* @__PURE__ */ jsxs("div", { role: "none", className: "select-none text-xs", children: [
|
|
949
|
+
/* @__PURE__ */ jsxs(
|
|
950
|
+
"div",
|
|
724
951
|
{
|
|
952
|
+
ref: (el) => {
|
|
953
|
+
if (el) itemRefs.current.set(item.id, el);
|
|
954
|
+
else itemRefs.current.delete(item.id);
|
|
955
|
+
},
|
|
956
|
+
role: "treeitem",
|
|
957
|
+
tabIndex: isFocused ? 0 : -1,
|
|
958
|
+
"aria-expanded": hasChildren ? isExpanded : void 0,
|
|
959
|
+
"aria-selected": isSelected,
|
|
960
|
+
"aria-level": level + 1,
|
|
961
|
+
"aria-posinset": index + 1,
|
|
962
|
+
"aria-setsize": items.length,
|
|
963
|
+
onClick: (e) => {
|
|
964
|
+
e.stopPropagation();
|
|
965
|
+
focusNode(item.id);
|
|
966
|
+
if (hasChildren) {
|
|
967
|
+
toggleExpand(item.id);
|
|
968
|
+
}
|
|
969
|
+
onSelect?.(item);
|
|
970
|
+
},
|
|
971
|
+
style: { paddingLeft: `${level * 16 + 8}px` },
|
|
725
972
|
className: cn(
|
|
726
|
-
"
|
|
727
|
-
isSelected ? "bg-
|
|
973
|
+
"flex items-center justify-between py-1.5 pr-2.5 rounded-xl cursor-pointer transition-colors group outline-none focus-visible:ring-2 focus-visible:ring-[var(--ui-primary)]",
|
|
974
|
+
isSelected ? "bg-[var(--ui-primary)] text-white font-semibold shadow-xs" : "text-[var(--ui-text-primary)] hover:bg-[var(--ui-bg-tertiary)]"
|
|
728
975
|
),
|
|
729
|
-
children:
|
|
976
|
+
children: [
|
|
977
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 truncate", children: [
|
|
978
|
+
hasChildren ? /* @__PURE__ */ jsx("span", { className: cn("p-0.5 rounded transition-transform duration-200", isExpanded && "rotate-90"), children: /* @__PURE__ */ jsx(ChevronRight, { className: cn("w-3 h-3", isSelected ? "text-white" : "text-[var(--ui-text-muted)]") }) }) : /* @__PURE__ */ jsx("span", { className: "w-4" }),
|
|
979
|
+
getIcon(item, hasChildren, isExpanded),
|
|
980
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: item.label })
|
|
981
|
+
] }),
|
|
982
|
+
item.badge !== void 0 && /* @__PURE__ */ jsx(
|
|
983
|
+
"span",
|
|
984
|
+
{
|
|
985
|
+
className: cn(
|
|
986
|
+
"px-1.5 py-0.5 rounded-md text-[10px] font-mono",
|
|
987
|
+
isSelected ? "bg-white/20 text-white" : "bg-[var(--ui-bg-secondary)] text-[var(--ui-text-muted)]"
|
|
988
|
+
),
|
|
989
|
+
children: item.badge
|
|
990
|
+
}
|
|
991
|
+
)
|
|
992
|
+
]
|
|
730
993
|
}
|
|
731
|
-
)
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
{
|
|
746
|
-
item: child,
|
|
747
|
-
level: level + 1,
|
|
748
|
-
selectedId,
|
|
749
|
-
onSelect
|
|
750
|
-
},
|
|
751
|
-
child.id
|
|
752
|
-
))
|
|
753
|
-
] })
|
|
754
|
-
] });
|
|
755
|
-
}
|
|
756
|
-
var TreeView = forwardRef(
|
|
757
|
-
({ data, selectedId, onSelect, className }, ref) => {
|
|
994
|
+
),
|
|
995
|
+
hasChildren && isExpanded && /* @__PURE__ */ jsxs("div", { role: "group", className: "relative space-y-0.5 animate-in fade-in duration-150", children: [
|
|
996
|
+
/* @__PURE__ */ jsx(
|
|
997
|
+
"div",
|
|
998
|
+
{
|
|
999
|
+
className: "absolute left-[15px] top-0 bottom-0 w-[1px] bg-[var(--ui-border-subtle)]",
|
|
1000
|
+
style: { left: `${level * 16 + 15}px` }
|
|
1001
|
+
}
|
|
1002
|
+
),
|
|
1003
|
+
renderNodes(item.children, level + 1)
|
|
1004
|
+
] })
|
|
1005
|
+
] }, item.id);
|
|
1006
|
+
});
|
|
1007
|
+
};
|
|
758
1008
|
return /* @__PURE__ */ jsx(
|
|
759
1009
|
"div",
|
|
760
1010
|
{
|
|
761
1011
|
ref,
|
|
1012
|
+
role: "tree",
|
|
1013
|
+
"aria-label": ariaLabel,
|
|
1014
|
+
onKeyDown: handleKeyDown,
|
|
762
1015
|
className: cn(
|
|
763
|
-
"w-full p-2 rounded-2xl bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] space-y-0.5 shadow-sm overflow-hidden",
|
|
1016
|
+
"w-full p-2 rounded-2xl bg-[var(--ui-bg-surface)] border border-[var(--ui-border-default)] space-y-0.5 shadow-sm overflow-hidden outline-none",
|
|
764
1017
|
className
|
|
765
1018
|
),
|
|
766
|
-
children: data
|
|
767
|
-
TreeNode,
|
|
768
|
-
{
|
|
769
|
-
item,
|
|
770
|
-
level: 0,
|
|
771
|
-
selectedId,
|
|
772
|
-
onSelect
|
|
773
|
-
},
|
|
774
|
-
item.id
|
|
775
|
-
))
|
|
1019
|
+
children: renderNodes(data, 0)
|
|
776
1020
|
}
|
|
777
1021
|
);
|
|
778
1022
|
}
|
|
@@ -878,5 +1122,5 @@ var Carousel = forwardRef(
|
|
|
878
1122
|
Carousel.displayName = "Carousel";
|
|
879
1123
|
|
|
880
1124
|
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Avatar, AvatarGroup, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, DataTablePro, StatCard, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Timeline, TreeView, avatarVariants, cardVariants, data_display_exports, statusVariants, useAccordion };
|
|
881
|
-
//# sourceMappingURL=chunk-
|
|
882
|
-
//# sourceMappingURL=chunk-
|
|
1125
|
+
//# sourceMappingURL=chunk-W5WNWTQC.js.map
|
|
1126
|
+
//# sourceMappingURL=chunk-W5WNWTQC.js.map
|