@ngx-stoui/core 21.0.10 → 21.0.12

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/toolbox-grid.css CHANGED
@@ -2,15 +2,43 @@
2
2
  /**
3
3
  * EDS (Equinor Design System) Theme for @toolbox-web/grid
4
4
  *
5
- * Styles the toolbox grid to match Equinor's design system.
6
- * Supports light/dark modes via the light-dark() CSS function.
7
- * Uses EDS CSS variables (--eds_*) when available, with light-dark() fallbacks.
5
+ * Styles the toolbox grid to match Equinor's design system. Shared by
6
+ * Angular consumers (cargo-tracker-apps via `@ngx-stoui/core/toolbox-grid.css`)
7
+ * and React consumers (planning Roma app).
8
+ *
9
+ * Both `<tbw-grid>` (web component) and `<div data-tbw-grid>` are supported
10
+ * so React apps that don't import the web component can still opt in to the
11
+ * theme by stamping the attribute on a wrapper.
12
+ *
13
+ * Supports light/dark modes via the light-dark() CSS function. Consumers that
14
+ * don't support dark mode (e.g. Roma) can opt out with `color-scheme: light only`
15
+ * on their root.
16
+ *
17
+ * In-cell editor coexistence:
18
+ * - Angular: Material form fields (`.mat-mdc-*`) — chrome is stripped so the
19
+ * surrounding `.tbw-editor-host` paints the visual boundary.
20
+ * - React/EDS: native EDS `<DatePicker>` / `<Autocomplete>` wrapped with
21
+ * `.tbw-eds-date-editor` / `.tbw-eds-autocomplete-editor` marker classes.
8
22
  *
9
23
  * Reference: https://eds.equinor.com/
10
24
  * Grid Theming: https://toolboxjs.com/?path=/docs/grid-theming--docs
11
25
  * Requires @toolbox-web/grid v1.3.1+
12
26
  *
13
- * Usage: "@ngx-stoui/core/toolbox-grid.css" in project.json styles array
27
+ * Usage:
28
+ * Angular: "@ngx-stoui/core/toolbox-grid.css" in project.json styles array
29
+ * React: import the compiled css, or @use this partial in a Sass entry
30
+ *
31
+ * Sections:
32
+ * 1. Theme Variables
33
+ * 2. Grid Styles (cells, editors, Material stripping, anchors, Typography reset)
34
+ * 3. Pinned cells & sticky group rows
35
+ * 4. Filter Panel
36
+ * 5. Context Menu
37
+ * 6. Overlay Panel
38
+ * 7. EDS in-cell editors (DatePicker / Autocomplete)
39
+ * 8. Empty State Overlay
40
+ * 9. Opt-ins (compact mode, thin header)
41
+ * 10. Dark Mode
14
42
  */
15
43
  /* ================================================================
16
44
  * 1. Theme Variables
@@ -22,6 +50,7 @@
22
50
  * rendered in document.body, so these variables cascade properly.
23
51
  * ================================================================ */
24
52
  tbw-grid,
53
+ [data-tbw-grid],
25
54
  .tbw-filter-panel {
26
55
  /* --- EDS Token Aliases (cascade to all children) --- */
27
56
  --_bg: var(--eds_ui_background__default, light-dark(#ffffff, #132634));
@@ -51,6 +80,7 @@ tbw-grid,
51
80
  --tbw-font-size: var(--sto-base-font-size, 13px);
52
81
  --tbw-font-size-header: var(--sto-base-font-size, 13px);
53
82
  --tbw-font-weight-header: 700;
83
+ --tbw-aggregation-font-size: 0.9em;
54
84
  /* --- Colors --- */
55
85
  --tbw-color-bg: var(--_bg);
56
86
  --tbw-color-fg: var(--_fg);
@@ -100,9 +130,16 @@ tbw-grid,
100
130
  --tbw-cell-padding: 0 var(--eds_spacing_medium, 8px);
101
131
  --tbw-cell-padding-header: 0 var(--eds_spacing_medium, 8px);
102
132
  --tbw-button-padding: 0.375rem 0.625rem;
103
- /* --- Focus --- */
133
+ /* --- Focus ---
134
+ `--tbw-focus-outline` paints the focus ring; the grid applies
135
+ `--tbw-focus-background` as the cell tint when a cell has focus. Use an
136
+ alpha-blended accent so the grid's own `.cell-focus` rule produces the
137
+ soft tint we want — no element-targeting needed. Pinned cells need a
138
+ pre-composited override (see section 3) because alpha over a sticky
139
+ opaque panel-bg would bleed scrolling content through. */
104
140
  --tbw-focus-outline: 0.5px dotted var(--_focus);
105
141
  --tbw-focus-outline-offset: -1px;
142
+ --tbw-focus-background: rgba(from var(--_accent) r g b / 8%);
106
143
  /* --- Resize Handle --- */
107
144
  --tbw-resize-handle-color: transparent;
108
145
  --tbw-resize-handle-color-hover: var(--_accent);
@@ -122,9 +159,12 @@ tbw-grid,
122
159
  rgba(0, 0, 0, 0.15),
123
160
  rgba(0, 0, 0, 0.4)
124
161
  );
125
- --tbw-filter-input-bg: var(--_bg);
126
- --tbw-filter-input-border: var(--_border);
127
- --tbw-filter-input-radius: var(--_radius);
162
+ /* Filter inputs: EDS underline style. Strip the grid's default border
163
+ and radius via variables; the underline box-shadow itself (no variable)
164
+ is applied in section 4. */
165
+ --tbw-filter-input-bg: var(--_surface);
166
+ --tbw-filter-input-border: none;
167
+ --tbw-filter-input-radius: 0;
128
168
  --tbw-filter-input-focus: var(--_focus);
129
169
  --tbw-filter-accent: var(--_accent);
130
170
  --tbw-filter-accent-fg: var(--_accent-fg);
@@ -147,17 +187,13 @@ tbw-grid,
147
187
  /* ================================================================
148
188
  * 2. Grid Styles
149
189
  *
150
- * All tbw-grid-scoped rules: compact mode, cell styling,
151
- * editor hosts, and Angular Material overrides.
190
+ * All grid-scoped rules: cell styling, editor hosts, anchors,
191
+ * Typography reset, and Angular Material overrides.
192
+ *
193
+ * Compact mode and thin-header opt-ins live in section 9.
152
194
  * ================================================================ */
153
- tbw-grid {
154
- /* --- Compact Mode --- */
155
- }
156
- tbw-grid.eds-compact {
157
- --tbw-row-height: calc(var(--sto-base-font-size, 13px) * 1.385);
158
- --tbw-header-height: calc(var(--sto-base-font-size, 13px) * 1.769);
159
- }
160
- tbw-grid {
195
+ tbw-grid,
196
+ [data-tbw-grid] {
161
197
  /* --- Angular Material overrides for in-grid editors --- */
162
198
  --mat-checkbox-state-layer-size: 20px;
163
199
  --mdc-filled-text-field-container-color: transparent;
@@ -168,57 +204,130 @@ tbw-grid {
168
204
  --mdc-outlined-text-field-focus-outline-color: transparent;
169
205
  --mdc-outlined-text-field-hover-outline-color: transparent;
170
206
  }
171
- tbw-grid .mat-mdc-icon-button.mat-mdc-button-base {
207
+ tbw-grid .mat-mdc-icon-button.mat-mdc-button-base,
208
+ [data-tbw-grid] .mat-mdc-icon-button.mat-mdc-button-base {
172
209
  --mdc-icon-button-state-layer-size: 28px;
173
210
  --mat-icon-button-state-layer-size: 28px;
174
211
  }
175
- tbw-grid {
212
+ tbw-grid,
213
+ [data-tbw-grid] {
176
214
  /* --- Toolbar --- */
177
215
  }
178
- tbw-grid .tbw-toolbar-content-slot {
216
+ tbw-grid .tbw-toolbar-content-slot,
217
+ [data-tbw-grid] .tbw-toolbar-content-slot {
179
218
  display: flex;
180
219
  place-items: center;
181
220
  }
182
- tbw-grid {
221
+ tbw-grid,
222
+ [data-tbw-grid] {
183
223
  /* --- Filter button icon --- */
184
224
  }
185
- tbw-grid .tbw-filter-btn .material-icons-outlined {
225
+ tbw-grid .tbw-filter-btn .material-icons-outlined,
226
+ [data-tbw-grid] .tbw-filter-btn .material-icons-outlined {
186
227
  font-size: 1.2em;
187
228
  width: 1.2em;
188
229
  height: 1.2em;
189
230
  }
190
- tbw-grid {
231
+ tbw-grid,
232
+ [data-tbw-grid] {
191
233
  /* --- Cell defaults --- */
192
234
  }
193
- tbw-grid .cell {
235
+ tbw-grid .cell,
236
+ [data-tbw-grid] .cell {
194
237
  line-height: 1em;
195
238
  }
196
- tbw-grid {
239
+ tbw-grid,
240
+ [data-tbw-grid] {
241
+ /* Anchor tags rendered inside cells (e.g. deep-link cells) should read
242
+ in the same color as plain text cells. Browser UA / EDS `Typography`
243
+ would otherwise paint them blue/teal. Underline is preserved
244
+ (we only override `color`). */
245
+ }
246
+ tbw-grid .cell a,
247
+ [data-tbw-grid] .cell a {
248
+ color: var(--_fg);
249
+ }
250
+ tbw-grid,
251
+ [data-tbw-grid] {
197
252
  /* --- Numeric alignment --- */
198
253
  }
199
- tbw-grid .cell[data-type=number] {
254
+ tbw-grid .cell[data-type=number],
255
+ [data-tbw-grid] .cell[data-type=number] {
200
256
  text-align: right;
201
257
  }
202
- tbw-grid {
203
- /* --- Data cell styling & editor host --- */
204
- }
205
- tbw-grid [part=cell], tbw-grid .data-grid-row .cell {
258
+ tbw-grid,
259
+ [data-tbw-grid] {
260
+ /* --- Data cell styling & editor host ---
261
+ The grid already paints `height: var(--tbw-row-height)` and
262
+ `background: var(--tbw-focus-background)` on focused cells from its own
263
+ base layer, so we only add what the grid doesn't expose as a variable:
264
+ `font-weight` on cells, the sticky-cell focus override, and editor-host
265
+ chrome (which lives on our `.tbw-editor-host` wrapper, not on a built-in
266
+ grid class). */
267
+ }
268
+ tbw-grid [part=cell], tbw-grid .data-grid-row .cell,
269
+ [data-tbw-grid] [part=cell],
270
+ [data-tbw-grid] .data-grid-row .cell {
206
271
  font-weight: 500;
207
- height: var(--tbw-row-height);
208
- }
209
- tbw-grid [part=cell].editing, tbw-grid .data-grid-row .cell.editing {
272
+ /* Neutralize EDS `<Typography>` when used inside custom cell renderers.
273
+ Typography defaults to its own color, weight, `<p>` margin, and
274
+ a `1.429em` line-height, all of which break the grid's uniform
275
+ row appearance.
276
+
277
+ `!important` is required: EDS ships a global rule with an ID
278
+ selector (specificity 1,1,0) that wins over any class-based
279
+ chain. The third-party rule is itself a hardcoded-ID hack;
280
+ overriding with `!important` is the correct counter and stays
281
+ scoped to elements inside a grid cell. */
282
+ }
283
+ tbw-grid [part=cell] [class*=Typography__StyledTypography], tbw-grid .data-grid-row .cell [class*=Typography__StyledTypography],
284
+ [data-tbw-grid] [part=cell] [class*=Typography__StyledTypography],
285
+ [data-tbw-grid] .data-grid-row .cell [class*=Typography__StyledTypography] {
286
+ color: inherit !important;
287
+ font-family: inherit !important;
288
+ font-size: inherit !important;
289
+ font-weight: inherit !important;
290
+ line-height: inherit !important;
291
+ letter-spacing: inherit !important;
292
+ }
293
+ tbw-grid [part=cell].editing, tbw-grid .data-grid-row .cell.editing,
294
+ [data-tbw-grid] [part=cell].editing,
295
+ [data-tbw-grid] .data-grid-row .cell.editing {
210
296
  padding: 2px 1px;
211
297
  position: relative;
212
298
  }
213
- tbw-grid [part=cell].cell-focus, tbw-grid .data-grid-row .cell.cell-focus {
214
- background: rgba(from var(--tbw-color-accent) r g b/8%);
215
- }
216
- tbw-grid [part=cell], tbw-grid .data-grid-row .cell {
299
+ tbw-grid [part=cell], tbw-grid .data-grid-row .cell,
300
+ [data-tbw-grid] [part=cell],
301
+ [data-tbw-grid] .data-grid-row .cell {
302
+ /* Pinned cell focus tint.
303
+
304
+ The grid's own `.cell-focus` rule already paints
305
+ `--tbw-focus-background` (set in section 1 to an alpha-blended
306
+ accent) on any focused cell. On a sticky cell the rows behind
307
+ would scroll through that translucent tint as the user pans
308
+ horizontally, so we pre-composite the same 8% accent onto the
309
+ pinned-cell `--tbw-color-panel-bg` to keep the result fully opaque.
310
+ This is the only place we still target `.cell-focus` directly
311
+ — `color-mix` needs the panel-bg as a second color, which a
312
+ single variable can't express. */
313
+ }
314
+ tbw-grid [part=cell].cell-focus.sticky-left, tbw-grid [part=cell].cell-focus.sticky-right, tbw-grid .data-grid-row .cell.cell-focus.sticky-left, tbw-grid .data-grid-row .cell.cell-focus.sticky-right,
315
+ [data-tbw-grid] [part=cell].cell-focus.sticky-left,
316
+ [data-tbw-grid] [part=cell].cell-focus.sticky-right,
317
+ [data-tbw-grid] .data-grid-row .cell.cell-focus.sticky-left,
318
+ [data-tbw-grid] .data-grid-row .cell.cell-focus.sticky-right {
319
+ background: color-mix(in srgb, var(--_accent) 8%, var(--tbw-color-panel-bg));
320
+ }
321
+ tbw-grid [part=cell], tbw-grid .data-grid-row .cell,
322
+ [data-tbw-grid] [part=cell],
323
+ [data-tbw-grid] .data-grid-row .cell {
217
324
  /* Editor host — visual boundary for all editor types */
218
325
  }
219
- tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host {
326
+ tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host,
327
+ [data-tbw-grid] [part=cell] .tbw-editor-host,
328
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host {
220
329
  border: 1px solid var(--_border);
221
- background: var(--eds_ui_background__default, light-dark(#ffffff, #243746));
330
+ background: var(--tbw-color-bg);
222
331
  display: flex;
223
332
  align-items: center;
224
333
  width: 100%;
@@ -226,31 +335,61 @@ tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor
226
335
  box-sizing: border-box;
227
336
  padding: var(--tbw-cell-padding, 0 6px);
228
337
  }
229
- tbw-grid [part=cell] .tbw-editor-host:has(.mat-form-field-invalid), tbw-grid .data-grid-row .cell .tbw-editor-host:has(.mat-form-field-invalid) {
338
+ tbw-grid [part=cell] .tbw-editor-host:has(.mat-form-field-invalid), tbw-grid .data-grid-row .cell .tbw-editor-host:has(.mat-form-field-invalid),
339
+ [data-tbw-grid] [part=cell] .tbw-editor-host:has(.mat-form-field-invalid),
340
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host:has(.mat-form-field-invalid) {
230
341
  border-color: var(--tbw-invalid-border-color);
231
342
  }
232
- tbw-grid [part=cell] .tbw-editor-host:focus-within, tbw-grid .data-grid-row .cell .tbw-editor-host:focus-within {
343
+ tbw-grid [part=cell] .tbw-editor-host:focus-within, tbw-grid .data-grid-row .cell .tbw-editor-host:focus-within,
344
+ [data-tbw-grid] [part=cell] .tbw-editor-host:focus-within,
345
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host:focus-within {
233
346
  box-shadow: inset 0 -2px 0 0 var(--_accent);
234
347
  outline: none;
235
348
  }
236
- tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host {
349
+ tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host,
350
+ [data-tbw-grid] [part=cell] .tbw-editor-host,
351
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host {
352
+ /* Editors that bring their own full-bleed input (e.g. EDS DatePicker /
353
+ Autocomplete) opt out of the host's padding so they can stretch
354
+ to fill the cell. See section 7. */
355
+ }
356
+ tbw-grid [part=cell] .tbw-editor-host:has(.tbw-eds-date-editor), tbw-grid [part=cell] .tbw-editor-host:has(.tbw-eds-autocomplete-editor), tbw-grid .data-grid-row .cell .tbw-editor-host:has(.tbw-eds-date-editor), tbw-grid .data-grid-row .cell .tbw-editor-host:has(.tbw-eds-autocomplete-editor),
357
+ [data-tbw-grid] [part=cell] .tbw-editor-host:has(.tbw-eds-date-editor),
358
+ [data-tbw-grid] [part=cell] .tbw-editor-host:has(.tbw-eds-autocomplete-editor),
359
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host:has(.tbw-eds-date-editor),
360
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host:has(.tbw-eds-autocomplete-editor) {
361
+ padding: 0;
362
+ }
363
+ tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host,
364
+ [data-tbw-grid] [part=cell] .tbw-editor-host,
365
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host {
237
366
  /* Framework component hosts: transparent for flex layout.
238
367
  :where() for zero specificity so component :host styles can override.
239
368
  Excludes form elements and custom editor boxes. */
240
369
  }
241
- tbw-grid [part=cell] .tbw-editor-host > :where(:not(input, select, textarea, [contenteditable], .tbw-editor-box)), tbw-grid .data-grid-row .cell .tbw-editor-host > :where(:not(input, select, textarea, [contenteditable], .tbw-editor-box)) {
370
+ tbw-grid [part=cell] .tbw-editor-host > :where(:not(input, select, textarea, [contenteditable], .tbw-editor-box)), tbw-grid .data-grid-row .cell .tbw-editor-host > :where(:not(input, select, textarea, [contenteditable], .tbw-editor-box)),
371
+ [data-tbw-grid] [part=cell] .tbw-editor-host > :where(:not(input, select, textarea, [contenteditable], .tbw-editor-box)),
372
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > :where(:not(input, select, textarea, [contenteditable], .tbw-editor-box)) {
242
373
  display: contents;
243
374
  }
244
- tbw-grid [part=cell] .tbw-editor-host > .tbw-editor-box, tbw-grid .data-grid-row .cell .tbw-editor-host > .tbw-editor-box {
375
+ tbw-grid [part=cell] .tbw-editor-host > .tbw-editor-box, tbw-grid .data-grid-row .cell .tbw-editor-host > .tbw-editor-box,
376
+ [data-tbw-grid] [part=cell] .tbw-editor-host > .tbw-editor-box,
377
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > .tbw-editor-box {
245
378
  display: flex;
246
379
  align-items: center;
247
380
  width: 100%;
248
381
  height: 100%;
249
382
  }
250
- tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host {
383
+ tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host,
384
+ [data-tbw-grid] [part=cell] .tbw-editor-host,
385
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host {
251
386
  /* Simple text/number inputs */
252
387
  }
253
- tbw-grid [part=cell] .tbw-editor-host > input[type=text], tbw-grid [part=cell] .tbw-editor-host > input[type=number], tbw-grid .data-grid-row .cell .tbw-editor-host > input[type=text], tbw-grid .data-grid-row .cell .tbw-editor-host > input[type=number] {
388
+ tbw-grid [part=cell] .tbw-editor-host > input[type=text], tbw-grid [part=cell] .tbw-editor-host > input[type=number], tbw-grid .data-grid-row .cell .tbw-editor-host > input[type=text], tbw-grid .data-grid-row .cell .tbw-editor-host > input[type=number],
389
+ [data-tbw-grid] [part=cell] .tbw-editor-host > input[type=text],
390
+ [data-tbw-grid] [part=cell] .tbw-editor-host > input[type=number],
391
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > input[type=text],
392
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > input[type=number] {
254
393
  border: none;
255
394
  background: transparent;
256
395
  font: inherit;
@@ -260,10 +399,14 @@ tbw-grid [part=cell] .tbw-editor-host > input[type=text], tbw-grid [part=cell] .
260
399
  width: 100%;
261
400
  height: 100%;
262
401
  }
263
- tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host {
402
+ tbw-grid [part=cell] .tbw-editor-host, tbw-grid .data-grid-row .cell .tbw-editor-host,
403
+ [data-tbw-grid] [part=cell] .tbw-editor-host,
404
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host {
264
405
  /* Native select */
265
406
  }
266
- tbw-grid [part=cell] .tbw-editor-host > select, tbw-grid .data-grid-row .cell .tbw-editor-host > select {
407
+ tbw-grid [part=cell] .tbw-editor-host > select, tbw-grid .data-grid-row .cell .tbw-editor-host > select,
408
+ [data-tbw-grid] [part=cell] .tbw-editor-host > select,
409
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > select {
267
410
  appearance: base-select;
268
411
  border: none;
269
412
  background: transparent;
@@ -276,7 +419,9 @@ tbw-grid [part=cell] .tbw-editor-host > select, tbw-grid .data-grid-row .cell .t
276
419
  cursor: pointer;
277
420
  place-items: center;
278
421
  }
279
- tbw-grid [part=cell] .tbw-editor-host > select::picker(select), tbw-grid .data-grid-row .cell .tbw-editor-host > select::picker(select) {
422
+ tbw-grid [part=cell] .tbw-editor-host > select::picker(select), tbw-grid .data-grid-row .cell .tbw-editor-host > select::picker(select),
423
+ [data-tbw-grid] [part=cell] .tbw-editor-host > select::picker(select),
424
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > select::picker(select) {
280
425
  appearance: base-select;
281
426
  border: none;
282
427
  border-radius: 4px;
@@ -284,7 +429,9 @@ tbw-grid [part=cell] .tbw-editor-host > select::picker(select), tbw-grid .data-g
284
429
  overscroll-behavior: contain;
285
430
  box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);
286
431
  }
287
- tbw-grid [part=cell] .tbw-editor-host > select option, tbw-grid .data-grid-row .cell .tbw-editor-host > select option {
432
+ tbw-grid [part=cell] .tbw-editor-host > select option, tbw-grid .data-grid-row .cell .tbw-editor-host > select option,
433
+ [data-tbw-grid] [part=cell] .tbw-editor-host > select option,
434
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > select option {
288
435
  font: inherit;
289
436
  padding: 8px 16px;
290
437
  min-height: 36px;
@@ -292,41 +439,52 @@ tbw-grid [part=cell] .tbw-editor-host > select option, tbw-grid .data-grid-row .
292
439
  align-items: center;
293
440
  border-radius: 0;
294
441
  }
295
- tbw-grid [part=cell] .tbw-editor-host > select option:hover, tbw-grid .data-grid-row .cell .tbw-editor-host > select option:hover {
442
+ tbw-grid [part=cell] .tbw-editor-host > select option:hover, tbw-grid .data-grid-row .cell .tbw-editor-host > select option:hover,
443
+ [data-tbw-grid] [part=cell] .tbw-editor-host > select option:hover,
444
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > select option:hover {
296
445
  background-color: light-dark(rgba(0, 0, 0, 0.04), rgba(255, 255, 255, 0.08));
297
446
  }
298
- tbw-grid [part=cell] .tbw-editor-host > select option:checked, tbw-grid .data-grid-row .cell .tbw-editor-host > select option:checked {
447
+ tbw-grid [part=cell] .tbw-editor-host > select option:checked, tbw-grid .data-grid-row .cell .tbw-editor-host > select option:checked,
448
+ [data-tbw-grid] [part=cell] .tbw-editor-host > select option:checked,
449
+ [data-tbw-grid] .data-grid-row .cell .tbw-editor-host > select option:checked {
299
450
  background-color: light-dark(rgba(0, 112, 121, 0.12), rgba(151, 202, 206, 0.2));
300
451
  color: inherit;
301
452
  }
302
- tbw-grid {
453
+ tbw-grid,
454
+ [data-tbw-grid] {
303
455
  /* --- Material form field stripping inside editor hosts ---
304
456
  Lower specificity than cell-scoped rules above; strips
305
457
  Angular Material chrome so .tbw-editor-host provides visuals. */
306
458
  }
307
- tbw-grid .tbw-editor-host .mat-mdc-form-field {
459
+ tbw-grid .tbw-editor-host .mat-mdc-form-field,
460
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field {
308
461
  width: 100%;
309
462
  height: 100%;
310
463
  }
311
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-text-field-wrapper {
464
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-text-field-wrapper,
465
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-text-field-wrapper {
312
466
  padding: 0 4px;
313
467
  background: transparent;
314
468
  height: 100%;
315
469
  display: flex;
316
470
  align-items: center;
317
471
  }
318
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-flex {
472
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-flex,
473
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-flex {
319
474
  height: 100%;
320
475
  display: flex;
321
476
  align-items: center;
322
477
  }
323
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-focus-overlay {
478
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-focus-overlay,
479
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-focus-overlay {
324
480
  display: none;
325
481
  }
326
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mdc-line-ripple {
482
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mdc-line-ripple,
483
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mdc-line-ripple {
327
484
  display: none;
328
485
  }
329
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-infix {
486
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-infix,
487
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-infix {
330
488
  padding: 0;
331
489
  min-height: unset;
332
490
  width: 100%;
@@ -334,57 +492,175 @@ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-form-field-infix {
334
492
  align-items: center;
335
493
  border: 0;
336
494
  }
337
- tbw-grid .tbw-editor-host .mat-mdc-form-field input.mat-mdc-input-element {
495
+ tbw-grid .tbw-editor-host .mat-mdc-form-field input.mat-mdc-input-element,
496
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field input.mat-mdc-input-element {
497
+ /* `line-height: normal` is browser/font-dependent (≈ 1.2-1.5) which
498
+ inflates the `1lh + 2 * padding` floor used by `.cell.editing`
499
+ and pushes the editing row past `--tbw-row-height`. Locking it
500
+ to 1 keeps the input the height of its font-size so the cell can
501
+ collapse to `--tbw-row-height` in compact mode. */
338
502
  height: auto;
339
- line-height: normal;
503
+ line-height: 1;
340
504
  }
341
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-select {
505
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-select,
506
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-select {
342
507
  height: 100%;
343
508
  display: flex;
344
509
  align-items: center;
345
510
  }
346
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-select-trigger {
511
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-select-trigger,
512
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-select-trigger {
347
513
  height: 100%;
348
514
  display: flex;
349
515
  align-items: center;
350
516
  }
351
- tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-select-value {
517
+ tbw-grid .tbw-editor-host .mat-mdc-form-field .mat-mdc-select-value,
518
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field .mat-mdc-select-value {
352
519
  display: flex;
353
520
  align-items: center;
354
521
  }
355
- tbw-grid .tbw-editor-host .mat-mdc-form-field-subscript-wrapper {
522
+ tbw-grid .tbw-editor-host .mat-mdc-form-field-subscript-wrapper,
523
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-form-field-subscript-wrapper {
356
524
  display: none;
357
525
  }
358
- tbw-grid .tbw-editor-host .editor-checkbox {
526
+ tbw-grid .tbw-editor-host .editor-checkbox,
527
+ [data-tbw-grid] .tbw-editor-host .editor-checkbox {
359
528
  display: flex;
360
529
  align-items: center;
361
530
  justify-content: center;
362
531
  height: 100%;
363
532
  }
364
- tbw-grid .tbw-editor-host .mat-mdc-option.mdc-list-item {
533
+ tbw-grid .tbw-editor-host .mat-mdc-option.mdc-list-item,
534
+ [data-tbw-grid] .tbw-editor-host .mat-mdc-option.mdc-list-item {
365
535
  background: var(--mat-autocomplete-background-color, var(--mat-sys-surface-container));
366
536
  }
537
+ tbw-grid,
538
+ [data-tbw-grid] {
539
+ /* ================================================================
540
+ * 3. Pinned cells & sticky group rows
541
+ * ================================================================ */
542
+ /* Row hover on pinned cells.
367
543
 
368
- /* Compact mode when applied from a parent element */
369
- .eds-compact tbw-grid {
370
- --tbw-row-height: calc(var(--sto-base-font-size, 13px) * 1.385);
371
- --tbw-header-height: calc(var(--sto-base-font-size, 13px) * 1.769);
544
+ Pinned cells (`.sticky-left` / `.sticky-right`) carry an opaque
545
+ `--tbw-color-panel-bg` so non-sticky content scrolling behind
546
+ them can't bleed through. That opaque fill also masks the row's
547
+ `:hover` tint, making pinned columns visually disconnected from
548
+ the rest of the row. Repaint them with the row-hover color to
549
+ restore continuity. Wrapped in `@media (hover: hover)` to mirror
550
+ the grid's own row-hover rule and avoid sticky tap-state flicker
551
+ on touch devices. */
552
+ }
553
+ @media (hover: hover) {
554
+ tbw-grid .data-grid-row:hover > .cell.sticky-left, tbw-grid .data-grid-row:hover > .cell.sticky-right,
555
+ [data-tbw-grid] .data-grid-row:hover > .cell.sticky-left,
556
+ [data-tbw-grid] .data-grid-row:hover > .cell.sticky-right {
557
+ background: var(--tbw-color-row-hover);
558
+ }
559
+ tbw-grid,
560
+ [data-tbw-grid] {
561
+ /* Hover + focus on a pinned cell: keep the focus tint visible by
562
+ flattening the same 8% accent over the row-hover color. */
563
+ }
564
+ tbw-grid .data-grid-row:hover > .cell.cell-focus.sticky-left, tbw-grid .data-grid-row:hover > .cell.cell-focus.sticky-right,
565
+ [data-tbw-grid] .data-grid-row:hover > .cell.cell-focus.sticky-left,
566
+ [data-tbw-grid] .data-grid-row:hover > .cell.cell-focus.sticky-right {
567
+ background: color-mix(in srgb, var(--tbw-color-accent) 8%, var(--tbw-color-row-hover));
568
+ }
569
+ }
570
+ tbw-grid,
571
+ [data-tbw-grid] {
572
+ /* Sticky group-row chrome.
573
+
574
+ The grouping-rows feature renders a full-width banner row for each
575
+ group boundary: a `.data-grid-row.group-row` whose only child is a
576
+ single `.cell.group-full` (spanning `grid-column: 1 / -1`) containing
577
+ `.group-toggle`, `.group-label`, `.group-count`, and optional
578
+ `.group-aggregates`. On a horizontally-scrollable grid the cell is
579
+ as wide as the row, so when the user scrolls right the entire chrome
580
+ slides off the left edge.
581
+
582
+ Approach: shrink the cell to its content width and pin it to the left
583
+ with `position: sticky; left: 0`. The chrome children keep their
584
+ inline flow — we never touch them individually, so new chrome
585
+ elements in a future grid version "just work".
586
+
587
+ Two things move from the cell up to the row:
588
+ 1. Background — the cell no longer spans the row, so the row paints
589
+ the banner tint.
590
+ 2. Full-row span override — the cell still has `grid-column: 1 / -1`
591
+ from the grid runtime; `width: max-content !important` shrinks
592
+ the rendered box while leaving the grid-track placement intact.
593
+
594
+ Why we override `overflow: hidden` on the cell:
595
+ @toolbox-web/grid sets `overflow: hidden` on every `.cell` to clip
596
+ content. Per the CSS Position spec, that establishes a scroll
597
+ container, which traps the cell's own sticky positioning inside the
598
+ (non-scrolling) cell box. `overflow: visible` lets the sticky context
599
+ bubble up past the row, past `.rows-viewport` (`overflow: clip` —
600
+ non-scrollable), all the way to `.tbw-scroll-area` (the actual
601
+ horizontal scroller) where sticky engages. */
602
+ }
603
+ tbw-grid .data-grid-row.group-row,
604
+ [data-tbw-grid] .data-grid-row.group-row {
605
+ background: var(--tbw-color-header-bg, var(--tbw-color-panel-bg, transparent));
606
+ }
607
+ tbw-grid .data-grid-row.group-row > .cell.group-full,
608
+ [data-tbw-grid] .data-grid-row.group-row > .cell.group-full {
609
+ overflow: visible;
610
+ position: sticky;
611
+ left: 0;
612
+ z-index: 2;
613
+ width: max-content !important;
614
+ max-width: 100%;
615
+ background: transparent;
616
+ }
617
+ tbw-grid .data-grid-row.group-row .group-count,
618
+ [data-tbw-grid] .data-grid-row.group-row .group-count {
619
+ padding: 0 0.5rem;
620
+ }
621
+ tbw-grid,
622
+ [data-tbw-grid] {
623
+ /* Sticky aggregation (footer) row.
624
+
625
+ The bottom aggregation row (`.tbw-footer > .tbw-aggregation-rows >
626
+ .tbw-aggregation-row > .tbw-aggregation-cell.tbw-aggregation-cell-full`)
627
+ has the same shape as a group row: a full-width cell that spans the
628
+ entire scrollable area (`grid-column: 1 / -1`, width = scrollWidth).
629
+ When the user scrolls horizontally the totals/label slide off the
630
+ left edge.
631
+
632
+ Same fix as `.group-row > .cell.group-full`: shrink the cell to its
633
+ content width, pin it to the left with `position: sticky; left: 0`,
634
+ and override the grid's `overflow: hidden` so the sticky context can
635
+ bubble up past the row to the scroll container.
636
+
637
+ `.tbw-footer` itself is already `position: sticky; bottom: 0` from
638
+ the grid runtime — we only need to handle horizontal stickiness. */
639
+ }
640
+ tbw-grid .tbw-aggregation-row > .tbw-aggregation-cell-full,
641
+ [data-tbw-grid] .tbw-aggregation-row > .tbw-aggregation-cell-full {
642
+ overflow: visible;
643
+ position: sticky;
644
+ left: 0;
645
+ z-index: 2;
646
+ width: max-content !important;
647
+ max-width: 100%;
648
+ background: transparent;
372
649
  }
373
650
 
374
651
  /* ================================================================
375
- * 3. Filter Panel Styles
652
+ * 4. Filter Panel Styles
376
653
  * ================================================================ */
377
654
  .tbw-filter-panel {
378
655
  max-width: none;
379
656
  max-height: none;
380
- /* EDS underline inputs */
657
+ /* EDS underline inputs — the bg/border/radius are stripped via
658
+ `--tbw-filter-input-*` variables in section 1. The underline
659
+ `box-shadow` and height have no variable equivalent. */
381
660
  }
382
661
  .tbw-filter-panel .tbw-filter-search-input, .tbw-filter-panel .tbw-filter-range-input, .tbw-filter-panel .tbw-filter-date-input {
383
662
  height: var(--tbw-row-height);
384
- border: none;
385
- border-radius: 0;
386
663
  box-shadow: inset 0px -1px 0px 0px var(--_fg-muted);
387
- background: var(--_surface);
388
664
  outline: 1px solid transparent;
389
665
  outline-offset: 0px;
390
666
  }
@@ -459,7 +735,7 @@ tbw-grid .tbw-editor-host .mat-mdc-option.mdc-list-item {
459
735
  }
460
736
 
461
737
  /* ================================================================
462
- * 4. Context Menu
738
+ * 5. Context Menu
463
739
  *
464
740
  * Appended to document.body (outside tbw-grid).
465
741
  * CSS variables are copied from tbw-grid at render time.
@@ -514,7 +790,7 @@ tbw-grid .tbw-editor-host .mat-mdc-option.mdc-list-item {
514
790
  }
515
791
 
516
792
  /* ================================================================
517
- * 5. Overlay Panel (BaseOverlayEditor)
793
+ * 6. Overlay Panel (BaseOverlayEditor)
518
794
  * ================================================================ */
519
795
  .tbw-overlay-panel {
520
796
  --tbw-overlay-bg: var(
@@ -531,9 +807,249 @@ tbw-grid .tbw-editor-host .mat-mdc-option.mdc-list-item {
531
807
  }
532
808
 
533
809
  /* ================================================================
534
- * 6. Dark Mode
810
+ * 7. EDS in-cell editors — DatePicker and Autocomplete
811
+ *
812
+ * Marker classes:
813
+ * `.tbw-eds-date-editor` — wrapper around EDS <DatePicker>
814
+ * `.tbw-eds-autocomplete-editor` — wrapper around EDS <Autocomplete>
815
+ *
816
+ * Used by React consumers that render EDS form components inside grid
817
+ * cell editors (typically inside `<EdsProvider density="compact">`).
818
+ * EDS wraps each field in an InputWrapper with a label and helper
819
+ * area — none of which we want inside a row-height cell. We strip the
820
+ * chrome, hide the label/helper for sighted users (kept for screen
821
+ * readers), and stretch the inner field stack to fill the cell.
822
+ *
823
+ * Popover positioning fix (applies to both):
824
+ * EDS uses the native popover API (`popover="manual"`) + floating-ui
825
+ * to place the calendar / options dropdown. Inline EDS sets
826
+ * `position: absolute` with viewport-anchored top/left from the
827
+ * trigger's getBoundingClientRect. That works in plain DOM, but
828
+ * `tbw-grid` virtualises rows with `transform` which creates a
829
+ * containing block. Once the popover enters the browser top-layer
830
+ * (`.showPopover()`), the spec says its containing block is the
831
+ * viewport — but floating-ui's inset values assume the regular
832
+ * containing-block cascade. The two coordinate systems mismatch and
833
+ * the popover renders off-screen.
834
+ *
835
+ * Forcing `position: fixed` aligns the popover's containing block
836
+ * with floating-ui's viewport math. The inset reset overrides the
837
+ * browser's default `[popover]:popover-open { inset: 0 }` rule that
838
+ * would otherwise stretch the popover full-viewport.
839
+ *
840
+ * Harmless when EDS is absent (Angular consumers don't ship these
841
+ * markers), so safe to include in the shared theme.
842
+ * ================================================================ */
843
+ /* Shared chrome-stripping + popover-positioning rules. Applied to both
844
+ editor wrappers via @extend so the rules stay co-located with their
845
+ shared docstring above. */
846
+ .tbw-eds-autocomplete-editor, .tbw-eds-date-editor {
847
+ width: 100%;
848
+ height: 100%;
849
+ display: flex;
850
+ align-items: stretch;
851
+ /* Hide the visually-rendered EDS label/helper, keep them for a11y. */
852
+ }
853
+ .tbw-eds-autocomplete-editor label, .tbw-eds-date-editor label,
854
+ .tbw-eds-autocomplete-editor [class*=HelperText],
855
+ .tbw-eds-date-editor [class*=HelperText] {
856
+ position: absolute;
857
+ width: 1px;
858
+ height: 1px;
859
+ padding: 0;
860
+ margin: -1px;
861
+ overflow: hidden;
862
+ clip: rect(0, 0, 0, 0);
863
+ white-space: nowrap;
864
+ border: 0;
865
+ }
866
+ .tbw-eds-autocomplete-editor, .tbw-eds-date-editor {
867
+ /* Calendar / options dropdown popover — see header for rationale. */
868
+ }
869
+ .tbw-eds-autocomplete-editor [popover], .tbw-eds-date-editor [popover] {
870
+ position: fixed !important;
871
+ right: auto !important;
872
+ bottom: auto !important;
873
+ width: max-content !important;
874
+ margin: 0 !important;
875
+ }
876
+
877
+ .tbw-eds-date-editor {
878
+ /* Stretch the EDS field stack to fill the cell vertically and strip
879
+ its own background/box-shadow underline since the surrounding
880
+ `.tbw-editor-host:focus-within` already provides the focus indicator.
881
+ `!important` beats EDS's ID-scoped rule (specificity 1,1,0).
882
+ NOTE: do not use `> div` — the calendar popover is also a direct
883
+ child once `popover="manual"` opens it, and forcing it to 100%
884
+ height stretches it to the full viewport and breaks auto-flip. */
885
+ }
886
+ .tbw-eds-date-editor [class*=InputWrapper__Container],
887
+ .tbw-eds-date-editor [class*=FieldWrapper] {
888
+ width: 100% !important;
889
+ height: 100% !important;
890
+ }
891
+ .tbw-eds-date-editor [class*=FieldWrapper] {
892
+ background: transparent !important;
893
+ box-shadow: none !important;
894
+ border: none !important;
895
+ display: flex;
896
+ align-items: center;
897
+ }
898
+
899
+ .tbw-eds-autocomplete-editor {
900
+ /* Stretch EDS field stack to fill the cell vertically and strip its
901
+ own background/underline since the editor host owns the focus ring. */
902
+ }
903
+ .tbw-eds-autocomplete-editor [class*=InputWrapper__Container],
904
+ .tbw-eds-autocomplete-editor [class*=Container] {
905
+ width: 100% !important;
906
+ height: 100% !important;
907
+ }
908
+ .tbw-eds-autocomplete-editor [class*=Container] {
909
+ background: transparent !important;
910
+ box-shadow: none !important;
911
+ border: none !important;
912
+ }
913
+
914
+ /* ================================================================
915
+ * 8. Empty State Overlay
916
+ *
917
+ * The grid's empty overlay (.tbw-empty-overlay) is absolutely
918
+ * positioned inside .rows-container. When the grid host is sized
919
+ * by content (no explicit height) and there are zero rows, the
920
+ * rows-container collapses to height 0 — leaving the overlay
921
+ * with no space and stacking the column header directly on top
922
+ * of the pinned/aggregation footer.
923
+ *
924
+ * Reserve a sensible minimum height for the rows area whenever
925
+ * the empty overlay is present, so the message has room to render
926
+ * and the header / footer separate visually.
927
+ * ================================================================ */
928
+ tbw-grid .rows-container:has(> .tbw-empty-overlay),
929
+ [data-tbw-grid] .rows-container:has(> .tbw-empty-overlay) {
930
+ min-height: var(--tbw-empty-min-height, 120px);
931
+ }
932
+ tbw-grid .tbw-empty-overlay,
933
+ [data-tbw-grid] .tbw-empty-overlay {
934
+ min-height: var(--tbw-empty-min-height, 120px);
935
+ color: var(--_fg-muted);
936
+ }
937
+
938
+ /* ================================================================
939
+ * 9. Opt-ins (compact mode, thin header)
940
+ * ================================================================ */
941
+ /* Compact mode — triggers when `.eds-compact` is on the grid itself
942
+ (`<tbw-grid class="eds-compact">`) or on any ancestor (e.g. a wrapping
943
+ section that toggles density for everything inside). */
944
+ tbw-grid.eds-compact,
945
+ [data-tbw-grid].eds-compact,
946
+ .eds-compact tbw-grid,
947
+ .eds-compact [data-tbw-grid] {
948
+ /* Multipliers are tuned against the 13px EDS base:
949
+ row 13 * 1.111 ≈ 14.4px (works once in-cell mat-icons and chip
950
+ padding are constrained — see section 2)
951
+ header 13 * 1.4 ≈ 18.2px
952
+ Apps with a larger base (e.g. 18px) get proportionally bigger:
953
+ 18 * 1.111 ≈ 20px / 18 * 1.4 ≈ 25px. */
954
+ --tbw-row-height: calc(var(--sto-base-font-size, 13px) * 1.111);
955
+ --tbw-header-height: calc(var(--sto-base-font-size, 13px) * 1.4);
956
+ /* In-cell Material icons.
957
+ Angular Material renders `<mat-icon>` as `<span class="mat-icon">` at a
958
+ hardcoded 24x24. Since `.data-grid-row` is `display: grid` and the row
959
+ track grows to fit the tallest cell content, a 24px icon would inflate
960
+ every row past `--tbw-row-height`. Constrain in-cell icons to the cell
961
+ font-size so they fit the compact row track.
962
+
963
+ Sizing trick: `font-size: 1em` keeps the glyph at the cell font-size
964
+ (13px default), then `width/height: 1em` resolves against the icon's
965
+ own font-size — producing a 13x13 box. Only applied under `.eds-compact`
966
+ so non-compact grids keep Material's standard 24px icons. */
967
+ }
968
+ tbw-grid.eds-compact .cell .mat-icon, tbw-grid.eds-compact .cell mat-icon,
969
+ [data-tbw-grid].eds-compact .cell .mat-icon,
970
+ [data-tbw-grid].eds-compact .cell mat-icon,
971
+ .eds-compact tbw-grid .cell .mat-icon,
972
+ .eds-compact tbw-grid .cell mat-icon,
973
+ .eds-compact [data-tbw-grid] .cell .mat-icon,
974
+ .eds-compact [data-tbw-grid] .cell mat-icon {
975
+ font-size: 1em;
976
+ width: 1em;
977
+ height: 1em;
978
+ line-height: 1em;
979
+ }
980
+ tbw-grid.eds-compact,
981
+ [data-tbw-grid].eds-compact,
982
+ .eds-compact tbw-grid,
983
+ .eds-compact [data-tbw-grid] {
984
+ /* In-cell editor density.
985
+ Active editors (`.cell.editing > .tbw-editor-host`) host Angular
986
+ Material form-fields. Even with all chrome stripped (see section 2),
987
+ a Material input renders at ~35px tall because of its intrinsic
988
+ padding/min-height — which then ratchets the grid's row-height
989
+ measurement upward and shrinks the visible-row count for every
990
+ other row.
991
+
992
+ In compact mode we constrain the editor to the compact row height
993
+ so editing a row no longer changes the row's painted height. */
994
+ }
995
+ tbw-grid.eds-compact .cell.editing,
996
+ [data-tbw-grid].eds-compact .cell.editing,
997
+ .eds-compact tbw-grid .cell.editing,
998
+ .eds-compact [data-tbw-grid] .cell.editing {
999
+ /* Eliminate the `1lh + 2 * padding` floor inherited from the base
1000
+ `.cell.editing` rule — the active cell follows row-height only. */
1001
+ min-height: var(--tbw-row-height);
1002
+ }
1003
+ tbw-grid.eds-compact .cell.editing .tbw-editor-host, tbw-grid.eds-compact .cell.editing .tbw-editor-host .mat-mdc-form-field, tbw-grid.eds-compact .cell.editing .tbw-editor-host .mat-mdc-text-field-wrapper, tbw-grid.eds-compact .cell.editing .tbw-editor-host .mat-mdc-form-field-flex, tbw-grid.eds-compact .cell.editing .tbw-editor-host .mat-mdc-form-field-infix,
1004
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host,
1005
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host .mat-mdc-form-field,
1006
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host .mat-mdc-text-field-wrapper,
1007
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host .mat-mdc-form-field-flex,
1008
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host .mat-mdc-form-field-infix,
1009
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host,
1010
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host .mat-mdc-form-field,
1011
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host .mat-mdc-text-field-wrapper,
1012
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host .mat-mdc-form-field-flex,
1013
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host .mat-mdc-form-field-infix,
1014
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host,
1015
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host .mat-mdc-form-field,
1016
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host .mat-mdc-text-field-wrapper,
1017
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host .mat-mdc-form-field-flex,
1018
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host .mat-mdc-form-field-infix {
1019
+ min-height: 0;
1020
+ height: 100%;
1021
+ }
1022
+ tbw-grid.eds-compact .cell.editing .tbw-editor-host input.mat-mdc-input-element, tbw-grid.eds-compact .cell.editing .tbw-editor-host .mat-mdc-select-trigger,
1023
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host input.mat-mdc-input-element,
1024
+ [data-tbw-grid].eds-compact .cell.editing .tbw-editor-host .mat-mdc-select-trigger,
1025
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host input.mat-mdc-input-element,
1026
+ .eds-compact tbw-grid .cell.editing .tbw-editor-host .mat-mdc-select-trigger,
1027
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host input.mat-mdc-input-element,
1028
+ .eds-compact [data-tbw-grid] .cell.editing .tbw-editor-host .mat-mdc-select-trigger {
1029
+ height: var(--tbw-row-height);
1030
+ min-height: 0;
1031
+ padding-top: 0;
1032
+ padding-bottom: 0;
1033
+ line-height: 1;
1034
+ }
1035
+
1036
+ /* Thin header — for grids that are sub-sections inside a larger page
1037
+ (e.g. a field-split table) where a full-height header competes
1038
+ visually with surrounding form headings.
1039
+
1040
+ Apply with: <div class="tbw-thin-header"><tbw-grid ... /></div> */
1041
+ .tbw-thin-header tbw-grid,
1042
+ .tbw-thin-header [data-tbw-grid] {
1043
+ --tbw-header-height: 28px;
1044
+ --tbw-font-weight-header: 500;
1045
+ --tbw-font-size-header: 0.75rem;
1046
+ }
1047
+
1048
+ /* ================================================================
1049
+ * 10. Dark Mode
535
1050
  * ================================================================ */
536
1051
  body.sto-dark-theme tbw-grid,
1052
+ body.sto-dark-theme [data-tbw-grid],
537
1053
  body.sto-dark-theme .tbw-filter-panel,
538
1054
  body.sto-dark-theme .tbw-context-menu,
539
1055
  body.sto-dark-theme .tbw-overlay-panel {