@jolly-pixel/ui 1.0.1 → 2.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 (117) hide show
  1. package/LICENSE +44 -44
  2. package/NOTICE +9 -0
  3. package/README.md +194 -194
  4. package/dist/containers/Dialog.js +11 -11
  5. package/dist/containers/Dialog.styles.js +48 -48
  6. package/dist/containers/Dock.js +11 -11
  7. package/dist/containers/Dock.styles.js +351 -351
  8. package/dist/containers/DockLayout.js +4 -4
  9. package/dist/containers/Floating.js +23 -23
  10. package/dist/containers/Floating.styles.js +116 -116
  11. package/dist/containers/Folder.js +28 -28
  12. package/dist/containers/Folder.styles.js +221 -221
  13. package/dist/containers/Pane.js +50 -50
  14. package/dist/containers/Pane.styles.js +186 -186
  15. package/dist/containers/Rail.js +18 -18
  16. package/dist/containers/Tab.js +10 -10
  17. package/dist/containers/Tabs.js +26 -26
  18. package/dist/containers/Tabs.styles.js +93 -93
  19. package/dist/containers/Toolbar.js +25 -25
  20. package/dist/containers/resize.js +5 -5
  21. package/dist/controls/Button.js +9 -9
  22. package/dist/controls/Button.styles.js +79 -79
  23. package/dist/controls/ButtonGroup.js +28 -28
  24. package/dist/controls/ButtonGroup.styles.js +98 -98
  25. package/dist/controls/Checkbox.js +14 -14
  26. package/dist/controls/Checkbox.styles.js +111 -111
  27. package/dist/controls/Color.js +51 -51
  28. package/dist/controls/Color.styles.js +83 -83
  29. package/dist/controls/ColorPicker.js +104 -104
  30. package/dist/controls/ColorPicker.styles.js +296 -296
  31. package/dist/controls/Control.js +33 -33
  32. package/dist/controls/Control.styles.js +102 -102
  33. package/dist/controls/Controls.js +11 -11
  34. package/dist/controls/Controls.styles.js +98 -98
  35. package/dist/controls/Flags.js +18 -18
  36. package/dist/controls/Flags.styles.js +59 -59
  37. package/dist/controls/Number.js +21 -21
  38. package/dist/controls/Number.styles.js +44 -44
  39. package/dist/controls/PropertyRow.js +13 -13
  40. package/dist/controls/PropertyRow.styles.js +105 -105
  41. package/dist/controls/Range.js +24 -24
  42. package/dist/controls/Range.styles.js +25 -25
  43. package/dist/controls/Select.js +23 -23
  44. package/dist/controls/Select.styles.js +47 -47
  45. package/dist/controls/Separator.js +11 -11
  46. package/dist/controls/Separator.styles.js +45 -45
  47. package/dist/controls/Slider.js +36 -36
  48. package/dist/controls/Slider.styles.js +161 -161
  49. package/dist/controls/Text.js +17 -17
  50. package/dist/data/Tree.d.ts +0 -14
  51. package/dist/data/Tree.d.ts.map +1 -1
  52. package/dist/data/Tree.js +90 -120
  53. package/dist/data/Tree.js.map +1 -1
  54. package/dist/data/Tree.styles.d.ts.map +1 -1
  55. package/dist/data/Tree.styles.js +220 -237
  56. package/dist/data/Tree.styles.js.map +1 -1
  57. package/dist/data/dropZone.d.ts +0 -10
  58. package/dist/data/dropZone.d.ts.map +1 -1
  59. package/dist/data/dropZone.js +0 -10
  60. package/dist/data/dropZone.js.map +1 -1
  61. package/dist/data/resolveRename.d.ts +0 -3
  62. package/dist/data/resolveRename.d.ts.map +1 -1
  63. package/dist/data/resolveRename.js +0 -3
  64. package/dist/data/resolveRename.js.map +1 -1
  65. package/dist/data/resolveReparent.d.ts +0 -7
  66. package/dist/data/resolveReparent.d.ts.map +1 -1
  67. package/dist/data/resolveReparent.js +0 -6
  68. package/dist/data/resolveReparent.js.map +1 -1
  69. package/dist/data/rowDragSession.d.ts +0 -8
  70. package/dist/data/rowDragSession.d.ts.map +1 -1
  71. package/dist/data/rowDragSession.js +0 -6
  72. package/dist/data/rowDragSession.js.map +1 -1
  73. package/dist/data/treeNodes.d.ts +0 -6
  74. package/dist/data/treeNodes.d.ts.map +1 -1
  75. package/dist/data/treeNodes.js +2 -7
  76. package/dist/data/treeNodes.js.map +1 -1
  77. package/dist/feedback/JollyPixelLogo.js +84 -84
  78. package/dist/feedback/Loading.js +29 -29
  79. package/dist/feedback/Loading.styles.js +230 -230
  80. package/dist/feedback/Log.js +8 -8
  81. package/dist/feedback/Log.styles.js +61 -61
  82. package/dist/feedback/Progress.js +17 -17
  83. package/dist/feedback/Progress.styles.js +146 -146
  84. package/dist/field/JollyField.js +51 -51
  85. package/dist/field/JollyField.styles.js +429 -429
  86. package/dist/icon/Icon.js +24 -24
  87. package/dist/icon/builtins.js +126 -126
  88. package/dist/interaction/drag/DragSession.js +6 -6
  89. package/dist/interaction/scrub/ScrubController.js +6 -6
  90. package/dist/math/AxisController.js +22 -22
  91. package/dist/math/Point2d.js +12 -12
  92. package/dist/math/Point2d.styles.js +49 -49
  93. package/dist/math/Quaternion.js +4 -4
  94. package/dist/math/Transform.js +40 -40
  95. package/dist/math/Transform.styles.js +17 -17
  96. package/dist/math/VectorField.js +4 -4
  97. package/dist/math/VectorField.styles.js +102 -102
  98. package/dist/monitors/Graph.js +8 -8
  99. package/dist/monitors/Graph.styles.js +42 -42
  100. package/dist/monitors/Monitor.js +5 -5
  101. package/dist/monitors/Monitor.styles.js +31 -31
  102. package/dist/peer/Presence.js +33 -33
  103. package/dist/peer/Presence.styles.js +82 -82
  104. package/dist/stats/Stats.js +6 -6
  105. package/dist/stats/Stats.styles.js +54 -54
  106. package/dist/theme/components/DensityControl.js +16 -16
  107. package/dist/theme/components/ThemeControl.js +16 -16
  108. package/dist/theme/components/ThemePreferences.js +18 -18
  109. package/dist/theme/font.js +9 -9
  110. package/dist/theme/styles/hiddenStyles.js +4 -4
  111. package/dist/theme/styles/mixins.js +16 -16
  112. package/dist/theme/styles/themeStyles.js +4 -4
  113. package/dist/theme/tokens/density.js +19 -19
  114. package/dist/theme/tokens/ramps.js +40 -40
  115. package/dist/theme/tokens/scales.js +56 -56
  116. package/dist/theme/tokens/semantic.js +184 -184
  117. package/package.json +6 -5
@@ -6,434 +6,434 @@ import { fillTransition, truncate } from "../theme/styles/mixins.js";
6
6
  /**
7
7
  * Shared field layout and state styles.
8
8
  */
9
- export const fieldStyles = css `
10
- /*
11
- * Rows carry no outer spacing. The container that stacks them owns the gap,
12
- * so a consumer can stack fields flush when that is what they want.
13
- */
14
- :host {
15
- --jolly-field-active-color: light-dark(
16
- var(--jolly-neutral-600),
17
- var(--jolly-neutral-50)
18
- );
19
- --jolly-field-active-color-hover: light-dark(
20
- var(--jolly-neutral-500),
21
- var(--jolly-neutral-200)
22
- );
23
-
24
- display: block;
25
- font-family: var(--jolly-font-family, ui-monospace, monospace);
26
- font-size: var(--jolly-font-size, 11px);
27
- color: var(--jolly-text, ${kFallback.text});
28
- }
29
-
30
- :host([colored]) {
31
- --jolly-field-active-color: var(--jolly-accent-fill);
32
- --jolly-field-active-color-hover: var(--jolly-accent-fill-hover);
33
- }
34
-
35
- :host([disabled]) {
36
- opacity: 0.5;
37
- pointer-events: none;
38
- }
39
-
40
- .row {
41
- display: flex;
42
- align-items: center;
43
- gap: var(--jolly-space-1, 4px);
44
- min-height: var(--jolly-row-height, 20px);
45
- padding-inline: var(--jolly-space-1, 4px)
46
- var(--jolly-field-inset-end, var(--jolly-space-1, 4px));
47
- border-radius: var(--jolly-radius-sm, 2px);
48
- ${fillTransition}
49
- }
50
-
51
- /*
52
- * Flattened into the row's flex items by default, so inline layout is
53
- * unaffected by the grouping these wrap for stacked layout.
54
- */
55
- .leading,
56
- .content {
57
- display: contents;
58
- }
59
-
60
- :host([label-position="top"]) .row {
61
- flex-direction: column;
62
- align-items: stretch;
63
- min-height: auto;
64
- gap: calc(var(--jolly-space-1, 4px) / 2);
65
- }
66
-
67
- :host([label-position="top"]) .leading,
68
- :host([label-position="top"]) .content {
69
- display: flex;
70
- align-items: center;
71
- gap: var(--jolly-space-1, 4px);
72
- }
73
-
74
- /*
75
- * The gutter sits only on the label's line, so the value line needs a
76
- * matching inset to keep both lines starting at the same edge.
77
- */
78
- :host([label-position="top"]) .content {
79
- padding-inline-start: calc(
80
- var(--jolly-gutter-width, 0px) + var(--jolly-space-1, 4px)
81
- );
82
- }
83
-
84
- /* With no label the leading line is an empty band, unless it holds a lock. */
85
- :host([unlabeled]:not([locked])[label-position="top"]) .leading {
86
- display: none;
87
- }
88
-
89
- :host([unlabeled]:not([locked])[label-position="top"]) .content {
90
- padding-inline-start: 0;
91
- }
92
-
93
- /*
94
- * Locating the active row in a long pane. Deliberately fainter than the
95
- * control's own focus tint, so the two read as a hierarchy and not a clash.
96
- */
97
- .row:focus-within {
98
- background: var(--jolly-row-bg-focus);
99
- }
100
-
101
- /*
102
- * Zero width by default. A collaborative container opts its subtree in, which
103
- * buys back the fixed inset that keeps lock state from shifting the row.
104
- */
105
- .gutter {
106
- display: flex;
107
- align-items: center;
108
- justify-content: center;
109
- box-sizing: border-box;
110
- flex: 0 0 auto;
111
- width: var(--jolly-gutter-width, 0px);
112
- height: 14px;
113
- overflow: hidden;
114
- }
115
-
116
- /*
117
- * Without a label the gap after a collapsed gutter is an inset paid for
118
- * nothing. Locked keeps it: there the gutter paints an icon.
119
- */
120
- :host([unlabeled]:not([locked])) .gutter {
121
- margin-inline-end: calc(var(--jolly-space-1, 4px) * -1);
122
- }
123
-
124
- /* No label column to inset for, so both edges fall back to the row inset. */
125
- :host([unlabeled]:not([locked])) .row {
126
- padding-inline-start: var(--jolly-field-inset-end, var(--jolly-space-1, 4px));
127
- }
128
-
129
- /*
130
- * A lock always has to be visible, even where nothing reserved room for it.
131
- * Opting the subtree in is what turns this from a widening row into a fixed
132
- * inset; without it the lock still shows, it just costs a shift.
133
- */
134
- :host([locked]) .gutter {
135
- width: max(var(--jolly-gutter-width, 0px), 14px);
136
- overflow: visible;
137
- }
138
-
139
- /*
140
- * Icons default to the 16px display size, which overflows the gutter. The
141
- * lock is chrome inside a 14px box, so it is sized to the box it sits in.
142
- */
143
- .gutter > jolly-icon {
144
- width: 14px;
145
- height: 14px;
146
- color: var(--jolly-locked-ring, var(--jolly-locked));
147
- }
148
-
149
- /*
150
- * A configured width aligns value columns across fields. The cap stops a long
151
- * label from eating the value area; a field packed beside another on one line
152
- * lifts it, since there the label is legitimately most of the row.
153
- */
154
- .label {
155
- flex: 0 0 auto;
156
- width: var(--jolly-label-width, auto);
157
- min-width: 0;
158
- max-width: var(--jolly-label-max-width, 45%);
159
- color: var(--jolly-text-muted);
160
- text-align: start;
161
- ${truncate}
162
- user-select: none;
163
- }
164
-
165
- :host([label-position="top"]) .label {
166
- width: auto;
167
- max-width: none;
168
- }
169
-
170
- .value {
171
- display: flex;
172
- align-items: center;
173
- flex: 1 1 auto;
174
- gap: var(--jolly-space-1, 4px);
175
- min-width: 0;
176
- font-variant-numeric: var(--jolly-font-numeric, tabular-nums);
177
- }
178
-
179
- /*
180
- * Base input styles shared by field controls. Boundaries are carried by the
181
- * fill, so there is no border to state here.
182
- */
183
- .value input:not([type="color"]),
184
- .value select {
185
- flex: 1 1 auto;
186
- min-width: 0;
187
- height: var(--jolly-control-height, 20px);
188
- padding: 0 var(--jolly-space-1, 4px);
189
- border: 0;
190
- border-radius: var(--jolly-radius-sm, 2px);
191
- background: var(--jolly-control-bg, ${kFallback.controlBg});
192
- color: inherit;
193
- font: inherit;
194
- font-variant-numeric: inherit;
195
- ${fillTransition}
196
- }
197
-
198
- .value input:hover:not(:disabled),
199
- .value select:hover:not(:disabled) {
200
- background: var(--jolly-control-bg-hover);
201
- }
202
-
203
- /*
204
- * Focus is a fill step rather than an outline. The step has to beat hover,
205
- * because both are the same channel.
206
- */
207
- .value input:focus,
208
- .value select:focus {
209
- background: var(--jolly-control-bg-focus);
210
- outline: none;
211
- }
212
-
213
- /*
214
- * Numeric and monitor-style rows read better against the trailing edge, where
215
- * the digits line up down the pane.
216
- */
217
- :host([align="end"]) .value input,
218
- :host([align="end"]) .value select {
219
- text-align: end;
220
- }
221
-
222
- :host([invalid]) .value input,
223
- :host([invalid]) .value select {
224
- background: var(--jolly-invalid-bg);
225
- }
226
-
227
- :host([invalid]) .value input:hover:not(:disabled),
228
- :host([invalid]) .value select:hover:not(:disabled) {
229
- background: var(--jolly-invalid-bg-hover);
230
- }
231
-
232
- :host([invalid]) .value input:focus,
233
- :host([invalid]) .value select:focus {
234
- background: var(--jolly-invalid-bg-focus);
235
- }
236
-
237
- :host([readonly]) .value input,
238
- :host([readonly]) .value select {
239
- background: var(--jolly-control-bg-muted);
240
- }
241
-
242
- /*
243
- * Modified and locked both want the leading bar, so locked takes it: a locked
244
- * field is not editable, which makes reverting moot anyway.
245
- */
246
- :host([modified]:not([locked])) {
247
- box-shadow: inset 2px 0 0 0 var(--jolly-field-active-color);
248
- border-radius: var(--jolly-radius-sm, 2px);
249
- }
250
-
251
- :host([locked]) {
252
- padding-block: calc(var(--jolly-space-1, 4px) / 2);
253
- box-shadow: inset 3px 0 0 0 var(--jolly-locked-ring, var(--jolly-locked));
254
- border-radius: var(--jolly-radius-sm, 2px);
255
- background: color-mix(
256
- in oklab,
257
- var(--jolly-locked-ring, var(--jolly-locked)) 12%,
258
- transparent
259
- );
260
- }
261
-
262
- /*
263
- * A container can reserve one trailing column across sibling fields. The
264
- * negative margin absorbs the row gap; padding restores it for presence,
265
- * while the revert button cancels that padding to stay joined to the value.
266
- */
267
- .trailing {
268
- display: flex;
269
- align-items: center;
270
- box-sizing: border-box;
271
- flex: 0 0 auto;
272
- gap: var(--jolly-space-1, 4px);
273
- width: var(--jolly-field-trailing-width, auto);
274
- margin-inline-start: calc(var(--jolly-space-1, 4px) * -1);
275
- padding-inline-start: var(--jolly-space-1, 4px);
276
- }
277
-
278
- .trailing:not(:has(.revert, .peers)) {
279
- padding-inline-start: 0;
280
- }
281
-
282
- /*
283
- * The muted action stays visible while a modified value can be restored.
284
- * It joins the value edge and uses the full control height, so its hover fill
285
- * reads as trailing field chrome instead of a highlight behind the glyph.
286
- */
287
- .revert {
288
- display: flex;
289
- align-items: center;
290
- justify-content: center;
291
- flex: 0 0 auto;
292
- width: var(--jolly-control-height, 20px);
293
- height: var(--jolly-control-height, 20px);
294
- margin-inline-start: calc(var(--jolly-space-1, 4px) * -1);
295
- padding: 0;
296
- border: 0;
297
- border-radius:
298
- 0
299
- var(--jolly-radius-sm, 2px)
300
- var(--jolly-radius-sm, 2px)
301
- 0;
302
- background: none;
303
- color: var(--jolly-text-muted);
304
- cursor: pointer;
305
- ${fillTransition}
306
- }
307
-
308
- .revert > jolly-icon {
309
- width: 14px;
310
- height: 14px;
311
- }
312
-
313
- /* Filled values and the trailing action form a single control silhouette. */
314
- .value:has(+ .trailing > .revert) input[type="text"]:last-child,
315
- .value:has(+ .trailing > .revert) select {
316
- border-start-end-radius: 0;
317
- border-end-end-radius: 0;
318
- }
319
-
320
- .revert:hover {
321
- background: var(--jolly-control-bg);
322
- }
323
-
324
- .revert:focus-visible {
325
- background: var(--jolly-control-bg-focus);
326
- outline: none;
327
- }
328
-
329
- .peers {
330
- display: flex;
331
- flex: 0 0 auto;
332
- align-items: center;
333
- margin-inline-start: auto;
334
- }
335
-
336
- .chip {
337
- width: 10px;
338
- height: 10px;
339
- margin-left: -3px;
340
- border: 1px solid var(--jolly-surface);
341
- border-radius: 50%;
342
- }
343
-
344
- .chip:first-child {
345
- margin-left: 0;
346
- }
347
-
348
- .overflow {
349
- margin-left: var(--jolly-space-1, 4px);
350
- color: var(--jolly-text-muted);
351
- font-size: 0.85em;
352
- }
353
-
354
- /* Tooltips grow inward to stay within the field bounds. */
355
- [data-tooltip] {
356
- position: relative;
357
- }
358
-
359
- [data-tooltip]::after {
360
- content: attr(data-tooltip);
361
- position: absolute;
362
- bottom: calc(100% + var(--jolly-space-1, 4px));
363
- z-index: 1;
364
- padding: 2px 6px;
365
- border-radius: var(--jolly-radius-sm, 2px);
366
- background: var(--jolly-surface-raised);
367
- box-shadow: var(--jolly-shadow-overlay);
368
- color: var(--jolly-text);
369
- font-size: 0.85em;
370
- white-space: nowrap;
371
- opacity: 0;
372
- pointer-events: none;
373
- transform: translateY(2px);
374
- transition:
375
- opacity var(--jolly-duration-fast, 100ms) var(--jolly-easing, ease),
376
- transform var(--jolly-duration-fast, 100ms) var(--jolly-easing, ease);
377
- }
378
-
379
- /*
380
- * Offset on the tooltip rather than as gutter padding, which would widen the
381
- * gutter on exactly the rows that must not change width.
382
- */
383
- .gutter[data-tooltip]::after {
384
- left: 3px;
385
- }
386
-
387
- .chip::after {
388
- right: 0;
389
- }
390
-
391
- [data-tooltip]:hover::after {
392
- opacity: 1;
393
- transform: translateY(0);
394
- }
395
-
396
- /* Align help and error text with the value area. */
397
- .description,
398
- .error {
399
- display: flex;
400
- align-items: flex-start;
401
- gap: var(--jolly-space-1, 4px);
402
- margin-block: calc(var(--jolly-space-1, 4px) / 2);
403
- margin-inline: calc(
404
- var(--jolly-gutter-width, 0px) + (var(--jolly-space-1, 4px) * 2)
405
- )
406
- var(--jolly-space-1, 4px);
407
- font-size: 0.9em;
408
- }
409
-
410
- /* No label column to clear, so they follow the value back to the row inset. */
411
- :host([unlabeled]:not([locked])) .description,
412
- :host([unlabeled]:not([locked])) .error {
413
- margin-inline-start: calc(
414
- var(--jolly-gutter-width, 0px) +
415
- var(--jolly-field-inset-end, var(--jolly-space-1, 4px))
416
- );
417
- }
418
-
419
- .description jolly-icon,
420
- .error jolly-icon {
421
- flex: 0 0 auto;
422
- width: 14px;
423
- height: 14px;
424
- margin-block-start: 0;
425
- }
426
-
427
- .description {
428
- color: var(--jolly-text-muted);
429
- }
430
-
431
- .description jolly-icon {
432
- color: var(--jolly-accent-text);
433
- }
434
-
435
- .error {
436
- color: var(--jolly-danger);
437
- }
9
+ export const fieldStyles = css `
10
+ /*
11
+ * Rows carry no outer spacing. The container that stacks them owns the gap,
12
+ * so a consumer can stack fields flush when that is what they want.
13
+ */
14
+ :host {
15
+ --jolly-field-active-color: light-dark(
16
+ var(--jolly-neutral-600),
17
+ var(--jolly-neutral-50)
18
+ );
19
+ --jolly-field-active-color-hover: light-dark(
20
+ var(--jolly-neutral-500),
21
+ var(--jolly-neutral-200)
22
+ );
23
+
24
+ display: block;
25
+ font-family: var(--jolly-font-family, ui-monospace, monospace);
26
+ font-size: var(--jolly-font-size, 11px);
27
+ color: var(--jolly-text, ${kFallback.text});
28
+ }
29
+
30
+ :host([colored]) {
31
+ --jolly-field-active-color: var(--jolly-accent-fill);
32
+ --jolly-field-active-color-hover: var(--jolly-accent-fill-hover);
33
+ }
34
+
35
+ :host([disabled]) {
36
+ opacity: 0.5;
37
+ pointer-events: none;
38
+ }
39
+
40
+ .row {
41
+ display: flex;
42
+ align-items: center;
43
+ gap: var(--jolly-space-1, 4px);
44
+ min-height: var(--jolly-row-height, 20px);
45
+ padding-inline: var(--jolly-space-1, 4px)
46
+ var(--jolly-field-inset-end, var(--jolly-space-1, 4px));
47
+ border-radius: var(--jolly-radius-sm, 2px);
48
+ ${fillTransition}
49
+ }
50
+
51
+ /*
52
+ * Flattened into the row's flex items by default, so inline layout is
53
+ * unaffected by the grouping these wrap for stacked layout.
54
+ */
55
+ .leading,
56
+ .content {
57
+ display: contents;
58
+ }
59
+
60
+ :host([label-position="top"]) .row {
61
+ flex-direction: column;
62
+ align-items: stretch;
63
+ min-height: auto;
64
+ gap: calc(var(--jolly-space-1, 4px) / 2);
65
+ }
66
+
67
+ :host([label-position="top"]) .leading,
68
+ :host([label-position="top"]) .content {
69
+ display: flex;
70
+ align-items: center;
71
+ gap: var(--jolly-space-1, 4px);
72
+ }
73
+
74
+ /*
75
+ * The gutter sits only on the label's line, so the value line needs a
76
+ * matching inset to keep both lines starting at the same edge.
77
+ */
78
+ :host([label-position="top"]) .content {
79
+ padding-inline-start: calc(
80
+ var(--jolly-gutter-width, 0px) + var(--jolly-space-1, 4px)
81
+ );
82
+ }
83
+
84
+ /* With no label the leading line is an empty band, unless it holds a lock. */
85
+ :host([unlabeled]:not([locked])[label-position="top"]) .leading {
86
+ display: none;
87
+ }
88
+
89
+ :host([unlabeled]:not([locked])[label-position="top"]) .content {
90
+ padding-inline-start: 0;
91
+ }
92
+
93
+ /*
94
+ * Locating the active row in a long pane. Deliberately fainter than the
95
+ * control's own focus tint, so the two read as a hierarchy and not a clash.
96
+ */
97
+ .row:focus-within {
98
+ background: var(--jolly-row-bg-focus);
99
+ }
100
+
101
+ /*
102
+ * Zero width by default. A collaborative container opts its subtree in, which
103
+ * buys back the fixed inset that keeps lock state from shifting the row.
104
+ */
105
+ .gutter {
106
+ display: flex;
107
+ align-items: center;
108
+ justify-content: center;
109
+ box-sizing: border-box;
110
+ flex: 0 0 auto;
111
+ width: var(--jolly-gutter-width, 0px);
112
+ height: 14px;
113
+ overflow: hidden;
114
+ }
115
+
116
+ /*
117
+ * Without a label the gap after a collapsed gutter is an inset paid for
118
+ * nothing. Locked keeps it: there the gutter paints an icon.
119
+ */
120
+ :host([unlabeled]:not([locked])) .gutter {
121
+ margin-inline-end: calc(var(--jolly-space-1, 4px) * -1);
122
+ }
123
+
124
+ /* No label column to inset for, so both edges fall back to the row inset. */
125
+ :host([unlabeled]:not([locked])) .row {
126
+ padding-inline-start: var(--jolly-field-inset-end, var(--jolly-space-1, 4px));
127
+ }
128
+
129
+ /*
130
+ * A lock always has to be visible, even where nothing reserved room for it.
131
+ * Opting the subtree in is what turns this from a widening row into a fixed
132
+ * inset; without it the lock still shows, it just costs a shift.
133
+ */
134
+ :host([locked]) .gutter {
135
+ width: max(var(--jolly-gutter-width, 0px), 14px);
136
+ overflow: visible;
137
+ }
138
+
139
+ /*
140
+ * Icons default to the 16px display size, which overflows the gutter. The
141
+ * lock is chrome inside a 14px box, so it is sized to the box it sits in.
142
+ */
143
+ .gutter > jolly-icon {
144
+ width: 14px;
145
+ height: 14px;
146
+ color: var(--jolly-locked-ring, var(--jolly-locked));
147
+ }
148
+
149
+ /*
150
+ * A configured width aligns value columns across fields. The cap stops a long
151
+ * label from eating the value area; a field packed beside another on one line
152
+ * lifts it, since there the label is legitimately most of the row.
153
+ */
154
+ .label {
155
+ flex: 0 0 auto;
156
+ width: var(--jolly-label-width, auto);
157
+ min-width: 0;
158
+ max-width: var(--jolly-label-max-width, 45%);
159
+ color: var(--jolly-text-muted);
160
+ text-align: start;
161
+ ${truncate}
162
+ user-select: none;
163
+ }
164
+
165
+ :host([label-position="top"]) .label {
166
+ width: auto;
167
+ max-width: none;
168
+ }
169
+
170
+ .value {
171
+ display: flex;
172
+ align-items: center;
173
+ flex: 1 1 auto;
174
+ gap: var(--jolly-space-1, 4px);
175
+ min-width: 0;
176
+ font-variant-numeric: var(--jolly-font-numeric, tabular-nums);
177
+ }
178
+
179
+ /*
180
+ * Base input styles shared by field controls. Boundaries are carried by the
181
+ * fill, so there is no border to state here.
182
+ */
183
+ .value input:not([type="color"]),
184
+ .value select {
185
+ flex: 1 1 auto;
186
+ min-width: 0;
187
+ height: var(--jolly-control-height, 20px);
188
+ padding: 0 var(--jolly-space-1, 4px);
189
+ border: 0;
190
+ border-radius: var(--jolly-radius-sm, 2px);
191
+ background: var(--jolly-control-bg, ${kFallback.controlBg});
192
+ color: inherit;
193
+ font: inherit;
194
+ font-variant-numeric: inherit;
195
+ ${fillTransition}
196
+ }
197
+
198
+ .value input:hover:not(:disabled),
199
+ .value select:hover:not(:disabled) {
200
+ background: var(--jolly-control-bg-hover);
201
+ }
202
+
203
+ /*
204
+ * Focus is a fill step rather than an outline. The step has to beat hover,
205
+ * because both are the same channel.
206
+ */
207
+ .value input:focus,
208
+ .value select:focus {
209
+ background: var(--jolly-control-bg-focus);
210
+ outline: none;
211
+ }
212
+
213
+ /*
214
+ * Numeric and monitor-style rows read better against the trailing edge, where
215
+ * the digits line up down the pane.
216
+ */
217
+ :host([align="end"]) .value input,
218
+ :host([align="end"]) .value select {
219
+ text-align: end;
220
+ }
221
+
222
+ :host([invalid]) .value input,
223
+ :host([invalid]) .value select {
224
+ background: var(--jolly-invalid-bg);
225
+ }
226
+
227
+ :host([invalid]) .value input:hover:not(:disabled),
228
+ :host([invalid]) .value select:hover:not(:disabled) {
229
+ background: var(--jolly-invalid-bg-hover);
230
+ }
231
+
232
+ :host([invalid]) .value input:focus,
233
+ :host([invalid]) .value select:focus {
234
+ background: var(--jolly-invalid-bg-focus);
235
+ }
236
+
237
+ :host([readonly]) .value input,
238
+ :host([readonly]) .value select {
239
+ background: var(--jolly-control-bg-muted);
240
+ }
241
+
242
+ /*
243
+ * Modified and locked both want the leading bar, so locked takes it: a locked
244
+ * field is not editable, which makes reverting moot anyway.
245
+ */
246
+ :host([modified]:not([locked])) {
247
+ box-shadow: inset 2px 0 0 0 var(--jolly-field-active-color);
248
+ border-radius: var(--jolly-radius-sm, 2px);
249
+ }
250
+
251
+ :host([locked]) {
252
+ padding-block: calc(var(--jolly-space-1, 4px) / 2);
253
+ box-shadow: inset 3px 0 0 0 var(--jolly-locked-ring, var(--jolly-locked));
254
+ border-radius: var(--jolly-radius-sm, 2px);
255
+ background: color-mix(
256
+ in oklab,
257
+ var(--jolly-locked-ring, var(--jolly-locked)) 12%,
258
+ transparent
259
+ );
260
+ }
261
+
262
+ /*
263
+ * A container can reserve one trailing column across sibling fields. The
264
+ * negative margin absorbs the row gap; padding restores it for presence,
265
+ * while the revert button cancels that padding to stay joined to the value.
266
+ */
267
+ .trailing {
268
+ display: flex;
269
+ align-items: center;
270
+ box-sizing: border-box;
271
+ flex: 0 0 auto;
272
+ gap: var(--jolly-space-1, 4px);
273
+ width: var(--jolly-field-trailing-width, auto);
274
+ margin-inline-start: calc(var(--jolly-space-1, 4px) * -1);
275
+ padding-inline-start: var(--jolly-space-1, 4px);
276
+ }
277
+
278
+ .trailing:not(:has(.revert, .peers)) {
279
+ padding-inline-start: 0;
280
+ }
281
+
282
+ /*
283
+ * The muted action stays visible while a modified value can be restored.
284
+ * It joins the value edge and uses the full control height, so its hover fill
285
+ * reads as trailing field chrome instead of a highlight behind the glyph.
286
+ */
287
+ .revert {
288
+ display: flex;
289
+ align-items: center;
290
+ justify-content: center;
291
+ flex: 0 0 auto;
292
+ width: var(--jolly-control-height, 20px);
293
+ height: var(--jolly-control-height, 20px);
294
+ margin-inline-start: calc(var(--jolly-space-1, 4px) * -1);
295
+ padding: 0;
296
+ border: 0;
297
+ border-radius:
298
+ 0
299
+ var(--jolly-radius-sm, 2px)
300
+ var(--jolly-radius-sm, 2px)
301
+ 0;
302
+ background: none;
303
+ color: var(--jolly-text-muted);
304
+ cursor: pointer;
305
+ ${fillTransition}
306
+ }
307
+
308
+ .revert > jolly-icon {
309
+ width: 14px;
310
+ height: 14px;
311
+ }
312
+
313
+ /* Filled values and the trailing action form a single control silhouette. */
314
+ .value:has(+ .trailing > .revert) input[type="text"]:last-child,
315
+ .value:has(+ .trailing > .revert) select {
316
+ border-start-end-radius: 0;
317
+ border-end-end-radius: 0;
318
+ }
319
+
320
+ .revert:hover {
321
+ background: var(--jolly-control-bg);
322
+ }
323
+
324
+ .revert:focus-visible {
325
+ background: var(--jolly-control-bg-focus);
326
+ outline: none;
327
+ }
328
+
329
+ .peers {
330
+ display: flex;
331
+ flex: 0 0 auto;
332
+ align-items: center;
333
+ margin-inline-start: auto;
334
+ }
335
+
336
+ .chip {
337
+ width: 10px;
338
+ height: 10px;
339
+ margin-left: -3px;
340
+ border: 1px solid var(--jolly-surface);
341
+ border-radius: 50%;
342
+ }
343
+
344
+ .chip:first-child {
345
+ margin-left: 0;
346
+ }
347
+
348
+ .overflow {
349
+ margin-left: var(--jolly-space-1, 4px);
350
+ color: var(--jolly-text-muted);
351
+ font-size: 0.85em;
352
+ }
353
+
354
+ /* Tooltips grow inward to stay within the field bounds. */
355
+ [data-tooltip] {
356
+ position: relative;
357
+ }
358
+
359
+ [data-tooltip]::after {
360
+ content: attr(data-tooltip);
361
+ position: absolute;
362
+ bottom: calc(100% + var(--jolly-space-1, 4px));
363
+ z-index: 1;
364
+ padding: 2px 6px;
365
+ border-radius: var(--jolly-radius-sm, 2px);
366
+ background: var(--jolly-surface-raised);
367
+ box-shadow: var(--jolly-shadow-overlay);
368
+ color: var(--jolly-text);
369
+ font-size: 0.85em;
370
+ white-space: nowrap;
371
+ opacity: 0;
372
+ pointer-events: none;
373
+ transform: translateY(2px);
374
+ transition:
375
+ opacity var(--jolly-duration-fast, 100ms) var(--jolly-easing, ease),
376
+ transform var(--jolly-duration-fast, 100ms) var(--jolly-easing, ease);
377
+ }
378
+
379
+ /*
380
+ * Offset on the tooltip rather than as gutter padding, which would widen the
381
+ * gutter on exactly the rows that must not change width.
382
+ */
383
+ .gutter[data-tooltip]::after {
384
+ left: 3px;
385
+ }
386
+
387
+ .chip::after {
388
+ right: 0;
389
+ }
390
+
391
+ [data-tooltip]:hover::after {
392
+ opacity: 1;
393
+ transform: translateY(0);
394
+ }
395
+
396
+ /* Align help and error text with the value area. */
397
+ .description,
398
+ .error {
399
+ display: flex;
400
+ align-items: flex-start;
401
+ gap: var(--jolly-space-1, 4px);
402
+ margin-block: calc(var(--jolly-space-1, 4px) / 2);
403
+ margin-inline: calc(
404
+ var(--jolly-gutter-width, 0px) + (var(--jolly-space-1, 4px) * 2)
405
+ )
406
+ var(--jolly-space-1, 4px);
407
+ font-size: 0.9em;
408
+ }
409
+
410
+ /* No label column to clear, so they follow the value back to the row inset. */
411
+ :host([unlabeled]:not([locked])) .description,
412
+ :host([unlabeled]:not([locked])) .error {
413
+ margin-inline-start: calc(
414
+ var(--jolly-gutter-width, 0px) +
415
+ var(--jolly-field-inset-end, var(--jolly-space-1, 4px))
416
+ );
417
+ }
418
+
419
+ .description jolly-icon,
420
+ .error jolly-icon {
421
+ flex: 0 0 auto;
422
+ width: 14px;
423
+ height: 14px;
424
+ margin-block-start: 0;
425
+ }
426
+
427
+ .description {
428
+ color: var(--jolly-text-muted);
429
+ }
430
+
431
+ .description jolly-icon {
432
+ color: var(--jolly-accent-text);
433
+ }
434
+
435
+ .error {
436
+ color: var(--jolly-danger);
437
+ }
438
438
  `;
439
439
  //# sourceMappingURL=JollyField.styles.js.map