@webority/theme 0.8.4 → 0.8.5

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.4",
3
+ "version": "0.8.5",
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, 22px squircle radius, 45px tall.
173
+ // Medium (default): 15px / 600, 24px side padding, 18px squircle radius, 45px tall.
174
174
  .btn {
175
- --bs-btn-border-radius: 22px;
175
+ --bs-btn-border-radius: 18px;
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, 17px squircle radius (proportional to md), 35px tall.
183
+ // Small: 14px, 18px side padding, 14px 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: 17px;
186
+ --bs-btn-border-radius: 14px;
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, 27px squircle radius (proportional to md), 55px tall — a spacious CTA.
194
+ // Large: 17px, 32px side padding, 22px 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: 27px;
197
+ --bs-btn-border-radius: 22px;
198
198
  --bs-btn-font-size: 1.0625rem;
199
199
  --bs-btn-padding-x: 2rem;
200
200
  display: inline-flex;
package/scss/_tokens.scss CHANGED
@@ -195,6 +195,14 @@
195
195
  --wui-radius-lg: 14px;
196
196
  --wui-radius-xl: 16px;
197
197
 
198
+ // Field (input/select/datepicker/…) radius — a rounder squircle than the
199
+ // generic radius ladder, matched to the button radius language. md is 18px;
200
+ // sm/lg step with the control height (36/44/52px → ~0.41 ratio) so every
201
+ // field size keeps a proportional corner.
202
+ --wui-field-radius: 18px;
203
+ --wui-field-radius-sm: 15px;
204
+ --wui-field-radius-lg: 21px;
205
+
198
206
  // ---- Portal dark palette ----------------------------------------
199
207
  // Marketing stays light. Portal flips [data-theme="dark"] and maps
200
208
  // --color-* aliases onto these so dark hexes live in theme/, not the app.
@@ -203,11 +203,13 @@
203
203
  height: var(--wui-control-height-sm);
204
204
  min-height: var(--wui-control-height-sm);
205
205
  font-size: 13px;
206
+ border-radius: var(--wui-field-radius-sm);
206
207
  }
207
208
  .search-select-lg .search-select-control {
208
209
  height: var(--wui-control-height-lg);
209
210
  min-height: var(--wui-control-height-lg);
210
211
  font-size: 16px;
212
+ border-radius: var(--wui-field-radius-lg);
211
213
  }
212
214
  // Multi-select grows with its chips, so a size sets the FLOOR (min-height from the rule
213
215
  // above) but never a fixed height — reset height:auto so a second row of chips can appear.
@@ -255,7 +255,8 @@
255
255
  width: 100%;
256
256
  height: var(--wui-control-height);
257
257
  padding: 12px;
258
- border-radius: var(--radius);
258
+ border-radius: var(--wui-field-radius);
259
+ corner-shape: squircle;
259
260
  border: 1px solid var(--color-border);
260
261
  background: var(--color-bg-muted);
261
262
  font-size: 14px;
@@ -274,12 +275,14 @@
274
275
  height: var(--wui-control-height-sm);
275
276
  padding: 6px 10px;
276
277
  font-size: 13px;
278
+ border-radius: var(--wui-field-radius-sm);
277
279
  }
278
280
  .form-control-lg,
279
281
  .input-lg {
280
282
  height: var(--wui-control-height-lg);
281
283
  padding: 14px 16px;
282
284
  font-size: 16px;
285
+ border-radius: var(--wui-field-radius-lg);
283
286
  }
284
287
  .textarea,
285
288
  textarea.form-control {
@@ -420,7 +423,12 @@ textarea.form-control.autosize {
420
423
  .field-error {
421
424
  font-size: 12px;
422
425
  line-height: normal;
426
+ // Must clear AA against the surface: --color-danger-active (#E82646) is 4.38:1 at this
427
+ // 12px size, under the 4.5:1 floor the a11y gate enforces.
423
428
  color: var(--color-danger-text);
429
+ // Tighten the space above the message: .field's 4px gap → effective 2px, without
430
+ // touching the label→control gap.
431
+ margin-top: -2px;
424
432
  }
425
433
 
426
434
  // Native select with a rounded squircle, custom chevron, off-surface fill.
@@ -675,7 +683,8 @@ textarea.form-control.autosize {
675
683
  align-items: stretch;
676
684
  width: 100%;
677
685
  border: 1px solid var(--color-border);
678
- border-radius: var(--radius);
686
+ border-radius: var(--wui-field-radius);
687
+ corner-shape: squircle;
679
688
  // Soft-filled at rest, white on focus — one shared fill for the whole control so the
680
689
  // prefix/suffix and the input body are always the SAME colour combination as the field.
681
690
  background: var(--color-bg-muted);
@@ -714,11 +723,11 @@ textarea.form-control.autosize {
714
723
  }
715
724
  .input-affixed .affix-pre {
716
725
  border-right: 1px solid var(--color-border);
717
- border-radius: var(--radius) 0 0 var(--radius);
726
+ border-radius: var(--wui-field-radius) 0 0 var(--wui-field-radius);
718
727
  }
719
728
  .input-affixed .affix-suf {
720
729
  border-left: 1px solid var(--color-border);
721
- border-radius: 0 var(--radius) var(--radius) 0;
730
+ border-radius: 0 var(--wui-field-radius) var(--wui-field-radius) 0;
722
731
  }
723
732
 
724
733
  // Floating label — the label starts centred as the placeholder, then slides up and shrinks
@@ -831,12 +840,14 @@ textarea.form-control.autosize {
831
840
  color: var(--color-text-subtle);
832
841
  }
833
842
  .required {
843
+ // AA against the surface — see .field-error; --color-danger-active is 4.38:1.
834
844
  color: var(--color-danger-text);
835
845
  // The gap is CSS, not a significant space in the markup. RequiredMark used to render
836
846
  // `{' '}*` while AppDatePicker and every Razor helper rendered a bare `*`, so the same
837
847
  // asterisk sat 4px further out in some fields than others — and no check could see it,
838
- // because HTML comparison collapses whitespace by design.
839
- margin-inline-start: 0.25em;
848
+ // because HTML comparison collapses whitespace by design. Gap removed — the star sits
849
+ // flush against the label.
850
+ margin-inline-start: 0;
840
851
  }
841
852
  .field {
842
853
  display: flex;
@@ -942,7 +953,7 @@ wui-select[compact] {
942
953
  display: flex;
943
954
  align-items: stretch;
944
955
  border: 1px solid var(--color-border);
945
- border-radius: var(--radius-lg);
956
+ border-radius: var(--wui-field-radius);
946
957
  corner-shape: squircle;
947
958
  // Soft-filled at rest, white on focus — the numeric input and its unit pill share the
948
959
  // one wrapper fill, same colour combination as every other field.
@@ -182,6 +182,19 @@
182
182
  color 0.12s ease,
183
183
  border-color 0.12s ease;
184
184
  }
185
+ // Leading icon / image — sit before the label with the strip's 8px gap (from .app-tab).
186
+ // The library Icon sizes itself; a custom <img> is constrained to a small rounded square
187
+ // (product logo / avatar). Both never shrink when the label truncates.
188
+ .app-tab-icon {
189
+ flex-shrink: 0;
190
+ }
191
+ .app-tab-img {
192
+ flex-shrink: 0;
193
+ width: 18px;
194
+ height: 18px;
195
+ object-fit: cover;
196
+ border-radius: var(--radius-sm);
197
+ }
185
198
  .app-tab:hover:not(:disabled):not(.active) {
186
199
  color: var(--color-text);
187
200
  }
@@ -296,10 +309,18 @@
296
309
  gap: 6px;
297
310
  font-size: 13px;
298
311
  }
312
+ .app-tabs-sm .app-tab-img {
313
+ width: 16px;
314
+ height: 16px;
315
+ }
299
316
  .app-tabs-lg .app-tab {
300
317
  padding: 14px 18px;
301
318
  font-size: 15px;
302
319
  }
320
+ .app-tabs-lg .app-tab-img {
321
+ width: 20px;
322
+ height: 20px;
323
+ }
303
324
 
304
325
  // ── Fitted: tabs share the width equally (no scroll). ──
305
326
  .app-tabs-fitted .app-tab {
@@ -395,6 +395,65 @@
395
395
  box-shadow: var(--wui-tooltip-shadow);
396
396
  }
397
397
 
398
+ // ── CSS-only tooltip ──────────────────────────────────────────────────────────────────
399
+ // Any element carrying `data-wui-tip="…"` grows a hover/focus bubble reusing the AppTooltip
400
+ // surface look — no JS, no Popper, instant, and identical on React and Razor by construction.
401
+ // It sits above the element; for a collision-aware / richer tooltip, use AppTooltip /
402
+ // <app-tooltip> instead.
403
+ //
404
+ // Two users, for different reasons:
405
+ // - `.wui-icon-tip`, the wrapper the `tooltip` prop on AppIcon / <app-icon> puts around a
406
+ // glyph (it adds the inline-flex layout below).
407
+ // - <app-tabs> tab buttons, which CANNOT use a Bootstrap tooltip: the button already owns a
408
+ // `bs.tab` instance and Bootstrap permits only one instance per element, so binding
409
+ // `bs.Tooltip` to it logs "Bootstrap doesn't allow more than one instance per element"
410
+ // and the tab instance is never registered.
411
+ [data-wui-tip] {
412
+ position: relative;
413
+ }
414
+ .wui-icon-tip {
415
+ display: inline-flex;
416
+ vertical-align: -0.125em;
417
+ }
418
+ [data-wui-tip]::after {
419
+ content: attr(data-wui-tip);
420
+ position: absolute;
421
+ bottom: calc(100% + 8px);
422
+ left: 50%;
423
+ transform: translateX(-50%);
424
+ z-index: var(--wui-z-menu, 1080);
425
+ width: max-content;
426
+ max-width: 240px;
427
+ padding: 7px 11px;
428
+ border-radius: var(--radius, 10px);
429
+ corner-shape: squircle;
430
+ background: var(--color-surface);
431
+ color: var(--color-text);
432
+ border: 1px solid var(--color-border-light);
433
+ box-shadow: var(--wui-shadow-overlay);
434
+ font-size: 0.8125rem;
435
+ font-weight: 500;
436
+ line-height: 1.4;
437
+ text-align: left;
438
+ white-space: normal;
439
+ pointer-events: none;
440
+ opacity: 0;
441
+ visibility: hidden;
442
+ transition:
443
+ opacity 0.12s ease,
444
+ visibility 0.12s;
445
+ }
446
+ [data-wui-tip]:hover::after,
447
+ [data-wui-tip]:focus-visible::after {
448
+ opacity: 1;
449
+ visibility: visible;
450
+ }
451
+ @media (prefers-reduced-motion: reduce) {
452
+ [data-wui-tip]::after {
453
+ transition: none;
454
+ }
455
+ }
456
+
398
457
  // Size presets — swap the four size vars. `md` is the :where default (no class).
399
458
  .tooltip.wui-tooltip.size-sm {
400
459
  --wui-tooltip-max-width: 200px;
@@ -595,7 +595,7 @@
595
595
  border: 1px solid var(--callout-border);
596
596
  // A thick coloured left edge — the callout's signature aside marker.
597
597
  border-left: 4px solid var(--callout-accent);
598
- border-radius: var(--radius-lg);
598
+ border-radius: 20px;
599
599
  corner-shape: squircle;
600
600
  background: var(--callout-bg);
601
601
  font-size: 14px;
@@ -624,6 +624,14 @@
624
624
  --callout-bg: var(--color-danger-10);
625
625
  }
626
626
 
627
+ // Borderless variant (`bordered={false}` / `bordered="false"`): drop the soft ring AND
628
+ // the thick tone-coloured left edge, keeping only the tint fill. Colours go `transparent`
629
+ // rather than the widths to 0 so the box keeps its 1px / 4px-left footprint — nothing
630
+ // shifts when toggling the border on and off. Mirrors `.alert-borderless`.
631
+ .info-callout-borderless {
632
+ border-color: transparent;
633
+ }
634
+
627
635
  // The leading glyph is a solid circular badge — tone fill, white glyph centred, with a
628
636
  // soft 3px same-colour halo ring. Base is the single-content size (20px badge / 20px
629
637
  // glyph); a title+body stack steps it up to 24px. The badge stays VERTICALLY CENTRED
@@ -723,7 +731,9 @@
723
731
  // the heading to the variant. Only the heading takes the variant colour — the body
724
732
  // stays dark ink so the message reads calmly.
725
733
  .alert {
726
- --bs-alert-border-radius: var(--wui-radius-lg);
734
+ --bs-alert-border-radius: 20px;
735
+ border-radius: 20px;
736
+ corner-shape: squircle;
727
737
  padding: 16px 18px;
728
738
  border-width: 1px;
729
739
  }