@lavalogic/scoria 0.37.12 → 0.37.14

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 (24) hide show
  1. package/dist/Components/Table/Body/QuickSearchCell.svelte +14 -9
  2. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +4 -3
  3. package/dist/Components/Table/Body/Rows/Columns/ActionsCell.svelte +4 -3
  4. package/dist/Components/Table/Body/Rows/Columns/BubbleCell.svelte +4 -3
  5. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +4 -3
  6. package/dist/Components/Table/Body/Rows/Columns/FocusableImmutableCell.svelte +4 -3
  7. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +4 -3
  8. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +4 -3
  9. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +4 -3
  10. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +4 -3
  11. package/dist/Components/Table/Body/Rows/Columns/TableQuerySelect.svelte +4 -3
  12. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +4 -3
  13. package/dist/Components/Table/Body/Rows/Columns/TableSelect.svelte +4 -3
  14. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +4 -3
  15. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +4 -3
  16. package/dist/Components/Table/Body/Rows/TableRow.svelte +16 -2
  17. package/dist/Components/Table/ColumnFactory.svelte.js +2 -0
  18. package/dist/Components/Table/Misc/FilterInput.svelte +18 -1
  19. package/dist/Components/Table/Table.svelte +21 -15
  20. package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.d.ts +19 -0
  21. package/dist/Components/Table/Types/Columns/Definitions/ColumnDef.svelte.js +19 -0
  22. package/dist/Components/Table/Types/Public/BaseColumnOptions.d.ts +12 -0
  23. package/dist/scss/_mixins.scss +12 -3
  24. package/package.json +1 -1
@@ -55,14 +55,18 @@
55
55
 
56
56
  const hasFilterFn = $derived(!!def.filterFn && typeof def.filterFn === 'function');
57
57
 
58
- // const hasAcceptableColumnType = $derived(
59
- // (def instanceof AccessorDef && searchableTypes.has(def.accessorType)) ||
60
- // (def instanceof AbstractDisplayDef && searchableTypes.has(def.displayType))
61
- // );
58
+ // A column declares it is filterable when it either (a) has a local
59
+ // `filterFn`, (b) declares a `filterValueType` (server-side filtering
60
+ // case: `paginationRepo.dateFilter` etc. are only defined for LOCAL
61
+ // data repositories, so remote-pagination tables otherwise silently
62
+ // hide every typed column from the quick-filter row), or (c) is keyed
63
+ // in `customFilters` (remote filter chips supplied via
64
+ // `defsWrapper.remoteFilters`).
65
+ const hasDeclaredFilterType = $derived(def.filterValueType != null);
62
66
 
63
67
  const isSearchable = $derived(
64
- def.allowFiltering && (hasFilterFn || customFilters?.has(def.id) == true)
65
- // ((hasFilterFn && hasAcceptableColumnType) || customFilters?.has(def.id) == true) // removed hasAcceptableColumnType due to it being redundant
68
+ def.allowFiltering &&
69
+ (hasFilterFn || hasDeclaredFilterType || customFilters?.has(def.id) == true)
66
70
  );
67
71
 
68
72
  const isNumeric = $derived(
@@ -687,8 +691,8 @@
687
691
  transition: line-height 0.2s ease, height 0.2s ease;
688
692
  --input-border: none;
689
693
  --input-height: var(--height);
690
- white-space: nowrap;
691
- overflow-x: clip;
694
+ white-space: var(--cell-white-space, nowrap);
695
+ overflow-x: var(--cell-overflow-x, clip);
692
696
  text-overflow: ellipsis;
693
697
  position: relative;
694
698
  padding-left: 0.75rem;
@@ -697,7 +701,8 @@
697
701
  border-bottom: solid 1px #cbd4da;
698
702
  box-sizing: border-box;
699
703
  width: 100%;
700
- height: var(--height);
704
+ height: var(--cell-height, var(--height));
705
+ min-height: var(--cell-min-height, var(--height));
701
706
  }
702
707
 
703
708
  .input-cell {
@@ -56,8 +56,8 @@ which reads either "Highlight row N" or "Unhighlight row N" depending on state.
56
56
  transition: line-height 0.2s ease, height 0.2s ease;
57
57
  --input-border: none;
58
58
  --input-height: var(--height);
59
- white-space: nowrap;
60
- overflow-x: clip;
59
+ white-space: var(--cell-white-space, nowrap);
60
+ overflow-x: var(--cell-overflow-x, clip);
61
61
  text-overflow: ellipsis;
62
62
  position: relative;
63
63
  padding-left: 0.75rem;
@@ -66,7 +66,8 @@ which reads either "Highlight row N" or "Unhighlight row N" depending on state.
66
66
  border-bottom: solid 1px #cbd4da;
67
67
  box-sizing: border-box;
68
68
  width: 100%;
69
- height: var(--height);
69
+ height: var(--cell-height, var(--height));
70
+ min-height: var(--cell-min-height, var(--height));
70
71
  }
71
72
 
72
73
  .highlight-content {
@@ -172,8 +172,8 @@
172
172
  transition: line-height 0.2s ease, height 0.2s ease;
173
173
  --input-border: none;
174
174
  --input-height: var(--height);
175
- white-space: nowrap;
176
- overflow-x: clip;
175
+ white-space: var(--cell-white-space, nowrap);
176
+ overflow-x: var(--cell-overflow-x, clip);
177
177
  text-overflow: ellipsis;
178
178
  position: relative;
179
179
  padding-left: 0.75rem;
@@ -182,7 +182,8 @@
182
182
  border-bottom: solid 1px #cbd4da;
183
183
  box-sizing: border-box;
184
184
  width: 100%;
185
- height: var(--height);
185
+ height: var(--cell-height, var(--height));
186
+ min-height: var(--cell-min-height, var(--height));
186
187
  }
187
188
 
188
189
  .focusable.multifocus,
@@ -117,8 +117,8 @@
117
117
  transition: line-height 0.2s ease, height 0.2s ease;
118
118
  --input-border: none;
119
119
  --input-height: var(--height);
120
- white-space: nowrap;
121
- overflow-x: clip;
120
+ white-space: var(--cell-white-space, nowrap);
121
+ overflow-x: var(--cell-overflow-x, clip);
122
122
  text-overflow: ellipsis;
123
123
  position: relative;
124
124
  padding-left: 0.75rem;
@@ -127,7 +127,8 @@
127
127
  border-bottom: solid 1px #cbd4da;
128
128
  box-sizing: border-box;
129
129
  width: 100%;
130
- height: var(--height);
130
+ height: var(--cell-height, var(--height));
131
+ min-height: var(--cell-min-height, var(--height));
131
132
  }
132
133
 
133
134
  .focusable.multifocus,
@@ -125,8 +125,8 @@
125
125
  transition: line-height 0.2s ease, height 0.2s ease;
126
126
  --input-border: none;
127
127
  --input-height: var(--height);
128
- white-space: nowrap;
129
- overflow-x: clip;
128
+ white-space: var(--cell-white-space, nowrap);
129
+ overflow-x: var(--cell-overflow-x, clip);
130
130
  text-overflow: ellipsis;
131
131
  position: relative;
132
132
  padding-left: 0.75rem;
@@ -135,7 +135,8 @@
135
135
  border-bottom: solid 1px #cbd4da;
136
136
  box-sizing: border-box;
137
137
  width: 100%;
138
- height: var(--height);
138
+ height: var(--cell-height, var(--height));
139
+ min-height: var(--cell-min-height, var(--height));
139
140
  }
140
141
 
141
142
  .focusable {
@@ -201,8 +201,8 @@
201
201
  transition: line-height 0.2s ease, height 0.2s ease;
202
202
  --input-border: none;
203
203
  --input-height: var(--height);
204
- white-space: nowrap;
205
- overflow-x: clip;
204
+ white-space: var(--cell-white-space, nowrap);
205
+ overflow-x: var(--cell-overflow-x, clip);
206
206
  text-overflow: ellipsis;
207
207
  position: relative;
208
208
  padding-left: 0.75rem;
@@ -211,7 +211,8 @@
211
211
  border-bottom: solid 1px #cbd4da;
212
212
  box-sizing: border-box;
213
213
  width: 100%;
214
- height: var(--height);
214
+ height: var(--cell-height, var(--height));
215
+ min-height: var(--cell-min-height, var(--height));
215
216
  }
216
217
 
217
218
  .focusable.multifocus,
@@ -110,8 +110,8 @@
110
110
  transition: line-height 0.2s ease, height 0.2s ease;
111
111
  --input-border: none;
112
112
  --input-height: var(--height);
113
- white-space: nowrap;
114
- overflow-x: clip;
113
+ white-space: var(--cell-white-space, nowrap);
114
+ overflow-x: var(--cell-overflow-x, clip);
115
115
  text-overflow: ellipsis;
116
116
  position: relative;
117
117
  padding-left: 0.75rem;
@@ -120,7 +120,8 @@
120
120
  border-bottom: solid 1px #cbd4da;
121
121
  box-sizing: border-box;
122
122
  width: 100%;
123
- height: var(--height);
123
+ height: var(--cell-height, var(--height));
124
+ min-height: var(--cell-min-height, var(--height));
124
125
  }
125
126
 
126
127
  .focusable.multifocus,
@@ -131,8 +131,8 @@
131
131
  transition: line-height 0.2s ease, height 0.2s ease;
132
132
  --input-border: none;
133
133
  --input-height: var(--height);
134
- white-space: nowrap;
135
- overflow-x: clip;
134
+ white-space: var(--cell-white-space, nowrap);
135
+ overflow-x: var(--cell-overflow-x, clip);
136
136
  text-overflow: ellipsis;
137
137
  position: relative;
138
138
  padding-left: 0.75rem;
@@ -141,7 +141,8 @@
141
141
  border-bottom: solid 1px #cbd4da;
142
142
  box-sizing: border-box;
143
143
  width: 100%;
144
- height: var(--height);
144
+ height: var(--cell-height, var(--height));
145
+ min-height: var(--cell-min-height, var(--height));
145
146
  }
146
147
 
147
148
  input[type=checkbox] {
@@ -251,8 +251,8 @@
251
251
  transition: line-height 0.2s ease, height 0.2s ease;
252
252
  --input-border: none;
253
253
  --input-height: var(--height);
254
- white-space: nowrap;
255
- overflow-x: clip;
254
+ white-space: var(--cell-white-space, nowrap);
255
+ overflow-x: var(--cell-overflow-x, clip);
256
256
  text-overflow: ellipsis;
257
257
  position: relative;
258
258
  padding-left: 0.75rem;
@@ -261,7 +261,8 @@
261
261
  border-bottom: solid 1px #cbd4da;
262
262
  box-sizing: border-box;
263
263
  width: 100%;
264
- height: var(--height);
264
+ height: var(--cell-height, var(--height));
265
+ min-height: var(--cell-min-height, var(--height));
265
266
  }
266
267
 
267
268
  .focusable.multifocus,
@@ -221,8 +221,8 @@
221
221
  transition: line-height 0.2s ease, height 0.2s ease;
222
222
  --input-border: none;
223
223
  --input-height: var(--height);
224
- white-space: nowrap;
225
- overflow-x: clip;
224
+ white-space: var(--cell-white-space, nowrap);
225
+ overflow-x: var(--cell-overflow-x, clip);
226
226
  text-overflow: ellipsis;
227
227
  position: relative;
228
228
  padding-left: 0.75rem;
@@ -231,7 +231,8 @@
231
231
  border-bottom: solid 1px #cbd4da;
232
232
  box-sizing: border-box;
233
233
  width: 100%;
234
- height: var(--height);
234
+ height: var(--cell-height, var(--height));
235
+ min-height: var(--cell-min-height, var(--height));
235
236
  }
236
237
 
237
238
  .focusable.multifocus,
@@ -262,8 +262,8 @@
262
262
  transition: line-height 0.2s ease, height 0.2s ease;
263
263
  --input-border: none;
264
264
  --input-height: var(--height);
265
- white-space: nowrap;
266
- overflow-x: clip;
265
+ white-space: var(--cell-white-space, nowrap);
266
+ overflow-x: var(--cell-overflow-x, clip);
267
267
  text-overflow: ellipsis;
268
268
  position: relative;
269
269
  padding-left: 0.75rem;
@@ -272,7 +272,8 @@
272
272
  border-bottom: solid 1px #cbd4da;
273
273
  box-sizing: border-box;
274
274
  width: 100%;
275
- height: var(--height);
275
+ height: var(--cell-height, var(--height));
276
+ min-height: var(--cell-min-height, var(--height));
276
277
  }
277
278
 
278
279
  .focusable.multifocus,
@@ -184,8 +184,8 @@
184
184
  transition: line-height 0.2s ease, height 0.2s ease;
185
185
  --input-border: none;
186
186
  --input-height: var(--height);
187
- white-space: nowrap;
188
- overflow-x: clip;
187
+ white-space: var(--cell-white-space, nowrap);
188
+ overflow-x: var(--cell-overflow-x, clip);
189
189
  text-overflow: ellipsis;
190
190
  position: relative;
191
191
  padding-left: 0.75rem;
@@ -194,7 +194,8 @@
194
194
  border-bottom: solid 1px #cbd4da;
195
195
  box-sizing: border-box;
196
196
  width: 100%;
197
- height: var(--height);
197
+ height: var(--cell-height, var(--height));
198
+ min-height: var(--cell-min-height, var(--height));
198
199
  }
199
200
 
200
201
  input[type=checkbox] {
@@ -234,8 +234,8 @@
234
234
  transition: line-height 0.2s ease, height 0.2s ease;
235
235
  --input-border: none;
236
236
  --input-height: var(--height);
237
- white-space: nowrap;
238
- overflow-x: clip;
237
+ white-space: var(--cell-white-space, nowrap);
238
+ overflow-x: var(--cell-overflow-x, clip);
239
239
  text-overflow: ellipsis;
240
240
  position: relative;
241
241
  padding-left: 0.75rem;
@@ -244,7 +244,8 @@
244
244
  border-bottom: solid 1px #cbd4da;
245
245
  box-sizing: border-box;
246
246
  width: 100%;
247
- height: var(--height);
247
+ height: var(--cell-height, var(--height));
248
+ min-height: var(--cell-min-height, var(--height));
248
249
  }
249
250
 
250
251
  .focusable.multifocus,
@@ -202,8 +202,8 @@
202
202
  transition: line-height 0.2s ease, height 0.2s ease;
203
203
  --input-border: none;
204
204
  --input-height: var(--height);
205
- white-space: nowrap;
206
- overflow-x: clip;
205
+ white-space: var(--cell-white-space, nowrap);
206
+ overflow-x: var(--cell-overflow-x, clip);
207
207
  text-overflow: ellipsis;
208
208
  position: relative;
209
209
  padding-left: 0.75rem;
@@ -212,7 +212,8 @@
212
212
  border-bottom: solid 1px #cbd4da;
213
213
  box-sizing: border-box;
214
214
  width: 100%;
215
- height: var(--height);
215
+ height: var(--cell-height, var(--height));
216
+ min-height: var(--cell-min-height, var(--height));
216
217
  }
217
218
 
218
219
  .focusable.multifocus,
@@ -188,8 +188,8 @@
188
188
  transition: line-height 0.2s ease, height 0.2s ease;
189
189
  --input-border: none;
190
190
  --input-height: var(--height);
191
- white-space: nowrap;
192
- overflow-x: clip;
191
+ white-space: var(--cell-white-space, nowrap);
192
+ overflow-x: var(--cell-overflow-x, clip);
193
193
  text-overflow: ellipsis;
194
194
  position: relative;
195
195
  padding-left: 0.75rem;
@@ -198,7 +198,8 @@
198
198
  border-bottom: solid 1px #cbd4da;
199
199
  box-sizing: border-box;
200
200
  width: 100%;
201
- height: var(--height);
201
+ height: var(--cell-height, var(--height));
202
+ min-height: var(--cell-min-height, var(--height));
202
203
  }
203
204
 
204
205
  .focusable {
@@ -153,6 +153,19 @@
153
153
  // `innerTableName`. Generating this once per row prevents localStorage
154
154
  // preset keys from accumulating UUID-keyed garbage every expand toggle.
155
155
  const fallbackInnerTableName = generateWeakId<ScoriaStorageKey>();
156
+
157
+ /**
158
+ * Inline style appended to a cell's `style="..."` when its column opts
159
+ * into `wrapValue`. The hooks switch the leaf cell's `white-space`,
160
+ * `overflow-x`, and `height` to wrap-friendly values. Implemented as
161
+ * CSS-variable overrides so the table-cell-basic mixin in
162
+ * `_mixins.scss` consumes them via `var(--cell-* , fallback)`.
163
+ */
164
+ function cellWrapStyle(cell: TableCell<T>): string {
165
+ return cell.column.columnDef.wrapValue
166
+ ? '--cell-white-space: normal; --cell-overflow-x: visible; --cell-height: auto; --cell-min-height: var(--height);'
167
+ : '';
168
+ }
156
169
  </script>
157
170
 
158
171
  <div
@@ -187,7 +200,7 @@
187
200
  <div
188
201
  role="cell"
189
202
  class="cell pinned-left"
190
- style="left: {leftOffsets[index]}px"
203
+ style="left: {leftOffsets[index]}px; {cellWrapStyle(cell)}"
191
204
  >
192
205
  <TableColumn
193
206
  {cell}
@@ -200,6 +213,7 @@
200
213
  <div
201
214
  role="cell"
202
215
  class="cell"
216
+ style={cellWrapStyle(cell)}
203
217
  >
204
218
  <TableColumn
205
219
  {cell}
@@ -212,7 +226,7 @@
212
226
  <div
213
227
  role="cell"
214
228
  class="cell pinned-right"
215
- style="right: {rightOffsets[index]}px"
229
+ style="right: {rightOffsets[index]}px; {cellWrapStyle(cell)}"
216
230
  >
217
231
  <TableColumn
218
232
  {cell}
@@ -109,6 +109,8 @@ function commonProps(opts, kind) {
109
109
  // per-kind differentiation the factory just put in place.
110
110
  minSize: opts.minWidth ?? defaultWidth,
111
111
  width: opts.width ?? defaultWidth,
112
+ maxWidth: opts.maxWidth,
113
+ wrapValue: opts.wrapValue,
112
114
  allowSorting: opts.allowSorting,
113
115
  allowFiltering: opts.allowFiltering,
114
116
  defaultHidden: opts.defaultHidden,
@@ -50,8 +50,25 @@
50
50
 
51
51
  const hasFilterFn = $derived(!!def.filterFn && typeof def.filterFn === 'function');
52
52
 
53
+ // A column declares it is filterable when it either (a) has a local
54
+ // `filterFn` (set on AccessorDef subclasses, and on Display/Bubble/
55
+ // Progress defs whose underlying data repo is local), or (b) declares
56
+ // a `filterValueType` (in which case the server is expected to do
57
+ // the filtering and the UI just renders an input of the matching
58
+ // type), or (c) is keyed in `customFilters` (remote filter chips
59
+ // supplied via `defsWrapper.remoteFilters`).
60
+ //
61
+ // Without case (b) a remote-pagination Table would silently hide
62
+ // every typed column from the quick-filter row and the advanced
63
+ // filter panel - `paginationRepo.dateFilter` and friends are only
64
+ // populated on LOCAL data repositories, so `setupDefaultColumnDefs`
65
+ // assigns `def.filterFn = undefined` for every typed column and
66
+ // the bare `hasFilterFn` gate would lock the input out.
67
+ const hasDeclaredFilterType = $derived(def.filterValueType != null);
68
+
53
69
  const isSearchable = $derived(
54
- def.allowFiltering && (hasFilterFn || customFilters?.has(def.id) == true)
70
+ def.allowFiltering &&
71
+ (hasFilterFn || hasDeclaredFilterType || customFilters?.has(def.id) == true)
55
72
  );
56
73
 
57
74
  const isSelect = $derived(
@@ -356,17 +356,17 @@
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` (default): `minmax(width, max-content)`.
360
- // The column is at least `width` wide (the per-kind default
361
- // set by the column factory, or any explicit `width` the caller
362
- // supplied) and grows up to its content's natural width. This
363
- // mirrors the legacy `<table>` element's auto-layout: columns
364
- // visually differentiate by content rather than collapsing to
365
- // equal `1fr` shares of leftover space. The grid container
366
- // (`.datatable-grid`) has `min-width: max-content` and the
367
- // scroll host (`.datatable`) has `overflow-x: auto`, so when
368
- // the summed track widths exceed the viewport the table
369
- // scrolls horizontally rather than crushing every column down.
359
+ // - `userResized = false` (default): `minmax(width, maxWidth ?? 1fr)`.
360
+ // The column is at least `width` wide and grows to share any
361
+ // leftover horizontal space with its sibling tracks. If the
362
+ // column has a `maxWidth`, that pixel value is the upper bound
363
+ // instead - the column never grows past `maxWidth`, and cells
364
+ // whose content exceeds the track ellipsise (or wrap, when the
365
+ // column opts in to `wrapValue`). The `1fr` upper bound was
366
+ // chosen over `max-content` because `max-content` is unstable
367
+ // under row virtualisation: tracks resize as rows scroll in
368
+ // and out of the rendered window because the auto-min/max
369
+ // consults only the currently-rendered cells.
370
370
  // - `userResized = true`: `${width}px` (fixed). The column sits
371
371
  // at exactly the size the user dragged it to, and dragging the
372
372
  // handle again only changes this column.
@@ -377,10 +377,16 @@
377
377
  // accurate sticky positions in both states.
378
378
  const colsTemplate = $derived.by(() => {
379
379
  void tableContext.columnSizing;
380
- const track = (col: { columnDef: { width: number; userResized: boolean } }) =>
381
- col.columnDef.userResized
382
- ? `${col.columnDef.width}px`
383
- : `minmax(${col.columnDef.width}px, max-content)`;
380
+ const track = (col: {
381
+ columnDef: { width: number; maxWidth?: number; userResized: boolean };
382
+ }) => {
383
+ if (col.columnDef.userResized) {
384
+ return `${col.columnDef.width}px`;
385
+ }
386
+ const upper =
387
+ col.columnDef.maxWidth != null ? `${col.columnDef.maxWidth}px` : '1fr';
388
+ return `minmax(${col.columnDef.width}px, ${upper})`;
389
+ };
384
390
  const tracks: Array<string> = ['20px'];
385
391
  for (const col of leftColumns) {
386
392
  tracks.push(track(col));
@@ -48,6 +48,16 @@ export interface ColumnDefProps<T extends object, in FilterFnType, out OptionsTy
48
48
  minSize?: Pixels;
49
49
  /** Initial width in pixels. Defaults to `minSize`. */
50
50
  width?: Pixels;
51
+ /** Maximum width in pixels. When set, caps the grid track at this
52
+ * value (replacing the default `1fr` upper bound on the track).
53
+ * Cell content beyond the track is ellipsised, or wraps when
54
+ * `wrapValue` is also set. */
55
+ maxWidth?: Pixels;
56
+ /** When true, cell content that does not fit wraps onto new lines
57
+ * and the row's height grows to fit. When false (default) overflow
58
+ * is clipped with ellipsis. Surfaces as the `--wrap-value` CSS
59
+ * variable on the column track so cell SCSS picks it up. */
60
+ wrapValue?: boolean;
51
61
  /** Async-flag predicate for whether a given cell is currently editable. */
52
62
  isEditable?: (item: T, index: number) => boolean | Promise<boolean>;
53
63
  /** Whether the column may be resized by the user. Defaults to `true`. */
@@ -129,6 +139,15 @@ export declare abstract class ColumnDef<T extends object, in FilterFnType = neve
129
139
  /** Current width in pixels. Mutated by the resize handle. */
130
140
  get width(): Pixels;
131
141
  set width(v: Pixels);
142
+ private _maxWidth;
143
+ /** Maximum width in pixels. Undefined = no cap (track flexes under `1fr`). */
144
+ get maxWidth(): Pixels | undefined;
145
+ set maxWidth(v: Pixels | undefined);
146
+ private _wrapValue;
147
+ /** Whether oversized cell content wraps onto new lines (true) or is
148
+ * clipped with ellipsis (false). */
149
+ get wrapValue(): boolean;
150
+ set wrapValue(v: boolean);
132
151
  private _isResizing;
133
152
  /** Whether the resize handle is currently active. */
134
153
  get isResizing(): boolean;
@@ -36,6 +36,8 @@ export class ColumnDef {
36
36
  this.accessorFn = $derived(props.accessorFn);
37
37
  this._minSize = $state(props.minSize ?? 48);
38
38
  this._width = $state(props.width ?? props.minSize ?? 48);
39
+ this._maxWidth = $state(props.maxWidth);
40
+ this._wrapValue = $state(props.wrapValue ?? false);
39
41
  this.isEditable = $derived(props.isEditable ?? (() => Promise.resolve(false)));
40
42
  this.resizable = $derived(props.resizable ?? true);
41
43
  this.header = $derived(props.header);
@@ -89,6 +91,23 @@ export class ColumnDef {
89
91
  set width(v) {
90
92
  this._width = v;
91
93
  }
94
+ _maxWidth;
95
+ /** Maximum width in pixels. Undefined = no cap (track flexes under `1fr`). */
96
+ get maxWidth() {
97
+ return this._maxWidth;
98
+ }
99
+ set maxWidth(v) {
100
+ this._maxWidth = v;
101
+ }
102
+ _wrapValue;
103
+ /** Whether oversized cell content wraps onto new lines (true) or is
104
+ * clipped with ellipsis (false). */
105
+ get wrapValue() {
106
+ return this._wrapValue;
107
+ }
108
+ set wrapValue(v) {
109
+ this._wrapValue = v;
110
+ }
92
111
  _isResizing = $state(false);
93
112
  /** Whether the resize handle is currently active. */
94
113
  get isResizing() {
@@ -21,6 +21,18 @@ export interface BaseColumnOptions {
21
21
  minWidth?: number;
22
22
  /** Initial width in pixels. Defaults to `minWidth`. */
23
23
  width?: number;
24
+ /** Maximum width in pixels. When set, the column's grid track is
25
+ * capped at this value (instead of flexing freely under `1fr`).
26
+ * Cell content longer than the track is ellipsised by default;
27
+ * set `wrapValue: true` to make the row grow vertically and the
28
+ * content wrap onto multiple lines instead. */
29
+ maxWidth?: number;
30
+ /** When true, cell content that does not fit horizontally wraps
31
+ * onto a new line and the row's height expands to fit. When false
32
+ * (the default) overflow is clipped with `text-overflow: ellipsis`.
33
+ * Most useful when combined with `maxWidth` to clamp the track
34
+ * width and force wrapping to kick in. */
35
+ wrapValue?: boolean;
24
36
  /** Whether this column may be sorted. Defaults to true. */
25
37
  allowSorting?: boolean;
26
38
  /** Whether this column may be filtered. Defaults to true. */
@@ -1605,8 +1605,13 @@
1605
1605
  @include table-height-transition;
1606
1606
  --input-border: none;
1607
1607
  --input-height: var(--height);
1608
- white-space: nowrap;
1609
- overflow-x: clip;
1608
+ // Layout hooks driven by per-column `wrapValue` (set as
1609
+ // `--cell-white-space`, `--cell-overflow-x`, `--cell-height` on
1610
+ // the cell wrapper by TableRow / TableHead when the column opts
1611
+ // in). Defaults preserve the historical single-line-with-ellipsis
1612
+ // rendering.
1613
+ white-space: var(--cell-white-space, nowrap);
1614
+ overflow-x: var(--cell-overflow-x, clip);
1610
1615
  text-overflow: ellipsis;
1611
1616
  position: relative;
1612
1617
  padding-left: 0.75rem;
@@ -1626,7 +1631,11 @@
1626
1631
  // BubbleCell, etc.) - the visible symptom was the display
1627
1632
  // cells' bottom borders sitting 1px above the row's actual
1628
1633
  // bottom edge.
1629
- height: var(--height);
1634
+ //
1635
+ // `--cell-height` lets `wrapValue` columns override the floor to
1636
+ // `auto`, allowing the row to grow vertically to fit wrapped text.
1637
+ height: var(--cell-height, var(--height));
1638
+ min-height: var(--cell-min-height, var(--height));
1630
1639
  }
1631
1640
  }
1632
1641
 
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.12",
4
+ "version": "0.37.14",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },