@x33025/sveltely 0.1.24 → 0.1.25

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 (71) hide show
  1. package/dist/actions/LoaderOverlay.svelte +10 -3
  2. package/dist/components/Library/Accordion/Accordion.demo.svelte +21 -0
  3. package/dist/components/Library/Accordion/Accordion.demo.svelte.d.ts +9 -0
  4. package/dist/components/Library/Accordion/Accordion.svelte +78 -0
  5. package/dist/components/Library/Accordion/Accordion.svelte.d.ts +14 -0
  6. package/dist/components/Library/Accordion/Content.svelte +57 -0
  7. package/dist/components/Library/Accordion/Content.svelte.d.ts +8 -0
  8. package/dist/components/Library/Accordion/Header.svelte +98 -0
  9. package/dist/components/Library/Accordion/Header.svelte.d.ts +10 -0
  10. package/dist/components/Library/Accordion/context.d.ts +9 -0
  11. package/dist/components/Library/Accordion/context.js +6 -0
  12. package/dist/components/Library/Accordion/index.d.ts +9 -0
  13. package/dist/components/Library/Accordion/index.js +7 -0
  14. package/dist/components/Library/AnimatedNumber/AnimatedNumber.demo.svelte +1 -1
  15. package/dist/components/Library/ArticleEditor/ArticleEditor.svelte +1 -2
  16. package/dist/components/Library/ArticleEditor/Blocks/Table.svelte +1 -1
  17. package/dist/components/Library/ChipInput/ChipInput.demo.svelte +1 -1
  18. package/dist/components/Library/Dropdown/Dropdown.demo.svelte +5 -3
  19. package/dist/components/Library/Grid/Grid.demo.svelte +58 -0
  20. package/dist/components/Library/Grid/Grid.demo.svelte.d.ts +25 -0
  21. package/dist/components/Library/Grid/Grid.svelte +120 -26
  22. package/dist/components/Library/Grid/Grid.svelte.d.ts +38 -10
  23. package/dist/components/Library/Grid/GridItem.svelte +8 -13
  24. package/dist/components/Library/ImageMask/ImageMask.demo.svelte +1 -1
  25. package/dist/components/Library/Label/Label.demo.svelte +1 -1
  26. package/dist/components/Library/Label/Label.svelte +5 -13
  27. package/dist/components/Library/Notifications/Notifications.demo.svelte +63 -0
  28. package/dist/components/Library/Notifications/Notifications.demo.svelte.d.ts +9 -0
  29. package/dist/components/Library/Notifications/Notifications.svelte +155 -0
  30. package/dist/components/Library/Notifications/Notifications.svelte.d.ts +35 -0
  31. package/dist/components/Library/Notifications/index.d.ts +2 -0
  32. package/dist/components/Library/Notifications/index.js +1 -0
  33. package/dist/components/Library/Notifications/types.d.ts +8 -0
  34. package/dist/components/Library/Notifications/types.js +1 -0
  35. package/dist/components/Library/NumberField/NumberField.svelte +25 -19
  36. package/dist/components/Library/Pagination/Pagination.svelte +6 -18
  37. package/dist/components/Library/ScrollView/ScrollView.svelte +76 -4
  38. package/dist/components/Library/ScrollView/ScrollView.svelte.d.ts +9 -2
  39. package/dist/components/Library/ScrollView/index.d.ts +1 -1
  40. package/dist/components/Library/SearchField/SearchField.demo.svelte +1 -1
  41. package/dist/components/Library/SegmentedPicker/SegmentedPicker.demo.svelte +1 -1
  42. package/dist/components/Library/Slider/Slider.demo.svelte +1 -1
  43. package/dist/components/Library/Table/Table.demo.svelte +9 -1
  44. package/dist/components/Library/Table/Table.svelte +315 -112
  45. package/dist/components/Library/Table/Table.svelte.d.ts +7 -1
  46. package/dist/components/Library/TextField/TextField.svelte +20 -14
  47. package/dist/components/Library/TokenSearchField/TokenSearchField.demo.svelte +1 -1
  48. package/dist/components/Local/ColorStyleControls.svelte +25 -64
  49. package/dist/components/Local/ComponentGrid.svelte +103 -22
  50. package/dist/components/Local/ComponentGrid.svelte.d.ts +2 -1
  51. package/dist/components/Local/ComponentPage.svelte +74 -0
  52. package/dist/components/Local/ComponentPage.svelte.d.ts +13 -0
  53. package/dist/components/Local/HeroCard.svelte +10 -5
  54. package/dist/components/Local/LayoutStyleControls.svelte +6 -6
  55. package/dist/index.d.ts +8 -3
  56. package/dist/index.js +4 -1
  57. package/dist/style/index.css +1 -2
  58. package/dist/style/layout.d.ts +11 -26
  59. package/dist/style/layout.js +31 -53
  60. package/dist/style.css +4 -1
  61. package/dist/viewport/geometry.d.ts +8 -0
  62. package/dist/viewport/geometry.js +43 -0
  63. package/dist/viewport/index.d.ts +4 -0
  64. package/dist/viewport/index.js +4 -0
  65. package/dist/viewport/layout.d.ts +4 -0
  66. package/dist/viewport/layout.js +138 -0
  67. package/dist/viewport/placement.d.ts +4 -0
  68. package/dist/viewport/placement.js +14 -0
  69. package/dist/viewport/types.d.ts +81 -0
  70. package/dist/viewport/types.js +1 -0
  71. package/package.json +1 -1
@@ -8,6 +8,7 @@
8
8
  import { extractLoaderProps, resolveLoaderOptions, type LoaderProps } from '../../../style/loader';
9
9
  import { extractLayoutProps, layoutStyle, type LayoutProps } from '../../../style/layout';
10
10
  import { extractStyleProps, surfaceStyle, type StyleProps } from '../../../style/surface';
11
+ import { tableViewportLayout, type ViewportGeometry, type ViewportOverscan } from '../../../viewport';
11
12
  import ScrollView from '../ScrollView';
12
13
  import { TABLE_CONTEXT } from './context';
13
14
  import type {
@@ -31,6 +32,10 @@
31
32
  columnHeaders?: TableColumnHeaderVisibility;
32
33
  columnCustomization?: TableColumnCustomization;
33
34
  emptyLabel?: string;
35
+ virtualized?: boolean;
36
+ rowHeight?: number;
37
+ headerHeight?: number;
38
+ overscan?: ViewportOverscan;
34
39
  onSortOrderChange?: (sortOrder: TableSortDescriptor<T>[]) => void;
35
40
  onSelectionChange?: (selection: TableSelection) => void;
36
41
  } & LayoutProps &
@@ -48,6 +53,10 @@
48
53
  columnHeaders = 'visible',
49
54
  columnCustomization = $bindable<TableColumnCustomization>({}),
50
55
  emptyLabel = 'No rows',
56
+ virtualized = false,
57
+ rowHeight = 42,
58
+ headerHeight = 38,
59
+ overscan = 160,
51
60
  onSortOrderChange,
52
61
  onSelectionChange,
53
62
  ...restProps
@@ -55,6 +64,10 @@
55
64
 
56
65
  let tableSortOrder = $state<TableSortDescriptor<T>[]>(sortOrder);
57
66
  let scrollOffsetX = $state(0);
67
+ let viewport = $state<ViewportGeometry>({
68
+ offset: { x: 0, y: 0 },
69
+ viewport: { width: 0, height: 0 }
70
+ });
58
71
  let dragSelection = $state<{
59
72
  active: boolean;
60
73
  pointerId: number;
@@ -89,12 +102,7 @@
89
102
  typeof value === 'number' ? `${value}px` : value;
90
103
 
91
104
  const tableShellStyle = $derived.by(() => {
92
- return [
93
- layoutStyle(layoutProps),
94
- rootStyle
95
- ]
96
- .filter(Boolean)
97
- .join(' ');
105
+ return [layoutStyle(layoutProps), rootStyle].filter(Boolean).join(' ');
98
106
  });
99
107
 
100
108
  const headerSpan = (value: TableColumn<T>['colspan'] | TableColumn<T>['rowspan']) =>
@@ -221,7 +229,6 @@
221
229
  const headerStyle = $derived(
222
230
  `${tableWidthStyle} transform: translate3d(${-scrollOffsetX}px, 0, 0);`
223
231
  );
224
-
225
232
  const sortedRows = $derived.by(() => {
226
233
  if (tableSortOrder.length === 0) return data;
227
234
 
@@ -250,6 +257,32 @@
250
257
  return 0;
251
258
  });
252
259
  });
260
+ const engineColumns = $derived.by(() =>
261
+ visibleColumns.map((column, index) => ({
262
+ key: String(columnKey(column, index)),
263
+ width:
264
+ typeof column.width === 'number'
265
+ ? column.width
266
+ : typeof column.minWidth === 'number'
267
+ ? column.minWidth
268
+ : 160
269
+ }))
270
+ );
271
+ const engineLayout = $derived.by(() =>
272
+ tableViewportLayout({
273
+ rows: sortedRows,
274
+ columns: engineColumns,
275
+ viewport,
276
+ rowHeight,
277
+ headerHeight: 0,
278
+ overscan,
279
+ rowKey
280
+ })
281
+ );
282
+ const engineHeaderStyle = $derived.by(() => {
283
+ const width = `${engineLayout.content.width}px`;
284
+ return `width: ${width}; min-width: ${width}; height: ${headerHeight}px; transform: translate3d(${-scrollOffsetX}px, 0, 0);`;
285
+ });
253
286
 
254
287
  const selectedKeys = $derived.by(() => {
255
288
  if (selection instanceof Set) return new Set<TableRowKey>(selection);
@@ -399,7 +432,8 @@
399
432
  updateSelection(key);
400
433
  };
401
434
 
402
- const handleScroll = (geometry: { offset: { x: number } }) => {
435
+ const handleScroll = (geometry: ViewportGeometry) => {
436
+ viewport = geometry;
403
437
  scrollOffsetX = geometry.offset.x;
404
438
  };
405
439
  </script>
@@ -414,122 +448,243 @@
414
448
  onpointercancel={endDragSelection}
415
449
  />
416
450
 
417
- <div class="table-shell" style={tableShellStyle} {...forwardedProps}>
451
+ <div
452
+ class="table-shell"
453
+ class:table-shell-engine={virtualized}
454
+ style={tableShellStyle}
455
+ {...forwardedProps}
456
+ >
418
457
  {#if columnHeaders === 'visible'}
419
458
  <div class="table-header-frame">
420
- <table
421
- class="table-header-table table"
422
- style={headerStyle}
423
- role={selectionMode === 'none' ? undefined : 'grid'}
424
- aria-multiselectable={selectionMode === 'multiple' ? 'true' : undefined}
425
- >
426
- <thead class="table-header">
427
- <tr>
428
- {#each visibleColumns as column, index (columnKey(column, index))}
429
- <th
430
- class={`table-heading table-align-${column.alignment ?? 'leading'}`}
431
- colspan={headerSpan(column.colspan)}
432
- rowspan={headerSpan(column.rowspan)}
433
- style:min-width={toCssSize(column.minWidth)}
434
- style:width={toCssSize(column.width)}
435
- aria-sort={tableSortOrder[0]?.key === columnSortKey(column, index)
436
- ? tableSortOrder[0].direction === 'ascending'
437
- ? 'ascending'
438
- : 'descending'
439
- : undefined}
440
- >
441
- {#if column.sortable}
442
- {@const sortDirection = activeSortDirection(column, index)}
443
- <button
444
- type="button"
445
- class="table-sort-button"
446
- onclick={() => updateSort(column, index)}
447
- >
448
- <span>
449
- {#if column.header}
450
- {@render column.header(column, index)}
451
- {:else}
452
- {column.label}
453
- {/if}
454
- </span>
455
- {#if sortDirection === 'ascending'}
456
- <ArrowUpIcon class="table-sort-icon" size={12} strokeWidth={2.25} />
457
- {:else if sortDirection === 'descending'}
458
- <ArrowDownIcon class="table-sort-icon" size={12} strokeWidth={2.25} />
459
+ {#if virtualized}
460
+ <div
461
+ class="table-header-table table-engine-header"
462
+ style={engineHeaderStyle}
463
+ role={selectionMode === 'none' ? undefined : 'row'}
464
+ >
465
+ {#each visibleColumns as column, index (columnKey(column, index))}
466
+ {@const layoutColumn = engineColumns[index]}
467
+ <div
468
+ class={`table-heading table-engine-heading table-align-${column.alignment ?? 'leading'}`}
469
+ style:width={`${layoutColumn.width}px`}
470
+ style:height={`${headerHeight}px`}
471
+ role={selectionMode === 'none' ? 'columnheader' : 'gridcell'}
472
+ aria-sort={tableSortOrder[0]?.key === columnSortKey(column, index)
473
+ ? tableSortOrder[0].direction === 'ascending'
474
+ ? 'ascending'
475
+ : 'descending'
476
+ : undefined}
477
+ >
478
+ {#if column.sortable}
479
+ {@const sortDirection = activeSortDirection(column, index)}
480
+ <button
481
+ type="button"
482
+ class="table-sort-button"
483
+ onclick={() => updateSort(column, index)}
484
+ >
485
+ <span>
486
+ {#if column.header}
487
+ {@render column.header(column, index)}
459
488
  {:else}
460
- <ArrowUpDownIcon
461
- class="table-sort-icon table-sort-icon-muted"
462
- size={12}
463
- strokeWidth={2.25}
464
- />
489
+ {column.label}
465
490
  {/if}
466
- </button>
467
- {:else}
468
- {#if column.header}
491
+ </span>
492
+ {#if sortDirection === 'ascending'}
493
+ <ArrowUpIcon class="table-sort-icon" size={12} strokeWidth={2.25} />
494
+ {:else if sortDirection === 'descending'}
495
+ <ArrowDownIcon class="table-sort-icon" size={12} strokeWidth={2.25} />
496
+ {:else}
497
+ <ArrowUpDownIcon
498
+ class="table-sort-icon table-sort-icon-muted"
499
+ size={12}
500
+ strokeWidth={2.25}
501
+ />
502
+ {/if}
503
+ </button>
504
+ {:else if column.header}
505
+ {@render column.header(column, index)}
506
+ {:else}
507
+ {column.label}
508
+ {/if}
509
+ </div>
510
+ {/each}
511
+ </div>
512
+ {:else}
513
+ <table
514
+ class="table-header-table table"
515
+ style={headerStyle}
516
+ role={selectionMode === 'none' ? undefined : 'grid'}
517
+ aria-multiselectable={selectionMode === 'multiple' ? 'true' : undefined}
518
+ >
519
+ <thead class="table-header">
520
+ <tr>
521
+ {#each visibleColumns as column, index (columnKey(column, index))}
522
+ <th
523
+ class={`table-heading table-align-${column.alignment ?? 'leading'}`}
524
+ colspan={headerSpan(column.colspan)}
525
+ rowspan={headerSpan(column.rowspan)}
526
+ style:min-width={toCssSize(column.minWidth)}
527
+ style:width={toCssSize(column.width)}
528
+ aria-sort={tableSortOrder[0]?.key === columnSortKey(column, index)
529
+ ? tableSortOrder[0].direction === 'ascending'
530
+ ? 'ascending'
531
+ : 'descending'
532
+ : undefined}
533
+ >
534
+ {#if column.sortable}
535
+ {@const sortDirection = activeSortDirection(column, index)}
536
+ <button
537
+ type="button"
538
+ class="table-sort-button"
539
+ onclick={() => updateSort(column, index)}
540
+ >
541
+ <span>
542
+ {#if column.header}
543
+ {@render column.header(column, index)}
544
+ {:else}
545
+ {column.label}
546
+ {/if}
547
+ </span>
548
+ {#if sortDirection === 'ascending'}
549
+ <ArrowUpIcon class="table-sort-icon" size={12} strokeWidth={2.25} />
550
+ {:else if sortDirection === 'descending'}
551
+ <ArrowDownIcon class="table-sort-icon" size={12} strokeWidth={2.25} />
552
+ {:else}
553
+ <ArrowUpDownIcon
554
+ class="table-sort-icon table-sort-icon-muted"
555
+ size={12}
556
+ strokeWidth={2.25}
557
+ />
558
+ {/if}
559
+ </button>
560
+ {:else if column.header}
469
561
  {@render column.header(column, index)}
470
562
  {:else}
471
563
  {column.label}
472
564
  {/if}
473
- {/if}
474
- </th>
475
- {/each}
476
- </tr>
477
- </thead>
478
- </table>
565
+ </th>
566
+ {/each}
567
+ </tr>
568
+ </thead>
569
+ </table>
570
+ {/if}
479
571
  </div>
480
572
  {/if}
481
573
 
482
- <ScrollView
483
- axis="both"
484
- loader={bodyLoaderOptions}
485
- contentStyles={{ paddingX: 0, paddingY: 0 }}
486
- onScroll={handleScroll}
487
- >
488
- <table
489
- class="table-body-table table"
490
- style={tableWidthStyle}
491
- role={selectionMode === 'none' ? undefined : 'grid'}
492
- aria-multiselectable={selectionMode === 'multiple' ? 'true' : undefined}
574
+ {#if virtualized}
575
+ {#snippet layout()}
576
+ {#each engineLayout.rows as placedRow (placedRow.key)}
577
+ {@const key = rowKey(placedRow.item, placedRow.index)}
578
+ <div
579
+ data-table-row-key={String(key)}
580
+ class="table-engine-row table-row"
581
+ class:table-row-selectable={selectionMode !== 'none'}
582
+ class:table-row-selected={isSelected(key)}
583
+ style:width={`${placedRow.rect.width}px`}
584
+ style:height={`${placedRow.rect.height}px`}
585
+ style:transform={`translate3d(${placedRow.rect.x}px, ${placedRow.rect.y}px, 0)`}
586
+ aria-selected={selectionMode === 'none' ? undefined : isSelected(key)}
587
+ role={selectionMode === 'none' ? 'row' : 'row'}
588
+ onclick={(event) => handleRowClick(event, key)}
589
+ onpointerdown={(event) => startDragSelection(event, key)}
590
+ onpointerenter={(event) => continueDragSelection(event, key)}
591
+ onpointerup={endDragSelection}
592
+ onpointercancel={endDragSelection}
593
+ ></div>
594
+ {/each}
595
+ {#each engineLayout.cells as placedCell (placedCell.key)}
596
+ {@const column = visibleColumns[placedCell.item.columnIndex]}
597
+ {@const row = placedCell.item.row}
598
+ {@const index = placedCell.item.rowIndex}
599
+ {@const key = rowKey(row, index)}
600
+ <div
601
+ data-table-row-key={String(key)}
602
+ class={`table-engine-cell table-cell table-align-${column.alignment ?? 'leading'}`}
603
+ class:table-row-selectable={selectionMode !== 'none'}
604
+ style:width={`${placedCell.rect.width}px`}
605
+ style:height={`${placedCell.rect.height}px`}
606
+ style:transform={`translate3d(${placedCell.rect.x}px, ${placedCell.rect.y}px, 0)`}
607
+ aria-selected={selectionMode === 'none' ? undefined : isSelected(key)}
608
+ role={selectionMode === 'none' ? 'cell' : 'gridcell'}
609
+ onclick={(event) => handleRowClick(event, key)}
610
+ onpointerdown={(event) => startDragSelection(event, key)}
611
+ onpointerenter={(event) => continueDragSelection(event, key)}
612
+ onpointerup={endDragSelection}
613
+ onpointercancel={endDragSelection}
614
+ >
615
+ {#if column.cell}
616
+ {@render column.cell(row, index)}
617
+ {:else}
618
+ {displayValue(columnValue(column, row))}
619
+ {/if}
620
+ </div>
621
+ {/each}
622
+ {#if sortedRows.length === 0}
623
+ <div class="table-empty table-engine-empty">{emptyLabel}</div>
624
+ {/if}
625
+ {/snippet}
626
+
627
+ <ScrollView
628
+ axis="both"
629
+ loader={bodyLoaderOptions}
630
+ contentSize={engineLayout.content}
631
+ contentStyles={{ paddingX: 0, paddingY: 0 }}
632
+ onScroll={handleScroll}
633
+ {layout}
634
+ />
635
+ {:else}
636
+ <ScrollView
637
+ axis="both"
638
+ loader={bodyLoaderOptions}
639
+ contentStyles={{ paddingX: 0, paddingY: 0 }}
640
+ onScroll={handleScroll}
493
641
  >
494
- <tbody>
495
- {#each sortedRows as row, index (rowKey(row, index))}
496
- {@const key = rowKey(row, index)}
497
- <tr
498
- data-table-row-key={String(key)}
499
- class="table-row"
500
- class:table-row-selectable={selectionMode !== 'none'}
501
- class:table-row-selected={isSelected(key)}
502
- aria-selected={selectionMode === 'none' ? undefined : isSelected(key)}
503
- onclick={(event) => handleRowClick(event, key)}
504
- onpointerdown={(event) => startDragSelection(event, key)}
505
- onpointerenter={(event) => continueDragSelection(event, key)}
506
- onpointerup={endDragSelection}
507
- onpointercancel={endDragSelection}
508
- >
509
- {#each visibleColumns as column, columnIndex (columnKey(column, columnIndex))}
510
- <td
511
- class={`table-cell table-align-${column.alignment ?? 'leading'}`}
512
- colspan={bodySpan(column.colspan, row, index)}
513
- rowspan={bodySpan(column.rowspan, row, index)}
514
- style:min-width={toCssSize(column.minWidth)}
515
- style:width={toCssSize(column.width)}
516
- >
517
- {#if column.cell}
518
- {@render column.cell(row, index)}
519
- {:else}
520
- {displayValue(columnValue(column, row))}
521
- {/if}
522
- </td>
523
- {/each}
524
- </tr>
525
- {:else}
526
- <tr>
527
- <td class="table-empty" colspan={Math.max(visibleColumns.length, 1)}>{emptyLabel}</td>
528
- </tr>
529
- {/each}
530
- </tbody>
531
- </table>
532
- </ScrollView>
642
+ <table
643
+ class="table-body-table table"
644
+ style={tableWidthStyle}
645
+ role={selectionMode === 'none' ? undefined : 'grid'}
646
+ aria-multiselectable={selectionMode === 'multiple' ? 'true' : undefined}
647
+ >
648
+ <tbody>
649
+ {#each sortedRows as row, index (rowKey(row, index))}
650
+ {@const key = rowKey(row, index)}
651
+ <tr
652
+ data-table-row-key={String(key)}
653
+ class="table-row"
654
+ class:table-row-selectable={selectionMode !== 'none'}
655
+ class:table-row-selected={isSelected(key)}
656
+ aria-selected={selectionMode === 'none' ? undefined : isSelected(key)}
657
+ onclick={(event) => handleRowClick(event, key)}
658
+ onpointerdown={(event) => startDragSelection(event, key)}
659
+ onpointerenter={(event) => continueDragSelection(event, key)}
660
+ onpointerup={endDragSelection}
661
+ onpointercancel={endDragSelection}
662
+ >
663
+ {#each visibleColumns as column, columnIndex (columnKey(column, columnIndex))}
664
+ <td
665
+ class={`table-cell table-align-${column.alignment ?? 'leading'}`}
666
+ colspan={bodySpan(column.colspan, row, index)}
667
+ rowspan={bodySpan(column.rowspan, row, index)}
668
+ style:min-width={toCssSize(column.minWidth)}
669
+ style:width={toCssSize(column.width)}
670
+ >
671
+ {#if column.cell}
672
+ {@render column.cell(row, index)}
673
+ {:else}
674
+ {displayValue(columnValue(column, row))}
675
+ {/if}
676
+ </td>
677
+ {/each}
678
+ </tr>
679
+ {:else}
680
+ <tr>
681
+ <td class="table-empty" colspan={Math.max(visibleColumns.length, 1)}>{emptyLabel}</td>
682
+ </tr>
683
+ {/each}
684
+ </tbody>
685
+ </table>
686
+ </ScrollView>
687
+ {/if}
533
688
  </div>
534
689
 
535
690
  <style>
@@ -581,6 +736,15 @@
581
736
  will-change: transform;
582
737
  }
583
738
 
739
+ .table-engine-header {
740
+ display: flex;
741
+ background: color-mix(
742
+ in oklab,
743
+ var(--sveltely-background-color) 92%,
744
+ var(--sveltely-control-active-color)
745
+ );
746
+ }
747
+
584
748
  .table-header-frame + :global(.scroll-view) {
585
749
  border-top-left-radius: 0;
586
750
  border-top-right-radius: 0;
@@ -612,6 +776,45 @@
612
776
  color: inherit;
613
777
  }
614
778
 
779
+ .table-engine-heading,
780
+ .table-engine-cell {
781
+ display: flex;
782
+ align-items: center;
783
+ min-width: 0;
784
+ overflow: hidden;
785
+ text-overflow: ellipsis;
786
+ }
787
+
788
+ .table-engine-cell {
789
+ position: absolute;
790
+ left: 0;
791
+ top: 0;
792
+ z-index: 1;
793
+ background: transparent;
794
+ }
795
+
796
+ .table-engine-row {
797
+ position: absolute;
798
+ left: 0;
799
+ top: 0;
800
+ z-index: 0;
801
+ border-bottom: 1px solid var(--sveltely-border-color);
802
+ }
803
+
804
+ .table-engine-row.table-row-selectable {
805
+ cursor: default;
806
+ }
807
+
808
+ .table-engine-row.table-row-selectable:hover {
809
+ background: color-mix(in oklab, var(--sveltely-control-active-color) 8%, transparent);
810
+ }
811
+
812
+ .table-engine-empty {
813
+ position: absolute;
814
+ inset: 0 auto auto 0;
815
+ width: 100%;
816
+ }
817
+
615
818
  .table-row:last-child .table-cell {
616
819
  border-bottom: 0;
617
820
  }
@@ -1,7 +1,9 @@
1
1
  export { default as Column } from './Column.svelte';
2
2
  import { type Snippet } from 'svelte';
3
3
  import { type LoaderProps } from '../../../style/loader';
4
+ import { type LayoutProps } from '../../../style/layout';
4
5
  import { type StyleProps } from '../../../style/surface';
6
+ import { type ViewportOverscan } from '../../../viewport';
5
7
  import type { TableColumn, TableColumnCustomization, TableColumnHeaderVisibility, TableSelection, TableSelectionMode, TableSortDescriptor } from './types';
6
8
  declare function $$render<T extends Record<string, unknown>>(): {
7
9
  props: {
@@ -14,9 +16,13 @@ declare function $$render<T extends Record<string, unknown>>(): {
14
16
  columnHeaders?: TableColumnHeaderVisibility;
15
17
  columnCustomization?: TableColumnCustomization;
16
18
  emptyLabel?: string;
19
+ virtualized?: boolean;
20
+ rowHeight?: number;
21
+ headerHeight?: number;
22
+ overscan?: ViewportOverscan;
17
23
  onSortOrderChange?: (sortOrder: TableSortDescriptor<T>[]) => void;
18
24
  onSelectionChange?: (selection: TableSelection) => void;
19
- } & import("../../../style/layout").FrameProps & import("../../../style/layout").StackProps & StyleProps & LoaderProps & Record<string, unknown>;
25
+ } & LayoutProps & StyleProps & LoaderProps & Record<string, unknown>;
20
26
  exports: {};
21
27
  bindings: "selection" | "sortOrder" | "columnCustomization";
22
28
  slots: {};
@@ -76,20 +76,22 @@
76
76
  data-disabled={disabled ? 'true' : 'false'}
77
77
  data-error={error ? 'true' : 'false'}
78
78
  >
79
- <input
80
- bind:value
81
- {type}
82
- {disabled}
83
- {name}
84
- {autocomplete}
85
- {required}
86
- {readonly}
87
- {inputmode}
88
- {placeholder}
89
- aria-invalid={error ? 'true' : undefined}
90
- aria-describedby={describedBy}
91
- class="text-field-input"
92
- />
79
+ <div class="text-field-control">
80
+ <input
81
+ bind:value
82
+ {type}
83
+ {disabled}
84
+ {name}
85
+ {autocomplete}
86
+ {required}
87
+ {readonly}
88
+ {inputmode}
89
+ {placeholder}
90
+ aria-invalid={error ? 'true' : undefined}
91
+ aria-describedby={describedBy}
92
+ class="text-field-input"
93
+ />
94
+ </div>
93
95
 
94
96
  {#if help}
95
97
  <span id="text-field-message" class="text-field-message">{help}</span>
@@ -107,6 +109,10 @@
107
109
  font-size: var(--text-field-font-size, var(--sveltely-font-size));
108
110
  }
109
111
 
112
+ .text-field-control {
113
+ display: contents;
114
+ }
115
+
110
116
  .text-field-input {
111
117
  width: 100%;
112
118
  min-width: 0;
@@ -14,7 +14,7 @@
14
14
  let value = $state('');
15
15
  </script>
16
16
 
17
- <VStack width="100%" maxWidth="28rem" gap={5}>
17
+ <VStack width="28rem" gap={5}>
18
18
  <TokenSearchField bind:tokens bind:value placeholder="Search keywords" />
19
19
  <p class="text-xs text-[var(--sveltely-text-secondary-color)]">
20
20
  Tokens: {tokens.join(', ') || 'empty'}