@webority/theme 0.102.3 → 0.103.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.102.3",
3
+ "version": "0.103.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,7 +51,7 @@
51
51
  "country-flag-icons": "^1.6.20",
52
52
  "sass-embedded": "^1.97.0",
53
53
  "vite": "^8.0.12",
54
- "@webority/tokens": "0.102.3"
54
+ "@webority/tokens": "0.103.0"
55
55
  },
56
56
  "scripts": {
57
57
  "tokens": "node ../tokens/dist/webority.js brand --library --out ../tokens/dist --web scss/_tokens.generated.scss",
@@ -1,4 +1,4 @@
1
- // Generated by @webority/tokens 0.102.3 from its token source. Do not edit; run webority brand --library.
1
+ // Generated by @webority/tokens 0.103.0 from its token source. Do not edit; run webority brand --library.
2
2
  $body-color: #252f4a !default;
3
3
  $body-secondary-color: #4b5675 !default;
4
4
  $body-tertiary-color: #626a82 !default;
@@ -625,6 +625,15 @@
625
625
  scrollbar-color: var(--wui-scrollbar) transparent;
626
626
  }
627
627
  }
628
+ // AppDropdown menuWidth: a fixed menu width, so long rows wrap instead of widening the menu.
629
+ .wui-dropdown-menu-sm { width: 15rem; }
630
+ .wui-dropdown-menu-md { width: 20rem; }
631
+ .wui-dropdown-menu-lg { width: 25rem; }
632
+ .wui-dropdown-menu-sm .dropdown-item,
633
+ .wui-dropdown-menu-md .dropdown-item,
634
+ .wui-dropdown-menu-lg .dropdown-item {
635
+ white-space: normal;
636
+ }
628
637
 
629
638
  .dropdown-item {
630
639
  display: flex;
@@ -669,6 +678,15 @@
669
678
  }
670
679
  }
671
680
 
681
+ // Listed but unchoosable (AppDropdown disabled): quiet, no hover or press tint.
682
+ .dropdown-item.wui-dropdown-item-disabled,
683
+ .dropdown-item.wui-dropdown-item-disabled:hover,
684
+ .dropdown-item.wui-dropdown-item-disabled:active {
685
+ color: var(--color-text-subtle);
686
+ cursor: not-allowed;
687
+ background: transparent;
688
+ }
689
+
672
690
  // The form of a posting dropdown item takes no box, so its item stays a plain row of the menu.
673
691
  .wui-dropdown-form {
674
692
  display: contents;
@@ -1,4 +1,4 @@
1
- // Generated by @webority/tokens 0.102.3 from its token source. Do not edit; run webority brand --library.
1
+ // Generated by @webority/tokens 0.103.0 from its token source. Do not edit; run webority brand --library.
2
2
 
3
3
  :root {
4
4
  --wui-primary: #4F46E5;
@@ -28,11 +28,11 @@
28
28
  outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
29
29
  outline-offset: var(--wui-focus-ring-offset);
30
30
  }
31
- .struct-card.checked {
31
+ .struct-card:has(.struct-card-input:checked) {
32
32
  border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
33
33
  background: color-mix(in srgb, var(--color-primary) 5%, transparent);
34
34
  }
35
- .struct-card.checked .struct-card-title {
35
+ .struct-card:has(.struct-card-input:checked) .struct-card-title {
36
36
  color: var(--color-primary-text);
37
37
  }
38
38
 
@@ -44,7 +44,7 @@
44
44
  .struct-card:has(.struct-card-input:disabled):hover {
45
45
  border-color: var(--color-border);
46
46
  }
47
- .struct-card.checked:has(.struct-card-input:disabled):hover {
47
+ .struct-card:has(.struct-card-input:checked):has(.struct-card-input:disabled):hover {
48
48
  border-color: color-mix(in srgb, var(--color-primary) 30%, transparent);
49
49
  }
50
50
  .struct-card:has(.struct-card-input:disabled):active {
@@ -69,10 +69,20 @@
69
69
  background 0.12s,
70
70
  color 0.12s;
71
71
  }
72
- .struct-card.checked .struct-card-ic {
72
+ .struct-card:has(.struct-card-input:checked) .struct-card-ic {
73
73
  background: var(--color-surface);
74
74
  color: var(--color-primary-text);
75
75
  }
76
+ // The linear and bold glyphs are both rendered; the input's checked state picks one.
77
+ .wui-struct-card-glyph-on {
78
+ display: none;
79
+ }
80
+ .struct-card:has(.struct-card-input:checked) .wui-struct-card-glyph {
81
+ display: none;
82
+ }
83
+ .struct-card:has(.struct-card-input:checked) .wui-struct-card-glyph-on {
84
+ display: inline-flex;
85
+ }
76
86
  // Hover previews the chosen glyph colour; a card that cannot change keeps its grey.
77
87
  .struct-card:hover:not(:has(.struct-card-input:disabled)) .struct-card-ic {
78
88
  color: var(--color-primary-text);
@@ -118,7 +128,7 @@
118
128
  opacity 0.12s ease,
119
129
  transform 0.12s ease;
120
130
  }
121
- .struct-card.checked .struct-card-check {
131
+ .struct-card:has(.struct-card-input:checked) .struct-card-check {
122
132
  opacity: 1;
123
133
  transform: scale(1);
124
134
  }
@@ -211,7 +221,7 @@
211
221
  }
212
222
  // Drop the icon disc — the illustration stands on its own, sized large.
213
223
  .struct-card-tile .struct-card-ic,
214
- .struct-card-tile.checked .struct-card-ic {
224
+ .struct-card-tile:has(.struct-card-input:checked) .struct-card-ic {
215
225
  width: auto;
216
226
  height: auto;
217
227
  border-radius: 0;
@@ -1723,6 +1723,17 @@ wui-select[compact] {
1723
1723
  background: var(--color-surface);
1724
1724
  color: var(--color-primary-text);
1725
1725
  }
1726
+ // variant="solid": the checked chip fills with primary and its count turns a translucent on-primary pill.
1727
+ .wui-choice-chip-solid:has(input:checked),
1728
+ .wui-choice-chip-solid:has(input:checked):hover {
1729
+ border-color: transparent;
1730
+ background: var(--color-primary);
1731
+ color: var(--color-on-primary);
1732
+ }
1733
+ .wui-choice-chip-solid:has(input:checked) .count {
1734
+ background: color-mix(in srgb, var(--color-on-primary) 22%, transparent);
1735
+ color: inherit;
1736
+ }
1726
1737
 
1727
1738
  // Size scale (`size`): height, padding, gap and font step together; md is the base above.
1728
1739
  .choice-chip-sm {
@@ -1380,6 +1380,14 @@
1380
1380
  background: color-mix(in srgb, var(--color-danger) 10%, transparent);
1381
1381
  color: var(--color-danger-text);
1382
1382
  }
1383
+ // A neutral action: muted ink at rest, a muted surface and body ink on hover (an action on a card or a quiet surface).
1384
+ .u-action.neutral {
1385
+ color: var(--color-text-muted);
1386
+ }
1387
+ .u-action.neutral:hover:not(:disabled) {
1388
+ background: var(--color-bg-muted);
1389
+ color: var(--color-text);
1390
+ }
1383
1391
  .u-action.u-action-preview {
1384
1392
  background: var(--color-primary-soft);
1385
1393
  color: var(--color-primary-text);
@@ -318,6 +318,45 @@
318
318
  }
319
319
  }
320
320
 
321
+ // The back arrow before a modal's title: the close button's size, shape and colours, on the start side.
322
+ .wui-modal-back {
323
+ margin-inline-end: var(--wui-space-xs);
324
+ display: grid;
325
+ place-items: center;
326
+ flex: none;
327
+ width: var(--wui-control-md);
328
+ height: var(--wui-control-md);
329
+ padding: 0;
330
+ border: none;
331
+ cursor: pointer;
332
+ background: var(--color-bg-subtle);
333
+ color: var(--color-text-muted);
334
+ border-radius: var(--wui-radius-lg);
335
+ corner-shape: squircle;
336
+ transition:
337
+ background 180ms cubic-bezier(0.4, 0, 0.2, 1),
338
+ color 180ms cubic-bezier(0.4, 0, 0.2, 1);
339
+ }
340
+ .wui-modal-back:hover {
341
+ background: var(--color-bg-muted);
342
+ color: var(--color-text);
343
+ transition:
344
+ background 280ms cubic-bezier(0.16, 1, 0.3, 1),
345
+ color 280ms cubic-bezier(0.16, 1, 0.3, 1);
346
+ }
347
+ .wui-modal-back:focus-visible {
348
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
349
+ outline-offset: var(--wui-focus-ring-offset);
350
+ }
351
+ @media (prefers-reduced-motion: reduce) {
352
+ .wui-modal-back,
353
+ .wui-modal-back:hover {
354
+ transition:
355
+ background 1ms linear,
356
+ color 1ms linear;
357
+ }
358
+ }
359
+
321
360
  // Fullscreen size: the card is the whole viewport. Both surfaces put `wui-modal-fullscreen` on the
322
361
  // `.modal` shell (Razor's size="fullscreen", React's size="fullscreen"); neither sets a max-width.
323
362
  // Header and footer are flex: none, so they stay pinned while the body scrolls between them, and
@@ -360,23 +360,71 @@
360
360
  // the brand row and needs none.
361
361
  .app-nav-group + .app-nav-group {
362
362
  margin-top: 20px;
363
- padding-top: 12px;
363
+ padding-top: var(--wui-space-md);
364
364
  border-top: 1px solid var(--color-border);
365
365
  }
366
366
  // A node the author places right after a group's links (`groups[].after` /
367
367
  // `<app-nav-group-after>`). Like sidebarStart it has no place on the 88px rail.
368
368
  .wui-nav-group-after {
369
369
  flex: none;
370
- margin-top: 4px;
370
+ margin-top: var(--wui-space-xs);
371
371
  }
372
372
  .app-nav-group-label {
373
373
  padding: 6px 14px;
374
374
  font-size: 12px;
375
- font-weight: 600;
375
+ font-weight: var(--wui-fw-semibold);
376
376
  text-transform: uppercase;
377
377
  letter-spacing: 0.06em;
378
378
  color: var(--color-text-subtle);
379
379
  }
380
+ // A collapsible group folds from this heading: the label's type on a full-width row, with the caret at the end.
381
+ .wui-nav-group-toggle {
382
+ display: flex;
383
+ align-items: center;
384
+ justify-content: space-between;
385
+ gap: var(--wui-space-sm);
386
+ width: 100%;
387
+ margin: 0;
388
+ padding: 6px 14px;
389
+ border: 0;
390
+ border-radius: var(--wui-radius-sm);
391
+ background: transparent;
392
+ font-family: inherit;
393
+ font-size: 12px;
394
+ font-weight: var(--wui-fw-semibold);
395
+ text-align: left;
396
+ text-transform: uppercase;
397
+ letter-spacing: 0.06em;
398
+ color: var(--color-text-subtle);
399
+ cursor: pointer;
400
+ }
401
+ .wui-nav-group-toggle:focus-visible {
402
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
403
+ outline-offset: var(--wui-focus-ring-inset);
404
+ }
405
+ .wui-nav-group-collapsible,
406
+ .wui-nav-group-text {
407
+ min-width: 0;
408
+ }
409
+ .wui-nav-group-caret {
410
+ flex: none;
411
+ display: inline-grid;
412
+ place-items: center;
413
+ transition: transform 0.2s var(--wui-ease-ui);
414
+ }
415
+ .wui-nav-group-folded > .wui-nav-group-toggle .wui-nav-group-caret {
416
+ transform: rotate(-90deg);
417
+ }
418
+ .app-shell:not(.collapsed) .wui-nav-group-folded > .wui-nav-group-body {
419
+ display: none;
420
+ }
421
+ // A sub-heading between runs of links inside a group.
422
+ .wui-nav-header {
423
+ padding: 6px 10px 2px 12px;
424
+ font-size: var(--wui-fs-xs);
425
+ font-weight: var(--wui-fw-semibold);
426
+ color: var(--color-text-subtle);
427
+ }
380
428
 
381
429
  .app-nav-item {
382
430
  position: relative;
@@ -474,6 +522,8 @@
474
522
  }
475
523
  .app-shell.collapsed .app-nav-badge,
476
524
  .app-shell.collapsed .app-nav-group-label,
525
+ .app-shell.collapsed .wui-nav-group-toggle,
526
+ .app-shell.collapsed .wui-nav-header,
477
527
  .app-shell.collapsed .wui-nav-group-after,
478
528
  .app-shell.collapsed .app-sidebar-brand-text,
479
529
  .app-shell.collapsed .app-sidebar-start {
@@ -919,10 +969,18 @@
919
969
  .app-shell.app-shell.collapsed .app-nav-text,
920
970
  .app-shell.app-shell.collapsed .app-nav-badge,
921
971
  .app-shell.app-shell.collapsed .app-nav-group-label,
972
+ .app-shell.app-shell.collapsed .wui-nav-header,
922
973
  .app-shell.app-shell.collapsed .wui-nav-group-after,
923
974
  .app-shell.app-shell.collapsed .app-sidebar-start {
924
975
  display: revert;
925
976
  }
977
+ // The drawer shows full labels even on the desktop collapsed state, so a folded group still folds here.
978
+ .app-shell.app-shell.collapsed .wui-nav-group-toggle {
979
+ display: flex;
980
+ }
981
+ .app-shell.app-shell.collapsed .wui-nav-group-folded > .wui-nav-group-body {
982
+ display: none;
983
+ }
926
984
  // Drawer always shows full labels — the compact rail control has no role here.
927
985
  .app-shell.app-shell.collapsed .app-sidebar-start-compact {
928
986
  display: none;
@@ -273,6 +273,16 @@
273
273
  color: currentColor;
274
274
  }
275
275
 
276
+ // A pressed toggle chip (aria-pressed="true" on its button) takes the primary look whatever its tone,
277
+ // so a script flips the look by flipping the attribute it already sets for screen readers.
278
+ .chip-clickable:has(> .chip-body[aria-pressed="true"]) {
279
+ @include wui-tone-pill-colors(primary, var(--color-primary-text));
280
+ }
281
+ .chip-clickable:has(> .chip-body[aria-pressed="true"]) .chip-ic,
282
+ .chip-clickable:has(> .chip-body[aria-pressed="true"]) .chip-remove {
283
+ color: currentColor;
284
+ }
285
+
276
286
  // Disabled — deliberately NOT opacity, and deliberately after the tones.
277
287
  //
278
288
  // `opacity: .55` fades the whole chip, label included, so a faded label can fall under the
@@ -441,6 +441,41 @@
441
441
  outline-offset: var(--wui-focus-ring-offset);
442
442
  border-radius: var(--wui-radius-sm);
443
443
  }
444
+ // AppDropdown toggleVariant="neutral": a custom trigger that keeps the surrounding font and colour, with a muted
445
+ // surface on hover and while open. The negative start margin keeps its text aligned with the text above it.
446
+ .wui-dropdown-trigger-neutral {
447
+ gap: var(--wui-space-xs);
448
+ margin-inline-start: calc(-1 * var(--wui-space-xs));
449
+ padding: var(--wui-space-xxs) var(--wui-space-xs);
450
+ border-radius: var(--wui-radius-sm);
451
+ transition: background 0.12s ease;
452
+ }
453
+ .wui-dropdown-trigger-neutral:hover,
454
+ .wui-dropdown-trigger-neutral[aria-expanded="true"] {
455
+ background: var(--color-bg-muted);
456
+ }
457
+
458
+ // A line of short facts ("1 Oct to 14 Oct . 3 days left . 4/9 Done"): muted small text, a 3px dot (the dot's own size) drawn between items.
459
+ // The dot is a pseudo-element, so screen readers never read it and no separator markup is written.
460
+ .wui-meta-list {
461
+ display: inline-flex;
462
+ align-items: center;
463
+ gap: var(--wui-space-sm);
464
+ font-size: var(--wui-fs-sm);
465
+ color: var(--color-text-muted);
466
+ white-space: nowrap;
467
+ }
468
+ .wui-meta-list > * + *::before {
469
+ content: "";
470
+ display: inline-block;
471
+ width: 3px;
472
+ height: 3px;
473
+ margin-inline-end: var(--wui-space-sm);
474
+ border-radius: 50%;
475
+ background: var(--color-text-muted);
476
+ opacity: 0.6;
477
+ vertical-align: middle;
478
+ }
444
479
 
445
480
  // AppPopover wrapper (React panel styling comes from Bootstrap's .popover; this is only the
446
481
  // Razor anchor span carrying the data-bs-* wiring). inline-block so it hugs its trigger and