@human-kit/svelte-components 1.0.0-alpha.4 → 1.0.0-alpha.5

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 (82) hide show
  1. package/dist/checkbox/README.md +53 -0
  2. package/dist/checkbox/TODO.md +16 -0
  3. package/dist/checkbox/index.d.ts +6 -0
  4. package/dist/checkbox/index.js +6 -0
  5. package/dist/checkbox/index.parts.d.ts +2 -0
  6. package/dist/checkbox/index.parts.js +2 -0
  7. package/dist/checkbox/indicator/README.md +23 -0
  8. package/dist/checkbox/indicator/checkbox-indicator.svelte +43 -0
  9. package/dist/checkbox/indicator/checkbox-indicator.svelte.d.ts +10 -0
  10. package/dist/checkbox/root/README.md +47 -0
  11. package/dist/checkbox/root/checkbox-label-test.svelte +10 -0
  12. package/dist/checkbox/root/checkbox-label-test.svelte.d.ts +18 -0
  13. package/dist/checkbox/root/checkbox-root.svelte +361 -0
  14. package/dist/checkbox/root/checkbox-root.svelte.d.ts +23 -0
  15. package/dist/checkbox/root/checkbox-test.svelte +59 -0
  16. package/dist/checkbox/root/checkbox-test.svelte.d.ts +18 -0
  17. package/dist/checkbox/root/context.d.ts +21 -0
  18. package/dist/checkbox/root/context.js +15 -0
  19. package/dist/combobox/list/combobox-listbox.svelte.d.ts +1 -1
  20. package/dist/index.d.ts +4 -0
  21. package/dist/index.js +4 -0
  22. package/dist/table/IMPLEMENTATION_NOTES.md +8 -0
  23. package/dist/table/PLAN-HIDDEN-COLUMNS.md +152 -0
  24. package/dist/table/PLAN.md +924 -0
  25. package/dist/table/README.md +116 -0
  26. package/dist/table/SELECTION_CHECKBOX_PLAN.md +234 -0
  27. package/dist/table/TODO.md +100 -0
  28. package/dist/table/body/README.md +24 -0
  29. package/dist/table/body/table-body.svelte +25 -0
  30. package/dist/table/body/table-body.svelte.d.ts +9 -0
  31. package/dist/table/cell/README.md +25 -0
  32. package/dist/table/cell/table-cell.svelte +247 -0
  33. package/dist/table/cell/table-cell.svelte.d.ts +9 -0
  34. package/dist/table/checkbox/README.md +38 -0
  35. package/dist/table/checkbox/table-checkbox-test.svelte +121 -0
  36. package/dist/table/checkbox/table-checkbox-test.svelte.d.ts +16 -0
  37. package/dist/table/checkbox/table-checkbox.svelte +274 -0
  38. package/dist/table/checkbox/table-checkbox.svelte.d.ts +13 -0
  39. package/dist/table/checkbox-indicator/README.md +29 -0
  40. package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte +22 -0
  41. package/dist/table/checkbox-indicator/table-checkbox-indicator.svelte.d.ts +10 -0
  42. package/dist/table/column/README.md +32 -0
  43. package/dist/table/column/table-column.svelte +108 -0
  44. package/dist/table/column/table-column.svelte.d.ts +18 -0
  45. package/dist/table/column-header-cell/README.md +28 -0
  46. package/dist/table/column-header-cell/table-column-header-cell.svelte +281 -0
  47. package/dist/table/column-header-cell/table-column-header-cell.svelte.d.ts +9 -0
  48. package/dist/table/column-resizer/README.md +32 -0
  49. package/dist/table/column-resizer/table-column-resizer-freeze-layout-test.svelte +51 -0
  50. package/dist/table/column-resizer/table-column-resizer-freeze-layout-test.svelte.d.ts +3 -0
  51. package/dist/table/column-resizer/table-column-resizer-selection-column-test.svelte +83 -0
  52. package/dist/table/column-resizer/table-column-resizer-selection-column-test.svelte.d.ts +3 -0
  53. package/dist/table/column-resizer/table-column-resizer-test.svelte +75 -0
  54. package/dist/table/column-resizer/table-column-resizer-test.svelte.d.ts +3 -0
  55. package/dist/table/column-resizer/table-column-resizer.svelte +616 -0
  56. package/dist/table/column-resizer/table-column-resizer.svelte.d.ts +11 -0
  57. package/dist/table/empty-state/README.md +25 -0
  58. package/dist/table/empty-state/table-empty-state.svelte +38 -0
  59. package/dist/table/empty-state/table-empty-state.svelte.d.ts +8 -0
  60. package/dist/table/footer/README.md +24 -0
  61. package/dist/table/footer/table-footer.svelte +19 -0
  62. package/dist/table/footer/table-footer.svelte.d.ts +9 -0
  63. package/dist/table/header/README.md +24 -0
  64. package/dist/table/header/table-header.svelte +19 -0
  65. package/dist/table/header/table-header.svelte.d.ts +9 -0
  66. package/dist/table/index.d.ts +16 -0
  67. package/dist/table/index.js +16 -0
  68. package/dist/table/index.parts.d.ts +12 -0
  69. package/dist/table/index.parts.js +12 -0
  70. package/dist/table/root/README.md +56 -0
  71. package/dist/table/root/context.d.ts +198 -0
  72. package/dist/table/root/context.js +1426 -0
  73. package/dist/table/root/table-reorder-test.svelte +64 -0
  74. package/dist/table/root/table-reorder-test.svelte.d.ts +3 -0
  75. package/dist/table/root/table-root.svelte +410 -0
  76. package/dist/table/root/table-root.svelte.d.ts +29 -0
  77. package/dist/table/root/table-test.svelte +165 -0
  78. package/dist/table/root/table-test.svelte.d.ts +25 -0
  79. package/dist/table/row/README.md +27 -0
  80. package/dist/table/row/table-row.svelte +321 -0
  81. package/dist/table/row/table-row.svelte.d.ts +13 -0
  82. package/package.json +11 -1
@@ -0,0 +1,59 @@
1
+ <script lang="ts">
2
+ import { Checkbox } from '../index';
3
+
4
+ type Props = {
5
+ id?: string;
6
+ name?: string;
7
+ value?: string;
8
+ isChecked?: boolean;
9
+ defaultChecked?: boolean;
10
+ isIndeterminate?: boolean;
11
+ defaultIndeterminate?: boolean;
12
+ isDisabled?: boolean;
13
+ isReadOnly?: boolean;
14
+ required?: boolean;
15
+ keepMounted?: boolean;
16
+ onCheckedChange?: (checked: boolean) => void;
17
+ onIndeterminateChange?: (indeterminate: boolean) => void;
18
+ };
19
+
20
+ let {
21
+ id,
22
+ name,
23
+ value = 'newsletter',
24
+ isChecked = $bindable(),
25
+ defaultChecked = false,
26
+ isIndeterminate = $bindable(),
27
+ defaultIndeterminate = false,
28
+ isDisabled = false,
29
+ isReadOnly = false,
30
+ required = false,
31
+ keepMounted = false,
32
+ onCheckedChange,
33
+ onIndeterminateChange
34
+ }: Props = $props();
35
+ </script>
36
+
37
+ <Checkbox.Root
38
+ {id}
39
+ {name}
40
+ {value}
41
+ bind:isChecked
42
+ {defaultChecked}
43
+ bind:isIndeterminate
44
+ {defaultIndeterminate}
45
+ {isDisabled}
46
+ {isReadOnly}
47
+ {required}
48
+ {onCheckedChange}
49
+ {onIndeterminateChange}
50
+ class="inline-flex h-5 w-5 items-center justify-center"
51
+ aria-label="Accept terms"
52
+ >
53
+ <Checkbox.Indicator {keepMounted}>
54
+ <span data-checkbox-icon="true">icon</span>
55
+ </Checkbox.Indicator>
56
+ </Checkbox.Root>
57
+
58
+ <output data-checked-state>{String(isChecked ?? false)}</output>
59
+ <output data-indeterminate-state>{String(isIndeterminate ?? false)}</output>
@@ -0,0 +1,18 @@
1
+ type Props = {
2
+ id?: string;
3
+ name?: string;
4
+ value?: string;
5
+ isChecked?: boolean;
6
+ defaultChecked?: boolean;
7
+ isIndeterminate?: boolean;
8
+ defaultIndeterminate?: boolean;
9
+ isDisabled?: boolean;
10
+ isReadOnly?: boolean;
11
+ required?: boolean;
12
+ keepMounted?: boolean;
13
+ onCheckedChange?: (checked: boolean) => void;
14
+ onIndeterminateChange?: (indeterminate: boolean) => void;
15
+ };
16
+ declare const CheckboxTest: import("svelte").Component<Props, {}, "isChecked" | "isIndeterminate">;
17
+ type CheckboxTest = ReturnType<typeof CheckboxTest>;
18
+ export default CheckboxTest;
@@ -0,0 +1,21 @@
1
+ export type CheckboxState = 'checked' | 'unchecked' | 'indeterminate';
2
+ export type CheckboxContext = {
3
+ id: string;
4
+ inputId: string;
5
+ inputRef: HTMLInputElement | null;
6
+ setInputRef: (element: HTMLInputElement | null) => void;
7
+ state: CheckboxState;
8
+ pressed: boolean;
9
+ isChecked: boolean;
10
+ isIndeterminate: boolean;
11
+ isDisabled: boolean;
12
+ isReadOnly: boolean;
13
+ required: boolean;
14
+ focused: boolean;
15
+ focusVisible: boolean;
16
+ toggle: (event?: Event) => void;
17
+ setState: (state: CheckboxState, event?: Event) => void;
18
+ };
19
+ export declare function setCheckboxContext(context: CheckboxContext): void;
20
+ export declare function getCheckboxContext(): CheckboxContext | undefined;
21
+ export declare function useCheckboxContext(): CheckboxContext;
@@ -0,0 +1,15 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const CHECKBOX_CONTEXT_KEY = Symbol('checkbox');
3
+ export function setCheckboxContext(context) {
4
+ setContext(CHECKBOX_CONTEXT_KEY, context);
5
+ }
6
+ export function getCheckboxContext() {
7
+ return getContext(CHECKBOX_CONTEXT_KEY);
8
+ }
9
+ export function useCheckboxContext() {
10
+ const context = getCheckboxContext();
11
+ if (!context) {
12
+ throw new Error('Checkbox components must be used within Checkbox.Root.');
13
+ }
14
+ return context;
15
+ }
@@ -17,7 +17,7 @@ declare function $$render<T extends object = object>(): {
17
17
  } & {
18
18
  context?: ListBoxContext;
19
19
  element?: HTMLElement;
20
- }, "selectionMode" | "selectionBehavior" | "id" | "value" | "defaultValue" | "onChange" | "items" | "children" | "context" | "element"> & {
20
+ }, "children" | "id" | "value" | "selectionMode" | "selectionBehavior" | "defaultValue" | "onChange" | "items" | "context" | "element"> & {
21
21
  /** Optional items for dynamic rendering - overrides items from ComboBox context */
22
22
  items?: Iterable<T>;
23
23
  /** Content of the listbox. Receives item in dynamic mode. */
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { Checkbox } from './checkbox/index.ts';
1
2
  export { ComboBox } from './combobox/index.ts';
2
3
  export { Calendar } from './calendar/index.ts';
3
4
  export { Clock } from './clock/index.ts';
@@ -6,11 +7,13 @@ export { TimePicker } from './timepicker/index.ts';
6
7
  export { Dialog } from './dialog/index.ts';
7
8
  export { ListBox } from './listbox/index.ts';
8
9
  export { Popover } from './popover/index.ts';
10
+ export { Table } from './table/index.ts';
9
11
  export { default as Input } from './input/index.ts';
10
12
  export { default as Label } from './label/index.ts';
11
13
  export { default as LocaleProvider } from './locale-provider/index.ts';
12
14
  export { Portal } from './portal/index.ts';
13
15
  export * from './locale-provider/index.ts';
16
+ export * from './checkbox/index.ts';
14
17
  export * from './combobox/index.ts';
15
18
  export * from './calendar/index.ts';
16
19
  export * from './clock/index.ts';
@@ -19,6 +22,7 @@ export * from './timepicker/index.ts';
19
22
  export * from './dialog/index.ts';
20
23
  export * from './listbox/index.ts';
21
24
  export * from './popover/index.ts';
25
+ export * from './table/index.ts';
22
26
  export * from './primitives/index.ts';
23
27
  export { cn } from './utils/index.ts';
24
28
  export * from './utils/index.ts';
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // Main library entry point
2
2
  // Components (namespace exports)
3
+ export { Checkbox } from './checkbox/index.ts';
3
4
  export { ComboBox } from './combobox/index.ts';
4
5
  export { Calendar } from './calendar/index.ts';
5
6
  export { Clock } from './clock/index.ts';
@@ -8,6 +9,7 @@ export { TimePicker } from './timepicker/index.ts';
8
9
  export { Dialog } from './dialog/index.ts';
9
10
  export { ListBox } from './listbox/index.ts';
10
11
  export { Popover } from './popover/index.ts';
12
+ export { Table } from './table/index.ts';
11
13
  // Simple components
12
14
  export { default as Input } from './input/index.ts';
13
15
  export { default as Label } from './label/index.ts';
@@ -15,6 +17,7 @@ export { default as LocaleProvider } from './locale-provider/index.ts';
15
17
  export { Portal } from './portal/index.ts';
16
18
  export * from './locale-provider/index.ts';
17
19
  // Re-export named exports from components
20
+ export * from './checkbox/index.ts';
18
21
  export * from './combobox/index.ts';
19
22
  export * from './calendar/index.ts';
20
23
  export * from './clock/index.ts';
@@ -23,6 +26,7 @@ export * from './timepicker/index.ts';
23
26
  export * from './dialog/index.ts';
24
27
  export * from './listbox/index.ts';
25
28
  export * from './popover/index.ts';
29
+ export * from './table/index.ts';
26
30
  // Primitives
27
31
  export * from './primitives/index.ts';
28
32
  // Utilities
@@ -0,0 +1,8 @@
1
+ # Table Implementation Notes
2
+
3
+ ## Open questions
4
+
5
+ - Disabled body rows are currently rendered and keyboard-focusable, but they cannot be selected. We should validate whether this matches the desired UX.
6
+ - `Table.Column` is implemented as a logical wrapper and currently assumes the intended child is a single `Table.ColumnHeaderCell`.
7
+ - `Table.Footer` renders semantic table cells but is intentionally excluded from the roving-focus model in v1.
8
+ - Interactive controls nested inside `Table.Cell` are still intentionally out of scope for v1.
@@ -0,0 +1,152 @@
1
+ # Plan: `hiddenColumns` prop for Table.Root
2
+
3
+ ## Objective
4
+
5
+ Add a `hiddenColumns` prop to `Table.Root` that accepts an array of column IDs and hides those columns automatically across header, body, and footer — without breaking the positional column↔cell mapping.
6
+
7
+ ## Reviewed decisions
8
+
9
+ - Keep **physical column order** for cell-to-column mapping in body/footer rows.
10
+ - Add a separate **visible column model** for aria counts, keyboard navigation, and visible `data-column-index` values.
11
+ - Preserve hidden column widths in state so re-showing a column restores its prior size.
12
+
13
+ ## API Design
14
+
15
+ ### New props on `Table.Root`
16
+
17
+ ```ts
18
+ hiddenColumns?: string[]; // controlled (bindable)
19
+ defaultHiddenColumns?: string[]; // uncontrolled initial state
20
+ onHiddenColumnsChange?: (ids: string[]) => void;
21
+ ```
22
+
23
+ - `hiddenColumns` is **bindable** (`bind:hiddenColumns`) so consumers can sync external state (e.g. a column-visibility dropdown).
24
+ - Follows the same controlled/uncontrolled pattern as `selectedKeys`, `sortDescriptor`, and `columnWidths`.
25
+
26
+ ### Internal context method
27
+
28
+ ```ts
29
+ isColumnHidden(columnId: string): boolean;
30
+ ```
31
+
32
+ ## Hiding strategy: `display: none` — not DOM removal
33
+
34
+ Body cells map their column by DOM position (`columnIndex`). Removing a `<Table.Column>` from the DOM with `{#if}` causes body cells to misalign because the index shifts.
35
+
36
+ Using `display: none`:
37
+
38
+ - DOM order is preserved → index mapping never breaks.
39
+ - Users don't need paired `{#if}` guards in both header and every body row.
40
+ - `display: none` on native `<th>`/`<td>` is valid — the table reflows correctly.
41
+
42
+ ## Implementation tasks
43
+
44
+ ### 1. Context (`table/root/context.ts`)
45
+
46
+ - Add `hiddenColumnsSet: Set<string>` as reactive internal state (derived from the array prop).
47
+ - Expose `isColumnHidden(columnId: string): boolean`.
48
+ - Add `hiddenColumnsVersion` store for efficient reactive invalidation.
49
+ - Update `getColumnCount()` to exclude hidden columns from the navigable count.
50
+ - Update navigable-cells cache (`navigableCellsCache`) to skip cells belonging to hidden columns.
51
+ - Update `getRowsWithCells()` so keyboard navigation sees only visible cells.
52
+
53
+ ### 2. Root component (`table/root/table-root.svelte`)
54
+
55
+ - Add props: `hiddenColumns` (bindable), `defaultHiddenColumns`, `onHiddenColumnsChange`.
56
+ - Implement controlled/uncontrolled pattern (identical to `selectedKeys`).
57
+ - Pass `hiddenColumnsSet` into the context.
58
+
59
+ ### 3. Column (`table/column/table-column.svelte`)
60
+
61
+ - Read `isColumnHidden(id)` from context.
62
+ - If hidden → propagate hidden state to column context so children can react.
63
+
64
+ ### 4. ColumnHeaderCell (`table/column-header-cell/`)
65
+
66
+ - Apply `display: none` when column is hidden.
67
+ - Set `aria-hidden="true"` when hidden.
68
+ - Exclude from tab order.
69
+
70
+ ### 5. Cell (`table/cell/table-cell.svelte`)
71
+
72
+ - Resolve column from `columnIndex` (existing behavior).
73
+ - If column is hidden → apply `display: none` and `aria-hidden="true"`.
74
+ - Exclude from tab order and focus navigation.
75
+
76
+ ### 6. ColumnResizer (`table/column-resizer/`)
77
+
78
+ - Not navigable or interactive while its column is hidden.
79
+
80
+ ### 7. Keyboard navigation
81
+
82
+ - Arrow left/right must skip cells of hidden columns.
83
+ - Home/End must target the first/last **visible** cell.
84
+ - If the currently focused cell becomes hidden, move focus to the nearest visible cell.
85
+ - Ctrl+A is unaffected (operates on rows, not columns).
86
+
87
+ ### 8. Sorting and column widths
88
+
89
+ - Sorting a hidden column: keep the descriptor but do not render a visual indicator.
90
+ - Column widths: hidden columns retain their width in the Map but do not affect layout.
91
+
92
+ ## Tests
93
+
94
+ ### Rendering
95
+
96
+ - Hidden column is not visible in the DOM (`display: none` on header, body, and footer cells).
97
+ - Columns not listed in `hiddenColumns` render normally.
98
+ - Dynamically changing `hiddenColumns` shows/hides columns reactively.
99
+
100
+ ### Bindable / controlled
101
+
102
+ - `bind:hiddenColumns` reflects bidirectional changes.
103
+ - `defaultHiddenColumns` applies only on initial mount.
104
+ - `onHiddenColumnsChange` fires when the set changes internally.
105
+
106
+ ### Keyboard navigation
107
+
108
+ - Arrow left/right skip cells of hidden columns.
109
+ - Home/End target the first/last visible cell.
110
+ - Tab enters the grid on a visible cell (never a hidden one).
111
+ - Hiding the column of the currently focused cell moves focus to the nearest visible neighbor.
112
+
113
+ ### Feature interactions
114
+
115
+ - Selection checkboxes in a hidden column: row selection still works.
116
+ - Sorting by a hidden column does not crash; descriptor is preserved.
117
+ - Column resize: hidden column is not resizable while hidden.
118
+ - `getColumnCount()` returns only visible columns.
119
+ - Empty `hiddenColumns` array has no effect.
120
+
121
+ ### Accessibility
122
+
123
+ - Hidden cells carry `aria-hidden="true"` in header, body, and footer.
124
+ - `aria-colcount` on the `<table>` reflects only **visible** columns.
125
+ - `aria-colindex` on visible cells is recalculated excluding hidden columns.
126
+ - Screen readers do not announce hidden columns during navigation.
127
+
128
+ ## Files affected
129
+
130
+ | File | Change |
131
+ | ---------------------------------------------------------- | ------------------------------------------ |
132
+ | `table/root/context.ts` | State, methods, caches |
133
+ | `table/root/table-root.svelte` | Props, binding, controlled pattern |
134
+ | `table/column/table-column.svelte` | Propagate hidden state |
135
+ | `table/column-header-cell/table-column-header-cell.svelte` | `display: none`, `aria-hidden` |
136
+ | `table/cell/table-cell.svelte` | `display: none`, `aria-hidden`, skip focus |
137
+ | `table/column-resizer/table-column-resizer.svelte` | Skip interaction when hidden |
138
+ | `table/index.parts.ts` | Type exports if needed |
139
+ | `table/index.ts` | Type exports if needed |
140
+ | `table/root/*.test.ts` | New test cases |
141
+
142
+ ## Execution order
143
+
144
+ 1. Context — state + methods (foundation)
145
+ 2. Root — props + binding (public API → context)
146
+ 3. Column + ColumnHeaderCell — hide header
147
+ 4. Cell — hide body/footer cells
148
+ 5. ColumnResizer — disable interaction
149
+ 6. Navigation — update keyboard nav to skip hidden cells
150
+ 7. Tests — validate all above
151
+ 8. Accessibility — audit aria attributes
152
+ 9. Demo page — add visibility toggle to the playground