@zeyos/zx 2.3.0 → 4.0.0

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 (150) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/DESIGN-SYSTEM.md +96 -0
  3. package/README.md +29 -39
  4. package/dist/types/components/account-menu/account-menu.d.ts +144 -0
  5. package/dist/types/components/app-sidebar/app-sidebar.d.ts +243 -0
  6. package/dist/types/components/avatar/avatar.d.ts +100 -0
  7. package/dist/types/components/card/card.d.ts +128 -0
  8. package/dist/types/components/chart/chart.d.ts +322 -0
  9. package/dist/types/components/date-picker/month-picker.d.ts +6 -0
  10. package/dist/types/components/dialog/dialog.d.ts +9 -0
  11. package/dist/types/components/dock/dock.d.ts +495 -0
  12. package/dist/types/components/dropdown/dropdown.d.ts +2 -2
  13. package/dist/types/components/field/field.d.ts +14 -0
  14. package/dist/types/components/field-upload/field-upload.d.ts +37 -4
  15. package/dist/types/components/form/form.d.ts +25 -3
  16. package/dist/types/components/grid/grid.d.ts +172 -0
  17. package/dist/types/components/launcher/launcher.d.ts +359 -0
  18. package/dist/types/components/layout/layout.d.ts +4 -4
  19. package/dist/types/components/menu-button/menu-button.d.ts +10 -2
  20. package/dist/types/components/modal/modal.d.ts +25 -0
  21. package/dist/types/components/multi-value-editor/multi-value-editor.d.ts +7 -1
  22. package/dist/types/components/questionnaire/items.d.ts +327 -0
  23. package/dist/types/components/questionnaire/questionnaire.d.ts +449 -0
  24. package/dist/types/components/select/select.d.ts +51 -0
  25. package/dist/types/components/sheet/sheet-stack.d.ts +167 -0
  26. package/dist/types/components/sheet/sheet.d.ts +294 -0
  27. package/dist/types/components/split-view/split-view.d.ts +2 -21
  28. package/dist/types/components/table/table.d.ts +223 -15
  29. package/dist/types/components/tooltip/tooltip.d.ts +2 -2
  30. package/dist/types/components/value-list/value-list.d.ts +24 -3
  31. package/dist/types/core/dom.d.ts +122 -0
  32. package/dist/types/core/drag-axis.d.ts +111 -0
  33. package/dist/types/core/position.d.ts +4 -2
  34. package/dist/types/index.d.ts +13 -2
  35. package/dist/types/internal/app-rail.d.ts +265 -0
  36. package/dist/types/zeyos/icons.d.ts +5 -0
  37. package/dist/types/zeyos/index.d.ts +2 -1
  38. package/dist/types/zeyos/launcher.d.ts +147 -0
  39. package/dist/types/zeyos/select.d.ts +39 -0
  40. package/dist/zx-zeyos.esm.js +1870 -133
  41. package/dist/zx-zeyos.esm.min.js +1 -1
  42. package/dist/zx.css +2006 -267
  43. package/dist/zx.esm.js +8987 -2757
  44. package/dist/zx.esm.min.js +3 -3
  45. package/dist/zx.global.js +8987 -2757
  46. package/dist/zx.global.min.js +3 -3
  47. package/dist/zx.min.css +1 -1
  48. package/docs/api.json +4396 -2344
  49. package/docs/llms.md +463 -86
  50. package/docs/llms.txt +32 -19
  51. package/package.json +10 -17
  52. package/src/components/account-menu/account-menu.css +70 -0
  53. package/src/components/account-menu/account-menu.js +208 -0
  54. package/src/components/app-rail/app-rail.css +107 -0
  55. package/src/components/app-sidebar/app-sidebar.css +80 -0
  56. package/src/components/app-sidebar/app-sidebar.js +588 -0
  57. package/src/components/avatar/avatar.css +61 -0
  58. package/src/components/avatar/avatar.js +222 -0
  59. package/src/components/button/button.css +0 -1
  60. package/src/components/card/card.css +149 -0
  61. package/src/components/card/card.js +285 -0
  62. package/src/components/chart/chart.css +61 -0
  63. package/src/components/chart/chart.js +523 -0
  64. package/src/components/date-picker/month-picker.js +9 -0
  65. package/src/components/dialog/dialog.js +11 -4
  66. package/src/components/dock/dock.css +228 -0
  67. package/src/components/dock/dock.js +977 -0
  68. package/src/components/dropdown/dropdown.js +1 -1
  69. package/src/components/field/field.js +2 -0
  70. package/src/components/field-upload/field-upload.js +9 -4
  71. package/src/components/form/form.js +6 -3
  72. package/src/components/grid/grid.css +6 -0
  73. package/src/components/grid/grid.js +220 -0
  74. package/src/components/launcher/launcher.css +210 -0
  75. package/src/components/launcher/launcher.js +765 -0
  76. package/src/components/layout/layout.js +2 -2
  77. package/src/components/menu-button/menu-button.js +27 -2
  78. package/src/components/modal/modal.css +5 -1
  79. package/src/components/modal/modal.js +37 -2
  80. package/src/components/multi-value-editor/multi-value-editor.js +2 -1
  81. package/src/components/questionnaire/items.js +370 -0
  82. package/src/components/questionnaire/questionnaire.css +387 -0
  83. package/src/components/questionnaire/questionnaire.js +1033 -0
  84. package/src/components/select/field-adapter.js +9 -4
  85. package/src/components/select/select.css +144 -11
  86. package/src/components/select/select.js +259 -27
  87. package/src/components/sheet/sheet-stack.js +304 -0
  88. package/src/components/sheet/sheet.css +351 -0
  89. package/src/components/sheet/sheet.js +551 -0
  90. package/src/components/split-view/split-view.js +76 -161
  91. package/src/components/table/table.css +43 -0
  92. package/src/components/table/table.js +531 -52
  93. package/src/components/tooltip/tooltip.js +5 -2
  94. package/src/components/value-list/value-list.js +6 -3
  95. package/src/core/dom.js +322 -0
  96. package/src/core/drag-axis.js +203 -0
  97. package/src/core/position.js +68 -22
  98. package/src/index.js +20 -2
  99. package/src/internal/app-rail.js +718 -0
  100. package/src/zeyos/icons.js +8 -3
  101. package/src/zeyos/index.js +7 -1
  102. package/src/zeyos/launcher.js +338 -0
  103. package/src/zeyos/modules.js +1 -0
  104. package/src/zeyos/select.js +115 -1
  105. package/styles/tokens/dark.css +2 -3
  106. package/styles/tokens/global.css +6 -6
  107. package/styles/tokens/modules.css +1 -0
  108. package/styles/tokens/semantic.css +5 -3
  109. package/styles/tokens/themes.css +1 -1
  110. package/styles/zx.css +11 -1
  111. package/MIGRATION.md +0 -598
  112. package/dist/types/compat/base.d.ts +0 -156
  113. package/dist/types/compat/globals.d.ts +0 -20
  114. package/dist/types/compat/index.d.ts +0 -128
  115. package/dist/types/compat/map/basic.d.ts +0 -175
  116. package/dist/types/compat/map/data.d.ts +0 -102
  117. package/dist/types/compat/map/date-time.d.ts +0 -80
  118. package/dist/types/compat/map/factory.d.ts +0 -9
  119. package/dist/types/compat/map/form.d.ts +0 -98
  120. package/dist/types/compat/map/helpers.d.ts +0 -12
  121. package/dist/types/compat/map/http.d.ts +0 -36
  122. package/dist/types/compat/map/layout.d.ts +0 -106
  123. package/dist/types/compat/map/options.d.ts +0 -80
  124. package/dist/types/compat/map/select.d.ts +0 -95
  125. package/dist/types/compat/map/stubs.d.ts +0 -32
  126. package/dist/types/compat/map/utilities.d.ts +0 -37
  127. package/dist/types/compat-entry.d.ts +0 -5
  128. package/dist/types/components/permission/permission.d.ts +0 -96
  129. package/dist/zx-compat.esm.js +0 -17484
  130. package/dist/zx-compat.esm.min.js +0 -1
  131. package/dist/zx-compat.global.js +0 -23635
  132. package/dist/zx-compat.global.min.js +0 -3
  133. package/src/compat/base.js +0 -291
  134. package/src/compat/globals.js +0 -165
  135. package/src/compat/index.js +0 -84
  136. package/src/compat/map/basic.js +0 -464
  137. package/src/compat/map/data.js +0 -232
  138. package/src/compat/map/date-time.js +0 -177
  139. package/src/compat/map/factory.js +0 -45
  140. package/src/compat/map/form.js +0 -330
  141. package/src/compat/map/helpers.js +0 -46
  142. package/src/compat/map/http.js +0 -117
  143. package/src/compat/map/layout.js +0 -256
  144. package/src/compat/map/options.js +0 -267
  145. package/src/compat/map/select.js +0 -198
  146. package/src/compat/map/stubs.js +0 -26
  147. package/src/compat/map/utilities.js +0 -113
  148. package/src/compat-entry.js +0 -11
  149. package/src/components/permission/permission.css +0 -47
  150. package/src/components/permission/permission.js +0 -201
@@ -1,12 +1,10 @@
1
1
  import { Component } from '../../core/component.js';
2
+ export { resolveSize } from '../../core/drag-axis.js';
3
+ import { STEP, STEP_LARGE, dragAxis, resolveSize } from '../../core/drag-axis.js';
2
4
  import { h, restoreTarget, snapshotTarget } from '../../core/dom.js';
3
5
  import { storage } from '../../core/storage.js';
4
6
  import { uid } from '../../core/util.js';
5
7
 
6
- /** Pixels an arrow key moves the divider. */
7
- const STEP = 16;
8
- /** Pixels a shifted arrow key moves the divider. */
9
- const STEP_LARGE = 64;
10
8
  /** Storage namespace shared by every split view that opted into persistence. */
11
9
  const STORAGE_NAMESPACE = 'split-view';
12
10
 
@@ -79,6 +77,8 @@ export class SplitView extends Component {
79
77
  #observer = null;
80
78
  /** @type {ReturnType<typeof storage>|null} */
81
79
  #store = null;
80
+ /** @type {ReturnType<typeof dragAxis>|null} */
81
+ #drag = null;
82
82
 
83
83
  /**
84
84
  * Creates a split view, or turns an existing element into one.
@@ -102,11 +102,33 @@ export class SplitView extends Component {
102
102
  }
103
103
 
104
104
  const divider = this.refs.divider;
105
- this.listen(divider, 'pointerdown', (event) => this.#onPointerDown(/** @type {PointerEvent} */ (event)));
106
- this.listen(divider, 'pointermove', (event) => this.#onPointerMove(/** @type {PointerEvent} */ (event)));
107
- this.listen(divider, 'pointerup', (event) => this.#endDrag(/** @type {PointerEvent} */ (event)));
108
- this.listen(divider, 'pointercancel', (event) => this.#endDrag(/** @type {PointerEvent} */ (event)));
109
- this.listen(divider, 'keydown', (event) => this.#onKeyDown(/** @type {KeyboardEvent} */ (event)));
105
+ this.#drag = dragAxis(divider, {
106
+ orientation: this._orientation,
107
+ disabled: () => this._disabled,
108
+ onStart: () => {
109
+ this._startSize = this.getSize();
110
+ /** @type {HTMLElement} */ (this.el).dataset.dragging = 'true';
111
+ },
112
+ onMove: (delta) => this.#trackDelta(delta, false),
113
+ onEnd: (delta, moved) => {
114
+ // A drag that ends back where it started still has a final position to restore.
115
+ if (moved) this.#trackDelta(delta, true);
116
+ delete /** @type {HTMLElement} */ (this.el).dataset.dragging;
117
+ if (!moved) return;
118
+ this.#persist();
119
+ this.#emitResizeEnd();
120
+ },
121
+ onStep: (direction, large) => this.#stepBy(direction * (large ? STEP_LARGE : STEP)),
122
+ onJump: (edge) => this.#jumpTo(edge),
123
+ onActivate: () => {
124
+ if (!this.options.collapsible) return;
125
+ if (this._collapsed === null) {
126
+ this.collapse(/** @type {'start'|'end'} */ (this.options.collapsible));
127
+ } else {
128
+ this.expand();
129
+ }
130
+ }
131
+ });
110
132
  this.listen(divider, 'dblclick', () => this.#onDoubleClick());
111
133
 
112
134
  if (typeof ResizeObserver === 'function') {
@@ -133,16 +155,8 @@ export class SplitView extends Component {
133
155
  this._collapsed = null;
134
156
  this._disabled = Boolean(options.disabled);
135
157
  this._destroyed = false;
136
- this._dragging = false;
137
- /** Handle of the frame a pending drag update is scheduled in; `0` if none. */
138
- this._frame = 0;
139
- /** @type {number|null} */
140
- this._pointerId = null;
141
- this._startClient = 0;
158
+ /** Start-pane size when the current drag began, in pixels. */
142
159
  this._startSize = 0;
143
- this._pointerClient = 0;
144
- /** Whether the pointer left its starting position, which separates a drag from a click. */
145
- this._moved = false;
146
160
  /** Container size of the last observer pass; `-1` forces the next one to run. */
147
161
  this._lastTotal = -1;
148
162
 
@@ -307,7 +321,8 @@ export class SplitView extends Component {
307
321
  */
308
322
  disable() {
309
323
  this._disabled = true;
310
- this.#endDrag(null);
324
+ this.#drag?.cancel();
325
+ delete /** @type {HTMLElement} */ (this.el).dataset.dragging;
311
326
  this.refs.divider.setAttribute('aria-disabled', 'true');
312
327
  this.refs.divider.setAttribute('tabindex', '-1');
313
328
  return this;
@@ -328,11 +343,8 @@ export class SplitView extends Component {
328
343
  destroy() {
329
344
  if (this._destroyed) return;
330
345
  this._destroyed = true;
331
- if (this._frame !== 0) {
332
- cancelAnimationFrame(this._frame);
333
- this._frame = 0;
334
- }
335
- this.#releasePointer();
346
+ this.#drag?.destroy();
347
+ this.#drag = null;
336
348
  this.#observer?.disconnect();
337
349
  this.#observer = null;
338
350
  super.destroy();
@@ -390,55 +402,20 @@ export class SplitView extends Component {
390
402
  return this;
391
403
  }
392
404
 
393
- /** @param {PointerEvent} event @returns {void} */
394
- #onPointerDown(event) {
395
- if (this._disabled || this._dragging || event.button !== 0) return;
396
- // No preventDefault(): cancelling pointerdown suppresses the compatibility mouse events the
397
- // double-click reset is built on. `user-select: none` on the divider stops the text selection
398
- // this would otherwise be guarding against.
399
- this._dragging = true;
400
- this._pointerId = event.pointerId;
401
- this._startClient = axisClient(event, this._orientation);
402
- this._pointerClient = this._startClient;
403
- this._startSize = this.getSize();
404
- this._moved = false;
405
- /** @type {HTMLElement} */ (this.el).dataset.dragging = 'true';
406
- try {
407
- this.refs.divider.setPointerCapture(event.pointerId);
408
- } catch {
409
- // A pointer that ended between the event and this call cannot be captured; the drag simply
410
- // finishes on the next pointerup.
411
- }
412
- }
413
-
414
- /** @param {PointerEvent} event @returns {void} */
415
- #onPointerMove(event) {
416
- if (!this._dragging || event.pointerId !== this._pointerId) return;
417
- this._pointerClient = axisClient(event, this._orientation);
418
- if (this._pointerClient !== this._startClient) this._moved = true;
419
- if (this._frame !== 0) return;
420
- // One write and at most one `resize` per frame, however fast the pointer reports.
421
- this._frame = requestAnimationFrame(() => {
422
- this._frame = 0;
423
- this.#trackPointer(false);
424
- });
425
- }
426
-
427
405
  /**
428
- * Clamps the pointer position into a legal size and applies it.
406
+ * Applies a pointer delta as a new start-pane size.
407
+ * @param {number} delta Pixels travelled along the axis since the drag began.
429
408
  * @param {boolean} settle Whether to apply the snap radius, which only makes sense at drag end.
430
409
  * @returns {void}
431
410
  */
432
- #trackPointer(settle) {
433
- if (!this._dragging || this._destroyed) return;
411
+ #trackDelta(delta, settle) {
412
+ if (this._destroyed) return;
434
413
  const { total, divider, min, max } = this.#metrics();
435
414
  if (total <= 0) return;
436
415
  // Dragging a folded pane brings it back rather than doing nothing; a plain click does not,
437
416
  // because this runs only once the pointer has actually moved.
438
417
  if (this._collapsed !== null) this.expand();
439
- let next = clampSize({
440
- size: this._startSize + (this._pointerClient - this._startClient), min, max, total, divider
441
- });
418
+ let next = clampSize({ size: this._startSize + delta, min, max, total, divider });
442
419
  if (settle) {
443
420
  next = clampSize({
444
421
  size: snapSize(next, this.#snapTargets(total, divider), Number(this.options.snap)),
@@ -451,91 +428,36 @@ export class SplitView extends Component {
451
428
  }
452
429
 
453
430
  /**
454
- * @param {number} total
455
- * @param {number} divider
456
- * @returns {number[]}
431
+ * Moves the divider by a keyboard step and reports it as a completed resize.
432
+ * @param {number} amount Signed pixels.
433
+ * @returns {void}
457
434
  */
458
- #snapTargets(total, divider) {
459
- const { min, max } = this.#metrics();
460
- const bounds = sizeBounds({ min, max, total, divider });
461
- const targets = [bounds.min, bounds.max];
462
- const initial = resolveSize(this.options.size, total);
463
- if (Number.isFinite(initial)) targets.unshift(initial);
464
- return targets;
435
+ #stepBy(amount) {
436
+ const { total, divider, min, max } = this.#metrics();
437
+ if (total <= 0) return;
438
+ if (this._collapsed !== null) this.expand();
439
+ this.#commit(clampSize({ size: this.getSize() + amount, min, max, total, divider }), total);
465
440
  }
466
441
 
467
442
  /**
468
- * Finishes a drag: flushes the last frame, applies the snap radius, releases the capture,
469
- * persists, and reports. A press that never moved is a click, not a resize, and reports nothing.
470
- * @param {PointerEvent|null} event Ending pointer event, or null when ending programmatically.
443
+ * Sends the divider to one end of its travel.
444
+ * @param {'min'|'max'} edge Bound to jump to.
471
445
  * @returns {void}
472
- * @fires SplitView#resizeend
473
446
  */
474
- #endDrag(event) {
475
- if (!this._dragging) return;
476
- if (event && event.pointerId !== this._pointerId) return;
477
- if (this._frame !== 0) {
478
- cancelAnimationFrame(this._frame);
479
- this._frame = 0;
480
- }
481
- if (event) this._pointerClient = axisClient(event, this._orientation);
482
- const moved = this._moved;
483
- // A drag that ends back where it started still has a final position to restore and report.
484
- if (moved) this.#trackPointer(true);
485
- this._dragging = false;
486
- this._moved = false;
487
- this.#releasePointer();
488
- delete /** @type {HTMLElement} */ (this.el).dataset.dragging;
489
- if (!moved) return;
490
- this.#persist();
491
- this.#emitResizeEnd();
492
- }
493
-
494
- /** @returns {void} */
495
- #releasePointer() {
496
- const pointerId = this._pointerId;
497
- this._pointerId = null;
498
- if (pointerId === null) return;
499
- try {
500
- this.refs.divider.releasePointerCapture(pointerId);
501
- } catch {
502
- // The capture is already gone once the pointer was cancelled or the node was detached.
503
- }
504
- }
505
-
506
- /** @param {KeyboardEvent} event @returns {void} */
507
- #onKeyDown(event) {
508
- if (this._disabled) return;
509
- const key = event.key;
510
-
511
- if (key === 'Enter' || key === ' ') {
512
- if (!this.options.collapsible) return;
513
- event.preventDefault();
514
- if (this._collapsed === null) {
515
- this.collapse(/** @type {'start'|'end'} */ (this.options.collapsible));
516
- } else {
517
- this.expand();
518
- }
519
- return;
520
- }
521
-
522
- const horizontal = this._orientation === 'horizontal';
523
- const shrink = horizontal ? 'ArrowLeft' : 'ArrowUp';
524
- const grow = horizontal ? 'ArrowRight' : 'ArrowDown';
525
- if (key !== shrink && key !== grow && key !== 'Home' && key !== 'End') return;
526
- event.preventDefault();
527
- // A key that moves the divider implies the pane should be visible again.
528
- if (this._collapsed !== null) this.expand();
529
-
447
+ #jumpTo(edge) {
530
448
  const { total, divider, min, max } = this.#metrics();
531
449
  if (total <= 0) return;
450
+ if (this._collapsed !== null) this.expand();
532
451
  const bounds = sizeBounds({ min, max, total, divider });
533
- const step = event.shiftKey ? STEP_LARGE : STEP;
534
- let next = bounds.min;
535
- if (key === 'End') next = bounds.max;
536
- else if (key !== 'Home') next = this.getSize() + (key === grow ? step : -step);
452
+ this.#commit(clampSize({ size: bounds[edge], min, max, total, divider }), total);
453
+ }
537
454
 
538
- const size = clampSize({ size: next, min, max, total, divider });
455
+ /**
456
+ * @param {number} size
457
+ * @param {number} total
458
+ * @returns {void}
459
+ */
460
+ #commit(size, total) {
539
461
  if (size === this._size) return;
540
462
  this.#applySize(size);
541
463
  this.emit('resize', { size, ratio: size / total });
@@ -543,6 +465,20 @@ export class SplitView extends Component {
543
465
  this.#emitResizeEnd();
544
466
  }
545
467
 
468
+ /**
469
+ * @param {number} total
470
+ * @param {number} divider
471
+ * @returns {number[]}
472
+ */
473
+ #snapTargets(total, divider) {
474
+ const { min, max } = this.#metrics();
475
+ const bounds = sizeBounds({ min, max, total, divider });
476
+ const targets = [bounds.min, bounds.max];
477
+ const initial = resolveSize(this.options.size, total);
478
+ if (Number.isFinite(initial)) targets.unshift(initial);
479
+ return targets;
480
+ }
481
+
546
482
  /**
547
483
  * Resets the divider to the initial `size`. A percentage goes back to being a percentage rather
548
484
  * than to the pixel value it happens to work out at, so the pane keeps tracking the container.
@@ -583,7 +519,7 @@ export class SplitView extends Component {
583
519
  * @returns {void}
584
520
  */
585
521
  #onContainerResize() {
586
- if (this._destroyed || this._dragging) return;
522
+ if (this._destroyed || this.#drag?.isDragging()) return;
587
523
  const { total, divider, min, max } = this.#metrics();
588
524
  if (total <= 0 || total === this._lastTotal) return;
589
525
  this._lastTotal = total;
@@ -688,27 +624,6 @@ export function clampSize({ size, min = 0, max = null, total = 0, divider = 0 })
688
624
  return Math.min(bounds.max, Math.max(bounds.min, requested));
689
625
  }
690
626
 
691
- /**
692
- * Resolves a size option to pixels without touching the DOM.
693
- *
694
- * Numbers, bare numeric strings, and `px` lengths are pixels; a percentage resolves against
695
- * `total`. Every other CSS length — `rem`, `vh`, `calc()` — needs the browser, so it returns `NaN`
696
- * and the caller hands the value to CSS instead of guessing at it.
697
- * @param {number|string} value Size option.
698
- * @param {number} total Container size along the split axis, in pixels.
699
- * @returns {number} Pixels, or `NaN` when only the browser can resolve the value.
700
- */
701
- export function resolveSize(value, total) {
702
- if (typeof value === 'number') return Number.isFinite(value) ? value : Number.NaN;
703
- if (typeof value !== 'string') return Number.NaN;
704
- const match = /^([+-]?(?:\d+\.?\d*|\.\d+))(px|%)?$/i.exec(value.trim());
705
- if (!match) return Number.NaN;
706
- const amount = Number(match[1]);
707
- if (!Number.isFinite(amount)) return Number.NaN;
708
- if ((match[2] ?? '').toLowerCase() !== '%') return amount;
709
- const span = Number(total);
710
- return Number.isFinite(span) ? (amount / 100) * span : Number.NaN;
711
- }
712
627
 
713
628
  /**
714
629
  * Pulls a size onto the nearest target within a radius, leaving it alone when nothing is close.
@@ -177,6 +177,49 @@
177
177
  text-align: center;
178
178
  }
179
179
 
180
+ /* --- Hierarchical line items --------------------------------------------------------------- */
181
+
182
+ .zx-table__tree-cell {
183
+ display: flex;
184
+ min-inline-size: 0;
185
+ align-items: center;
186
+ gap: var(--zx-space-1);
187
+ padding-inline-start: calc(var(--zx-table-depth, 0) * var(--zx-space-4));
188
+ }
189
+
190
+ .zx-table__tree-toggle,
191
+ .zx-table__tree-spacer {
192
+ inline-size: 24px;
193
+ block-size: 24px;
194
+ flex: 0 0 24px;
195
+ }
196
+
197
+ .zx-table__tree-toggle {
198
+ display: inline-grid;
199
+ min-block-size: 0;
200
+ place-items: center;
201
+ padding: 0;
202
+ border: 0;
203
+ border-radius: var(--zx-radius-sm);
204
+ background: transparent;
205
+ color: var(--zx-color-text-muted);
206
+ cursor: pointer;
207
+ }
208
+
209
+ .zx-table__tree-toggle:hover {
210
+ background: var(--zx-color-bg-hover);
211
+ color: var(--zx-color-text);
212
+ }
213
+
214
+ .zx-table__tree-toggle:focus-visible {
215
+ outline: 0;
216
+ box-shadow: var(--zx-focus-ring);
217
+ }
218
+
219
+ .zx-table__cell-content {
220
+ min-inline-size: 0;
221
+ }
222
+
180
223
  /* --- Inline editing (Table editMode) -------------------------------------------------------- */
181
224
 
182
225
  /* Reserve a control-sized content box in every body cell as soon as the table is editable, so