nexus-shared 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1564 -0
- package/README.md +1705 -1123
- package/dist/Client.Index.d.ts +14 -0
- package/dist/Client.Index.js +14 -0
- package/dist/Components/Documents/DocumentFrame.d.ts +50 -0
- package/dist/Components/Documents/DocumentFrame.js +83 -0
- package/dist/Components/Documents/Menu.d.ts +4 -0
- package/dist/Components/Documents/Menu.js +40 -24
- package/dist/Components/Documents/PrintDocument.d.ts +95 -0
- package/dist/Components/Documents/PrintDocument.js +62 -0
- package/dist/Components/Documents/Tabs.d.ts +59 -0
- package/dist/Components/Documents/Tabs.js +70 -0
- package/dist/Components/Forms/ApiForm.js +19 -2
- package/dist/Components/Forms/Crud.d.ts +2 -2
- package/dist/Components/Forms/Crud.js +576 -243
- package/dist/Components/Forms/CrudActions.d.ts +136 -0
- package/dist/Components/Forms/CrudActions.js +184 -0
- package/dist/Components/Forms/CrudNarrowPicker.d.ts +31 -0
- package/dist/Components/Forms/CrudNarrowPicker.js +180 -0
- package/dist/Components/Forms/CrudParts.d.ts +30 -2
- package/dist/Components/Forms/CrudParts.js +55 -5
- package/dist/Components/Forms/CrudRowForms.d.ts +26 -0
- package/dist/Components/Forms/CrudRowForms.js +114 -0
- package/dist/Components/Forms/CrudScopes.d.ts +28 -0
- package/dist/Components/Forms/CrudScopes.js +76 -0
- package/dist/Components/Forms/CrudTree.d.ts +90 -0
- package/dist/Components/Forms/CrudTree.js +363 -0
- package/dist/Components/Forms/CrudWorkspace.d.ts +63 -0
- package/dist/Components/Forms/CrudWorkspace.js +169 -0
- package/dist/Components/Forms/ExcelImport.js +3 -3
- package/dist/Components/Forms/Form.d.ts +4 -4
- package/dist/Components/Forms/Form.js +123 -17
- package/dist/Components/Forms/FormLeaveGuard.d.ts +44 -0
- package/dist/Components/Forms/FormLeaveGuard.js +65 -0
- package/dist/Components/Forms/RecordFlows.d.ts +50 -0
- package/dist/Components/Forms/RecordFlows.js +282 -0
- package/dist/Components/Forms/SubmitForm.d.ts +37 -2
- package/dist/Components/Forms/SubmitForm.js +195 -10
- package/dist/Components/Inputs/CheckBox.js +1 -1
- package/dist/Components/Inputs/ChoiceField.d.ts +21 -1
- package/dist/Components/Inputs/ChoiceField.js +28 -2
- package/dist/Components/Inputs/Dropdown.d.ts +13 -0
- package/dist/Components/Inputs/Dropdown.js +5 -5
- package/dist/Components/Inputs/DropdownParts.d.ts +3 -1
- package/dist/Components/Inputs/DropdownParts.js +16 -4
- package/dist/Components/Inputs/Field.d.ts +7 -1
- package/dist/Components/Inputs/Field.js +2 -2
- package/dist/Components/Inputs/GroupForm.d.ts +6 -6
- package/dist/Components/Inputs/GroupForm.js +10 -11
- package/dist/Components/Inputs/InputRenderer.d.ts +9 -6
- package/dist/Components/Inputs/InputRenderer.js +37 -32
- package/dist/Components/Inputs/PictureInput.d.ts +41 -0
- package/dist/Components/Inputs/PictureInput.js +70 -0
- package/dist/Components/Inputs/RadioGroup.d.ts +16 -3
- package/dist/Components/Inputs/RadioGroup.js +8 -3
- package/dist/Components/Inputs/RowsInput.d.ts +1 -1
- package/dist/Components/Inputs/RowsInput.js +18 -3
- package/dist/Components/Inputs/TabularForm.d.ts +5 -5
- package/dist/Components/Inputs/TabularForm.js +29 -29
- package/dist/Components/Inputs/TextArea.d.ts +6 -0
- package/dist/Components/Inputs/TextArea.js +11 -2
- package/dist/Components/Inputs/TextBoxTypes.d.ts +6 -0
- package/dist/Components/Inputs/TextBoxTypes.js +17 -0
- package/dist/Components/Inputs/TreeView.d.ts +53 -2
- package/dist/Components/Inputs/TreeView.js +147 -13
- package/dist/Components/Layouts/MessageBox.d.ts +15 -2
- package/dist/Components/Layouts/MessageBox.js +56 -7
- package/dist/Components/Layouts/Popup.d.ts +13 -6
- package/dist/Components/Layouts/Popup.js +37 -9
- package/dist/Components/Layouts/PopupDock.d.ts +3 -1
- package/dist/Components/Layouts/PopupDock.js +2 -1
- package/dist/Components/Layouts/PopupHost.js +5 -4
- package/dist/Components/Viewers/DataTable.js +150 -48
- package/dist/Components/Viewers/DataTableFilters.d.ts +1 -1
- package/dist/Components/Viewers/DataTableFilters.js +17 -2
- package/dist/Components/Viewers/DataTableParts.d.ts +21 -5
- package/dist/Components/Viewers/DataTableParts.js +26 -14
- package/dist/Components/Viewers/OwnerFiles.d.ts +175 -0
- package/dist/Components/Viewers/OwnerFiles.js +589 -0
- package/dist/Components/Viewers/QrCodeImage.d.ts +22 -0
- package/dist/Components/Viewers/QrCodeImage.js +15 -0
- package/dist/Components/Viewers/RecordCards.d.ts +16 -0
- package/dist/Components/Viewers/RecordCards.js +509 -0
- package/dist/Helpers/BusyHooks.d.ts +6 -0
- package/dist/Helpers/BusyHooks.js +39 -0
- package/dist/Helpers/CrudBackend.d.ts +20 -2
- package/dist/Helpers/CrudBackend.js +46 -2
- package/dist/Helpers/CrudColumns.d.ts +53 -6
- package/dist/Helpers/CrudColumns.js +98 -7
- package/dist/Helpers/CrudDetailsTabs.d.ts +58 -0
- package/dist/Helpers/CrudDetailsTabs.js +126 -0
- package/dist/Helpers/CrudHelpers.d.ts +81 -2
- package/dist/Helpers/CrudHelpers.js +195 -0
- package/dist/Helpers/CrudNarrowPick.d.ts +83 -0
- package/dist/Helpers/CrudNarrowPick.js +157 -0
- package/dist/Helpers/CrudRowForms.d.ts +15 -0
- package/dist/Helpers/CrudRowForms.js +43 -0
- package/dist/Helpers/CrudScopes.d.ts +32 -0
- package/dist/Helpers/CrudScopes.js +79 -0
- package/dist/Helpers/DropdownHelpers.d.ts +3 -1
- package/dist/Helpers/DropdownHelpers.js +6 -2
- package/dist/Helpers/ExcelHelpers.d.ts +1 -1
- package/dist/Helpers/ExcelHelpers.js +12 -11
- package/dist/Helpers/FileAdapter.d.ts +78 -0
- package/dist/Helpers/FileAdapter.js +102 -0
- package/dist/Helpers/FilePrimaries.d.ts +48 -0
- package/dist/Helpers/FilePrimaries.js +138 -0
- package/dist/Helpers/FormConfirm.d.ts +32 -0
- package/dist/Helpers/FormConfirm.js +40 -0
- package/dist/Helpers/FormStore.d.ts +90 -5
- package/dist/Helpers/FormStore.js +318 -22
- package/dist/Helpers/InputConditions.d.ts +50 -0
- package/dist/Helpers/InputConditions.js +168 -0
- package/dist/Helpers/InputMemory.d.ts +106 -0
- package/dist/Helpers/InputMemory.js +385 -0
- package/dist/Helpers/InputNarrowing.d.ts +18 -0
- package/dist/Helpers/InputNarrowing.js +67 -0
- package/dist/Helpers/InputParamsHelpers.d.ts +44 -1
- package/dist/Helpers/InputParamsHelpers.js +157 -74
- package/dist/Helpers/NexusDriveAdapter.d.ts +55 -0
- package/dist/Helpers/NexusDriveAdapter.js +207 -0
- package/dist/Helpers/NumberHelpers.d.ts +95 -0
- package/dist/Helpers/NumberHelpers.js +126 -0
- package/dist/Helpers/Permissions.js +2 -1
- package/dist/Helpers/QrCode.d.ts +26 -0
- package/dist/Helpers/QrCode.js +463 -0
- package/dist/Helpers/RecordCards.d.ts +205 -0
- package/dist/Helpers/RecordCards.js +378 -0
- package/dist/Helpers/RequestCache.d.ts +14 -2
- package/dist/Helpers/RequestCache.js +22 -3
- package/dist/Helpers/RowsStore.d.ts +37 -2
- package/dist/Helpers/RowsStore.js +128 -10
- package/dist/Helpers/ServerPreview.d.ts +69 -0
- package/dist/Helpers/ServerPreview.js +99 -0
- package/dist/Helpers/TableColumns.js +4 -3
- package/dist/Helpers/TableExport.d.ts +7 -1
- package/dist/Helpers/TableExport.js +9 -3
- package/dist/Helpers/TableFilters.d.ts +1 -1
- package/dist/Helpers/TableFilters.js +24 -23
- package/dist/Helpers/TableHelpers.d.ts +23 -2
- package/dist/Helpers/TableHelpers.js +51 -10
- package/dist/Helpers/TableJoins.d.ts +13 -0
- package/dist/Helpers/TableJoins.js +34 -0
- package/dist/Helpers/TableStore.d.ts +21 -1
- package/dist/Helpers/TableStore.js +64 -7
- package/dist/Helpers/TreeStore.d.ts +81 -0
- package/dist/Helpers/TreeStore.js +365 -0
- package/dist/Interfaces/CrudInterfaces.d.ts +465 -5
- package/dist/Interfaces/FileInterfaces.d.ts +162 -0
- package/dist/Interfaces/FileInterfaces.js +4 -0
- package/dist/Interfaces/FormInterfaces.d.ts +391 -30
- package/dist/Interfaces/FormInterfaces.js +79 -1
- package/dist/Interfaces/InputInterfaces.d.ts +15 -3
- package/dist/Interfaces/RecordInterfaces.d.ts +367 -0
- package/dist/Interfaces/RecordInterfaces.js +1 -0
- package/dist/Interfaces/TableInterfaces.d.ts +74 -1
- package/dist/Services/ExcelApi.js +5 -0
- package/dist/Services/FileApi.d.ts +13 -0
- package/dist/Services/FileApi.js +29 -0
- package/dist/Services/ImageEditorLoader.d.ts +14 -0
- package/dist/Services/ImageEditorLoader.js +51 -0
- package/dist/Services/JoinSources.d.ts +37 -5
- package/dist/Services/JoinSources.js +90 -14
- package/dist/Services/ModuleImport.d.ts +7 -0
- package/dist/Services/ModuleImport.js +22 -0
- package/dist/Shared.Index.d.ts +16 -0
- package/dist/Shared.Index.js +16 -0
- package/package.json +7 -2
- package/src/Styles/Nexus.Avatar.css +6 -5
- package/src/Styles/Nexus.Button.css +10 -4
- package/src/Styles/Nexus.Choice.css +16 -0
- package/src/Styles/Nexus.Crud.css +383 -9
- package/src/Styles/Nexus.Dropdown.css +8 -0
- package/src/Styles/Nexus.Files.css +410 -0
- package/src/Styles/Nexus.Form.css +5 -2
- package/src/Styles/Nexus.Index.css +4 -0
- package/src/Styles/Nexus.Input.css +42 -0
- package/src/Styles/Nexus.Menu.css +10 -1
- package/src/Styles/Nexus.Popup.css +77 -1
- package/src/Styles/Nexus.Print.css +288 -0
- package/src/Styles/Nexus.QrCode.css +12 -0
- package/src/Styles/Nexus.Record.css +430 -0
- package/src/Styles/Nexus.Tab.Buttons.css +87 -22
- package/src/Styles/Nexus.Table.css +67 -5
- package/src/Styles/Nexus.Themes.css +12 -6
- package/src/Styles/Nexus.Tokens.css +8 -3
- package/src/Styles/Nexus.Tree.css +31 -1
|
@@ -19,6 +19,28 @@
|
|
|
19
19
|
flex: 1 1 auto;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
/*
|
|
23
|
+
* A list narrowed to one record picked in another (`narrow`): whose records these are, in the table's caption, kept
|
|
24
|
+
* while nothing is picked so the rows never move. Positioned, so the words kept for screen readers stay in it.
|
|
25
|
+
*/
|
|
26
|
+
.nx-crud__scope {
|
|
27
|
+
position: relative;
|
|
28
|
+
margin: 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.nx-crud__scope-name {
|
|
32
|
+
color: var(--nx-text);
|
|
33
|
+
font-weight: 600;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* A tree of records (`CrudTree`): the picked record's buttons, beside its name in the page's panel, wrapping as one group. */
|
|
37
|
+
.nx-crud-tree__actions {
|
|
38
|
+
display: flex;
|
|
39
|
+
flex-wrap: wrap;
|
|
40
|
+
align-items: center;
|
|
41
|
+
gap: var(--nx-space-2);
|
|
42
|
+
}
|
|
43
|
+
|
|
22
44
|
/* Details: label over value, two to a line where there is room. */
|
|
23
45
|
.nx-crud-details {
|
|
24
46
|
display: flex;
|
|
@@ -44,6 +66,31 @@
|
|
|
44
66
|
grid-column: 1 / -1;
|
|
45
67
|
}
|
|
46
68
|
|
|
69
|
+
/*
|
|
70
|
+
* Details in sections (`column.group`): each run of fields under its heading in the small muted heading style, the
|
|
71
|
+
* heading nearer its fields than the section before it.
|
|
72
|
+
*/
|
|
73
|
+
.nx-crud-details__section {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
gap: var(--nx-space-2);
|
|
77
|
+
min-width: 0;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.nx-crud-details__section + .nx-crud-details__section {
|
|
81
|
+
margin-top: var(--nx-space-3);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.nx-crud-details__heading {
|
|
85
|
+
margin: 0;
|
|
86
|
+
color: var(--nx-text-muted);
|
|
87
|
+
font-size: var(--nx-text-xs);
|
|
88
|
+
font-weight: 600;
|
|
89
|
+
line-height: 1.3;
|
|
90
|
+
letter-spacing: 0.04em;
|
|
91
|
+
text-transform: uppercase;
|
|
92
|
+
}
|
|
93
|
+
|
|
47
94
|
.nx-crud-details__label {
|
|
48
95
|
color: var(--nx-text-muted);
|
|
49
96
|
font-size: var(--nx-text-sm);
|
|
@@ -124,18 +171,27 @@
|
|
|
124
171
|
flex-direction: column;
|
|
125
172
|
}
|
|
126
173
|
|
|
174
|
+
/*
|
|
175
|
+
* Under the fields, at every width (`details.asidePlace: "below"`, a record's workspace by default): the fields take
|
|
176
|
+
* the whole width, the panel the whole width under them, as tall as what it holds; what scrolls is the box around
|
|
177
|
+
* both (the workspace's panel, the popup's body), never a column of its own.
|
|
178
|
+
*/
|
|
179
|
+
.nx-crud-aside--below > .nx-crud-aside__side {
|
|
180
|
+
max-height: none;
|
|
181
|
+
}
|
|
182
|
+
|
|
127
183
|
/*
|
|
128
184
|
* Side by side, where there is room for both. The popup's body stops scrolling and each column takes its own, so a
|
|
129
185
|
* long form never pushes the panel off the screen. The body is a flex row here, which is what gives its one child a
|
|
130
186
|
* height to work from: no percentage height anywhere, so it holds at every popup size.
|
|
131
187
|
*/
|
|
132
188
|
@media (min-width: 1000px) {
|
|
133
|
-
.nx-popup__body:has(> .nx-crud-aside) {
|
|
189
|
+
.nx-popup__body:has(> .nx-crud-aside:not(.nx-crud-aside--below)) {
|
|
134
190
|
display: flex;
|
|
135
191
|
overflow: hidden;
|
|
136
192
|
}
|
|
137
193
|
|
|
138
|
-
.nx-crud-aside {
|
|
194
|
+
.nx-crud-aside:not(.nx-crud-aside--below) {
|
|
139
195
|
flex: 1 1 auto;
|
|
140
196
|
min-width: 0;
|
|
141
197
|
/* The panel takes a share of the width, not half of it: a form has columns to fit, and code lines are short. */
|
|
@@ -146,23 +202,341 @@
|
|
|
146
202
|
* A details popup's panel (`details.aside`) is what the popup is for, and the details beside it are a short list
|
|
147
203
|
* of fields, so the shares turn round: the fields take a column of their own width and the panel the rest.
|
|
148
204
|
*/
|
|
149
|
-
.nx-crud-aside.nx-crud-aside--
|
|
205
|
+
.nx-crud-aside--details:not(.nx-crud-aside--below) {
|
|
150
206
|
grid-template-columns: minmax(0, var(--nx-crud-details-width, clamp(16rem, 30%, 26rem))) minmax(0, 1fr);
|
|
151
207
|
}
|
|
152
208
|
|
|
153
|
-
|
|
209
|
+
/*
|
|
210
|
+
* Each column scrolls on its own, and a scroll box clips at its padding edge: a field first in it would lose what it
|
|
211
|
+
* draws past its box. Room inside the edges, paid back by a negative margin so nothing moves: above, an outlined
|
|
212
|
+
* field's raised label (lifted 0.6em of the xs text over the top border) and its 2px focus outline; on every side,
|
|
213
|
+
* the 3px focus ring (`--nx-focus-ring`). Focus scrolls a field's control to an edge, so `scroll-padding` keeps the
|
|
214
|
+
* same room past the control: the label above, the box's 1px border and the ring below (the popup's body too).
|
|
215
|
+
*/
|
|
216
|
+
.nx-crud-aside:not(.nx-crud-aside--below) > :is(.nx-crud-aside__main, .nx-crud-aside__side) {
|
|
154
217
|
overflow: auto;
|
|
155
218
|
overscroll-behavior: contain;
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
219
|
+
padding: calc(var(--nx-text-xs) * 0.6 + 2px) 3px 3px;
|
|
220
|
+
margin: calc(var(--nx-text-xs) * -0.6 - 2px) -3px -3px;
|
|
221
|
+
scroll-padding: calc(var(--nx-text-xs) * 0.6 + 2px) 4px 4px;
|
|
159
222
|
}
|
|
160
223
|
|
|
161
224
|
/* A panel taller than the popup scrolls here, whatever it holds; one that fills the height scrolls inside itself. */
|
|
162
225
|
.nx-crud-aside__side {
|
|
163
226
|
max-height: none;
|
|
164
|
-
|
|
165
|
-
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
* A record's workspace in its details popup (`details.tabs`, `details.profile`): who the record is and its tabs in a
|
|
232
|
+
* column on the left, the chosen tab on the right. The popup's body stops scrolling and only the tab scrolls, inside
|
|
233
|
+
* itself, so the profile, the tabs and the footer stay where they are and a switch never changes the popup's size. The
|
|
234
|
+
* workspace is the container its column and the tabs' `auto` design follow: below 720px (a phone) the profile is one
|
|
235
|
+
* row and the tabs one strip, above the tab.
|
|
236
|
+
*/
|
|
237
|
+
.nx-popup__body:has(> .nx-crud-workspace) {
|
|
238
|
+
display: flex;
|
|
239
|
+
overflow: hidden;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.nx-crud-workspace {
|
|
243
|
+
container-type: inline-size;
|
|
244
|
+
flex: 1 1 auto;
|
|
245
|
+
min-width: 0;
|
|
246
|
+
/* A popup of a set width (`lg`, `xl`) gets a height of its own, so no tab changes it; `full` gives its own. */
|
|
247
|
+
height: min(40rem, calc(100dvh - 10rem));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.nx-popup:is(.nx-popup--full, .nx-popup--maximized) .nx-crud-workspace {
|
|
251
|
+
height: auto;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.nx-crud-workspace__frame {
|
|
255
|
+
--nx-crud-profile-picture: 10rem;
|
|
256
|
+
|
|
257
|
+
display: grid;
|
|
258
|
+
grid-template-columns: minmax(0, 20rem) minmax(0, 1fr);
|
|
259
|
+
height: 100%;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/* Neither a profile nor more than one tab for this person: the tab alone, the width of the popup. */
|
|
263
|
+
.nx-crud-workspace__frame--alone {
|
|
264
|
+
grid-template-columns: minmax(0, 1fr);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.nx-crud-workspace__side {
|
|
268
|
+
display: flex;
|
|
269
|
+
flex-direction: column;
|
|
270
|
+
min-height: 0;
|
|
271
|
+
border-inline-end: 1px solid var(--nx-border);
|
|
272
|
+
background: color-mix(in oklab, var(--nx-text) 3%, transparent);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.nx-crud-workspace__profile {
|
|
276
|
+
flex-shrink: 0;
|
|
277
|
+
padding: var(--nx-space-5) var(--nx-space-4);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.nx-crud-workspace__profile + .nx-crud-workspace__nav {
|
|
281
|
+
border-top: 1px solid var(--nx-border);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.nx-crud-workspace__nav {
|
|
285
|
+
flex: 1 1 auto;
|
|
286
|
+
min-height: 0;
|
|
287
|
+
padding: var(--nx-space-3);
|
|
288
|
+
overflow-y: auto;
|
|
289
|
+
overscroll-behavior: contain;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/*
|
|
293
|
+
* Its padding is the room for a field first in it; `scroll-padding` the room round one the focus scrolls to (as the
|
|
294
|
+
* aside's). The side padding is named, so a tab's footer can reach across it.
|
|
295
|
+
*/
|
|
296
|
+
.nx-crud-workspace__panel {
|
|
297
|
+
--nx-crud-panel-pad-x: var(--nx-space-5);
|
|
298
|
+
|
|
299
|
+
min-width: 0;
|
|
300
|
+
min-height: 0;
|
|
301
|
+
padding: var(--nx-space-4) var(--nx-crud-panel-pad-x) var(--nx-space-5);
|
|
302
|
+
overflow: auto;
|
|
303
|
+
overscroll-behavior: contain;
|
|
304
|
+
scroll-padding: calc(var(--nx-text-xs) * 0.6 + 2px) 4px 4px;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/*
|
|
308
|
+
* A tab's footer (`CrudTabFooter`): one bar, its words at the start and its buttons at the end, with the popup
|
|
309
|
+
* footer's room and hairline. On a phone the words and the buttons wrap as whole groups. Where it is not in a
|
|
310
|
+
* workspace's panel, this is all it is: a plain bar where it stands.
|
|
311
|
+
*/
|
|
312
|
+
.nx-crud-tab-footer {
|
|
313
|
+
display: flex;
|
|
314
|
+
flex-wrap: wrap;
|
|
315
|
+
align-items: center;
|
|
316
|
+
justify-content: flex-end;
|
|
317
|
+
gap: var(--nx-space-2);
|
|
318
|
+
padding-block: var(--nx-space-3);
|
|
319
|
+
border-top: 1px solid var(--nx-border);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.nx-crud-tab-footer > p {
|
|
323
|
+
flex: 1 1 auto;
|
|
324
|
+
min-width: 0;
|
|
325
|
+
margin: 0;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* A form's bar fills the rest, so its status line sits beside its buttons (as in the popup's footer). */
|
|
329
|
+
.nx-crud-tab-footer > .nx-form-buttons {
|
|
330
|
+
flex: 1 1 auto;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/*
|
|
334
|
+
* In a workspace's panel it stays in view: it sticks to the bottom of the panel while the tab scrolls and sits in its
|
|
335
|
+
* place at the end, across the panel's whole width (past its side padding) on the panel's own surface, never a box of
|
|
336
|
+
* its own (no shadow, no frame). The panel keeps no padding under it, so it meets the panel's foot at the end as
|
|
337
|
+
* while it sticks. What the focus scrolls into view (a field, a caret) clears it: the panel keeps the footer's height
|
|
338
|
+
* as `CrudTabFooter` measures it (`scroll-padding`). Above what a tab's content raises (a field's label, a table's
|
|
339
|
+
* sticky header: 5 at most).
|
|
340
|
+
*/
|
|
341
|
+
.nx-crud-workspace__panel:has(.nx-crud-tab-footer) {
|
|
342
|
+
padding-bottom: 0;
|
|
343
|
+
scroll-padding-bottom: calc(var(--nx-crud-tab-footer-size, 0px) + 4px);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* While the focus is in the footer, which is always in view, that room goes: its Save never scrolls the tab. */
|
|
347
|
+
.nx-crud-workspace__panel:has(.nx-crud-tab-footer:focus-within) {
|
|
348
|
+
scroll-padding-bottom: 4px;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.nx-crud-workspace__panel .nx-crud-tab-footer {
|
|
352
|
+
position: sticky;
|
|
353
|
+
bottom: 0;
|
|
354
|
+
z-index: 6;
|
|
355
|
+
margin-inline: calc(-1 * var(--nx-crud-panel-pad-x));
|
|
356
|
+
padding-inline: var(--nx-crud-panel-pad-x);
|
|
357
|
+
background: var(--nx-surface);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* The profile: the picture over the name, the line under it and the tags, in the middle of the column. */
|
|
361
|
+
.nx-crud-profile {
|
|
362
|
+
display: flex;
|
|
363
|
+
flex-direction: column;
|
|
364
|
+
align-items: center;
|
|
365
|
+
gap: var(--nx-space-3);
|
|
366
|
+
min-width: 0;
|
|
367
|
+
text-align: center;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.nx-crud-profile__picture {
|
|
371
|
+
display: flex;
|
|
372
|
+
flex-shrink: 0;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.nx-crud-profile__text {
|
|
376
|
+
display: grid;
|
|
377
|
+
justify-items: center;
|
|
378
|
+
gap: 2px;
|
|
379
|
+
min-width: 0;
|
|
380
|
+
max-width: 100%;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.nx-crud-profile__title {
|
|
384
|
+
margin: 0;
|
|
385
|
+
font-size: var(--nx-text-lg);
|
|
386
|
+
font-weight: 600;
|
|
387
|
+
line-height: 1.35;
|
|
388
|
+
overflow-wrap: anywhere;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.nx-crud-profile__subtitle {
|
|
392
|
+
margin: 0;
|
|
393
|
+
color: var(--nx-text-muted);
|
|
394
|
+
font-size: var(--nx-text-sm);
|
|
395
|
+
overflow-wrap: anywhere;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.nx-crud-profile__tags {
|
|
399
|
+
display: flex;
|
|
400
|
+
flex-wrap: wrap;
|
|
401
|
+
justify-content: center;
|
|
402
|
+
gap: 4px;
|
|
403
|
+
margin: 4px 0 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/*
|
|
407
|
+
* A few of the record's fields under the tags (`profile.fields`): a small grid in the middle of the column, a label
|
|
408
|
+
* (muted) and its value (the text colour) a line, each pair on the grid's two tracks so the values line up. A long
|
|
409
|
+
* value wraps inside the column, never past it, and a column's tag follows its value, under it when the line is full.
|
|
410
|
+
*/
|
|
411
|
+
.nx-crud-profile__fields {
|
|
412
|
+
display: grid;
|
|
413
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
414
|
+
gap: var(--nx-space-1) var(--nx-space-3);
|
|
415
|
+
max-width: 100%;
|
|
416
|
+
margin: var(--nx-space-2) 0 0;
|
|
417
|
+
font-size: var(--nx-text-sm);
|
|
418
|
+
line-height: 1.5;
|
|
419
|
+
text-align: start;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.nx-crud-profile__field {
|
|
423
|
+
display: grid;
|
|
424
|
+
grid-column: 1 / -1;
|
|
425
|
+
grid-template-columns: subgrid;
|
|
426
|
+
align-items: baseline;
|
|
427
|
+
min-width: 0;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.nx-crud-profile__label {
|
|
431
|
+
color: var(--nx-text-muted);
|
|
432
|
+
overflow-wrap: break-word;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.nx-crud-profile__value {
|
|
436
|
+
display: flex;
|
|
437
|
+
flex-wrap: wrap;
|
|
438
|
+
align-items: baseline;
|
|
439
|
+
gap: 2px var(--nx-space-2);
|
|
440
|
+
min-width: 0;
|
|
441
|
+
margin: 0;
|
|
442
|
+
color: var(--nx-text);
|
|
443
|
+
overflow-wrap: anywhere;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* The gap places the tag: a word's space after the value, or the start of the next line. */
|
|
447
|
+
.nx-crud-profile__value > .nx-table__tag--after {
|
|
448
|
+
margin-inline-start: 0;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/* A field only the full record has, held while it is read: a short value's width on the value's baseline. */
|
|
452
|
+
.nx-table__bone.nx-crud-profile__bone {
|
|
453
|
+
width: 6rem;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@container (max-width: 719.98px) {
|
|
457
|
+
.nx-crud-workspace__frame {
|
|
458
|
+
--nx-crud-profile-picture: 3rem;
|
|
459
|
+
|
|
460
|
+
display: flex;
|
|
461
|
+
flex-direction: column;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.nx-crud-workspace__side {
|
|
465
|
+
flex-shrink: 0;
|
|
466
|
+
border-inline-end: 0;
|
|
467
|
+
border-bottom: 1px solid var(--nx-border);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.nx-crud-workspace__profile {
|
|
471
|
+
padding: var(--nx-space-3) var(--nx-space-4);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
.nx-crud-workspace__profile + .nx-crud-workspace__nav {
|
|
475
|
+
border-top: 0;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.nx-crud-profile {
|
|
479
|
+
flex-direction: row;
|
|
480
|
+
text-align: start;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.nx-crud-profile__text {
|
|
484
|
+
justify-items: start;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
.nx-crud-profile__tags {
|
|
488
|
+
justify-content: flex-start;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/*
|
|
492
|
+
* The fields follow the tags as one wrapped line of "label value" pairs: beside the tags when all of them fit there,
|
|
493
|
+
* else from the next line, so they take the lines their words need, not a line a field.
|
|
494
|
+
*/
|
|
495
|
+
.nx-crud-profile__text:has(> .nx-crud-profile__fields) {
|
|
496
|
+
display: flex;
|
|
497
|
+
flex-wrap: wrap;
|
|
498
|
+
align-items: baseline;
|
|
499
|
+
gap: 2px var(--nx-space-3);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.nx-crud-profile__text:has(> .nx-crud-profile__fields) > :is(.nx-crud-profile__title, .nx-crud-profile__subtitle) {
|
|
503
|
+
flex-basis: 100%;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.nx-crud-profile__fields {
|
|
507
|
+
display: flex;
|
|
508
|
+
flex-wrap: wrap;
|
|
509
|
+
gap: 2px var(--nx-space-3);
|
|
510
|
+
min-width: 0;
|
|
511
|
+
margin-top: 4px;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* A pair longer than the line wraps as words do, its label kept with the start of its value. */
|
|
515
|
+
.nx-crud-profile__field {
|
|
516
|
+
display: block;
|
|
517
|
+
min-width: 0;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.nx-crud-profile__label,
|
|
521
|
+
.nx-crud-profile__value {
|
|
522
|
+
display: inline;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.nx-crud-profile__value > .nx-table__tag--after {
|
|
526
|
+
margin-inline-start: var(--nx-space-2);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.nx-crud-workspace__nav {
|
|
530
|
+
flex: 0 0 auto;
|
|
531
|
+
padding: 0 var(--nx-space-2) var(--nx-space-1);
|
|
532
|
+
overflow: visible;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.nx-crud-workspace__panel {
|
|
536
|
+
--nx-crud-panel-pad-x: var(--nx-space-4);
|
|
537
|
+
|
|
538
|
+
flex: 1 1 auto;
|
|
539
|
+
padding: var(--nx-space-3) var(--nx-crud-panel-pad-x) var(--nx-space-4);
|
|
166
540
|
}
|
|
167
541
|
}
|
|
168
542
|
}
|
|
@@ -385,7 +385,10 @@
|
|
|
385
385
|
user-select: none;
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
/* The list's gutters, not the row's own 8px gap: a subgrid with a gap of its own sets its cells a pixel past each side
|
|
389
|
+
of their headings, so a figure at the end of its column ended a pixel past its heading. */
|
|
388
390
|
.nx-dropdown-list--columns > .nx-dropdown-option {
|
|
391
|
+
column-gap: normal;
|
|
389
392
|
padding-inline: 0;
|
|
390
393
|
}
|
|
391
394
|
|
|
@@ -550,6 +553,11 @@
|
|
|
550
553
|
letter-spacing: 0.03em;
|
|
551
554
|
}
|
|
552
555
|
|
|
556
|
+
/* A price beside a name: figures in even digits, so a column of them lines up at the end. */
|
|
557
|
+
.nx-dropdown-cell--money {
|
|
558
|
+
font-variant-numeric: tabular-nums;
|
|
559
|
+
}
|
|
560
|
+
|
|
553
561
|
.nx-dropdown-cell--media {
|
|
554
562
|
display: grid;
|
|
555
563
|
place-items: center;
|