nexus-shared 3.1.0 → 3.2.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 (104) hide show
  1. package/CHANGELOG.md +704 -446
  2. package/LICENSE +21 -21
  3. package/README.md +44 -5
  4. package/dist/Client.Index.d.ts +3 -0
  5. package/dist/Client.Index.js +3 -0
  6. package/dist/Components/Forms/Crud.js +322 -161
  7. package/dist/Components/Forms/CrudHistory.d.ts +66 -0
  8. package/dist/Components/Forms/CrudHistory.js +140 -0
  9. package/dist/Components/Forms/CrudParts.js +2 -1
  10. package/dist/Components/Forms/Form.js +4 -1
  11. package/dist/Components/Inputs/CodeBox.d.ts +69 -0
  12. package/dist/Components/Inputs/CodeBox.js +316 -0
  13. package/dist/Components/Inputs/DatePicker.js +4 -1
  14. package/dist/Components/Inputs/DateRangePicker.js +4 -1
  15. package/dist/Components/Inputs/DateTimePicker.js +4 -1
  16. package/dist/Components/Inputs/Dropdown.js +4 -1
  17. package/dist/Components/Inputs/InputRenderer.js +3 -0
  18. package/dist/Components/Inputs/NumberBox.js +4 -2
  19. package/dist/Components/Inputs/TextArea.js +4 -1
  20. package/dist/Components/Inputs/TextBox.js +4 -1
  21. package/dist/Components/Inputs/TimePicker.js +4 -1
  22. package/dist/Components/Inputs/TreeView.d.ts +55 -5
  23. package/dist/Components/Inputs/TreeView.js +372 -23
  24. package/dist/Components/Layouts/ThemePicker.d.ts +3 -2
  25. package/dist/Components/Layouts/ThemePicker.js +16 -4
  26. package/dist/Components/Viewers/DataTable.js +63 -21
  27. package/dist/Components/Viewers/DataTableParts.d.ts +26 -8
  28. package/dist/Components/Viewers/DataTableParts.js +39 -10
  29. package/dist/Helpers/ApiModules.d.ts +3 -34
  30. package/dist/Helpers/ApiModules.js +3 -3
  31. package/dist/Helpers/ApiRoutes.d.ts +68 -26
  32. package/dist/Helpers/ApiRoutes.js +31 -27
  33. package/dist/Helpers/ArrayHelpers.d.ts +0 -0
  34. package/dist/Helpers/ArrayHelpers.js +2 -0
  35. package/dist/Helpers/CodeHelpers.d.ts +97 -0
  36. package/dist/Helpers/CodeHelpers.js +332 -0
  37. package/dist/Helpers/CrudBackend.d.ts +94 -4
  38. package/dist/Helpers/CrudBackend.js +168 -9
  39. package/dist/Helpers/CrudColumns.d.ts +51 -0
  40. package/dist/Helpers/CrudColumns.js +69 -0
  41. package/dist/Helpers/CrudHelpers.d.ts +50 -5
  42. package/dist/Helpers/CrudHelpers.js +109 -12
  43. package/dist/Helpers/InputParamsHelpers.js +8 -0
  44. package/dist/Helpers/MessageBuilder.js +2 -0
  45. package/dist/Helpers/NexusHelpers.d.ts +0 -0
  46. package/dist/Helpers/NexusHelpers.js +1 -0
  47. package/dist/Helpers/RequestCache.d.ts +35 -0
  48. package/dist/Helpers/RequestCache.js +113 -0
  49. package/dist/Helpers/TableExport.js +12 -12
  50. package/dist/Helpers/TableHelpers.d.ts +1 -1
  51. package/dist/Helpers/TableHelpers.js +7 -2
  52. package/dist/Helpers/TableJoins.d.ts +70 -0
  53. package/dist/Helpers/TableJoins.js +250 -0
  54. package/dist/Helpers/TableStore.d.ts +5 -0
  55. package/dist/Helpers/TableStore.js +9 -0
  56. package/dist/Helpers/TreeStore.d.ts +225 -11
  57. package/dist/Helpers/TreeStore.js +683 -90
  58. package/dist/Helpers/UserPreferences.d.ts +8 -0
  59. package/dist/Helpers/UserPreferences.js +17 -0
  60. package/dist/Interfaces/CrudInterfaces.d.ts +47 -9
  61. package/dist/Interfaces/FormInterfaces.d.ts +4 -1
  62. package/dist/Interfaces/InputInterfaces.d.ts +24 -0
  63. package/dist/Interfaces/MessageInterfaces.d.ts +1 -1
  64. package/dist/Interfaces/PreferenceInterfaces.d.ts +8 -0
  65. package/dist/Interfaces/PreferenceInterfaces.js +2 -5
  66. package/dist/Interfaces/TableInterfaces.d.ts +86 -4
  67. package/dist/Services/ApiProxy.d.ts +36 -1
  68. package/dist/Services/ApiProxy.js +182 -52
  69. package/dist/Services/ApiProxyRules.d.ts +203 -0
  70. package/dist/Services/ApiProxyRules.js +426 -0
  71. package/dist/Services/JoinSources.d.ts +48 -0
  72. package/dist/Services/JoinSources.js +74 -0
  73. package/dist/Services/ServerApi.d.ts +13 -2
  74. package/dist/Services/ServerApi.js +8 -3
  75. package/dist/Shared.Index.d.ts +4 -0
  76. package/dist/Shared.Index.js +4 -0
  77. package/package.json +87 -85
  78. package/src/Styles/Nexus.Avatar.css +79 -79
  79. package/src/Styles/Nexus.Base.css +117 -117
  80. package/src/Styles/Nexus.Button.css +180 -180
  81. package/src/Styles/Nexus.Calendar.css +273 -273
  82. package/src/Styles/Nexus.Chat.css +1443 -1443
  83. package/src/Styles/Nexus.Choice.css +343 -343
  84. package/src/Styles/Nexus.Crud.css +168 -168
  85. package/src/Styles/Nexus.DateTime.css +81 -81
  86. package/src/Styles/Nexus.Dropdown.css +725 -725
  87. package/src/Styles/Nexus.Editor.css +295 -295
  88. package/src/Styles/Nexus.Excel.css +389 -389
  89. package/src/Styles/Nexus.Form.css +279 -279
  90. package/src/Styles/Nexus.Index.css +37 -37
  91. package/src/Styles/Nexus.Input.css +196 -4
  92. package/src/Styles/Nexus.Markdown.css +237 -237
  93. package/src/Styles/Nexus.Menu.css +237 -237
  94. package/src/Styles/Nexus.Popup.css +724 -724
  95. package/src/Styles/Nexus.Rows.css +637 -637
  96. package/src/Styles/Nexus.Slider.css +276 -276
  97. package/src/Styles/Nexus.Tab.Buttons.css +432 -432
  98. package/src/Styles/Nexus.Table.css +31 -30
  99. package/src/Styles/Nexus.Theme.Picker.css +59 -3
  100. package/src/Styles/Nexus.Themes.css +194 -194
  101. package/src/Styles/Nexus.Time.css +144 -144
  102. package/src/Styles/Nexus.Toast.css +263 -263
  103. package/src/Styles/Nexus.Tokens.css +89 -89
  104. package/src/Styles/Nexus.Tree.css +500 -431
@@ -1,431 +1,500 @@
1
- @layer nexus.components {
2
- /*
3
- * Tree view: a panel with a toolbar and a scrolling list of rows. Rows have a fixed height (the component places
4
- * rows by it: keep --nx-tree-row and --nx-tree-pad in step with ROW_HEIGHT and PAD in TreeView.tsx). The checkbox
5
- * is the CheckBox control itself, so checked, mixed, and read-only boxes look the same as everywhere else.
6
- */
7
- .nx-tree {
8
- --nx-tree-row: 32px;
9
- --nx-tree-pad: 4px;
10
- --nx-tree-indent: 20px;
11
- --nx-tree-font: var(--nx-text-md);
12
- --nx-tree-open: 200ms;
13
- --nx-tree-close: 160ms;
14
- /* A line under every parent's chevron, soft enough to leave the rows in front. */
15
- --nx-tree-guide: color-mix(in oklab, var(--nx-border-strong) 55%, transparent);
16
-
17
- display: flex;
18
- flex-direction: column;
19
- min-width: 0;
20
- overflow: hidden;
21
- border: 1px solid var(--nx-field-border);
22
- border-radius: var(--nx-radius);
23
- background: var(--nx-field-bg);
24
- color: var(--nx-text);
25
- font-size: var(--nx-tree-font);
26
- line-height: 1.35;
27
- transition: border-color var(--nx-duration);
28
- }
29
-
30
- .nx-tree--sm {
31
- --nx-tree-row: 28px;
32
- --nx-tree-indent: 18px;
33
- --nx-tree-font: var(--nx-text-sm);
34
- }
35
-
36
- .nx-tree--lg {
37
- --nx-tree-row: 38px;
38
- --nx-tree-indent: 22px;
39
- --nx-tree-font: var(--nx-text-lg);
40
- }
41
-
42
- .nx-tree:hover {
43
- border-color: var(--nx-field-border-hover);
44
- }
45
-
46
- .nx-tree:focus-within {
47
- border-color: var(--nx-field-accent);
48
- }
49
-
50
- .nx-field:is([data-readonly], [data-disabled]) .nx-tree {
51
- border-color: var(--nx-field-border);
52
- }
53
-
54
- /* Toolbar: select all and counts at the start, tools at the end, a line under it. */
55
- .nx-tree__toolbar {
56
- display: flex;
57
- flex-wrap: wrap;
58
- align-items: center;
59
- gap: var(--nx-space-1) var(--nx-space-3);
60
- min-height: calc(var(--nx-control-sm) + 12px);
61
- padding: 6px 6px 6px var(--nx-space-3);
62
- border-bottom: 1px solid var(--nx-border);
63
- font-size: var(--nx-text-sm);
64
- }
65
-
66
- .nx-tree__all {
67
- flex: none;
68
- }
69
-
70
- .nx-tree__all .nx-choice__label {
71
- font-weight: 500;
72
- }
73
-
74
- /* A read-only tree has one lock, after its label; select all still shows the note when clicked. */
75
- .nx-tree__all .nx-field__lock {
76
- display: none;
77
- }
78
-
79
- .nx-tree__summary {
80
- display: inline-flex;
81
- align-items: center;
82
- gap: 6px;
83
- min-width: 0;
84
- margin-right: auto;
85
- color: var(--nx-text-muted);
86
- font-variant-numeric: tabular-nums;
87
- white-space: nowrap;
88
- }
89
-
90
- .nx-tree__summary .nx-icon {
91
- width: 14px;
92
- height: 14px;
93
- vertical-align: 0;
94
- }
95
-
96
- .nx-tree__tools {
97
- display: inline-flex;
98
- align-items: center;
99
- gap: 2px;
100
- }
101
-
102
- .nx-tree__tools .nx-btn--secondary {
103
- margin-left: var(--nx-space-1);
104
- }
105
-
106
- /* Rows */
107
- .nx-tree__viewport {
108
- position: relative;
109
- overflow: auto;
110
- overscroll-behavior: contain;
111
- outline: none;
112
- }
113
-
114
- .nx-tree__viewport:focus-visible {
115
- box-shadow: inset 0 0 0 2px var(--nx-primary);
116
- }
117
-
118
- .nx-tree__list {
119
- min-width: 0;
120
- padding-inline: var(--nx-tree-pad);
121
- }
122
-
123
- .nx-tree__row {
124
- --nx-tree-depth: 0;
125
- /* Muted texts of a row. On a hovered or focused row they move toward the text color, so they keep 4.5:1 on the
126
- hover tint in every theme. */
127
- --nx-tree-muted: var(--nx-text-muted);
128
- --nx-tree-count: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 25%);
129
-
130
- display: flex;
131
- align-items: center;
132
- gap: 6px;
133
- height: var(--nx-tree-row);
134
- padding: 0 4px 0 calc(var(--nx-tree-depth) * var(--nx-tree-indent));
135
- border-radius: var(--nx-radius);
136
- /* Guides: one line per level, centered under the chevron of the parent at that level. */
137
- background-image: repeating-linear-gradient(
138
- to right,
139
- transparent 0 calc(var(--nx-tree-indent) / 2 - 0.5px),
140
- var(--nx-tree-guide) calc(var(--nx-tree-indent) / 2 - 0.5px) calc(var(--nx-tree-indent) / 2 + 0.5px),
141
- transparent calc(var(--nx-tree-indent) / 2 + 0.5px) var(--nx-tree-indent)
142
- );
143
- background-repeat: no-repeat;
144
- background-size: calc(var(--nx-tree-depth) * var(--nx-tree-indent)) 100%;
145
- white-space: nowrap;
146
- cursor: pointer;
147
- user-select: none;
148
- outline: none;
149
- -webkit-tap-highlight-color: transparent;
150
- }
151
-
152
- .nx-tree__row[role="treeitem"]:hover {
153
- background-color: var(--nx-surface-hover);
154
- }
155
-
156
- .nx-tree__row:focus-visible {
157
- background-color: var(--nx-surface-hover);
158
- box-shadow: inset 0 0 0 2px var(--nx-primary);
159
- }
160
-
161
- .nx-tree__row[role="treeitem"]:is(:hover, :focus-visible) {
162
- --nx-tree-muted: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
163
- --nx-tree-count: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 50%);
164
- }
165
-
166
- .nx-tree__toggle {
167
- display: grid;
168
- flex: none;
169
- place-items: center;
170
- width: var(--nx-tree-indent);
171
- height: var(--nx-tree-indent);
172
- margin-right: -2px;
173
- border-radius: var(--nx-radius-sm);
174
- color: var(--nx-tree-muted);
175
- }
176
-
177
- .nx-tree__toggle .nx-icon {
178
- width: 14px;
179
- height: 14px;
180
- vertical-align: 0;
181
- transition: transform var(--nx-tree-open) cubic-bezier(0.2, 0, 0, 1);
182
- }
183
-
184
- .nx-tree__row[aria-expanded="true"] > .nx-tree__toggle .nx-icon {
185
- transform: rotate(90deg);
186
- }
187
-
188
- .nx-tree__toggle:has(.nx-icon):hover {
189
- background: color-mix(in oklab, var(--nx-text) 10%, transparent);
190
- color: var(--nx-text);
191
- }
192
-
193
- /* The CheckBox control, without its label's line-height offset; the row takes the clicks. */
194
- .nx-tree__check {
195
- flex: none;
196
- align-items: center;
197
- gap: 0;
198
- }
199
-
200
- .nx-tree__check .nx-choice__control {
201
- margin: 0;
202
- pointer-events: none;
203
- }
204
-
205
- .nx-tree__row:hover .nx-choice__control:not(:checked, :indeterminate, :disabled) {
206
- border-color: var(--nx-choice-border-hover);
207
- }
208
-
209
- .nx-tree__icon {
210
- display: grid;
211
- flex: none;
212
- place-items: center;
213
- color: var(--nx-tree-muted);
214
- }
215
-
216
- .nx-tree__icon .nx-icon {
217
- width: 1.15em;
218
- height: 1.15em;
219
- vertical-align: 0;
220
- }
221
-
222
- .nx-tree__text {
223
- display: flex;
224
- flex: 1 1 auto;
225
- align-items: baseline;
226
- gap: var(--nx-space-2);
227
- min-width: 0;
228
- overflow: hidden;
229
- }
230
-
231
- .nx-tree__label {
232
- flex: 0 1 auto;
233
- min-width: 2em;
234
- overflow: hidden;
235
- text-overflow: ellipsis;
236
- }
237
-
238
- .nx-tree__description {
239
- flex: 0 100 auto;
240
- min-width: 0;
241
- overflow: hidden;
242
- color: var(--nx-tree-muted);
243
- font-size: calc(var(--nx-tree-font) - 1px);
244
- text-overflow: ellipsis;
245
- }
246
-
247
- .nx-tree__count {
248
- flex: none;
249
- padding: 0 6px;
250
- border-radius: var(--nx-radius-full);
251
- background: color-mix(in oklab, var(--nx-text) 7%, transparent);
252
- color: var(--nx-tree-count);
253
- font-size: var(--nx-text-xs);
254
- font-variant-numeric: tabular-nums;
255
- line-height: 18px;
256
- }
257
-
258
- .nx-tree__lock,
259
- .nx-tree__busy {
260
- display: grid;
261
- flex: none;
262
- place-items: center;
263
- color: var(--nx-tree-muted);
264
- }
265
-
266
- .nx-tree__lock .nx-icon,
267
- .nx-tree__busy {
268
- width: 14px;
269
- height: 14px;
270
- vertical-align: 0;
271
- }
272
-
273
- /* A locked item: the read-only box (data-readonly), a muted label, and a lock. */
274
- .nx-tree__row--locked {
275
- cursor: default;
276
- }
277
-
278
- .nx-tree__row--locked .nx-tree__label {
279
- color: var(--nx-tree-muted);
280
- }
281
-
282
- /* Actions show on the row under the pointer or with focus; on touch screens, always. They keep their space, so
283
- labels do not jump when they appear. */
284
- .nx-tree__actions {
285
- display: flex;
286
- flex: none;
287
- gap: 1px;
288
- margin-left: auto;
289
- visibility: hidden;
290
- }
291
-
292
- .nx-tree__row:is(:hover, :focus-visible, :focus-within) > .nx-tree__actions {
293
- visibility: visible;
294
- }
295
-
296
- @media (hover: none) {
297
- .nx-tree__actions {
298
- visibility: visible;
299
- }
300
- }
301
-
302
- .nx-btn.nx-tree__action {
303
- --nx-btn-height: calc(var(--nx-tree-row) - 6px);
304
- }
305
-
306
- .nx-tree__action .nx-icon {
307
- width: 15px;
308
- height: 15px;
309
- }
310
-
311
- /* The name box of a row being added or renamed. */
312
- .nx-tree__edit {
313
- display: flex;
314
- flex: 1 1 auto;
315
- align-items: center;
316
- gap: 1px;
317
- min-width: 0;
318
- }
319
-
320
- .nx-tree__input {
321
- flex: 1 1 auto;
322
- width: 0;
323
- min-width: 6em;
324
- height: calc(var(--nx-tree-row) - 6px);
325
- margin: 0 2px 0 0;
326
- padding: 0 6px;
327
- border: 1px solid var(--nx-field-accent);
328
- border-radius: var(--nx-radius-sm);
329
- background: var(--nx-surface);
330
- box-shadow: var(--nx-field-ring);
331
- color: var(--nx-text);
332
- font: inherit;
333
- outline: none;
334
- }
335
-
336
- .nx-tree__input[aria-invalid="true"] {
337
- border-color: var(--nx-danger);
338
- box-shadow: 0 0 0 3px color-mix(in oklab, var(--nx-danger) 30%, transparent);
339
- }
340
-
341
- .nx-tree__input:read-only {
342
- color: var(--nx-text-muted);
343
- }
344
-
345
- /*
346
- * Expand and collapse: the rows that come or go sit in a group whose height opens from 0, or closes to 0. Only the
347
- * rows in view are in the group, so opening 10,000 children animates about 30 rows.
348
- */
349
- .nx-tree__motion {
350
- height: var(--nx-tree-motion-height);
351
- overflow: hidden;
352
- }
353
-
354
- .nx-tree__motion--open {
355
- animation: nx-tree-open var(--nx-tree-open) cubic-bezier(0.2, 0, 0, 1);
356
- }
357
-
358
- .nx-tree__motion--close {
359
- height: 0;
360
- pointer-events: none;
361
- animation: nx-tree-close var(--nx-tree-close) cubic-bezier(0.3, 0, 0.8, 0.15);
362
- }
363
-
364
- @keyframes nx-tree-open {
365
- from {
366
- height: 0;
367
- opacity: 0.35;
368
- }
369
- }
370
-
371
- @keyframes nx-tree-close {
372
- from {
373
- height: var(--nx-tree-motion-height);
374
- opacity: 1;
375
- }
376
- to {
377
- height: 0;
378
- opacity: 0;
379
- }
380
- }
381
-
382
- /* Loading and empty */
383
- .nx-tree__row--skeleton {
384
- cursor: default;
385
- }
386
-
387
- .nx-tree__skeleton {
388
- display: inline-block;
389
- height: 0.7em;
390
- border-radius: var(--nx-radius-full);
391
- background: color-mix(in oklab, var(--nx-text) 11%, transparent);
392
- animation: nx-tree-pulse 1.2s ease-in-out infinite;
393
- }
394
-
395
- @keyframes nx-tree-pulse {
396
- 50% {
397
- opacity: 0.45;
398
- }
399
- }
400
-
401
- .nx-tree__empty {
402
- margin: 0;
403
- padding: var(--nx-space-6) var(--nx-space-4);
404
- color: var(--nx-text-muted);
405
- font-size: var(--nx-text-sm);
406
- text-align: center;
407
- }
408
-
409
- /* States of the whole tree */
410
- .nx-field[data-disabled] .nx-tree__row {
411
- cursor: not-allowed;
412
- }
413
-
414
- .nx-field[data-disabled] .nx-tree__row:hover {
415
- background-color: transparent;
416
- }
417
-
418
- .nx-field[data-readonly] .nx-tree__row {
419
- cursor: default;
420
- }
421
-
422
- [data-nx-motion="reduce"] .nx-tree__motion,
423
- [data-nx-motion="reduce"] .nx-tree__skeleton {
424
- animation: none;
425
- }
426
-
427
- [data-nx-motion="reduce"] .nx-tree,
428
- [data-nx-motion="reduce"] .nx-tree__toggle .nx-icon {
429
- transition: none;
430
- }
431
- }
1
+ @layer nexus.components {
2
+ /*
3
+ * Tree view: a panel with a toolbar and a scrolling list of rows. Rows have a fixed height (the component places
4
+ * rows by it: keep --nx-tree-row and --nx-tree-pad in step with ROW_HEIGHT and PAD in TreeView.tsx). The checkbox
5
+ * is the CheckBox control itself, so checked, mixed, and read-only boxes look the same as everywhere else.
6
+ */
7
+ .nx-tree {
8
+ --nx-tree-row: 32px;
9
+ --nx-tree-pad: 4px;
10
+ --nx-tree-indent: 20px;
11
+ --nx-tree-font: var(--nx-text-md);
12
+ --nx-tree-open: 200ms;
13
+ --nx-tree-close: 160ms;
14
+ /* A line under every parent's chevron, soft enough to leave the rows in front. */
15
+ --nx-tree-guide: color-mix(in oklab, var(--nx-border-strong) 55%, transparent);
16
+
17
+ display: flex;
18
+ flex-direction: column;
19
+ min-width: 0;
20
+ overflow: hidden;
21
+ border: 1px solid var(--nx-field-border);
22
+ border-radius: var(--nx-radius);
23
+ background: var(--nx-field-bg);
24
+ color: var(--nx-text);
25
+ font-size: var(--nx-tree-font);
26
+ line-height: 1.35;
27
+ transition: border-color var(--nx-duration);
28
+ }
29
+
30
+ .nx-tree--sm {
31
+ --nx-tree-row: 28px;
32
+ --nx-tree-indent: 18px;
33
+ --nx-tree-font: var(--nx-text-sm);
34
+ }
35
+
36
+ .nx-tree--lg {
37
+ --nx-tree-row: 38px;
38
+ --nx-tree-indent: 22px;
39
+ --nx-tree-font: var(--nx-text-lg);
40
+ }
41
+
42
+ .nx-tree:hover {
43
+ border-color: var(--nx-field-border-hover);
44
+ }
45
+
46
+ .nx-tree:focus-within {
47
+ border-color: var(--nx-field-accent);
48
+ }
49
+
50
+ .nx-field:is([data-readonly], [data-disabled]) .nx-tree {
51
+ border-color: var(--nx-field-border);
52
+ }
53
+
54
+ /* Toolbar: select all and counts at the start, tools at the end, a line under it. */
55
+ .nx-tree__toolbar {
56
+ display: flex;
57
+ flex-wrap: wrap;
58
+ align-items: center;
59
+ gap: var(--nx-space-1) var(--nx-space-3);
60
+ min-height: calc(var(--nx-control-sm) + 12px);
61
+ padding: 6px 6px 6px var(--nx-space-3);
62
+ border-bottom: 1px solid var(--nx-border);
63
+ font-size: var(--nx-text-sm);
64
+ }
65
+
66
+ .nx-tree__all {
67
+ flex: none;
68
+ }
69
+
70
+ .nx-tree__all .nx-choice__label {
71
+ font-weight: 500;
72
+ }
73
+
74
+ /* A read-only tree has one lock, after its label; select all still shows the note when clicked. */
75
+ .nx-tree__all .nx-field__lock {
76
+ display: none;
77
+ }
78
+
79
+ .nx-tree__summary {
80
+ display: inline-flex;
81
+ align-items: center;
82
+ gap: 6px;
83
+ min-width: 0;
84
+ margin-right: auto;
85
+ color: var(--nx-text-muted);
86
+ font-variant-numeric: tabular-nums;
87
+ white-space: nowrap;
88
+ }
89
+
90
+ .nx-tree__summary .nx-icon {
91
+ width: 14px;
92
+ height: 14px;
93
+ vertical-align: 0;
94
+ }
95
+
96
+ .nx-tree__tools {
97
+ display: inline-flex;
98
+ align-items: center;
99
+ gap: 2px;
100
+ }
101
+
102
+ .nx-tree__tools .nx-btn--secondary {
103
+ margin-left: var(--nx-space-1);
104
+ }
105
+
106
+ /* Rows */
107
+ .nx-tree__viewport {
108
+ position: relative;
109
+ overflow: auto;
110
+ overscroll-behavior: contain;
111
+ outline: none;
112
+ }
113
+
114
+ .nx-tree__viewport:focus-visible {
115
+ box-shadow: inset 0 0 0 2px var(--nx-primary);
116
+ }
117
+
118
+ .nx-tree__list {
119
+ min-width: 0;
120
+ padding-inline: var(--nx-tree-pad);
121
+ }
122
+
123
+ .nx-tree__row {
124
+ --nx-tree-depth: 0;
125
+ /* Muted texts of a row. On a hovered or focused row they move toward the text color, so they keep 4.5:1 on the
126
+ hover tint in every theme. */
127
+ --nx-tree-muted: var(--nx-text-muted);
128
+ --nx-tree-count: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 25%);
129
+
130
+ display: flex;
131
+ align-items: center;
132
+ gap: 6px;
133
+ height: var(--nx-tree-row);
134
+ padding: 0 4px 0 calc(var(--nx-tree-depth) * var(--nx-tree-indent));
135
+ border-radius: var(--nx-radius);
136
+ /* Guides: one line per level, centered under the chevron of the parent at that level. */
137
+ background-image: repeating-linear-gradient(
138
+ to right,
139
+ transparent 0 calc(var(--nx-tree-indent) / 2 - 0.5px),
140
+ var(--nx-tree-guide) calc(var(--nx-tree-indent) / 2 - 0.5px) calc(var(--nx-tree-indent) / 2 + 0.5px),
141
+ transparent calc(var(--nx-tree-indent) / 2 + 0.5px) var(--nx-tree-indent)
142
+ );
143
+ background-repeat: no-repeat;
144
+ background-size: calc(var(--nx-tree-depth) * var(--nx-tree-indent)) 100%;
145
+ white-space: nowrap;
146
+ cursor: pointer;
147
+ user-select: none;
148
+ outline: none;
149
+ -webkit-tap-highlight-color: transparent;
150
+ }
151
+
152
+ .nx-tree__row[role="treeitem"]:hover {
153
+ background-color: var(--nx-surface-hover);
154
+ }
155
+
156
+ .nx-tree__row:focus-visible {
157
+ background-color: var(--nx-surface-hover);
158
+ box-shadow: inset 0 0 0 2px var(--nx-primary);
159
+ }
160
+
161
+ .nx-tree__row[role="treeitem"]:is(:hover, :focus-visible) {
162
+ --nx-tree-muted: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
163
+ --nx-tree-count: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 50%);
164
+ }
165
+
166
+ .nx-tree__toggle {
167
+ display: grid;
168
+ flex: none;
169
+ place-items: center;
170
+ width: var(--nx-tree-indent);
171
+ height: var(--nx-tree-indent);
172
+ margin-right: -2px;
173
+ border-radius: var(--nx-radius-sm);
174
+ color: var(--nx-tree-muted);
175
+ }
176
+
177
+ .nx-tree__toggle .nx-icon {
178
+ width: 14px;
179
+ height: 14px;
180
+ vertical-align: 0;
181
+ transition: transform var(--nx-tree-open) cubic-bezier(0.2, 0, 0, 1);
182
+ }
183
+
184
+ .nx-tree__row[aria-expanded="true"] > .nx-tree__toggle .nx-icon {
185
+ transform: rotate(90deg);
186
+ }
187
+
188
+ .nx-tree__toggle:has(.nx-icon):hover {
189
+ background: color-mix(in oklab, var(--nx-text) 10%, transparent);
190
+ color: var(--nx-text);
191
+ }
192
+
193
+ /* The CheckBox control, without its label's line-height offset; the row takes the clicks. */
194
+ .nx-tree__check {
195
+ flex: none;
196
+ align-items: center;
197
+ gap: 0;
198
+ }
199
+
200
+ .nx-tree__check .nx-choice__control {
201
+ margin: 0;
202
+ pointer-events: none;
203
+ }
204
+
205
+ .nx-tree__row:hover .nx-choice__control:not(:checked, :indeterminate, :disabled) {
206
+ border-color: var(--nx-choice-border-hover);
207
+ }
208
+
209
+ .nx-tree__icon {
210
+ display: grid;
211
+ flex: none;
212
+ place-items: center;
213
+ color: var(--nx-tree-muted);
214
+ }
215
+
216
+ .nx-tree__icon .nx-icon {
217
+ width: 1.15em;
218
+ height: 1.15em;
219
+ vertical-align: 0;
220
+ }
221
+
222
+ .nx-tree__text {
223
+ display: flex;
224
+ flex: 1 1 auto;
225
+ align-items: baseline;
226
+ gap: var(--nx-space-2);
227
+ min-width: 0;
228
+ overflow: hidden;
229
+ }
230
+
231
+ .nx-tree__label {
232
+ flex: 0 1 auto;
233
+ min-width: 2em;
234
+ overflow: hidden;
235
+ text-overflow: ellipsis;
236
+ }
237
+
238
+ .nx-tree__description {
239
+ flex: 0 100 auto;
240
+ min-width: 0;
241
+ overflow: hidden;
242
+ color: var(--nx-tree-muted);
243
+ font-size: calc(var(--nx-tree-font) - 1px);
244
+ text-overflow: ellipsis;
245
+ }
246
+
247
+ .nx-tree__count {
248
+ flex: none;
249
+ padding: 0 6px;
250
+ border-radius: var(--nx-radius-full);
251
+ background: color-mix(in oklab, var(--nx-text) 7%, transparent);
252
+ color: var(--nx-tree-count);
253
+ font-size: var(--nx-text-xs);
254
+ font-variant-numeric: tabular-nums;
255
+ line-height: 18px;
256
+ }
257
+
258
+ .nx-tree__lock,
259
+ .nx-tree__busy {
260
+ display: grid;
261
+ flex: none;
262
+ place-items: center;
263
+ color: var(--nx-tree-muted);
264
+ }
265
+
266
+ .nx-tree__lock .nx-icon,
267
+ .nx-tree__busy {
268
+ width: 14px;
269
+ height: 14px;
270
+ vertical-align: 0;
271
+ }
272
+
273
+ /*
274
+ * Rows that are not items, under a parent of a lazy tree (loadChildren): its page on its way, a page that failed
275
+ * with Retry, and Load more. They sit at the children's level and take no checkbox; the whole row is the button, so
276
+ * the Retry drawn in it is not a second stop for the keyboard.
277
+ */
278
+ .nx-tree__row--status {
279
+ cursor: default;
280
+ }
281
+
282
+ .nx-tree__row--more,
283
+ .nx-tree__row--error {
284
+ cursor: pointer;
285
+ }
286
+
287
+ /* Nothing to press while a page comes. */
288
+ .nx-tree__row--loading[role="treeitem"]:hover {
289
+ background-color: transparent;
290
+ }
291
+
292
+ .nx-tree__status-icon {
293
+ flex: none;
294
+ width: 14px;
295
+ height: 14px;
296
+ color: var(--nx-tree-muted);
297
+ vertical-align: 0;
298
+ }
299
+
300
+ /* The sentence keeps its own width, so Retry follows it rather than the row's far end. */
301
+ .nx-tree__row--status .nx-tree__text {
302
+ flex: 0 1 auto;
303
+ }
304
+
305
+ .nx-tree__status-text {
306
+ flex: 0 1 auto;
307
+ min-width: 0;
308
+ overflow: hidden;
309
+ color: var(--nx-tree-muted);
310
+ text-overflow: ellipsis;
311
+ }
312
+
313
+ .nx-tree__row--error .nx-tree__status-icon {
314
+ color: var(--nx-danger);
315
+ }
316
+
317
+ .nx-tree__row--error .nx-tree__status-text {
318
+ color: var(--nx-text);
319
+ }
320
+
321
+ /* The accent as text; on the hover tint it moves toward the text color, as muted texts do, to keep 4.5:1 (the plain
322
+ accent measured 3.79:1 on Dracula dark's hover tint). */
323
+ .nx-tree__row--more {
324
+ --nx-tree-link: var(--nx-primary);
325
+ }
326
+
327
+ .nx-tree__row--more:is(:hover, :focus-visible) {
328
+ --nx-tree-link: color-mix(in oklab, var(--nx-primary), var(--nx-text) 35%);
329
+ }
330
+
331
+ .nx-tree__row--more .nx-tree__status-text {
332
+ color: var(--nx-tree-link);
333
+ font-weight: 500;
334
+ }
335
+
336
+ .nx-btn.nx-tree__retry {
337
+ --nx-btn-height: calc(var(--nx-tree-row) - 6px);
338
+ flex: none;
339
+ margin-left: var(--nx-space-1);
340
+ }
341
+
342
+ /* A locked item: the read-only box (data-readonly), a muted label, and a lock. */
343
+ .nx-tree__row--locked {
344
+ cursor: default;
345
+ }
346
+
347
+ .nx-tree__row--locked .nx-tree__label {
348
+ color: var(--nx-tree-muted);
349
+ }
350
+
351
+ /* Actions show on the row under the pointer or with focus; on touch screens, always. They keep their space, so
352
+ labels do not jump when they appear. */
353
+ .nx-tree__actions {
354
+ display: flex;
355
+ flex: none;
356
+ gap: 1px;
357
+ margin-left: auto;
358
+ visibility: hidden;
359
+ }
360
+
361
+ .nx-tree__row:is(:hover, :focus-visible, :focus-within) > .nx-tree__actions {
362
+ visibility: visible;
363
+ }
364
+
365
+ @media (hover: none) {
366
+ .nx-tree__actions {
367
+ visibility: visible;
368
+ }
369
+ }
370
+
371
+ .nx-btn.nx-tree__action {
372
+ --nx-btn-height: calc(var(--nx-tree-row) - 6px);
373
+ }
374
+
375
+ .nx-tree__action .nx-icon {
376
+ width: 15px;
377
+ height: 15px;
378
+ }
379
+
380
+ /* The name box of a row being added or renamed. */
381
+ .nx-tree__edit {
382
+ display: flex;
383
+ flex: 1 1 auto;
384
+ align-items: center;
385
+ gap: 1px;
386
+ min-width: 0;
387
+ }
388
+
389
+ .nx-tree__input {
390
+ flex: 1 1 auto;
391
+ width: 0;
392
+ min-width: 6em;
393
+ height: calc(var(--nx-tree-row) - 6px);
394
+ margin: 0 2px 0 0;
395
+ padding: 0 6px;
396
+ border: 1px solid var(--nx-field-accent);
397
+ border-radius: var(--nx-radius-sm);
398
+ background: var(--nx-surface);
399
+ box-shadow: var(--nx-field-ring);
400
+ color: var(--nx-text);
401
+ font: inherit;
402
+ outline: none;
403
+ }
404
+
405
+ .nx-tree__input[aria-invalid="true"] {
406
+ border-color: var(--nx-danger);
407
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--nx-danger) 30%, transparent);
408
+ }
409
+
410
+ .nx-tree__input:read-only {
411
+ color: var(--nx-text-muted);
412
+ }
413
+
414
+ /*
415
+ * Expand and collapse: the rows that come or go sit in a group whose height opens from 0, or closes to 0. Only the
416
+ * rows in view are in the group, so opening 10,000 children animates about 30 rows.
417
+ */
418
+ .nx-tree__motion {
419
+ height: var(--nx-tree-motion-height);
420
+ overflow: hidden;
421
+ }
422
+
423
+ .nx-tree__motion--open {
424
+ animation: nx-tree-open var(--nx-tree-open) cubic-bezier(0.2, 0, 0, 1);
425
+ }
426
+
427
+ .nx-tree__motion--close {
428
+ height: 0;
429
+ pointer-events: none;
430
+ animation: nx-tree-close var(--nx-tree-close) cubic-bezier(0.3, 0, 0.8, 0.15);
431
+ }
432
+
433
+ @keyframes nx-tree-open {
434
+ from {
435
+ height: 0;
436
+ opacity: 0.35;
437
+ }
438
+ }
439
+
440
+ @keyframes nx-tree-close {
441
+ from {
442
+ height: var(--nx-tree-motion-height);
443
+ opacity: 1;
444
+ }
445
+ to {
446
+ height: 0;
447
+ opacity: 0;
448
+ }
449
+ }
450
+
451
+ /* Loading and empty */
452
+ .nx-tree__row--skeleton {
453
+ cursor: default;
454
+ }
455
+
456
+ .nx-tree__skeleton {
457
+ display: inline-block;
458
+ height: 0.7em;
459
+ border-radius: var(--nx-radius-full);
460
+ background: color-mix(in oklab, var(--nx-text) 11%, transparent);
461
+ animation: nx-tree-pulse 1.2s ease-in-out infinite;
462
+ }
463
+
464
+ @keyframes nx-tree-pulse {
465
+ 50% {
466
+ opacity: 0.45;
467
+ }
468
+ }
469
+
470
+ .nx-tree__empty {
471
+ margin: 0;
472
+ padding: var(--nx-space-6) var(--nx-space-4);
473
+ color: var(--nx-text-muted);
474
+ font-size: var(--nx-text-sm);
475
+ text-align: center;
476
+ }
477
+
478
+ /* States of the whole tree */
479
+ .nx-field[data-disabled] .nx-tree__row {
480
+ cursor: not-allowed;
481
+ }
482
+
483
+ .nx-field[data-disabled] .nx-tree__row:hover {
484
+ background-color: transparent;
485
+ }
486
+
487
+ .nx-field[data-readonly] .nx-tree__row {
488
+ cursor: default;
489
+ }
490
+
491
+ [data-nx-motion="reduce"] .nx-tree__motion,
492
+ [data-nx-motion="reduce"] .nx-tree__skeleton {
493
+ animation: none;
494
+ }
495
+
496
+ [data-nx-motion="reduce"] .nx-tree,
497
+ [data-nx-motion="reduce"] .nx-tree__toggle .nx-icon {
498
+ transition: none;
499
+ }
500
+ }