@spaethtech/svelte-ui 0.18.0 → 0.18.1-dev.88.f4b29b6

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.
@@ -223,6 +223,9 @@ examples):
223
223
  the query, filters via **`matchesRow(row, ast)`** (the in-memory AST evaluator: cmp/and/or/not/
224
224
  match/in/range/search, honouring column `id`/`searchable`/`sortKey`), then sorts + paginates. Only a
225
225
  remote/DB backend needs to compile the AST itself; do NOT hand-roll a "strip `$` + substring" filter.
226
+ `createGrid` also takes **`selectableRow: (row) => boolean`** — rows returning `false` are locked out
227
+ of selection (disabled checkbox, excluded from select-all, never in `grid.selected`), so
228
+ `bulkActions(selected)` never sees them; don't filter locked ids in the handler.
226
229
  · **`Pagination`** (standalone
227
230
  pager styled like the DataTable footer: tinted band, per-page `Select`, range total, and a
228
231
  `First·Prev·[page]/N·Next·Last` stepper whose indicator is an editable `NumberInput` quick-jump;
@@ -387,6 +387,7 @@
387
387
  {size}
388
388
  aria-label={i18n.messages.selectRow}
389
389
  checked={grid.isSelected(id)}
390
+ disabled={!grid.isRowSelectable(id)}
390
391
  onchange={() => grid.toggleRow(id)}
391
392
  />
392
393
  {/if}
@@ -9,6 +9,9 @@ export type GridOptions<T> = {
9
9
  perPageOptions?: number[];
10
10
  initialQuery?: string;
11
11
  initialSort?: Sort | null;
12
+ /** Per-row selection lock. Return `false` to make a row non-selectable: its checkbox is disabled,
13
+ * it's excluded from select-all, and `toggleRow`/`selected` never include it. Default: all selectable. */
14
+ selectableRow?: (row: T) => boolean;
12
15
  };
13
16
  /**
14
17
  * Shared, reactive controller for a data table. Implements {@link DataSet} (so any `<Query>` can
@@ -20,6 +23,7 @@ export declare class DataGrid<T> implements DataSet {
20
23
  readonly fetch: FetchFn<T>;
21
24
  readonly getRowId: (row: T) => string;
22
25
  readonly perPageOptions: number[];
26
+ readonly selectableRow: (row: T) => boolean;
23
27
  query: string;
24
28
  applied: string;
25
29
  error: string | null;
@@ -43,6 +47,10 @@ export declare class DataGrid<T> implements DataSet {
43
47
  setPage(p: number): void;
44
48
  setPerPage(n: number): void;
45
49
  get pageIds(): string[];
50
+ /** Whether a row may be selected (per `selectableRow`); unknown ids default selectable. */
51
+ isRowSelectable(id: string): boolean;
52
+ /** Current-page ids that are actually selectable — the set select-all operates over. */
53
+ get selectableIds(): string[];
46
54
  isSelected(id: string): boolean;
47
55
  toggleRow(id: string): void;
48
56
  get allSelected(): boolean;
@@ -10,6 +10,7 @@ export class DataGrid {
10
10
  fetch;
11
11
  getRowId;
12
12
  perPageOptions;
13
+ selectableRow;
13
14
  query = $state("");
14
15
  applied = $state("");
15
16
  error = $state(null);
@@ -25,6 +26,7 @@ export class DataGrid {
25
26
  this.columns = opts.columns;
26
27
  this.fetch = opts.fetch;
27
28
  this.getRowId = opts.getRowId ?? ((r) => String(r.id));
29
+ this.selectableRow = opts.selectableRow ?? (() => true);
28
30
  this.perPage = opts.perPage ?? 25;
29
31
  this.perPageOptions = opts.perPageOptions ?? [10, 25, 50, 100];
30
32
  this.sort = opts.initialSort ?? null;
@@ -86,24 +88,35 @@ export class DataGrid {
86
88
  get pageIds() {
87
89
  return this.rows.map((r) => this.getRowId(r));
88
90
  }
91
+ /** Whether a row may be selected (per `selectableRow`); unknown ids default selectable. */
92
+ isRowSelectable(id) {
93
+ const row = this.rows.find((r) => this.getRowId(r) === id);
94
+ return row === undefined ? true : this.selectableRow(row);
95
+ }
96
+ /** Current-page ids that are actually selectable — the set select-all operates over. */
97
+ get selectableIds() {
98
+ return this.rows.filter((r) => this.selectableRow(r)).map((r) => this.getRowId(r));
99
+ }
89
100
  isSelected(id) {
90
101
  return this.selected.has(id);
91
102
  }
92
103
  toggleRow(id) {
104
+ if (!this.isRowSelectable(id))
105
+ return; // locked rows never enter `selected`
93
106
  if (this.selected.has(id))
94
107
  this.selected.delete(id);
95
108
  else
96
109
  this.selected.add(id);
97
110
  }
98
111
  get allSelected() {
99
- const ids = this.pageIds;
112
+ const ids = this.selectableIds;
100
113
  return ids.length > 0 && ids.every((id) => this.selected.has(id));
101
114
  }
102
115
  get someSelected() {
103
- return this.pageIds.some((id) => this.selected.has(id)) && !this.allSelected;
116
+ return this.selectableIds.some((id) => this.selected.has(id)) && !this.allSelected;
104
117
  }
105
118
  toggleAll() {
106
- const ids = this.pageIds;
119
+ const ids = this.selectableIds;
107
120
  if (this.allSelected)
108
121
  ids.forEach((id) => this.selected.delete(id));
109
122
  else
@@ -384,6 +384,10 @@ Config-driven, responsive 12-column data table over a `DataGrid`.
384
384
  - **`rowActions` per row**: return `null`/`undefined`/`[]` for a row with no actions — the kebab still
385
385
  renders (the tail column stays aligned across rows) but is **disabled**, rather than opening an empty
386
386
  or all-greyed menu. Return items to enable it.
387
+ - **Per-row selection lock**: pass **`selectableRow: (row) => boolean`** to `createGrid`. Rows where it
388
+ returns `false` get a disabled checkbox, are excluded from select-all (`toggleAll`/`allSelected`/
389
+ `someSelected` operate only over selectable rows), and can never enter `grid.selected` — so
390
+ `bulkActions(selected)` never sees them (no need to re-filter in the handler). Default: all selectable.
387
391
  - **Links in an expandable table**: wrap only the **text** in `<a>` inside your `cell` snippet (not the
388
392
  whole cell). The cell is a flex box, so a plain inline `<a>text</a>` is text-width — the rest of the
389
393
  cell stays an expand/collapse target. Row-click already ignores clicks on `a`/`button`/`input`/…, so
package/docs/usage.md CHANGED
@@ -1119,7 +1119,6 @@ bar with `Query` over a `DataSet`.
1119
1119
 
1120
1120
  <DataTable
1121
1121
  {grid}
1122
- {columns}
1123
1122
  selectable
1124
1123
  rowActions={(row) => [{ label: "Edit", icon: IconPencil, onclick: () => edit(row) }]}
1125
1124
  />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaethtech/svelte-ui",
3
- "version": "0.18.0",
3
+ "version": "0.18.1-dev.88.f4b29b6",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/spaethtech/svelte-ui.git"