@human-kit/svelte-components 1.0.0-alpha.15 → 1.0.0-alpha.17

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 (29) hide show
  1. package/dist/table/PLAN.md +6 -6
  2. package/dist/table/README.md +4 -2
  3. package/dist/table/body/table-body.svelte +5 -0
  4. package/dist/table/cell/table-cell.svelte +17 -0
  5. package/dist/table/checkbox/README.md +1 -1
  6. package/dist/table/checkbox/table-checkbox.svelte +2 -15
  7. package/dist/table/checkbox-indicator/README.md +1 -1
  8. package/dist/table/column/README.md +11 -11
  9. package/dist/table/column-header-cell/table-column-header-cell.svelte +19 -16
  10. package/dist/table/column-resizer/table-column-resizer-fixed-width-test.svelte +57 -0
  11. package/dist/table/column-resizer/table-column-resizer-fixed-width-test.svelte.d.ts +3 -0
  12. package/dist/table/column-resizer/table-column-resizer-freeze-layout-test.svelte +2 -1
  13. package/dist/table/column-resizer/table-column-resizer-overflow-test.svelte +64 -0
  14. package/dist/table/column-resizer/table-column-resizer-overflow-test.svelte.d.ts +3 -0
  15. package/dist/table/column-resizer/table-column-resizer-padded-container-test.svelte +67 -0
  16. package/dist/table/column-resizer/table-column-resizer-padded-container-test.svelte.d.ts +3 -0
  17. package/dist/table/column-resizer/table-column-resizer-selection-column-test.svelte +2 -1
  18. package/dist/table/column-resizer/table-column-resizer-test.svelte +3 -3
  19. package/dist/table/column-resizer/table-column-resizer-three-column-relative-test.svelte +64 -0
  20. package/dist/table/column-resizer/table-column-resizer-three-column-relative-test.svelte.d.ts +3 -0
  21. package/dist/table/column-resizer/table-column-resizer.svelte +49 -56
  22. package/dist/table/root/README.md +12 -12
  23. package/dist/table/root/context.d.ts +13 -7
  24. package/dist/table/root/context.js +363 -38
  25. package/dist/table/root/table-root.svelte +116 -17
  26. package/dist/table/types.d.ts +4 -4
  27. package/dist/table/utils/visually-hidden-style.d.ts +1 -0
  28. package/dist/table/utils/visually-hidden-style.js +1 -0
  29. package/package.json +1 -1
@@ -16,10 +16,12 @@
16
16
  shouldShowFocusVisible,
17
17
  trackInteractionModality
18
18
  } from '../../primitives/input-modality';
19
+ import { visuallyHiddenStyle } from '../utils/visually-hidden-style';
19
20
  import type { TableRootProps } from '../types.js';
20
21
  import {
21
22
  createTableContext,
22
23
  setTableContext,
24
+ type TableColumnWidth,
23
25
  type TableSelectionKey,
24
26
  type TableSortDescriptor
25
27
  } from './context';
@@ -59,7 +61,7 @@
59
61
  let focusVisible = $state(false);
60
62
  let pendingControlledHiddenColumns = $state<string[] | null>(null);
61
63
  let pendingControlledSelection = $state<Set<TableSelectionKey> | null>(null);
62
- let pendingControlledColumnWidths = $state<Map<string, number> | null>(null);
64
+ let pendingControlledColumnWidths = $state<Map<string, TableColumnWidth> | null>(null);
63
65
  let sortAnnouncement = $state('');
64
66
  let hasObservedSortState = $state(false);
65
67
  let hasInitializedSortSync = $state(false);
@@ -136,7 +138,10 @@
136
138
  return true;
137
139
  }
138
140
 
139
- function hasSameColumnWidths(left: Map<string, number>, right: Map<string, number>) {
141
+ function hasSameColumnWidths(
142
+ left: Map<string, TableColumnWidth>,
143
+ right: Map<string, TableColumnWidth>
144
+ ) {
140
145
  if (left.size !== right.size) return false;
141
146
  for (const [key, value] of left) {
142
147
  if (right.get(key) !== value) return false;
@@ -163,7 +168,52 @@
163
168
  return ctx.hasResizableColumns();
164
169
  });
165
170
 
171
+ const hasDefinedColumnWidths = $derived.by(() => {
172
+ void $layoutVersion;
173
+ for (let index = 0; index < ctx.getColumnCount(); index += 1) {
174
+ const column = ctx.getColumnAt(index);
175
+ if (!column || ctx.isColumnHidden(column.id)) continue;
176
+ if (column.width !== undefined || column.defaultWidth !== undefined) {
177
+ return true;
178
+ }
179
+ }
180
+ return false;
181
+ });
182
+
183
+ const layoutColumns = $derived.by(() => {
184
+ void $layoutVersion;
185
+ void $widthVersion;
186
+
187
+ const columns: Array<{
188
+ id: string;
189
+ width: number | undefined;
190
+ widthStyle: string | undefined;
191
+ implicitWidth: boolean;
192
+ minWidth: number | undefined;
193
+ maxWidth: number | undefined;
194
+ }> = [];
195
+
196
+ for (let index = 0; index < ctx.getColumnCount(); index += 1) {
197
+ const column = ctx.getColumnAt(index);
198
+ if (!column || ctx.isColumnHidden(column.id)) continue;
199
+
200
+ columns.push({
201
+ id: column.id,
202
+ width: ctx.getColumnWidth(column.id),
203
+ widthStyle: ctx.getColumnWidthStyle(column.id),
204
+ implicitWidth: !ctx.hasAuthoredColumnWidthSpec(column.id),
205
+ minWidth: ctx.getColumnMinWidth(column.id),
206
+ maxWidth: ctx.getColumnMaxWidth(column.id)
207
+ });
208
+ }
209
+
210
+ return columns;
211
+ });
212
+
166
213
  const explicitManagedTableWidth = $derived.by(() => {
214
+ void $layoutVersion;
215
+ if (ctx.hasRelativeVisibleColumnWidths()) return undefined;
216
+
167
217
  const widths = columnWidths ?? defaultColumnWidths;
168
218
  if (!widths) return undefined;
169
219
 
@@ -171,8 +221,10 @@
171
221
  let hasAnyWidth = false;
172
222
  for (const [columnId, width] of widths) {
173
223
  if (ctx.isColumnHidden(columnId)) continue;
174
- if (!Number.isFinite(width)) continue;
175
- total += width;
224
+ if (typeof width === 'string' && !width.trim().endsWith('px')) return undefined;
225
+ const numericWidth = typeof width === 'number' ? width : Number.parseFloat(width);
226
+ if (!Number.isFinite(numericWidth)) return undefined;
227
+ total += numericWidth;
176
228
  hasAnyWidth = true;
177
229
  }
178
230
 
@@ -182,16 +234,37 @@
182
234
  const managedTableWidth = $derived.by(() => {
183
235
  void $widthVersion;
184
236
  void $layoutVersion;
185
- if (!hasResizable) return undefined;
186
- const widths = ctx.getVisibleColumnWidths();
237
+ const widths = ctx.getResolvedVisibleColumnWidths();
187
238
  const columnCount = ctx.getVisibleColumnCount();
188
239
  if (widths.size === 0 || widths.size < columnCount) return undefined;
240
+ if (ctx.hasRelativeVisibleColumnWidths()) return undefined;
189
241
  let total = 0;
190
242
  for (const w of widths.values()) total += w;
191
243
  return total;
192
244
  });
193
245
 
194
- const resolvedTableWidth = $derived(managedTableWidth ?? explicitManagedTableWidth);
246
+ const relativeResolvedTableWidth = $derived.by(() => {
247
+ void $widthVersion;
248
+ void $layoutVersion;
249
+ if (!ctx.hasRelativeVisibleColumnWidths()) return undefined;
250
+
251
+ const widths = ctx.getResolvedVisibleColumnWidths();
252
+ const columnCount = ctx.getVisibleColumnCount();
253
+ if (widths.size === 0 || widths.size < columnCount) return undefined;
254
+
255
+ let total = 0;
256
+ for (const w of widths.values()) total += w;
257
+ return total;
258
+ });
259
+
260
+ const fallbackRelativeTableWidth = $derived.by(() => {
261
+ void $layoutVersion;
262
+ return ctx.hasRelativeVisibleColumnWidths() ? '100%' : undefined;
263
+ });
264
+
265
+ const resolvedTableWidth = $derived(
266
+ managedTableWidth ?? explicitManagedTableWidth ?? relativeResolvedTableWidth
267
+ );
195
268
 
196
269
  context = ctx;
197
270
 
@@ -368,8 +441,13 @@
368
441
  bind:this={tableElement}
369
442
  role="grid"
370
443
  class={className}
371
- style:table-layout={hasResizable || resolvedTableWidth !== undefined ? 'fixed' : undefined}
372
- style:width={resolvedTableWidth !== undefined ? `${resolvedTableWidth}px` : undefined}
444
+ style:--table-visible-column-count={ariaColCount ? `${ariaColCount}` : undefined}
445
+ style:table-layout={hasResizable || hasDefinedColumnWidths || resolvedTableWidth !== undefined
446
+ ? 'fixed'
447
+ : undefined}
448
+ style:width={resolvedTableWidth !== undefined
449
+ ? `${resolvedTableWidth}px`
450
+ : fallbackRelativeTableWidth}
373
451
  style:min-width={resolvedTableWidth !== undefined ? '0' : undefined}
374
452
  aria-label={ariaLabel}
375
453
  aria-labelledby={ariaLabelledby}
@@ -387,21 +465,42 @@
387
465
  onkeydown={handleKeyDown}
388
466
  {...restProps}
389
467
  >
468
+ {#if layoutColumns.length > 0}
469
+ <colgroup>
470
+ {#each layoutColumns as column (column.id)}
471
+ <col
472
+ data-table-implicit-width={column.implicitWidth ? 'true' : undefined}
473
+ style:width={column.widthStyle}
474
+ style:min-width={column.minWidth !== undefined ? `${column.minWidth}px` : undefined}
475
+ style:max-width={column.maxWidth !== undefined ? `${column.maxWidth}px` : undefined}
476
+ />
477
+ {/each}
478
+ </colgroup>
479
+ {/if}
480
+
390
481
  {#if children}
391
482
  {@render children()}
392
483
  {/if}
393
484
  </table>
394
485
 
395
- <span
396
- role="status"
397
- aria-live="polite"
398
- aria-atomic="true"
399
- style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;"
486
+ <span role="status" aria-live="polite" aria-atomic="true" style={visuallyHiddenStyle}
400
487
  >{sortAnnouncement}</span
401
488
  >
402
489
 
403
- <span
404
- id={ctx.selectionUnavailableDescriptionId}
405
- style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;"
490
+ <span id={ctx.selectionUnavailableDescriptionId} style={visuallyHiddenStyle}
406
491
  >Selection unavailable for this row.</span
407
492
  >
493
+
494
+ <style>
495
+ :global(table[role='grid']:has([data-table-column-resizer='true'])) {
496
+ table-layout: fixed;
497
+ width: 100%;
498
+ min-width: 0;
499
+ }
500
+
501
+ :global(
502
+ table[role='grid']:has([data-table-column-resizer='true']) col[data-table-implicit-width='true']
503
+ ) {
504
+ width: calc(100% / var(--table-visible-column-count, 1));
505
+ }
506
+ </style>
@@ -35,16 +35,16 @@ export type TableRootProps = Omit<HTMLAttributes<HTMLTableElement>, 'children'>
35
35
  defaultSelectedKeys?: Iterable<TableSelectionKey>;
36
36
  sortDescriptor?: TableSortDescriptor;
37
37
  defaultSortDescriptor?: TableSortDescriptor;
38
- columnWidths?: Map<string, number>;
39
- defaultColumnWidths?: Iterable<readonly [string, number]>;
38
+ columnWidths?: Map<string, TableColumnWidth>;
39
+ defaultColumnWidths?: Iterable<readonly [string, TableColumnWidth]>;
40
40
  disabledKeys?: Iterable<TableSelectionKey>;
41
41
  onRowAction?: TableRowActionHandler;
42
42
  onSelectionChange?: (keys: Set<TableSelectionKey>) => void;
43
43
  onSortChange?: (descriptor: TableSortDescriptor | undefined) => void;
44
- onColumnWidthsChange?: (widths: Map<string, number>) => void;
44
+ onColumnWidthsChange?: (widths: Map<string, TableColumnWidth>) => void;
45
45
  onHiddenColumnsChange?: (columnIds: string[]) => void;
46
46
  onColumnResizeStart?: (columnId: string) => void;
47
- onColumnResizeEnd?: (widths: Map<string, number>) => void;
47
+ onColumnResizeEnd?: (widths: Map<string, TableColumnWidth>) => void;
48
48
  children?: Snippet;
49
49
  class?: string;
50
50
  context?: TableContext;
@@ -0,0 +1 @@
1
+ export declare const visuallyHiddenStyle = "position:fixed;top:0;left:0;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;";
@@ -0,0 +1 @@
1
+ export const visuallyHiddenStyle = 'position:fixed;top:0;left:0;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@human-kit/svelte-components",
3
- "version": "1.0.0-alpha.15",
3
+ "version": "1.0.0-alpha.17",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "svelte": "./dist/index.js",