@human-kit/svelte-components 1.0.0-alpha.16 → 1.0.0-alpha.18

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 (32) hide show
  1. package/dist/checkbox/root/checkbox-root.svelte +9 -4
  2. package/dist/checkbox/root/checkbox-root.svelte.d.ts +4 -1
  3. package/dist/table/PLAN.md +6 -6
  4. package/dist/table/README.md +4 -2
  5. package/dist/table/body/table-body.svelte +5 -0
  6. package/dist/table/cell/table-cell.svelte +18 -1
  7. package/dist/table/checkbox/README.md +1 -1
  8. package/dist/table/checkbox/table-checkbox.svelte +5 -48
  9. package/dist/table/checkbox-indicator/README.md +1 -1
  10. package/dist/table/column/README.md +11 -11
  11. package/dist/table/column-header-cell/table-column-header-cell.svelte +20 -17
  12. package/dist/table/column-resizer/table-column-resizer-fixed-width-test.svelte +57 -0
  13. package/dist/table/column-resizer/table-column-resizer-fixed-width-test.svelte.d.ts +3 -0
  14. package/dist/table/column-resizer/table-column-resizer-freeze-layout-test.svelte +2 -1
  15. package/dist/table/column-resizer/table-column-resizer-overflow-test.svelte +64 -0
  16. package/dist/table/column-resizer/table-column-resizer-overflow-test.svelte.d.ts +3 -0
  17. package/dist/table/column-resizer/table-column-resizer-padded-container-test.svelte +67 -0
  18. package/dist/table/column-resizer/table-column-resizer-padded-container-test.svelte.d.ts +3 -0
  19. package/dist/table/column-resizer/table-column-resizer-sandbox-overflow-test.svelte +87 -0
  20. package/dist/table/column-resizer/table-column-resizer-sandbox-overflow-test.svelte.d.ts +3 -0
  21. package/dist/table/column-resizer/table-column-resizer-selection-column-test.svelte +2 -1
  22. package/dist/table/column-resizer/table-column-resizer-test.svelte +3 -3
  23. package/dist/table/column-resizer/table-column-resizer-three-column-relative-test.svelte +64 -0
  24. package/dist/table/column-resizer/table-column-resizer-three-column-relative-test.svelte.d.ts +3 -0
  25. package/dist/table/column-resizer/table-column-resizer.svelte +47 -54
  26. package/dist/table/root/README.md +12 -12
  27. package/dist/table/root/context.d.ts +24 -7
  28. package/dist/table/root/context.js +506 -43
  29. package/dist/table/root/table-root.svelte +140 -9
  30. package/dist/table/row/table-row.svelte +20 -60
  31. package/dist/table/types.d.ts +4 -4
  32. package/package.json +1 -1
@@ -14,7 +14,6 @@
14
14
  | 'class'
15
15
  | 'id'
16
16
  | 'role'
17
- | 'tabindex'
18
17
  | 'aria-checked'
19
18
  | 'aria-disabled'
20
19
  | 'aria-readonly'
@@ -40,8 +39,11 @@
40
39
  class?: string;
41
40
  'aria-label'?: string;
42
41
  'aria-labelledby'?: string;
42
+ tabindex?: number;
43
43
  onclick?: HTMLAttributes<HTMLSpanElement>['onclick'];
44
44
  onkeydown?: HTMLAttributes<HTMLSpanElement>['onkeydown'];
45
+ onfocus?: HTMLAttributes<HTMLSpanElement>['onfocus'];
46
+ onmousedown?: HTMLAttributes<HTMLSpanElement>['onmousedown'];
45
47
  };
46
48
 
47
49
  function composeEventHandlers<TEvent extends Event>(
@@ -85,8 +87,11 @@
85
87
  class: className = '',
86
88
  'aria-label': ariaLabel,
87
89
  'aria-labelledby': ariaLabelledby,
90
+ tabindex,
88
91
  onclick: onClickExternal,
89
92
  onkeydown: onKeyDownExternal,
93
+ onfocus: onFocusExternal,
94
+ onmousedown: onMouseDownExternal,
90
95
  ...restProps
91
96
  }: CheckboxRootProps = $props();
92
97
 
@@ -329,7 +334,7 @@
329
334
  bind:this={rootRef}
330
335
  id={rootId}
331
336
  role="checkbox"
332
- tabindex={isDisabled ? undefined : 0}
337
+ tabindex={isDisabled ? undefined : (tabindex ?? 0)}
333
338
  aria-checked={currentIndeterminate ? 'mixed' : currentChecked ? 'true' : 'false'}
334
339
  aria-disabled={isDisabled || undefined}
335
340
  aria-readonly={isReadOnly || undefined}
@@ -350,8 +355,8 @@
350
355
  onkeydown={composeEventHandlers(handleKeyDown, onKeyDownExternal ?? undefined)}
351
356
  onkeyup={handleKeyUp}
352
357
  onpointerdown={handlePointerDown}
353
- onmousedown={handlePointerDown}
354
- onfocus={handleFocus}
358
+ onmousedown={composeEventHandlers(onMouseDownExternal ?? undefined, handlePointerDown)}
359
+ onfocus={composeEventHandlers(handleFocus, onFocusExternal ?? undefined)}
355
360
  onblur={handleBlur}
356
361
  class={cn(
357
362
  'relative inline-flex shrink-0 items-center justify-center align-middle outline-none',
@@ -1,6 +1,6 @@
1
1
  import { type Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- type CheckboxRootProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'class' | 'id' | 'role' | 'tabindex' | 'aria-checked' | 'aria-disabled' | 'aria-readonly' | 'aria-required' | 'onclick' | 'onkeydown' | 'value'> & {
3
+ type CheckboxRootProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'class' | 'id' | 'role' | 'aria-checked' | 'aria-disabled' | 'aria-readonly' | 'aria-required' | 'onclick' | 'onkeydown' | 'value'> & {
4
4
  id?: string;
5
5
  element?: HTMLSpanElement | null;
6
6
  name?: string;
@@ -18,8 +18,11 @@ type CheckboxRootProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children' | 'cla
18
18
  class?: string;
19
19
  'aria-label'?: string;
20
20
  'aria-labelledby'?: string;
21
+ tabindex?: number;
21
22
  onclick?: HTMLAttributes<HTMLSpanElement>['onclick'];
22
23
  onkeydown?: HTMLAttributes<HTMLSpanElement>['onkeydown'];
24
+ onfocus?: HTMLAttributes<HTMLSpanElement>['onfocus'];
25
+ onmousedown?: HTMLAttributes<HTMLSpanElement>['onmousedown'];
23
26
  };
24
27
  declare const CheckboxRoot: import("svelte").Component<CheckboxRootProps, {}, "element" | "isChecked" | "isIndeterminate">;
25
28
  type CheckboxRoot = ReturnType<typeof CheckboxRoot>;
@@ -911,7 +911,7 @@ Minimum regression coverage:
911
911
 
912
912
  ## Phase 3: Row Actions and Disabled Behavior Plan
913
913
 
914
- ### Goal
914
+ ### Phase 3 Goal
915
915
 
916
916
  Add row actions in a way that matches the React Aria Components mental model closely enough for consumers to predict behavior, while still fitting the existing `Table` architecture in this repository:
917
917
 
@@ -936,7 +936,7 @@ The goal is functional parity for the supported cases, not a byte-for-byte clone
936
936
 
937
937
  ### Public API Recommendation
938
938
 
939
- #### `Table.Root`
939
+ #### `Table.Root` Props
940
940
 
941
941
  Add the following props:
942
942
 
@@ -970,7 +970,7 @@ Reasons:
970
970
  - React Aria already establishes a recognizable interaction contract based on those inputs
971
971
  - a separate `rowPressBehavior` prop would create redundant states and undocumented invalid combinations
972
972
 
973
- ### Interaction Model
973
+ ### Phase 3 Interaction Model
974
974
 
975
975
  #### Core Principle
976
976
 
@@ -1163,7 +1163,7 @@ The coordinator should decide behavior using:
1163
1163
 
1164
1164
  ### Affected Parts
1165
1165
 
1166
- #### `root/context.ts`
1166
+ #### `root/context.ts` Changes
1167
1167
 
1168
1168
  Will need to own:
1169
1169
 
@@ -1278,7 +1278,7 @@ This is important because reusing the current all-or-nothing `aria-disabled` con
1278
1278
  | `single` / `multiple` | no | existing selection behavior | existing selection behavior |
1279
1279
  | `single` / `multiple` | yes | action | selection |
1280
1280
 
1281
- ### Testing Plan
1281
+ ### Phase 3 Testing Plan
1282
1282
 
1283
1283
  Minimum regression coverage:
1284
1284
 
@@ -1320,7 +1320,7 @@ This phase should not attempt to solve:
1320
1320
 
1321
1321
  These can be revisited later, but they should not block the collection-level row action API.
1322
1322
 
1323
- ### Recommended Implementation Order
1323
+ ### Phase 3 Recommended Implementation Order
1324
1324
 
1325
1325
  1. Add `onRowAction` and `disabledBehavior` to `Table.Root` and root context.
1326
1326
  2. Refactor disabled-state helpers into selection-vs-action-aware logic.
@@ -90,8 +90,10 @@ All public Table part prop types are exported from the table barrel, including `
90
90
  - Use `defaultSortDescriptor` for uncontrolled initial sort state.
91
91
  - Use `hiddenColumns` for controlled column visibility when consumers need to show or hide columns without changing the table markup.
92
92
  - Use `defaultHiddenColumns` for uncontrolled initial column visibility.
93
- - Use `columnWidths` / `onColumnWidthsChange` for controlled column width state.
94
- - Use `defaultColumnWidths`, `Table.Column.defaultWidth`, and `Table.Column.width` to seed explicit widths.
93
+ - Use `columnWidths` / `onColumnWidthsChange` for controlled column width state. Width specs can be px, `%`, or `fr`.
94
+ - Use `defaultColumnWidths` and `Table.Column.defaultWidth` to seed uncontrolled initial widths that can still be resized by the user.
95
+ - Use `Table.Column.width` when a column should stay fixed at an explicit width. Fixed-width columns ignore resize attempts even if a `Table.ColumnResizer` is composed.
96
+ - In resizable tables, unspecified columns behave like an implicit `1fr` width before interaction. On the first real resize, visible columns are materialized to px; the trailing column absorbs the delta until its minimum width, and further growth overflows the table horizontally.
95
97
  - Setting `sortDescriptor` back to `undefined` clears the controlled sort state, matching React Aria Table semantics.
96
98
  - Set `Table.Column.textValue` when the spoken column label should differ from the column id; `Table.Root` uses it for polite sort announcements.
97
99
  - Use `Table.EmptyState` inside `Table.Body` instead of conditionally rendering freeform body content.
@@ -6,6 +6,11 @@
6
6
  setTableSectionContext({ section: 'body' });
7
7
  const table = useTableContext();
8
8
  const layoutVersion = table.layoutVersion;
9
+
10
+ $effect(() => {
11
+ table.markBodyRowsInitialized();
12
+ });
13
+
9
14
  const isEmpty = $derived.by(() => {
10
15
  void $layoutVersion;
11
16
  return table.getBodyRowCount() === 0;
@@ -21,6 +21,7 @@
21
21
  const layoutVersion = table.layoutVersion;
22
22
  const focusVersion = table.focusVersion;
23
23
  const selectionVersion = table.selectionVersion;
24
+ const widthVersion = table.widthVersion;
24
25
  const cellOrderVersion = row.cellOrderVersion;
25
26
 
26
27
  let element = $state<HTMLElement | undefined>(undefined);
@@ -82,6 +83,18 @@
82
83
  void $layoutVersion;
83
84
  return column ? table.getVisibleColumnIndexByToken(column.token) : -1;
84
85
  });
86
+ const columnWidthStyle = $derived.by(() => {
87
+ void $widthVersion;
88
+ return column ? table.getColumnWidthStyle(column.id) : undefined;
89
+ });
90
+ const columnMinWidth = $derived.by(() => {
91
+ void $widthVersion;
92
+ return column ? table.getColumnMinWidth(column.id) : undefined;
93
+ });
94
+ const columnMaxWidth = $derived.by(() => {
95
+ void $widthVersion;
96
+ return column ? table.getColumnMaxWidth(column.id) : undefined;
97
+ });
85
98
  const tagName = $derived(row.section === 'body' && column?.isRowHeader ? 'th' : 'td');
86
99
  const role = $derived.by(() => {
87
100
  if (isColumnHidden) return undefined;
@@ -234,7 +247,11 @@
234
247
  : undefined}
235
248
  data-disabled={isRowDisabled || undefined}
236
249
  data-column-index={visibleColumnIndex >= 0 ? visibleColumnIndex : undefined}
237
- style:display={isColumnHidden ? 'none' : undefined}
250
+ style:box-sizing="border-box"
251
+ style:width={columnWidthStyle}
252
+ style:min-width={columnMinWidth !== undefined ? `${columnMinWidth}px` : undefined}
253
+ style:max-width={columnMaxWidth !== undefined ? `${columnMaxWidth}px` : undefined}
254
+ style:display={isColumnHidden ? 'none' : 'table-cell'}
238
255
  onfocus={row.section === 'body' ? handleFocus : undefined}
239
256
  onclick={row.section === 'body' ? handleClick : undefined}
240
257
  ondblclick={row.section === 'body' ? handleDoubleClick : undefined}
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## API reference
4
4
 
5
- ### Table.Checkbox
5
+ ### Checkbox Part
6
6
 
7
7
  Name: `Table.Checkbox`
8
8
  Description: Headless selection-aware checkbox root for tables. In body cells it toggles the owning row. In header cells it becomes a select-all checkbox for multiple selection mode.
@@ -30,8 +30,6 @@
30
30
  const layoutVersion = table.layoutVersion;
31
31
 
32
32
  let checkboxElement = $state<HTMLSpanElement | null>(null);
33
- let checkboxChecked = $state(false);
34
- let checkboxIndeterminate = $state(false);
35
33
 
36
34
  const isVisible = $derived.by(() => {
37
35
  if (table.selectionMode === 'none') return false;
@@ -85,17 +83,6 @@
85
83
  return checkboxElement ?? undefined;
86
84
  }
87
85
 
88
- $effect(() => {
89
- void $selectionVersion;
90
- checkboxChecked = isChecked;
91
- });
92
-
93
- $effect(() => {
94
- void $selectionVersion;
95
- void $layoutVersion;
96
- checkboxIndeterminate = isIndeterminate;
97
- });
98
-
99
86
  $effect(() => {
100
87
  if (!isVisible || isDisabled) {
101
88
  cell.unregisterFocusDelegate();
@@ -109,39 +96,6 @@
109
96
  };
110
97
  });
111
98
 
112
- $effect(() => {
113
- const checkboxElement = getCheckboxRootElement();
114
- if (!checkboxElement) return;
115
-
116
- if (!isVisible || isDisabled || tabIndex === undefined) {
117
- checkboxElement.removeAttribute('tabindex');
118
- return;
119
- }
120
-
121
- checkboxElement.tabIndex = tabIndex;
122
- });
123
-
124
- $effect(() => {
125
- const checkboxElement = getCheckboxRootElement();
126
- if (!checkboxElement) return;
127
-
128
- const handleElementFocus = (event: FocusEvent) => {
129
- handleFocusIn(event);
130
- };
131
-
132
- const handleElementMouseDown = (event: MouseEvent) => {
133
- handleMouseDown(event);
134
- };
135
-
136
- checkboxElement.addEventListener('focus', handleElementFocus);
137
- checkboxElement.addEventListener('mousedown', handleElementMouseDown);
138
-
139
- return () => {
140
- checkboxElement.removeEventListener('focus', handleElementFocus);
141
- checkboxElement.removeEventListener('mousedown', handleElementMouseDown);
142
- };
143
- });
144
-
145
99
  function applySelection(nextChecked: boolean) {
146
100
  if (isDisabled) return;
147
101
 
@@ -260,16 +214,19 @@
260
214
  <Checkbox.Root
261
215
  {id}
262
216
  bind:element={checkboxElement}
263
- bind:isChecked={checkboxChecked}
264
- bind:isIndeterminate={checkboxIndeterminate}
217
+ {isChecked}
218
+ {isIndeterminate}
265
219
  {isDisabled}
266
220
  onCheckedChange={applySelection}
267
221
  {title}
268
222
  aria-label={accessibleLabel}
269
223
  aria-labelledby={ariaLabelledby}
270
224
  data-table-checkbox="true"
225
+ tabindex={tabIndex}
271
226
  onclick={handleClick}
272
227
  onkeydown={handleKeyDown}
228
+ onfocus={handleFocusIn}
229
+ onmousedown={handleMouseDown}
273
230
  class={className}
274
231
  {...restProps}
275
232
  >
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## API reference
4
4
 
5
- ### Table.CheckboxIndicator
5
+ ### Indicator Part
6
6
 
7
7
  Name: `Table.CheckboxIndicator`
8
8
  Description: Headless presence wrapper for indicator content inside `Table.Checkbox`. It renders when the checkbox is checked or indeterminate.
@@ -11,17 +11,17 @@ Description: Logical metadata wrapper for a header column. It does not render DO
11
11
 
12
12
  Public prop type: `TableColumnProps`
13
13
 
14
- | Prop | Type | Default | Description |
15
- | --------------- | --------------------------- | ----------- | ------------------------------------------------------------------------------------------------- |
16
- | `id` | `string` | `-` | Stable identifier for the column. |
17
- | `allowsSorting` | `boolean` | `false` | Enables sorting for the wrapped header cell. |
18
- | `isRowHeader` | `boolean` | `false` | Marks the associated body column as row-header cells. |
19
- | `textValue` | `string` | `undefined` | Optional spoken label used by `Table.Root` sort announcements when it should differ from `id`. |
20
- | `width` | `number \| \`${number}px\`` | `undefined` | Explicit column width hint. Px numbers are the first-class format for the current resize release. |
21
- | `defaultWidth` | `number \| \`${number}px\`` | `undefined` | Uncontrolled initial width hint for the column. |
22
- | `minWidth` | `number` | `undefined` | Minimum width in px enforced during resize interactions. |
23
- | `maxWidth` | `number` | `undefined` | Maximum width in px enforced during resize interactions. |
24
- | `children` | `Snippet` | `undefined` | Usually a single `Table.ColumnHeaderCell`. |
14
+ | Prop | Type | Default | Description |
15
+ | --------------- | --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------- |
16
+ | `id` | `string` | `-` | Stable identifier for the column. |
17
+ | `allowsSorting` | `boolean` | `false` | Enables sorting for the wrapped header cell. |
18
+ | `isRowHeader` | `boolean` | `false` | Marks the associated body column as row-header cells. |
19
+ | `textValue` | `string` | `undefined` | Optional spoken label used by `Table.Root` sort announcements when it should differ from `id`. |
20
+ | `width` | `number \| \`${number}px\`` | `undefined` | Fixed column width. When set, the column keeps that width and user resize interactions are disabled. |
21
+ | `defaultWidth` | `number \| \`${number}px\`` | `undefined` | Uncontrolled initial width hint for the column. The column remains user-resizable when a resizer is composed. |
22
+ | `minWidth` | `number` | `undefined` | Minimum width in px enforced during resize interactions. |
23
+ | `maxWidth` | `number` | `undefined` | Maximum width in px enforced during resize interactions. |
24
+ | `children` | `Snippet` | `undefined` | Usually a single `Table.ColumnHeaderCell`. |
25
25
 
26
26
  `Table.ColumnResizer` is the public resize opt-in. Compose it inside `Table.ColumnHeaderCell` when the owning column should be resizable.
27
27
 
@@ -93,10 +93,17 @@
93
93
  void $layoutVersion;
94
94
  return column.isHidden;
95
95
  });
96
-
97
- const columnWidth = $derived.by(() => {
96
+ const columnWidthStyle = $derived.by(() => {
97
+ void $widthVersion;
98
+ return table.getColumnWidthStyle(column.id);
99
+ });
100
+ const columnMinWidth = $derived.by(() => {
101
+ void $widthVersion;
102
+ return table.getColumnMinWidth(column.id);
103
+ });
104
+ const columnMaxWidth = $derived.by(() => {
98
105
  void $widthVersion;
99
- return table.getColumnWidth(column.id);
106
+ return table.getColumnMaxWidth(column.id);
100
107
  });
101
108
  const visibleColumnIndex = $derived.by(() => {
102
109
  void $layoutVersion;
@@ -249,8 +256,13 @@
249
256
  data-sortable={column.allowsSorting || undefined}
250
257
  data-sort-direction={sortDirection}
251
258
  data-column-index={visibleColumnIndex >= 0 ? visibleColumnIndex : undefined}
252
- style:width={columnWidth !== undefined ? `${columnWidth}px` : undefined}
253
- style:display={isHidden ? 'none' : undefined}
259
+ style:box-sizing="border-box"
260
+ style:position="relative"
261
+ style:overflow="visible"
262
+ style:width={columnWidthStyle}
263
+ style:min-width={columnMinWidth !== undefined ? `${columnMinWidth}px` : undefined}
264
+ style:max-width={columnMaxWidth !== undefined ? `${columnMaxWidth}px` : undefined}
265
+ style:display={isHidden ? 'none' : 'table-cell'}
254
266
  onfocusin={handleFocusIn}
255
267
  onfocusout={handleFocusOut}
256
268
  onfocus={handleFocus}
@@ -260,16 +272,7 @@
260
272
  onkeydown={handleKeyDown}
261
273
  {...restProps}
262
274
  >
263
- <div
264
- data-table-header-content
265
- style:overflow="visible"
266
- style:position="relative"
267
- style:min-width="0"
268
- style:width="100%"
269
- style:height="100%"
270
- >
271
- {#if children}
272
- {@render children()}
273
- {/if}
274
- </div>
275
+ {#if children}
276
+ {@render children()}
277
+ {/if}
275
278
  </th>
@@ -0,0 +1,57 @@
1
+ <script lang="ts">
2
+ import { Table } from '../index';
3
+ import type { TableColumnWidth } from '../root/context';
4
+
5
+ let currentColumnWidths = $state<Map<string, TableColumnWidth>>(new Map());
6
+ </script>
7
+
8
+ <Table.Root aria-label="Fixed width table" bind:columnWidths={currentColumnWidths}>
9
+ <Table.Header>
10
+ <Table.Row>
11
+ <Table.Column
12
+ id="email"
13
+ isRowHeader
14
+ textValue="Email"
15
+ width={220}
16
+ minWidth={220}
17
+ maxWidth={220}
18
+ >
19
+ <Table.ColumnHeaderCell>
20
+ <div class="flex items-center justify-between gap-3">
21
+ <span>Email</span>
22
+ <Table.ColumnResizer
23
+ data-testid="fixed-email-resizer"
24
+ class="inline-flex w-3 cursor-col-resize justify-center"
25
+ />
26
+ </div>
27
+ </Table.ColumnHeaderCell>
28
+ </Table.Column>
29
+ <Table.Column id="role" textValue="Role" defaultWidth={180} minWidth={120}>
30
+ <Table.ColumnHeaderCell>
31
+ <div class="flex items-center justify-between gap-3">
32
+ <span>Role</span>
33
+ <Table.ColumnResizer
34
+ data-testid="role-resizer"
35
+ class="inline-flex w-3 cursor-col-resize justify-center"
36
+ />
37
+ </div>
38
+ </Table.ColumnHeaderCell>
39
+ </Table.Column>
40
+ </Table.Row>
41
+ </Table.Header>
42
+
43
+ <Table.Body>
44
+ <Table.Row id="danilo">
45
+ <Table.Cell>danilo.fernandez+workspace-owner@example.com</Table.Cell>
46
+ <Table.Cell>Developer</Table.Cell>
47
+ </Table.Row>
48
+ <Table.Row id="zahra">
49
+ <Table.Cell>zahra@example.com</Table.Cell>
50
+ <Table.Cell>Admin</Table.Cell>
51
+ </Table.Row>
52
+ </Table.Body>
53
+ </Table.Root>
54
+
55
+ <output data-testid="column-widths"
56
+ >{JSON.stringify(Object.fromEntries(currentColumnWidths))}</output
57
+ >
@@ -0,0 +1,3 @@
1
+ declare const TableColumnResizerFixedWidthTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type TableColumnResizerFixedWidthTest = ReturnType<typeof TableColumnResizerFixedWidthTest>;
3
+ export default TableColumnResizerFixedWidthTest;
@@ -1,7 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { Table } from '../index';
3
+ import type { TableColumnWidth } from '../root/context';
3
4
 
4
- let currentColumnWidths = $state<Map<string, number> | undefined>(undefined);
5
+ let currentColumnWidths = $state<Map<string, TableColumnWidth> | undefined>(undefined);
5
6
  </script>
6
7
 
7
8
  <div style="width: 640px;">
@@ -0,0 +1,64 @@
1
+ <script lang="ts">
2
+ import { Table } from '../index';
3
+ import type { TableColumnWidth } from '../root/context';
4
+
5
+ let currentColumnWidths = $state<Map<string, TableColumnWidth> | undefined>(undefined);
6
+ </script>
7
+
8
+ <div style="width: 640px; overflow-x: auto;">
9
+ <Table.Root
10
+ aria-label="Resizable overflow table"
11
+ bind:columnWidths={currentColumnWidths}
12
+ class="min-w-full border-collapse text-left"
13
+ >
14
+ <Table.Header>
15
+ <Table.Row>
16
+ <Table.Column id="name" isRowHeader textValue="Name" width={240}>
17
+ <Table.ColumnHeaderCell data-testid="overflow-name-header-cell">
18
+ <div class="flex items-center justify-between gap-3">
19
+ <span>Name</span>
20
+ <Table.ColumnResizer
21
+ data-testid="overflow-name-resizer"
22
+ class="inline-flex w-3 cursor-col-resize justify-center"
23
+ />
24
+ </div>
25
+ </Table.ColumnHeaderCell>
26
+ </Table.Column>
27
+ <Table.Column id="region" textValue="Region" defaultWidth={180} minWidth={140}>
28
+ <Table.ColumnHeaderCell data-testid="overflow-region-header-cell">
29
+ <div class="flex items-center justify-between gap-3">
30
+ <span>Region</span>
31
+ <Table.ColumnResizer
32
+ data-testid="overflow-region-resizer"
33
+ class="inline-flex w-3 cursor-col-resize justify-center"
34
+ />
35
+ </div>
36
+ </Table.ColumnHeaderCell>
37
+ </Table.Column>
38
+ <Table.Column id="plan" textValue="Plan">
39
+ <Table.ColumnHeaderCell data-testid="overflow-plan-header-cell">
40
+ <div class="flex items-center justify-between gap-3">
41
+ <span>Plan</span>
42
+ <Table.ColumnResizer
43
+ data-testid="overflow-plan-resizer"
44
+ class="inline-flex w-3 cursor-col-resize justify-center"
45
+ />
46
+ </div>
47
+ </Table.ColumnHeaderCell>
48
+ </Table.Column>
49
+ </Table.Row>
50
+ </Table.Header>
51
+
52
+ <Table.Body>
53
+ <Table.Row id="danilo">
54
+ <Table.Cell>Danilo Fernandez</Table.Cell>
55
+ <Table.Cell>Buenos Aires</Table.Cell>
56
+ <Table.Cell>Enterprise</Table.Cell>
57
+ </Table.Row>
58
+ </Table.Body>
59
+ </Table.Root>
60
+ </div>
61
+
62
+ <output data-testid="overflow-column-widths"
63
+ >{JSON.stringify(Object.fromEntries(currentColumnWidths ?? new Map()))}</output
64
+ >
@@ -0,0 +1,3 @@
1
+ declare const TableColumnResizerOverflowTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type TableColumnResizerOverflowTest = ReturnType<typeof TableColumnResizerOverflowTest>;
3
+ export default TableColumnResizerOverflowTest;
@@ -0,0 +1,67 @@
1
+ <script lang="ts">
2
+ import { Table } from '../index';
3
+ import type { TableColumnWidth } from '../root/context';
4
+
5
+ let currentColumnWidths = $state<Map<string, TableColumnWidth> | undefined>(undefined);
6
+ </script>
7
+
8
+ <div
9
+ data-testid="padded-relative-container"
10
+ style="width: 640px; box-sizing: border-box; overflow-x: auto; padding: 12px; border: 1px solid transparent;"
11
+ >
12
+ <Table.Root
13
+ aria-label="Padded relative resize table"
14
+ bind:columnWidths={currentColumnWidths}
15
+ class="min-w-full border-collapse text-left"
16
+ >
17
+ <Table.Header>
18
+ <Table.Row>
19
+ <Table.Column id="name" isRowHeader textValue="Name">
20
+ <Table.ColumnHeaderCell data-testid="padded-name-header-cell">
21
+ <div class="flex items-center justify-between gap-3">
22
+ <span>Name</span>
23
+ <Table.ColumnResizer
24
+ data-testid="padded-name-resizer"
25
+ class="inline-flex w-3 cursor-col-resize justify-center"
26
+ />
27
+ </div>
28
+ </Table.ColumnHeaderCell>
29
+ </Table.Column>
30
+ <Table.Column id="region" textValue="Region" defaultWidth={180} minWidth={140}>
31
+ <Table.ColumnHeaderCell data-testid="padded-region-header-cell">
32
+ <div class="flex items-center justify-between gap-3">
33
+ <span>Region</span>
34
+ <Table.ColumnResizer
35
+ data-testid="padded-region-resizer"
36
+ class="inline-flex w-3 cursor-col-resize justify-center"
37
+ />
38
+ </div>
39
+ </Table.ColumnHeaderCell>
40
+ </Table.Column>
41
+ <Table.Column id="plan" textValue="Plan">
42
+ <Table.ColumnHeaderCell data-testid="padded-plan-header-cell">
43
+ <div class="flex items-center justify-between gap-3">
44
+ <span>Plan</span>
45
+ <Table.ColumnResizer
46
+ data-testid="padded-plan-resizer"
47
+ class="inline-flex w-3 cursor-col-resize justify-center"
48
+ />
49
+ </div>
50
+ </Table.ColumnHeaderCell>
51
+ </Table.Column>
52
+ </Table.Row>
53
+ </Table.Header>
54
+
55
+ <Table.Body>
56
+ <Table.Row id="danilo">
57
+ <Table.Cell>Danilo Fernandez</Table.Cell>
58
+ <Table.Cell>Buenos Aires</Table.Cell>
59
+ <Table.Cell>Enterprise</Table.Cell>
60
+ </Table.Row>
61
+ </Table.Body>
62
+ </Table.Root>
63
+ </div>
64
+
65
+ <output data-testid="padded-relative-widths"
66
+ >{JSON.stringify(Object.fromEntries(currentColumnWidths ?? new Map()))}</output
67
+ >
@@ -0,0 +1,3 @@
1
+ declare const TableColumnResizerPaddedContainerTest: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type TableColumnResizerPaddedContainerTest = ReturnType<typeof TableColumnResizerPaddedContainerTest>;
3
+ export default TableColumnResizerPaddedContainerTest;