@webority/theme 0.0.9 → 0.2.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.0.9",
3
+ "version": "0.2.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,6 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "bootstrap": "5.3.3",
31
+ "country-flag-icons": "^1.6.20",
31
32
  "sass": "~1.77.8"
32
33
  },
33
34
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  // =====================================================================
2
- // Lumex — Shared custom component CSS.
2
+ // Webority UI — shared custom component CSS.
3
3
  // Imported AFTER Bootstrap. Anything that needs to render identically
4
4
  // on the Razor marketing site AND the React customer portal lives here.
5
5
  // Per-project styling (page layouts, route-specific tweaks) stays in
@@ -7,13 +7,6 @@
7
7
  // =====================================================================
8
8
 
9
9
 
10
- // ---- Brand wordmark / logo ------------------------------------------
11
- .lumex-logo {
12
- height: 2rem;
13
- width: auto;
14
- }
15
-
16
-
17
10
  // ---- Section helpers ------------------------------------------------
18
11
  // Marketing + portal both use vertically-padded sections with the
19
12
  // brand's spacing rhythm. Bootstrap's py-* gets you part-way; these
@@ -72,14 +65,23 @@
72
65
  // ---- Button polish (used by both Razor + React) ---------------------
73
66
  // Flat buttons — no drop shadow. Active-press feedback (1px nudge) is
74
67
  // retained because it's a tactile signal, not a depth cue.
68
+ // Default-size buttons match the shared control height so a button next to an
69
+ // input in a filter bar or form row lines up exactly. sm/lg opt out — they are
70
+ // deliberately a different size.
71
+ .btn:not(.btn-sm):not(.btn-lg):not(.btn-pill):not(.btn-pill-sm):not(.u-action):not(.btn-icon) {
72
+ display: inline-flex;
73
+ align-items: center;
74
+ justify-content: center;
75
+ min-height: var(--wui-control-height);
76
+ }
77
+
75
78
  .btn-primary {
76
- // Pin hover/active to the reference's `--accent-dark` (#2440C4).
77
- // Bootstrap's auto-shaded $primary would compute a slightly different
78
- // shade, drifting off-spec by a few hex points.
79
- --bs-btn-hover-bg: #2440C4;
80
- --bs-btn-hover-border-color: #2440C4;
81
- --bs-btn-active-bg: #2440C4;
82
- --bs-btn-active-border-color: #2440C4;
79
+ // Pin hover/active to the pressed-primary token so a rebrand tracks
80
+ // automatically instead of Bootstrap auto-shading $primary off-spec.
81
+ --bs-btn-hover-bg: var(--wui-primary-pressed);
82
+ --bs-btn-hover-border-color: var(--wui-primary-pressed);
83
+ --bs-btn-active-bg: var(--wui-primary-pressed);
84
+ --bs-btn-active-border-color: var(--wui-primary-pressed);
83
85
  &:active:not(:disabled) {
84
86
  transform: translateY(1px);
85
87
  }
@@ -139,17 +141,17 @@
139
141
  // (src/components/marketing/brand/watch-demo-button.tsx):
140
142
  // - border : rgba(13, 24, 43, 0.15) (foreground/15 in marketing-root)
141
143
  // - bg : rgba(255, 255, 255, 0.6) (surface/60)
142
- // - text : #0d182b (text-foreground in marketing-root)
144
+ // - text : --wui-text-heading (text-foreground in marketing-root)
143
145
  // - blur : 4px (backdrop-blur-sm)
144
146
  // - hover bg: #ffffff (hover:bg-surface = full opacity)
145
147
  .btn-ghost-dark {
146
- --bs-btn-color: #0d182b;
148
+ --bs-btn-color: var(--wui-text-heading);
147
149
  --bs-btn-bg: rgba(255, 255, 255, 0.60);
148
150
  --bs-btn-border-color: rgba(13, 24, 43, 0.15);
149
- --bs-btn-hover-color: #0d182b;
151
+ --bs-btn-hover-color: var(--wui-text-heading);
150
152
  --bs-btn-hover-bg: #ffffff;
151
153
  --bs-btn-hover-border-color: rgba(13, 24, 43, 0.20);
152
- --bs-btn-active-color: #0d182b;
154
+ --bs-btn-active-color: var(--wui-text-heading);
153
155
  --bs-btn-active-bg: #ffffff;
154
156
  --bs-btn-active-border-color: rgba(13, 24, 43, 0.20);
155
157
  backdrop-filter: blur(4px);
@@ -170,10 +172,10 @@
170
172
  }
171
173
 
172
174
 
173
- // ---- Inputs (Lumex canonical) ---------------------------------------
175
+ // ---- Inputs ---------------------------------------------------------
174
176
  // 5 locked states — default / hover / focus / disabled / error —
175
177
  // matching the reference `<Input>` component. Bootstrap drives the base
176
- // look via $input-* vars in _lumex-variables.scss; these blocks add the
178
+ // look via $input-* vars in _variables.scss; these blocks add the
177
179
  // hover-border-darken cue and the leading/trailing-slot wrapper.
178
180
  //
179
181
  // The error state is driven by `aria-invalid="true"` (NOT by Bootstrap's
@@ -219,16 +221,16 @@
219
221
  // / error states are visible regardless of which child has focus.
220
222
  //
221
223
  // Usage:
222
- // <div class="lumex-input-group">
223
- // <span class="lumex-input-leading"><i class="bi bi-currency-dollar"></i></span>
224
+ // <div class="wui-input-group">
225
+ // <span class="wui-input-leading"><i class="bi bi-currency-dollar"></i></span>
224
226
  // <input type="text" class="form-control" placeholder="0.00" />
225
227
  // </div>
226
228
  //
227
- // <div class="lumex-input-group">
229
+ // <div class="wui-input-group">
228
230
  // <input type="password" class="form-control" placeholder="Password" />
229
- // <button type="button" class="lumex-input-trailing"><i class="bi bi-eye"></i></button>
231
+ // <button type="button" class="wui-input-trailing"><i class="bi bi-eye"></i></button>
230
232
  // </div>
231
- .lumex-input-group {
233
+ .wui-input-group {
232
234
  display: flex;
233
235
  align-items: center;
234
236
  gap: 0.5rem;
@@ -236,30 +238,30 @@
236
238
  height: calc(2.5rem + 2px); // 40px box + 1px border each side
237
239
  background: var(--wui-bg-light, #FFFFFF);
238
240
  border: 1px solid var(--bs-border-color);
239
- border-radius: 0.625rem; // 10px — matches the bare input radius
241
+ border-radius: var(--radius); // matches the bare input radius
240
242
  transition: border-color 0.15s ease;
241
243
 
242
244
 
243
245
  }
244
- .lumex-input-group:hover:not(:focus-within):not(.is-disabled) {
246
+ .wui-input-group:hover:not(:focus-within):not(.is-disabled) {
245
247
  border-color: rgba(120, 130, 157, 0.6);
246
248
  }
247
- .lumex-input-group:focus-within {
248
- border-color: var(--wui-primary, #2F50E4);
249
+ .wui-input-group:focus-within {
250
+ border-color: var(--wui-primary);
249
251
  }
250
- .lumex-input-group.is-disabled,
251
- .lumex-input-group:has(input:disabled) {
252
- background: var(--wui-bg-muted, #F5F6FA);
252
+ .wui-input-group.is-disabled,
253
+ .wui-input-group:has(input:disabled) {
254
+ background: var(--wui-bg-muted);
253
255
  cursor: not-allowed;
254
256
  border-color: var(--bs-border-color);
255
257
  }
256
- .lumex-input-group.has-error,
257
- .lumex-input-group:has(input[aria-invalid="true"]) {
258
+ .wui-input-group.has-error,
259
+ .wui-input-group:has(input[aria-invalid="true"]) {
258
260
  border-color: var(--bs-danger);
259
261
  }
260
262
 
261
263
  // Strip the bare input's own chrome — the wrapper carries it all.
262
- .lumex-input-group > .form-control {
264
+ .wui-input-group > .form-control {
263
265
  flex: 1 1 auto;
264
266
  min-width: 0;
265
267
  height: 100%;
@@ -270,8 +272,8 @@
270
272
  box-shadow: none !important;
271
273
  border-radius: 0;
272
274
  }
273
- .lumex-input-group > .form-control:focus,
274
- .lumex-input-group > .form-control:hover {
275
+ .wui-input-group > .form-control:focus,
276
+ .wui-input-group > .form-control:hover {
275
277
  border: 0;
276
278
  box-shadow: none !important;
277
279
  background: transparent;
@@ -279,12 +281,12 @@
279
281
 
280
282
  // Leading + trailing slots — flex children that hold icons or buttons.
281
283
  // Default muted color, inherits hover/focus state from the wrapper.
282
- .lumex-input-leading,
283
- .lumex-input-trailing {
284
+ .wui-input-leading,
285
+ .wui-input-trailing {
284
286
  display: inline-flex;
285
287
  align-items: center;
286
288
  justify-content: center;
287
- color: var(--wui-text-3, #78829D);
289
+ color: var(--wui-text-3);
288
290
  flex-shrink: 0;
289
291
  font-size: 1rem;
290
292
  line-height: 1;
@@ -293,8 +295,8 @@
293
295
 
294
296
  // When the trailing slot is a button (clear, toggle, etc.), reset
295
297
  // button chrome and re-enable pointer events.
296
- button.lumex-input-trailing,
297
- button.lumex-input-leading {
298
+ button.wui-input-trailing,
299
+ button.wui-input-leading {
298
300
  background: transparent;
299
301
  border: 0;
300
302
  padding: 0;
@@ -302,12 +304,12 @@ button.lumex-input-leading {
302
304
  cursor: pointer;
303
305
  transition: color 0.15s ease;
304
306
  }
305
- button.lumex-input-trailing:hover,
306
- button.lumex-input-leading:hover {
307
- color: var(--wui-text-1, #252F4A);
307
+ button.wui-input-trailing:hover,
308
+ button.wui-input-leading:hover {
309
+ color: var(--wui-text-1);
308
310
  }
309
- button.lumex-input-trailing:focus-visible,
310
- button.lumex-input-leading:focus-visible {
311
+ button.wui-input-trailing:focus-visible,
312
+ button.wui-input-leading:focus-visible {
311
313
  outline: none;
312
314
  color: var(--wui-primary);
313
315
  border-radius: 9999px;
@@ -356,38 +358,15 @@ button.lumex-input-leading:focus-visible {
356
358
 
357
359
 
358
360
  // ---- Squircle corners (iOS-style) -----------------------------------
359
- // `corner-shape: squircle` renders a smoother continuous curve instead
360
- // of a simple circular arc — the same effect iOS app icons use. Mirrors
361
- // the locked design's global `* { corner-shape: squircle }` rule.
362
- // Browser support: Chrome 138+ and Safari 16+ with -webkit- prefix.
363
- // Older browsers ignore the property and fall back to standard
364
- // border-radius — no breakage.
365
- //
366
- // Apply by default to EVERY element, then explicitly opt
367
- // `.rounded-circle` and `.rounded-pill` back to `round` — squircle on
368
- // a 50% / 9999px radius reads as a subtly rounded square rather than a
369
- // true circle/pill.
370
- * {
371
-
372
-
373
- }
374
- .rounded-circle,
375
- .rounded-pill {
376
-
377
-
378
- }
379
-
380
- // Named opt-in utilities — preserved for places where authors want a
381
- // specific squircle radius without relying on Bootstrap's $border-radius.
361
+ // Named opt-in utilities for a specific squircle radius without relying
362
+ // on Bootstrap's $border-radius. A consuming product can layer a global
363
+ // `corner-shape: squircle` rule on top (Chrome 138+ / Safari 16+; older
364
+ // browsers fall back to the plain border-radius — no breakage).
382
365
  .btn-squircle {
383
366
  border-radius: 16px;
384
-
385
-
386
367
  }
387
368
  .rounded-squircle {
388
369
  border-radius: 32px;
389
-
390
-
391
370
  }
392
371
 
393
372
 
@@ -396,7 +375,7 @@ button.lumex-input-leading:focus-visible {
396
375
  .hero-wash {
397
376
  background:
398
377
  radial-gradient(80% 50% at 50% 0%,
399
- rgba(47, 80, 228, 0.08), transparent 70%),
378
+ color-mix(in srgb, var(--wui-primary) 8%, transparent), transparent 70%),
400
379
  var(--wui-bg-elevated);
401
380
  }
402
381
 
@@ -592,7 +571,7 @@ body {
592
571
  }
593
572
  * {
594
573
  scrollbar-width: thin;
595
- scrollbar-color: rgba(145, 158, 171, 0.45) transparent;
574
+ scrollbar-color: var(--wui-scrollbar) transparent;
596
575
  }
597
576
  *::-webkit-scrollbar {
598
577
  width: 8px;
@@ -602,7 +581,7 @@ body {
602
581
  background: transparent;
603
582
  }
604
583
  *::-webkit-scrollbar-thumb {
605
- background-color: rgba(145, 158, 171, 0.45);
584
+ background-color: var(--wui-scrollbar);
606
585
  border-radius: 9999px;
607
586
  border: 2px solid transparent;
608
587
  background-clip: padding-box;
@@ -611,11 +590,11 @@ body {
611
590
  transition: background-color 220ms ease;
612
591
  }
613
592
  *::-webkit-scrollbar-thumb:hover {
614
- background-color: rgba(145, 158, 171, 0.65);
593
+ background-color: var(--wui-scrollbar-hover);
615
594
  background-clip: padding-box;
616
595
  }
617
596
  *::-webkit-scrollbar-thumb:active {
618
- background-color: rgba(145, 158, 171, 0.85);
597
+ background-color: var(--wui-scrollbar-active);
619
598
  background-clip: padding-box;
620
599
  }
621
600
  *::-webkit-scrollbar-corner {
@@ -625,10 +604,10 @@ body {
625
604
  // While the page is actively scrolling, give the thumb a slight extra
626
605
  // pop so the user can track its position more easily.
627
606
  html.is-scrolling * {
628
- scrollbar-color: rgba(145, 158, 171, 0.65) transparent;
607
+ scrollbar-color: var(--wui-scrollbar-hover) transparent;
629
608
  }
630
609
  html.is-scrolling *::-webkit-scrollbar-thumb {
631
- background-color: rgba(145, 158, 171, 0.65);
610
+ background-color: var(--wui-scrollbar-hover);
632
611
  }
633
612
 
634
613
  // Utility: completely hide a scrollbar (e.g., for marquee/horizontal