@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.
Files changed (69) hide show
  1. package/dist/components/ButtonGroup/ButtonGroup.meta.d.ts.map +1 -1
  2. package/dist/components/CheckboxGroup/CheckboxGroup.d.ts.map +1 -1
  3. package/dist/components/CheckboxGroup/CheckboxGroup.meta.d.ts.map +1 -1
  4. package/dist/components/Combobox/Combobox.d.ts +44 -0
  5. package/dist/components/Combobox/Combobox.d.ts.map +1 -0
  6. package/dist/components/Combobox/Combobox.meta.d.ts +3 -0
  7. package/dist/components/Combobox/Combobox.meta.d.ts.map +1 -0
  8. package/dist/components/Combobox/Combobox.stories.d.ts +9 -0
  9. package/dist/components/Combobox/Combobox.stories.d.ts.map +1 -0
  10. package/dist/components/Combobox/ComboboxContext.d.ts +19 -0
  11. package/dist/components/Combobox/ComboboxContext.d.ts.map +1 -0
  12. package/dist/components/Combobox/styles.css.d.ts +112 -0
  13. package/dist/components/Combobox/styles.css.d.ts.map +1 -0
  14. package/dist/components/Combobox/useComboboxRoot.d.ts +15 -0
  15. package/dist/components/Combobox/useComboboxRoot.d.ts.map +1 -0
  16. package/dist/components/Field/Field.d.ts +4 -0
  17. package/dist/components/Field/Field.d.ts.map +1 -1
  18. package/dist/components/Field/Field.stories.d.ts +3 -0
  19. package/dist/components/Field/Field.stories.d.ts.map +1 -1
  20. package/dist/components/Field/FieldContext.d.ts +5 -0
  21. package/dist/components/Field/FieldContext.d.ts.map +1 -1
  22. package/dist/components/Field/styles.css.d.ts +26 -0
  23. package/dist/components/Field/styles.css.d.ts.map +1 -1
  24. package/dist/components/Form/Form.d.ts +7 -2
  25. package/dist/components/Form/Form.d.ts.map +1 -1
  26. package/dist/components/Form/Form.stories.d.ts +6 -0
  27. package/dist/components/Form/Form.stories.d.ts.map +1 -1
  28. package/dist/components/Form/FormContext.d.ts +9 -2
  29. package/dist/components/Form/FormContext.d.ts.map +1 -1
  30. package/dist/components/Input/Input.d.ts.map +1 -1
  31. package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
  32. package/dist/components/RadioGroup/RadioGroup.meta.d.ts.map +1 -1
  33. package/dist/components/Table/SortIndicator.d.ts.map +1 -1
  34. package/dist/components/Table/Table.d.ts.map +1 -1
  35. package/dist/components/Table/Table.stories.d.ts.map +1 -1
  36. package/dist/components/Table/useDataTable.d.ts.map +1 -1
  37. package/dist/components/Textarea/Textarea.d.ts.map +1 -1
  38. package/dist/index.css +1 -1
  39. package/dist/index.d.ts +2 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2964 -2381
  42. package/dist/index.js.map +1 -1
  43. package/package.json +2 -2
  44. package/src/components/ButtonGroup/ButtonGroup.meta.ts +10 -2
  45. package/src/components/CheckboxGroup/CheckboxGroup.meta.ts +4 -1
  46. package/src/components/CheckboxGroup/CheckboxGroup.tsx +2 -9
  47. package/src/components/Combobox/Combobox.meta.ts +35 -0
  48. package/src/components/Combobox/Combobox.stories.tsx +119 -0
  49. package/src/components/Combobox/Combobox.tsx +247 -0
  50. package/src/components/Combobox/ComboboxContext.ts +26 -0
  51. package/src/components/Combobox/styles.css.ts +119 -0
  52. package/src/components/Combobox/useComboboxRoot.ts +235 -0
  53. package/src/components/Field/Field.stories.tsx +60 -0
  54. package/src/components/Field/Field.tsx +97 -9
  55. package/src/components/Field/FieldContext.ts +5 -0
  56. package/src/components/Field/styles.css.ts +26 -0
  57. package/src/components/Form/Form.stories.tsx +275 -0
  58. package/src/components/Form/Form.tsx +73 -7
  59. package/src/components/Form/FormContext.ts +10 -1
  60. package/src/components/Input/Input.tsx +2 -1
  61. package/src/components/RadioGroup/RadioGroup.meta.ts +4 -1
  62. package/src/components/RadioGroup/RadioGroup.tsx +1 -4
  63. package/src/components/Table/SortIndicator.tsx +1 -4
  64. package/src/components/Table/Table.stories.tsx +135 -84
  65. package/src/components/Table/Table.tsx +10 -5
  66. package/src/components/Table/useDataTable.ts +34 -48
  67. package/src/components/Textarea/Textarea.tsx +2 -1
  68. package/src/index.ts +2 -0
  69. 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
- function SortingDemo() {
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
- const cols = [
445
- createColumnHelper<typeof data[0]>().accessor('name', {header: 'Name', enableSorting: true}),
446
- createColumnHelper<typeof data[0]>().accessor('role', {header: 'Role', enableSorting: true}),
447
- createColumnHelper<typeof data[0]>().accessor('port', {header: 'Port', enableSorting: true}),
448
- createColumnHelper<typeof data[0]>().accessor('uptime', {header: 'Uptime', enableSorting: true}),
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: cols,
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
- function PaginationDemo() {
507
- const data = generateUsers(35)
547
+ const paginationData = generateUsers(35)
508
548
 
509
- const cols = [
510
- createColumnHelper<User>().accessor('name', {header: 'Name'}),
511
- createColumnHelper<User>().accessor('role', {header: 'Role'}),
512
- createColumnHelper<User>().accessor('email', {header: 'Email'}),
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: cols,
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
- function FilteringDemo() {
568
- const data = generateUsers(20)
608
+ const filteringData = generateUsers(20)
569
609
 
570
- const cols = [
571
- createColumnHelper<User>().accessor('name', {header: 'Name', enableColumnFilter: true}),
572
- createColumnHelper<User>().accessor('role', {header: 'Role', enableColumnFilter: false}),
573
- createColumnHelper<User>().accessor('status', {header: 'Status', enableColumnFilter: false}),
574
- createColumnHelper<User>().accessor('email', {header: 'Email', enableColumnFilter: true}),
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: cols,
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: true,
682
+ enableColumnFilter: false,
678
683
  }),
679
684
  columnHelper.accessor('role', {
680
685
  header: 'Role',
681
686
  enableSorting: true,
682
- enableColumnFilter: false,
687
+ enableColumnFilter: true,
683
688
  }),
684
689
  columnHelper.accessor('status', {
685
690
  header: 'Status',
686
691
  enableSorting: true,
687
- enableColumnFilter: false,
692
+ enableColumnFilter: true,
688
693
  }),
689
694
  columnHelper.accessor('email', {
690
695
  header: 'Email',
691
696
  enableSorting: true,
692
- enableColumnFilter: true,
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: 'column',
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 {type ReactNode, type MutableRefObject, createContext, useContext, useRef, Children, isValidElement} from 'react'
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: paginationInit?.pageIndex ?? 0,
61
- pageSize: paginationInit?.pageSize ?? 10,
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 = (updater: any) => {
66
- setRowSelection(updater)
67
- if (onSelectionChangeProp) {
68
- const next = typeof updater === 'function' ? updater(rowSelection) : updater
69
- onSelectionChangeProp(next)
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
- const tableOptions: TableOptions<TData> = {
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
- // Sorting
79
- ...(enableSorting && {
80
- getSortedRowModel: getSortedRowModel(),
81
- onSortingChange: setSorting,
82
- state: {sorting},
83
- }),
84
-
85
- // Filtering
86
- ...(enableFiltering && {
87
- getFilteredRowModel: getFilteredRowModel(),
88
- onColumnFiltersChange: setColumnFilters,
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={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'
package/src/strict.css CHANGED
@@ -2,6 +2,6 @@
2
2
  @react-strict-dom;
3
3
 
4
4
  /* Table: reveal sort indicator on header cell hover */
5
- [role="columnheader"]:hover [data-sort-indicator] {
5
+ [role='columnheader']:hover [data-sort-indicator] {
6
6
  opacity: 1 !important;
7
7
  }