@webority/theme 0.69.0 → 0.71.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/theme",
3
- "version": "0.69.0",
3
+ "version": "0.71.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": {
@@ -28,9 +28,13 @@
28
28
  "./css": "./dist/webority-theme.css",
29
29
  "./css/flags": "./dist/webority-flags.css",
30
30
  "./css/brand-signal": "./dist/webority-brand-signal.css",
31
+ "./css/runtime-brand": "./dist/webority-runtime-brand.css",
31
32
  "./purge-safelist.json": "./dist/purge-safelist.json",
32
33
  "./package.json": "./package.json"
33
34
  },
35
+ "bin": {
36
+ "webority-theme-export": "./dist/webority-theme-export.mjs"
37
+ },
34
38
  "sass": "index.scss",
35
39
  "style": "dist/webority-theme.css",
36
40
  "peerDependencies": {
@@ -39,9 +43,10 @@
39
43
  "devDependencies": {
40
44
  "bootstrap": "5.3.3",
41
45
  "country-flag-icons": "^1.6.20",
42
- "sass-embedded": "^1.97.0"
46
+ "sass-embedded": "^1.97.0",
47
+ "vite": "^8.0.12"
43
48
  },
44
49
  "scripts": {
45
- "build": "sass index.scss dist/webority-theme.css --load-path=node_modules --style=compressed --no-source-map --quiet-deps --silence-deprecation=if-function && sass scss/_flags.scss dist/webority-flags.css --style=compressed --no-source-map --quiet && sass scss/_brand-signal.scss dist/webority-brand-signal.css --style=compressed --no-source-map --quiet && node ../../scripts/gen-purge-safelist.mjs && node ../../scripts/sync-rcl-assets.mjs theme"
50
+ "build": "sass index.scss dist/webority-theme.css --load-path=node_modules --style=compressed --no-source-map --quiet-deps --silence-deprecation=if-function && sass scss/_flags.scss dist/webority-flags.css --style=compressed --no-source-map --quiet && sass scss/_brand-signal.scss dist/webority-brand-signal.css --style=compressed --no-source-map --quiet && sass scss/_runtime-brand.scss dist/webority-runtime-brand.css --style=compressed --no-source-map --quiet && node ../../scripts/gen-purge-safelist.mjs && node ../../scripts/sync-rcl-assets.mjs theme && vite build --config vite.cli.config.js"
46
51
  }
47
52
  }
@@ -6,15 +6,14 @@
6
6
  // ---- Button polish (used by both Razor + React) ---------------------
7
7
  // Flat buttons — no drop shadow. Active-press feedback (1px nudge) is
8
8
  // retained because it's a tactile signal, not a depth cue.
9
- // Button heights are fixed to the design reference — large 55px, medium 45px,
10
- // small 35px — via min-height, with the label flex-centred. (These are button-
11
- // specific and intentionally a touch taller than the shared --wui-control-height
12
- // input ladder; sm/lg pin their own height in their size blocks below.)
9
+ // A button is exactly as tall as a field of the same size (the --wui-control-height ladder, 36/44/52px), so a
10
+ // button beside an input lines up in every form row. Heights are min-height with the label flex-centred; sm/lg
11
+ // set theirs in their size blocks below.
13
12
  .btn:not(.btn-sm):not(.btn-lg):not(.btn-pill):not(.btn-pill-sm):not(.u-action):not(.btn-icon) {
14
13
  display: inline-flex;
15
14
  align-items: center;
16
15
  justify-content: center;
17
- min-height: 45px;
16
+ min-height: var(--wui-control-height);
18
17
  }
19
18
 
20
19
  // Tactile press feedback — every variant AND every size (sm/md/lg). Kept
@@ -266,7 +265,7 @@
266
265
  // sizes step font-size, horizontal padding and radius together (vertical size
267
266
  // comes from --wui-control-height, so a button lines up with an input). Weight
268
267
  // is 600 on every rung — buttons read as a deliberate action, not body text.
269
- // Medium (default): 14px / 600, 24px side padding, 18px squircle radius, 45px tall.
268
+ // Medium (default): 14px / 600, 24px side padding, 18px squircle radius, --wui-control-height tall.
270
269
  .btn {
271
270
  --bs-btn-border-radius: 18px;
272
271
  --bs-btn-font-size: 0.875rem;
@@ -276,7 +275,7 @@
276
275
  // keep a plain border-radius arc — not a cross-browser design contract.
277
276
  corner-shape: squircle;
278
277
  }
279
- // Small: 12px, 18px side padding, 14px squircle radius (proportional to md), 35px tall.
278
+ // Small: 12px, 18px side padding, 14px squircle radius (proportional to md), as tall as a small field.
280
279
  .btn-sm:not(.btn-icon),
281
280
  .btn-group-sm > .btn:not(.btn-icon) {
282
281
  --bs-btn-border-radius: 14px;
@@ -285,9 +284,9 @@
285
284
  display: inline-flex;
286
285
  align-items: center;
287
286
  justify-content: center;
288
- min-height: 35px;
287
+ min-height: var(--wui-control-height-sm);
289
288
  }
290
- // Large: 16px, 32px side padding, 22px squircle radius (proportional to md), 55px tall — a spacious CTA.
289
+ // Large: 16px, 32px side padding, 22px squircle radius (proportional to md), as tall as a large field.
291
290
  .btn-lg:not(.btn-icon),
292
291
  .btn-group-lg > .btn:not(.btn-icon) {
293
292
  --bs-btn-border-radius: 22px;
@@ -296,7 +295,7 @@
296
295
  display: inline-flex;
297
296
  align-items: center;
298
297
  justify-content: center;
299
- min-height: 55px;
298
+ min-height: var(--wui-control-height-lg);
300
299
  }
301
300
 
302
301
  // ---- Hover animation options (opt-in modifiers) ---------------------
@@ -0,0 +1,83 @@
1
+ // Runtime brand: an opt-in layer that lets a product's exported token file (webority-theme-export,
2
+ // format webority-theme-tokens/1) restyle the precompiled theme without recompiling it.
3
+ //
4
+ // Loaded AFTER webority-theme.css and BEFORE the token file's values. It holds no colour of its own.
5
+ // Bootstrap compiles $primary into a few component rules as literals; this layer re-points each of
6
+ // them at --bs-primary / --bs-primary-rgb, which the token file sets on :root. Every other brand
7
+ // value (--wui-*, links, fonts, the Bootstrap subtle and emphasis colours, dark mode) is already a
8
+ // custom property on :root and arrives with the token file unchanged.
9
+ //
10
+ // Each tint below is the colour-mix equivalent of the Bootstrap function that made the literal
11
+ // (tint-color = mix with white, shade-color = mix with black), so a product's own primary renders
12
+ // the same through this layer as through its compiled build. The compiled values are the same in
13
+ // light and dark, so there is no dark block.
14
+
15
+ .btn-primary {
16
+ --bs-btn-bg: var(--bs-primary);
17
+ --bs-btn-border-color: var(--bs-primary);
18
+ --bs-btn-disabled-bg: var(--bs-primary);
19
+ --bs-btn-disabled-border-color: var(--bs-primary);
20
+ // Bootstrap mixes 15% white into this triplet; a triplet cannot be mixed at runtime.
21
+ --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
22
+ }
23
+
24
+ .btn-outline-primary {
25
+ --bs-btn-focus-shadow-rgb: var(--bs-primary-rgb);
26
+ }
27
+
28
+ .nav-pills {
29
+ --bs-nav-pills-link-active-bg: var(--bs-primary);
30
+ }
31
+
32
+ .pagination {
33
+ --bs-pagination-active-bg: var(--bs-primary);
34
+ --bs-pagination-active-border-color: var(--bs-primary);
35
+ }
36
+
37
+ .list-group {
38
+ --bs-list-group-active-bg: var(--bs-primary);
39
+ --bs-list-group-active-border-color: var(--bs-primary);
40
+ }
41
+
42
+ .progress,
43
+ .progress-stacked {
44
+ --bs-progress-bar-bg: var(--bs-primary);
45
+ }
46
+
47
+ // Mouse focus only: the theme paints keyboard focus and checked boxes from --color-primary already,
48
+ // and a plain :focus rule here would win over both by source order.
49
+ .form-check-input:focus:not(:focus-visible):not(:checked):not([type="checkbox"]:indeterminate) {
50
+ border-color: color-mix(in srgb, var(--bs-primary) 50%, #fff);
51
+ }
52
+
53
+ .form-range::-webkit-slider-thumb {
54
+ background-color: var(--bs-primary);
55
+ }
56
+
57
+ .form-range::-webkit-slider-thumb:active {
58
+ background-color: color-mix(in srgb, var(--bs-primary) 30%, #fff);
59
+ }
60
+
61
+ .form-range::-moz-range-thumb {
62
+ background-color: var(--bs-primary);
63
+ }
64
+
65
+ .form-range::-moz-range-thumb:active {
66
+ background-color: color-mix(in srgb, var(--bs-primary) 30%, #fff);
67
+ }
68
+
69
+ .link-primary:hover,
70
+ .link-primary:focus {
71
+ color: color-mix(in srgb, color-mix(in srgb, var(--bs-primary) 80%, #000) calc(var(--bs-link-opacity, 1) * 100%), transparent) !important;
72
+ text-decoration-color: color-mix(in srgb, color-mix(in srgb, var(--bs-primary) 80%, #000) calc(var(--bs-link-underline-opacity, 1) * 100%), transparent) !important;
73
+ }
74
+
75
+ // Bootstrap's table-variant mixin: the cell colour is black, and each state mixes it into the tint.
76
+ .table-primary {
77
+ --wui-table-primary-bg: color-mix(in srgb, var(--bs-primary) 20%, #fff);
78
+ --bs-table-bg: var(--wui-table-primary-bg);
79
+ --bs-table-border-color: color-mix(in srgb, #000 20%, var(--wui-table-primary-bg));
80
+ --bs-table-striped-bg: color-mix(in srgb, #000 5%, var(--wui-table-primary-bg));
81
+ --bs-table-active-bg: color-mix(in srgb, #000 10%, var(--wui-table-primary-bg));
82
+ --bs-table-hover-bg: color-mix(in srgb, #000 7.5%, var(--wui-table-primary-bg));
83
+ }
@@ -101,9 +101,10 @@
101
101
  background: var(--color-info-soft);
102
102
  color: var(--color-info-text-on-soft);
103
103
  }
104
+ // Foreground lightness 31%: at 32% the hue-60 pair falls to 4.42:1 on the 90% tint.
104
105
  .avatar-auto {
105
106
  background: hsl(var(--avatar-hue, 0) 60% 90%);
106
- color: hsl(var(--avatar-hue, 0) 42% 32%);
107
+ color: hsl(var(--avatar-hue, 0) 42% 31%);
107
108
  }
108
109
 
109
110
  // ── Ring ── (`ring`): a tone-coloured ring with a surface gap, separating stacked
@@ -600,6 +600,21 @@
600
600
  max-width: min(92vw, 400px);
601
601
  }
602
602
 
603
+ // An end-side stack moves clear of an open side drawer, so a toast never covers the panel's
604
+ // content or its Save button. Widths mirror the drawer sizes in _drawer.scss; !important beats
605
+ // Bootstrap's .end-0 utility, which is itself !important.
606
+ @include media-breakpoint-up(md) {
607
+ body:has(.wui-drawer[open]:not([side="start"])) .wui-toast-container.end-0 {
608
+ right: min(480px, 100%) !important;
609
+ }
610
+ body:has(.wui-drawer[open][size="sm"]:not([side="start"])) .wui-toast-container.end-0 {
611
+ right: min(360px, 100%) !important;
612
+ }
613
+ body:has(.wui-drawer[open][size="lg"]:not([side="start"])) .wui-toast-container.end-0 {
614
+ right: min(640px, 100%) !important;
615
+ }
616
+ }
617
+
603
618
  // Bootstrap's .toast-container stacks children with margin-bottom: $toast-spacing (1.5rem),
604
619
  // which ADDED to the flex gap above — the stack spacing is the gap alone.
605
620
  .wui-toast-container > :not(:last-child) {
@@ -83,6 +83,20 @@
83
83
  text-overflow: ellipsis;
84
84
  white-space: nowrap;
85
85
  }
86
+ // At 360px and narrower a label wraps to two lines instead of cutting off, so "Earnings" shows in
87
+ // full at 320px with WCAG text spacing. A third line is clamped.
88
+ @media (max-width: 360px) {
89
+ .wui-tabbar-label {
90
+ display: -webkit-box;
91
+ -webkit-box-orient: vertical;
92
+ -webkit-line-clamp: 2;
93
+ font-size: 0.6875rem;
94
+ line-height: 1.15;
95
+ overflow-wrap: anywhere;
96
+ text-overflow: clip;
97
+ white-space: normal;
98
+ }
99
+ }
86
100
  // A count over the icon. Neutral by default, toned like the nav badge it mirrors (-text on -soft,
87
101
  // the 4.5:1 pairing the nav badge tones use).
88
102
  .wui-tabbar-badge {