nexus-shared 2.0.0 → 3.1.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 (176) hide show
  1. package/CHANGELOG.md +446 -0
  2. package/LICENSE +21 -21
  3. package/README.md +1084 -903
  4. package/dist/Client.Index.d.ts +14 -0
  5. package/dist/Client.Index.js +14 -0
  6. package/dist/Components/Chats/Chat.d.ts +28 -0
  7. package/dist/Components/Chats/Chat.js +19 -0
  8. package/dist/Components/Chats/ChatButton.d.ts +26 -0
  9. package/dist/Components/Chats/ChatButton.js +41 -0
  10. package/dist/Components/Chats/ChatComposer.d.ts +41 -0
  11. package/dist/Components/Chats/ChatComposer.js +177 -0
  12. package/dist/Components/Chats/ChatConversations.d.ts +35 -0
  13. package/dist/Components/Chats/ChatConversations.js +38 -0
  14. package/dist/Components/Chats/ChatPanel.d.ts +66 -0
  15. package/dist/Components/Chats/ChatPanel.js +94 -0
  16. package/dist/Components/Chats/ChatParts.d.ts +87 -0
  17. package/dist/Components/Chats/ChatParts.js +96 -0
  18. package/dist/Components/Chats/ChatThread.d.ts +22 -0
  19. package/dist/Components/Chats/ChatThread.js +96 -0
  20. package/dist/Components/Documents/Button.d.ts +6 -1
  21. package/dist/Components/Documents/Button.js +2 -2
  22. package/dist/Components/Documents/Menu.js +44 -28
  23. package/dist/Components/Documents/SplitButton.d.ts +3 -1
  24. package/dist/Components/Documents/SplitButton.js +12 -8
  25. package/dist/Components/Documents/TabButtons.d.ts +29 -8
  26. package/dist/Components/Documents/TabButtons.js +24 -5
  27. package/dist/Components/Forms/ApiForm.d.ts +6 -4
  28. package/dist/Components/Forms/ApiForm.js +15 -14
  29. package/dist/Components/Forms/Crud.js +342 -71
  30. package/dist/Components/Forms/CrudParts.d.ts +5 -1
  31. package/dist/Components/Forms/CrudParts.js +37 -5
  32. package/dist/Components/Forms/ExcelImport.d.ts +58 -0
  33. package/dist/Components/Forms/ExcelImport.js +319 -0
  34. package/dist/Components/Forms/Form.js +9 -13
  35. package/dist/Components/Forms/SubmitForm.d.ts +11 -2
  36. package/dist/Components/Forms/SubmitForm.js +23 -12
  37. package/dist/Components/Inputs/DateTimePicker.js +2 -1
  38. package/dist/Components/Inputs/DropdownParts.d.ts +1 -1
  39. package/dist/Components/Inputs/DropdownParts.js +4 -6
  40. package/dist/Components/Inputs/GroupForm.js +4 -2
  41. package/dist/Components/Inputs/InputRenderer.d.ts +2 -0
  42. package/dist/Components/Inputs/InputRenderer.js +1 -1
  43. package/dist/Components/Inputs/NumberBox.js +24 -2
  44. package/dist/Components/Inputs/ReadOnlyNotice.js +2 -1
  45. package/dist/Components/Inputs/RowsInput.d.ts +12 -1
  46. package/dist/Components/Inputs/RowsInput.js +55 -6
  47. package/dist/Components/Inputs/Slider.js +4 -1
  48. package/dist/Components/Inputs/TabularForm.d.ts +7 -3
  49. package/dist/Components/Inputs/TabularForm.js +117 -20
  50. package/dist/Components/Inputs/TimePanel.js +4 -3
  51. package/dist/Components/Inputs/TimePicker.js +2 -1
  52. package/dist/Components/Layouts/Popup.js +1 -4
  53. package/dist/Components/Layouts/ThemePicker.d.ts +20 -3
  54. package/dist/Components/Layouts/ThemePicker.js +77 -6
  55. package/dist/Components/Layouts/ThemeScript.d.ts +4 -2
  56. package/dist/Components/Layouts/ThemeScript.js +4 -2
  57. package/dist/Components/Layouts/ThemeSwitcher.d.ts +6 -3
  58. package/dist/Components/Layouts/ThemeSwitcher.js +39 -18
  59. package/dist/Components/Viewers/Avatar.d.ts +21 -0
  60. package/dist/Components/Viewers/Avatar.js +21 -0
  61. package/dist/Components/Viewers/DataTable.js +262 -60
  62. package/dist/Components/Viewers/DataTableColumns.d.ts +32 -0
  63. package/dist/Components/Viewers/DataTableColumns.js +200 -0
  64. package/dist/Components/Viewers/DataTableFilters.d.ts +21 -0
  65. package/dist/Components/Viewers/DataTableFilters.js +68 -0
  66. package/dist/Components/Viewers/DataTableParts.d.ts +8 -4
  67. package/dist/Components/Viewers/DataTableParts.js +24 -12
  68. package/dist/Helpers/AnimationHelpers.d.ts +11 -0
  69. package/dist/Helpers/AnimationHelpers.js +20 -2
  70. package/dist/Helpers/ApiClient.d.ts +22 -0
  71. package/dist/Helpers/ApiClient.js +4 -1
  72. package/dist/Helpers/ApiFormHelpers.d.ts +27 -4
  73. package/dist/Helpers/ApiFormHelpers.js +73 -9
  74. package/dist/Helpers/ApiModules.d.ts +0 -4
  75. package/dist/Helpers/ApiModules.js +1 -0
  76. package/dist/Helpers/ApiResponses.d.ts +14 -4
  77. package/dist/Helpers/ApiResponses.js +116 -25
  78. package/dist/Helpers/ApiRoutes.d.ts +0 -10
  79. package/dist/Helpers/ApiRoutes.js +2 -10
  80. package/dist/Helpers/ChatBackend.d.ts +134 -0
  81. package/dist/Helpers/ChatBackend.js +332 -0
  82. package/dist/Helpers/ChatHelpers.d.ts +189 -0
  83. package/dist/Helpers/ChatHelpers.js +486 -0
  84. package/dist/Helpers/ChatHooks.d.ts +81 -0
  85. package/dist/Helpers/ChatHooks.js +175 -0
  86. package/dist/Helpers/ChatStore.d.ts +132 -0
  87. package/dist/Helpers/ChatStore.js +394 -0
  88. package/dist/Helpers/ChatSummaries.d.ts +39 -0
  89. package/dist/Helpers/ChatSummaries.js +118 -0
  90. package/dist/Helpers/CrudBackend.d.ts +54 -9
  91. package/dist/Helpers/CrudBackend.js +103 -6
  92. package/dist/Helpers/CrudHelpers.d.ts +39 -4
  93. package/dist/Helpers/CrudHelpers.js +76 -11
  94. package/dist/Helpers/ExcelBackend.d.ts +106 -0
  95. package/dist/Helpers/ExcelBackend.js +296 -0
  96. package/dist/Helpers/ExcelHelpers.d.ts +126 -0
  97. package/dist/Helpers/ExcelHelpers.js +344 -0
  98. package/dist/Helpers/FormStore.d.ts +11 -5
  99. package/dist/Helpers/FormStore.js +44 -6
  100. package/dist/Helpers/MessageBuilder.js +1 -2
  101. package/dist/Helpers/NumberHelpers.d.ts +7 -1
  102. package/dist/Helpers/NumberHelpers.js +41 -3
  103. package/dist/Helpers/PopoverHelpers.d.ts +46 -9
  104. package/dist/Helpers/PopoverHelpers.js +163 -24
  105. package/dist/Helpers/PopoverHooks.d.ts +24 -0
  106. package/dist/Helpers/PopoverHooks.js +62 -0
  107. package/dist/Helpers/RowsStore.d.ts +14 -3
  108. package/dist/Helpers/RowsStore.js +37 -3
  109. package/dist/Helpers/TableColumns.d.ts +7 -0
  110. package/dist/Helpers/TableColumns.js +41 -13
  111. package/dist/Helpers/TableExport.js +12 -12
  112. package/dist/Helpers/TableFilters.d.ts +25 -0
  113. package/dist/Helpers/TableFilters.js +162 -0
  114. package/dist/Helpers/TableHelpers.d.ts +15 -4
  115. package/dist/Helpers/TableHelpers.js +28 -4
  116. package/dist/Helpers/TableStore.d.ts +11 -3
  117. package/dist/Helpers/TableStore.js +16 -5
  118. package/dist/Helpers/ThemeHelpers.d.ts +21 -4
  119. package/dist/Helpers/ThemeHelpers.js +46 -9
  120. package/dist/Helpers/UserPreferences.d.ts +14 -0
  121. package/dist/Helpers/UserPreferences.js +99 -0
  122. package/dist/Interfaces/ApiInterfaces.d.ts +29 -4
  123. package/dist/Interfaces/ApiInterfaces.js +16 -10
  124. package/dist/Interfaces/ChatInterfaces.d.ts +240 -0
  125. package/dist/Interfaces/ChatInterfaces.js +1 -0
  126. package/dist/Interfaces/CrudInterfaces.d.ts +92 -12
  127. package/dist/Interfaces/ExcelInterfaces.d.ts +227 -0
  128. package/dist/Interfaces/ExcelInterfaces.js +45 -0
  129. package/dist/Interfaces/FormInterfaces.d.ts +85 -7
  130. package/dist/Interfaces/MessageInterfaces.d.ts +1 -1
  131. package/dist/Interfaces/PreferenceInterfaces.d.ts +43 -0
  132. package/dist/Interfaces/PreferenceInterfaces.js +28 -0
  133. package/dist/Interfaces/TableInterfaces.d.ts +116 -9
  134. package/dist/Interfaces/ThemeInterfaces.d.ts +25 -0
  135. package/dist/Interfaces/ThemeInterfaces.js +15 -0
  136. package/dist/Services/BrowserApi.d.ts +18 -1
  137. package/dist/Services/BrowserApi.js +18 -0
  138. package/dist/Services/ChatApi.d.ts +37 -0
  139. package/dist/Services/ChatApi.js +98 -0
  140. package/dist/Services/ExcelApi.d.ts +48 -0
  141. package/dist/Services/ExcelApi.js +196 -0
  142. package/dist/Services/ServerApi.d.ts +6 -1
  143. package/dist/Services/ServerApi.js +3 -0
  144. package/dist/Services/ThemeService.d.ts +18 -2
  145. package/dist/Services/ThemeService.js +80 -16
  146. package/dist/Shared.Index.d.ts +10 -0
  147. package/dist/Shared.Index.js +10 -0
  148. package/package.json +85 -82
  149. package/src/Styles/Nexus.Avatar.css +79 -0
  150. package/src/Styles/Nexus.Base.css +117 -70
  151. package/src/Styles/Nexus.Button.css +180 -151
  152. package/src/Styles/Nexus.Calendar.css +273 -275
  153. package/src/Styles/Nexus.Chat.css +1443 -0
  154. package/src/Styles/Nexus.Choice.css +343 -345
  155. package/src/Styles/Nexus.Crud.css +168 -84
  156. package/src/Styles/Nexus.DateTime.css +81 -81
  157. package/src/Styles/Nexus.Dropdown.css +725 -774
  158. package/src/Styles/Nexus.Editor.css +295 -297
  159. package/src/Styles/Nexus.Excel.css +389 -0
  160. package/src/Styles/Nexus.Form.css +279 -298
  161. package/src/Styles/Nexus.Index.css +37 -34
  162. package/src/Styles/Nexus.Input.css +602 -637
  163. package/src/Styles/Nexus.Markdown.css +237 -265
  164. package/src/Styles/Nexus.Menu.css +237 -249
  165. package/src/Styles/Nexus.Popup.css +724 -731
  166. package/src/Styles/Nexus.RichText.css +2 -32
  167. package/src/Styles/Nexus.Rows.css +637 -566
  168. package/src/Styles/Nexus.Slider.css +276 -278
  169. package/src/Styles/Nexus.Tab.Buttons.css +432 -364
  170. package/src/Styles/Nexus.Table.css +1386 -1014
  171. package/src/Styles/Nexus.Theme.Picker.css +286 -159
  172. package/src/Styles/Nexus.Themes.css +194 -194
  173. package/src/Styles/Nexus.Time.css +144 -147
  174. package/src/Styles/Nexus.Toast.css +263 -265
  175. package/src/Styles/Nexus.Tokens.css +89 -72
  176. package/src/Styles/Nexus.Tree.css +431 -435
@@ -1,566 +1,637 @@
1
- @layer nexus.components {
2
- /*
3
- * Tabular and group forms: rows of inputs in a table, or as sections. Both sit in a fieldset with a legend, and end
4
- * with a line that holds the Add button, the rows' message (or a removed row with Undo), and the count.
5
- */
6
- .nx-rows {
7
- min-width: 0;
8
- margin: 0;
9
- padding: 0;
10
- border: 0;
11
- }
12
-
13
- .nx-rows__legend {
14
- margin-bottom: 6px;
15
- padding: 0;
16
- }
17
-
18
- .nx-rows__footer {
19
- display: flex;
20
- flex-wrap: wrap;
21
- align-items: center;
22
- gap: var(--nx-space-2) var(--nx-space-3);
23
- margin-top: var(--nx-space-2);
24
- }
25
-
26
- .nx-rows__message {
27
- flex: 1 1 14rem;
28
- align-items: center;
29
- min-width: 0;
30
- margin: 0;
31
- font-size: var(--nx-text-xs);
32
- line-height: 1.35;
33
- }
34
-
35
- .nx-rows__removed {
36
- display: flex;
37
- gap: var(--nx-space-2);
38
- color: var(--nx-text-muted);
39
- }
40
-
41
- .nx-rows__removed .nx-btn {
42
- margin-block: -4px;
43
- }
44
-
45
- .nx-rows__count {
46
- margin-left: auto;
47
- color: var(--nx-text-muted);
48
- font-size: var(--nx-text-xs);
49
- font-variant-numeric: tabular-nums;
50
- white-space: nowrap;
51
- }
52
-
53
- /*
54
- * Tabular form. Rows have a fixed height (the component places rows by it, and measures the first one), so every
55
- * input is one line. Cells are drawn like a sheet: the inputs lose their own box, the grid lines take its place, and
56
- * the cell with focus gets the ring inside its edges. Messages show under the table, for the input with focus.
57
- */
58
- .nx-tabular {
59
- --nx-tabular-row: calc(var(--nx-control-md) + 1px);
60
- --nx-tabular-end: 40px;
61
- --nx-tabular-line: var(--nx-border);
62
- --nx-tabular-frame: var(--nx-border-strong);
63
- --nx-tabular-bg: var(--nx-surface);
64
- --nx-tabular-head: color-mix(in oklab, var(--nx-text) 4%, var(--nx-surface));
65
- --nx-tabular-hover: color-mix(in oklab, var(--nx-text) 3%, var(--nx-surface));
66
- --nx-tabular-readonly: light-dark(var(--nx-surface-2), var(--nx-bg));
67
- }
68
-
69
- .nx-tabular--sm {
70
- --nx-tabular-row: calc(var(--nx-control-sm) + 1px);
71
- --nx-tabular-end: 34px;
72
- }
73
-
74
- .nx-tabular--lg {
75
- --nx-tabular-row: calc(var(--nx-control-lg) + 1px);
76
- --nx-tabular-end: 44px;
77
- }
78
-
79
- .nx-tabular[data-problem] {
80
- --nx-tabular-frame: var(--nx-danger);
81
- }
82
-
83
- .nx-tabular__viewport {
84
- position: relative;
85
- overflow: auto;
86
- border: 1px solid var(--nx-tabular-frame);
87
- border-radius: var(--nx-radius);
88
- background: var(--nx-tabular-bg);
89
- box-shadow: var(--nx-shadow-sm);
90
- outline: none;
91
- /* A focused cell scrolls clear of the header and the fixed columns. */
92
- scroll-padding: var(--nx-tabular-row) var(--nx-tabular-end) 0 48px;
93
- scrollbar-width: thin;
94
- scrollbar-color: color-mix(in oklab, var(--nx-text-subtle) 75%, transparent) transparent;
95
- transition: border-color var(--nx-duration);
96
- }
97
-
98
- .nx-tabular__viewport:focus-visible {
99
- box-shadow: inset 0 0 0 2px var(--nx-primary);
100
- }
101
-
102
- .nx-tabular__table {
103
- width: 100%;
104
- }
105
-
106
- .nx-tabular__row {
107
- display: grid;
108
- grid-template-columns: var(--nx-tabular-columns);
109
- height: var(--nx-tabular-row);
110
- border-bottom: 1px solid var(--nx-tabular-line);
111
- background: var(--nx-tabular-bg);
112
- }
113
-
114
- /* The last row's line hides under the frame. */
115
- .nx-tabular__body {
116
- margin-bottom: -1px;
117
- }
118
-
119
- .nx-tabular__body > .nx-tabular__row:hover {
120
- background: var(--nx-tabular-hover);
121
- }
122
-
123
- /* Header: stays at the top while the rows scroll. */
124
- .nx-tabular__head {
125
- position: sticky;
126
- top: 0;
127
- z-index: 3;
128
- }
129
-
130
- .nx-tabular__head > .nx-tabular__row {
131
- background: var(--nx-tabular-head);
132
- }
133
-
134
- .nx-tabular__head-cell {
135
- display: flex;
136
- align-items: center;
137
- gap: 2px;
138
- min-width: 0;
139
- padding: 0 10px;
140
- border-left: 1px solid var(--nx-tabular-line);
141
- color: var(--nx-text);
142
- font-size: var(--nx-text-sm);
143
- font-weight: 600;
144
- white-space: nowrap;
145
- }
146
-
147
- .nx-tabular__head-label {
148
- overflow: hidden;
149
- text-overflow: ellipsis;
150
- }
151
-
152
- .nx-tabular__head-cell.nx-tabular__cell--number {
153
- justify-content: flex-end;
154
- }
155
-
156
- .nx-tabular__head-cell.nx-tabular__cell--check {
157
- justify-content: center;
158
- padding-inline: 6px;
159
- }
160
-
161
- /* Cells */
162
- .nx-tabular__cell {
163
- display: flex;
164
- align-items: stretch;
165
- min-width: 0;
166
- border-left: 1px solid var(--nx-tabular-line);
167
- }
168
-
169
- .nx-tabular__cell > * {
170
- flex: 1 1 auto;
171
- min-width: 0;
172
- }
173
-
174
- .nx-tabular__cell .nx-field {
175
- --nx-field-bg: transparent;
176
- --nx-field-border: transparent;
177
- --nx-field-border-hover: transparent;
178
- }
179
-
180
- .nx-tabular__cell .nx-field:is([data-readonly], [data-disabled]) {
181
- --nx-field-bg: var(--nx-tabular-readonly);
182
- }
183
-
184
- .nx-tabular__cell .nx-field[data-disabled] {
185
- opacity: 1;
186
- color: var(--nx-text-muted);
187
- }
188
-
189
- .nx-tabular__cell .nx-field__box {
190
- height: 100%;
191
- min-height: 0;
192
- border-radius: 0;
193
- box-shadow: none;
194
- }
195
-
196
- .nx-tabular__cell .nx-field__box:focus-within {
197
- box-shadow: inset 0 0 0 2px var(--nx-field-accent);
198
- }
199
-
200
- .nx-tabular__cell .nx-field[data-invalid] .nx-field__box {
201
- box-shadow: inset 0 0 0 1px var(--nx-danger);
202
- }
203
-
204
- .nx-tabular__cell .nx-field[data-invalid] .nx-field__box:focus-within {
205
- box-shadow: inset 0 0 0 2px var(--nx-danger);
206
- }
207
-
208
- /* The message of the input with focus shows under the table instead. Screen readers still hear it with the input. */
209
- .nx-tabular__cell :is(.nx-field, .nx-choice-field, .nx-choices) > .nx-field__footer {
210
- display: none;
211
- }
212
-
213
- .nx-tabular__cell--number .nx-field__control {
214
- text-align: end;
215
- }
216
-
217
- .nx-tabular__cell--check {
218
- align-items: center;
219
- justify-content: center;
220
- }
221
-
222
- .nx-tabular__cell--check > * {
223
- flex: 0 0 auto;
224
- }
225
-
226
- .nx-tabular__cell .nx-choice__control {
227
- margin: 0;
228
- }
229
-
230
- .nx-tabular__cell--check:has(.nx-field__lock) {
231
- background: var(--nx-tabular-readonly);
232
- }
233
-
234
- .nx-tabular__cell .nx-choices {
235
- display: flex;
236
- align-items: center;
237
- padding-inline: 10px;
238
- }
239
-
240
- .nx-tabular__cell .nx-choices__options {
241
- display: flex;
242
- flex-wrap: nowrap;
243
- gap: var(--nx-space-3);
244
- overflow: hidden;
245
- }
246
-
247
- /* Row numbers, fixed at the start: the button of each row's menu. Dots take the number's place on hover. */
248
- .nx-tabular__num {
249
- position: sticky;
250
- left: 0;
251
- z-index: 1;
252
- display: flex;
253
- align-items: center;
254
- justify-content: center;
255
- border-right: 1px solid var(--nx-tabular-line);
256
- background: inherit;
257
- color: var(--nx-text-muted);
258
- font-size: var(--nx-text-xs);
259
- font-variant-numeric: tabular-nums;
260
- }
261
-
262
- .nx-tabular__head .nx-tabular__num {
263
- color: var(--nx-text);
264
- font-weight: 600;
265
- }
266
-
267
- .nx-tabular__num + .nx-tabular__cell,
268
- .nx-tabular__num + .nx-tabular__head-cell {
269
- border-left: 0;
270
- }
271
-
272
- .nx-tabular__num-button {
273
- display: grid;
274
- place-items: center;
275
- width: calc(100% - 6px);
276
- height: calc(100% - 6px);
277
- padding: 0;
278
- border: 0;
279
- border-radius: var(--nx-radius-sm);
280
- background: none;
281
- color: inherit;
282
- font: inherit;
283
- cursor: pointer;
284
- }
285
-
286
- .nx-tabular__num-button > * {
287
- grid-area: 1 / 1;
288
- transition: opacity var(--nx-duration);
289
- }
290
-
291
- .nx-tabular__num-icon {
292
- width: 16px;
293
- height: 16px;
294
- opacity: 0;
295
- }
296
-
297
- .nx-tabular__num-button:is(:hover, :focus-visible, [aria-expanded="true"]) {
298
- background: var(--nx-surface-hover);
299
- color: var(--nx-text);
300
- }
301
-
302
- .nx-tabular__row:hover .nx-tabular__num-icon,
303
- .nx-tabular__num-button:is(:focus-visible, [aria-expanded="true"]) .nx-tabular__num-icon {
304
- opacity: 1;
305
- }
306
-
307
- .nx-tabular__row:hover .nx-tabular__num-button .nx-tabular__num-text,
308
- .nx-tabular__num-button:is(:focus-visible, [aria-expanded="true"]) .nx-tabular__num-text {
309
- opacity: 0;
310
- }
311
-
312
- .nx-tabular__num-button:focus-visible {
313
- outline: 2px solid var(--nx-primary);
314
- outline-offset: -2px;
315
- }
316
-
317
- /* A row with a problem, after a check: a red edge at its start, and a red number. */
318
- .nx-tabular__row[data-problem] > .nx-tabular__num {
319
- box-shadow: inset 3px 0 0 var(--nx-danger);
320
- color: var(--nx-danger);
321
- font-weight: 600;
322
- }
323
-
324
- /* Remove buttons, fixed at the end. */
325
- .nx-tabular__end {
326
- position: sticky;
327
- right: 0;
328
- z-index: 1;
329
- display: flex;
330
- align-items: center;
331
- justify-content: center;
332
- border-left: 1px solid var(--nx-tabular-line);
333
- background: inherit;
334
- }
335
-
336
- .nx-tabular__remove.nx-btn {
337
- width: calc(var(--nx-tabular-row) - 9px);
338
- height: calc(var(--nx-tabular-row) - 9px);
339
- color: var(--nx-text-muted);
340
- }
341
-
342
- .nx-tabular__row--empty {
343
- display: block;
344
- height: auto;
345
- border-bottom: 0;
346
- }
347
-
348
- .nx-tabular__empty {
349
- position: sticky;
350
- left: 0;
351
- width: max-content;
352
- max-width: 100%;
353
- padding: var(--nx-space-4);
354
- color: var(--nx-text-muted);
355
- font-size: var(--nx-text-sm);
356
- }
357
-
358
- /*
359
- * Group form: each row is a section on a light tint, without a border, so the inputs' own boxes are the only frames.
360
- * The header collapses the section; the inputs sit on a 12-column grid by their span, one column on narrow screens.
361
- */
362
- .nx-group-form {
363
- --nx-group-tint: color-mix(in oklab, var(--nx-text) 3.5%, var(--nx-surface));
364
- --nx-group-hover: color-mix(in oklab, var(--nx-text) 6%, var(--nx-surface));
365
- --nx-group-pad: var(--nx-space-4);
366
- --nx-group-gap: var(--nx-space-4);
367
- }
368
-
369
- .nx-group-form--sm {
370
- --nx-group-pad: var(--nx-space-3);
371
- --nx-group-gap: var(--nx-space-3);
372
- }
373
-
374
- .nx-group-form--lg {
375
- --nx-group-pad: var(--nx-space-5);
376
- --nx-group-gap: var(--nx-space-5);
377
- }
378
-
379
- .nx-group-form__list {
380
- display: flex;
381
- flex-direction: column;
382
- gap: var(--nx-space-3);
383
- margin: 0;
384
- padding: 0;
385
- list-style: none;
386
- }
387
-
388
- .nx-group-form__section {
389
- border-radius: var(--nx-radius-lg);
390
- background: var(--nx-group-tint);
391
- }
392
-
393
- .nx-group-form__section[data-problem] {
394
- box-shadow: inset 3px 0 0 var(--nx-danger);
395
- }
396
-
397
- .nx-group-form__head {
398
- display: flex;
399
- align-items: center;
400
- gap: var(--nx-space-2);
401
- padding: 6px 8px 6px 6px;
402
- }
403
-
404
- .nx-group-form__toggle,
405
- .nx-group-form__heading {
406
- display: flex;
407
- flex: 1 1 auto;
408
- align-items: center;
409
- gap: var(--nx-space-2);
410
- min-width: 0;
411
- min-height: 34px;
412
- padding: 4px 10px 4px 8px;
413
- color: var(--nx-text);
414
- font-size: var(--nx-text-md);
415
- text-align: start;
416
- }
417
-
418
- .nx-group-form__heading {
419
- padding-left: calc(var(--nx-group-pad) - 6px);
420
- }
421
-
422
- .nx-group-form__toggle {
423
- border: 0;
424
- border-radius: var(--nx-radius);
425
- background: none;
426
- font: inherit;
427
- cursor: pointer;
428
- transition: background-color var(--nx-duration);
429
- }
430
-
431
- .nx-group-form__toggle:hover {
432
- background: var(--nx-group-hover);
433
- }
434
-
435
- .nx-group-form__toggle:focus-visible {
436
- outline: 2px solid var(--nx-primary);
437
- outline-offset: 0;
438
- }
439
-
440
- .nx-group-form__chevron {
441
- width: 16px;
442
- height: 16px;
443
- color: var(--nx-text-muted);
444
- transition: transform var(--nx-duration);
445
- }
446
-
447
- .nx-group-form__toggle[aria-expanded="false"] .nx-group-form__chevron {
448
- transform: rotate(-90deg);
449
- }
450
-
451
- .nx-group-form__title {
452
- flex: none;
453
- font-weight: 600;
454
- white-space: nowrap;
455
- }
456
-
457
- /* A radio this row has on, such as "Primary". Text color on the tint, as tags do. */
458
- .nx-group-form__tag {
459
- flex: none;
460
- padding: 1px 8px;
461
- border-radius: var(--nx-radius-full);
462
- background: var(--nx-primary-soft);
463
- color: var(--nx-text);
464
- font-size: var(--nx-text-xs);
465
- font-weight: 500;
466
- line-height: 1.5;
467
- }
468
-
469
- /* Muted text moves toward the text color, so it keeps 4.5:1 on the tint and on the hover tint. */
470
- .nx-group-form__summary {
471
- min-width: 0;
472
- overflow: hidden;
473
- color: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
474
- font-size: var(--nx-text-sm);
475
- text-overflow: ellipsis;
476
- white-space: nowrap;
477
- }
478
-
479
- .nx-group-form__problems {
480
- display: inline-flex;
481
- flex: none;
482
- align-items: center;
483
- gap: 4px;
484
- margin-left: auto;
485
- color: var(--nx-danger);
486
- font-size: var(--nx-text-xs);
487
- font-weight: 600;
488
- white-space: nowrap;
489
- }
490
-
491
- .nx-group-form__problems .nx-icon {
492
- width: 14px;
493
- height: 14px;
494
- vertical-align: 0;
495
- }
496
-
497
- .nx-group-form__actions {
498
- display: flex;
499
- flex: none;
500
- align-items: center;
501
- gap: 2px;
502
- }
503
-
504
- .nx-group-form__actions .nx-btn {
505
- color: var(--nx-text-muted);
506
- }
507
-
508
- .nx-group-form__body {
509
- container-type: inline-size;
510
- display: grid;
511
- grid-template-columns: repeat(12, minmax(0, 1fr));
512
- align-items: start;
513
- gap: var(--nx-group-gap);
514
- padding: 2px var(--nx-group-pad) var(--nx-group-pad);
515
- }
516
-
517
- .nx-group-form__cell {
518
- grid-column: span var(--nx-span, 12);
519
- min-width: 0;
520
- }
521
-
522
- /* A checkbox, switch, or radio lines up with the boxes beside it. */
523
- .nx-group-form__cell--choice {
524
- display: flex;
525
- align-self: end;
526
- align-items: center;
527
- min-height: var(--nx-control-md);
528
- }
529
-
530
- .nx-group-form--sm .nx-group-form__cell--choice {
531
- min-height: var(--nx-control-sm);
532
- }
533
-
534
- .nx-group-form--lg .nx-group-form__cell--choice {
535
- min-height: var(--nx-control-lg);
536
- }
537
-
538
- @container (max-width: 34rem) {
539
- .nx-group-form__cell {
540
- grid-column: span 12;
541
- }
542
-
543
- .nx-group-form__cell--choice {
544
- min-height: 0;
545
- }
546
- }
547
-
548
- .nx-group-form__empty {
549
- margin: 0;
550
- padding: var(--nx-space-4);
551
- border-radius: var(--nx-radius-lg);
552
- background: var(--nx-group-tint);
553
- color: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
554
- font-size: var(--nx-text-sm);
555
- text-align: center;
556
- }
557
-
558
- @media (prefers-reduced-motion: reduce) {
559
- .nx-tabular__viewport,
560
- .nx-tabular__num-button > *,
561
- .nx-group-form__toggle,
562
- .nx-group-form__chevron {
563
- transition: none;
564
- }
565
- }
566
- }
1
+ @layer nexus.components {
2
+ /*
3
+ * Tabular and group forms: rows of inputs in a table, or as sections. Both sit in a fieldset with a legend, and end
4
+ * with a line that holds the Add button, the rows' message (or a removed row with Undo), and the count.
5
+ */
6
+ .nx-rows {
7
+ min-width: 0;
8
+ margin: 0;
9
+ padding: 0;
10
+ border: 0;
11
+ }
12
+
13
+ .nx-rows__legend {
14
+ margin-bottom: 6px;
15
+ padding: 0;
16
+ }
17
+
18
+ .nx-rows__footer {
19
+ display: flex;
20
+ flex-wrap: wrap;
21
+ align-items: center;
22
+ gap: var(--nx-space-2) var(--nx-space-3);
23
+ margin-top: var(--nx-space-2);
24
+ }
25
+
26
+ .nx-rows__message {
27
+ flex: 1 1 14rem;
28
+ align-items: center;
29
+ min-width: 0;
30
+ margin: 0;
31
+ font-size: var(--nx-text-xs);
32
+ line-height: 1.35;
33
+ }
34
+
35
+ .nx-rows__removed {
36
+ display: flex;
37
+ gap: var(--nx-space-2);
38
+ color: var(--nx-text-muted);
39
+ }
40
+
41
+ .nx-rows__removed .nx-btn {
42
+ margin-block: -4px;
43
+ }
44
+
45
+ .nx-rows__count {
46
+ margin-left: auto;
47
+ color: var(--nx-text-muted);
48
+ font-size: var(--nx-text-xs);
49
+ font-variant-numeric: tabular-nums;
50
+ white-space: nowrap;
51
+ }
52
+
53
+ /*
54
+ * Tabular form. Rows have a fixed height (the component places rows by it, and measures the first one), so every
55
+ * input is one line. Cells are drawn like a sheet: the inputs lose their own box, the grid lines take its place, and
56
+ * the cell with focus gets the ring inside its edges. Messages show under the table, for the input with focus.
57
+ */
58
+ .nx-tabular {
59
+ --nx-tabular-row: calc(var(--nx-control-md) + 1px);
60
+ --nx-tabular-menu: 22px;
61
+ --nx-tabular-line: var(--nx-border);
62
+ /*
63
+ * The sheet keeps the strong edge. Making it the plain border to answer "boxes inside boxes" put the frame below
64
+ * the edge of every input box beside it, in all seven themes light and dark, which the library asserts against
65
+ * (`tabular-form.cjs`, "frame edge"): the outermost edge of a control cannot be fainter than the ones inside it.
66
+ */
67
+ --nx-tabular-frame: var(--nx-border-strong);
68
+ --nx-tabular-bg: var(--nx-surface);
69
+ --nx-tabular-head: color-mix(in oklab, var(--nx-text) 4%, var(--nx-surface));
70
+ --nx-tabular-hover: color-mix(in oklab, var(--nx-text) 3%, var(--nx-surface));
71
+ --nx-tabular-readonly: light-dark(var(--nx-surface-2), var(--nx-bg));
72
+ }
73
+
74
+ .nx-tabular--sm {
75
+ --nx-tabular-row: calc(var(--nx-control-sm) + 1px);
76
+ --nx-tabular-menu: 20px;
77
+ }
78
+
79
+ .nx-tabular--lg {
80
+ --nx-tabular-row: calc(var(--nx-control-lg) + 1px);
81
+ --nx-tabular-menu: 24px;
82
+ }
83
+
84
+ .nx-tabular[data-problem] {
85
+ --nx-tabular-frame: var(--nx-danger);
86
+ }
87
+
88
+ .nx-tabular__viewport {
89
+ position: relative;
90
+ overflow: auto;
91
+ border: 1px solid var(--nx-tabular-frame);
92
+ border-radius: var(--nx-radius);
93
+ background: var(--nx-tabular-bg);
94
+ box-shadow: var(--nx-shadow-sm);
95
+ outline: none;
96
+ /* A focused cell scrolls clear of the header and the fixed columns. */
97
+ scroll-padding: var(--nx-tabular-row) 0 0 var(--nx-tabular-num, 48px);
98
+ transition: border-color var(--nx-duration);
99
+ }
100
+
101
+ .nx-tabular__viewport:focus-visible {
102
+ box-shadow: inset 0 0 0 2px var(--nx-primary);
103
+ }
104
+
105
+ .nx-tabular__table {
106
+ width: 100%;
107
+ }
108
+
109
+ .nx-tabular__row {
110
+ display: grid;
111
+ grid-template-columns: var(--nx-tabular-columns);
112
+ /*
113
+ * One track, exactly the row's height. Without it the track is sized by the tallest cell, so a single
114
+ * textarea of two lines made every cell of its row 20px too tall and drew them over the rows below: the row
115
+ * looked taller than its neighbours, and its focus ring and its edges bled out of it.
116
+ */
117
+ grid-template-rows: minmax(0, 1fr);
118
+ height: var(--nx-tabular-row);
119
+ border-bottom: 1px solid var(--nx-tabular-line);
120
+ background: var(--nx-tabular-bg);
121
+ }
122
+
123
+ /* The last row's line hides under the frame. */
124
+ .nx-tabular__body {
125
+ margin-bottom: -1px;
126
+ }
127
+
128
+ .nx-tabular__body > .nx-tabular__row:hover {
129
+ background: var(--nx-tabular-hover);
130
+ }
131
+
132
+ /* Header: stays at the top while the rows scroll. */
133
+ .nx-tabular__head {
134
+ position: sticky;
135
+ top: 0;
136
+ z-index: 3;
137
+ }
138
+
139
+ .nx-tabular__head > .nx-tabular__row {
140
+ background: var(--nx-tabular-head);
141
+ }
142
+
143
+ .nx-tabular__head-cell {
144
+ display: flex;
145
+ align-items: center;
146
+ gap: 2px;
147
+ min-width: 0;
148
+ padding: 0 10px;
149
+ border-left: 1px solid var(--nx-tabular-line);
150
+ color: var(--nx-text);
151
+ font-size: var(--nx-text-sm);
152
+ font-weight: 600;
153
+ white-space: nowrap;
154
+ }
155
+
156
+ .nx-tabular__head-label {
157
+ overflow: hidden;
158
+ text-overflow: ellipsis;
159
+ }
160
+
161
+ .nx-tabular__head-cell.nx-tabular__cell--number {
162
+ justify-content: flex-end;
163
+ }
164
+
165
+ .nx-tabular__head-cell.nx-tabular__cell--check {
166
+ justify-content: center;
167
+ padding-inline: 6px;
168
+ }
169
+
170
+ /* Cells */
171
+ .nx-tabular__cell {
172
+ display: flex;
173
+ align-items: stretch;
174
+ min-width: 0;
175
+ /* Nothing a cell holds is drawn past its own edges: the ring, the invalid edge and the tint all stop here. */
176
+ min-height: 0;
177
+ overflow: hidden;
178
+ border-left: 1px solid var(--nx-tabular-line);
179
+ }
180
+
181
+ /*
182
+ * A textarea scrolls inside its cell instead of making the cell taller. Its own `rows` would size the row, and
183
+ * its resize grip would let one cell break the alignment of its row: in a grid where every other cell keeps the
184
+ * line, that grip is a handle for making the table wrong, eighteen of them down one column.
185
+ */
186
+ .nx-tabular__cell textarea.nx-field__control {
187
+ height: 100%;
188
+ min-height: 0;
189
+ /* Two classes: the multi-line rule in Nexus.Input.css is two, and one would lose to it in the same layer. */
190
+ resize: none;
191
+ }
192
+
193
+ .nx-tabular__cell > * {
194
+ flex: 1 1 auto;
195
+ min-width: 0;
196
+ }
197
+
198
+ .nx-tabular__cell .nx-field {
199
+ --nx-field-bg: transparent;
200
+ --nx-field-border: transparent;
201
+ --nx-field-border-hover: transparent;
202
+ }
203
+
204
+ .nx-tabular__cell .nx-field:is([data-readonly], [data-disabled]) {
205
+ --nx-field-bg: var(--nx-tabular-readonly);
206
+ }
207
+
208
+ .nx-tabular__cell .nx-field[data-disabled] {
209
+ opacity: 1;
210
+ color: var(--nx-text-muted);
211
+ }
212
+
213
+ .nx-tabular__cell .nx-field__box {
214
+ height: 100%;
215
+ min-height: 0;
216
+ border-radius: 0;
217
+ box-shadow: none;
218
+ }
219
+
220
+ .nx-tabular__cell .nx-field__box:focus-within {
221
+ box-shadow: inset 0 0 0 2px var(--nx-field-accent);
222
+ }
223
+
224
+ .nx-tabular__cell .nx-field[data-invalid] .nx-field__box {
225
+ box-shadow: inset 0 0 0 1px var(--nx-danger);
226
+ }
227
+
228
+ .nx-tabular__cell .nx-field[data-invalid] .nx-field__box:focus-within {
229
+ box-shadow: inset 0 0 0 2px var(--nx-danger);
230
+ }
231
+
232
+ /* The message of the input with focus shows under the table instead. Screen readers still hear it with the input. */
233
+ .nx-tabular__cell :is(.nx-field, .nx-choice-field, .nx-choices) > .nx-field__footer {
234
+ display: none;
235
+ }
236
+
237
+ .nx-tabular__cell--number .nx-field__control {
238
+ text-align: end;
239
+ }
240
+
241
+ .nx-tabular__cell--check {
242
+ align-items: center;
243
+ justify-content: center;
244
+ }
245
+
246
+ .nx-tabular__cell--check > * {
247
+ flex: 0 0 auto;
248
+ }
249
+
250
+ .nx-tabular__cell .nx-choice__control {
251
+ margin: 0;
252
+ }
253
+
254
+ /*
255
+ * A generated cell wears the read-only tint and no lock: the column header carries one lock for the whole
256
+ * column, and the cell still says why under the table when it is used. One fact, said once, not once a row.
257
+ */
258
+ .nx-tabular__cell .nx-field__lock {
259
+ display: none;
260
+ }
261
+
262
+ .nx-tabular__cell--check:has([data-readonly]) {
263
+ background: var(--nx-tabular-readonly);
264
+ }
265
+
266
+ .nx-tabular__head-cell[data-nx-locked] {
267
+ color: var(--nx-text-muted);
268
+ }
269
+
270
+ .nx-tabular__head-lock {
271
+ width: 13px;
272
+ height: 13px;
273
+ margin-left: auto;
274
+ color: var(--nx-text-muted);
275
+ }
276
+
277
+ .nx-tabular__head-cell.nx-tabular__cell--number .nx-tabular__head-lock {
278
+ margin-left: 4px;
279
+ }
280
+
281
+ .nx-tabular__cell .nx-choices {
282
+ display: flex;
283
+ align-items: center;
284
+ padding-inline: 10px;
285
+ }
286
+
287
+ .nx-tabular__cell .nx-choices__options {
288
+ display: flex;
289
+ flex-wrap: nowrap;
290
+ gap: var(--nx-space-3);
291
+ overflow: hidden;
292
+ }
293
+
294
+ /*
295
+ * Row numbers, fixed at the start, with the row's menu beside them. Both have their own place and neither
296
+ * moves: a menu that takes the number's place on hover makes the numbering look broken and the grid unstable.
297
+ */
298
+ .nx-tabular__num {
299
+ position: sticky;
300
+ left: 0;
301
+ z-index: 1;
302
+ display: grid;
303
+ grid-template-columns: minmax(0, 1fr) var(--nx-tabular-menu);
304
+ align-items: center;
305
+ gap: 2px;
306
+ padding-left: 6px;
307
+ border-right: 1px solid var(--nx-tabular-line);
308
+ background: inherit;
309
+ color: var(--nx-text-muted);
310
+ font-size: var(--nx-text-xs);
311
+ font-variant-numeric: tabular-nums;
312
+ }
313
+
314
+ .nx-tabular__head .nx-tabular__num {
315
+ color: var(--nx-text);
316
+ font-weight: 600;
317
+ }
318
+
319
+ /* Right-aligned, so 9 and 10 line up under one another and the menu is always the same distance away. */
320
+ .nx-tabular__num-text {
321
+ text-align: end;
322
+ }
323
+
324
+ .nx-tabular__num + .nx-tabular__cell,
325
+ .nx-tabular__num + .nx-tabular__head-cell {
326
+ border-left: 0;
327
+ }
328
+
329
+ .nx-tabular__num-button {
330
+ display: grid;
331
+ place-items: center;
332
+ width: var(--nx-tabular-menu);
333
+ height: calc(var(--nx-tabular-row) - 8px);
334
+ padding: 0;
335
+ border: 0;
336
+ border-radius: var(--nx-radius-sm);
337
+ background: none;
338
+ /* Muted, like the numbers beside it, so the column reads as one thing; it is the row's only control now. */
339
+ color: var(--nx-text-muted);
340
+ font: inherit;
341
+ cursor: pointer;
342
+ transition:
343
+ background-color var(--nx-duration),
344
+ color var(--nx-duration);
345
+ }
346
+
347
+ .nx-tabular__num-button .nx-icon {
348
+ width: 15px;
349
+ height: 15px;
350
+ }
351
+
352
+ .nx-tabular__num-button:not(:disabled):is(:hover, :focus-visible, [aria-expanded="true"]) {
353
+ background: var(--nx-surface-hover);
354
+ color: var(--nx-text);
355
+ }
356
+
357
+ .nx-tabular__num-button[data-tone="danger"]:not(:disabled):is(:hover, :focus-visible) {
358
+ color: var(--nx-danger);
359
+ }
360
+
361
+ /* A locked row's lock is drawn in the text colour, so the locked rows can be told apart down the column. */
362
+ .nx-tabular__num-button[aria-pressed="true"] {
363
+ color: var(--nx-text);
364
+ }
365
+
366
+ .nx-tabular__num-button:disabled {
367
+ cursor: default;
368
+ opacity: 0.4;
369
+ }
370
+
371
+ .nx-tabular__num-button:focus-visible {
372
+ outline: 2px solid var(--nx-primary);
373
+ outline-offset: -2px;
374
+ }
375
+
376
+ /* With the actions at the end, the number column is the number alone. */
377
+ .nx-tabular[data-actions-at="end"] .nx-tabular__num {
378
+ grid-template-columns: minmax(0, 1fr);
379
+ padding-right: 10px;
380
+ }
381
+
382
+ /*
383
+ * The row's actions at its end (`actionsAt="end"`), as a data table has them: fixed at the right edge while the
384
+ * columns scroll, each action its own small button, every one always in its place.
385
+ */
386
+ .nx-tabular__actions {
387
+ position: sticky;
388
+ right: 0;
389
+ z-index: 1;
390
+ display: flex;
391
+ align-items: center;
392
+ justify-content: flex-end;
393
+ gap: 2px;
394
+ padding-inline: 4px;
395
+ border-left: 1px solid var(--nx-tabular-line);
396
+ background: inherit;
397
+ }
398
+
399
+ /*
400
+ * The line under the table keeps its height in a tabular form, said or not: it holds the hint or the message of the
401
+ * input with focus, and a line that came and went with the focus made the whole panel jump on every click.
402
+ */
403
+ .nx-tabular > .nx-rows__footer {
404
+ min-height: calc(var(--nx-text-xs) * 1.35);
405
+ }
406
+
407
+ /* A row with a problem, after a check: a red edge at its start, and a red number. */
408
+ .nx-tabular__row[data-problem] > .nx-tabular__num {
409
+ box-shadow: inset 3px 0 0 var(--nx-danger);
410
+ color: var(--nx-danger);
411
+ font-weight: 600;
412
+ }
413
+
414
+
415
+ .nx-tabular__row--empty {
416
+ display: block;
417
+ height: auto;
418
+ border-bottom: 0;
419
+ }
420
+
421
+ .nx-tabular__empty {
422
+ position: sticky;
423
+ left: 0;
424
+ width: max-content;
425
+ max-width: 100%;
426
+ padding: var(--nx-space-4);
427
+ color: var(--nx-text-muted);
428
+ font-size: var(--nx-text-sm);
429
+ }
430
+
431
+ /*
432
+ * Group form: each row is a section on a light tint, without a border, so the inputs' own boxes are the only frames.
433
+ * The header collapses the section; the inputs sit on a 12-column grid by their span, one column on narrow screens.
434
+ */
435
+ .nx-group-form {
436
+ --nx-group-tint: color-mix(in oklab, var(--nx-text) 3.5%, var(--nx-surface));
437
+ --nx-group-hover: color-mix(in oklab, var(--nx-text) 6%, var(--nx-surface));
438
+ --nx-group-pad: var(--nx-space-4);
439
+ --nx-group-gap: var(--nx-space-4);
440
+ }
441
+
442
+ .nx-group-form--sm {
443
+ --nx-group-pad: var(--nx-space-3);
444
+ --nx-group-gap: var(--nx-space-3);
445
+ }
446
+
447
+ .nx-group-form--lg {
448
+ --nx-group-pad: var(--nx-space-5);
449
+ --nx-group-gap: var(--nx-space-5);
450
+ }
451
+
452
+ .nx-group-form__list {
453
+ display: flex;
454
+ flex-direction: column;
455
+ gap: var(--nx-space-3);
456
+ margin: 0;
457
+ padding: 0;
458
+ list-style: none;
459
+ }
460
+
461
+ .nx-group-form__section {
462
+ border-radius: var(--nx-radius-lg);
463
+ background: var(--nx-group-tint);
464
+ }
465
+
466
+ .nx-group-form__section[data-problem] {
467
+ box-shadow: inset 3px 0 0 var(--nx-danger);
468
+ }
469
+
470
+ .nx-group-form__head {
471
+ display: flex;
472
+ align-items: center;
473
+ gap: var(--nx-space-2);
474
+ padding: 6px 8px 6px 6px;
475
+ }
476
+
477
+ .nx-group-form__toggle,
478
+ .nx-group-form__heading {
479
+ display: flex;
480
+ flex: 1 1 auto;
481
+ align-items: center;
482
+ gap: var(--nx-space-2);
483
+ min-width: 0;
484
+ min-height: 34px;
485
+ padding: 4px 10px 4px 8px;
486
+ color: var(--nx-text);
487
+ font-size: var(--nx-text-md);
488
+ text-align: start;
489
+ }
490
+
491
+ .nx-group-form__heading {
492
+ padding-left: calc(var(--nx-group-pad) - 6px);
493
+ }
494
+
495
+ .nx-group-form__toggle {
496
+ border: 0;
497
+ border-radius: var(--nx-radius);
498
+ background: none;
499
+ font: inherit;
500
+ cursor: pointer;
501
+ transition: background-color var(--nx-duration);
502
+ }
503
+
504
+ .nx-group-form__toggle:hover {
505
+ background: var(--nx-group-hover);
506
+ }
507
+
508
+ .nx-group-form__toggle:focus-visible {
509
+ outline: 2px solid var(--nx-primary);
510
+ outline-offset: 0;
511
+ }
512
+
513
+ .nx-group-form__chevron {
514
+ width: 16px;
515
+ height: 16px;
516
+ color: var(--nx-text-muted);
517
+ transition: transform var(--nx-duration);
518
+ }
519
+
520
+ .nx-group-form__toggle[aria-expanded="false"] .nx-group-form__chevron {
521
+ transform: rotate(-90deg);
522
+ }
523
+
524
+ .nx-group-form__title {
525
+ flex: none;
526
+ font-weight: 600;
527
+ white-space: nowrap;
528
+ }
529
+
530
+ /* A radio this row has on, such as "Primary". Text color on the tint, as tags do. */
531
+ .nx-group-form__tag {
532
+ flex: none;
533
+ padding: 1px 8px;
534
+ border-radius: var(--nx-radius-full);
535
+ background: var(--nx-primary-soft);
536
+ color: var(--nx-text);
537
+ font-size: var(--nx-text-xs);
538
+ font-weight: 500;
539
+ line-height: 1.5;
540
+ }
541
+
542
+ /* Muted text moves toward the text color, so it keeps 4.5:1 on the tint and on the hover tint. */
543
+ .nx-group-form__summary {
544
+ min-width: 0;
545
+ overflow: hidden;
546
+ color: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
547
+ font-size: var(--nx-text-sm);
548
+ text-overflow: ellipsis;
549
+ white-space: nowrap;
550
+ }
551
+
552
+ .nx-group-form__problems {
553
+ display: inline-flex;
554
+ flex: none;
555
+ align-items: center;
556
+ gap: 4px;
557
+ margin-left: auto;
558
+ color: var(--nx-danger);
559
+ font-size: var(--nx-text-xs);
560
+ font-weight: 600;
561
+ white-space: nowrap;
562
+ }
563
+
564
+ .nx-group-form__problems .nx-icon {
565
+ width: 14px;
566
+ height: 14px;
567
+ vertical-align: 0;
568
+ }
569
+
570
+ .nx-group-form__actions {
571
+ display: flex;
572
+ flex: none;
573
+ align-items: center;
574
+ gap: 2px;
575
+ }
576
+
577
+ .nx-group-form__actions .nx-btn {
578
+ color: var(--nx-text-muted);
579
+ }
580
+
581
+ .nx-group-form__body {
582
+ container-type: inline-size;
583
+ display: grid;
584
+ grid-template-columns: repeat(12, minmax(0, 1fr));
585
+ align-items: start;
586
+ gap: var(--nx-group-gap);
587
+ padding: 2px var(--nx-group-pad) var(--nx-group-pad);
588
+ }
589
+
590
+ .nx-group-form__cell {
591
+ grid-column: span var(--nx-span, 12);
592
+ min-width: 0;
593
+ }
594
+
595
+ /* A checkbox, switch, or radio lines up with the boxes beside it. */
596
+ .nx-group-form__cell--choice {
597
+ display: flex;
598
+ align-self: end;
599
+ align-items: center;
600
+ min-height: var(--nx-control-md);
601
+ }
602
+
603
+ .nx-group-form--sm .nx-group-form__cell--choice {
604
+ min-height: var(--nx-control-sm);
605
+ }
606
+
607
+ .nx-group-form--lg .nx-group-form__cell--choice {
608
+ min-height: var(--nx-control-lg);
609
+ }
610
+
611
+ @container (max-width: 34rem) {
612
+ .nx-group-form__cell {
613
+ grid-column: span 12;
614
+ }
615
+
616
+ .nx-group-form__cell--choice {
617
+ min-height: 0;
618
+ }
619
+ }
620
+
621
+ .nx-group-form__empty {
622
+ margin: 0;
623
+ padding: var(--nx-space-4);
624
+ border-radius: var(--nx-radius-lg);
625
+ background: var(--nx-group-tint);
626
+ color: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
627
+ font-size: var(--nx-text-sm);
628
+ text-align: center;
629
+ }
630
+
631
+ [data-nx-motion="reduce"] .nx-tabular__viewport,
632
+ [data-nx-motion="reduce"] .nx-tabular__num-button,
633
+ [data-nx-motion="reduce"] .nx-group-form__toggle,
634
+ [data-nx-motion="reduce"] .nx-group-form__chevron {
635
+ transition: none;
636
+ }
637
+ }