@webority/theme 0.8.1 → 0.8.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/theme",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
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": {
@@ -170,9 +170,9 @@
170
170
  // sizes step font-size, horizontal padding and radius together (vertical size
171
171
  // comes from --wui-control-height, so a button lines up with an input). Weight
172
172
  // is 600 on every rung — buttons read as a deliberate action, not body text.
173
- // Medium (default): 15px / 600, 24px side padding, 10px radius, 44px tall.
173
+ // Medium (default): 15px / 600, 24px side padding, 22px squircle radius, 45px tall.
174
174
  .btn {
175
- --bs-btn-border-radius: var(--wui-radius);
175
+ --bs-btn-border-radius: 22px;
176
176
  --bs-btn-font-size: 0.9375rem;
177
177
  --bs-btn-font-weight: 600;
178
178
  --bs-btn-padding-x: 1.5rem;
@@ -180,10 +180,10 @@
180
180
  // keep a plain border-radius arc — not a cross-browser design contract.
181
181
  corner-shape: squircle;
182
182
  }
183
- // Small: 14px, 18px side padding, 8px radius, 35px tall.
183
+ // Small: 14px, 18px side padding, 17px squircle radius (proportional to md), 35px tall.
184
184
  .btn-sm:not(.btn-icon),
185
185
  .btn-group-sm > .btn:not(.btn-icon) {
186
- --bs-btn-border-radius: var(--wui-radius-sm);
186
+ --bs-btn-border-radius: 17px;
187
187
  --bs-btn-font-size: 0.875rem;
188
188
  --bs-btn-padding-x: 1.125rem;
189
189
  display: inline-flex;
@@ -191,10 +191,10 @@
191
191
  justify-content: center;
192
192
  min-height: 35px;
193
193
  }
194
- // Large: 17px, 32px side padding, 14px radius, 55px tall — a spacious CTA.
194
+ // Large: 17px, 32px side padding, 27px squircle radius (proportional to md), 55px tall — a spacious CTA.
195
195
  .btn-lg:not(.btn-icon),
196
196
  .btn-group-lg > .btn:not(.btn-icon) {
197
- --bs-btn-border-radius: var(--wui-radius-lg);
197
+ --bs-btn-border-radius: 27px;
198
198
  --bs-btn-font-size: 1.0625rem;
199
199
  --bs-btn-padding-x: 2rem;
200
200
  display: inline-flex;
@@ -894,7 +894,8 @@ button.datepicker-month:hover {
894
894
  border: 1px solid var(--color-border);
895
895
  border-radius: var(--radius);
896
896
  corner-shape: squircle;
897
- background: var(--color-surface);
897
+ // Match AppInput exactly: muted resting fill that lifts to a clean surface on focus.
898
+ background: var(--color-bg-muted);
898
899
  // Clip the inner control to the shell's rounded shape — a full-height child was painting
899
900
  // over the squircle border at the bottom, which read as a cut-off bottom edge. The dial
900
901
  // dropdown is position:fixed, so it is unaffected by this.
@@ -907,10 +908,10 @@ button.datepicker-month:hover {
907
908
  background: var(--color-bg-muted);
908
909
  border-color: var(--color-border-strong);
909
910
  }
910
- // Match AppInput's focus: a soft primary border, not a full-strength one.
911
+ // Match AppInput's focus: clean surface fill + a soft primary border.
911
912
  .app-phone-number-input .phone-input-wrap:focus-within {
912
- background: var(--color-bg-muted);
913
- border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
913
+ background: var(--color-surface);
914
+ border-color: var(--wui-primary-30);
914
915
  }
915
916
  .app-phone-number-input .phone-input-wrap:has(> .input:disabled) {
916
917
  background: var(--color-bg-muted);
@@ -998,6 +999,20 @@ button.datepicker-month:hover {
998
999
  font-weight: 500;
999
1000
  color: var(--color-text);
1000
1001
  }
1002
+ // Country-adornment toggles (AppPhoneNumberInput showFlag / showDialCode). Driven
1003
+ // by a host attribute so it survives <wui-phone>'s innerHTML re-renders; the flex
1004
+ // gap collapses on its own, leaving no gap where a hidden glyph sat.
1005
+ .app-phone-number-input wui-phone[hide-flag] [data-flag] {
1006
+ display: none;
1007
+ }
1008
+ .app-phone-number-input wui-phone[hide-dial] [data-dial] {
1009
+ display: none;
1010
+ }
1011
+ // Both hidden → the country toggle is just the chevron; drop its leading pad so
1012
+ // the number sits flush like a plain input's.
1013
+ .app-phone-number-input wui-phone[hide-flag][hide-dial] .phone-country-adornment {
1014
+ padding-left: 10px;
1015
+ }
1001
1016
 
1002
1017
  // Menu, search field and rows all share the .search-select language so the
1003
1018
  // country picker reads as the same component family as every other picker.
@@ -999,7 +999,8 @@ wui-select[compact] {
999
999
  border: 1px solid var(--color-border);
1000
1000
  border-radius: var(--radius-lg);
1001
1001
  corner-shape: squircle;
1002
- background: var(--color-surface);
1002
+ // Match AppInput exactly: muted resting fill that lifts to a clean surface on focus.
1003
+ background: var(--color-bg-muted);
1003
1004
  transition:
1004
1005
  border-color 0.12s,
1005
1006
  background-color 0.12s;
@@ -1010,8 +1011,8 @@ wui-select[compact] {
1010
1011
  border-color: var(--color-border-strong);
1011
1012
  }
1012
1013
  .num-wrap:focus-within {
1013
- background: var(--color-bg-muted);
1014
- border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
1014
+ background: var(--color-surface);
1015
+ border-color: var(--wui-primary-30);
1015
1016
  }
1016
1017
  .num-wrap:has(.num-input.error) {
1017
1018
  border-color: var(--color-danger);
@@ -1019,25 +1020,34 @@ wui-select[compact] {
1019
1020
 
1020
1021
  // Numeric input inside the stepper — plain text field, no native spinner.
1021
1022
  // Flows seamlessly between the stepper buttons; the wrapper carries the border.
1023
+ // The value reads as the segmented centre cell — centred + semibold like the
1024
+ // reference: minus | value | plus, three even cells divided by the button borders.
1022
1025
  .num-wrap .num-input {
1023
1026
  flex: 1;
1024
1027
  border: none;
1025
1028
  border-radius: 0;
1026
1029
  background: transparent;
1027
1030
  min-width: 0;
1031
+ text-align: center;
1032
+ font-weight: 600;
1033
+ color: var(--color-text);
1028
1034
  }
1029
1035
  .num-wrap .num-input:focus {
1030
1036
  box-shadow: none;
1031
1037
  }
1032
1038
 
1033
1039
  // Stepper buttons — decrease/increase the value by step.
1034
- // Positioned left and right of the input, disabled at min/max or when the
1035
- // control is disabled.
1040
+ // Positioned left (minus, :first-child) and right (plus, :last-child) of the
1041
+ // input; disabled at min/max or when the control is disabled. Each carries the
1042
+ // divider on its input-facing edge so the value sits in its own segment.
1036
1043
  .num-btn {
1037
1044
  display: grid;
1038
1045
  place-items: center;
1039
- width: 40px;
1040
- height: 100%;
1046
+ width: 44px;
1047
+ // Fill the field height and centre the glyph. `height: 100%` resolved to auto
1048
+ // against the wrap's content-based height and left the button icon-tall, pinned
1049
+ // to the top; align-self:stretch fills the full field so place-items centres it.
1050
+ align-self: stretch;
1041
1051
  border: none;
1042
1052
  background: transparent;
1043
1053
  padding: 0;
@@ -1064,10 +1074,32 @@ wui-select[compact] {
1064
1074
  cursor: not-allowed;
1065
1075
  opacity: 0.5;
1066
1076
  }
1067
- .num-btn:not(:first-child) {
1077
+ // Segment dividers: minus divides on its right, plus on its left — so the value
1078
+ // cell is bounded on both sides. (DOM order is minus, input, [unit], plus on both
1079
+ // surfaces, so :first-child / :last-child land on the two buttons.)
1080
+ .num-btn:first-child {
1081
+ border-right: 1px solid var(--color-border);
1082
+ }
1083
+ .num-btn:last-child {
1068
1084
  border-left: 1px solid var(--color-border);
1069
1085
  }
1070
1086
 
1087
+ // ── Size variants ── the inner input carries .input-sm / .input-lg (height +
1088
+ // font), the wrapper carries .num-wrap-sm / .num-wrap-lg to scale the button
1089
+ // cells to match. Default (md) uses the base 44px cell above.
1090
+ .num-wrap-sm .num-btn {
1091
+ width: 36px;
1092
+ }
1093
+ .num-wrap-sm .num-input {
1094
+ font-size: 13px;
1095
+ }
1096
+ .num-wrap-lg .num-btn {
1097
+ width: 52px;
1098
+ }
1099
+ .num-wrap-lg .num-input {
1100
+ font-size: 16px;
1101
+ }
1102
+
1071
1103
  // Affix (unit) in the num-wrap — a trailing pill after the input.
1072
1104
  .num-wrap .affix {
1073
1105
  background: var(--color-bg-muted);
@@ -63,7 +63,9 @@
63
63
  }
64
64
  .kpi-value {
65
65
  margin-top: 6px;
66
- font-size: 28px;
66
+ // The value ("main heading") size flows from one var, so a size tier (sm/md/lg,
67
+ // spotlight) or a custom `valueSize` (px) can drive it. Default (md) is 28px.
68
+ font-size: var(--wui-kpi-value-size, 28px);
67
69
  font-weight: 700;
68
70
  // Large numerals need negative tracking to stop reading as separate digits;
69
71
  // tabular figures stop a live-updating value from shifting width.
@@ -133,17 +135,29 @@
133
135
  background: var(--color-warning-soft);
134
136
  }
135
137
 
138
+ // Compact size — dense dashboards and tight cards. Shrinks the value + chrome.
139
+ .kpi.kpi-sm {
140
+ padding: 12px 14px;
141
+ --wui-kpi-value-size: 22px;
142
+ }
143
+ .kpi.kpi-sm .kpi-label {
144
+ font-size: 12px;
145
+ }
146
+ .kpi.kpi-sm .kpi-icon {
147
+ width: 32px;
148
+ height: 32px;
149
+ margin-bottom: 8px;
150
+ }
151
+
136
152
  // Hero size — the single headline stat above a dashboard. Enlarges the value and its
137
153
  // chrome; orthogonal to variant/inline/attention, so it composes with all of them.
138
154
  .kpi.kpi-lg {
139
155
  padding: 20px;
156
+ --wui-kpi-value-size: 40px;
140
157
  }
141
158
  .kpi.kpi-lg .kpi-label {
142
159
  font-size: 14px;
143
160
  }
144
- .kpi.kpi-lg .kpi-value {
145
- font-size: 40px;
146
- }
147
161
  .kpi.kpi-lg .kpi-icon {
148
162
  width: 44px;
149
163
  height: 44px;
@@ -158,6 +172,7 @@
158
172
  grid-template-columns: minmax(0, 1fr) auto;
159
173
  column-gap: 16px;
160
174
  padding: 22px 24px;
175
+ --wui-kpi-value-size: 44px;
161
176
  }
162
177
  .kpi.kpi-spotlight .kpi-icon {
163
178
  grid-column: 2;
@@ -183,8 +198,9 @@
183
198
  // The editorial serif is this variant's signature (see the reference tile), so the value gets
184
199
  // a serif stack directly — not --wui-font-display, which defaults to the body sans and so would
185
200
  // never read as serif. A product that wants its own face overrides this one selector.
201
+ // Size comes from --wui-kpi-value-size (44px default, set on the spotlight root above), so a
202
+ // custom `valueSize` (px) can tame a too-large headline.
186
203
  font-family: Georgia, 'Times New Roman', 'Noto Serif', serif;
187
- font-size: 44px;
188
204
  line-height: 1;
189
205
  font-weight: 600;
190
206
  }
@@ -830,16 +830,24 @@ wui-wizard-step[hidden] {
830
830
  // A resting min-height so the footer doesn't jump as steps of different length
831
831
  // swap in; content taller than this simply grows the panel.
832
832
  min-height: 96px;
833
+ // A rounded squircle card around the step content. The surface (border + fill +
834
+ // padding) is what makes the radius visible — a radius on a border/background-less
835
+ // box shows nothing.
836
+ padding: 20px 24px;
837
+ border: 1px solid var(--color-border);
838
+ border-radius: 22px;
839
+ corner-shape: squircle;
840
+ background: var(--color-surface);
833
841
  }
834
842
  .wizard-footer {
835
- // The sticky Back/Skip/Next/Finish bar — pinned to the bottom of a scrolling flow
836
- // so the actions (and the Skip on an optional step) are always in reach. Runs flush on
837
- // the flow (no divider or fill) — the buttons alone read as the footer.
838
- position: sticky;
839
- bottom: 0;
843
+ // The Back/Skip/Next/Finish bar sits at the END of the wizard content — NOT
844
+ // viewport-pinned. A transparent sticky bar (the old behaviour) pinned to the
845
+ // viewport bottom collided with a page/app footer below the wizard, burying the
846
+ // buttons behind it. Inline keeps them in the flow, always clear of a page footer.
847
+ // (For a wizard inside its OWN fixed-height scroll panel, a product can opt back
848
+ // into sticky on its container.)
840
849
  margin-top: 24px;
841
850
  padding: 16px 0;
842
- z-index: 1;
843
851
  }
844
852
  .wizard-footer-actions {
845
853
  display: flex;
@@ -527,16 +527,23 @@
527
527
  border-radius: var(--radius-lg);
528
528
  corner-shape: squircle;
529
529
  border: 1px solid var(--color-border);
530
- background: var(--color-surface);
530
+ // Match AppInput: muted resting fill, lifts to a clean surface on focus.
531
+ background: var(--color-bg-muted);
531
532
  overflow: hidden;
532
533
  cursor: pointer;
533
534
  transition:
534
535
  border-color 0.12s,
535
536
  box-shadow 0.12s;
536
537
  }
537
- .file-input:hover {
538
+ .file-input:hover:not(:focus-within) {
539
+ background: var(--color-bg-muted);
538
540
  border-color: var(--color-border-strong);
539
541
  }
542
+ .file-input:focus-within {
543
+ background: var(--color-surface);
544
+ border-color: var(--wui-primary-30);
545
+ box-shadow: none;
546
+ }
540
547
  .file-input-btn {
541
548
  display: inline-flex;
542
549
  align-items: center;
@@ -579,21 +586,25 @@
579
586
  width: 100%;
580
587
  padding: 20px;
581
588
  text-align: center;
582
- background: var(--color-bg-subtle);
583
- border: 1px dashed var(--color-border-strong);
589
+ // Match AppInput: muted resting fill + resting border (dashed kept as the dropzone
590
+ // affordance), border-strong on hover, primary border + surface lift on focus/drag.
591
+ background: var(--color-bg-muted);
592
+ border: 1px dashed var(--color-border);
584
593
  transition:
585
594
  border-color 0.15s ease,
586
595
  background-color 0.15s ease;
587
596
  }
588
- // Hover, focus and drag-over all take the same soft primary-30% border AppInput shows on
589
- // focus — a clear hue shift from the resting grey dashed border, without the loud full
590
- // --color-primary the dropzone used before.
591
- .file-input.file-input-tall:hover,
597
+ // Hover mirrors AppInput hover — border-strong, fill unchanged.
598
+ .file-input.file-input-tall:hover:not(:focus-within):not(.dragging) {
599
+ border-color: var(--color-border-strong);
600
+ background: var(--color-bg-muted);
601
+ }
602
+ // Focus and drag-over mirror AppInput focus — soft primary border, lift onto a clean surface.
592
603
  .file-input.file-input-tall:focus-within,
593
604
  .file-input.file-input-tall:active,
594
605
  .file-input.file-input-tall.dragging {
595
- border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
596
- background: var(--color-bg-muted);
606
+ border-color: var(--wui-primary-30);
607
+ background: var(--color-surface);
597
608
  box-shadow: none;
598
609
  }
599
610
  // A rejected file (wrong type / too large) turns the dropzone border danger to match the
@@ -639,11 +650,11 @@
639
650
  .file-input.file-input-tall.has-files:hover,
640
651
  .file-input.file-input-tall.has-files:focus-within {
641
652
  border-color: var(--color-border-strong);
642
- background: var(--color-bg-subtle);
653
+ background: var(--color-bg-muted);
643
654
  }
644
655
  .file-input.file-input-tall.has-files.dragging {
645
- border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
646
- background: var(--color-bg-muted);
656
+ border-color: var(--wui-primary-30);
657
+ background: var(--color-surface);
647
658
  }
648
659
  // Width presets — put a .file-w-* class on the field (React className / Razor class) to cap the
649
660
  // dropzone to a fixed width instead of the full column. Mirror of the datepicker .date-w-* set.
@@ -15,8 +15,15 @@
15
15
  // Do NOT put layout on backdropClassName — that targets a sibling, not
16
16
  // .modal.
17
17
  .modal-backdrop.wui-modal-dim {
18
- background: var(--color-scrim);
18
+ // Frost the page behind the dialog — the blur is the star, so the dim is kept
19
+ // SOFT (a heavy scrim would flatten the blur into a muddy grey). A lighter dim
20
+ // over a strong blur reads as clean frosted glass; the modal is still clearly
21
+ // the one live surface. The dialog sits in `.modal` (a higher z-index sibling),
22
+ // so it is never blurred.
23
+ background: color-mix(in srgb, var(--color-scrim) 55%, transparent);
19
24
  z-index: var(--wui-z-modal-backdrop);
25
+ backdrop-filter: blur(12px);
26
+ -webkit-backdrop-filter: blur(12px);
20
27
  }
21
28
  .modal.wui-modal-shell {
22
29
  --bs-modal-bg: transparent;
@@ -68,8 +68,17 @@
68
68
  }
69
69
  .chip-ic {
70
70
  display: inline-flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ line-height: 0;
71
74
  color: var(--color-text-subtle);
72
75
  }
76
+ // Bootstrap Icons carry a -.125em baseline nudge meant for inline-with-text use;
77
+ // inside the chip's flex row it just drops the glyph below the label's centre.
78
+ // Reset it so a library-icon leading glyph lines up with the label.
79
+ .chip-ic .bi::before {
80
+ vertical-align: middle;
81
+ }
73
82
  .chip-avatar {
74
83
  display: inline-flex;
75
84
  width: 18px;