@webority/theme 0.9.6 → 0.9.8
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/dist/webority-theme.css +1 -1
- package/package.json +1 -1
- package/scss/_components.scss +22 -0
- package/scss/wui/_choice.scss +8 -0
- package/scss/wui/_controls.scss +20 -0
- package/scss/wui/_data.scss +34 -0
- package/scss/wui/_overlays.scss +13 -0
- package/scss/wui/_utilities.scss +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/theme",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.8",
|
|
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": {
|
package/scss/_components.scss
CHANGED
|
@@ -58,6 +58,28 @@
|
|
|
58
58
|
--bs-btn-active-border-color: transparent;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
// A soft-tinted affirmative — the success counterpart of .btn-secondary. Dark success text on a
|
|
62
|
+
// faint success fill, so it reads as "resolved / confirmed" without the weight of a solid green.
|
|
63
|
+
.btn-success {
|
|
64
|
+
--bs-btn-color: var(--color-success-text);
|
|
65
|
+
--bs-btn-bg: color-mix(in srgb, var(--color-success) 14%, transparent);
|
|
66
|
+
--bs-btn-border-color: transparent;
|
|
67
|
+
--bs-btn-hover-color: var(--color-success-text);
|
|
68
|
+
--bs-btn-hover-bg: color-mix(in srgb, var(--color-success) 20%, transparent);
|
|
69
|
+
--bs-btn-hover-border-color: transparent;
|
|
70
|
+
--bs-btn-active-color: var(--color-success-text);
|
|
71
|
+
--bs-btn-active-bg: color-mix(in srgb, var(--color-success) 28%, transparent);
|
|
72
|
+
--bs-btn-active-border-color: transparent;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// A button-shaped label that does nothing: keeps the .btn chrome but takes no pointer, so it
|
|
76
|
+
// neither clicks nor lifts on hover. Used for a resolved confirmation (AppButton `static`) that
|
|
77
|
+
// must sit exactly where its action button was.
|
|
78
|
+
.btn-static {
|
|
79
|
+
cursor: default;
|
|
80
|
+
pointer-events: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
61
83
|
.btn-danger {
|
|
62
84
|
// White-on-red destructive look via the --wui-danger-strong token: white fails AA on the
|
|
63
85
|
// brighter danger fills (#F8285A → 3.86:1, #E82646 → 4.38:1), so the button uses the
|
package/scss/wui/_choice.scss
CHANGED
|
@@ -943,6 +943,14 @@ button.datepicker-month:hover {
|
|
|
943
943
|
// Match AppInput's soft invalid border exactly (danger at 30%, mirroring primary-30 focus).
|
|
944
944
|
border-color: color-mix(in srgb, var(--color-danger) 30%, transparent);
|
|
945
945
|
}
|
|
946
|
+
// The live-validation error renders INSIDE <wui-phone> (after .phone-input-wrap), not as a
|
|
947
|
+
// direct child of .field — so .field's 4px column gap can't separate it from the control, and
|
|
948
|
+
// .field-error's -2px pull then makes it touch the input. <wui-phone> is display:block with no
|
|
949
|
+
// gap of its own, so restore the same effective 2px control→error gap the plain field gives,
|
|
950
|
+
// matching AppInput.
|
|
951
|
+
.app-phone-number-input wui-phone > .field-error {
|
|
952
|
+
margin-top: 2px;
|
|
953
|
+
}
|
|
946
954
|
// Popover-field controls (date / date-range / time) carry aria-invalid on the HOST element —
|
|
947
955
|
// React/Razor set it from the `error` prop — while the visible border lives on the inner trigger
|
|
948
956
|
// button. Redden that trigger, and keep it red while the popover is open (mirroring AppInput,
|
package/scss/wui/_controls.scss
CHANGED
|
@@ -657,6 +657,26 @@ textarea.form-control.autosize {
|
|
|
657
657
|
color: var(--color-primary);
|
|
658
658
|
}
|
|
659
659
|
|
|
660
|
+
// Trailing action beside the field — a control (a labelled button, or a confirmation once the
|
|
661
|
+
// value resolves) that sits OUTSIDE the input border. The field flexes to fill the row; the
|
|
662
|
+
// action keeps its natural width and centres against the control.
|
|
663
|
+
.input-action-row {
|
|
664
|
+
display: flex;
|
|
665
|
+
align-items: center;
|
|
666
|
+
gap: 0.5rem;
|
|
667
|
+
}
|
|
668
|
+
.input-action-row > .input-wrap,
|
|
669
|
+
.input-action-row > .input-icon {
|
|
670
|
+
flex: 1 1 auto;
|
|
671
|
+
min-width: 0;
|
|
672
|
+
}
|
|
673
|
+
.input-action {
|
|
674
|
+
flex: 0 0 auto;
|
|
675
|
+
display: flex;
|
|
676
|
+
align-items: center;
|
|
677
|
+
white-space: nowrap;
|
|
678
|
+
}
|
|
679
|
+
|
|
660
680
|
// Password reveal toggle (place inside .input-wrap).
|
|
661
681
|
.input.pw {
|
|
662
682
|
padding-right: 44px;
|
package/scss/wui/_data.scss
CHANGED
|
@@ -112,6 +112,40 @@
|
|
|
112
112
|
.table-ledger tbody tr:hover td.wui-table-empty:has(> .tbl-empty) {
|
|
113
113
|
background: transparent;
|
|
114
114
|
}
|
|
115
|
+
// Keep the empty state on screen. An empty table has no data to scroll to, yet its
|
|
116
|
+
// header row can still be wider than the viewport (many columns, or wide header
|
|
117
|
+
// labels), so `.table-wrap` would scroll horizontally and the centred empty message —
|
|
118
|
+
// spanning that full width in a colSpan cell — would slide off screen on a narrow
|
|
119
|
+
// screen. Keyed off the empty body itself (`.tbl-empty` for a rich AppTableEmptyState,
|
|
120
|
+
// `.tbl-empty-plain` for a plain string — both surfaces render one), lay the empty
|
|
121
|
+
// table out at the visible wrap width and drop the scroll, so the message stays centred
|
|
122
|
+
// and fully in view. This is the "do it without turning the scroll container into a
|
|
123
|
+
// query container" path the pin note on `.table-wrap:has(> .table-ledger)` calls for —
|
|
124
|
+
// it replaces the earlier `container-type` + `100cqw` pin, which collapsed the wrap as a
|
|
125
|
+
// flex/grid item. Scoped to the empty body, so a table WITH rows is untouched and still
|
|
126
|
+
// scrolls its columns.
|
|
127
|
+
// Keyed on the empty CELL (`td.wui-table-empty`, the one element unique to the empty
|
|
128
|
+
// state on both surfaces) with CHILD combinators, NOT a loose descendant `:has(.tbl-empty)`.
|
|
129
|
+
// The child chain matches only a table's OWN empty body — so an expandable row whose
|
|
130
|
+
// nested table happens to be empty can never force the outer, data-bearing table into
|
|
131
|
+
// this layout. A data table (no empty cell of its own) is untouched and still scrolls.
|
|
132
|
+
.table-wrap:has(> table > tbody > tr > td.wui-table-empty) {
|
|
133
|
+
overflow-x: hidden;
|
|
134
|
+
}
|
|
135
|
+
.table:has(> tbody > tr > td.wui-table-empty) {
|
|
136
|
+
width: 100%;
|
|
137
|
+
min-width: 0;
|
|
138
|
+
table-layout: fixed;
|
|
139
|
+
}
|
|
140
|
+
// Under the fixed layout above the columns are narrow, so a long header label would
|
|
141
|
+
// spill out of its cell and back into horizontal overflow — the very thing we just
|
|
142
|
+
// removed. Clip each header to its column (ellipsis) in the empty state; short labels
|
|
143
|
+
// are unaffected, and the data table keeps its natural header sizing.
|
|
144
|
+
.table:has(> tbody > tr > td.wui-table-empty) > thead th {
|
|
145
|
+
overflow: hidden;
|
|
146
|
+
white-space: nowrap;
|
|
147
|
+
text-overflow: ellipsis;
|
|
148
|
+
}
|
|
115
149
|
|
|
116
150
|
// ── Table (base) ──
|
|
117
151
|
// The shared data-table look, on the plain `.table` class Bootstrap already
|
package/scss/wui/_overlays.scss
CHANGED
|
@@ -547,6 +547,19 @@
|
|
|
547
547
|
animation: wui-toast-in 0.24s ease;
|
|
548
548
|
}
|
|
549
549
|
|
|
550
|
+
// A single-line toast — bare message, no title / action / progress stack — centers its icon,
|
|
551
|
+
// text and close as one row. The flex-start default above exists for the multi-line variants
|
|
552
|
+
// (title+message, an action button, a progress track), where the icon must sit on the first
|
|
553
|
+
// line rather than float to the middle of a tall card.
|
|
554
|
+
.wui-toast:not(:has(.wui-toast-title)):not(:has(.wui-toast-action)):not(:has(.wui-toast-task)) {
|
|
555
|
+
align-items: center;
|
|
556
|
+
}
|
|
557
|
+
// The 1px top nudges align the icon/close with the first text line under flex-start; once the
|
|
558
|
+
// row is centered they would push those items a touch low, so zero them here.
|
|
559
|
+
.wui-toast:not(:has(.wui-toast-title)):not(:has(.wui-toast-action)):not(:has(.wui-toast-task)) :is(.wui-toast-icon, .wui-toast-close) {
|
|
560
|
+
margin-top: 0;
|
|
561
|
+
}
|
|
562
|
+
|
|
550
563
|
// While a swipe is in progress the toast follows the pointer with no transition.
|
|
551
564
|
.wui-toast--dragging {
|
|
552
565
|
transition: none;
|
package/scss/wui/_utilities.scss
CHANGED
|
@@ -164,6 +164,13 @@
|
|
|
164
164
|
align-items: center;
|
|
165
165
|
justify-content: space-between;
|
|
166
166
|
gap: 16px;
|
|
167
|
+
// Content-driven wrap: while the title block and actions both fit, space-between keeps the
|
|
168
|
+
// actions pinned right; once a long title needs the full width they can no longer share the
|
|
169
|
+
// row, so the actions drop onto their own line — left-aligned, since space-between places a
|
|
170
|
+
// lone wrapped item at flex-start — instead of being crushed against the title. The gap above
|
|
171
|
+
// doubles as the row-gap to that dropped line. (Below lg they stack unconditionally, further
|
|
172
|
+
// down; this is the any-width, content-driven case.)
|
|
173
|
+
flex-wrap: wrap;
|
|
167
174
|
}
|
|
168
175
|
// Left block: an optional leading icon tile + the title stack, kept together.
|
|
169
176
|
.page-header-lead {
|