@webority/theme 0.50.1 → 0.51.1
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/dist/purge-safelist.json +1 -0
- package/dist/webority-theme.css +1 -1
- package/package.json +1 -1
- package/scss/_components.scss +54 -22
- package/scss/wui/_choice.scss +14 -12
- package/scss/wui/_controls.scss +8 -1
- package/scss/wui/_utilities.scss +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.1",
|
|
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": {
|
package/scss/_components.scss
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
// Tactile press feedback — every variant AND every size (sm/md/lg). Kept
|
|
21
21
|
// separate from the height rule above so sm/lg (which opt out of the shared
|
|
22
22
|
// control height) still get the nudge. A signal, not a depth cue.
|
|
23
|
-
.btn:not(.btn-pill):not(.btn-pill-sm):not(.u-action):not(.btn-icon):active:not(:disabled) {
|
|
23
|
+
.btn:not(.btn-pill):not(.btn-pill-sm):not(.u-action):not(.btn-icon):not(.btn-ghost):active:not(:disabled) {
|
|
24
24
|
transform: translateY(1px);
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -303,8 +303,8 @@
|
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
// --- Sheen (default + .btn-anim-sheen): slim angled glossy band sweeps across.
|
|
306
|
-
.btn:not(.btn-icon):not(.u-action):not([class*="btn-anim-"])::before,
|
|
307
|
-
.btn-anim-sheen::before {
|
|
306
|
+
.btn:not(.btn-icon):not(.u-action):not(.btn-ghost):not([class*="btn-anim-"])::before,
|
|
307
|
+
.btn-anim-sheen:not(.btn-ghost)::before {
|
|
308
308
|
content: "";
|
|
309
309
|
position: absolute;
|
|
310
310
|
top: 0;
|
|
@@ -322,12 +322,12 @@
|
|
|
322
322
|
transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
|
|
323
323
|
pointer-events: none;
|
|
324
324
|
}
|
|
325
|
-
.btn:not(.btn-icon):not(.u-action):not([class*="btn-anim-"]):hover:not(:disabled)::before,
|
|
326
|
-
.btn-anim-sheen:hover:not(:disabled)::before {
|
|
325
|
+
.btn:not(.btn-icon):not(.u-action):not(.btn-ghost):not([class*="btn-anim-"]):hover:not(:disabled)::before,
|
|
326
|
+
.btn-anim-sheen:not(.btn-ghost):hover:not(:disabled)::before {
|
|
327
327
|
transform: translateX(320%) skewX(-18deg);
|
|
328
328
|
}
|
|
329
|
-
.btn:not(.btn-icon):not(.u-action):not([class*="btn-anim-"]):hover:not(:disabled),
|
|
330
|
-
.btn-anim-sheen:hover:not(:disabled) {
|
|
329
|
+
.btn:not(.btn-icon):not(.u-action):not(.btn-ghost):not([class*="btn-anim-"]):hover:not(:disabled),
|
|
330
|
+
.btn-anim-sheen:not(.btn-ghost):hover:not(:disabled) {
|
|
331
331
|
transform: translateY(-1px);
|
|
332
332
|
}
|
|
333
333
|
|
|
@@ -489,27 +489,59 @@
|
|
|
489
489
|
}
|
|
490
490
|
}
|
|
491
491
|
|
|
492
|
-
// ---- Ghost button
|
|
493
|
-
//
|
|
494
|
-
//
|
|
495
|
-
//
|
|
496
|
-
//
|
|
497
|
-
// (underlined, link-coloured text) rather than a quiet button. Marketing anchors reach
|
|
498
|
-
// for it directly for the same look on a plain <a>.
|
|
492
|
+
// ---- Ghost button: the tertiary action --------------------------------
|
|
493
|
+
// Brand-coloured, underlined text with no box in any state. It has no visible container,
|
|
494
|
+
// so nothing may draw one: no hover fill, no sheen sweep, no lift or press nudge, and no
|
|
495
|
+
// grey box when disabled or loading. Hover darkens the colour and thickens the underline.
|
|
496
|
+
// AppButton's `ghost` variant emits this class on both surfaces.
|
|
499
497
|
//
|
|
500
|
-
// No .btn-ghost-sm/-lg rungs:
|
|
501
|
-
//
|
|
502
|
-
// Bootstrap's own .btn-sm/.btn-lg.
|
|
498
|
+
// No .btn-ghost-sm/-lg rungs: it is an ordinary .btn variant and sizes with Bootstrap's
|
|
499
|
+
// own .btn-sm/.btn-lg, like .btn-primary.
|
|
503
500
|
.btn-ghost {
|
|
504
|
-
--bs-btn-color: var(--color-
|
|
501
|
+
--bs-btn-color: var(--color-primary-ink);
|
|
505
502
|
--bs-btn-bg: transparent;
|
|
506
503
|
--bs-btn-border-color: transparent;
|
|
507
|
-
--bs-btn-hover-color: var(--color-text);
|
|
508
|
-
--bs-btn-hover-bg:
|
|
504
|
+
--bs-btn-hover-color: color-mix(in srgb, var(--color-primary-ink) 80%, var(--color-text));
|
|
505
|
+
--bs-btn-hover-bg: transparent;
|
|
509
506
|
--bs-btn-hover-border-color: transparent;
|
|
510
|
-
--bs-btn-active-color: var(--color-text);
|
|
511
|
-
--bs-btn-active-bg:
|
|
507
|
+
--bs-btn-active-color: color-mix(in srgb, var(--color-primary-ink) 70%, var(--color-text));
|
|
508
|
+
--bs-btn-active-bg: transparent;
|
|
512
509
|
--bs-btn-active-border-color: transparent;
|
|
510
|
+
--bs-btn-disabled-color: var(--color-primary-ink);
|
|
511
|
+
--bs-btn-disabled-bg: transparent;
|
|
512
|
+
--bs-btn-disabled-border-color: transparent;
|
|
513
|
+
text-decoration: underline;
|
|
514
|
+
text-decoration-thickness: 1px;
|
|
515
|
+
text-underline-offset: 3px;
|
|
516
|
+
}
|
|
517
|
+
// Bootstrap's `.btn:hover` drops the underline (from $link-hover-decoration), so restate it
|
|
518
|
+
// with more specificity on every interactive state.
|
|
519
|
+
.btn.btn-ghost:hover,
|
|
520
|
+
.btn.btn-ghost:active,
|
|
521
|
+
.btn.btn-ghost:focus-visible {
|
|
522
|
+
text-decoration: underline;
|
|
523
|
+
text-decoration-thickness: 1px;
|
|
524
|
+
}
|
|
525
|
+
.btn.btn-ghost:hover:not(:disabled),
|
|
526
|
+
.btn.btn-ghost:active:not(:disabled) {
|
|
527
|
+
text-decoration-thickness: 2px;
|
|
528
|
+
}
|
|
529
|
+
// No box to light up, so keyboard focus gets the outline ring instead.
|
|
530
|
+
.btn.btn-ghost:focus-visible {
|
|
531
|
+
outline: 2px solid var(--color-primary-ink);
|
|
532
|
+
outline-offset: 2px;
|
|
533
|
+
box-shadow: none;
|
|
534
|
+
}
|
|
535
|
+
.btn.btn-ghost.btn-ghost:disabled,
|
|
536
|
+
.btn.btn-ghost.btn-ghost.disabled {
|
|
537
|
+
background-color: transparent;
|
|
538
|
+
border-color: transparent;
|
|
539
|
+
color: var(--color-primary-ink);
|
|
540
|
+
opacity: 0.55;
|
|
541
|
+
}
|
|
542
|
+
.btn.btn-ghost.btn-ghost.is-loading:disabled,
|
|
543
|
+
.btn.btn-ghost.btn-ghost.is-loading.disabled {
|
|
544
|
+
opacity: 1;
|
|
513
545
|
}
|
|
514
546
|
|
|
515
547
|
// ---- Card hover-lift (name is historical) -----------------------------
|
package/scss/wui/_choice.scss
CHANGED
|
@@ -1074,6 +1074,14 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
|
|
|
1074
1074
|
background: var(--color-surface);
|
|
1075
1075
|
border-color: color-mix(in srgb, var(--color-danger) 30%, transparent);
|
|
1076
1076
|
}
|
|
1077
|
+
.app-phone-number-input {
|
|
1078
|
+
// One size for the tel input, its placeholder and the dial code; the dial is not
|
|
1079
|
+
// inside the input, so it cannot inherit the input's font-size.
|
|
1080
|
+
--wui-phone-font-size: 14px;
|
|
1081
|
+
}
|
|
1082
|
+
.app-phone-number-input .phone-input-wrap > .input {
|
|
1083
|
+
font-size: var(--wui-phone-font-size);
|
|
1084
|
+
}
|
|
1077
1085
|
// The inner control drops its own chrome — the shell carries it.
|
|
1078
1086
|
.app-phone-number-input .phone-input-wrap > .input,
|
|
1079
1087
|
.app-phone-number-input .phone-input-wrap > .input:hover,
|
|
@@ -1148,8 +1156,8 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
|
|
|
1148
1156
|
transform: rotate(180deg);
|
|
1149
1157
|
}
|
|
1150
1158
|
.app-phone-number-input .phone-dial {
|
|
1151
|
-
font-size:
|
|
1152
|
-
font-weight:
|
|
1159
|
+
font-size: var(--wui-phone-font-size);
|
|
1160
|
+
font-weight: 400;
|
|
1153
1161
|
color: var(--color-text);
|
|
1154
1162
|
}
|
|
1155
1163
|
// Country-adornment toggles (AppPhoneNumberInput showFlag / showDialCode). Driven
|
|
@@ -1176,11 +1184,8 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
|
|
|
1176
1184
|
height: var(--wui-control-height-sm);
|
|
1177
1185
|
border-radius: var(--wui-field-radius-sm);
|
|
1178
1186
|
}
|
|
1179
|
-
.app-phone-number-input.phone-sm
|
|
1180
|
-
font-size: 13px;
|
|
1181
|
-
}
|
|
1182
|
-
.app-phone-number-input.phone-sm .phone-dial {
|
|
1183
|
-
font-size: 12px;
|
|
1187
|
+
.app-phone-number-input.phone-sm {
|
|
1188
|
+
--wui-phone-font-size: 13px;
|
|
1184
1189
|
}
|
|
1185
1190
|
.app-phone-number-input.phone-sm .phone-country-adornment {
|
|
1186
1191
|
padding-left: 10px;
|
|
@@ -1189,11 +1194,8 @@ wui-timepicker[aria-invalid="true"] .timepicker.open .timepicker-trigger {
|
|
|
1189
1194
|
height: var(--wui-control-height-lg);
|
|
1190
1195
|
border-radius: var(--wui-field-radius-lg);
|
|
1191
1196
|
}
|
|
1192
|
-
.app-phone-number-input.phone-lg
|
|
1193
|
-
font-size: 16px;
|
|
1194
|
-
}
|
|
1195
|
-
.app-phone-number-input.phone-lg .phone-dial {
|
|
1196
|
-
font-size: 14px;
|
|
1197
|
+
.app-phone-number-input.phone-lg {
|
|
1198
|
+
--wui-phone-font-size: 16px;
|
|
1197
1199
|
}
|
|
1198
1200
|
.app-phone-number-input.phone-lg .phone-country-adornment {
|
|
1199
1201
|
padding-left: 14px;
|
package/scss/wui/_controls.scss
CHANGED
|
@@ -193,9 +193,16 @@
|
|
|
193
193
|
.wui-radio:disabled {
|
|
194
194
|
cursor: not-allowed;
|
|
195
195
|
opacity: 0.55;
|
|
196
|
+
box-shadow: none;
|
|
197
|
+
}
|
|
198
|
+
// A disabled box that is ticked keeps its primary fill, only dimmed; the muted fill is for an
|
|
199
|
+
// empty one. :where keeps this at the :disabled specificity so the switch track still wins.
|
|
200
|
+
// A radio in a group with nothing chosen also matches :indeterminate, hence the type test.
|
|
201
|
+
.form-check-input:disabled:where(:not(:checked, [type="checkbox"]:indeterminate)),
|
|
202
|
+
.wui-check:disabled:where(:not(:checked, :indeterminate)),
|
|
203
|
+
.wui-radio:disabled:where(:not(:checked)) {
|
|
196
204
|
background-color: var(--color-bg-muted);
|
|
197
205
|
border-color: var(--color-border);
|
|
198
|
-
box-shadow: none;
|
|
199
206
|
}
|
|
200
207
|
.form-check-input:disabled ~ .form-check-label,
|
|
201
208
|
.wui-control:has(:disabled) {
|
package/scss/wui/_utilities.scss
CHANGED
|
@@ -523,6 +523,13 @@
|
|
|
523
523
|
color: var(--wui-success-active);
|
|
524
524
|
--pw-mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' fill-rule='evenodd' d='M12 21a9 9 0 1 0 0-18 9 9 0 0 0 0 18Zm4.03-11.28a.9.9 0 0 0-1.32-1.22l-4.02 4.35-1.4-1.5a.9.9 0 1 0-1.32 1.22l2.06 2.22a.9.9 0 0 0 1.32 0l4.68-5.07Z' clip-rule='evenodd'/%3E%3C/svg%3E");
|
|
525
525
|
}
|
|
526
|
+
// requirementsPlacement="inline": the same checklist, but in the field under the input and always
|
|
527
|
+
// visible, in place of the hint. `.field` is align-items:flex-start, so it is stretched to the
|
|
528
|
+
// control's width; the rows keep the popover's type and the same met/unmet marks.
|
|
529
|
+
.wui-pw-inline {
|
|
530
|
+
align-self: stretch;
|
|
531
|
+
margin-top: 8px;
|
|
532
|
+
}
|
|
526
533
|
// The checklist and the field help tip open with a PLAIN FADE only — no drop / zoom / scale. It opts out of the shared
|
|
527
534
|
// menu-open motion (_menu-motion.scss animates every `.popover.show`) and lets Bootstrap's own
|
|
528
535
|
// `.fade` opacity transition carry the fade in and out. Both surfaces render `.popover.pw-popover`
|