@webority/theme 0.14.0 → 0.15.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/README.md +2 -2
- package/dist/purge-safelist.json +19 -0
- package/dist/webority-theme.css +1 -1
- package/package.json +1 -1
- package/scss/_wui-components.scss +2 -0
- package/scss/wui/_command-palette.scss +195 -0
- package/scss/wui/_display.scss +49 -4
- package/scss/wui/_overlays.scss +7 -7
- package/scss/wui/_shell.scss +8 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Webority shared design system — Bootstrap 5.3 SCSS overrides, --wui-* tokens, and shared component CSS. The single source of brand chrome for React portals and Razor sites.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"publishConfig": {
|
|
@@ -51,5 +51,7 @@
|
|
|
51
51
|
@import "wui/dock";
|
|
52
52
|
@import "wui/consent-banner";
|
|
53
53
|
@import "wui/toolbar";
|
|
54
|
+
// After `overlays`: anchors the shared modal shell to the top when it holds the palette card.
|
|
55
|
+
@import "wui/command-palette";
|
|
54
56
|
// Last: restates the settled state of menus other partials style, so it must win.
|
|
55
57
|
@import "wui/menu-motion";
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// ── Command palette ──
|
|
2
|
+
// AppCommandPalette / <app-command-palette> / <wui-command-palette>: app-wide "search and jump".
|
|
3
|
+
// The overlay is the shared modal (.wui-modal-shell, .wui-modal), with .wui-cmd-card on the
|
|
4
|
+
// card; this partial styles only what sits inside it, plus the top anchoring. The element marks
|
|
5
|
+
// the active result with aria-selected="true", which is the one state hook below. Every colour
|
|
6
|
+
// is a theme token, so dark mode follows the token flip with no rules of its own.
|
|
7
|
+
//
|
|
8
|
+
// Part of the wui-components layer, see _wui-components.scss for load order.
|
|
9
|
+
|
|
10
|
+
// Anchored near the top rather than centred, so the input stays put while results grow and
|
|
11
|
+
// shrink underneath it.
|
|
12
|
+
.modal.wui-modal-shell:has(.wui-cmd-card) {
|
|
13
|
+
align-items: flex-start;
|
|
14
|
+
padding-top: max(20px, min(12vh, 120px));
|
|
15
|
+
}
|
|
16
|
+
.wui-modal.wui-cmd-card {
|
|
17
|
+
max-height: min(560px, calc(100vh - 2 * max(20px, min(12vh, 120px))));
|
|
18
|
+
}
|
|
19
|
+
// The list scrolls, not the body: the input and the footer stay pinned.
|
|
20
|
+
.wui-cmd-card > .wui-modal-body {
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
padding: 0;
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
wui-command-palette {
|
|
28
|
+
display: flex;
|
|
29
|
+
flex: 1 1 auto;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
min-height: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.wui-cmd-search {
|
|
35
|
+
display: flex;
|
|
36
|
+
flex: 0 0 auto;
|
|
37
|
+
align-items: center;
|
|
38
|
+
gap: 10px;
|
|
39
|
+
padding: 0 16px;
|
|
40
|
+
border-bottom: 1px solid var(--color-border);
|
|
41
|
+
}
|
|
42
|
+
.wui-cmd-search-icon {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
flex: 0 0 auto;
|
|
45
|
+
color: var(--color-text-muted);
|
|
46
|
+
}
|
|
47
|
+
.wui-cmd-input {
|
|
48
|
+
flex: 1 1 auto;
|
|
49
|
+
min-width: 0;
|
|
50
|
+
height: 52px;
|
|
51
|
+
padding: 0;
|
|
52
|
+
border: none;
|
|
53
|
+
outline: none;
|
|
54
|
+
background: transparent;
|
|
55
|
+
color: var(--color-text);
|
|
56
|
+
font-size: 16px;
|
|
57
|
+
}
|
|
58
|
+
.wui-cmd-input::placeholder {
|
|
59
|
+
color: var(--color-text-subtle);
|
|
60
|
+
}
|
|
61
|
+
.wui-cmd-spinner {
|
|
62
|
+
flex: 0 0 auto;
|
|
63
|
+
color: var(--color-primary);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.wui-cmd-list {
|
|
67
|
+
flex: 1 1 auto;
|
|
68
|
+
min-height: 0;
|
|
69
|
+
padding: 6px;
|
|
70
|
+
overflow-y: auto;
|
|
71
|
+
overscroll-behavior: contain;
|
|
72
|
+
scrollbar-width: thin;
|
|
73
|
+
scrollbar-color: var(--color-border-strong) transparent;
|
|
74
|
+
}
|
|
75
|
+
.wui-cmd-list[hidden],
|
|
76
|
+
.wui-cmd-group[hidden],
|
|
77
|
+
.wui-cmd-item[hidden] {
|
|
78
|
+
display: none;
|
|
79
|
+
}
|
|
80
|
+
.wui-cmd-group + .wui-cmd-group {
|
|
81
|
+
margin-top: 4px;
|
|
82
|
+
}
|
|
83
|
+
.wui-cmd-group-label {
|
|
84
|
+
padding: 8px 10px 4px;
|
|
85
|
+
color: var(--color-text-muted);
|
|
86
|
+
font-size: 11px;
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
letter-spacing: 0.04em;
|
|
89
|
+
text-transform: uppercase;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.wui-cmd-item {
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 12px;
|
|
96
|
+
padding: 8px 10px;
|
|
97
|
+
border-radius: var(--radius);
|
|
98
|
+
corner-shape: squircle;
|
|
99
|
+
color: var(--color-text);
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
// Keeps a little of the next row visible when the keyboard scrolls the active one in.
|
|
102
|
+
scroll-margin: 6px;
|
|
103
|
+
}
|
|
104
|
+
.wui-cmd-item[aria-selected="true"] {
|
|
105
|
+
background: var(--color-primary-soft);
|
|
106
|
+
color: var(--color-primary);
|
|
107
|
+
}
|
|
108
|
+
.wui-cmd-item-icon {
|
|
109
|
+
display: inline-grid;
|
|
110
|
+
flex: 0 0 auto;
|
|
111
|
+
place-items: center;
|
|
112
|
+
width: 32px;
|
|
113
|
+
height: 32px;
|
|
114
|
+
border-radius: var(--radius);
|
|
115
|
+
corner-shape: squircle;
|
|
116
|
+
background: var(--color-bg-muted);
|
|
117
|
+
color: var(--color-text-muted);
|
|
118
|
+
}
|
|
119
|
+
.wui-cmd-item[aria-selected="true"] .wui-cmd-item-icon {
|
|
120
|
+
background: var(--color-surface);
|
|
121
|
+
color: var(--color-primary);
|
|
122
|
+
}
|
|
123
|
+
.wui-cmd-item-text {
|
|
124
|
+
display: flex;
|
|
125
|
+
flex: 1 1 auto;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
min-width: 0;
|
|
128
|
+
}
|
|
129
|
+
.wui-cmd-item-label,
|
|
130
|
+
.wui-cmd-item-desc {
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
text-overflow: ellipsis;
|
|
133
|
+
white-space: nowrap;
|
|
134
|
+
line-height: 1.4;
|
|
135
|
+
}
|
|
136
|
+
.wui-cmd-item-label {
|
|
137
|
+
font-size: 14px;
|
|
138
|
+
}
|
|
139
|
+
.wui-cmd-item-desc {
|
|
140
|
+
color: var(--color-text-muted);
|
|
141
|
+
font-size: 12px;
|
|
142
|
+
}
|
|
143
|
+
.wui-cmd-item-meta {
|
|
144
|
+
flex: 0 0 auto;
|
|
145
|
+
color: var(--color-text-muted);
|
|
146
|
+
font-size: 12px;
|
|
147
|
+
}
|
|
148
|
+
// The query inside a label: bolder, never a highlighter block.
|
|
149
|
+
.wui-cmd-mark {
|
|
150
|
+
padding: 0;
|
|
151
|
+
background: transparent;
|
|
152
|
+
color: inherit;
|
|
153
|
+
font-weight: 700;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.wui-cmd-empty {
|
|
157
|
+
padding: 20px 16px;
|
|
158
|
+
color: var(--color-text-muted);
|
|
159
|
+
font-size: 13px;
|
|
160
|
+
text-align: center;
|
|
161
|
+
}
|
|
162
|
+
// The status region is always in the page, so a screen reader hears the empty text arrive;
|
|
163
|
+
// with nothing to say it takes no room.
|
|
164
|
+
.wui-cmd-empty:empty {
|
|
165
|
+
display: none;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.wui-cmd-footer {
|
|
169
|
+
display: flex;
|
|
170
|
+
flex: 0 0 auto;
|
|
171
|
+
flex-wrap: wrap;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 6px 16px;
|
|
174
|
+
padding: 8px 16px;
|
|
175
|
+
border-top: 1px solid var(--color-border);
|
|
176
|
+
color: var(--color-text-muted);
|
|
177
|
+
font-size: 12px;
|
|
178
|
+
}
|
|
179
|
+
.wui-cmd-footer kbd {
|
|
180
|
+
padding: 1px 6px;
|
|
181
|
+
border: 1px solid var(--color-border);
|
|
182
|
+
border-radius: var(--wui-radius-sm);
|
|
183
|
+
background: var(--color-bg-muted);
|
|
184
|
+
color: var(--color-text);
|
|
185
|
+
font-family: inherit;
|
|
186
|
+
font-size: 11px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
190
|
+
.wui-cmd-item {
|
|
191
|
+
transition:
|
|
192
|
+
background-color 0.12s ease,
|
|
193
|
+
color 0.12s ease;
|
|
194
|
+
}
|
|
195
|
+
}
|
package/scss/wui/_display.scss
CHANGED
|
@@ -412,8 +412,14 @@ a.info-row:hover .info-value {
|
|
|
412
412
|
// label in primary. The tint is 8% so the label clears AA on it in both themes (light 5.6:1,
|
|
413
413
|
// dark 4.5:1); a stronger tint drops the dark label under 4.5:1.
|
|
414
414
|
// ============================================================================
|
|
415
|
+
// Each size sets one option height, icon size and note size, so a text, icon or note option in
|
|
416
|
+
// the same control lines up, and the four sizes step evenly: 28 / 32 / 38 / 44px tall overall
|
|
417
|
+
// (the track adds 8px), xl matching the 44px field height. A note option grows past the height.
|
|
415
418
|
.segmented {
|
|
416
419
|
--segmented-selected-bg: color-mix(in srgb, var(--color-primary) 8%, var(--color-surface));
|
|
420
|
+
--segmented-option-h: 24px;
|
|
421
|
+
--segmented-icon: 13px;
|
|
422
|
+
--segmented-note: 10px;
|
|
417
423
|
position: relative;
|
|
418
424
|
display: inline-flex;
|
|
419
425
|
gap: 2px;
|
|
@@ -428,7 +434,10 @@ a.info-row:hover .info-value {
|
|
|
428
434
|
display: inline-flex;
|
|
429
435
|
align-items: center;
|
|
430
436
|
gap: 5px;
|
|
431
|
-
|
|
437
|
+
min-height: var(--segmented-option-h);
|
|
438
|
+
// A small fixed vertical padding: the min-height sets the height, so an icon cannot push
|
|
439
|
+
// one option taller than its text-only siblings. Only a two-line note option grows.
|
|
440
|
+
padding: 4px 12px;
|
|
432
441
|
border: 0;
|
|
433
442
|
border-radius: 999px;
|
|
434
443
|
background: transparent;
|
|
@@ -478,7 +487,7 @@ a.info-row:hover .info-value {
|
|
|
478
487
|
color: inherit;
|
|
479
488
|
}
|
|
480
489
|
.segmented-option-note {
|
|
481
|
-
font-size:
|
|
490
|
+
font-size: var(--segmented-note);
|
|
482
491
|
font-weight: 400;
|
|
483
492
|
// Inherits the option's current text colour (plain, hover, or primary-on-checked) rather
|
|
484
493
|
// than a fixed token, so it always matches without a separate state per variant. No opacity
|
|
@@ -529,25 +538,61 @@ a.info-row:hover .info-value {
|
|
|
529
538
|
background: transparent;
|
|
530
539
|
box-shadow: none;
|
|
531
540
|
}
|
|
541
|
+
// A two-line note option keeps a little more air inside the ring than a one-line option needs.
|
|
542
|
+
.segmented-option:has(.segmented-option-note) {
|
|
543
|
+
padding-top: 6px;
|
|
544
|
+
padding-bottom: 6px;
|
|
545
|
+
}
|
|
546
|
+
.segmented-option > .wui-icon {
|
|
547
|
+
flex: none;
|
|
548
|
+
width: var(--segmented-icon);
|
|
549
|
+
height: var(--segmented-icon);
|
|
550
|
+
}
|
|
551
|
+
// Borderless (bordered={false} / bordered="false") — the selected pill keeps its tint and primary
|
|
552
|
+
// label but drops the ring, on both the sliding thumb and the no-JS per-option pill.
|
|
553
|
+
.segmented-borderless .segmented-thumb,
|
|
554
|
+
.segmented-borderless .segmented-option:has(.segmented-input:checked) {
|
|
555
|
+
box-shadow: none;
|
|
556
|
+
}
|
|
532
557
|
// Icon pop — the selected segment's glyph springs up a touch as it becomes active.
|
|
533
558
|
.segmented-option:has(.segmented-input:checked) .wui-icon {
|
|
534
559
|
transform: scale(1.14);
|
|
535
560
|
transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
536
561
|
}
|
|
537
562
|
.segmented-sm .segmented-thumb,
|
|
538
|
-
.segmented-lg .segmented-thumb
|
|
563
|
+
.segmented-lg .segmented-thumb,
|
|
564
|
+
.segmented-xl .segmented-thumb {
|
|
539
565
|
top: 3px;
|
|
540
566
|
bottom: 3px;
|
|
541
567
|
}
|
|
568
|
+
.segmented-sm {
|
|
569
|
+
--segmented-option-h: 20px;
|
|
570
|
+
--segmented-icon: 12px;
|
|
571
|
+
}
|
|
572
|
+
.segmented-lg {
|
|
573
|
+
--segmented-option-h: 30px;
|
|
574
|
+
--segmented-icon: 15px;
|
|
575
|
+
--segmented-note: 11px;
|
|
576
|
+
}
|
|
577
|
+
.segmented-xl {
|
|
578
|
+
--segmented-option-h: 36px;
|
|
579
|
+
--segmented-icon: 17px;
|
|
580
|
+
--segmented-note: 12px;
|
|
581
|
+
}
|
|
542
582
|
.segmented-sm .segmented-option {
|
|
543
583
|
padding: 4px 9px;
|
|
544
584
|
font-size: 11px;
|
|
545
585
|
}
|
|
546
586
|
.segmented-lg .segmented-option {
|
|
547
587
|
gap: 6px;
|
|
548
|
-
padding:
|
|
588
|
+
padding: 4px 16px;
|
|
549
589
|
font-size: 13px;
|
|
550
590
|
}
|
|
591
|
+
.segmented-xl .segmented-option {
|
|
592
|
+
gap: 7px;
|
|
593
|
+
padding: 4px 20px;
|
|
594
|
+
font-size: 15px;
|
|
595
|
+
}
|
|
551
596
|
// Full width — segments share the row equally (a toggle spanning a card or toolbar).
|
|
552
597
|
.segmented-full {
|
|
553
598
|
display: flex;
|
package/scss/wui/_overlays.scss
CHANGED
|
@@ -316,23 +316,23 @@
|
|
|
316
316
|
// keeps a non-square source whole rather than cropping it.
|
|
317
317
|
.wui-confirm-icon img {
|
|
318
318
|
display: block;
|
|
319
|
-
width: var(--wui-confirm-icon-size,
|
|
320
|
-
height: var(--wui-confirm-icon-size,
|
|
319
|
+
width: var(--wui-confirm-icon-size, 120px);
|
|
320
|
+
height: var(--wui-confirm-icon-size, 120px);
|
|
321
321
|
object-fit: contain;
|
|
322
322
|
}
|
|
323
323
|
.wui-confirm-icon svg {
|
|
324
|
-
width: var(--wui-confirm-icon-size,
|
|
325
|
-
height: var(--wui-confirm-icon-size,
|
|
324
|
+
width: var(--wui-confirm-icon-size, 120px);
|
|
325
|
+
height: var(--wui-confirm-icon-size, 120px);
|
|
326
326
|
}
|
|
327
|
-
// Icon size tracks the copy: a title+message dialog keeps the full
|
|
327
|
+
// Icon size tracks the copy: a title+message dialog keeps the full 120px badge, but a lone
|
|
328
328
|
// title (no message) is one line and gets a smaller badge. `.wui-confirm-msg` is a real
|
|
329
329
|
// element rendered only when a message exists, so `:has()` is reliable here; CSS width/height
|
|
330
330
|
// override the SVG's own width/height attributes. An explicit iconSize / icon-size sets
|
|
331
331
|
// --wui-confirm-icon-size on the badge and wins in both cases.
|
|
332
332
|
.wui-confirm-content:not(:has(.wui-confirm-msg)) .wui-confirm-icon svg,
|
|
333
333
|
.wui-confirm-content:not(:has(.wui-confirm-msg)) .wui-confirm-icon img {
|
|
334
|
-
width: var(--wui-confirm-icon-size,
|
|
335
|
-
height: var(--wui-confirm-icon-size,
|
|
334
|
+
width: var(--wui-confirm-icon-size, 84px);
|
|
335
|
+
height: var(--wui-confirm-icon-size, 84px);
|
|
336
336
|
}
|
|
337
337
|
.wui-confirm-title {
|
|
338
338
|
margin: 0 0 10px;
|
package/scss/wui/_shell.scss
CHANGED
|
@@ -194,8 +194,12 @@
|
|
|
194
194
|
.app-shell {
|
|
195
195
|
--app-sidebar-w: 260px;
|
|
196
196
|
--app-sidebar-rail-w: 88px;
|
|
197
|
+
// The sidebar's bottom band, from the rule above the collapse toggle to the sidebar's
|
|
198
|
+
// bottom edge, is the height of a one-line footer. The rule then continues the footer's
|
|
199
|
+
// top edge across the shell. The toggle fills what is left after the rule and two gaps.
|
|
200
|
+
--app-shell-foot-h: 39px;
|
|
197
201
|
// The equal space above (below the rule) and below the collapse toggle.
|
|
198
|
-
--app-sidebar-toggle-gap:
|
|
202
|
+
--app-sidebar-toggle-gap: 4px;
|
|
199
203
|
|
|
200
204
|
position: relative;
|
|
201
205
|
display: grid;
|
|
@@ -552,7 +556,9 @@
|
|
|
552
556
|
justify-content: center;
|
|
553
557
|
width: 100%;
|
|
554
558
|
position: relative;
|
|
555
|
-
|
|
559
|
+
// The band height less the rule and the gaps above and below the toggle, so rule + toggle
|
|
560
|
+
// + bottom inset add up to exactly --app-shell-foot-h.
|
|
561
|
+
height: calc(var(--app-shell-foot-h) - 1px - 2 * var(--app-sidebar-toggle-gap));
|
|
556
562
|
// 8px above the rule, the 1px rule, then the same gap below it as under the row.
|
|
557
563
|
margin-top: calc(9px + var(--app-sidebar-toggle-gap));
|
|
558
564
|
padding: 0;
|