@dataworkz/crystal 0.1.0-beta.1 → 0.1.0-beta.10
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 +120 -0
- package/fesm2022/dataworkz-crystal-icons.mjs +1 -1
- package/fesm2022/dataworkz-crystal-icons.mjs.map +1 -1
- package/fesm2022/dataworkz-crystal-primeng.mjs +28 -2
- package/fesm2022/dataworkz-crystal-primeng.mjs.map +1 -1
- package/fesm2022/dataworkz-crystal.mjs +2555 -206
- package/fesm2022/dataworkz-crystal.mjs.map +1 -1
- package/icons/index.d.ts +4 -2
- package/index.d.ts +1125 -25
- package/package.json +5 -7
- package/primeng/index.d.ts +42 -2
- package/styles/components/button.css +3 -0
- package/styles/components/content.css +100 -0
- package/styles/components/data.css +23 -0
- package/styles/components/form.css +116 -13
- package/styles/components/navigation.css +31 -1
- package/styles/components/overlay.css +16 -1
- package/styles/components/surface.css +36 -0
- package/styles/crystal-no-fonts.css +2 -0
- package/styles/icons.css +6 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dataworkz/crystal",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.10",
|
|
4
4
|
"description": "Dataworkz core UI for Angular: dw-* components, icons, toasts, design tokens, theme CSS and bundled fonts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Dataworkz",
|
|
@@ -19,21 +19,19 @@
|
|
|
19
19
|
"@angular/forms": "^20.3.0",
|
|
20
20
|
"@angular/platform-browser": "^20.3.0",
|
|
21
21
|
"@angular/router": "^20.3.0",
|
|
22
|
-
"@primeng/themes": "^21.0.0",
|
|
23
22
|
"ngx-markdown": "^20.0.0",
|
|
24
|
-
"primeicons": "^7.0.0",
|
|
25
|
-
"primeng": "^20.4.0",
|
|
26
23
|
"rxjs": "~7.8.0"
|
|
27
24
|
},
|
|
28
25
|
"peerDependenciesMeta": {
|
|
29
|
-
"@primeng/themes": {
|
|
30
|
-
"optional": true
|
|
31
|
-
},
|
|
32
26
|
"ngx-markdown": {
|
|
33
27
|
"optional": true
|
|
34
28
|
}
|
|
35
29
|
},
|
|
36
30
|
"dependencies": {
|
|
31
|
+
"@primeng/themes": "^21.0.0",
|
|
32
|
+
"chart.js": "^4.5.1",
|
|
33
|
+
"primeicons": "^7.0.0",
|
|
34
|
+
"primeng": "~20.4.0",
|
|
37
35
|
"tslib": "^2.8.1"
|
|
38
36
|
},
|
|
39
37
|
"exports": {
|
package/primeng/index.d.ts
CHANGED
|
@@ -608,8 +608,48 @@ declare const DW_PRESET_OVERRIDES: {
|
|
|
608
608
|
/** Dataworkz PrimeNG preset: Aura retargeted to the design system. */
|
|
609
609
|
declare const DwPreset: _primeuix_themes_types.Preset<_primeuix_themes_aura_base.AuraBaseDesignTokens>;
|
|
610
610
|
|
|
611
|
-
/** PrimeNG's dark mode follows the attribute ThemeService (and provideCrystal()) put on
|
|
611
|
+
/** PrimeNG's dark mode follows the attribute ThemeService (and provideCrystal()) put on `<html>`. */
|
|
612
612
|
declare const DW_DARK_MODE_SELECTOR = "[data-theme=\"dark\"]";
|
|
613
|
+
/** Panel class that sizes a select's option list for a small trigger (components/form.css). */
|
|
614
|
+
declare const DW_SELECT_PANEL_SM = "dw-select-panel--sm";
|
|
615
|
+
type SizedInstance = {
|
|
616
|
+
size?: () => string | null | undefined;
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* Crystal's pass-through defaults: a small `p-select` / `p-multiselect` gets small options even when its list is
|
|
620
|
+
* appended to `<body>` (where CSS can't see the trigger).
|
|
621
|
+
*/
|
|
622
|
+
declare const DW_PRIMENG_PT: {
|
|
623
|
+
readonly select: {
|
|
624
|
+
readonly overlay: ({ instance }: {
|
|
625
|
+
instance?: SizedInstance;
|
|
626
|
+
}) => {
|
|
627
|
+
class: string;
|
|
628
|
+
} | {
|
|
629
|
+
class?: undefined;
|
|
630
|
+
};
|
|
631
|
+
};
|
|
632
|
+
readonly multiselect: {
|
|
633
|
+
readonly overlay: ({ instance }: {
|
|
634
|
+
instance?: SizedInstance;
|
|
635
|
+
}) => {
|
|
636
|
+
class: string;
|
|
637
|
+
} | {
|
|
638
|
+
class?: undefined;
|
|
639
|
+
};
|
|
640
|
+
};
|
|
641
|
+
};
|
|
642
|
+
/**
|
|
643
|
+
* PrimeNG's z-index bases, with tooltips raised to 5000: PrimeNG already stacks a tooltip above the overlays it manages
|
|
644
|
+
* (dialogs, drawers, popovers), and the higher base keeps it above layers that set their own z-index too (a panel or
|
|
645
|
+
* page chrome with `z-index` in CSS), so a tooltip is never hidden under what it describes.
|
|
646
|
+
*/
|
|
647
|
+
declare const DW_PRIMENG_Z_INDEX: {
|
|
648
|
+
readonly modal: 1100;
|
|
649
|
+
readonly overlay: 1000;
|
|
650
|
+
readonly menu: 1000;
|
|
651
|
+
readonly tooltip: 5000;
|
|
652
|
+
};
|
|
613
653
|
/**
|
|
614
654
|
* PrimeNG with the Dataworkz preset, dark mode on `[data-theme="dark"]`. Pass app-specific PrimeNG settings
|
|
615
655
|
* (ripple, zIndex, translation…) as `config`; its `theme.options` are merged over crystal's.
|
|
@@ -620,4 +660,4 @@ declare const DW_DARK_MODE_SELECTOR = "[data-theme=\"dark\"]";
|
|
|
620
660
|
*/
|
|
621
661
|
declare function provideCrystalPrimeNG(config?: PrimeNGConfigType): EnvironmentProviders;
|
|
622
662
|
|
|
623
|
-
export { AZURE_PRIMARY_RAMP, DW_COLOR_SCHEME, DW_DARK_MODE_SELECTOR, DW_PRESET_OVERRIDES, DwPreset, provideCrystalPrimeNG };
|
|
663
|
+
export { AZURE_PRIMARY_RAMP, DW_COLOR_SCHEME, DW_DARK_MODE_SELECTOR, DW_PRESET_OVERRIDES, DW_PRIMENG_PT, DW_PRIMENG_Z_INDEX, DW_SELECT_PANEL_SM, DwPreset, provideCrystalPrimeNG };
|
|
@@ -325,6 +325,9 @@
|
|
|
325
325
|
.dw-icon-btn.is-active { background: var(--dw-accent-tint); color: var(--dw-accent); }
|
|
326
326
|
/* Hovering the active (selected) button keeps it accented, a step stronger */
|
|
327
327
|
.dw-icon-btn.is-active:hover:not(:disabled) { background: var(--dw-accent-tint-strong); color: var(--dw-accent); }
|
|
328
|
+
/* A selected danger toggle (e.g. a "not helpful" rating) keeps its danger colour instead of the accent. */
|
|
329
|
+
.dw-icon-btn--danger.is-active,
|
|
330
|
+
.dw-icon-btn--danger.is-active:hover:not(:disabled) { background: var(--dw-danger-tint); color: var(--dw-danger-solid); }
|
|
328
331
|
.dw-icon-btn--inverse { color: var(--dw-text-muted); }
|
|
329
332
|
.dw-icon-btn--inverse:hover:not(:disabled),
|
|
330
333
|
.dw-icon-btn--inverse.is-active { background: color-mix(in srgb, var(--dw-text-inverse) 12%, transparent); color: var(--dw-text-inverse); }
|
|
@@ -156,3 +156,103 @@ dw-markdown.dw-prose { display: block; }
|
|
|
156
156
|
/* ── dw-icon: app SVG glyphs, drawn in currentColor at the text size ── */
|
|
157
157
|
.dw-icon { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; line-height: 0; vertical-align: -0.125em; }
|
|
158
158
|
.dw-icon svg { display: block; }
|
|
159
|
+
/* A PrimeIcons glyph (dw-icon pi="…") is a font glyph: it needs a line box, which the SVG case sets to 0. */
|
|
160
|
+
.dw-icon.pi { line-height: 1; }
|
|
161
|
+
.dw-icon--spin { animation: dw-icon-spin 1s linear infinite; }
|
|
162
|
+
@keyframes dw-icon-spin { to { transform: rotate(360deg); } }
|
|
163
|
+
@media (prefers-reduced-motion: reduce) { .dw-icon--spin, .dw-icon.pi-spin { animation-duration: 3s; } }
|
|
164
|
+
|
|
165
|
+
/* ── dw-accordion: panels that open and close under a header row (PrimeNG's p-accordion underneath) ──
|
|
166
|
+
PrimeNG reads its accordion design tokens as --p-accordion-* variables, so the look is set through them (no
|
|
167
|
+
specificity race with its own :hover / :first-child rules). flush (default): rows on the container, a divider
|
|
168
|
+
between panels; card: each panel a bordered card, the list spaced, a divider under an open header. */
|
|
169
|
+
.dw-accordion {
|
|
170
|
+
display: block;
|
|
171
|
+
min-width: 0;
|
|
172
|
+
--p-accordion-panel-border-width: 0;
|
|
173
|
+
--p-accordion-panel-border-color: var(--dw-border);
|
|
174
|
+
--p-accordion-header-padding: var(--dw-space-3) var(--dw-space-4);
|
|
175
|
+
--p-accordion-header-font-weight: var(--dw-font-weight-semibold);
|
|
176
|
+
--p-accordion-header-color: var(--dw-text-strong);
|
|
177
|
+
--p-accordion-header-hover-color: var(--dw-text-strong);
|
|
178
|
+
--p-accordion-header-active-color: var(--dw-text-strong);
|
|
179
|
+
--p-accordion-header-active-hover-color: var(--dw-text-strong);
|
|
180
|
+
--p-accordion-header-background: transparent;
|
|
181
|
+
--p-accordion-header-hover-background: var(--dw-surface-hover);
|
|
182
|
+
--p-accordion-header-active-background: transparent;
|
|
183
|
+
--p-accordion-header-active-hover-background: var(--dw-surface-hover);
|
|
184
|
+
--p-accordion-header-border-width: 0;
|
|
185
|
+
--p-accordion-header-border-color: var(--dw-border);
|
|
186
|
+
--p-accordion-header-border-radius: 0;
|
|
187
|
+
--p-accordion-header-first-border-width: 0;
|
|
188
|
+
--p-accordion-header-first-top-border-radius: 0;
|
|
189
|
+
--p-accordion-header-last-bottom-border-radius: 0;
|
|
190
|
+
--p-accordion-header-last-active-bottom-border-radius: 0;
|
|
191
|
+
--p-accordion-header-focus-ring-width: 0;
|
|
192
|
+
--p-accordion-header-focus-ring-shadow: inset var(--dw-focus-ring);
|
|
193
|
+
--p-accordion-content-background: transparent;
|
|
194
|
+
--p-accordion-content-color: var(--dw-text);
|
|
195
|
+
--p-accordion-content-padding: 0 var(--dw-space-4) var(--dw-space-4);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.dw-accordion .p-accordionheader {
|
|
199
|
+
gap: var(--dw-space-3);
|
|
200
|
+
font-size: var(--dw-font-size-14);
|
|
201
|
+
line-height: 1.4;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.dw-accordion__header {
|
|
205
|
+
display: flex;
|
|
206
|
+
flex: 1 1 auto;
|
|
207
|
+
align-items: center;
|
|
208
|
+
gap: var(--dw-space-2);
|
|
209
|
+
min-width: 0;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.dw-accordion__title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
213
|
+
|
|
214
|
+
.dw-accordion__chevron {
|
|
215
|
+
flex: none;
|
|
216
|
+
font-size: var(--dw-font-size-12);
|
|
217
|
+
color: var(--dw-text-secondary);
|
|
218
|
+
transition: transform var(--dw-dur-enter) var(--dw-ease);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.dw-accordion .p-accordionpanel-active > .p-accordionheader .dw-accordion__chevron { transform: rotate(180deg); }
|
|
222
|
+
.dw-accordion .p-accordionpanel.p-disabled > .p-accordionheader { cursor: default; }
|
|
223
|
+
|
|
224
|
+
/* flush: a divider between panels */
|
|
225
|
+
.dw-accordion--flush .p-accordionpanel + .p-accordionpanel { --p-accordion-panel-border-width: 1px 0 0; }
|
|
226
|
+
|
|
227
|
+
/* card: each panel its own card; a closed one lifts on hover, an open one divides its header from its content */
|
|
228
|
+
.dw-accordion--card {
|
|
229
|
+
--p-accordion-header-hover-background: transparent;
|
|
230
|
+
--p-accordion-header-active-hover-background: transparent;
|
|
231
|
+
--p-accordion-header-border-radius: calc(var(--dw-radius-card) - 1px);
|
|
232
|
+
--p-accordion-header-first-top-border-radius: calc(var(--dw-radius-card) - 1px);
|
|
233
|
+
--p-accordion-header-last-bottom-border-radius: calc(var(--dw-radius-card) - 1px);
|
|
234
|
+
--p-accordion-content-padding: var(--dw-space-4);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.dw-accordion--card > .p-accordion { display: flex; flex-direction: column; gap: var(--dw-space-2); }
|
|
238
|
+
|
|
239
|
+
.dw-accordion--card .p-accordionpanel {
|
|
240
|
+
border: 1px solid var(--dw-border);
|
|
241
|
+
border-radius: var(--dw-radius-card);
|
|
242
|
+
background: var(--dw-surface);
|
|
243
|
+
transition: box-shadow var(--dw-dur-enter) var(--dw-ease);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.dw-accordion--card .p-accordionpanel:not(.p-accordionpanel-active):not(.p-disabled):hover { box-shadow: var(--dw-shadow-md); }
|
|
247
|
+
|
|
248
|
+
.dw-accordion--card .p-accordionpanel-active {
|
|
249
|
+
--p-accordion-header-border-width: 0 0 1px;
|
|
250
|
+
--p-accordion-header-first-border-width: 0 0 1px;
|
|
251
|
+
--p-accordion-header-border-radius: calc(var(--dw-radius-card) - 1px) calc(var(--dw-radius-card) - 1px) 0 0;
|
|
252
|
+
--p-accordion-header-last-active-bottom-border-radius: 0;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
@media (prefers-reduced-motion: reduce) {
|
|
256
|
+
.dw-accordion__chevron,
|
|
257
|
+
.dw-accordion--card .p-accordionpanel { transition: none; }
|
|
258
|
+
}
|
|
@@ -138,6 +138,29 @@ body .p-treetable .p-treetable-tbody > tr.p-treetable-row-selected {
|
|
|
138
138
|
border-left: 1px solid var(--dw-tree-spine);
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/* dw-tree: no box of its own (it sits on its container); --framed draws one. Node content fills the row, so a
|
|
142
|
+
dwTreeNode template can lay out across it. */
|
|
143
|
+
.dw-tree-view { display: block; min-width: 0; }
|
|
144
|
+
.dw-tree-view > .p-tree { padding: 0; border: 0; border-radius: 0; background: transparent; }
|
|
145
|
+
.dw-tree-view.dw-tree-view--framed > .p-tree {
|
|
146
|
+
padding: var(--dw-space-2);
|
|
147
|
+
border: 1px solid var(--dw-border-strong);
|
|
148
|
+
border-radius: var(--dw-radius-control);
|
|
149
|
+
background: var(--dw-surface);
|
|
150
|
+
}
|
|
151
|
+
.dw-tree-view .p-tree-node-label { flex: 1 1 auto; min-width: 0; }
|
|
152
|
+
/* --sm: compact rows, through PrimeNG's own tree variables (row ~28px instead of ~36px). */
|
|
153
|
+
.dw-tree-view.dw-tree-view--sm {
|
|
154
|
+
--p-tree-node-padding: var(--dw-space-1) var(--dw-space-2);
|
|
155
|
+
--p-tree-node-gap: var(--dw-space-1);
|
|
156
|
+
--p-tree-node-toggle-button-size: var(--dw-space-5);
|
|
157
|
+
--p-tree-gap: 0;
|
|
158
|
+
font-size: var(--dw-font-size-13);
|
|
159
|
+
}
|
|
160
|
+
/* --marker: the selected row's accent bar, as dw-nav-list [marker] (an inset shadow, so nothing shifts). Specific
|
|
161
|
+
enough to outlast PrimeNG's focus styles, which it loads after crystal. */
|
|
162
|
+
.dw-tree-view.dw-tree-view--marker .p-tree-node-content.p-tree-node-selected { box-shadow: inset 3px 0 0 var(--dw-accent); }
|
|
163
|
+
|
|
141
164
|
/* ── Skeleton ── */
|
|
142
165
|
.dw-skeleton {
|
|
143
166
|
height: 20px;
|
|
@@ -225,14 +225,15 @@ dw-field.dw-field--inline:has(.dw-field__control :is(.p-inputtext-sm, .p-textare
|
|
|
225
225
|
.dw-field__control > :first-child:not([dwFieldSuffix]) { flex: 1 1 auto; min-width: 0; }
|
|
226
226
|
/* Switches, checkboxes and radios keep their own size — stretching one turns a toggle into a bar. */
|
|
227
227
|
/* (Same specificity as the stretch rule above, plus the element, so it wins.) */
|
|
228
|
-
.dw-field__control > :is(p-toggleswitch, p-checkbox, p-radiobutton):first-child:not([dwFieldSuffix]) { flex: none; }
|
|
228
|
+
.dw-field__control > :is(p-toggleswitch, p-checkbox, p-radiobutton, dw-switch, dw-checkbox, dw-radio):first-child:not([dwFieldSuffix]) { flex: none; }
|
|
229
229
|
.dw-field__control > input,
|
|
230
230
|
.dw-field__control > textarea,
|
|
231
231
|
.dw-field__control > p-select,
|
|
232
232
|
.dw-field__control > p-multiselect,
|
|
233
233
|
.dw-field__control > p-inputnumber,
|
|
234
234
|
.dw-field__control > p-datepicker,
|
|
235
|
-
.dw-field__control > p-autocomplete
|
|
235
|
+
.dw-field__control > p-autocomplete,
|
|
236
|
+
.dw-field__control > :is(dw-select, dw-multiselect, dw-number-input, dw-date-picker, dw-autocomplete, dw-slider) { width: 100%; }
|
|
236
237
|
.dw-field__error { display: inline-flex; align-items: center; gap: var(--dw-space-1); }
|
|
237
238
|
/* Field errors are text only (the red text and border carry the state): no leading icon, even in
|
|
238
239
|
hand-written error lines. */
|
|
@@ -391,12 +392,6 @@ dw-search-input.dw-search--block { width: 100%; }
|
|
|
391
392
|
display: none;
|
|
392
393
|
}
|
|
393
394
|
|
|
394
|
-
/* PrimeNG's slider host is inline; give it the field's width. */
|
|
395
|
-
p-slider {
|
|
396
|
-
display: block;
|
|
397
|
-
width: 100%;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
395
|
/* pSize="small" inputs: base.css's `font: inherit` would keep them at 14px, so restate the
|
|
401
396
|
small type here — 5px padding + 16px line + 1px borders = 28px, the small dw-button height. */
|
|
402
397
|
/* Small selects match small inputs exactly (28px): their label gets the same 16px line
|
|
@@ -470,12 +465,14 @@ p-slider {
|
|
|
470
465
|
|
|
471
466
|
|
|
472
467
|
/* Small selects (size="small"): their option list matches the 12px trigger instead of the default
|
|
473
|
-
14px rows.
|
|
474
|
-
|
|
468
|
+
14px rows. A list rendered inside the select matches `.p-select-sm`; a list appended elsewhere
|
|
469
|
+
(appendTo="body") gets `dw-select-panel--sm` from provideCrystalPrimeNG()'s pass-through, so no
|
|
470
|
+
screen sets it by hand. */
|
|
475
471
|
.p-select-sm .p-select-option,
|
|
476
472
|
.p-multiselect-sm .p-multiselect-option,
|
|
477
473
|
.dw-select-panel--sm .p-select-option,
|
|
478
|
-
.dw-select-panel--sm .p-multiselect-option
|
|
474
|
+
.dw-select-panel--sm .p-multiselect-option,
|
|
475
|
+
.dw-autocomplete-panel--sm .p-autocomplete-option {
|
|
479
476
|
padding: 5px 10px;
|
|
480
477
|
font-size: var(--dw-font-size-12);
|
|
481
478
|
line-height: var(--dw-line-height-16);
|
|
@@ -483,7 +480,8 @@ p-slider {
|
|
|
483
480
|
.p-select-sm .p-select-empty-message,
|
|
484
481
|
.p-multiselect-sm .p-multiselect-empty-message,
|
|
485
482
|
.dw-select-panel--sm .p-select-empty-message,
|
|
486
|
-
.dw-select-panel--sm .p-multiselect-empty-message
|
|
483
|
+
.dw-select-panel--sm .p-multiselect-empty-message,
|
|
484
|
+
.dw-autocomplete-panel--sm .p-autocomplete-empty-message {
|
|
487
485
|
padding: 5px 10px;
|
|
488
486
|
font-size: var(--dw-font-size-12);
|
|
489
487
|
}
|
|
@@ -635,7 +633,7 @@ body .dw-var-field .p-textarea {
|
|
|
635
633
|
.dw-check-toggle.is-on .dw-check-toggle__label { color: var(--dw-text-strong); font-weight: var(--dw-font-weight-medium); }
|
|
636
634
|
|
|
637
635
|
/* Compact calendar (inline in popovers): smaller day cells and type, quieter weekday row and a
|
|
638
|
-
tighter time picker. <
|
|
636
|
+
tighter time picker. <dw-date-picker [compact]="true" [inline]="true" />.
|
|
639
637
|
Two classes per rule so they outrank PrimeNG's own (unlayered) datepicker styles. */
|
|
640
638
|
.dw-datepicker--compact .p-datepicker-header { padding: 0 0 var(--dw-space-2); }
|
|
641
639
|
.dw-datepicker--compact .p-datepicker-title,
|
|
@@ -675,3 +673,108 @@ body .dw-var-field .p-textarea {
|
|
|
675
673
|
.config-form-body .toggle-label { margin: 0; cursor: pointer; }
|
|
676
674
|
/* Host of a config form component inside .config-drawer-body: fill the drawer height. */
|
|
677
675
|
.config-form-host { display: flex; flex: 1; flex-direction: column; min-height: 0; }
|
|
676
|
+
|
|
677
|
+
/* ── dw-select / dw-multiselect (components) ──
|
|
678
|
+
The host takes the screen's sizing (a width, `dw-w-full`, a grid track) and the PrimeNG control fills it; with no
|
|
679
|
+
width set, the host is as wide as the control would be on its own. */
|
|
680
|
+
.dw-select,
|
|
681
|
+
.dw-multiselect {
|
|
682
|
+
display: inline-flex;
|
|
683
|
+
min-width: 0;
|
|
684
|
+
max-width: 100%;
|
|
685
|
+
vertical-align: middle;
|
|
686
|
+
}
|
|
687
|
+
.dw-select > p-select,
|
|
688
|
+
.dw-multiselect > p-multiselect {
|
|
689
|
+
flex: 1 1 auto;
|
|
690
|
+
min-width: 0;
|
|
691
|
+
}
|
|
692
|
+
.dw-select.dw-select--fluid,
|
|
693
|
+
.dw-multiselect.dw-multiselect--fluid {
|
|
694
|
+
display: flex;
|
|
695
|
+
width: 100%;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/* ── dw-checkbox / dw-radio / dw-switch (components): the control and its label on one line (dw-check) ── */
|
|
699
|
+
.dw-checkbox__label--empty:empty,
|
|
700
|
+
.dw-radio__label--empty:empty { display: none; }
|
|
701
|
+
|
|
702
|
+
/* ── dw-number-input (component): sized by the screen like dw-select ── */
|
|
703
|
+
.dw-number-input { display: inline-flex; min-width: 0; max-width: 100%; vertical-align: middle; }
|
|
704
|
+
.dw-number-input > p-inputnumber { flex: 1 1 auto; min-width: 0; }
|
|
705
|
+
.dw-number-input.dw-number-input--fluid { display: flex; width: 100%; }
|
|
706
|
+
|
|
707
|
+
/* ── dw-date-picker (component): sized by the screen like dw-select; the inline calendar keeps its own width unless fluid ── */
|
|
708
|
+
.dw-date-picker { display: inline-flex; min-width: 0; max-width: 100%; vertical-align: middle; }
|
|
709
|
+
.dw-date-picker > p-datepicker { flex: 1 1 auto; min-width: 0; }
|
|
710
|
+
.dw-date-picker.dw-date-picker--fluid { display: flex; width: 100%; }
|
|
711
|
+
.dw-date-picker.dw-date-picker--inline > p-datepicker { flex: none; }
|
|
712
|
+
.dw-date-picker.dw-date-picker--inline.dw-date-picker--fluid > p-datepicker { flex: 1 1 auto; }
|
|
713
|
+
/* flush: the inline calendar loses its own box and sits on its container's surface (a popover or a panel pads it). */
|
|
714
|
+
.dw-date-picker.dw-date-picker--flush .p-datepicker-panel-inline {
|
|
715
|
+
padding: 0;
|
|
716
|
+
border: 0;
|
|
717
|
+
border-radius: 0;
|
|
718
|
+
background: transparent;
|
|
719
|
+
box-shadow: none;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/* ── dw-autocomplete (component): sized by the screen like dw-select; the text input fills it ──
|
|
723
|
+
(The extra elements outweigh PrimeNG's `width: 1%` on the input beside a dropdown button, whose styles load after ours.) */
|
|
724
|
+
.dw-autocomplete { display: inline-flex; min-width: 0; max-width: 100%; vertical-align: middle; }
|
|
725
|
+
.dw-autocomplete > p-autocomplete { display: flex; flex: 1 1 auto; min-width: 0; }
|
|
726
|
+
.dw-autocomplete > p-autocomplete.p-autocomplete > input.p-autocomplete-input { flex: 1 1 auto; width: auto; min-width: 0; }
|
|
727
|
+
.dw-autocomplete.dw-autocomplete--fluid { display: flex; width: 100%; }
|
|
728
|
+
/* Its list (appended to <body>, so styled by its panel classes): rows in the 14px body type, unless small. */
|
|
729
|
+
body .dw-autocomplete-panel:not(.dw-autocomplete-panel--sm) :is(.p-autocomplete-option, .p-autocomplete-empty-message) {
|
|
730
|
+
font-size: var(--dw-font-size-14);
|
|
731
|
+
}
|
|
732
|
+
/* panelWidth="field": exactly as wide as the field, as select lists are (see above): PrimeNG puts the field's width in
|
|
733
|
+
the overlay's inline min-width, a zero width lets it win, and long suggestions ellipsise. */
|
|
734
|
+
.p-overlay:has(> .p-overlay-content > .dw-autocomplete-panel--field) { width: 0; }
|
|
735
|
+
.dw-autocomplete-panel--field .p-autocomplete-option > * {
|
|
736
|
+
min-width: 0;
|
|
737
|
+
overflow: hidden;
|
|
738
|
+
text-overflow: ellipsis;
|
|
739
|
+
}
|
|
740
|
+
/* size="sm" gives it the small select rows (`.dw-autocomplete-panel--sm`, with the small select lists above). */
|
|
741
|
+
|
|
742
|
+
/* ── dw-slider (component): fills its container, in crystal's tokens ──
|
|
743
|
+
A 4px track in the meter's colours (dw-meter) and a 16px accent handle with a surface centre; the padding keeps the
|
|
744
|
+
handle clear of what sits above and below. PrimeNG draws it from these variables. */
|
|
745
|
+
.dw-slider {
|
|
746
|
+
--p-slider-track-size: 4px;
|
|
747
|
+
--p-slider-track-background: var(--dw-surface-pressed);
|
|
748
|
+
--p-slider-track-border-radius: var(--dw-radius-full);
|
|
749
|
+
--p-slider-range-background: var(--dw-accent);
|
|
750
|
+
--p-slider-handle-width: 16px;
|
|
751
|
+
--p-slider-handle-height: 16px;
|
|
752
|
+
--p-slider-handle-border-radius: var(--dw-radius-full);
|
|
753
|
+
--p-slider-handle-background: var(--dw-accent);
|
|
754
|
+
--p-slider-handle-hover-background: var(--dw-accent-hover);
|
|
755
|
+
--p-slider-handle-content-width: 8px;
|
|
756
|
+
--p-slider-handle-content-height: 8px;
|
|
757
|
+
--p-slider-handle-content-border-radius: var(--dw-radius-full);
|
|
758
|
+
--p-slider-handle-content-background: var(--dw-surface);
|
|
759
|
+
--p-slider-handle-content-hover-background: var(--dw-surface);
|
|
760
|
+
--p-slider-handle-content-shadow: none;
|
|
761
|
+
--p-slider-handle-focus-ring-width: 0;
|
|
762
|
+
--p-slider-handle-focus-ring-shadow: var(--dw-focus-ring);
|
|
763
|
+
|
|
764
|
+
display: block;
|
|
765
|
+
width: 100%;
|
|
766
|
+
padding-block: var(--dw-space-2);
|
|
767
|
+
}
|
|
768
|
+
/* PrimeNG shows a grab cursor on the handle; show it grabbing while held. */
|
|
769
|
+
.dw-slider .p-slider-handle:active { cursor: grabbing; }
|
|
770
|
+
.dw-slider.dw-slider--invalid {
|
|
771
|
+
--p-slider-range-background: var(--dw-danger-solid);
|
|
772
|
+
--p-slider-handle-background: var(--dw-danger-solid);
|
|
773
|
+
--p-slider-handle-hover-background: var(--dw-danger-solid);
|
|
774
|
+
--p-slider-handle-focus-ring-shadow: var(--dw-focus-ring-danger);
|
|
775
|
+
}
|
|
776
|
+
.dw-slider.dw-slider--vertical { display: inline-block; width: auto; height: 100%; padding-block: 0; padding-inline: var(--dw-space-2); }
|
|
777
|
+
.dw-slider.dw-slider--vertical > p-slider { height: 100%; }
|
|
778
|
+
/* p-slider used directly (until its screens move to dw-slider): a block as wide as its field. */
|
|
779
|
+
p-slider { display: block; width: 100%; }
|
|
780
|
+
.dw-slider--vertical > p-slider { width: var(--p-slider-track-size); }
|
|
@@ -215,7 +215,7 @@
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
/* Selected marker: an accent left border that follows the item's rounded corners. Only the agents
|
|
218
|
-
list page's sidebar has it (dw-nav-list [marker], and its tags tree: dw-
|
|
218
|
+
list page's sidebar has it (dw-nav-list [marker], and its tags tree: dw-tree [marker]); every
|
|
219
219
|
other selection is the plain selected fill. An inset shadow, not a border, so the item's content
|
|
220
220
|
does not shift when it is selected. */
|
|
221
221
|
.dw-nav-list--marker .dw-nav-item.is-active,
|
|
@@ -547,6 +547,36 @@ dw-nav-list.dw-nav-list--minimizable { overflow: hidden; padding-bottom: 0; }
|
|
|
547
547
|
.dw-steps__item.is-done .dw-steps__no { border-color: var(--dw-accent); background: var(--dw-accent); color: var(--dw-text-inverse); }
|
|
548
548
|
.dw-steps__sep { flex: 0 0 48px; height: 1px; background: var(--dw-border-strong); }
|
|
549
549
|
|
|
550
|
+
/* ── dw-stepper: the component over .dw-steps. Each step is a button; a done step goes back,
|
|
551
|
+
an upcoming step of a linear stepper is disabled but drawn as upcoming (not faded).
|
|
552
|
+
--inline drops the sub-header strip (a wizard header); --md is the wizard size, --sm the strip above. ── */
|
|
553
|
+
.dw-stepper { display: block; min-width: 0; }
|
|
554
|
+
.dw-steps--inline { padding: 0; border-bottom: 0; }
|
|
555
|
+
.dw-steps__btn {
|
|
556
|
+
display: inline-flex;
|
|
557
|
+
align-items: center;
|
|
558
|
+
gap: var(--dw-space-2);
|
|
559
|
+
margin: calc(-1 * var(--dw-space-1));
|
|
560
|
+
padding: var(--dw-space-1);
|
|
561
|
+
border: 0;
|
|
562
|
+
border-radius: var(--dw-radius-md);
|
|
563
|
+
background: transparent;
|
|
564
|
+
color: inherit;
|
|
565
|
+
font-weight: inherit;
|
|
566
|
+
white-space: nowrap;
|
|
567
|
+
transition: color var(--dw-dur-micro) var(--dw-ease);
|
|
568
|
+
}
|
|
569
|
+
.dw-steps__btn:disabled,
|
|
570
|
+
.dw-steps__btn[aria-current='step'] { cursor: default; }
|
|
571
|
+
.dw-steps__btn:not(:disabled, [aria-current='step']):hover { color: var(--dw-text-link); }
|
|
572
|
+
.dw-steps__btn:focus-visible { outline: none; box-shadow: var(--dw-focus-ring); }
|
|
573
|
+
.dw-steps__no { flex: none; transition: background-color var(--dw-dur-micro) var(--dw-ease), border-color var(--dw-dur-micro) var(--dw-ease); }
|
|
574
|
+
.dw-steps__item.is-disabled { opacity: 0.5; }
|
|
575
|
+
.dw-steps__item.is-disabled .dw-steps__btn { cursor: not-allowed; }
|
|
576
|
+
.dw-steps__sep.is-done { background: var(--dw-accent); }
|
|
577
|
+
.dw-steps--md .dw-steps__no { width: 32px; height: 32px; border-width: 2px; font-size: var(--dw-font-size-14); }
|
|
578
|
+
.dw-steps--md .dw-steps__sep { height: 2px; }
|
|
579
|
+
|
|
550
580
|
/* ── dw-rail-tabs: vertical icon-over-label tab strip at a panel edge ── */
|
|
551
581
|
.dw-rail-tabs { display: flex; flex-shrink: 0; width: 64px; }
|
|
552
582
|
.dw-rail-tabs__nav {
|
|
@@ -339,9 +339,24 @@ body .p-drawer-right {
|
|
|
339
339
|
}
|
|
340
340
|
.p-tooltip.dw-tooltip--multiline .p-tooltip-text { white-space: pre-line; }
|
|
341
341
|
.p-tooltip.dw-tooltip--error .p-tooltip-text { background: var(--dw-status-danger-fg); color: var(--dw-text-inverse); }
|
|
342
|
+
/* Preview (dwTooltipVariant="preview"): a long value shown whole, up to 720 × 340px, then scrolled; line breaks kept,
|
|
343
|
+
long tokens broken anywhere. Pair it with dwTooltipInteractive so the pointer can scroll it. */
|
|
344
|
+
.p-tooltip.dw-tooltip--preview { width: auto; max-width: min(720px, 68vw); }
|
|
345
|
+
.p-tooltip.dw-tooltip--preview .p-tooltip-text {
|
|
346
|
+
display: inline-block;
|
|
347
|
+
box-sizing: border-box;
|
|
348
|
+
width: max-content;
|
|
349
|
+
max-width: min(720px, 68vw);
|
|
350
|
+
max-height: min(42vh, 340px);
|
|
351
|
+
overflow: auto;
|
|
352
|
+
white-space: pre-wrap;
|
|
353
|
+
overflow-wrap: anywhere;
|
|
354
|
+
font-size: var(--dw-font-size-12);
|
|
355
|
+
line-height: 1.45;
|
|
356
|
+
}
|
|
342
357
|
.p-tooltip.dw-tooltip--error .p-tooltip-arrow { border-top-color: var(--dw-status-danger-fg); }
|
|
343
358
|
/* Long code / JSON: wide, scrollable, monospace, wrapped. */
|
|
344
|
-
.p-tooltip.dw-tooltip--code { width: min(520px, calc(100vw - 48px)); max-width: min(520px, calc(100vw - 48px));
|
|
359
|
+
.p-tooltip.dw-tooltip--code { width: min(520px, calc(100vw - 48px)); max-width: min(520px, calc(100vw - 48px)); }
|
|
345
360
|
.p-tooltip.dw-tooltip--code .p-tooltip-text {
|
|
346
361
|
display: block;
|
|
347
362
|
width: 100%;
|
|
@@ -703,3 +703,39 @@ div.dw-section__header { cursor: default; }
|
|
|
703
703
|
.p-splitter.dw-splitter--rail-start > .p-splitter-gutter {
|
|
704
704
|
background: linear-gradient(to right, var(--dw-surface-rail) 50%, transparent 50%);
|
|
705
705
|
}
|
|
706
|
+
|
|
707
|
+
/* ── dw-splitter (the component): the same flat panes and hairline gutter, the gutter holding a
|
|
708
|
+
dw-resizer. The pane sizes are flex-grow ratios set by the component; the handle is a zero-size
|
|
709
|
+
anchor at the gutter's centre that the resizer's 10px hit strip straddles. The resizer's own line
|
|
710
|
+
and grip are hidden: the hairline is the gutter's. ── */
|
|
711
|
+
.dw-splitter--horizontal,
|
|
712
|
+
.dw-splitter--vertical { display: flex; height: 100%; min-width: 0; min-height: 0; }
|
|
713
|
+
.dw-splitter--horizontal { flex-direction: row; }
|
|
714
|
+
.dw-splitter--vertical { flex-direction: column; }
|
|
715
|
+
.dw-splitter__pane { display: flex; flex: 1 1 0; min-width: 0; min-height: 0; overflow: hidden; }
|
|
716
|
+
.dw-splitter__pane > * { flex: 1 1 auto; height: 100%; min-width: 0; min-height: 0; }
|
|
717
|
+
.dw-splitter__gutter { position: relative; flex: 0 0 auto; background: transparent; }
|
|
718
|
+
.dw-splitter--horizontal > .dw-splitter__gutter { cursor: col-resize; }
|
|
719
|
+
.dw-splitter--vertical > .dw-splitter__gutter { cursor: row-resize; }
|
|
720
|
+
.dw-splitter__gutter::before {
|
|
721
|
+
content: '';
|
|
722
|
+
position: absolute;
|
|
723
|
+
background: var(--dw-border);
|
|
724
|
+
transition: background var(--dw-dur-micro) var(--dw-ease);
|
|
725
|
+
}
|
|
726
|
+
.dw-splitter--horizontal > .dw-splitter__gutter::before { top: 0; bottom: 0; left: 50%; width: 1px; transform: translateX(-50%); }
|
|
727
|
+
.dw-splitter--vertical > .dw-splitter__gutter::before { top: 50%; right: 0; left: 0; height: 1px; transform: translateY(-50%); }
|
|
728
|
+
.dw-splitter--horizontal > .dw-splitter__gutter:is(:hover, .is-dragging, :has(.dw-resizer:focus-visible))::before { width: 2px; background: var(--dw-accent); }
|
|
729
|
+
.dw-splitter--vertical > .dw-splitter__gutter:is(:hover, .is-dragging, :has(.dw-resizer:focus-visible))::before { height: 2px; background: var(--dw-accent); }
|
|
730
|
+
.dw-splitter__handle { position: absolute; }
|
|
731
|
+
.dw-splitter--horizontal > .dw-splitter__gutter > .dw-splitter__handle { top: 0; bottom: 0; left: 50%; width: 0; }
|
|
732
|
+
.dw-splitter--vertical > .dw-splitter__gutter > .dw-splitter__handle { top: 50%; right: 0; left: 0; height: 0; }
|
|
733
|
+
.dw-splitter__handle > .dw-resizer::before,
|
|
734
|
+
.dw-splitter__handle > .dw-resizer::after { display: none; }
|
|
735
|
+
.dw-splitter.is-resizing { user-select: none; }
|
|
736
|
+
.dw-splitter--rail-start.dw-splitter--horizontal > .dw-splitter__gutter {
|
|
737
|
+
background: linear-gradient(to right, var(--dw-surface-rail) 50%, transparent 50%);
|
|
738
|
+
}
|
|
739
|
+
.dw-splitter--rail-start.dw-splitter--vertical > .dw-splitter__gutter {
|
|
740
|
+
background: linear-gradient(to bottom, var(--dw-surface-rail) 50%, transparent 50%);
|
|
741
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Rules: colours only in tokens/primitives.css (everything else uses semantic tokens); font-family only in base.css.
|
|
6
6
|
*/
|
|
7
|
+
/* PrimeIcons (pi pi-*): crystal's dependency, so an app never installs or loads it itself. Its font is local. */
|
|
8
|
+
@import './icons.css';
|
|
7
9
|
@import './tokens/primitives.css';
|
|
8
10
|
@import './tokens/semantic.css';
|
|
9
11
|
@import './tokens/semantic-dark.css';
|
package/styles/icons.css
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @dataworkz/crystal — the PrimeIcons font (`pi pi-*`, `<dw-icon pi>`), shipped as @dataworkz/crystal/styles/icons.css.
|
|
3
|
+
* Crystal depends on primeicons, so an app never installs or loads it itself: crystal.css / crystal-no-fonts.css import
|
|
4
|
+
* this file; an app that imports crystal's styles file by file imports it too. The font files are local (no CDN).
|
|
5
|
+
*/
|
|
6
|
+
@import 'primeicons/primeicons.css';
|