@tensor_1/tokens 2.41.0 → 2.42.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/build/css/components.css +1 -1
- package/build/css/styles.css +1 -1
- package/package.json +1 -1
- package/styles/components/button.css +14 -0
- package/styles/components/description-list.css +23 -1
- package/styles/components/detail-layout.css +2 -0
- package/styles/components/drawer.css +4 -0
- package/styles/components/editorial-home.css +29 -2
- package/styles/components/input.css +5 -0
- package/styles/components/modal.css +3 -0
- package/styles/components/popover.css +5 -0
- package/styles/components/sidebar.css +3 -0
- package/styles/components/table.css +7 -3
- package/styles/components/tooltip.css +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tensor_1/tokens",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.42.0",
|
|
4
4
|
"description": "UIx v2 design tokens — the --uix-* contract for house products (Tensor, POSx, SHOPx). One DTCG source -> CSS variables, Tailwind theme, and typed TS constants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|
|
@@ -38,6 +38,20 @@
|
|
|
38
38
|
.uix-btn--icon.uix-btn--sm { width: 28px; }
|
|
39
39
|
.uix-btn--icon.uix-btn--lg { width: 44px; }
|
|
40
40
|
|
|
41
|
+
/* A label that may wrap (HAR-1813, WCAG 1.4.10). The size sets a floor instead of a fixed
|
|
42
|
+
height, so a long human-language label breaks onto a second line in a narrow or zoomed
|
|
43
|
+
column instead of pushing it wider. Opt-in (`wrap` on Button / ButtonLink): dense staff
|
|
44
|
+
rows keep one line. Never on an icon-only button, which keeps its square. */
|
|
45
|
+
.uix-btn--wrap:not(.uix-btn--icon) {
|
|
46
|
+
height: auto; min-height: var(--uix-control-h); max-width: 100%;
|
|
47
|
+
padding-block: var(--uix-space-2); white-space: normal; line-height: 1.25;
|
|
48
|
+
text-align: center; text-wrap: balance; overflow-wrap: anywhere;
|
|
49
|
+
}
|
|
50
|
+
.uix-btn--wrap.uix-btn--xs:not(.uix-btn--icon) { min-height: 24px; padding-block: var(--uix-space-1); }
|
|
51
|
+
.uix-btn--wrap.uix-btn--sm:not(.uix-btn--icon) { min-height: 28px; padding-block: var(--uix-space-1); }
|
|
52
|
+
.uix-btn--wrap.uix-btn--lg:not(.uix-btn--icon) { min-height: 44px; }
|
|
53
|
+
.uix-btn--wrap.uix-btn--link { min-height: 0; padding-block: 0; }
|
|
54
|
+
|
|
41
55
|
.uix-btn[data-loading] { color: transparent !important; position: relative; pointer-events: none; }
|
|
42
56
|
/* The label is hidden (color: transparent), so the ring cannot inherit
|
|
43
57
|
currentColor from the button; each variant names its own foreground.
|
|
@@ -1,7 +1,29 @@
|
|
|
1
1
|
/* uix description / key-value list — depends only on --uix-* tokens. */
|
|
2
2
|
@layer uix.components {
|
|
3
|
-
|
|
3
|
+
/* The list is its own inline-size container, so it stacks by ITS width, not the viewport's
|
|
4
|
+
(HAR-2032): a list in a phone card, a 320 px side rail or a narrow column gets the same
|
|
5
|
+
treatment. Inline-size containment replaces the list's content width with
|
|
6
|
+
contain-intrinsic-inline-size, both where a box is sized by its content (a flex row, a
|
|
7
|
+
max-content popover) and where a parent sizes from its children's minimum (a grid with
|
|
8
|
+
auto tracks). 0 would collapse the list in a flex row; a wide value would push a phone
|
|
9
|
+
page sideways. 12rem is neither: it fits a card on a 280 px screen, and a list in a flex
|
|
10
|
+
row is 12rem wide (stacked) unless you size it (`flex: 1`, a width). */
|
|
11
|
+
.uix-dl {
|
|
12
|
+
display: grid; grid-template-columns: max-content 1fr; gap: var(--uix-space-3) var(--uix-space-6);
|
|
13
|
+
container: uix-dl / inline-size; contain-intrinsic-inline-size: 12rem; min-width: 0;
|
|
14
|
+
}
|
|
4
15
|
.uix-dl dt { color: var(--uix-text-muted); font-size: var(--uix-text-meta); }
|
|
5
16
|
/* min-width:0 + anywhere: a long unbroken value (URL, id, hash) wraps instead of widening the grid (HAR-1353) */
|
|
6
17
|
.uix-dl dd { color: var(--uix-text); font-size: var(--uix-text-body); margin: 0; min-width: 0; overflow-wrap: anywhere; }
|
|
18
|
+
|
|
19
|
+
/* Narrow: each label sits above its value and both take the full width, so a long label
|
|
20
|
+
("Neue Tickets pro Person und Stunde") can no longer squeeze the value to a letter per
|
|
21
|
+
line or push it off a 320 px screen (TENSOR HAR-1651). The label is pulled toward its own
|
|
22
|
+
value, so the gap inside a pair (4 px) is smaller than the gap between pairs (12 px). */
|
|
23
|
+
/* Pairs may sit in display:contents <div>s, which HTML allows. The pull assumes the default
|
|
24
|
+
12 px row gap: shrink the list's row-gap below 8 px and a stacked label touches its value. */
|
|
25
|
+
@container uix-dl (max-width: 22rem) {
|
|
26
|
+
.uix-dl > :is(dt, dd), .uix-dl > div > :is(dt, dd) { grid-column: 1 / -1; }
|
|
27
|
+
.uix-dl > dt, .uix-dl > div > dt { margin-bottom: calc(-1 * var(--uix-space-2)); overflow-wrap: anywhere; }
|
|
28
|
+
}
|
|
7
29
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/* uix detail layout — two-column record (main + side meta). Depends only on --uix-* tokens. */
|
|
2
2
|
@layer uix.components {
|
|
3
3
|
.uix-detail { display: grid; grid-template-columns: 1fr 280px; gap: var(--uix-space-5); align-items: start; }
|
|
4
|
+
/* No side column: the main column takes the whole width instead of leaving 280 px empty (HAR-1814). */
|
|
5
|
+
.uix-detail:not(:has(> .uix-detail__side)) { grid-template-columns: minmax(0, 1fr); }
|
|
4
6
|
.uix-detail__main { min-width: 0; display: flex; flex-direction: column; gap: var(--uix-space-4); }
|
|
5
7
|
.uix-detail__side { display: flex; flex-direction: column; gap: var(--uix-space-4); }
|
|
6
8
|
.uix-detail-page { display: flex; flex-direction: column; gap: var(--uix-space-5); }
|
|
@@ -33,4 +33,8 @@
|
|
|
33
33
|
.uix-drawer__header { display: flex; align-items: center; gap: var(--uix-space-3); padding: var(--uix-space-4) var(--uix-space-5); border-bottom: 1px solid var(--uix-border); }
|
|
34
34
|
.uix-drawer__body { padding: var(--uix-space-5); overflow-y: auto; flex: 1; }
|
|
35
35
|
.uix-drawer__footer { display: flex; gap: var(--uix-space-2); padding: var(--uix-space-4) var(--uix-space-5); border-top: 1px solid var(--uix-border); }
|
|
36
|
+
/* the React close button (it was inline styles until HAR-2029 gave it a pending state) */
|
|
37
|
+
.uix-drawer__close { margin-left: auto; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--uix-radius-sm); }
|
|
38
|
+
/* `pending` (HAR-2029): a save is in flight, so the close button does nothing and says so */
|
|
39
|
+
.uix-drawer__close[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
|
|
36
40
|
}
|
|
@@ -23,6 +23,28 @@
|
|
|
23
23
|
.uix-searchbar__wrap { position: relative; }
|
|
24
24
|
.uix-searchbar__wrap > svg { position: absolute; top: 50%; left: 14px; z-index: var(--uix-z-raised); width: 17px; height: 17px; color: var(--uix-text-hushed); transform: translateY(-50%); pointer-events: none; }
|
|
25
25
|
|
|
26
|
+
/* React SearchBar (HAR-2030). Without a submit button the field takes the whole row (an
|
|
27
|
+
empty auto track would still leave the column gap). The clear button sits inside the
|
|
28
|
+
field's end, and the browser's own search clear (×) is not drawn beside it. */
|
|
29
|
+
.uix-searchbar > :only-child { grid-column: 1 / -1; }
|
|
30
|
+
.uix-searchbar__wrap:has(> .uix-searchbar__clear) > .uix-input::-webkit-search-cancel-button,
|
|
31
|
+
.uix-searchbar__wrap:has(> .uix-searchbar__clear) > .uix-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
|
|
32
|
+
.uix-searchbar__wrap:has(> .uix-searchbar__clear) > .uix-input { padding-right: 44px; }
|
|
33
|
+
.uix-searchbar__clear {
|
|
34
|
+
position: absolute; top: 50%; right: 8px; z-index: var(--uix-z-raised); transform: translateY(-50%);
|
|
35
|
+
display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0;
|
|
36
|
+
border: 0; border-radius: var(--uix-radius-sm); background: transparent; color: var(--uix-text-muted); cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
.uix-searchbar__clear svg { width: 14px; height: 14px; }
|
|
39
|
+
.uix-searchbar__clear:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
|
|
40
|
+
.uix-searchbar__clear:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 1px; }
|
|
41
|
+
/* md: a control-height field for a header or a toolbar (the bare contract is the 44 px public size) */
|
|
42
|
+
.uix-searchbar--md .uix-input, .uix-searchbar--md .uix-btn { min-height: 0; }
|
|
43
|
+
.uix-searchbar--md .uix-input { padding-left: 36px; }
|
|
44
|
+
.uix-searchbar--md .uix-searchbar__wrap > svg { left: 12px; width: var(--uix-icon-md); height: var(--uix-icon-md); }
|
|
45
|
+
.uix-searchbar--md .uix-searchbar__wrap:has(> .uix-searchbar__clear) > .uix-input { padding-right: 36px; }
|
|
46
|
+
.uix-searchbar--md .uix-searchbar__clear { right: 6px; width: 24px; height: 24px; }
|
|
47
|
+
|
|
26
48
|
/* The grid fits ITSELF rather than counting columns: a fixed count is only safe for label
|
|
27
49
|
lengths you already know, and `1fr` takes an auto minimum, so nowrap button labels push
|
|
28
50
|
the track past the viewport (LD-11: 382 px of content at 320 px on the German portal).
|
|
@@ -122,8 +144,11 @@
|
|
|
122
144
|
.uix-content-list { margin: 0; padding: 0; list-style: none; }
|
|
123
145
|
.uix-content-list__item { min-height: 68px; padding: var(--uix-space-3) 0; display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: var(--uix-space-4); border-bottom: 1px solid var(--uix-border); }
|
|
124
146
|
.uix-content-list__item:last-child { border-bottom: 0; }
|
|
125
|
-
|
|
126
|
-
|
|
147
|
+
/* One long unbroken word (a German compound, a file name) breaks inside the row instead of
|
|
148
|
+
widening the page (HAR-1811). */
|
|
149
|
+
.uix-content-list__item > div { min-width: 0; }
|
|
150
|
+
.uix-content-list__title { margin: 0; font-weight: 600; min-width: 0; overflow-wrap: anywhere; }
|
|
151
|
+
.uix-content-list__meta { margin: var(--uix-space-1) 0 0; color: var(--uix-text-hushed); font-size: var(--uix-text-meta); min-width: 0; overflow-wrap: anywhere; }
|
|
127
152
|
|
|
128
153
|
/* ── resource grid ─────────────────────────────────────────────────────────── */
|
|
129
154
|
.uix-resource-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--uix-space-2); }
|
|
@@ -178,6 +203,8 @@
|
|
|
178
203
|
.uix-notice__position { flex: 1; }
|
|
179
204
|
|
|
180
205
|
.uix-searchbar { grid-template-columns: 1fr; }
|
|
206
|
+
/* a header or toolbar field keeps its button beside it */
|
|
207
|
+
.uix-searchbar--md { grid-template-columns: minmax(0, 1fr) auto; }
|
|
181
208
|
|
|
182
209
|
.uix-page-intro { margin-top: var(--uix-space-5); gap: var(--uix-space-5); }
|
|
183
210
|
/* auto-fit already narrows the tracks; only the touch target grows here. Re-pinning a
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
.uix-field__hint { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
|
|
14
14
|
.uix-field__error { font-size: var(--uix-text-meta); color: var(--uix-danger-text); display: inline-flex; align-items: center; gap: var(--uix-space-2); }
|
|
15
15
|
.uix-field__error svg, .uix-field__success svg { width: 14px; height: 14px; flex: none; }
|
|
16
|
+
.uix-field__warning { font-size: var(--uix-text-meta); color: var(--uix-warning-text); display: inline-flex; align-items: center; gap: var(--uix-space-2); }
|
|
16
17
|
.uix-field__success { font-size: var(--uix-text-meta); color: var(--uix-success); display: inline-flex; align-items: center; gap: var(--uix-space-2); }
|
|
17
18
|
|
|
18
19
|
.uix-input {
|
|
@@ -38,6 +39,10 @@
|
|
|
38
39
|
/* validation microinteractions */
|
|
39
40
|
.uix-input[data-valid] { border-color: var(--uix-success); }
|
|
40
41
|
.uix-input[data-valid]:focus { box-shadow: 0 0 0 3px var(--uix-success-bg); }
|
|
42
|
+
/* "Check this": a value to confirm, not an error (HAR-1814; e.g. a field an assistant filled).
|
|
43
|
+
Invalid wins when both are set. */
|
|
44
|
+
.uix-input[data-warning]:not([aria-invalid="true"]) { border-color: var(--uix-warning); }
|
|
45
|
+
.uix-input[data-warning]:not([aria-invalid="true"]):focus { box-shadow: 0 0 0 3px var(--uix-warning-bg); }
|
|
41
46
|
.uix-input-group--has-trailing .uix-input { padding-right: 38px; }
|
|
42
47
|
.uix-input-group__icon--trailing { left: auto; right: 10px; }
|
|
43
48
|
}
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
.uix-dialog__close { margin-left: auto; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--uix-radius-sm); }
|
|
29
29
|
.uix-dialog__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
|
|
30
30
|
.uix-dialog__close svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
|
|
31
|
+
/* `pending` (HAR-2029): a save is in flight, so the close button does nothing and says so */
|
|
32
|
+
.uix-dialog__close[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
|
|
33
|
+
.uix-dialog__close[aria-disabled="true"]:hover { background: transparent; color: var(--uix-text-muted); }
|
|
31
34
|
.uix-dialog__body { padding: var(--uix-space-5); color: var(--uix-text-hushed); }
|
|
32
35
|
/* wraps at 320 px (WCAG 1.4.10) */
|
|
33
36
|
.uix-dialog__footer { display: flex; flex-wrap: wrap; gap: var(--uix-space-2); justify-content: flex-end; padding: var(--uix-space-4) var(--uix-space-5); border-top: 1px solid var(--uix-border); }
|
|
@@ -13,6 +13,11 @@
|
|
|
13
13
|
[popover].uix-popover[data-placement^="left"] { --popover-from: translateX(var(--uix-lift)); }
|
|
14
14
|
[popover].uix-popover[data-placement^="right"] { --popover-from: translateX(calc(-1 * var(--uix-lift))); }
|
|
15
15
|
[popover].uix-popover:popover-open { opacity: 1; transform: none; }
|
|
16
|
+
/* A closed popover is display:none by the UA stylesheet only, so a component that sets its
|
|
17
|
+
own display (.uix-popconfirm, .uix-filter-popover: grid) stayed laid out while closed: an
|
|
18
|
+
invisible fixed box at the viewport's top-left that took clicks (HAR-2029). The display
|
|
19
|
+
transition above still keeps it painted while it fades out. */
|
|
20
|
+
[popover].uix-popover:not(:popover-open) { display: none; }
|
|
16
21
|
@starting-style { [popover].uix-popover:popover-open { opacity: 0; transform: var(--popover-from); } }
|
|
17
22
|
[popover].uix-popover[data-uix-placing]:popover-open { opacity: 0; transform: var(--popover-from); transition: none; }
|
|
18
23
|
}
|
|
@@ -24,6 +24,9 @@
|
|
|
24
24
|
transition: background-color var(--uix-dur-fast) var(--uix-ease-out), color var(--uix-dur-fast) var(--uix-ease-out);
|
|
25
25
|
}
|
|
26
26
|
.uix-navitem:hover { background: var(--uix-bg-hover); color: var(--uix-text); text-decoration: none; }
|
|
27
|
+
/* Its own ring, drawn inside: the global outset ring is cut off by the sidebar's
|
|
28
|
+
overflow-x: hidden (HAR-1814). */
|
|
29
|
+
.uix-navitem:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: -2px; }
|
|
27
30
|
/* active uses --uix-link (the brightened-on-dark accent) not raw --uix-accent: the deep accent
|
|
28
31
|
fails AA as text on the brand-muted tint in dark; link reads legibly in both themes. */
|
|
29
32
|
.uix-navitem[aria-current="page"] { background: var(--uix-brand-muted); color: var(--uix-link); font-weight: 500; }
|
|
@@ -26,7 +26,9 @@
|
|
|
26
26
|
plain-text th — inherited font/colour, no chrome — with an inset overlay so the whole
|
|
27
27
|
cell stays the click target (the sticky th is its containing block). The sort arrow and
|
|
28
28
|
ordinal stay as th pseudo-content so they never pollute the button's accessible name. */
|
|
29
|
-
|
|
29
|
+
/* letter-spacing and text-transform too: the UA button style resets them, so a sortable
|
|
30
|
+
header lost the eyebrow tracking and case its neighbours keep (HAR-1814). */
|
|
31
|
+
.uix-th__sortbtn { font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; background: none; border: 0; padding: 0; text-align: inherit; cursor: pointer; }
|
|
30
32
|
.uix-th__sortbtn::before { content: ""; position: absolute; inset: 0; }
|
|
31
33
|
|
|
32
34
|
.uix-table td { padding: 0 var(--uix-space-4); height: var(--uix-row-h); border-bottom: 1px solid var(--uix-border); color: var(--uix-text); vertical-align: middle; }
|
|
@@ -112,7 +114,8 @@
|
|
|
112
114
|
width: var(--uix-icon-sm); height: var(--uix-icon-sm); flex-shrink: 0; color: var(--uix-text-muted);
|
|
113
115
|
opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out);
|
|
114
116
|
}
|
|
115
|
-
|
|
117
|
+
/* :focus-within as well: a keyboard user on the id link sees the arrow too (HAR-1814). */
|
|
118
|
+
.uix-table tbody tr:hover .uix-id-cell__arrow, .uix-table tbody tr:focus-within .uix-id-cell__arrow { opacity: 1; }
|
|
116
119
|
|
|
117
120
|
/* ── selection column + select-all ────────────────────────────────────────────── */
|
|
118
121
|
.uix-table th.uix-table__selcol, .uix-table td.uix-table__selcell { width: 44px; padding-left: var(--uix-space-3); padding-right: 0; text-align: center; }
|
|
@@ -135,7 +138,8 @@
|
|
|
135
138
|
.uix-table__actions { width: 84px; text-align: right; white-space: nowrap; }
|
|
136
139
|
.uix-rowact { border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; padding: var(--uix-space-1); border-radius: var(--uix-radius-sm); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out), background-color var(--uix-dur-fast) var(--uix-ease-out); }
|
|
137
140
|
.uix-rowact svg { width: 16px; height: 16px; display: block; }
|
|
138
|
-
|
|
141
|
+
/* A row the keyboard is in shows its actions, as a hovered one does (HAR-1814). */
|
|
142
|
+
.uix-table tbody tr:hover .uix-rowact, .uix-table tbody tr:focus-within .uix-rowact, .uix-rowact:focus-visible, .uix-rowact[aria-expanded="true"] { opacity: 1; }
|
|
139
143
|
.uix-rowact:hover { background: var(--uix-bg-active); color: var(--uix-text); }
|
|
140
144
|
|
|
141
145
|
/* ── expandable inline row ─────────────────────────────────────────────────────── */
|
|
@@ -21,6 +21,13 @@
|
|
|
21
21
|
.uix-tooltip__bubble :is(ul, ol) { margin: 0; padding-left: 1.1em; }
|
|
22
22
|
.uix-tooltip__bubble :is(p, ul, ol) + :is(p, ul, ol) { margin-top: var(--uix-space-1); }
|
|
23
23
|
.uix-tooltip__bubble:popover-open { opacity: 1; }
|
|
24
|
+
/* A shortcut in the bubble (HAR-2031: Tooltip `shortcut`, Button `shortcut`): after the text,
|
|
25
|
+
the keys drawn as outlines in the bubble's own colour, so they keep its contrast in both
|
|
26
|
+
themes. A Button's hint bubble is one line: the name of an icon button, then the keys. */
|
|
27
|
+
.uix-tooltip__shortcut { display: inline-flex; vertical-align: middle; margin-inline-start: var(--uix-space-2); }
|
|
28
|
+
.uix-tooltip__shortcut:first-child { margin-inline-start: 0; }
|
|
29
|
+
.uix-tooltip__shortcut .uix-kbd { color: inherit; background: transparent; border-color: color-mix(in srgb, currentColor 45%, transparent); }
|
|
30
|
+
.uix-tooltip__bubble--hint { white-space: nowrap; }
|
|
24
31
|
@starting-style { .uix-tooltip__bubble:popover-open { opacity: 0; } }
|
|
25
32
|
|
|
26
33
|
/* legacy CSS-only tooltip — clipped by overflow ancestors; superseded by .uix-tooltip__bubble */
|