@lavalogic/scoria 0.37.14 → 0.37.16
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.
- package/dist/Components/Table/ColumnFactory.svelte.js +40 -4
- package/dist/Components/Table/Table.svelte +27 -15
- package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.d.ts +14 -0
- package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.js +11 -0
- package/dist/Components/Table/Types/Public/ColumnOptions.d.ts +12 -0
- package/package.json +1 -1
|
@@ -111,6 +111,12 @@ function commonProps(opts, kind) {
|
|
|
111
111
|
width: opts.width ?? defaultWidth,
|
|
112
112
|
maxWidth: opts.maxWidth,
|
|
113
113
|
wrapValue: opts.wrapValue,
|
|
114
|
+
// `widthIsFixed` is true only when the caller passed an explicit
|
|
115
|
+
// `width`. The grid template uses this to render the track as
|
|
116
|
+
// fixed `${W}px` for explicit widths, leaving the per-kind-default
|
|
117
|
+
// columns on `minmax(W, 1fr)` so they absorb any horizontal space
|
|
118
|
+
// the fixed columns leave behind.
|
|
119
|
+
widthIsFixed: opts.width != null,
|
|
114
120
|
allowSorting: opts.allowSorting,
|
|
115
121
|
allowFiltering: opts.allowFiltering,
|
|
116
122
|
defaultHidden: opts.defaultHidden,
|
|
@@ -133,7 +139,12 @@ function mintSyntheticId(prefix, hint) {
|
|
|
133
139
|
* required by the Def's signature; we spread to drop readonly. */
|
|
134
140
|
function normaliseOptionsLoader(options) {
|
|
135
141
|
if (typeof options === 'function') {
|
|
136
|
-
|
|
142
|
+
// `options()` may return either a Promise or a plain array - some
|
|
143
|
+
// project helpers (e.g. flowms `ColumnDefRepository.getAccounts()`
|
|
144
|
+
// vs. `getOutboundStatuses()`) settle on different conventions per
|
|
145
|
+
// data source. `Promise.resolve` accepts both so the loader hands
|
|
146
|
+
// the consumer a uniform Promise either way.
|
|
147
|
+
return () => Promise.resolve(options()).then((res) => [...res]);
|
|
137
148
|
}
|
|
138
149
|
const snapshot = [...options];
|
|
139
150
|
return () => Promise.resolve(snapshot);
|
|
@@ -285,7 +296,12 @@ export function createColumnFactory() {
|
|
|
285
296
|
// typed kinds where the factory pins one based on the
|
|
286
297
|
// column kind). Consumers opt in by passing the type they
|
|
287
298
|
// want the filter input rendered as.
|
|
288
|
-
|
|
299
|
+
// Default to string-typed filter when the caller did not specify
|
|
300
|
+
// one, so a display column with no explicit `filterValueType`
|
|
301
|
+
// still appears in the filter UI (matches the `DisplayDef →
|
|
302
|
+
// stringFilter (undefined case)` mapping in
|
|
303
|
+
// `setupDefaultColumnDefs`).
|
|
304
|
+
filterValueType: opts.filterValueType ?? FilterValueType.String,
|
|
289
305
|
getSortingFn: opts.getSortingFn,
|
|
290
306
|
getOptions: normalisedOptions,
|
|
291
307
|
});
|
|
@@ -293,12 +309,21 @@ export function createColumnFactory() {
|
|
|
293
309
|
},
|
|
294
310
|
bubble(opts) {
|
|
295
311
|
const id = mintSyntheticId('bubble', opts.idHint);
|
|
312
|
+
const normalisedOptions = opts.getOptions
|
|
313
|
+
? normaliseOptionsLoader(opts.getOptions)
|
|
314
|
+
: undefined;
|
|
296
315
|
const def = new BubbleDef({
|
|
297
316
|
id,
|
|
298
317
|
...commonProps(opts, 'bubble'),
|
|
299
318
|
accessorFn: opts.value,
|
|
300
319
|
getColour: opts.colour,
|
|
301
|
-
|
|
320
|
+
// Default to a string-typed filter so bubble columns appear in
|
|
321
|
+
// the quick-filter row and advanced filter panel by default
|
|
322
|
+
// (matches the `BubbleDef → stringFilter` mapping in
|
|
323
|
+
// `setupDefaultColumnDefs`). Caller can override to any other
|
|
324
|
+
// `filterValueType`, or pass `allowFiltering: false` to opt out.
|
|
325
|
+
filterValueType: opts.filterValueType ?? FilterValueType.String,
|
|
326
|
+
getOptions: normalisedOptions,
|
|
302
327
|
});
|
|
303
328
|
return makeSpec('bubble', def);
|
|
304
329
|
},
|
|
@@ -319,12 +344,19 @@ export function createColumnFactory() {
|
|
|
319
344
|
return userColour(row, index, fraction);
|
|
320
345
|
}
|
|
321
346
|
: () => 'grey';
|
|
347
|
+
const progressOptions = opts.getOptions
|
|
348
|
+
? normaliseOptionsLoader(opts.getOptions)
|
|
349
|
+
: undefined;
|
|
322
350
|
const def = new ProgressBarDef({
|
|
323
351
|
id,
|
|
324
352
|
...commonProps(opts, 'progress'),
|
|
325
353
|
accessorFn: tupleAccessor,
|
|
326
354
|
getColour,
|
|
327
|
-
|
|
355
|
+
// Default to number-typed filter so progress columns appear in
|
|
356
|
+
// the filter UI by default (matches `ProgressBarDef →
|
|
357
|
+
// numberFilter` in `setupDefaultColumnDefs`).
|
|
358
|
+
filterValueType: opts.filterValueType ?? FilterValueType.Number,
|
|
359
|
+
getOptions: progressOptions,
|
|
328
360
|
});
|
|
329
361
|
return makeSpec('progress', def);
|
|
330
362
|
},
|
|
@@ -336,6 +368,7 @@ export function createColumnFactory() {
|
|
|
336
368
|
header: opts?.header ?? '',
|
|
337
369
|
minSize: opts?.minWidth ?? KIND_DEFAULT_WIDTHS.validity,
|
|
338
370
|
width: opts?.width ?? KIND_DEFAULT_WIDTHS.validity,
|
|
371
|
+
widthIsFixed: opts?.width != null,
|
|
339
372
|
defaultHidden: opts?.defaultHidden,
|
|
340
373
|
resizable: opts?.resizable ?? false,
|
|
341
374
|
debug: opts?.debug,
|
|
@@ -354,6 +387,7 @@ export function createColumnFactory() {
|
|
|
354
387
|
// fallback and share equal `1fr` track space with wider columns.
|
|
355
388
|
def.width = KIND_DEFAULT_WIDTHS.rowSelection;
|
|
356
389
|
def.minSize = KIND_DEFAULT_WIDTHS.rowSelection;
|
|
390
|
+
def.widthIsFixed = true;
|
|
357
391
|
return makeSpec('rowSelection', def);
|
|
358
392
|
},
|
|
359
393
|
actions(opts) {
|
|
@@ -378,6 +412,7 @@ export function createColumnFactory() {
|
|
|
378
412
|
});
|
|
379
413
|
// Actions has no public width option - apply the per-kind default.
|
|
380
414
|
def.width = KIND_DEFAULT_WIDTHS.actions;
|
|
415
|
+
def.widthIsFixed = true;
|
|
381
416
|
return makeSpec('actions', def);
|
|
382
417
|
},
|
|
383
418
|
expand(opts) {
|
|
@@ -423,6 +458,7 @@ export function createColumnFactory() {
|
|
|
423
458
|
// Expand has no public width option - apply the per-kind default.
|
|
424
459
|
def.width = KIND_DEFAULT_WIDTHS.expand;
|
|
425
460
|
def.minSize = KIND_DEFAULT_WIDTHS.expand;
|
|
461
|
+
def.widthIsFixed = true;
|
|
426
462
|
return makeSpec('expand', def);
|
|
427
463
|
},
|
|
428
464
|
filterOnly(opts) {
|
|
@@ -356,17 +356,20 @@
|
|
|
356
356
|
// 20px to match the existing visual).
|
|
357
357
|
// - Each other track uses one of two strategies based on the
|
|
358
358
|
// column's `userResized` flag:
|
|
359
|
-
// - `userResized = false
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
//
|
|
359
|
+
// - `userResized = false`: track depends on whether the consumer
|
|
360
|
+
// supplied an explicit `width` and / or `maxWidth`:
|
|
361
|
+
// - `widthIsFixed` (consumer-supplied `width`, no `maxWidth`):
|
|
362
|
+
// fixed `${width}px` track. Stays at exactly that pixel value
|
|
363
|
+
// regardless of leftover container width.
|
|
364
|
+
// - `maxWidth` set (with or without explicit width): the track
|
|
365
|
+
// becomes `minmax(${width}px, ${maxWidth}px)`, a bounded flex
|
|
366
|
+
// that grows up to `maxWidth` and is then capped.
|
|
367
|
+
// - Neither (the column is on its per-kind default width):
|
|
368
|
+
// `minmax(${width}px, 1fr)`, the column flexes to absorb any
|
|
369
|
+
// horizontal space the fixed-width tracks leave behind.
|
|
370
|
+
// This produces the "specify widths for the columns you care
|
|
371
|
+
// about; let the rest fill the gap" behaviour that mirrors the
|
|
372
|
+
// legacy `<table>` element when only some columns set a width.
|
|
370
373
|
// - `userResized = true`: `${width}px` (fixed). The column sits
|
|
371
374
|
// at exactly the size the user dragged it to, and dragging the
|
|
372
375
|
// handle again only changes this column.
|
|
@@ -378,14 +381,23 @@
|
|
|
378
381
|
const colsTemplate = $derived.by(() => {
|
|
379
382
|
void tableContext.columnSizing;
|
|
380
383
|
const track = (col: {
|
|
381
|
-
columnDef: {
|
|
384
|
+
columnDef: {
|
|
385
|
+
width: number;
|
|
386
|
+
maxWidth?: number;
|
|
387
|
+
userResized: boolean;
|
|
388
|
+
widthIsFixed: boolean;
|
|
389
|
+
};
|
|
382
390
|
}) => {
|
|
383
391
|
if (col.columnDef.userResized) {
|
|
384
392
|
return `${col.columnDef.width}px`;
|
|
385
393
|
}
|
|
386
|
-
|
|
387
|
-
col.columnDef.
|
|
388
|
-
|
|
394
|
+
if (col.columnDef.maxWidth != null) {
|
|
395
|
+
return `minmax(${col.columnDef.width}px, ${col.columnDef.maxWidth}px)`;
|
|
396
|
+
}
|
|
397
|
+
if (col.columnDef.widthIsFixed) {
|
|
398
|
+
return `${col.columnDef.width}px`;
|
|
399
|
+
}
|
|
400
|
+
return `minmax(${col.columnDef.width}px, 1fr)`;
|
|
389
401
|
};
|
|
390
402
|
const tracks: Array<string> = ['20px'];
|
|
391
403
|
for (const col of leftColumns) {
|
|
@@ -53,6 +53,14 @@ export interface ColumnDefProps<T extends object, in FilterFnType, out OptionsTy
|
|
|
53
53
|
* Cell content beyond the track is ellipsised, or wraps when
|
|
54
54
|
* `wrapValue` is also set. */
|
|
55
55
|
maxWidth?: Pixels;
|
|
56
|
+
/** Set by the column factory when the consumer supplied an explicit
|
|
57
|
+
* `width` (vs. the factory's per-kind default). The grid template
|
|
58
|
+
* treats an explicit width as fixed (`${width}px` track) and a
|
|
59
|
+
* per-kind default as flexible (`minmax(width, 1fr)` track), so a
|
|
60
|
+
* table whose specified widths total less than the container leaves
|
|
61
|
+
* the unspecified columns to absorb the trailing space rather than
|
|
62
|
+
* every column expanding by equal `1fr` shares. */
|
|
63
|
+
widthIsFixed?: boolean;
|
|
56
64
|
/** When true, cell content that does not fit wraps onto new lines
|
|
57
65
|
* and the row's height grows to fit. When false (default) overflow
|
|
58
66
|
* is clipped with ellipsis. Surfaces as the `--wrap-value` CSS
|
|
@@ -148,6 +156,12 @@ export declare abstract class ColumnDef<T extends object, in FilterFnType = neve
|
|
|
148
156
|
* clipped with ellipsis (false). */
|
|
149
157
|
get wrapValue(): boolean;
|
|
150
158
|
set wrapValue(v: boolean);
|
|
159
|
+
private _widthIsFixed;
|
|
160
|
+
/** Set by the column factory when the consumer supplied an explicit
|
|
161
|
+
* `width`. Drives the grid-template branch: true = fixed `${width}px`
|
|
162
|
+
* track, false = `minmax(width, 1fr)` flex track. */
|
|
163
|
+
get widthIsFixed(): boolean;
|
|
164
|
+
set widthIsFixed(v: boolean);
|
|
151
165
|
private _isResizing;
|
|
152
166
|
/** Whether the resize handle is currently active. */
|
|
153
167
|
get isResizing(): boolean;
|
|
@@ -38,6 +38,7 @@ export class ColumnDef {
|
|
|
38
38
|
this._width = $state(props.width ?? props.minSize ?? 48);
|
|
39
39
|
this._maxWidth = $state(props.maxWidth);
|
|
40
40
|
this._wrapValue = $state(props.wrapValue ?? false);
|
|
41
|
+
this._widthIsFixed = $state(props.widthIsFixed ?? false);
|
|
41
42
|
this.isEditable = $derived(props.isEditable ?? (() => Promise.resolve(false)));
|
|
42
43
|
this.resizable = $derived(props.resizable ?? true);
|
|
43
44
|
this.header = $derived(props.header);
|
|
@@ -108,6 +109,16 @@ export class ColumnDef {
|
|
|
108
109
|
set wrapValue(v) {
|
|
109
110
|
this._wrapValue = v;
|
|
110
111
|
}
|
|
112
|
+
_widthIsFixed;
|
|
113
|
+
/** Set by the column factory when the consumer supplied an explicit
|
|
114
|
+
* `width`. Drives the grid-template branch: true = fixed `${width}px`
|
|
115
|
+
* track, false = `minmax(width, 1fr)` flex track. */
|
|
116
|
+
get widthIsFixed() {
|
|
117
|
+
return this._widthIsFixed;
|
|
118
|
+
}
|
|
119
|
+
set widthIsFixed(v) {
|
|
120
|
+
this._widthIsFixed = v;
|
|
121
|
+
}
|
|
111
122
|
_isResizing = $state(false);
|
|
112
123
|
/** Whether the resize handle is currently active. */
|
|
113
124
|
get isResizing() {
|
|
@@ -201,6 +201,13 @@ export interface BubbleColumnOptions<TRow extends object, TValue = unknown> exte
|
|
|
201
201
|
* where the displayed values are strings but the server filter is a select.
|
|
202
202
|
*/
|
|
203
203
|
filterValueType?: FilterValueType;
|
|
204
|
+
/**
|
|
205
|
+
* Option list for `filterValueType: 'Select'`. Drives the filter row's
|
|
206
|
+
* dropdown contents. Returning a `Promise` lets consumers fetch
|
|
207
|
+
* options lazily on first read; returning a plain array is also
|
|
208
|
+
* supported (scoria internally wraps it in `Promise.resolve`).
|
|
209
|
+
*/
|
|
210
|
+
getOptions?: () => ReadonlyArray<SelectOption<TValue>> | Promise<ReadonlyArray<SelectOption<TValue>>>;
|
|
204
211
|
}
|
|
205
212
|
/** Options for `col.progress({ header, value, ... })`. Renders a horizontal
|
|
206
213
|
* progress bar from a numeric ratio. */
|
|
@@ -216,6 +223,11 @@ export interface ProgressColumnOptions<TRow extends object> extends BaseColumnOp
|
|
|
216
223
|
* "percent complete" field, in which case set this to `'Number'`.
|
|
217
224
|
*/
|
|
218
225
|
filterValueType?: FilterValueType;
|
|
226
|
+
/**
|
|
227
|
+
* Option list for `filterValueType: 'Select'`. Drives the filter row's
|
|
228
|
+
* dropdown contents.
|
|
229
|
+
*/
|
|
230
|
+
getOptions?: () => ReadonlyArray<SelectOption<unknown>> | Promise<ReadonlyArray<SelectOption<unknown>>>;
|
|
219
231
|
}
|
|
220
232
|
/** Options for `col.validity({ header, ... })`. Renders the row's overall
|
|
221
233
|
* validity indicator and (optionally) opens a modal with the validity
|