@streamscloud/kit 0.17.0 → 0.19.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 (91) hide show
  1. package/dist/ui/badge/cmp.badge.svelte +4 -0
  2. package/dist/ui/badge/cmp.badge.svelte.d.ts +1 -0
  3. package/dist/ui/page-toolbar/cmp.reorderable-checkbox-list.svelte +131 -0
  4. package/dist/ui/page-toolbar/cmp.reorderable-checkbox-list.svelte.d.ts +31 -0
  5. package/dist/ui/page-toolbar/cmp.toolbar-checkbox.svelte +14 -0
  6. package/dist/ui/page-toolbar/cmp.toolbar-checkbox.svelte.d.ts +19 -0
  7. package/dist/ui/page-toolbar/cmp.toolbar-divider.svelte +19 -0
  8. package/dist/ui/page-toolbar/cmp.toolbar-divider.svelte.d.ts +35 -0
  9. package/dist/ui/page-toolbar/cmp.toolbar-filter-select.svelte +143 -0
  10. package/dist/ui/page-toolbar/cmp.toolbar-filter-select.svelte.d.ts +68 -0
  11. package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte +71 -0
  12. package/dist/ui/page-toolbar/cmp.toolbar-icon-button.svelte.d.ts +32 -0
  13. package/dist/ui/page-toolbar/cmp.toolbar-option.svelte +189 -0
  14. package/dist/ui/page-toolbar/cmp.toolbar-option.svelte.d.ts +47 -0
  15. package/dist/ui/page-toolbar/cmp.toolbar-popover.svelte +23 -8
  16. package/dist/ui/page-toolbar/cmp.toolbar-popover.svelte.d.ts +14 -6
  17. package/dist/ui/page-toolbar/cmp.toolbar-section-title.svelte +46 -0
  18. package/dist/ui/page-toolbar/cmp.toolbar-section-title.svelte.d.ts +24 -0
  19. package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte +31 -0
  20. package/dist/ui/page-toolbar/cmp.toolbar-sort-select.svelte.d.ts +44 -0
  21. package/dist/ui/page-toolbar/{cmp.toolbar-switch-item.svelte → cmp.toolbar-switch.svelte} +10 -10
  22. package/dist/ui/page-toolbar/{cmp.toolbar-switch-item.svelte.d.ts → cmp.toolbar-switch.svelte.d.ts} +2 -2
  23. package/dist/ui/page-toolbar/cmp.toolbar-toggle.svelte +14 -0
  24. package/dist/ui/page-toolbar/cmp.toolbar-toggle.svelte.d.ts +19 -0
  25. package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte +51 -0
  26. package/dist/ui/page-toolbar/cmp.toolbar-view-controls.svelte.d.ts +27 -0
  27. package/dist/ui/page-toolbar/index.d.ts +12 -7
  28. package/dist/ui/page-toolbar/index.js +11 -6
  29. package/dist/ui/page-toolbar/reorderable-checkbox-list-localization.d.ts +5 -0
  30. package/dist/ui/page-toolbar/reorderable-checkbox-list-localization.js +17 -0
  31. package/dist/ui/page-toolbar/toolbar-filter-select-localization.d.ts +5 -0
  32. package/dist/ui/page-toolbar/toolbar-filter-select-localization.js +20 -0
  33. package/dist/ui/page-toolbar/toolbar-sort-select-localization.d.ts +3 -0
  34. package/dist/ui/page-toolbar/toolbar-sort-select-localization.js +9 -0
  35. package/dist/ui/page-toolbar/toolbar-view-controls-localization.d.ts +5 -0
  36. package/dist/ui/page-toolbar/toolbar-view-controls-localization.js +17 -0
  37. package/dist/ui/page-toolbar/types.d.ts +1 -1
  38. package/dist/ui/select/index.d.ts +1 -0
  39. package/dist/ui/select/index.js +1 -0
  40. package/dist/ui/select/select-listbox.svelte +11 -5
  41. package/dist/ui/select/select-listbox.svelte.d.ts +1 -1
  42. package/dist/ui/table/_table-styles.scss +156 -0
  43. package/dist/ui/table/cmp.table-draggable.svelte +338 -0
  44. package/dist/ui/table/cmp.table-draggable.svelte.d.ts +79 -0
  45. package/dist/ui/table/cmp.table.svelte +96 -265
  46. package/dist/ui/table/cmp.table.svelte.d.ts +16 -8
  47. package/dist/ui/table/index.d.ts +1 -0
  48. package/dist/ui/table/index.js +1 -0
  49. package/dist/ui/table/table-cells/index.d.ts +1 -12
  50. package/dist/ui/table/table-cells/index.js +1 -12
  51. package/dist/ui/table/table-cells/table-cell.svelte +77 -0
  52. package/dist/ui/table/table-cells/{table-select-cell.svelte.d.ts → table-cell.svelte.d.ts} +12 -6
  53. package/dist/ui/table/table-column-models.svelte.d.ts +1 -2
  54. package/dist/ui/table/table-column-models.svelte.js +0 -1
  55. package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte +20 -47
  56. package/dist/ui/table/table-columns-manager/cmp.table-columns-manager.svelte.d.ts +3 -7
  57. package/dist/ui/table/table-columns-manager/table-columns-manager-localization.d.ts +1 -1
  58. package/dist/ui/table/table-columns-manager/table-columns-manager-localization.js +7 -7
  59. package/dist/ui/table/table-localization.d.ts +0 -2
  60. package/dist/ui/table/table-localization.js +0 -14
  61. package/dist/ui/table/table-model.svelte.d.ts +2 -3
  62. package/dist/ui/table/table-model.svelte.js +5 -35
  63. package/dist/ui/table/table-view.svelte.d.ts +14 -0
  64. package/dist/ui/table/table-view.svelte.js +32 -0
  65. package/dist/ui/table/types.d.ts +5 -28
  66. package/dist/ui/toggle/cmp.toggle.svelte +32 -26
  67. package/dist/ui/toggle/cmp.toggle.svelte.d.ts +2 -0
  68. package/dist/ui/tree/cmp.tree-node-view.svelte +16 -10
  69. package/dist/ui/tree/cmp.tree-node-view.svelte.d.ts +2 -2
  70. package/dist/ui/tree/cmp.tree.svelte +14 -30
  71. package/dist/ui/tree/cmp.tree.svelte.d.ts +5 -5
  72. package/dist/ui/tree/tree-keyboard.svelte.d.ts +9 -0
  73. package/dist/ui/tree/tree-keyboard.svelte.js +107 -0
  74. package/dist/ui/tree/tree-node.svelte.d.ts +7 -3
  75. package/dist/ui/tree/tree-node.svelte.js +32 -16
  76. package/package.json +1 -1
  77. package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte +0 -153
  78. package/dist/ui/page-toolbar/cmp.reorderable-toggle-list.svelte.d.ts +0 -20
  79. package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte +0 -19
  80. package/dist/ui/page-toolbar/cmp.toolbar-checkbox-item.svelte.d.ts +0 -12
  81. package/dist/ui/page-toolbar/cmp.toolbar-panel-button.svelte +0 -42
  82. package/dist/ui/page-toolbar/cmp.toolbar-panel-button.svelte.d.ts +0 -20
  83. package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte +0 -57
  84. package/dist/ui/page-toolbar/cmp.toolbar-panel.svelte.d.ts +0 -19
  85. package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte +0 -16
  86. package/dist/ui/page-toolbar/cmp.toolbar-toggle-item.svelte.d.ts +0 -12
  87. package/dist/ui/table/table-cells/table-select-cell.svelte +0 -28
  88. package/dist/ui/table/table-cells/table-text-input-cell.svelte +0 -69
  89. package/dist/ui/table/table-cells/table-text-input-cell.svelte.d.ts +0 -38
  90. package/dist/ui/tree/tree-navigation.svelte.d.ts +0 -14
  91. package/dist/ui/tree/tree-navigation.svelte.js +0 -99
@@ -1,6 +1,6 @@
1
1
  import type { DynamicComponentModel } from '../dynamic-component';
2
2
  import type { IOneOfTableColumn, ITableActionsColumn, TableColumnSortDirection, TableColumnType, WithId } from './types';
3
- export type ColumnDef<T extends WithId> = IOneOfTableColumn<T, keyof T> | ITableActionsColumn;
3
+ export type ColumnDef<T extends WithId> = IOneOfTableColumn<T> | ITableActionsColumn;
4
4
  export type SortableTableColumn = {
5
5
  uniqueId: symbol;
6
6
  title: string;
@@ -17,7 +17,6 @@ export declare class ResolvedColumn<T extends WithId> {
17
17
  readonly def: ColumnDef<T>;
18
18
  readonly uniqueId: symbol;
19
19
  headerView: DynamicComponentModel;
20
- editorColumn: ResolvedColumn<T> | null;
21
20
  hidden: boolean;
22
21
  sortDirection: TableColumnSortDirection;
23
22
  constructor(def: ColumnDef<T>);
@@ -2,7 +2,6 @@ export class ResolvedColumn {
2
2
  def;
3
3
  uniqueId = Symbol();
4
4
  headerView = null;
5
- editorColumn = null;
6
5
  hidden = $state(false);
7
6
  sortDirection = $state('none');
8
7
  constructor(def) {
@@ -1,10 +1,6 @@
1
1
  <script lang="ts" generics="T extends {id: string}">import { LocalStorageItem } from '../../../core/local-storage';
2
- import { Button } from '../../button';
3
- import { IconText } from '../../icon-text';
4
- import { ReorderableToggleList } from '../../page-toolbar';
5
- import { Popover } from '../../popover';
2
+ import { ReorderableCheckboxList, ToolbarPopover } from '../../page-toolbar';
6
3
  import { TableColumnsManagerLocalization } from './table-columns-manager-localization';
7
- import IconChevronDown from '@fluentui/svg-icons/icons/chevron_down_20_regular.svg?raw';
8
4
  import IconColumnTwo from '@fluentui/svg-icons/icons/text_column_two_20_regular.svg?raw';
9
5
  import { untrack } from 'svelte';
10
6
  let { model, localStorageKey, on } = $props();
@@ -16,15 +12,20 @@ const items = $derived(hideableColumns.map((col) => ({
16
12
  label: col.title,
17
13
  enabled: !col.hidden
18
14
  })));
19
- // Load from localStorage once columns are available
20
15
  let initialized = false;
16
+ let standardItems = $state.raw([]);
21
17
  $effect(() => {
22
18
  const columns = hideableColumns;
23
- if (!storage || columns.length === 0 || initialized) {
19
+ if (columns.length === 0 || initialized) {
24
20
  return;
25
21
  }
26
22
  initialized = true;
27
- const saved = storage.get();
23
+ standardItems = columns.map((col) => ({
24
+ id: String(col.id),
25
+ label: col.title,
26
+ enabled: !('hidden' in col.def && col.def.hidden === true)
27
+ }));
28
+ const saved = storage?.get();
28
29
  if (!saved || !Array.isArray(saved)) {
29
30
  return;
30
31
  }
@@ -75,46 +76,18 @@ const handleChange = (updatedItems) => {
75
76
  };
76
77
  </script>
77
78
 
78
- <Popover position="bottom-start" keepOpen>
79
- {#snippet trigger()}
80
- <Button type="presentational" variant="secondary" size="sm">
81
- <IconText icon={{ src: IconColumnTwo, color: 'accent' }} secondaryIcon={IconChevronDown} size="sm" iconScale="large">{localization.columns}</IconText>
82
- </Button>
83
- {/snippet}
84
- <div class="columns-manager">
85
- <div class="columns-manager__title">{localization.selectColumns}</div>
86
- <div class="columns-manager__body">
87
- <ReorderableToggleList items={items} on={{ change: handleChange }} />
88
- </div>
89
- </div>
90
- </Popover>
79
+ <ToolbarPopover triggerLabel={localization.view} icon={{ src: IconColumnTwo, color: 'accent' }}>
80
+ <ReorderableCheckboxList
81
+ items={items}
82
+ title={localization.columns}
83
+ standard={standardItems.length ? standardItems : undefined}
84
+ showClearAll={false}
85
+ on={{ change: handleChange }} />
86
+ </ToolbarPopover>
91
87
 
92
88
  <!--
93
89
  @component
94
- Column visibility and order manager for tables. Shows a popover with a reorderable toggle list for each hideable column.
95
- Supports optional localStorage persistence of column order and visibility.
96
-
97
- ### CSS Custom Properties
98
- | Property | Description | Default |
99
- |---|---|---|
100
- | `--sc-kit--table-columns-manager--title--color` | Title text color | `var(--sc-kit--color--text--primary)` |
90
+ Column visibility and order manager for tables. Opens a `ToolbarPopover` with a `ReorderableCheckboxList`
91
+ of the hideable columns drag to reorder, click to show / hide. Supports optional localStorage persistence
92
+ of column order and visibility.
101
93
  -->
102
-
103
- <style>.columns-manager {
104
- --_columns-manager--title--color: var(--sc-kit--table-columns-manager--title--color, var(--sc-kit--color--text--primary));
105
- width: 21.875rem;
106
- padding: 1.5rem;
107
- }
108
- .columns-manager__title {
109
- font-size: 0.875rem;
110
- font-weight: 600;
111
- line-height: 1.25rem;
112
- color: var(--_columns-manager--title--color);
113
- margin-bottom: 0.5rem;
114
- }
115
- .columns-manager__body {
116
- display: flex;
117
- flex-direction: column;
118
- gap: 1rem;
119
- padding-block: 0.5rem;
120
- }</style>
@@ -41,13 +41,9 @@ interface $$IsomorphicComponent {
41
41
  z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
42
42
  }
43
43
  /**
44
- * Column visibility and order manager for tables. Shows a popover with a reorderable toggle list for each hideable column.
45
- * Supports optional localStorage persistence of column order and visibility.
46
- *
47
- * ### CSS Custom Properties
48
- * | Property | Description | Default |
49
- * |---|---|---|
50
- * | `--sc-kit--table-columns-manager--title--color` | Title text color | `var(--sc-kit--color--text--primary)` |
44
+ * Column visibility and order manager for tables. Opens a `ToolbarPopover` with a `ReorderableCheckboxList`
45
+ * of the hideable columns drag to reorder, click to show / hide. Supports optional localStorage persistence
46
+ * of column order and visibility.
51
47
  */
52
48
  declare const Cmp: $$IsomorphicComponent;
53
49
  type Cmp<T extends {
@@ -1,4 +1,4 @@
1
1
  export declare class TableColumnsManagerLocalization {
2
+ get view(): string;
2
3
  get columns(): string;
3
- get selectColumns(): string;
4
4
  }
@@ -1,19 +1,19 @@
1
1
  import { AppLocale } from '../../../core/locale';
2
2
  export class TableColumnsManagerLocalization {
3
+ get view() {
4
+ return loc.view[AppLocale.current];
5
+ }
3
6
  get columns() {
4
7
  return loc.columns[AppLocale.current];
5
8
  }
6
- get selectColumns() {
7
- return loc.selectColumns[AppLocale.current];
8
- }
9
9
  }
10
10
  const loc = {
11
+ view: {
12
+ en: 'View',
13
+ no: 'Visning'
14
+ },
11
15
  columns: {
12
16
  en: 'Columns',
13
17
  no: 'Kolonner'
14
- },
15
- selectColumns: {
16
- en: 'Select Columns',
17
- no: 'Velg kolonner'
18
18
  }
19
19
  };
@@ -1,6 +1,4 @@
1
1
  export declare class TableLocalization {
2
2
  get noItemsFoundTitle(): string;
3
3
  get noItemsFoundBody(): string;
4
- get save(): string;
5
- get cancel(): string;
6
4
  }
@@ -6,12 +6,6 @@ export class TableLocalization {
6
6
  get noItemsFoundBody() {
7
7
  return loc.noItemsFoundBody[AppLocale.current];
8
8
  }
9
- get save() {
10
- return loc.save[AppLocale.current];
11
- }
12
- get cancel() {
13
- return loc.cancel[AppLocale.current];
14
- }
15
9
  }
16
10
  const loc = {
17
11
  noItemsFoundTitle: {
@@ -21,13 +15,5 @@ const loc = {
21
15
  noItemsFoundBody: {
22
16
  en: 'No data found. Create one to get started',
23
17
  no: 'Ingen data funnet. Opprett en for å komme i gang'
24
- },
25
- save: {
26
- en: 'Save',
27
- no: 'Lagre'
28
- },
29
- cancel: {
30
- en: 'Cancel',
31
- no: 'Avbryt'
32
18
  }
33
19
  };
@@ -20,7 +20,6 @@ export declare class TableModel<T extends WithId> {
20
20
  private _selection;
21
21
  private _preserveSelection;
22
22
  private _dataProvider;
23
- private _editingItem;
24
23
  private _highlightedItemIds;
25
24
  constructor(init: TableModelInit<T>);
26
25
  get items(): T[];
@@ -29,13 +28,13 @@ export declare class TableModel<T extends WithId> {
29
28
  get itemGroupActions(): TableGroupAction<T>[];
30
29
  get styles(): Readonly<TableStyles>;
31
30
  get selection(): Repository<T>;
32
- get editingItem(): T | null;
33
31
  get highlightedItemIds(): string[];
34
32
  set items(value: T[]);
35
33
  set itemActions(value: TableItemAction<T>[]);
36
34
  set columns(value: IAnyTableColumn<T>[]);
37
- set editingItem(value: T | null);
38
35
  set highlightedItemIds(value: string[]);
36
+ /** Reassign items as a pure reorder of the same set — preserves the current selection (unlike the `items` setter). */
37
+ reorderItems: (value: T[]) => void;
39
38
  updateStyles: (styles: Partial<TableStyles>) => void;
40
39
  setResolvedColumns: (columns: ResolvedColumn<T>[]) => void;
41
40
  private reconcileColumns;
@@ -1,6 +1,5 @@
1
1
  import { Css } from '../../core/css';
2
2
  import { createRepository } from '../../core/repository';
3
- import { Utils } from '../../core/utils';
4
3
  import { DynamicComponentModel } from '../dynamic-component';
5
4
  import { ResolvedColumn } from './table-column-models.svelte';
6
5
  import { TableCheckboxHeader, TableHeader, TableHeaderSortable } from './table-headers';
@@ -15,7 +14,6 @@ export class TableModel {
15
14
  _selection;
16
15
  _preserveSelection = false;
17
16
  _dataProvider;
18
- _editingItem = $state(null);
19
17
  _highlightedItemIds = $state.raw([]);
20
18
  constructor(init) {
21
19
  this._init = init;
@@ -64,9 +62,6 @@ export class TableModel {
64
62
  get selection() {
65
63
  return this._selection;
66
64
  }
67
- get editingItem() {
68
- return this._editingItem;
69
- }
70
65
  get highlightedItemIds() {
71
66
  return this._highlightedItemIds;
72
67
  }
@@ -76,9 +71,6 @@ export class TableModel {
76
71
  if (!this._preserveSelection) {
77
72
  this._selection.clear();
78
73
  }
79
- if (this._editingItem && !this._items.find((x) => x.id === this._editingItem?.id)) {
80
- this._editingItem = null;
81
- }
82
74
  }
83
75
  set itemActions(value) {
84
76
  this._itemActions = value;
@@ -86,17 +78,14 @@ export class TableModel {
86
78
  set columns(value) {
87
79
  this.reconcileColumns(value);
88
80
  }
89
- set editingItem(value) {
90
- if (!this._items.find((x) => x.id === value?.id)) {
91
- this._editingItem = null;
92
- }
93
- else {
94
- this._editingItem = structuredClone($state.snapshot(value));
95
- }
96
- }
97
81
  set highlightedItemIds(value) {
98
82
  this._highlightedItemIds = value;
99
83
  }
84
+ /** Reassign items as a pure reorder of the same set — preserves the current selection (unlike the `items` setter). */
85
+ reorderItems = (value) => {
86
+ this._items = value;
87
+ this._dataProvider.set(...value);
88
+ };
100
89
  updateStyles = (styles) => {
101
90
  Object.assign(this._styles, styles);
102
91
  };
@@ -157,22 +146,6 @@ export class TableModel {
157
146
  props: { column: resolved }
158
147
  });
159
148
  };
160
- const resolveEditorColumn = (column) => {
161
- switch (column.type) {
162
- case 'text-input':
163
- case 'select': {
164
- const resolved = new ResolvedColumn(column);
165
- resolved.headerView = new DynamicComponentModel({
166
- component: TableHeader,
167
- props: { column: resolved }
168
- });
169
- return resolved;
170
- }
171
- default: {
172
- Utils.assertUnreachable(column);
173
- }
174
- }
175
- };
176
149
  switch (column.type) {
177
150
  case 'checkbox': {
178
151
  const resolved = new ResolvedColumn({
@@ -198,9 +171,6 @@ export class TableModel {
198
171
  case 'text': {
199
172
  const resolved = new ResolvedColumn(column);
200
173
  resolved.headerView = resolveSortableHeader(resolved);
201
- if (column.editorColumn) {
202
- resolved.editorColumn = resolveEditorColumn(column.editorColumn);
203
- }
204
174
  return resolved;
205
175
  }
206
176
  default: {
@@ -0,0 +1,14 @@
1
+ import type { ResolvedColumn } from './table-column-models.svelte';
2
+ import type { TableModel } from './table-model.svelte';
3
+ import type { WithId } from './types';
4
+ type SelectionCallbacks<T> = {
5
+ selectionChanged?: (e: T[]) => void;
6
+ itemsSelected?: (e: T[]) => void;
7
+ itemsDeselected?: (e: T[]) => void;
8
+ };
9
+ export declare const cssWidth: <T extends WithId>(column: ResolvedColumn<T>) => string;
10
+ /** Shared presentation wiring for the table views: selection-event subscriptions + the debounced no-items placeholder. */
11
+ export declare const createTableView: <T extends WithId>(model: () => TableModel<T>, on: () => SelectionCallbacks<T> | undefined) => {
12
+ readonly showNoItemsPlaceholder: boolean;
13
+ };
14
+ export {};
@@ -0,0 +1,32 @@
1
+ import { untrack } from 'svelte';
2
+ export const cssWidth = (column) => (column.fixedCssWidth ? `width: ${column.fixedCssWidth};` : 'width: auto;');
3
+ /** Shared presentation wiring for the table views: selection-event subscriptions + the debounced no-items placeholder. */
4
+ export const createTableView = (model, on) => {
5
+ let showNoItemsPlaceholder = $state(false);
6
+ let timeout = 0;
7
+ $effect(() => untrack(() => {
8
+ const selection = model().selection;
9
+ const subscriptions = [
10
+ selection.subscribeOnChange((values) => on()?.selectionChanged?.(values)),
11
+ selection.subscribeOnAdd((values) => on()?.itemsSelected?.(values)),
12
+ selection.subscribeOnRemove((values) => on()?.itemsDeselected?.(values))
13
+ ];
14
+ return () => subscriptions.forEach((unsubscribe) => unsubscribe());
15
+ }));
16
+ $effect(() => {
17
+ if (model().items.length) {
18
+ clearTimeout(timeout);
19
+ showNoItemsPlaceholder = false;
20
+ return;
21
+ }
22
+ timeout = window.setTimeout(() => {
23
+ showNoItemsPlaceholder = !model().items.length;
24
+ }, 700);
25
+ return () => clearTimeout(timeout);
26
+ });
27
+ return {
28
+ get showNoItemsPlaceholder() {
29
+ return showNoItemsPlaceholder;
30
+ }
31
+ };
32
+ };
@@ -3,18 +3,13 @@ import type { BadgeVariant } from '../badge';
3
3
  import type { ButtonSize, ButtonVariant } from '../button';
4
4
  import { DynamicComponentModel } from '../dynamic-component';
5
5
  import type { IconProp } from '../icon';
6
- import type { SelectOption } from '../select';
7
6
  import type { Snippet } from 'svelte';
8
- import type { ISchema } from 'yup';
9
7
  export type WithId = {
10
8
  id: string;
11
9
  };
12
- export type IAnyTableColumn<T> = {
13
- [P in keyof T]: IOneOfTableColumn<T, P>;
14
- }[keyof T];
15
- export type IOneOfTableColumn<T, K extends keyof T> = ITableBadgeColumn<T> | ITableButtonColumn<T> | ITableByColumn<T> | ITableCheckboxColumn | ITableCustomColumn<T> | ITableIconColumn<T> | ITableImageColumn<T> | ITableMoveRowColumn | ITableSelectColumn<T, K> | ITableSnippetColumn<T> | ITableTextColumn<T> | ITableTextInputColumn<T>;
16
- export type IEditorColumn<T> = ITableTextInputColumn<T> | ITableSelectColumn<T, keyof T>;
17
- export type TableColumnType = 'actions' | 'badge' | 'button' | 'by' | 'checkbox' | 'custom' | 'icon' | 'image' | 'move-row' | 'select' | 'snippet' | 'text' | 'text-input';
10
+ export type IAnyTableColumn<T> = IOneOfTableColumn<T>;
11
+ export type IOneOfTableColumn<T> = ITableBadgeColumn<T> | ITableButtonColumn<T> | ITableByColumn<T> | ITableCheckboxColumn | ITableCustomColumn<T> | ITableIconColumn<T> | ITableImageColumn<T> | ITableMoveRowColumn | ITableSnippetColumn<T> | ITableTextColumn<T>;
12
+ export type TableColumnType = 'actions' | 'badge' | 'button' | 'by' | 'checkbox' | 'custom' | 'icon' | 'image' | 'move-row' | 'snippet' | 'text';
18
13
  interface ITableColumnBase {
19
14
  type: TableColumnType;
20
15
  fixedCssWidth?: string;
@@ -45,7 +40,8 @@ export interface ITableBadgeColumn<T> extends ITableColumn<T> {
45
40
  }
46
41
  export interface ITableByColumn<T> extends ITableColumn<T> {
47
42
  type: 'by';
48
- valueFactory?: ((item: T) => Date) | null;
43
+ /** The "when" an ISO date string. */
44
+ valueFactory?: ((item: T) => string) | null;
49
45
  byValueFactory?: ((item: T) => {
50
46
  id: string;
51
47
  name: string;
@@ -92,17 +88,6 @@ export interface ITableMoveRowColumn extends ITableColumnBase {
92
88
  type: 'move-row';
93
89
  disableFactory?: (() => boolean) | null;
94
90
  }
95
- export interface ITableSelectColumn<T, K extends keyof T> extends ITableColumn<T> {
96
- id: K;
97
- type: 'select';
98
- valueFactory?: ((item: T) => T[K]) | null;
99
- optionsFactory: (item: T) => SelectOption<T[K]>[];
100
- placeholder?: string | null;
101
- disabledFactory?: ((item: T) => boolean) | null;
102
- visibilityFactory?: ((item: T) => boolean) | null;
103
- clearable?: boolean;
104
- onSelected: (item: T, value: T[K] | null) => void;
105
- }
106
91
  export interface ITableSnippetColumn<T> extends ITableColumn<T> {
107
92
  type: 'snippet';
108
93
  /** Render-prop snippet receiving the row item. Use for rich / custom cell composition without creating a separate cell component. */
@@ -114,14 +99,6 @@ export interface ITableTextColumn<T> extends ITableColumn<T> {
114
99
  /** @default 1 */
115
100
  maxLines?: number | 'single-line-no-trim' | null;
116
101
  valueFactory?: ((item: T) => string) | null;
117
- editorColumn?: IEditorColumn<T> | null;
118
- }
119
- export interface ITableTextInputColumn<T> extends ITableColumn<T> {
120
- type: 'text-input';
121
- inputType?: 'text' | 'number' | null;
122
- validationSchema?: ISchema<unknown> | null;
123
- onValidated?: ((item: T, error: string) => void) | null;
124
- onInput?: ((item: T, value: string) => void) | null;
125
102
  }
126
103
  export type TableTextColumnFormat = 'text' | 'html' | 'money' | 'date' | 'date-time';
127
104
  export type TableImageColumnFormat = 'circle' | 'square-contain' | 'square-cover';
@@ -1,4 +1,4 @@
1
- <script lang="ts">const { checked, size = 'md', disabled = false, layout = 'spread', label, sublabel, title, name, on } = $props();
1
+ <script lang="ts">const { checked, size = 'md', disabled = false, presentational = false, layout = 'spread', label, sublabel, title, name, on } = $props();
2
2
  const hasLabel = $derived(label !== undefined || sublabel !== undefined);
3
3
  const ariaLabel = $derived(typeof label === 'string' ? label : name);
4
4
  const handleClick = (event) => {
@@ -12,19 +12,25 @@ export {};
12
12
  </script>
13
13
 
14
14
  {#snippet switchControl()}
15
- <button
16
- type="button"
17
- class="toggle toggle--{size}"
18
- class:toggle--on={checked}
19
- class:toggle--disabled={disabled}
20
- role="switch"
21
- aria-checked={checked}
22
- aria-label={ariaLabel}
23
- title={hasLabel ? undefined : title}
24
- disabled={disabled}
25
- onclick={handleClick}>
26
- <span class="toggle__thumb" aria-hidden="true"></span>
27
- </button>
15
+ {#if presentational}
16
+ <span class="toggle toggle--{size}" class:toggle--on={checked} class:toggle--disabled={disabled} aria-hidden="true">
17
+ <span class="toggle__thumb"></span>
18
+ </span>
19
+ {:else}
20
+ <button
21
+ type="button"
22
+ class="toggle toggle--{size}"
23
+ class:toggle--on={checked}
24
+ class:toggle--disabled={disabled}
25
+ role="switch"
26
+ aria-checked={checked}
27
+ aria-label={ariaLabel}
28
+ title={hasLabel ? undefined : title}
29
+ disabled={disabled}
30
+ onclick={handleClick}>
31
+ <span class="toggle__thumb" aria-hidden="true"></span>
32
+ </button>
33
+ {/if}
28
34
  {/snippet}
29
35
 
30
36
  {#if hasLabel}
@@ -140,10 +146,10 @@ switch left + label right, intrinsic width).
140
146
  }
141
147
 
142
148
  .toggle {
143
- --_toggle--track-width: var(--sc-kit--toggle--track-width, 2rem);
144
- --_toggle--track-height: var(--sc-kit--toggle--track-height, 1.125rem);
145
- --_toggle--thumb-size: var(--sc-kit--toggle--thumb-size, 0.875rem);
146
- --_toggle--thumb-travel: var(--sc-kit--toggle--thumb-travel, 0.875rem);
149
+ --_toggle--track-width: var(--sc-kit--toggle--track-width, var(--_toggle--size-track-width, 2rem));
150
+ --_toggle--track-height: var(--sc-kit--toggle--track-height, var(--_toggle--size-track-height, 1.125rem));
151
+ --_toggle--thumb-size: var(--sc-kit--toggle--thumb-size, var(--_toggle--size-thumb-size, 0.875rem));
152
+ --_toggle--thumb-travel: var(--sc-kit--toggle--thumb-travel, var(--_toggle--size-thumb-travel, 0.875rem));
147
153
  --_toggle--thumb-offset: var(--sc-kit--toggle--thumb-offset, 0.125rem);
148
154
  --_toggle--thumb-translate: 0;
149
155
  --_toggle--background: var(--sc-kit--toggle--background, var(--sc-kit--color--border--strong));
@@ -166,16 +172,16 @@ switch left + label right, intrinsic width).
166
172
  outline-offset: 2px;
167
173
  }
168
174
  .toggle--sm {
169
- --sc-kit--toggle--track-width: 1.625rem;
170
- --sc-kit--toggle--track-height: 0.875rem;
171
- --sc-kit--toggle--thumb-size: 0.625rem;
172
- --sc-kit--toggle--thumb-travel: 0.75rem;
175
+ --_toggle--size-track-width: 1.625rem;
176
+ --_toggle--size-track-height: 0.875rem;
177
+ --_toggle--size-thumb-size: 0.625rem;
178
+ --_toggle--size-thumb-travel: 0.75rem;
173
179
  }
174
180
  .toggle--md {
175
- --sc-kit--toggle--track-width: 2rem;
176
- --sc-kit--toggle--track-height: 1.125rem;
177
- --sc-kit--toggle--thumb-size: 0.875rem;
178
- --sc-kit--toggle--thumb-travel: 0.875rem;
181
+ --_toggle--size-track-width: 2rem;
182
+ --_toggle--size-track-height: 1.125rem;
183
+ --_toggle--size-thumb-size: 0.875rem;
184
+ --_toggle--size-thumb-travel: 0.875rem;
179
185
  }
180
186
  .toggle--on {
181
187
  --sc-kit--toggle--background: var(--sc-kit--toggle--background--on, var(--sc-kit--color--accent));
@@ -4,6 +4,8 @@ type Props = {
4
4
  /** @default 'md' */
5
5
  size?: 'sm' | 'md';
6
6
  disabled?: boolean;
7
+ /** Render a non-interactive visual switch (a `<span>`, not a button) for embedding inside another interactive row that owns the click + semantics. @default false */
8
+ presentational?: boolean;
7
9
  /** Label position relative to the switch. `spread` = label left, switch right (settings-row). `inline` = switch left, label right (compact). @default 'spread' */
8
10
  layout?: 'spread' | 'inline';
9
11
  /** Label: plain text or a snippet for rich content. */
@@ -10,7 +10,7 @@ import IconCheckmarkCircle from '@fluentui/svg-icons/icons/checkmark_circle_20_f
10
10
  import IconChevronRight from '@fluentui/svg-icons/icons/chevron_right_20_regular.svg?raw';
11
11
  import IconMoreVertical from '@fluentui/svg-icons/icons/more_vertical_20_regular.svg?raw';
12
12
  import { slide } from 'svelte/transition';
13
- let { node, nav, hideExpandIcon = false, level = 0, showSelectedCheckmark } = $props();
13
+ let { node, keyboard, hideExpandIcon = false, level = 0, showSelectedCheckmark } = $props();
14
14
  let actionsOpened = $state(false);
15
15
  let dbClickTimeout = undefined;
16
16
  let dragExpandTimeout = undefined;
@@ -67,7 +67,6 @@ const handleDrop = (e) => {
67
67
  };
68
68
  const handleSelectNode = (e) => {
69
69
  e.stopPropagation();
70
- nav.setActive(node);
71
70
  clearTimeout(dbClickTimeout);
72
71
  if (node.expandOnDoubleClick) {
73
72
  dbClickTimeout = window.setTimeout(() => {
@@ -80,7 +79,6 @@ const handleSelectNode = (e) => {
80
79
  };
81
80
  const handleExpandNode = (e) => {
82
81
  e.stopPropagation();
83
- nav.setActive(node);
84
82
  if (node.expanded) {
85
83
  node.collapse();
86
84
  }
@@ -112,9 +110,7 @@ const handleMouseLeave = () => {
112
110
  <div
113
111
  class="tree-node"
114
112
  style={`--_tree-node--level: ${level}`}
115
- id={nav.itemId(node)}
116
113
  role="treeitem"
117
- tabindex="-1"
118
114
  aria-level={level + 1}
119
115
  aria-selected={node.selected}
120
116
  aria-expanded={children.length ? node.expanded : undefined}>
@@ -122,7 +118,6 @@ const handleMouseLeave = () => {
122
118
  <div
123
119
  class="tree-node__leaf"
124
120
  class:tree-node__leaf--active={node.selected}
125
- class:tree-node__leaf--focused={nav.hasFocus && nav.activeId === node.id}
126
121
  class:tree-node__leaf--draggable={node.dragConfig}
127
122
  class:tree-node__leaf--expandable={children.length}
128
123
  class:tree-node__leaf--drag-over={isDraggedOver}
@@ -150,8 +145,15 @@ const handleMouseLeave = () => {
150
145
  </button>
151
146
  {/if}
152
147
 
153
- <!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
154
- <div class="tree-node__anchor" onclick={handleSelectNode} ondblclick={handleExpandOnDoubleClick}>
148
+ <div
149
+ class="tree-node__anchor"
150
+ id={keyboard.anchorId(node)}
151
+ role="button"
152
+ tabindex={keyboard.currentId === node.id ? 0 : -1}
153
+ onclick={handleSelectNode}
154
+ ondblclick={handleExpandOnDoubleClick}
155
+ onfocusin={() => keyboard.setFocused(node.id)}
156
+ onkeydown={(e) => keyboard.handleKeydown(node, e)}>
155
157
  {#if !node.hideIcon}
156
158
  <div class="tree-node__icon" class:tree-node__icon--active={node.selected}>
157
159
  {#if node.icon}
@@ -196,7 +198,7 @@ const handleMouseLeave = () => {
196
198
  {#if node.expanded && children.length}
197
199
  <div transition:slide={{ duration: transitionDuration.base }} class="tree-node__children" role="group">
198
200
  {#each children as child (child.id)}
199
- <Self node={child} nav={nav} level={level + 1} hideExpandIcon={hideChildExpandIcon} showSelectedCheckmark={showSelectedCheckmark} />
201
+ <Self node={child} keyboard={keyboard} level={level + 1} hideExpandIcon={hideChildExpandIcon} showSelectedCheckmark={showSelectedCheckmark} />
200
202
  {/each}
201
203
  </div>
202
204
  {/if}
@@ -235,7 +237,10 @@ const handleMouseLeave = () => {
235
237
  color: var(--sc-kit--color--text--primary);
236
238
  background: var(--sc-kit--color--bg--active);
237
239
  }
238
- .tree-node__leaf--focused {
240
+ .tree-node__leaf:focus-within {
241
+ --_tree-node--action-opacity: 1;
242
+ }
243
+ .tree-node__leaf:has(.tree-node__anchor:focus-visible) {
239
244
  outline: 2px solid var(--sc-kit--color--border--focus);
240
245
  outline-offset: -2px;
241
246
  }
@@ -280,6 +285,7 @@ const handleMouseLeave = () => {
280
285
  gap: var(--sc-kit--space--2);
281
286
  min-width: 0;
282
287
  padding: var(--_tree-node--padding-block) 0;
288
+ outline: none;
283
289
  }
284
290
  .tree-node__icon {
285
291
  --sc-kit--icon--size: var(--_tree-node--icon-size);
@@ -1,8 +1,8 @@
1
- import type { TreeNavigation } from './tree-navigation.svelte';
1
+ import type { TreeKeyboard } from './tree-keyboard.svelte';
2
2
  import { type TreeNode } from './tree-node.svelte';
3
3
  type Props = {
4
4
  node: TreeNode;
5
- nav: TreeNavigation;
5
+ keyboard: TreeKeyboard;
6
6
  hideExpandIcon?: boolean;
7
7
  level?: number;
8
8
  showSelectedCheckmark?: boolean;