@lavalogic/scoria 0.37.4 → 0.37.5

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.
@@ -125,6 +125,7 @@ export function createColumnFactory() {
125
125
  id: opts.id,
126
126
  ...commonProps(opts),
127
127
  accessorFn: opts.accessor,
128
+ getDisplayValue: opts.getDisplayValue,
128
129
  filterValueType: FilterValueType.String,
129
130
  });
130
131
  return makeSpec('text', def, {
@@ -137,6 +138,7 @@ export function createColumnFactory() {
137
138
  id: opts.id,
138
139
  ...commonProps(opts),
139
140
  accessorFn: opts.accessor,
141
+ getDisplayValue: opts.getDisplayValue,
140
142
  min: opts.min ?? Number.MIN_SAFE_INTEGER,
141
143
  max: opts.max ?? Number.MAX_SAFE_INTEGER,
142
144
  filterValueType: FilterValueType.Number,
@@ -151,6 +153,7 @@ export function createColumnFactory() {
151
153
  id: opts.id,
152
154
  ...commonProps(opts),
153
155
  accessorFn: opts.accessor,
156
+ getDisplayValue: opts.getDisplayValue,
154
157
  filterValueType: FilterValueType.Bool,
155
158
  });
156
159
  return makeSpec('checkbox', def, {
@@ -163,6 +166,7 @@ export function createColumnFactory() {
163
166
  id: opts.id,
164
167
  ...commonProps(opts),
165
168
  accessorFn: opts.accessor,
169
+ getDisplayValue: opts.getDisplayValue,
166
170
  showTime: opts.withTime ?? false,
167
171
  filterValueType: FilterValueType.Date,
168
172
  });
@@ -197,8 +201,12 @@ export function createColumnFactory() {
197
201
  id: opts.id,
198
202
  ...commonProps(opts),
199
203
  accessorFn: opts.accessor,
200
- query: (queryString) => opts
201
- .query(queryString)
204
+ // Forward the row to the consumer's query callback so it
205
+ // may scope results by row-level context (e.g. a `pod`
206
+ // query filtered by `row.warehouse_id`). Index dropped on
207
+ // the public surface but available internally.
208
+ query: (queryString, item) => opts
209
+ .query(queryString, item)
202
210
  .then((res) => res),
203
211
  getDisplayValue: opts.getDisplayValue ?? ((row) => String(row[opts.id] ?? '')),
204
212
  filterValueType: FilterValueType.Select,
@@ -211,6 +219,9 @@ export function createColumnFactory() {
211
219
  // ─── Display kinds ──────────────────────────────────────────
212
220
  display(opts) {
213
221
  const id = mintSyntheticId('display', opts.idHint);
222
+ const normalisedOptions = opts.getOptions
223
+ ? normaliseOptionsLoader(opts.getOptions)
224
+ : undefined;
214
225
  const def = new DisplayDef({
215
226
  id,
216
227
  ...commonProps(opts),
@@ -221,6 +232,8 @@ export function createColumnFactory() {
221
232
  // column kind). Consumers opt in by passing the type they
222
233
  // want the filter input rendered as.
223
234
  filterValueType: opts.filterValueType,
235
+ getSortingFn: opts.getSortingFn,
236
+ getOptions: normalisedOptions,
224
237
  });
225
238
  return makeSpec('display', def);
226
239
  },
@@ -285,13 +298,20 @@ export function createColumnFactory() {
285
298
  return makeSpec('rowSelection', def);
286
299
  },
287
300
  actions(opts) {
288
- const wrapped = opts.actions.map((action) => ({
289
- getLabel: () => action.label,
290
- callback: (row) => {
291
- void action.callback(row);
292
- },
293
- colourSet: action.colourSet,
294
- }));
301
+ const wrapped = opts.actions.map((action) => {
302
+ // `label` may be a literal string or a `(row) => string |
303
+ // Promise<string>` function. The internal Def expects a
304
+ // `getLabel(item, index)` so wrap accordingly.
305
+ const labelOption = action.label;
306
+ const getLabel = typeof labelOption === 'function' ? (item) => labelOption(item) : () => labelOption;
307
+ return {
308
+ getLabel,
309
+ callback: (row) => {
310
+ void action.callback(row);
311
+ },
312
+ colourSet: action.colourSet,
313
+ };
314
+ });
295
315
  const isEnabledFn = opts.isEnabled;
296
316
  const def = new ActionsDef({
297
317
  actions: wrapped,
@@ -316,9 +336,14 @@ export function createColumnFactory() {
316
336
  accessorFn: opts.childRows,
317
337
  headerIcon: opts.headerIcon ?? 'chevron-down',
318
338
  innerTableName: scoriaStorageKey(opts.name),
319
- getInnerColumnDefs: () => {
339
+ getInnerColumnDefs: (row, index) => {
340
+ // `childColumns` receives the outer row + index so the
341
+ // inner column set may branch per row (pick-wave-subtype
342
+ // drill-downs, for example). Outer-row args are optional
343
+ // at the consumer site, so closures that ignore them
344
+ // continue working unchanged.
320
345
  const innerFactory = createColumnFactory();
321
- const innerSpecs = opts.childColumns(innerFactory);
346
+ const innerSpecs = opts.childColumns(innerFactory, row, index);
322
347
  const innerDefs = innerSpecs.map((spec) => unwrapColumnSpec(spec).def);
323
348
  return { defs: innerDefs };
324
349
  },
@@ -40,6 +40,14 @@ export interface TextColumnOptions<TRow extends object, K extends StringKeyOf<TR
40
40
  id: K;
41
41
  /** Reads the cell value from the row. Defaults to `row[id]`. */
42
42
  accessor?: (row: TRow, index: number) => TRow[K] | Promise<TRow[K]>;
43
+ /** Renders a different value in the cell while the underlying field
44
+ * (and therefore the typed filter / sort / edit input) remains
45
+ * `row[id]`. Useful for foreign-key columns where the cell shows a
46
+ * resolved name but the column's identity stays the typed field
47
+ * (e.g. `id: 'userName'` but the cell wants to render
48
+ * "{firstName} {lastName}" instead). Returns `null` to fall back to
49
+ * the accessor / default. */
50
+ getDisplayValue?: (row: TRow, index: number) => string | null | Promise<string | null>;
43
51
  /** Placeholder shown in the edit input when the cell is empty. */
44
52
  placeholder?: string;
45
53
  /** Maximum input length. */
@@ -61,6 +69,11 @@ export interface TextColumnOptions<TRow extends object, K extends StringKeyOf<TR
61
69
  export interface NumberColumnOptions<TRow extends object, K extends NumberKeyOf<TRow>> extends BaseColumnOptions {
62
70
  id: K;
63
71
  accessor?: (row: TRow, index: number) => TRow[K] | Promise<TRow[K]>;
72
+ /** See `TextColumnOptions.getDisplayValue`. Common use: render
73
+ * placeholder text like "Already Held" / "Already Released" in
74
+ * non-editable cells while the underlying numeric field still drives
75
+ * the typed filter UI. */
76
+ getDisplayValue?: (row: TRow, index: number) => string | null | Promise<string | null>;
64
77
  /** Lower bound. The edit input enforces; values outside resolve as invalid. */
65
78
  min?: number;
66
79
  /** Upper bound. */
@@ -78,6 +91,8 @@ export interface NumberColumnOptions<TRow extends object, K extends NumberKeyOf<
78
91
  export interface CheckboxColumnOptions<TRow extends object, K extends BooleanKeyOf<TRow>> extends BaseColumnOptions {
79
92
  id: K;
80
93
  accessor?: (row: TRow, index: number) => TRow[K] | Promise<TRow[K]>;
94
+ /** See `TextColumnOptions.getDisplayValue`. */
95
+ getDisplayValue?: (row: TRow, index: number) => string | null | Promise<string | null>;
81
96
  isEditable?: (row: TRow, index: number) => boolean | Promise<boolean>;
82
97
  onEdit?: (row: TRow, value: TRow[K], coords: CellCoordinates) => void | Promise<void>;
83
98
  reactiveDependencies?: (row: TRow) => ReadonlyArray<unknown>;
@@ -86,6 +101,8 @@ export interface CheckboxColumnOptions<TRow extends object, K extends BooleanKey
86
101
  export interface DateColumnOptions<TRow extends object, K extends DateKeyOf<TRow>> extends BaseColumnOptions {
87
102
  id: K;
88
103
  accessor?: (row: TRow, index: number) => TRow[K] | Promise<TRow[K]>;
104
+ /** See `TextColumnOptions.getDisplayValue`. */
105
+ getDisplayValue?: (row: TRow, index: number) => string | null | Promise<string | null>;
89
106
  /** Whether the time component is editable. Defaults to false (date-only). */
90
107
  withTime?: boolean;
91
108
  isValid?: ValidationFn<TRow>;
@@ -113,9 +130,12 @@ export interface SelectColumnOptions<TRow extends object, K extends keyof TRow &
113
130
  /** Options for `col.query({ id, header, query, ... })`. */
114
131
  export interface QueryColumnOptions<TRow extends object, K extends keyof TRow & string, TValue = TRow[K]> extends BaseColumnOptions {
115
132
  id: K;
116
- /** Async query loader; called with the current user input and expected to
117
- * return matching options. */
118
- query: (input: string) => Promise<ReadonlyArray<SelectOption<TValue>>>;
133
+ /** Async query loader; receives the current user input and the row
134
+ * being edited so the result set may depend on row-level context
135
+ * (e.g. a `pod` query scoped by the row's `warehouse_id`). The `row`
136
+ * argument is optional at the consumer site - `(input) => ...`
137
+ * callbacks continue working unchanged. */
138
+ query: (input: string, row: TRow) => Promise<ReadonlyArray<SelectOption<TValue>>>;
119
139
  accessor?: (row: TRow, index: number) => TValue | Promise<TValue>;
120
140
  getDisplayValue?: (row: TRow, index: number) => string | null | Promise<string | null>;
121
141
  isValid?: ValidationFn<TRow>;
@@ -148,6 +168,22 @@ export interface DisplayColumnOptions<TRow extends object, TValue = unknown> ext
148
168
  * id matching the server field name).
149
169
  */
150
170
  filterValueType?: FilterValueType;
171
+ /**
172
+ * Per-column sort comparator. Returns a `(a, b) => 1 | -1 | 0` for the
173
+ * given direction. Useful when the displayed `value` derives from a
174
+ * different field than the server would sort on, or when the value
175
+ * needs a non-default ordering (e.g. status enum ranked by workflow
176
+ * stage rather than alphabetically). Defaults to a generic
177
+ * `value`-derived comparator.
178
+ */
179
+ getSortingFn?: (desc: boolean) => (a: TRow, b: TRow) => 1 | -1 | 0;
180
+ /**
181
+ * Option list for `filterValueType: 'Select'`. Drives the filter row's
182
+ * dropdown contents. Returning a `Promise` lets consumers fetch
183
+ * options lazily on first read. Has no effect for non-Select filter
184
+ * types.
185
+ */
186
+ getOptions?: () => ReadonlyArray<SelectOption<TValue>> | Promise<ReadonlyArray<SelectOption<TValue>>>;
151
187
  }
152
188
  /** Options for `col.bubble({ header, value, colour, ... })`. Renders one or
153
189
  * more coloured pill bubbles per row. */
@@ -216,7 +252,14 @@ export interface ActionsColumnOptions<TRow extends object> extends Omit<BaseColu
216
252
  }
217
253
  /** Single row-action entry. */
218
254
  export interface RowAction<TRow extends object> {
219
- label: string;
255
+ /**
256
+ * Button label. May be a literal string, or a function that derives the
257
+ * label from the row (sync or async). Use the function form when the
258
+ * same action button should render different text per row (e.g. a
259
+ * combined "View / Edit" button whose label flips based on the row's
260
+ * editable state).
261
+ */
262
+ label: string | ((row: TRow) => string | Promise<string>);
220
263
  icon?: string;
221
264
  colourSet?: ColourSet;
222
265
  /** Invoked when the action is clicked. Receives the row. */
@@ -278,9 +321,19 @@ export interface ExpandColumnOptions<TRow extends object, TInner extends object,
278
321
  * shape on `CreateTableOptions` so callers can use the same
279
322
  * shorthand at every nesting level. */
280
323
  childRowId: (keyof TInner & string) | ((inner: TInner) => TInnerId | Promise<TInnerId>);
281
- /** Inner column declarations. Builder closure receives a typed
282
- * `ColumnFactory<TInner>`. */
283
- childColumns: (col: ColumnFactory<TInner>) => ReadonlyArray<ColumnSpec<TInner>>;
324
+ /**
325
+ * Inner column declarations. Builder closure receives a typed
326
+ * `ColumnFactory<TInner>` plus the outer row and its index, so the inner
327
+ * column set may branch per-row (e.g. a pick-wave subtype that shows
328
+ * shipment lines for shipment-typed waves and job lines for job-typed
329
+ * waves). The outer row + index arguments are optional at the consumer
330
+ * site - existing `(col) => [...]` closures continue to compile.
331
+ *
332
+ * Called per expansion, so the closure may safely read row-specific
333
+ * state. Returned `ColumnSpec` arrays are NOT cached between expansions
334
+ * - return shape may differ per call.
335
+ */
336
+ childColumns: (col: ColumnFactory<TInner>, row: TRow, index: number) => ReadonlyArray<ColumnSpec<TInner>>;
284
337
  /**
285
338
  * Icon rendered on the per-row expand toggle button. Defaults to
286
339
  * `'chevron-down'`. Useful when the parent context needs a richer
@@ -52,13 +52,23 @@ export interface SelectionApi<TRow extends object, TRowId extends Primitive> {
52
52
  export interface FilteringApi<TRow extends object> {
53
53
  /** Current column-filter state. Reactive. */
54
54
  readonly state: ColumnFiltersState;
55
- /** Set or clear the filter for a single column. */
56
- set(columnId: keyof TRow & string, value: unknown): void;
55
+ /**
56
+ * Set or clear the filter for a single column.
57
+ *
58
+ * `columnId` accepts any string so consumers may filter on synthetic
59
+ * display-column ids, nested-path filter ids, and `col.filterOnly`
60
+ * server-only ids (all of which are not `keyof TRow`). Typed callers
61
+ * that pass a row key keep their narrowed inference.
62
+ */
63
+ set(columnId: (keyof TRow & string) | string, value: unknown): void;
57
64
  /** Reset every column's filter to its default. */
58
65
  reset(): void;
59
- /** Change the filter mode (e.g. `'contains'` vs `'starts-with'`) for a
60
- * string column or `'between'` for a number / date column. */
61
- setMode(columnId: keyof TRow & string, mode: FilterMode): void;
66
+ /**
67
+ * Change the filter mode (e.g. `'contains'` vs `'starts-with'`) for a
68
+ * string column or `'between'` for a number / date column. Same
69
+ * widened `columnId` rules as `set`.
70
+ */
71
+ setMode(columnId: (keyof TRow & string) | string, mode: FilterMode): void;
62
72
  /** Whether the quick-filter input row is visible. */
63
73
  showQuickFilter: boolean;
64
74
  /** Whether the table is showing only selected rows. */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lavalogic/scoria",
3
3
  "description": "Svelte components used for the FloWMS Web Frontend",
4
- "version": "0.37.4",
4
+ "version": "0.37.5",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },