@nexterajs/ui 0.0.1 → 0.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 (63) hide show
  1. package/README.md +279 -34
  2. package/fesm2022/nexterajs-ui-charts.mjs +1096 -0
  3. package/fesm2022/nexterajs-ui-charts.mjs.map +1 -0
  4. package/fesm2022/nexterajs-ui-core.mjs +835 -11
  5. package/fesm2022/nexterajs-ui-core.mjs.map +1 -1
  6. package/fesm2022/nexterajs-ui-display.mjs +1142 -0
  7. package/fesm2022/nexterajs-ui-display.mjs.map +1 -0
  8. package/fesm2022/nexterajs-ui-dropdowns.mjs +621 -69
  9. package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -1
  10. package/fesm2022/nexterajs-ui-file-uploader.mjs +576 -11
  11. package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -1
  12. package/fesm2022/nexterajs-ui-forms.mjs +2702 -452
  13. package/fesm2022/nexterajs-ui-forms.mjs.map +1 -1
  14. package/fesm2022/nexterajs-ui-grid.mjs +2350 -336
  15. package/fesm2022/nexterajs-ui-grid.mjs.map +1 -1
  16. package/fesm2022/nexterajs-ui-intl.mjs +117 -15
  17. package/fesm2022/nexterajs-ui-intl.mjs.map +1 -1
  18. package/fesm2022/nexterajs-ui-navigation.mjs +1054 -0
  19. package/fesm2022/nexterajs-ui-navigation.mjs.map +1 -0
  20. package/fesm2022/nexterajs-ui-notify.mjs +353 -0
  21. package/fesm2022/nexterajs-ui-notify.mjs.map +1 -0
  22. package/fesm2022/nexterajs-ui-overlay.mjs +1671 -0
  23. package/fesm2022/nexterajs-ui-overlay.mjs.map +1 -0
  24. package/fesm2022/nexterajs-ui-pivot.mjs +191 -136
  25. package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -1
  26. package/fesm2022/nexterajs-ui-shell.mjs +542 -0
  27. package/fesm2022/nexterajs-ui-shell.mjs.map +1 -0
  28. package/fesm2022/nexterajs-ui-styling.mjs +568 -3
  29. package/fesm2022/nexterajs-ui-styling.mjs.map +1 -1
  30. package/fesm2022/nexterajs-ui-tree-view.mjs +150 -18
  31. package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -1
  32. package/fesm2022/nexterajs-ui-validation.mjs +283 -97
  33. package/fesm2022/nexterajs-ui-validation.mjs.map +1 -1
  34. package/fesm2022/nexterajs-ui.mjs +6 -0
  35. package/fesm2022/nexterajs-ui.mjs.map +1 -1
  36. package/package.json +37 -2
  37. package/styles/_dropdown.scss +150 -1
  38. package/styles/_editor.scss +75 -21
  39. package/styles/_icons.scss +92 -0
  40. package/styles/_mixins.scss +104 -1
  41. package/styles/_scrollbar.scss +134 -0
  42. package/styles/_status.scss +21 -0
  43. package/styles/_toast.scss +243 -0
  44. package/styles/_tokens.scss +467 -2
  45. package/styles/_widget.scss +14 -3
  46. package/styles/index.scss +10 -4
  47. package/types/nexterajs-ui-charts.d.ts +446 -0
  48. package/types/nexterajs-ui-core.d.ts +515 -30
  49. package/types/nexterajs-ui-display.d.ts +720 -0
  50. package/types/nexterajs-ui-dropdowns.d.ts +318 -57
  51. package/types/nexterajs-ui-file-uploader.d.ts +240 -8
  52. package/types/nexterajs-ui-forms.d.ts +772 -43
  53. package/types/nexterajs-ui-grid.d.ts +878 -135
  54. package/types/nexterajs-ui-intl.d.ts +39 -4
  55. package/types/nexterajs-ui-navigation.d.ts +531 -0
  56. package/types/nexterajs-ui-notify.d.ts +149 -0
  57. package/types/nexterajs-ui-overlay.d.ts +703 -0
  58. package/types/nexterajs-ui-pivot.d.ts +91 -70
  59. package/types/nexterajs-ui-shell.d.ts +294 -0
  60. package/types/nexterajs-ui-styling.d.ts +163 -3
  61. package/types/nexterajs-ui-tree-view.d.ts +56 -4
  62. package/types/nexterajs-ui-validation.d.ts +110 -22
  63. package/types/nexterajs-ui.d.ts +6 -0
@@ -30,12 +30,14 @@
30
30
  // `:root` overrides — defaults silently winning over the app that is trying to configure them.
31
31
  // `:where()` pins these to zero specificity, so any host declaration always wins.
32
32
  :where(:root) {
33
+ // @group Typography
33
34
  // Typography — reference `.dx-widget`
34
35
  --nxe-ui-font-family: Helvetica Neue, Segoe UI, helvetica, verdana, sans-serif;
35
36
  --nxe-ui-font-size: 14px; // dx default. orbit overrides -> 0.85rem (= 12.24px @ 14.4px root)
36
37
  --nxe-ui-font-weight: 400;
37
38
  --nxe-ui-line-height: 1.35715;
38
39
 
40
+ // @group Palette
39
41
  // Palette — reference dx.light
40
42
  --nxe-ui-text: #333;
41
43
  --nxe-ui-text-muted: #999;
@@ -45,33 +47,496 @@
45
47
  --nxe-ui-accent-contrast: #fff;
46
48
  --nxe-ui-danger: #d9534f;
47
49
  --nxe-ui-success: #5cb85c;
50
+ --nxe-ui-accent-strong: #265a87; // accent hover border (checkbox, calendar, dropdown); darker than accent
51
+ --nxe-ui-surface-alt: #f5f5f5; // alternate / header / hover-fill surface (grid rows, pivot headers)
52
+ --nxe-ui-ink-strong: #30374c; // badge fill, spinner head, drop-zone outline
48
53
 
54
+ // @group Derived tints
55
+ // Derived tints. color-mix keeps them in step with the base colour: an app that sets only
56
+ // `--nxe-ui-accent` gets matching hover borders and selection tints. With the default colours
57
+ // they equal the old literal rgba() values exactly.
58
+ --nxe-ui-accent-faded: color-mix(in srgb, var(--nxe-ui-accent) 40%, transparent); // editor hover border
59
+ --nxe-ui-accent-tint: color-mix(in srgb, var(--nxe-ui-accent) 24%, transparent); // calendar selected-range tint
60
+ --nxe-ui-border-faded: color-mix(in srgb, var(--nxe-ui-border) 20%, transparent); // pivot area header fill
61
+ --nxe-ui-text-disabled: color-mix(in srgb, var(--nxe-ui-text) 38%, transparent); // calendar out-of-range days
62
+
63
+ // @group Invalid state
64
+ // Invalid state: editors, check box, file uploader. Defaults to the danger colour.
65
+ --nxe-ui-invalid: var(--nxe-ui-danger); // border, badge disc, message bubble, error text
66
+ --nxe-ui-invalid-contrast: #fff; // "!" glyph and message text on the invalid fill
67
+ --nxe-ui-invalid-faded: color-mix(in srgb, var(--nxe-ui-invalid) 40%, transparent); // resting invalid border
68
+
69
+ // @group Focus
70
+ // Focus. `focus-ring` is a box-shadow value (calendar selected day; opt-in for buttons via
71
+ // `--nxe-ui-button-focus-ring`); `focus-ring-color` is the pager keyboard outline.
72
+ --nxe-ui-focus-ring: 0 0 0 2px color-mix(in srgb, var(--nxe-ui-accent) 50%, transparent);
73
+ --nxe-ui-focus-ring-color: #5c95c5;
74
+
75
+ // @group State layers
49
76
  // State layers — reference dx.light list/menu states
50
77
  --nxe-ui-hover-bg: rgba(0, 0, 0, 0.04);
51
78
  --nxe-ui-selected-bg: rgba(0, 0, 0, 0.1);
52
79
  --nxe-ui-selected-hover-bg: rgba(0, 0, 0, 0.07);
53
80
  --nxe-ui-focus-selected-bg: rgba(51, 122, 183, 0.7);
54
81
  --nxe-ui-disabled-opacity: 0.5;
82
+ --nxe-ui-focus-bg: rgba(0, 0, 0, 0.08); // keyboard-focused icon button
83
+ --nxe-ui-active-bg: rgba(0, 0, 0, 0.24); // pressed icon button
84
+ --nxe-ui-checkbox-active-bg: rgba(96, 96, 96, 0.2); // pressed check box icon
55
85
 
86
+ // @group Metrics
56
87
  // Metrics
57
88
  --nxe-ui-radius: 4px;
58
89
  --nxe-ui-popup-radius: 6px;
59
- --nxe-ui-popup-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
90
+ --nxe-ui-popup-shadow: var(--nxe-ui-shadow-md);
60
91
  --nxe-ui-item-padding: 7px 9px;
61
92
  --nxe-ui-list-padding: 10px;
62
93
 
94
+ // @group Overlay geometry
63
95
  // Overlay geometry — host apps that skinned dx popups override these.
64
96
  // 0 keeps a dropdown panel exactly as wide as the editor it drops from (the components set
65
97
  // `width` inline from the trigger's offsetWidth; a non-zero floor here overrides that). Orbit
66
98
  // carried the dx-era `.dx-overlay-content { min-width: 400px !important }` here until
67
99
  // 2026-07-29 and dropped it — see nxe-ui/DEFAULTS.md.
68
100
  --nxe-ui-overlay-min-width: 0px;
101
+ // Header-filter popup floor. The popup is dx's own 252x325; broker's global
102
+ // `.dx-overlay-content{min-width:400px}` made it 400px wide in the dx era, which an app can
103
+ // restore here without widening every dropdown panel.
104
+ --nxe-ui-header-filter-min-width: 0px;
105
+ // Field-chooser popup floor. dx's own field chooser popup has no 400px floor; broker's global
106
+ // `.dx-overlay-content{min-width:400px}` made it 400px wide in the dx era, which an app can
107
+ // restore here without widening every dropdown panel.
108
+ --nxe-ui-fieldchooser-min-width: 0px;
109
+
110
+ // @group Check box and button gap
111
+ // Check box hover border - dx `.dx-checkbox.dx-state-hover .dx-checkbox-icon{border-color:#265a87}`.
112
+ --nxe-ui-checkbox-hover-border: var(--nxe-ui-accent-strong);
113
+
114
+ // Gap between a button's projected children. dx `.dx-button-content` has none; an app whose
115
+ // icon + text buttons relied on the library's former 4px can set it back.
116
+ --nxe-ui-button-gap: 0px;
117
+
118
+ // @group Data grid
119
+ // Data grid empty state — dx `.dx-datagrid-rowsview.dx-empty{height:100px}` and
120
+ // `.dx-datagrid-nodata{font-size:17px}`.
121
+ --nxe-ui-grid-empty-height: 100px;
122
+ --nxe-ui-grid-nodata-font-size: 17px;
123
+
124
+ // Data grid and tree list lines - dx.light's values. Whether a grid draws them is per grid
125
+ // ([showRowLines], [showColumnLines], [showBorders], [rowAlternationEnabled]) or app-wide
126
+ // (NXE_DEFAULT_OPTIONS.dataGrid / .treeList); these set how they look. Override them at :root
127
+ // for the whole app, or on one grid, e.g.
128
+ // nxe-data-grid.quotes { --nxe-ui-grid-column-line-color: #e2e8f0; }
129
+ // The grid's rules outweigh dx-compat's #ddd copies, so an override holds on selected, edited
130
+ // and group rows too. Literals, not var(--nxe-ui-border): a var() here resolves at :root, and a
131
+ // subtree override of --nxe-ui-border would never reach them.
132
+ --nxe-ui-grid-line-width: 1px; // every grid line and the showBorders box
133
+ --nxe-ui-grid-row-line-color: #ddd; // `.dx-row-lines>td{border-bottom}`, group rows and footers
134
+ --nxe-ui-grid-column-line-color: #ddd; // `.dx-column-lines>td{border-left;border-right}`
135
+ --nxe-ui-grid-border-color: #ddd; // showBorders: `.dx-datagrid-borders>.dx-datagrid-rowsview`,
136
+ // and the pager's top line (`.dx-pager{border-top}`), which
137
+ // lies on the box's bottom edge in a bordered grid
138
+ --nxe-ui-grid-header-line-color: #ddd; // `.dx-datagrid-headers .dx-datagrid-table .dx-row>td`
139
+ --nxe-ui-grid-alt-row-bg: #f5f5f5; // rowAlternationEnabled: `.dx-row-alt>td`
140
+
141
+ // Data grid group rows and expand cells - dx.light's values.
142
+ // group-row-color: `.dx-datagrid-rowsview .dx-row.dx-group-row:not(.dx-row-focused){color:#222}`
143
+ // summary-color: `.dx-datagrid-summary-item{color:rgba(51,51,51,.7)}` (aligned group sums)
144
+ // expand-offset: `.dx-command-expand.dx-datagrid-group-space{padding-top:7px}` - how far down
145
+ // the cell the 18px group / master-detail toggle starts. dx leaves it about
146
+ // 3.3px below the row's middle; an app that wants it centred sets
147
+ // (row height - 18px) / 2 here.
148
+ --nxe-ui-grid-group-row-color: #222;
149
+ --nxe-ui-grid-summary-color: rgba(51, 51, 51, 0.7);
150
+ --nxe-ui-grid-expand-offset: 7px;
151
+
152
+ // Data grid cells and column header - dx.light's values. Apps that skin the grid (bright and
153
+ // orbit: 4px cells, 20px at the edges, a #f8fafc caption row in #525252, indicators at
154
+ // 0.7) set these rather than writing cell selectors.
155
+ // cell-padding: `.dx-datagrid .dx-row>td{padding:7px}`
156
+ // cell-vertical-align: centred, where a table cell sits by default (dx states top, but its cell
157
+ // content fills the line; the grid's geometry specs measure dx with this)
158
+ // indicator-scale / indicator-offset: the sort arrow and header-filter funnel block, shrunk
159
+ // and dropped as one (dx draws them at 14px, flush with the line top)
160
+ // Unset unless an app sets them, because their default is whatever is around them:
161
+ // --nxe-ui-grid-edge-padding the first and last cell's outer side (default: cell-padding)
162
+ // --nxe-ui-grid-header-bg the caption row's fill (default: the headers view's white)
163
+ // --nxe-ui-grid-header-color the caption row's text and arrows (default: #757575, above)
164
+ --nxe-ui-grid-cell-padding: 7px;
165
+ --nxe-ui-grid-cell-vertical-align: middle;
166
+ --nxe-ui-grid-indicator-scale: 1;
167
+ --nxe-ui-grid-indicator-offset: 0px;
168
+
169
+ // @group Neutral ramp
170
+ // Neutral ramp: the greys dx.light hard-codes across the grid, pivot, calendar and scrollbars.
171
+ // The number is lightness (50 lightest, 900 darkest) in the LIGHT theme; `.dark` mirrors the
172
+ // ramp so a step keeps its job (a "250" fill is still the quiet fill) on a dark surface.
173
+ --nxe-ui-neutral-50: #fafafa; // master-detail cell
174
+ --nxe-ui-neutral-60: #f7f7f7; // group-row fill
175
+ --nxe-ui-neutral-65: #f8f8f8; // grid caption fill
176
+ --nxe-ui-neutral-80: #f4f4f4; // button hover, readonly border
177
+ --nxe-ui-neutral-100: #f0f0f0;
178
+ --nxe-ui-neutral-110: #eee; // scrollbar rail hover
179
+ --nxe-ui-neutral-120: #ebebeb; // pager keyboard focus
180
+ --nxe-ui-neutral-150: #e6e6e6; // calendar hover, selected-row frame
181
+ --nxe-ui-neutral-230: #d4d4d4; // pressed header cell
182
+ --nxe-ui-neutral-240: #d3d3d3; // chart axis
183
+ --nxe-ui-neutral-250: #ccc; // toast link hover
184
+ --nxe-ui-neutral-300: #c2c2c2; // pressed secondary button
185
+ --nxe-ui-neutral-350: #b3b3b3; // calendar open
186
+ --nxe-ui-neutral-400: #aaa; // scrollbar thumb, tag close
187
+ --nxe-ui-neutral-450: #959595; // tree glyphs, sort arrows
188
+ --nxe-ui-neutral-500: #898989; // grid icon strokes
189
+ --nxe-ui-neutral-600: #757575; // grid header text
190
+ --nxe-ui-neutral-600-faded: rgba(117, 117, 117, 0.5); // empty header-filter icon
191
+ --nxe-ui-neutral-700: #525252; // pivot header text
192
+ --nxe-ui-neutral-900: #222; // group row text
193
+
194
+ // @group Overlays and scrolling
195
+ --nxe-ui-scrim: rgba(255, 255, 255, 0.5); // grid loading overlay
196
+ --nxe-ui-spinner-track: rgba(48, 55, 76, 0.2);
197
+ --nxe-ui-scrollbar-thumb: rgba(0, 0, 0, 0.5); // fallback thumb (mixins.nxe-thin-scrollbar)
198
+ --nxe-ui-scroll-thumb: rgba(191, 191, 191, 0.7); // nxe-scroll-view thumb
199
+ --nxe-ui-scroll-thumb-hover: rgb(191, 191, 191);
200
+
201
+ // @group Buttons
202
+ // Buttons. The four button types map to the design vocabulary: `primary` = type "default",
203
+ // `secondary` = type "normal" (the white one), plus `success` and `danger`. Fills follow the
204
+ // base palette by default, so setting `--nxe-ui-accent` already recolours primary buttons.
205
+ // Hover and pressed shades are literals because dx's are not a fixed mix of the base: set all
206
+ // five per type for a complete re-skin.
207
+ --nxe-ui-button-bg-primary: var(--nxe-ui-accent);
208
+ --nxe-ui-button-fg-primary: var(--nxe-ui-accent-contrast);
209
+ --nxe-ui-button-border-primary: transparent;
210
+ --nxe-ui-button-hover-bg-primary: #2d6ca3;
211
+ --nxe-ui-button-active-bg-primary: #19405b;
212
+ --nxe-ui-button-bg-secondary: var(--nxe-ui-surface);
213
+ --nxe-ui-button-fg-secondary: var(--nxe-ui-text);
214
+ --nxe-ui-button-border-secondary: var(--nxe-ui-border);
215
+ --nxe-ui-button-hover-bg-secondary: #f4f4f4;
216
+ --nxe-ui-button-active-bg-secondary: #c2c2c2;
217
+ --nxe-ui-button-bg-success: var(--nxe-ui-success);
218
+ --nxe-ui-button-fg-success: #fff;
219
+ --nxe-ui-button-border-success: transparent;
220
+ --nxe-ui-button-hover-bg-success: #46a046;
221
+ --nxe-ui-button-active-bg-success: #306e30;
222
+ --nxe-ui-button-bg-danger: var(--nxe-ui-danger);
223
+ --nxe-ui-button-fg-danger: #fff;
224
+ --nxe-ui-button-border-danger: transparent;
225
+ --nxe-ui-button-hover-bg-danger: #cd312c;
226
+ --nxe-ui-button-active-bg-danger: #932320;
227
+ --nxe-ui-button-focus-ring: none; // keyboard focus box-shadow; dx draws none. Try var(--nxe-ui-focus-ring)
228
+
229
+ // @group Toast
230
+ // Toast notifications (styles/_toast.scss). Dark in both themes by design, so `.dark` leaves them.
231
+ --nxe-ui-toast-fg: #fff;
232
+ --nxe-ui-toast-fg-muted: #ccc;
233
+ --nxe-ui-toast-ink: #000;
234
+ --nxe-ui-toast-shadow-hover: #999;
235
+ --nxe-ui-toast-bg: #030303;
236
+ --nxe-ui-toast-success-bg: #51a351;
237
+ --nxe-ui-toast-error-bg: #bd362f;
238
+ --nxe-ui-toast-info-bg: #2f96b4;
239
+ --nxe-ui-toast-warning-bg: #f89406;
240
+
241
+ // @group Status families
242
+ // Status families (nxe-tag, nxe-badge). The six families of the status catalogue: neutral
243
+ // (draft), info (waiting on the other party), attention (the viewer's move), success, danger and
244
+ // muted (expired, inactive; drawn with a dashed border). `fg` is the text on `bg` at >= 4.5:1;
245
+ // `border` is the quiet edge. Solid tags and badges swap the pair (fill = fg, text = bg), which
246
+ // keeps the same ratio. Outlined tags put `fg` on `--nxe-ui-surface`, also held at >= 4.5:1.
247
+ --nxe-ui-status-neutral-fg: #4a5868;
248
+ --nxe-ui-status-neutral-bg: #eef1f4;
249
+ --nxe-ui-status-neutral-border: #b5bbc3;
250
+ --nxe-ui-status-info-fg: #004d8f;
251
+ --nxe-ui-status-info-bg: #eaf3fb;
252
+ --nxe-ui-status-info-border: #98b9d5;
253
+ --nxe-ui-status-attention-fg: #8a5a00;
254
+ --nxe-ui-status-attention-bg: #fff4db;
255
+ --nxe-ui-status-attention-border: #d6be8e;
256
+ --nxe-ui-status-success-fg: #1c7a4e;
257
+ --nxe-ui-status-success-bg: #e5f5ec;
258
+ --nxe-ui-status-success-border: #9fcab5;
259
+ --nxe-ui-status-danger-fg: #b4322a;
260
+ --nxe-ui-status-danger-bg: #fdecea;
261
+ --nxe-ui-status-danger-border: #e3aba7;
262
+ --nxe-ui-status-muted-fg: #5a6b7d;
263
+ --nxe-ui-status-muted-bg: #f2f4f6;
264
+ --nxe-ui-status-muted-border: #bdc4cc;
265
+
266
+ // @group Chart palette
267
+ // Chart palette (nxe-line-chart, nxe-area-chart, nxe-donut-chart). Eight categorical hues in a
268
+ // FIXED order, assigned to series 1..8 and never cycled: the order is what keeps neighbours apart
269
+ // under colour-vision deficiency. Validated against --nxe-ui-surface (#fff / dark #1c232d) with
270
+ // the dataviz palette validator: every mark >= 3:1 on the surface, adjacent CVD distance >= 8
271
+ // (protan/deutan, OKLab x100), adjacent normal-vision distance >= 15. charts-contrast.spec.ts
272
+ // re-checks the contrast on every build. A host that re-brands the surface must re-run it.
273
+ // `other` is the neutral for the grouped "Other" segment (never a ninth hue).
274
+ --nxe-ui-chart-1: #2a78d6; // blue
275
+ --nxe-ui-chart-2: #eb6834; // orange
276
+ --nxe-ui-chart-3: #16a074; // aqua
277
+ --nxe-ui-chart-4: #b57c00; // yellow, stepped down to clear 3:1 on white
278
+ --nxe-ui-chart-5: #c24e7f; // magenta
279
+ --nxe-ui-chart-6: #008300; // green
280
+ --nxe-ui-chart-7: #4a3aa7; // violet
281
+ --nxe-ui-chart-8: #e34948; // red
282
+ --nxe-ui-chart-other: #898989; // = neutral-500
283
+
284
+ // @group App shell
285
+ // App shell (nxe-shell, nxe-sidenav, nxe-topbar). Sizes are the design-system layout: a 248px
286
+ // sidebar that collapses to a 64px icon rail, a 56px topbar. Colours: the sidebar is a quiet
287
+ // tint of the surface so the page reads as the foreground; `fg` and `active-fg` hold >= 4.5:1
288
+ // on their backgrounds, `fg-muted` (group headings) too. The breakpoint is the `breakpoint`
289
+ // input of nxe-shell, not a token: a media query cannot read a custom property.
290
+ --nxe-ui-shell-sidenav-width: 248px;
291
+ --nxe-ui-shell-sidenav-collapsed-width: 64px;
292
+ --nxe-ui-shell-topbar-height: 56px;
293
+ --nxe-ui-shell-sidenav-bg: #f5f7fa;
294
+ --nxe-ui-shell-sidenav-fg: #333f4d;
295
+ --nxe-ui-shell-sidenav-fg-muted: #5f6b7a;
296
+ --nxe-ui-shell-sidenav-border: #dde3ea;
297
+ --nxe-ui-shell-sidenav-hover-bg: rgba(0, 0, 0, 0.05);
298
+ --nxe-ui-shell-sidenav-active-bg: #e1ecf7;
299
+ --nxe-ui-shell-sidenav-active-fg: #174f80;
300
+ --nxe-ui-shell-topbar-bg: #fff;
301
+ --nxe-ui-shell-topbar-fg: #333;
302
+ --nxe-ui-shell-scrim: rgba(15, 23, 32, 0.45);
303
+ // @group Tooltip
304
+ // Tooltip (nxeTooltip). A dark chip in the light theme and a light one in the dark theme, so it
305
+ // always stands off the page. Both pairs hold >= 4.5:1 (nxe-tooltip-contrast.spec.ts).
306
+ --nxe-ui-tooltip-bg: #2b3340;
307
+ --nxe-ui-tooltip-fg: #fff;
308
+
309
+
310
+ // @group Spacing scale
311
+ // Spacing scale (4px base). New: no component reads these yet. They are for the host app's
312
+ // own layout so app and library share one rhythm.
313
+ --nxe-ui-space-1: 4px;
314
+ --nxe-ui-space-2: 8px;
315
+ --nxe-ui-space-3: 12px;
316
+ --nxe-ui-space-4: 16px;
317
+ --nxe-ui-space-5: 20px;
318
+ --nxe-ui-space-6: 24px;
319
+ --nxe-ui-space-7: 32px;
320
+ --nxe-ui-space-8: 48px;
321
+
322
+ // @group Type scale
323
+ // Type scale (14px base, ~1.2 ratio): sizes, paired line-heights, weights.
324
+ --nxe-ui-font-size-xs: 12px;
325
+ --nxe-ui-font-size-sm: 13px;
326
+ --nxe-ui-font-size-md: 14px;
327
+ --nxe-ui-font-size-lg: 16px;
328
+ --nxe-ui-font-size-xl: 20px;
329
+ --nxe-ui-font-size-2xl: 24px;
330
+ --nxe-ui-font-size-3xl: 32px;
331
+ --nxe-ui-line-height-xs: 16px;
332
+ --nxe-ui-line-height-sm: 18px;
333
+ --nxe-ui-line-height-md: 20px;
334
+ --nxe-ui-line-height-lg: 24px;
335
+ --nxe-ui-line-height-xl: 26px;
336
+ --nxe-ui-line-height-2xl: 30px;
337
+ --nxe-ui-line-height-3xl: 38px;
338
+ --nxe-ui-font-weight-regular: 400;
339
+ --nxe-ui-font-weight-medium: 500;
340
+ --nxe-ui-font-weight-semibold: 600;
341
+ --nxe-ui-font-weight-bold: 700;
342
+
343
+ // @group Radius and elevation scale
344
+ // Radius and elevation scales. `popup-shadow` defaults to `shadow-md`; the grid's floating
345
+ // chips use `shadow-sm`; `shadow-lg` is for dialogs and drawers.
346
+ --nxe-ui-radius-sm: 4px;
347
+ --nxe-ui-radius-md: 6px;
348
+ --nxe-ui-radius-lg: 10px;
349
+ --nxe-ui-radius-xl: 12px;
350
+ --nxe-ui-radius-pill: 999px;
351
+ --nxe-ui-shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.15);
352
+ --nxe-ui-shadow-md: 0 6px 12px rgba(0, 0, 0, 0.175);
353
+ --nxe-ui-shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.2);
354
+
355
+ // @group Density
356
+ // Density. Comfortable is the dx default. `.nxe-density-compact` (below) tightens these.
357
+ --nxe-ui-control-min-height: 34px; // text editors' input row
358
+ --nxe-ui-editor-padding: 7px 9px 8px; // text editors' input padding
359
+ --nxe-ui-button-padding: 8px; // button content padding (icon-only)
360
+ --nxe-ui-button-padding-inline: 12px; // button content inline padding (with text)
69
361
 
70
- // foreground.divider — slate.200
362
+ // foreground.divider: slate.200
71
363
  --nxe-divider-color: #e2e8f0;
72
364
  }
73
365
 
366
+ // Compact density. Put the class on <body> (or any ancestor of the controls). Not zero
367
+ // specificity on purpose: it must beat an app's `:root` token file when the class sits on <html>.
368
+ .nxe-density-compact {
369
+ --nxe-ui-control-min-height: 28px;
370
+ --nxe-ui-editor-padding: 4px 9px 5px;
371
+ --nxe-ui-button-padding: 5px;
372
+ --nxe-ui-button-padding-inline: 10px;
373
+ --nxe-ui-item-padding: 4px 9px;
374
+ --nxe-ui-list-padding: 6px;
375
+ }
376
+
377
+ // Dark theme. Add `class="dark"` to <html> or <body> (or any subtree).
378
+ //
379
+ // This block restates every token that is a different colour in the dark, or an alias / colour-mix
380
+ // of one: a custom property holding `var(--x)` is resolved where it is DECLARED, so a `.dark` on a
381
+ // subtree would otherwise keep the light root's values. Zero specificity, like the defaults: an
382
+ // app's own `.dark { ... }` (or `:root.dark { ... }` when the class is on <html>) wins. An app that
383
+ // re-colours the brand in light must restate those tokens inside `.dark`, or the library's dark
384
+ // blue replaces its brand.
74
385
  :where(.dark) {
386
+ color-scheme: dark;
387
+
388
+ // @group Palette
389
+ --nxe-ui-text: #e4e8ee;
390
+ --nxe-ui-text-muted: #8f9bab;
391
+ --nxe-ui-border: #3a4452;
392
+ --nxe-ui-surface: #1c232d;
393
+ --nxe-ui-accent: #5aa5de;
394
+ --nxe-ui-accent-contrast: #0d1a26;
395
+ --nxe-ui-danger: #ee6f6a;
396
+ --nxe-ui-success: #5fcf86;
397
+ --nxe-ui-accent-strong: #8cc4ee;
398
+ --nxe-ui-surface-alt: #232b37;
399
+ --nxe-ui-ink-strong: #c5cddb;
400
+
401
+ // @group Derived tints
402
+ --nxe-ui-accent-faded: color-mix(in srgb, var(--nxe-ui-accent) 40%, transparent);
403
+ --nxe-ui-accent-tint: color-mix(in srgb, var(--nxe-ui-accent) 24%, transparent);
404
+ --nxe-ui-border-faded: color-mix(in srgb, var(--nxe-ui-border) 20%, transparent);
405
+ --nxe-ui-text-disabled: color-mix(in srgb, var(--nxe-ui-text) 38%, transparent);
406
+
407
+ // @group Invalid state
408
+ --nxe-ui-invalid: var(--nxe-ui-danger);
409
+ --nxe-ui-invalid-contrast: #2a0f0e;
410
+ --nxe-ui-invalid-faded: color-mix(in srgb, var(--nxe-ui-invalid) 40%, transparent);
411
+
412
+ // @group Focus
413
+ --nxe-ui-focus-ring: 0 0 0 2px color-mix(in srgb, var(--nxe-ui-accent) 50%, transparent);
414
+ --nxe-ui-focus-ring-color: #7fb6e6;
415
+
416
+ // @group State layers
417
+ --nxe-ui-hover-bg: rgba(255, 255, 255, 0.06);
418
+ --nxe-ui-selected-bg: rgba(255, 255, 255, 0.12);
419
+ --nxe-ui-selected-hover-bg: rgba(255, 255, 255, 0.09);
420
+ --nxe-ui-focus-selected-bg: rgba(90, 165, 222, 0.55);
421
+ --nxe-ui-focus-bg: rgba(255, 255, 255, 0.1);
422
+ --nxe-ui-active-bg: rgba(255, 255, 255, 0.2);
423
+ --nxe-ui-checkbox-active-bg: rgba(255, 255, 255, 0.18);
424
+
425
+ // @group Metrics
426
+ --nxe-ui-popup-shadow: var(--nxe-ui-shadow-md);
427
+
428
+ // @group Check box and button gap
429
+ --nxe-ui-checkbox-hover-border: var(--nxe-ui-accent-strong);
430
+
431
+ // @group Data grid
432
+ --nxe-ui-grid-row-line-color: #313a47;
433
+ --nxe-ui-grid-column-line-color: #313a47;
434
+ --nxe-ui-grid-border-color: #3a4452;
435
+ --nxe-ui-grid-header-line-color: #3a4452;
436
+ --nxe-ui-grid-alt-row-bg: #202833;
437
+ --nxe-ui-grid-group-row-color: #e9edf2;
438
+ --nxe-ui-grid-summary-color: rgba(228, 232, 238, 0.7);
439
+
440
+ // @group Neutral ramp
441
+ --nxe-ui-neutral-50: #20272f;
442
+ --nxe-ui-neutral-60: #222a33;
443
+ --nxe-ui-neutral-65: #232b34;
444
+ --nxe-ui-neutral-80: #262e38;
445
+ --nxe-ui-neutral-100: #29323d;
446
+ --nxe-ui-neutral-110: #2b3541;
447
+ --nxe-ui-neutral-120: #2e3844;
448
+ --nxe-ui-neutral-150: #333e4b;
449
+ --nxe-ui-neutral-230: #4a5462;
450
+ --nxe-ui-neutral-240: #4d5765;
451
+ --nxe-ui-neutral-250: #566170;
452
+ --nxe-ui-neutral-300: #5f6a79;
453
+ --nxe-ui-neutral-350: #6c7787;
454
+ --nxe-ui-neutral-400: #7a8595;
455
+ --nxe-ui-neutral-450: #8993a2;
456
+ --nxe-ui-neutral-500: #95a0ae;
457
+ --nxe-ui-neutral-600: #a7b1be;
458
+ --nxe-ui-neutral-600-faded: rgba(167, 177, 190, 0.5);
459
+ --nxe-ui-neutral-700: #c0c8d2;
460
+ --nxe-ui-neutral-900: #e9edf2;
461
+
462
+ // @group Overlays and scrolling
463
+ --nxe-ui-scrim: rgba(28, 35, 45, 0.6);
464
+ --nxe-ui-spinner-track: rgba(197, 205, 219, 0.25);
465
+ --nxe-ui-scrollbar-thumb: rgba(255, 255, 255, 0.4);
466
+ --nxe-ui-scroll-thumb: rgba(143, 155, 171, 0.6);
467
+ --nxe-ui-scroll-thumb-hover: rgb(143, 155, 171);
468
+
469
+ // @group Buttons
470
+ --nxe-ui-button-bg-primary: var(--nxe-ui-accent);
471
+ --nxe-ui-button-fg-primary: var(--nxe-ui-accent-contrast);
472
+ --nxe-ui-button-hover-bg-primary: #7ab9e8;
473
+ --nxe-ui-button-active-bg-primary: #9acbee;
474
+ --nxe-ui-button-bg-secondary: #2a3340;
475
+ --nxe-ui-button-fg-secondary: var(--nxe-ui-text);
476
+ --nxe-ui-button-border-secondary: var(--nxe-ui-border);
477
+ --nxe-ui-button-hover-bg-secondary: #323c4a;
478
+ --nxe-ui-button-active-bg-secondary: #3d4959;
479
+ --nxe-ui-button-bg-success: var(--nxe-ui-success);
480
+ --nxe-ui-button-fg-success: #0d1a26;
481
+ --nxe-ui-button-hover-bg-success: #7edb9d;
482
+ --nxe-ui-button-active-bg-success: #9de6b5;
483
+ --nxe-ui-button-bg-danger: var(--nxe-ui-danger);
484
+ --nxe-ui-button-fg-danger: #2a0f0e;
485
+ --nxe-ui-button-hover-bg-danger: #f58d89;
486
+ --nxe-ui-button-active-bg-danger: #f9a9a6;
487
+
488
+ // @group Status families
489
+ --nxe-ui-status-neutral-fg: #b9c4d0;
490
+ --nxe-ui-status-neutral-bg: #353d47;
491
+ --nxe-ui-status-neutral-border: #636b76;
492
+ --nxe-ui-status-info-fg: #8cc4ee;
493
+ --nxe-ui-status-info-bg: #2e3d4c;
494
+ --nxe-ui-status-info-border: #4e6b84;
495
+ --nxe-ui-status-attention-fg: #f0c36a;
496
+ --nxe-ui-status-attention-bg: #3e3d37;
497
+ --nxe-ui-status-attention-border: #7b6b48;
498
+ --nxe-ui-status-success-fg: #6fd49b;
499
+ --nxe-ui-status-success-bg: #293f3f;
500
+ --nxe-ui-status-success-border: #41735e;
501
+ --nxe-ui-status-danger-fg: #f59a94;
502
+ --nxe-ui-status-danger-bg: #3f363d;
503
+ --nxe-ui-status-danger-border: #7e595b;
504
+ --nxe-ui-status-muted-fg: #9aa6b5;
505
+ --nxe-ui-status-muted-bg: #303843;
506
+ --nxe-ui-status-muted-border: #555e6a;
507
+
508
+ // @group Chart palette
509
+ --nxe-ui-chart-1: #3987e5;
510
+ --nxe-ui-chart-2: #d95926;
511
+ --nxe-ui-chart-3: #199e70;
512
+ --nxe-ui-chart-4: #c98500;
513
+ --nxe-ui-chart-5: #d55181;
514
+ --nxe-ui-chart-6: #008300;
515
+ --nxe-ui-chart-7: #9085e9;
516
+ --nxe-ui-chart-8: #e66767;
517
+ --nxe-ui-chart-other: #95a0ae; // = neutral-500
518
+
519
+ // @group App shell
520
+ --nxe-ui-shell-sidenav-bg: #171d26;
521
+ --nxe-ui-shell-sidenav-fg: #cbd3de;
522
+ --nxe-ui-shell-sidenav-fg-muted: #8f9bab;
523
+ --nxe-ui-shell-sidenav-border: #2c3542;
524
+ --nxe-ui-shell-sidenav-hover-bg: rgba(255, 255, 255, 0.06);
525
+ --nxe-ui-shell-sidenav-active-bg: #243447;
526
+ --nxe-ui-shell-sidenav-active-fg: #9ccdf2;
527
+ --nxe-ui-shell-topbar-bg: #1c232d;
528
+ --nxe-ui-shell-topbar-fg: #e4e8ee;
529
+ --nxe-ui-shell-scrim: rgba(0, 0, 0, 0.6);
530
+ // @group Tooltip
531
+ --nxe-ui-tooltip-bg: #e4e8ee;
532
+ --nxe-ui-tooltip-fg: #161b22;
533
+
534
+
535
+ // @group Radius and elevation scale
536
+ --nxe-ui-shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.45);
537
+ --nxe-ui-shadow-md: 0 6px 12px rgba(0, 0, 0, 0.5);
538
+ --nxe-ui-shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.6);
539
+
75
540
  // slate.100 @ 12%
76
541
  --nxe-divider-color: rgba(241, 245, 249, 0.12);
77
542
  }
@@ -39,14 +39,25 @@
39
39
  }
40
40
  }
41
41
 
42
- // Deliberately NOT part of nxe-widget yet. dx also put `color` and `box-sizing` on `.dx-widget`,
43
- // but adopting `color` here would newly repaint nxe-tree-view / nxe-list / nxe-file-uploader, and
44
- // the host app renders its sidebar inside a `.dark` container. Land it only after a visual pass.
42
+ // The rest of dx.light's `.dx-widget`: its #333 text, and the touch and print settings
43
+ // (`-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:none;-webkit-touch-callout:none;
44
+ // print-color-adjust:exact`). Apps used to get these from their copy of dx.light; the visual pass
45
+ // against orbit, which had it on every widget, is what let `color` land here. Not dx's `display:
46
+ // block` or `outline:0`: each component states its own display, and the focus outline stays.
45
47
  @mixin nxe-widget-chrome {
46
48
  :where(.nxe-widget) {
47
49
  color: var(--nxe-ui-text);
50
+ -webkit-tap-highlight-color: transparent;
51
+ -webkit-text-size-adjust: none;
52
+ text-size-adjust: none;
53
+ -webkit-touch-callout: none;
54
+ print-color-adjust: exact;
48
55
  }
56
+ }
49
57
 
58
+ // dx's `.dx-widget, .dx-widget * {box-sizing:border-box}`. Not in the bundle: a host with Tailwind's
59
+ // preflight already has it, and one without may lay its own content out on content-box.
60
+ @mixin nxe-widget-box-sizing {
50
61
  .nxe-widget,
51
62
  .nxe-widget *,
52
63
  .nxe-widget ::before,
package/styles/index.scss CHANGED
@@ -10,10 +10,13 @@
10
10
  @use 'editor';
11
11
  @use 'dropdown';
12
12
  @use 'button-directives';
13
+ @use 'icons';
13
14
 
14
- // The widget base (font family/size/weight/line-height). Must come before the component chrome
15
- // below so those can override it, and it is what carries the contract across a CDK portal.
15
+ // The widget base (font family/size/weight/line-height, text colour). Must come before the
16
+ // component chrome below so those can override it, and it is what carries the contract across a
17
+ // CDK portal.
16
18
  @include widget.nxe-widget;
19
+ @include widget.nxe-widget-chrome;
17
20
 
18
21
  @include button-directives.nxe-button-directives;
19
22
 
@@ -23,6 +26,9 @@
23
26
  // Shared select-family dropdown panel (select-box, tag-box).
24
27
  @include dropdown.nxe-dropdown;
25
28
 
29
+ // The `<i class="nxe-icon nxe-icon-NAME">` glyph layer (nxe-button's `icon`).
30
+ @include icons.nxe-icons;
31
+
26
32
  // Pointer-drag chrome for NxeDragGesture, shared by the data grid's column/group drags and the
27
33
  // pivot's field-panel/chooser chip drags. Global because a page can render a pivot and NO data
28
34
  // grid (an ANALYTIC report is exactly that), and component styles only ship while an instance of
@@ -57,8 +63,8 @@ body.nxe-grid-dragging {
57
63
  height: 18px;
58
64
  padding: 0 4px;
59
65
  border-radius: 9px;
60
- background: #30374c;
61
- color: #fff;
66
+ background: var(--nxe-ui-ink-strong, #30374c);
67
+ color: var(--nxe-ui-accent-contrast, #fff);
62
68
  font-size: 10px;
63
69
  font-weight: 600;
64
70
  line-height: 1;