@duro-app/ui 0.24.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ButtonGroup/ButtonGroup.meta.d.ts.map +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.d.ts.map +1 -1
- package/dist/components/CheckboxGroup/CheckboxGroup.meta.d.ts.map +1 -1
- package/dist/components/Combobox/Combobox.d.ts +44 -0
- package/dist/components/Combobox/Combobox.d.ts.map +1 -0
- package/dist/components/Combobox/Combobox.meta.d.ts +3 -0
- package/dist/components/Combobox/Combobox.meta.d.ts.map +1 -0
- package/dist/components/Combobox/Combobox.stories.d.ts +9 -0
- package/dist/components/Combobox/Combobox.stories.d.ts.map +1 -0
- package/dist/components/Combobox/ComboboxContext.d.ts +19 -0
- package/dist/components/Combobox/ComboboxContext.d.ts.map +1 -0
- package/dist/components/Combobox/styles.css.d.ts +112 -0
- package/dist/components/Combobox/styles.css.d.ts.map +1 -0
- package/dist/components/Combobox/useComboboxRoot.d.ts +15 -0
- package/dist/components/Combobox/useComboboxRoot.d.ts.map +1 -0
- package/dist/components/Field/Field.d.ts +4 -0
- package/dist/components/Field/Field.d.ts.map +1 -1
- package/dist/components/Field/Field.stories.d.ts +3 -0
- package/dist/components/Field/Field.stories.d.ts.map +1 -1
- package/dist/components/Field/FieldContext.d.ts +5 -0
- package/dist/components/Field/FieldContext.d.ts.map +1 -1
- package/dist/components/Field/styles.css.d.ts +26 -0
- package/dist/components/Field/styles.css.d.ts.map +1 -1
- package/dist/components/Form/Form.d.ts +7 -2
- package/dist/components/Form/Form.d.ts.map +1 -1
- package/dist/components/Form/Form.stories.d.ts +6 -0
- package/dist/components/Form/Form.stories.d.ts.map +1 -1
- package/dist/components/Form/FormContext.d.ts +9 -2
- package/dist/components/Form/FormContext.d.ts.map +1 -1
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.meta.d.ts.map +1 -1
- package/dist/components/Table/SortIndicator.d.ts.map +1 -1
- package/dist/components/Table/Table.d.ts.map +1 -1
- package/dist/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/components/Table/useDataTable.d.ts.map +1 -1
- package/dist/components/Textarea/Textarea.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2964 -2381
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ButtonGroup/ButtonGroup.meta.ts +10 -2
- package/src/components/CheckboxGroup/CheckboxGroup.meta.ts +4 -1
- package/src/components/CheckboxGroup/CheckboxGroup.tsx +2 -9
- package/src/components/Combobox/Combobox.meta.ts +35 -0
- package/src/components/Combobox/Combobox.stories.tsx +119 -0
- package/src/components/Combobox/Combobox.tsx +247 -0
- package/src/components/Combobox/ComboboxContext.ts +26 -0
- package/src/components/Combobox/styles.css.ts +119 -0
- package/src/components/Combobox/useComboboxRoot.ts +235 -0
- package/src/components/Field/Field.stories.tsx +60 -0
- package/src/components/Field/Field.tsx +97 -9
- package/src/components/Field/FieldContext.ts +5 -0
- package/src/components/Field/styles.css.ts +26 -0
- package/src/components/Form/Form.stories.tsx +275 -0
- package/src/components/Form/Form.tsx +73 -7
- package/src/components/Form/FormContext.ts +10 -1
- package/src/components/Input/Input.tsx +2 -1
- package/src/components/RadioGroup/RadioGroup.meta.ts +4 -1
- package/src/components/RadioGroup/RadioGroup.tsx +1 -4
- package/src/components/Table/SortIndicator.tsx +1 -4
- package/src/components/Table/Table.stories.tsx +135 -84
- package/src/components/Table/Table.tsx +10 -5
- package/src/components/Table/useDataTable.ts +34 -48
- package/src/components/Textarea/Textarea.tsx +2 -1
- package/src/index.ts +2 -0
- package/src/strict.css +1 -1
|
@@ -9,7 +9,10 @@ import {Button} from '../Button/Button'
|
|
|
9
9
|
import {ActionBar} from '../ActionBar/ActionBar'
|
|
10
10
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
11
11
|
|
|
12
|
-
import {flexRender, createColumnHelper, useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, type SortingState, type ColumnFiltersState} from '@tanstack/react-table'
|
|
12
|
+
import {flexRender, createColumnHelper, useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel, getPaginationRowModel, type SortingState, type ColumnFiltersState, type PaginationState} from '@tanstack/react-table'
|
|
13
|
+
import {useDataTable} from './useDataTable'
|
|
14
|
+
import {Combobox} from '../Combobox/Combobox'
|
|
15
|
+
import {spacing} from '@duro-app/tokens/tokens/spacing.css'
|
|
13
16
|
|
|
14
17
|
const meta: Meta = {
|
|
15
18
|
title: 'Components/Table',
|
|
@@ -429,30 +432,31 @@ export const AllVariants: Story = {
|
|
|
429
432
|
},
|
|
430
433
|
}
|
|
431
434
|
|
|
432
|
-
|
|
433
435
|
// --- Sorting: demonstrates click-to-sort with hover indicators ---
|
|
434
436
|
|
|
435
|
-
|
|
436
|
-
const data = [
|
|
437
|
-
{name: 'Traefik', role: 'Reverse Proxy', port: 443, uptime: '14d 3h'},
|
|
438
|
-
{name: 'Pi-hole', role: 'DNS Filter', port: 80, uptime: '14d 3h'},
|
|
439
|
-
{name: 'Grafana', role: 'Monitoring', port: 3000, uptime: '7d 12h'},
|
|
440
|
-
{name: 'Portainer', role: 'Container Mgmt', port: 9000, uptime: '2d 5h'},
|
|
441
|
-
{name: 'Nginx', role: 'Web Server', port: 8080, uptime: '30d 1h'},
|
|
442
|
-
]
|
|
437
|
+
type Service = {name: string; role: string; port: number; uptime: string}
|
|
443
438
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
439
|
+
const sortingData: Service[] = [
|
|
440
|
+
{name: 'Traefik', role: 'Reverse Proxy', port: 443, uptime: '14d 3h'},
|
|
441
|
+
{name: 'Pi-hole', role: 'DNS Filter', port: 80, uptime: '14d 3h'},
|
|
442
|
+
{name: 'Grafana', role: 'Monitoring', port: 3000, uptime: '7d 12h'},
|
|
443
|
+
{name: 'Portainer', role: 'Container Mgmt', port: 9000, uptime: '2d 5h'},
|
|
444
|
+
{name: 'Nginx', role: 'Web Server', port: 8080, uptime: '30d 1h'},
|
|
445
|
+
]
|
|
446
|
+
|
|
447
|
+
const sortingCols = [
|
|
448
|
+
createColumnHelper<Service>().accessor('name', {header: 'Name', enableSorting: true}),
|
|
449
|
+
createColumnHelper<Service>().accessor('role', {header: 'Role', enableSorting: true}),
|
|
450
|
+
createColumnHelper<Service>().accessor('port', {header: 'Port', enableSorting: true}),
|
|
451
|
+
createColumnHelper<Service>().accessor('uptime', {header: 'Uptime', enableSorting: true}),
|
|
452
|
+
]
|
|
450
453
|
|
|
454
|
+
function SortingDemo() {
|
|
451
455
|
const [sorting, setSorting] = useState<SortingState>([])
|
|
452
456
|
|
|
453
457
|
const table = useReactTable({
|
|
454
|
-
data,
|
|
455
|
-
columns:
|
|
458
|
+
data: sortingData,
|
|
459
|
+
columns: sortingCols,
|
|
456
460
|
state: {sorting},
|
|
457
461
|
onSortingChange: setSorting,
|
|
458
462
|
getCoreRowModel: getCoreRowModel(),
|
|
@@ -501,22 +505,59 @@ export const Sorting: Story = {
|
|
|
501
505
|
},
|
|
502
506
|
}
|
|
503
507
|
|
|
508
|
+
// --- Shared data helpers for interactive demos ---
|
|
509
|
+
|
|
510
|
+
interface User {
|
|
511
|
+
name: string
|
|
512
|
+
role: string
|
|
513
|
+
status: string
|
|
514
|
+
email: string
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const firstNames = [
|
|
518
|
+
'Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank', 'Grace', 'Hank',
|
|
519
|
+
'Iris', 'Jack', 'Karen', 'Leo', 'Mona', 'Nick', 'Olivia', 'Paul',
|
|
520
|
+
'Quinn', 'Rita', 'Sam', 'Tina', 'Uma', 'Vince', 'Wendy', 'Xander',
|
|
521
|
+
'Yara', 'Zach',
|
|
522
|
+
]
|
|
523
|
+
const lastNames = [
|
|
524
|
+
'Adams', 'Brown', 'Clark', 'Davis', 'Evans', 'Foster', 'Garcia',
|
|
525
|
+
'Hill', 'Ito', 'Jones', 'Kim', 'Lee', 'Moore', 'Nash', 'Owen',
|
|
526
|
+
'Patel', 'Quinn', 'Reed', 'Smith', 'Tran', 'Ueda', 'Voss', 'Wang',
|
|
527
|
+
'Xu', 'Yang', 'Zhang',
|
|
528
|
+
]
|
|
529
|
+
const roles = ['Admin', 'Editor', 'Viewer', 'Moderator', 'Analyst']
|
|
530
|
+
const statuses = ['Active', 'Inactive', 'Pending', 'Suspended']
|
|
531
|
+
|
|
532
|
+
function generateUsers(count: number): User[] {
|
|
533
|
+
return Array.from({length: count}, (_, i) => {
|
|
534
|
+
const first = firstNames[i % firstNames.length]
|
|
535
|
+
const last = lastNames[(i * 7) % lastNames.length]
|
|
536
|
+
return {
|
|
537
|
+
name: `${first} ${last}`,
|
|
538
|
+
role: roles[i % roles.length],
|
|
539
|
+
status: statuses[i % statuses.length],
|
|
540
|
+
email: `${first.toLowerCase()}.${last.toLowerCase()}@example.com`,
|
|
541
|
+
}
|
|
542
|
+
})
|
|
543
|
+
}
|
|
544
|
+
|
|
504
545
|
// --- Pagination: demonstrates page navigation ---
|
|
505
546
|
|
|
506
|
-
|
|
507
|
-
const data = generateUsers(35)
|
|
547
|
+
const paginationData = generateUsers(35)
|
|
508
548
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
549
|
+
const paginationCols = [
|
|
550
|
+
createColumnHelper<User>().accessor('name', {header: 'Name'}),
|
|
551
|
+
createColumnHelper<User>().accessor('role', {header: 'Role'}),
|
|
552
|
+
createColumnHelper<User>().accessor('email', {header: 'Email'}),
|
|
553
|
+
]
|
|
514
554
|
|
|
555
|
+
function PaginationDemo() {
|
|
515
556
|
const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 10})
|
|
516
557
|
|
|
517
558
|
const table = useReactTable({
|
|
518
|
-
data,
|
|
519
|
-
columns:
|
|
559
|
+
data: paginationData,
|
|
560
|
+
columns: paginationCols,
|
|
520
561
|
state: {pagination},
|
|
521
562
|
onPaginationChange: setPagination,
|
|
522
563
|
getCoreRowModel: getCoreRowModel(),
|
|
@@ -564,21 +605,21 @@ export const WithPagination: Story = {
|
|
|
564
605
|
|
|
565
606
|
// --- Filtering: demonstrates column filter inputs ---
|
|
566
607
|
|
|
567
|
-
|
|
568
|
-
const data = generateUsers(20)
|
|
608
|
+
const filteringData = generateUsers(20)
|
|
569
609
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
610
|
+
const filteringCols = [
|
|
611
|
+
createColumnHelper<User>().accessor('name', {header: 'Name', enableColumnFilter: true}),
|
|
612
|
+
createColumnHelper<User>().accessor('role', {header: 'Role', enableColumnFilter: false}),
|
|
613
|
+
createColumnHelper<User>().accessor('status', {header: 'Status', enableColumnFilter: false}),
|
|
614
|
+
createColumnHelper<User>().accessor('email', {header: 'Email', enableColumnFilter: true}),
|
|
615
|
+
]
|
|
576
616
|
|
|
617
|
+
function FilteringDemo() {
|
|
577
618
|
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
|
578
619
|
|
|
579
620
|
const table = useReactTable({
|
|
580
|
-
data,
|
|
581
|
-
columns:
|
|
621
|
+
data: filteringData,
|
|
622
|
+
columns: filteringCols,
|
|
582
623
|
state: {columnFilters},
|
|
583
624
|
onColumnFiltersChange: setColumnFilters,
|
|
584
625
|
getCoreRowModel: getCoreRowModel(),
|
|
@@ -628,44 +669,8 @@ export const WithFiltering: Story = {
|
|
|
628
669
|
},
|
|
629
670
|
}
|
|
630
671
|
|
|
631
|
-
|
|
632
672
|
// --- FullFeatured: useDataTable with pagination, sorting, and filtering ---
|
|
633
673
|
|
|
634
|
-
interface User {
|
|
635
|
-
name: string
|
|
636
|
-
role: string
|
|
637
|
-
status: string
|
|
638
|
-
email: string
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
const firstNames = [
|
|
642
|
-
'Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank', 'Grace', 'Hank',
|
|
643
|
-
'Iris', 'Jack', 'Karen', 'Leo', 'Mona', 'Nick', 'Olivia', 'Paul',
|
|
644
|
-
'Quinn', 'Rita', 'Sam', 'Tina', 'Uma', 'Vince', 'Wendy', 'Xander',
|
|
645
|
-
'Yara', 'Zach',
|
|
646
|
-
]
|
|
647
|
-
const lastNames = [
|
|
648
|
-
'Adams', 'Brown', 'Clark', 'Davis', 'Evans', 'Foster', 'Garcia',
|
|
649
|
-
'Hill', 'Ito', 'Jones', 'Kim', 'Lee', 'Moore', 'Nash', 'Owen',
|
|
650
|
-
'Patel', 'Quinn', 'Reed', 'Smith', 'Tran', 'Ueda', 'Voss', 'Wang',
|
|
651
|
-
'Xu', 'Yang', 'Zhang',
|
|
652
|
-
]
|
|
653
|
-
const roles = ['Admin', 'Editor', 'Viewer', 'Moderator', 'Analyst']
|
|
654
|
-
const statuses = ['Active', 'Inactive', 'Pending', 'Suspended']
|
|
655
|
-
|
|
656
|
-
function generateUsers(count: number): User[] {
|
|
657
|
-
return Array.from({length: count}, (_, i) => {
|
|
658
|
-
const first = firstNames[i % firstNames.length]
|
|
659
|
-
const last = lastNames[(i * 7) % lastNames.length]
|
|
660
|
-
return {
|
|
661
|
-
name: `${first} ${last}`,
|
|
662
|
-
role: roles[i % roles.length],
|
|
663
|
-
status: statuses[i % statuses.length],
|
|
664
|
-
email: `${first.toLowerCase()}.${last.toLowerCase()}@example.com`,
|
|
665
|
-
}
|
|
666
|
-
})
|
|
667
|
-
}
|
|
668
|
-
|
|
669
674
|
const fakeUsers = generateUsers(50)
|
|
670
675
|
|
|
671
676
|
const columnHelper = createColumnHelper<User>()
|
|
@@ -674,35 +679,45 @@ const fullFeaturedColumns = [
|
|
|
674
679
|
columnHelper.accessor('name', {
|
|
675
680
|
header: 'Name',
|
|
676
681
|
enableSorting: true,
|
|
677
|
-
enableColumnFilter:
|
|
682
|
+
enableColumnFilter: false,
|
|
678
683
|
}),
|
|
679
684
|
columnHelper.accessor('role', {
|
|
680
685
|
header: 'Role',
|
|
681
686
|
enableSorting: true,
|
|
682
|
-
enableColumnFilter:
|
|
687
|
+
enableColumnFilter: true,
|
|
683
688
|
}),
|
|
684
689
|
columnHelper.accessor('status', {
|
|
685
690
|
header: 'Status',
|
|
686
691
|
enableSorting: true,
|
|
687
|
-
enableColumnFilter:
|
|
692
|
+
enableColumnFilter: true,
|
|
688
693
|
}),
|
|
689
694
|
columnHelper.accessor('email', {
|
|
690
695
|
header: 'Email',
|
|
691
696
|
enableSorting: true,
|
|
692
|
-
enableColumnFilter:
|
|
697
|
+
enableColumnFilter: false,
|
|
693
698
|
}),
|
|
694
699
|
]
|
|
695
700
|
|
|
696
701
|
const fullFeaturedStyles = css.create({
|
|
697
702
|
wrapper: {display: 'flex', flexDirection: 'column', gap: 0},
|
|
703
|
+
filterBar: {
|
|
704
|
+
display: 'flex',
|
|
705
|
+
gap: spacing.md,
|
|
706
|
+
paddingBottom: spacing.md,
|
|
707
|
+
},
|
|
698
708
|
headerContent: {
|
|
699
709
|
display: 'flex',
|
|
700
|
-
flexDirection: '
|
|
710
|
+
flexDirection: 'row',
|
|
711
|
+
alignItems: 'center',
|
|
712
|
+
justifyContent: 'space-between',
|
|
701
713
|
cursor: 'pointer',
|
|
702
714
|
userSelect: 'none',
|
|
703
715
|
},
|
|
704
716
|
})
|
|
705
717
|
|
|
718
|
+
const uniqueRoles = [...new Set(fakeUsers.map((u) => u.role))].sort()
|
|
719
|
+
const uniqueStatuses = [...new Set(fakeUsers.map((u) => u.status))].sort()
|
|
720
|
+
|
|
706
721
|
function FullFeaturedDemo() {
|
|
707
722
|
const table = useDataTable(fakeUsers, fullFeaturedColumns, {
|
|
708
723
|
pagination: {pageSize: 10},
|
|
@@ -712,6 +727,48 @@ function FullFeaturedDemo() {
|
|
|
712
727
|
|
|
713
728
|
return (
|
|
714
729
|
<html.div style={fullFeaturedStyles.wrapper}>
|
|
730
|
+
<html.div style={fullFeaturedStyles.filterBar}>
|
|
731
|
+
<Combobox.Root
|
|
732
|
+
value={table.getColumn('role')?.getFilterValue() as string ?? ''}
|
|
733
|
+
onValueChange={(v) => table.getColumn('role')?.setFilterValue(v || undefined)}
|
|
734
|
+
onInputChange={(v) => table.getColumn('role')?.setFilterValue(v || undefined)}
|
|
735
|
+
>
|
|
736
|
+
<Combobox.Input placeholder="Filter role...">
|
|
737
|
+
<Combobox.Trigger />
|
|
738
|
+
</Combobox.Input>
|
|
739
|
+
<Combobox.Popup>
|
|
740
|
+
<Combobox.Item value="">
|
|
741
|
+
<Combobox.ItemText>All Roles</Combobox.ItemText>
|
|
742
|
+
</Combobox.Item>
|
|
743
|
+
{uniqueRoles.map((role) => (
|
|
744
|
+
<Combobox.Item key={role} value={role}>
|
|
745
|
+
<Combobox.ItemText>{role}</Combobox.ItemText>
|
|
746
|
+
</Combobox.Item>
|
|
747
|
+
))}
|
|
748
|
+
<Combobox.Empty>No roles found</Combobox.Empty>
|
|
749
|
+
</Combobox.Popup>
|
|
750
|
+
</Combobox.Root>
|
|
751
|
+
<Combobox.Root
|
|
752
|
+
value={table.getColumn('status')?.getFilterValue() as string ?? ''}
|
|
753
|
+
onValueChange={(v) => table.getColumn('status')?.setFilterValue(v || undefined)}
|
|
754
|
+
onInputChange={(v) => table.getColumn('status')?.setFilterValue(v || undefined)}
|
|
755
|
+
>
|
|
756
|
+
<Combobox.Input placeholder="Filter status...">
|
|
757
|
+
<Combobox.Trigger />
|
|
758
|
+
</Combobox.Input>
|
|
759
|
+
<Combobox.Popup>
|
|
760
|
+
<Combobox.Item value="">
|
|
761
|
+
<Combobox.ItemText>All Statuses</Combobox.ItemText>
|
|
762
|
+
</Combobox.Item>
|
|
763
|
+
{uniqueStatuses.map((status) => (
|
|
764
|
+
<Combobox.Item key={status} value={status}>
|
|
765
|
+
<Combobox.ItemText>{status}</Combobox.ItemText>
|
|
766
|
+
</Combobox.Item>
|
|
767
|
+
))}
|
|
768
|
+
<Combobox.Empty>No statuses found</Combobox.Empty>
|
|
769
|
+
</Combobox.Popup>
|
|
770
|
+
</Combobox.Root>
|
|
771
|
+
</html.div>
|
|
715
772
|
<Table.Root>
|
|
716
773
|
<Table.Header>
|
|
717
774
|
{table.getHeaderGroups().map((headerGroup) => (
|
|
@@ -725,12 +782,6 @@ function FullFeaturedDemo() {
|
|
|
725
782
|
{flexRender(header.column.columnDef.header, header.getContext())}
|
|
726
783
|
<Table.SortIndicator column={header.column} />
|
|
727
784
|
</html.div>
|
|
728
|
-
{(header.column.id === 'name' || header.column.id === 'email') && (
|
|
729
|
-
<Table.ColumnFilter
|
|
730
|
-
column={header.column}
|
|
731
|
-
placeholder={`Filter ${header.column.id}...`}
|
|
732
|
-
/>
|
|
733
|
-
)}
|
|
734
785
|
</Table.HeaderCell>
|
|
735
786
|
))}
|
|
736
787
|
</Table.Row>
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
type ReactNode,
|
|
3
|
+
type MutableRefObject,
|
|
4
|
+
createContext,
|
|
5
|
+
useContext,
|
|
6
|
+
useRef,
|
|
7
|
+
Children,
|
|
8
|
+
isValidElement,
|
|
9
|
+
} from 'react'
|
|
2
10
|
import {html} from 'react-strict-dom'
|
|
3
11
|
import {styles} from './styles.css'
|
|
4
12
|
import {Pagination} from './Pagination'
|
|
@@ -81,10 +89,7 @@ function Root({children, variant = 'default', size = 'md'}: RootProps) {
|
|
|
81
89
|
<TableContext.Provider value={{variant, size, inferredTemplateRef}}>
|
|
82
90
|
<html.div
|
|
83
91
|
role="table"
|
|
84
|
-
style={[
|
|
85
|
-
styles.root,
|
|
86
|
-
template ? styles.gridColumns(template) : undefined,
|
|
87
|
-
]}
|
|
92
|
+
style={[styles.root, template ? styles.gridColumns(template) : undefined]}
|
|
88
93
|
>
|
|
89
94
|
{children}
|
|
90
95
|
</html.div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useState} from 'react'
|
|
1
|
+
import {useCallback, useState} from 'react'
|
|
2
2
|
import {
|
|
3
3
|
useReactTable,
|
|
4
4
|
getCoreRowModel,
|
|
@@ -10,7 +10,6 @@ import {
|
|
|
10
10
|
type ColumnFiltersState,
|
|
11
11
|
type PaginationState,
|
|
12
12
|
type RowSelectionState,
|
|
13
|
-
type TableOptions,
|
|
14
13
|
type Table,
|
|
15
14
|
} from '@tanstack/react-table'
|
|
16
15
|
|
|
@@ -47,67 +46,54 @@ export function useDataTable<TData>(
|
|
|
47
46
|
options: UseDataTableOptions<TData> = {},
|
|
48
47
|
): Table<TData> {
|
|
49
48
|
const {
|
|
50
|
-
pagination: paginationInit,
|
|
51
49
|
enableSorting = false,
|
|
52
50
|
enableFiltering = false,
|
|
53
51
|
enableRowSelection = false,
|
|
54
52
|
onRowSelectionChange: onSelectionChangeProp,
|
|
55
53
|
} = options
|
|
56
54
|
|
|
55
|
+
const enablePagination = options.pagination != null
|
|
56
|
+
|
|
57
57
|
const [sorting, setSorting] = useState<SortingState>([])
|
|
58
58
|
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
|
|
59
59
|
const [pagination, setPagination] = useState<PaginationState>({
|
|
60
|
-
pageIndex:
|
|
61
|
-
pageSize:
|
|
60
|
+
pageIndex: options.pagination?.pageIndex ?? 0,
|
|
61
|
+
pageSize: options.pagination?.pageSize ?? 10,
|
|
62
62
|
})
|
|
63
63
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
|
|
64
64
|
|
|
65
|
-
const handleRowSelectionChange = (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
const handleRowSelectionChange = useCallback(
|
|
66
|
+
(updater: any) => {
|
|
67
|
+
setRowSelection((prev: RowSelectionState) => {
|
|
68
|
+
const next = typeof updater === 'function' ? updater(prev) : updater
|
|
69
|
+
onSelectionChangeProp?.(next)
|
|
70
|
+
return next
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
[onSelectionChangeProp],
|
|
74
|
+
)
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
// Follow TanStack's recommended pattern: always pass all row models
|
|
77
|
+
// unconditionally and let the library handle unused ones. Conditional
|
|
78
|
+
// spreads create unstable option shapes that can trigger infinite loops.
|
|
79
|
+
return useReactTable({
|
|
74
80
|
data,
|
|
75
81
|
columns,
|
|
82
|
+
state: {sorting, columnFilters, pagination, rowSelection},
|
|
76
83
|
getCoreRowModel: getCoreRowModel(),
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Pagination
|
|
92
|
-
...(paginationInit && {
|
|
93
|
-
getPaginationRowModel: getPaginationRowModel(),
|
|
94
|
-
onPaginationChange: setPagination,
|
|
84
|
+
getSortedRowModel: getSortedRowModel(),
|
|
85
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
86
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
87
|
+
onSortingChange: setSorting,
|
|
88
|
+
onColumnFiltersChange: setColumnFilters,
|
|
89
|
+
onPaginationChange: setPagination,
|
|
90
|
+
enableSorting,
|
|
91
|
+
enableRowSelection:
|
|
92
|
+
typeof enableRowSelection === 'function' ? enableRowSelection : !!enableRowSelection,
|
|
93
|
+
onRowSelectionChange: handleRowSelectionChange,
|
|
94
|
+
// When pagination is disabled, set a very large page size to show all rows
|
|
95
|
+
...(!enablePagination && {
|
|
96
|
+
autoResetPageIndex: false,
|
|
95
97
|
}),
|
|
96
|
-
|
|
97
|
-
// Row selection
|
|
98
|
-
...(enableRowSelection && {
|
|
99
|
-
enableRowSelection: typeof enableRowSelection === 'function' ? enableRowSelection : true,
|
|
100
|
-
onRowSelectionChange: handleRowSelectionChange,
|
|
101
|
-
}),
|
|
102
|
-
|
|
103
|
-
// Merge all state
|
|
104
|
-
state: {
|
|
105
|
-
...(enableSorting && {sorting}),
|
|
106
|
-
...(enableFiltering && {columnFilters}),
|
|
107
|
-
...(paginationInit && {pagination}),
|
|
108
|
-
...(enableRowSelection && {rowSelection}),
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return useReactTable(tableOptions)
|
|
98
|
+
})
|
|
113
99
|
}
|
|
@@ -41,6 +41,7 @@ export function Textarea({
|
|
|
41
41
|
const effectiveOnChange = onChange ?? fieldCtx?.onChange
|
|
42
42
|
const effectiveOnBlur = onBlur ?? fieldCtx?.onBlur
|
|
43
43
|
const effectiveRef = ref ?? fieldCtx?.ref
|
|
44
|
+
const effectiveDisabled = disabled ?? ctx?.disabled
|
|
44
45
|
const effectiveVariant = ctx?.invalid ? 'error' : variant
|
|
45
46
|
|
|
46
47
|
return (
|
|
@@ -52,7 +53,7 @@ export function Textarea({
|
|
|
52
53
|
rows={rows}
|
|
53
54
|
value={effectiveValue}
|
|
54
55
|
defaultValue={defaultValue}
|
|
55
|
-
disabled={
|
|
56
|
+
disabled={effectiveDisabled}
|
|
56
57
|
aria-describedby={
|
|
57
58
|
ctx ? `${ctx.descriptionId} ${ctx.invalid ? ctx.errorId : ''}`.trim() : undefined
|
|
58
59
|
}
|
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ export {Heading, type HeadingVariant} from './components/Heading/Heading'
|
|
|
21
21
|
export {List, type ListSelectionMode} from './components/List/List'
|
|
22
22
|
export {Field} from './components/Field/Field'
|
|
23
23
|
export {Form, type FormProps} from './components/Form/Form'
|
|
24
|
+
export type {LabelPosition, NecessityIndicator} from './components/Form/FormContext'
|
|
24
25
|
export {Fieldset, type FieldsetGap} from './components/Fieldset/Fieldset'
|
|
25
26
|
export {Input, type InputVariant} from './components/Input/Input'
|
|
26
27
|
export {InputGroup} from './components/InputGroup/InputGroup'
|
|
@@ -33,6 +34,7 @@ export {Menu} from './components/Menu/Menu'
|
|
|
33
34
|
export {Panel} from './components/Panel/Panel'
|
|
34
35
|
export {RadioGroup} from './components/RadioGroup/RadioGroup'
|
|
35
36
|
export {ScrollArea} from './components/ScrollArea/ScrollArea'
|
|
37
|
+
export {Combobox} from './components/Combobox/Combobox'
|
|
36
38
|
export {Select} from './components/Select/Select'
|
|
37
39
|
export {SideNav} from './components/SideNav/SideNav'
|
|
38
40
|
export {Spinner, type SpinnerSize} from './components/Spinner/Spinner'
|