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
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* An owner's pictures and documents (OwnerFiles.tsx, PictureInput.tsx): a picture of any size and shape, the picture
|
|
3
|
+
* input's preview and buttons, the gallery's two panes and the document list. Nothing moves under the pointer: a hovered
|
|
4
|
+
* picture gets a ring, never a new size, so a table's rows and the gallery's grid stay where they are.
|
|
5
|
+
*/
|
|
6
|
+
@layer nexus.components {
|
|
7
|
+
/* A picture: its height from --nx-picture-h, its width from the shape (--nx-picture-ratio, width / height). */
|
|
8
|
+
.nx-picture {
|
|
9
|
+
position: relative;
|
|
10
|
+
display: inline-grid;
|
|
11
|
+
flex-shrink: 0;
|
|
12
|
+
place-items: center;
|
|
13
|
+
height: var(--nx-picture-h, 28px);
|
|
14
|
+
aspect-ratio: var(--nx-picture-ratio, 1);
|
|
15
|
+
padding: 0;
|
|
16
|
+
overflow: hidden;
|
|
17
|
+
border: 0;
|
|
18
|
+
border-radius: var(--nx-radius-sm);
|
|
19
|
+
background: color-mix(in oklab, var(--nx-text) 7%, var(--nx-surface));
|
|
20
|
+
color: var(--nx-text-subtle);
|
|
21
|
+
font: inherit;
|
|
22
|
+
vertical-align: middle;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.nx-picture img {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: 0;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
30
|
+
object-fit: cover;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.nx-picture--empty .nx-icon {
|
|
34
|
+
width: min(50%, 2rem);
|
|
35
|
+
height: auto;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.nx-picture--round {
|
|
39
|
+
border-radius: 50%;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* No picture, a name: its initials, on the name's avatar tone (Nexus.Avatar.css), in the text colour. */
|
|
43
|
+
.nx-picture--initials {
|
|
44
|
+
color: var(--nx-text);
|
|
45
|
+
font-size: max(8px, calc(var(--nx-picture-h, 28px) * 0.4));
|
|
46
|
+
font-weight: 600;
|
|
47
|
+
line-height: 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Not read yet: the tint alone, so a row with a picture never flashes the no-picture icon first. */
|
|
51
|
+
.nx-picture--loading .nx-icon {
|
|
52
|
+
visibility: hidden;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
button.nx-picture {
|
|
56
|
+
cursor: pointer;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
button.nx-picture:hover {
|
|
60
|
+
box-shadow: 0 0 0 1px var(--nx-border-strong);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:is(button.nx-picture, .nx-files__name):focus-visible {
|
|
64
|
+
outline: none;
|
|
65
|
+
box-shadow: var(--nx-focus-ring);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* The picture input: the preview beside its buttons, which wrap under it when the form is narrow. */
|
|
69
|
+
.nx-picture-input {
|
|
70
|
+
min-width: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.nx-picture-input__body {
|
|
74
|
+
display: flex;
|
|
75
|
+
flex-wrap: wrap;
|
|
76
|
+
align-items: center;
|
|
77
|
+
gap: var(--nx-space-3) var(--nx-space-4);
|
|
78
|
+
margin-top: var(--nx-space-1);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.nx-picture-input__actions {
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-wrap: wrap;
|
|
84
|
+
gap: var(--nx-space-2);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* The gallery and the document list. */
|
|
88
|
+
.nx-files {
|
|
89
|
+
display: grid;
|
|
90
|
+
gap: var(--nx-space-4);
|
|
91
|
+
min-width: 0;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.nx-files__bar {
|
|
95
|
+
display: flex;
|
|
96
|
+
flex-wrap: wrap;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: space-between;
|
|
99
|
+
gap: var(--nx-space-2) var(--nx-space-3);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.nx-files__note {
|
|
103
|
+
margin: 0;
|
|
104
|
+
color: var(--nx-text-muted);
|
|
105
|
+
font-size: var(--nx-text-sm);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.nx-files__note--error {
|
|
109
|
+
color: var(--nx-danger-text);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.nx-files__empty {
|
|
113
|
+
display: grid;
|
|
114
|
+
place-items: center;
|
|
115
|
+
gap: var(--nx-space-2);
|
|
116
|
+
padding: var(--nx-space-8) var(--nx-space-4);
|
|
117
|
+
border-radius: var(--nx-radius-lg);
|
|
118
|
+
background: color-mix(in oklab, var(--nx-text) 4%, var(--nx-surface));
|
|
119
|
+
color: var(--nx-text-muted);
|
|
120
|
+
text-align: center;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.nx-files__empty > .nx-icon {
|
|
124
|
+
width: 2rem;
|
|
125
|
+
height: 2rem;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.nx-files__empty p {
|
|
129
|
+
margin: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.nx-files__grid,
|
|
133
|
+
.nx-files__list {
|
|
134
|
+
margin: 0;
|
|
135
|
+
padding: 0;
|
|
136
|
+
list-style: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/*
|
|
140
|
+
* Pictures in two panes (the 2026-06-20 gallery): the main picture large with its buttons and the count, a hairline,
|
|
141
|
+
* then the grid. The gallery is the size container: under 560px of its own width the main picture sits small beside
|
|
142
|
+
* its buttons, over the grid. In its window (a flush popup's body) it has a height of its own, so the grid scrolls and
|
|
143
|
+
* nothing else does; in a page or a tab it is as tall as its pictures.
|
|
144
|
+
*/
|
|
145
|
+
.nx-files--panes {
|
|
146
|
+
container-type: inline-size;
|
|
147
|
+
width: 100%;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.nx-files__frame {
|
|
151
|
+
display: grid;
|
|
152
|
+
grid-template-columns: auto minmax(0, 1fr);
|
|
153
|
+
min-height: 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.nx-files__side {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-direction: column;
|
|
159
|
+
gap: var(--nx-space-4);
|
|
160
|
+
box-sizing: content-box;
|
|
161
|
+
width: 15rem;
|
|
162
|
+
min-height: 0;
|
|
163
|
+
padding-inline-end: var(--nx-space-5);
|
|
164
|
+
border-inline-end: 1px solid var(--nx-border);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/* The main picture: about 15rem on its long side, a rounded square for every shape (only an avatar is round). */
|
|
168
|
+
.nx-files__cover {
|
|
169
|
+
--nx-picture-h: calc(15rem / max(1, var(--nx-picture-ratio, 1)));
|
|
170
|
+
|
|
171
|
+
align-self: center;
|
|
172
|
+
border-radius: var(--nx-radius-lg);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.nx-files__cover.nx-picture--empty .nx-icon {
|
|
176
|
+
width: 3rem;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.nx-files__about {
|
|
180
|
+
display: grid;
|
|
181
|
+
align-content: start;
|
|
182
|
+
gap: var(--nx-space-3);
|
|
183
|
+
min-width: 0;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.nx-files__side-actions {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-wrap: wrap;
|
|
189
|
+
gap: var(--nx-space-2);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.nx-files__side-actions > .nx-btn {
|
|
193
|
+
flex: 1 1 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.nx-files__pane {
|
|
197
|
+
min-width: 0;
|
|
198
|
+
min-height: 0;
|
|
199
|
+
padding-inline-start: var(--nx-space-5);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/*
|
|
203
|
+
* The window: edge to edge, the panes padded inside, a height of its own (the whole window once it fills it). What is
|
|
204
|
+
* not the panes there - the list that could not be read, with Try again - has the window's own padding.
|
|
205
|
+
*/
|
|
206
|
+
.nx-popup--flush .nx-popup__body > .nx-files:not(.nx-files--panes) {
|
|
207
|
+
padding: var(--nx-space-5);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@media (max-width: 600px) {
|
|
211
|
+
.nx-popup--flush .nx-popup__body > .nx-files:not(.nx-files--panes) {
|
|
212
|
+
padding: var(--nx-space-4);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.nx-popup--flush .nx-popup__body > .nx-files--panes {
|
|
217
|
+
height: min(36rem, calc(100dvh - 10rem));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.nx-popup:is(.nx-popup--full, .nx-popup--maximized) .nx-popup__body > .nx-files--panes {
|
|
221
|
+
height: 100%;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.nx-popup--flush .nx-popup__body > .nx-files--panes .nx-files__frame {
|
|
225
|
+
height: 100%;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.nx-popup--flush .nx-popup__body > .nx-files--panes :is(.nx-files__side, .nx-files__pane) {
|
|
229
|
+
padding: var(--nx-space-5);
|
|
230
|
+
overflow-y: auto;
|
|
231
|
+
overscroll-behavior: contain;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/* At least two pictures a row; about 11rem each where there is room. */
|
|
235
|
+
.nx-files__grid {
|
|
236
|
+
display: grid;
|
|
237
|
+
grid-template-columns: repeat(auto-fill, minmax(min(11rem, calc(50% - var(--nx-space-3) / 2)), 1fr));
|
|
238
|
+
gap: var(--nx-space-3);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.nx-files__tile {
|
|
242
|
+
position: relative;
|
|
243
|
+
min-width: 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* A picture in the grid: a rounded square (or the page's shape), the picture covering it. */
|
|
247
|
+
.nx-files__thumb,
|
|
248
|
+
.nx-table__bone.nx-files__bone {
|
|
249
|
+
position: relative;
|
|
250
|
+
display: block;
|
|
251
|
+
width: 100%;
|
|
252
|
+
height: auto;
|
|
253
|
+
aspect-ratio: var(--nx-picture-ratio, 1);
|
|
254
|
+
overflow: hidden;
|
|
255
|
+
border-radius: var(--nx-radius-lg);
|
|
256
|
+
background: color-mix(in oklab, var(--nx-text) 7%, var(--nx-surface));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.nx-files__thumb img {
|
|
260
|
+
position: absolute;
|
|
261
|
+
inset: 0;
|
|
262
|
+
width: 100%;
|
|
263
|
+
height: 100%;
|
|
264
|
+
object-fit: cover;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.nx-files__tile:hover .nx-files__thumb {
|
|
268
|
+
box-shadow: 0 0 0 1px var(--nx-border-strong);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* The main picture: a ring in the accent, and the Main tag in its corner. */
|
|
272
|
+
.nx-files__tile[data-primary] .nx-files__thumb {
|
|
273
|
+
box-shadow: 0 0 0 2px var(--nx-primary);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
.nx-files__mark {
|
|
277
|
+
position: absolute;
|
|
278
|
+
top: var(--nx-space-2);
|
|
279
|
+
left: var(--nx-space-2);
|
|
280
|
+
box-shadow: var(--nx-shadow-sm);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/*
|
|
284
|
+
* The picture's buttons, inside it and centred, on a popover's panel. Shown on hover and on a keyboard's focus in the
|
|
285
|
+
* picture; where a finger may press (a touch screen, a laptop's too) always, so no button waits behind a hover.
|
|
286
|
+
* Hidden, they stay in the Tab order and to a screen reader, but take no press: a tap meant for the picture never
|
|
287
|
+
* runs Make main or Edit unseen.
|
|
288
|
+
*/
|
|
289
|
+
.nx-files__tools {
|
|
290
|
+
position: absolute;
|
|
291
|
+
inset: 0;
|
|
292
|
+
display: flex;
|
|
293
|
+
flex-wrap: wrap;
|
|
294
|
+
justify-content: center;
|
|
295
|
+
gap: 2px;
|
|
296
|
+
width: fit-content;
|
|
297
|
+
max-width: calc(100% - var(--nx-space-2));
|
|
298
|
+
height: fit-content;
|
|
299
|
+
margin: auto;
|
|
300
|
+
padding: 3px;
|
|
301
|
+
border: 1px solid var(--nx-border);
|
|
302
|
+
border-radius: var(--nx-radius);
|
|
303
|
+
background: light-dark(var(--nx-surface), var(--nx-surface-2));
|
|
304
|
+
box-shadow: var(--nx-shadow);
|
|
305
|
+
opacity: 0;
|
|
306
|
+
pointer-events: none;
|
|
307
|
+
transition: opacity var(--nx-duration) ease-out;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.nx-files__tile:is(:hover, :has(:focus-visible)) .nx-files__tools {
|
|
311
|
+
opacity: 1;
|
|
312
|
+
pointer-events: auto;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
@media (hover: none), (any-hover: none), (any-pointer: coarse) {
|
|
316
|
+
.nx-files__tools {
|
|
317
|
+
opacity: 1;
|
|
318
|
+
pointer-events: auto;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
@container (max-width: 559.98px) {
|
|
323
|
+
.nx-files__frame {
|
|
324
|
+
display: flex;
|
|
325
|
+
flex-direction: column;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.nx-files__side {
|
|
329
|
+
flex-direction: row;
|
|
330
|
+
align-items: flex-start;
|
|
331
|
+
flex-shrink: 0;
|
|
332
|
+
gap: var(--nx-space-3);
|
|
333
|
+
box-sizing: border-box;
|
|
334
|
+
width: auto;
|
|
335
|
+
padding: 0 0 var(--nx-space-4);
|
|
336
|
+
border-inline-end: 0;
|
|
337
|
+
border-bottom: 1px solid var(--nx-border);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.nx-files__cover {
|
|
341
|
+
--nx-picture-h: calc(7rem / max(1, var(--nx-picture-ratio, 1)));
|
|
342
|
+
|
|
343
|
+
align-self: flex-start;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.nx-files__cover.nx-picture--empty .nx-icon {
|
|
347
|
+
width: 2rem;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.nx-files__about {
|
|
351
|
+
flex: 1 1 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.nx-files__pane {
|
|
355
|
+
flex: 1 1 auto;
|
|
356
|
+
padding: var(--nx-space-4) 0 0;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.nx-popup--flush .nx-popup__body > .nx-files--panes .nx-files__side {
|
|
360
|
+
flex-shrink: 0;
|
|
361
|
+
padding: var(--nx-space-4);
|
|
362
|
+
overflow: visible;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.nx-popup--flush .nx-popup__body > .nx-files--panes .nx-files__pane {
|
|
366
|
+
padding: var(--nx-space-4);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
[data-nx-motion="reduce"] .nx-files__tools {
|
|
371
|
+
transition: none;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* The document list: a row per file, its buttons at the end. */
|
|
375
|
+
.nx-files__actions {
|
|
376
|
+
display: inline-flex;
|
|
377
|
+
gap: 2px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.nx-files__row {
|
|
381
|
+
display: grid;
|
|
382
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
383
|
+
align-items: center;
|
|
384
|
+
gap: var(--nx-space-3);
|
|
385
|
+
padding: var(--nx-space-2) 0;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.nx-files__row + .nx-files__row {
|
|
389
|
+
border-top: 1px solid var(--nx-border);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.nx-files__row-text {
|
|
393
|
+
display: grid;
|
|
394
|
+
min-width: 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.nx-files__name {
|
|
398
|
+
overflow: hidden;
|
|
399
|
+
border-radius: var(--nx-radius-sm);
|
|
400
|
+
color: var(--nx-text);
|
|
401
|
+
font-weight: 500;
|
|
402
|
+
text-decoration: none;
|
|
403
|
+
text-overflow: ellipsis;
|
|
404
|
+
white-space: nowrap;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.nx-files__name:hover {
|
|
408
|
+
text-decoration: underline;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
@@ -180,10 +180,13 @@
|
|
|
180
180
|
flex: 1;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
/*
|
|
183
|
+
/*
|
|
184
|
+
* One line kept even when empty: "Loading…", "Saving…" and "Unsaved changes" come and go, and the bar never jumps.
|
|
185
|
+
* The room kept beside the buttons is 14rem; a bar whose words are fewer asks less (`--nx-form-status-basis`).
|
|
186
|
+
*/
|
|
184
187
|
.nx-form-status {
|
|
185
188
|
display: flex;
|
|
186
|
-
flex: 1 1 14rem;
|
|
189
|
+
flex: 1 1 var(--nx-form-status-basis, 14rem);
|
|
187
190
|
align-items: flex-start;
|
|
188
191
|
gap: 6px;
|
|
189
192
|
min-width: 0;
|
|
@@ -22,10 +22,14 @@
|
|
|
22
22
|
@import "./Nexus.Input.css";
|
|
23
23
|
@import "./Nexus.Editor.css";
|
|
24
24
|
@import "./Nexus.Excel.css";
|
|
25
|
+
@import "./Nexus.Files.css";
|
|
25
26
|
@import "./Nexus.Form.css";
|
|
26
27
|
@import "./Nexus.Markdown.css";
|
|
27
28
|
@import "./Nexus.Menu.css";
|
|
28
29
|
@import "./Nexus.Popup.css";
|
|
30
|
+
@import "./Nexus.Print.css";
|
|
31
|
+
@import "./Nexus.QrCode.css";
|
|
32
|
+
@import "./Nexus.Record.css";
|
|
29
33
|
@import "./Nexus.RichText.css";
|
|
30
34
|
@import "./Nexus.Rows.css";
|
|
31
35
|
@import "./Nexus.Slider.css";
|
|
@@ -139,11 +139,36 @@
|
|
|
139
139
|
font-variant-numeric: tabular-nums;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
/*
|
|
143
|
+
* A value worked out from other inputs (a form's `compute`): an <output> where an input would be, its text placed as an
|
|
144
|
+
* input's is (in the middle of the box, low in an inbox one) and in the text colour, a long one cut with an ellipsis.
|
|
145
|
+
* Never typed in, so no I-beam; the read-only tint around it comes from the field.
|
|
146
|
+
*/
|
|
147
|
+
.nx-field__control--output {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
overflow: hidden;
|
|
151
|
+
white-space: nowrap;
|
|
152
|
+
cursor: default;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.nx-field__output-text {
|
|
156
|
+
min-width: 0;
|
|
157
|
+
overflow: hidden;
|
|
158
|
+
text-overflow: ellipsis;
|
|
159
|
+
}
|
|
160
|
+
|
|
142
161
|
.nx-field__control::placeholder {
|
|
143
162
|
color: var(--nx-text-subtle);
|
|
144
163
|
opacity: 1;
|
|
145
164
|
}
|
|
146
165
|
|
|
166
|
+
/* A read-only field's placeholder is all it shows ("None"), so it reads as text: --nx-text-subtle is under 3:1 on the
|
|
167
|
+
read-only box in light themes, muted text at least 4.5:1. */
|
|
168
|
+
.nx-field[data-readonly] .nx-field__control::placeholder {
|
|
169
|
+
color: var(--nx-text-muted);
|
|
170
|
+
}
|
|
171
|
+
|
|
147
172
|
/* Browser extras that the field replaces with its own buttons. */
|
|
148
173
|
.nx-field__control::-webkit-search-cancel-button,
|
|
149
174
|
.nx-field__control::-webkit-search-decoration {
|
|
@@ -338,6 +363,12 @@
|
|
|
338
363
|
animation: nx-field-nudge 320ms ease-in-out;
|
|
339
364
|
}
|
|
340
365
|
|
|
366
|
+
/* A box pointed at with the same nudge: the one thing to set first, when the cursor is sent to it (a CRUD's Add pressed
|
|
367
|
+
while its narrowing box has nothing picked). */
|
|
368
|
+
.nx-field__box[data-nudge] {
|
|
369
|
+
animation: nx-field-nudge 320ms ease-in-out;
|
|
370
|
+
}
|
|
371
|
+
|
|
341
372
|
@keyframes nx-field-nudge {
|
|
342
373
|
20%,
|
|
343
374
|
60% {
|
|
@@ -577,6 +608,16 @@
|
|
|
577
608
|
resize: vertical;
|
|
578
609
|
}
|
|
579
610
|
|
|
611
|
+
/* Code (`TextArea code`): the editor's monospace, lines kept as typed, a long one scrolled sideways in the box. */
|
|
612
|
+
.nx-field--multiline .nx-field__control--code {
|
|
613
|
+
overflow-x: auto;
|
|
614
|
+
font-family: var(--nx-font-mono);
|
|
615
|
+
font-size: calc(var(--nx-field-font) - 0.5px);
|
|
616
|
+
white-space: pre;
|
|
617
|
+
overflow-wrap: normal;
|
|
618
|
+
tab-size: 2;
|
|
619
|
+
}
|
|
620
|
+
|
|
580
621
|
/* Buttons and the read-only lock sit at the top end, centered on the first line (line height 1.4). */
|
|
581
622
|
.nx-field--multiline .nx-field__actions {
|
|
582
623
|
align-items: flex-start;
|
|
@@ -788,6 +829,7 @@
|
|
|
788
829
|
}
|
|
789
830
|
|
|
790
831
|
[data-nx-motion="reduce"] .nx-field__lock[data-nudge],
|
|
832
|
+
[data-nx-motion="reduce"] .nx-field__box[data-nudge],
|
|
791
833
|
[data-nx-motion="reduce"] .nx-field-notice:popover-open {
|
|
792
834
|
animation: none;
|
|
793
835
|
}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
min-width: 180px;
|
|
16
16
|
max-width: min(360px, calc(100% - 16px));
|
|
17
17
|
outline: none;
|
|
18
|
+
/* A row's menu sits inside the table's actions cell, which does not wrap; an item's second line has to. */
|
|
19
|
+
white-space: normal;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/* The items scroll inside the panel (`.nx-popover__scroll`): a block, so a long menu scrolls instead of squeezing
|
|
@@ -60,12 +62,19 @@
|
|
|
60
62
|
background: var(--nx-surface-hover);
|
|
61
63
|
}
|
|
62
64
|
|
|
65
|
+
/*
|
|
66
|
+
* A switched-off item fades its icon, check, label and shortcut, not its second line: that line is why it is off
|
|
67
|
+
* (a locked record's reason, what an action waits for), and at half strength it measured 2.0 to 3.1:1 in every theme.
|
|
68
|
+
*/
|
|
63
69
|
.nx-menu__item[aria-disabled="true"] {
|
|
64
70
|
background: none;
|
|
65
|
-
opacity: 0.5;
|
|
66
71
|
cursor: not-allowed;
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
.nx-menu__item[aria-disabled="true"] :is(.nx-menu__icon, .nx-menu__check, .nx-menu__label, .nx-menu__shortcut) {
|
|
75
|
+
opacity: 0.5;
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
/* The icon column: the same width on every item, empty on items without an icon. */
|
|
70
79
|
.nx-menu__icon {
|
|
71
80
|
display: grid;
|
|
@@ -351,12 +351,18 @@
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
/* Body: scrolls when the content is taller than the window allows. */
|
|
354
|
+
/*
|
|
355
|
+
* Focus scrolls a field's control to the body's edge: `scroll-padding` keeps room past it for what the field draws
|
|
356
|
+
* outside, an outlined field's raised label above (0.6em of the xs text, and the 2px outline) and the box's border and
|
|
357
|
+
* 3px focus ring below. A field first in the body has its padding for that.
|
|
358
|
+
*/
|
|
354
359
|
.nx-popup__body {
|
|
355
360
|
flex: 1 1 auto;
|
|
356
361
|
min-height: 0;
|
|
357
362
|
padding: var(--nx-space-4) var(--nx-space-5) var(--nx-space-5);
|
|
358
363
|
overflow: auto;
|
|
359
364
|
overscroll-behavior: contain;
|
|
365
|
+
scroll-padding: calc(var(--nx-text-xs) * 0.6 + 2px) 4px 4px;
|
|
360
366
|
}
|
|
361
367
|
|
|
362
368
|
.nx-popup__head + .nx-popup__body:empty {
|
|
@@ -403,6 +409,15 @@
|
|
|
403
409
|
line-height: 1.5;
|
|
404
410
|
}
|
|
405
411
|
|
|
412
|
+
/* What a question is about, in full (`details`): read as content, so in the normal text colour, under the message. */
|
|
413
|
+
.nx-message__details {
|
|
414
|
+
color: var(--nx-text);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.nx-message__text + .nx-message__details {
|
|
418
|
+
margin-top: var(--nx-space-4);
|
|
419
|
+
}
|
|
420
|
+
|
|
406
421
|
.nx-message__form {
|
|
407
422
|
display: grid;
|
|
408
423
|
gap: var(--nx-space-4);
|
|
@@ -628,8 +643,15 @@
|
|
|
628
643
|
vertical-align: 0;
|
|
629
644
|
}
|
|
630
645
|
|
|
631
|
-
.
|
|
646
|
+
/* The title, and under it what the window is about when it says (its description): the record, the place. */
|
|
647
|
+
.nx-dock__text {
|
|
648
|
+
display: flex;
|
|
632
649
|
flex: 1 1 auto;
|
|
650
|
+
flex-direction: column;
|
|
651
|
+
min-width: 0;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.nx-dock__title {
|
|
633
655
|
min-width: 0;
|
|
634
656
|
overflow: hidden;
|
|
635
657
|
font-size: var(--nx-text-md);
|
|
@@ -639,6 +661,21 @@
|
|
|
639
661
|
white-space: nowrap;
|
|
640
662
|
}
|
|
641
663
|
|
|
664
|
+
.nx-dock__description {
|
|
665
|
+
min-width: 0;
|
|
666
|
+
overflow: hidden;
|
|
667
|
+
color: var(--nx-text-muted);
|
|
668
|
+
font-size: var(--nx-text-xs);
|
|
669
|
+
line-height: 1.3;
|
|
670
|
+
text-overflow: ellipsis;
|
|
671
|
+
white-space: nowrap;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/* Muted text on the hover tint moves toward the text color, so it keeps 4.5:1 in every theme. */
|
|
675
|
+
.nx-dock__window:hover .nx-dock__description {
|
|
676
|
+
color: color-mix(in oklab, var(--nx-text-muted), var(--nx-text) 35%);
|
|
677
|
+
}
|
|
678
|
+
|
|
642
679
|
.nx-dock__restore {
|
|
643
680
|
flex-shrink: 0;
|
|
644
681
|
width: 18px;
|
|
@@ -711,6 +748,45 @@
|
|
|
711
748
|
.nx-popup__foot {
|
|
712
749
|
padding: var(--nx-space-3) var(--nx-space-4);
|
|
713
750
|
}
|
|
751
|
+
|
|
752
|
+
/*
|
|
753
|
+
* A phone has no room for the description after the title: it takes the lines under the title it needs, in full,
|
|
754
|
+
* and the bar grows with it. The icon and the window buttons keep the bar's first line; the title stays one line.
|
|
755
|
+
*/
|
|
756
|
+
.nx-popup--window .nx-popup__head {
|
|
757
|
+
align-items: flex-start;
|
|
758
|
+
height: auto;
|
|
759
|
+
min-height: var(--nx-popup-bar);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
.nx-popup--window .nx-popup__icon {
|
|
763
|
+
align-self: flex-start;
|
|
764
|
+
height: var(--nx-popup-bar);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.nx-popup--window .nx-popup__heading {
|
|
768
|
+
flex-wrap: wrap;
|
|
769
|
+
row-gap: 0;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.nx-popup--window .nx-popup__title {
|
|
773
|
+
flex-basis: 100%;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.nx-popup--window .nx-popup__description:not(:empty) {
|
|
777
|
+
flex-basis: 100%;
|
|
778
|
+
margin-top: calc(var(--nx-space-1) * -1);
|
|
779
|
+
padding-bottom: var(--nx-space-2);
|
|
780
|
+
overflow: visible;
|
|
781
|
+
line-height: 1.45;
|
|
782
|
+
white-space: normal;
|
|
783
|
+
overflow-wrap: anywhere;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.nx-popup--window .nx-popup__controls {
|
|
787
|
+
align-self: flex-start;
|
|
788
|
+
height: var(--nx-popup-bar);
|
|
789
|
+
}
|
|
714
790
|
}
|
|
715
791
|
|
|
716
792
|
[data-nx-motion="reduce"] .nx-popup[open],
|