@tensor_1/tokens 2.24.0 → 2.26.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": "@tensor_1/tokens",
3
- "version": "2.24.0",
3
+ "version": "2.26.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": [
@@ -0,0 +1,28 @@
1
+ /* uix arrival — "you are here": the highlight a page puts on the element a link or a search result
2
+ landed on (a settings row, a section, a comment). Add the class after scrolling the target into
3
+ view; it tints the target and fades out on its own. To replay it, remove the class, force a
4
+ reflow, and add it again. Depends only on --uix-* tokens. */
5
+ @layer uix.components {
6
+ .uix-arrival {
7
+ border-radius: var(--uix-radius-md);
8
+ scroll-margin-block: var(--uix-space-10);
9
+ animation: uix-arrival 2.4s var(--uix-ease-out) both;
10
+ }
11
+ @keyframes uix-arrival {
12
+ 0%, 40% { background-color: var(--uix-brand-muted); box-shadow: 0 0 0 var(--uix-space-2) var(--uix-brand-muted); }
13
+ 100% { background-color: transparent; box-shadow: 0 0 0 var(--uix-space-2) transparent; }
14
+ }
15
+
16
+ /* no fade: a steady outline for two seconds, then nothing */
17
+ @keyframes uix-arrival-static {
18
+ 0% { outline: 2px solid var(--uix-ring); outline-offset: var(--uix-space-1); }
19
+ 100% { outline: 2px solid transparent; outline-offset: var(--uix-space-1); }
20
+ }
21
+ @media (prefers-reduced-motion: reduce) {
22
+ .uix-arrival { animation: uix-arrival-static 2s step-end both; }
23
+ }
24
+
25
+ @media (forced-colors: active) {
26
+ .uix-arrival { animation: uix-arrival-static 2s step-end both; }
27
+ }
28
+ }
@@ -3,6 +3,7 @@
3
3
  .uix-card { background: var(--uix-surface); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); box-shadow: var(--uix-shadow-sm); }
4
4
  .uix-card__header { padding: var(--uix-space-5) var(--uix-space-6); border-bottom: 1px solid var(--uix-border); display: flex; align-items: center; gap: var(--uix-space-3); }
5
5
  .uix-card__title { font-size: var(--uix-text-h3); font-weight: 600; }
6
+ .uix-card__title-row { display: flex; align-items: baseline; gap: var(--uix-space-1); min-width: 0; font-size: var(--uix-text-h3); }
6
7
  .uix-card__subtitle { font-size: var(--uix-text-meta); color: var(--uix-text-muted); margin-top: var(--uix-space-1); }
7
8
  .uix-card__body { padding: var(--uix-space-6); }
8
9
  /* wraps at 320 px (WCAG 1.4.10) */
@@ -98,6 +98,7 @@
98
98
  /* ── section heads ─────────────────────────────────────────────────────────── */
99
99
  .uix-section-head { min-height: 36px; margin-bottom: var(--uix-space-3); display: flex; align-items: center; justify-content: space-between; gap: var(--uix-space-4); }
100
100
  .uix-section-title { margin: 0; font-family: var(--uix-font-heading); font-size: var(--uix-text-h2); font-weight: 400; letter-spacing: var(--uix-tracking-tight); }
101
+ .uix-section-head__title-row { display: flex; align-items: baseline; gap: var(--uix-space-1); min-width: 0; font-family: var(--uix-font-heading); font-size: var(--uix-text-h2); }
101
102
  .uix-section-link { color: var(--uix-text-hushed); font-size: var(--uix-text-meta); text-decoration: none; }
102
103
  /* already a quiet link by its own design — hover/focus parity with link.css */
103
104
  .uix-section-link:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
@@ -0,0 +1,41 @@
1
+ /* uix info tip — a small ? that opens a plain-text help panel beside a page title, section title
2
+ or field label. The panel is a top-layer .uix-popover (React <InfoTip> positions it with the
3
+ shared overlay engine); this file owns the ? and the panel's type and measure.
4
+ The ? is a fixed 9px filled glyph (no circle), whatever the size of the text it follows, and
5
+ sits superscript-style at the top right of that text: the .uix-info-tip box sits on the text's
6
+ baseline and raises the glyph so its top overshoots the capitals (`1cap`) by 0.2em. A glyph
7
+ whose top only met the cap line spanned the whole height of 15px capitals and read as centred.
8
+ That holds for any line-height, inline in running text too. The slot rows (page header, card, section
9
+ head, field) align on the first baseline and set the title's font-size, so `cap` measures the
10
+ title. Depends only on --uix-* tokens. */
11
+ @layer uix.components {
12
+ .uix-info-tip { display: inline-block; flex: none; line-height: 1; }
13
+
14
+ .uix-info-tip__button {
15
+ position: relative;
16
+ /* no text inside, so its baseline is its bottom edge: raise its top 0.2em above cap height */
17
+ display: inline-block; vertical-align: calc(1cap + 0.2em - 9px);
18
+ width: 7px; height: 9px; padding: 0; margin: 0;
19
+ border: 0; border-radius: var(--uix-radius-sm);
20
+ background: transparent; color: var(--uix-text-muted);
21
+ cursor: pointer;
22
+ transition: color var(--uix-dur-fast) var(--uix-ease-out);
23
+ }
24
+ /* 25px hit area around the 7x9px glyph (WCAG 2.5.8), without changing the layout */
25
+ .uix-info-tip__button::before { content: ""; position: absolute; inset: -8px -9px; }
26
+ .uix-info-tip__button svg { width: 7px; height: 9px; display: block; }
27
+ .uix-info-tip__button:hover,
28
+ .uix-info-tip[data-open] .uix-info-tip__button { color: var(--uix-accent); } /* the primary-button blue */
29
+ .uix-info-tip__button:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 2px; }
30
+
31
+ .uix-popover.uix-info-tip__panel {
32
+ width: max-content; max-width: min(360px, calc(100vw - 16px));
33
+ padding: var(--uix-space-3);
34
+ font-size: var(--uix-text-meta); font-weight: 400; line-height: var(--uix-leading-body);
35
+ color: var(--uix-text); text-align: start; text-transform: none; letter-spacing: normal;
36
+ overflow-wrap: anywhere;
37
+ }
38
+ /* single line breaks inside a paragraph are kept; blank lines already split paragraphs */
39
+ .uix-info-tip__panel p { margin: 0; white-space: pre-line; }
40
+ .uix-info-tip__panel p + p { margin-top: var(--uix-space-2); }
41
+ }
@@ -3,6 +3,10 @@
3
3
  .uix-field { display: flex; flex-direction: column; gap: var(--uix-space-2); }
4
4
  .uix-field__label { font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-text); }
5
5
  .uix-field__label[data-required]::after { content: " *"; color: var(--uix-danger-text); }
6
+ /* label + help ? (React Field `help`): the ? stays OUTSIDE the <label> (a button inside a label
7
+ is its activation target), so the row draws the required marker after the ? */
8
+ .uix-field__label-row { display: flex; align-items: baseline; gap: var(--uix-space-1); min-width: 0; font-size: var(--uix-text-meta); }
9
+ .uix-field__required { font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-danger-text); }
6
10
  /* message slot for hint / error / success — reserves one line so an appearing error never
7
11
  shifts the layout (UIX-FIX-04); the React <Field> always renders it. */
8
12
  .uix-field__msg { font-size: var(--uix-text-meta); line-height: 1.45; min-height: 1.45em; }
@@ -4,6 +4,9 @@
4
4
  .uix-page-header__titles { flex: 1; min-width: 220px; }
5
5
  .uix-page-header__eyebrow { font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow); text-transform: uppercase; font-weight: 600; color: var(--uix-text-muted); margin-bottom: var(--uix-space-2); }
6
6
  .uix-page-header__title { font-size: var(--uix-text-h2); font-weight: 600; letter-spacing: var(--uix-tracking-tight); }
7
+ /* title + help ? (React PageHeader `help`): the ? sits beside the heading, not inside it; the row
8
+ carries the title size so the ? (info-tip.css) lands at the top right of the title text */
9
+ .uix-page-header__title-row { display: flex; align-items: baseline; gap: var(--uix-space-1); min-width: 0; font-family: var(--uix-font-heading); font-size: var(--uix-text-h2); }
7
10
  .uix-page-header__subtitle { color: var(--uix-text-muted); font-size: var(--uix-text-meta); margin-top: var(--uix-space-2); max-width: 70ch; }
8
11
  .uix-page-header__actions { display: flex; gap: var(--uix-space-2); align-items: center; flex-wrap: wrap; }
9
12
  }
@@ -130,6 +130,11 @@
130
130
  .uix-rich-text--composer .uix-rich-text__counter,
131
131
  .uix-rich-text--composer .uix-rich-text__status { flex: none; margin-right: 0; }
132
132
  .uix-rich-text--composer .uix-rich-text__bar > :last-child:not(.uix-rich-text__toolbar) { margin-left: auto; }
133
+ /* a status message (uploading, failed, images off) takes its own row under the tools: inline, a
134
+ long message squeezed the toolbar to a sliver on a 320 px phone (TENSOR HAR-749) */
135
+ .uix-rich-text--composer .uix-rich-text__bar:has(> .uix-rich-text__status:not(:empty)) { flex-wrap: wrap; }
136
+ .uix-rich-text--composer .uix-rich-text__bar:has(> .uix-rich-text__status:not(:empty)) > .uix-rich-text__toolbar { flex-basis: 0; }
137
+ .uix-rich-text--composer .uix-rich-text__status:not(:empty) { order: 1; flex: 1 0 100%; }
133
138
  .uix-rich-text--composer .uix-rich-text__source.uix-textarea { border: 0; box-shadow: none; }
134
139
 
135
140
  /* link popover */
@@ -0,0 +1,116 @@
1
+ /* uix search suggest — a search field with a suggestion list (name · where it lives · context).
2
+ Depends only on --uix-* tokens. React: <SearchSuggest>. */
3
+ @layer uix.components {
4
+ .uix-search-suggest { position: relative; width: 100%; }
5
+
6
+ /* field: leading magnifier, trailing spinner / clear / shortcut hint */
7
+ .uix-search-suggest__field { position: relative; display: flex; align-items: center; }
8
+ .uix-search-suggest__input { padding-left: 38px; padding-right: 44px; }
9
+ .uix-search-suggest__lead {
10
+ position: absolute; left: 12px; display: inline-flex; color: var(--uix-text-muted); pointer-events: none;
11
+ }
12
+ .uix-search-suggest__lead svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
13
+ .uix-search-suggest__trail {
14
+ position: absolute; right: var(--uix-space-2); display: inline-flex; align-items: center; gap: var(--uix-space-2);
15
+ }
16
+ .uix-search-suggest__spinner { width: 14px; height: 14px; }
17
+ .uix-search-suggest__clear {
18
+ display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0;
19
+ border: 0; border-radius: var(--uix-radius-sm); background: transparent; color: var(--uix-text-muted); cursor: pointer;
20
+ }
21
+ .uix-search-suggest__clear svg { width: 14px; height: 14px; }
22
+ .uix-search-suggest__clear:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
23
+ .uix-search-suggest__clear:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 1px; }
24
+
25
+ .uix-search-suggest--lg .uix-search-suggest__input { height: calc(var(--uix-control-h) + 8px); padding-left: 44px; font-size: var(--uix-text-h3); }
26
+ .uix-search-suggest--lg .uix-search-suggest__lead { left: 14px; }
27
+ .uix-search-suggest--lg .uix-search-suggest__lead svg { width: var(--uix-icon-lg); height: var(--uix-icon-lg); }
28
+
29
+ /* the suggestion list */
30
+ .uix-search-suggest__popup:not([hidden]) {
31
+ position: absolute; z-index: var(--uix-z-dropdown); inset-inline: 0; top: calc(100% + var(--uix-space-1));
32
+ display: flex; flex-direction: column; max-height: min(28rem, 70vh); overflow-y: auto; overscroll-behavior: contain;
33
+ padding: var(--uix-space-1); background: var(--uix-surface-2); border: 1px solid var(--uix-border);
34
+ border-radius: var(--uix-radius-md); box-shadow: var(--uix-shadow-popover);
35
+ animation: uix-search-suggest-in var(--uix-dur-fast) var(--uix-ease-out);
36
+ }
37
+ @keyframes uix-search-suggest-in { from { opacity: 0; transform: translateY(-4px); } }
38
+
39
+ .uix-search-suggest__header {
40
+ display: flex; align-items: baseline; justify-content: space-between; gap: var(--uix-space-3);
41
+ padding: var(--uix-space-2) var(--uix-space-3) var(--uix-space-1);
42
+ }
43
+ .uix-search-suggest__heading {
44
+ font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow); text-transform: uppercase; color: var(--uix-text-muted);
45
+ }
46
+ .uix-search-suggest__header-action {
47
+ border: 0; padding: 0; background: none; font: inherit; font-size: var(--uix-text-meta); color: var(--uix-link); cursor: pointer;
48
+ border-radius: var(--uix-radius-xs);
49
+ }
50
+ .uix-search-suggest__header-action:hover { text-decoration: underline; }
51
+ .uix-search-suggest__header-action:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 2px; }
52
+
53
+ .uix-search-suggest__list { list-style: none; margin: 0; padding: 0; }
54
+ .uix-search-suggest__list:empty { display: none; }
55
+
56
+ .uix-search-suggest__option {
57
+ display: flex; align-items: flex-start; gap: var(--uix-space-3);
58
+ padding: var(--uix-space-2) var(--uix-space-3); border-radius: var(--uix-radius-sm); cursor: pointer; color: var(--uix-text);
59
+ }
60
+ .uix-search-suggest__option[data-active] { background: var(--uix-bg-hover); }
61
+ .uix-search-suggest__icon { display: inline-flex; flex: none; margin-top: 2px; color: var(--uix-text-muted); }
62
+ .uix-search-suggest__icon svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
63
+ .uix-search-suggest__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
64
+ .uix-search-suggest__title {
65
+ font-size: var(--uix-text-body); font-weight: 500; line-height: 1.35;
66
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
67
+ }
68
+
69
+ /* breadcrumb: middle crumbs give way first so the outermost and the innermost stay readable */
70
+ .uix-search-suggest__meta {
71
+ display: flex; min-width: 0; overflow: hidden; white-space: nowrap;
72
+ font-size: var(--uix-text-meta); line-height: 1.35; color: var(--uix-text-muted);
73
+ }
74
+ .uix-search-suggest__crumb { flex: 0 1000 auto; min-width: 1.75em; overflow: hidden; text-overflow: ellipsis; }
75
+ .uix-search-suggest__crumb:first-child, .uix-search-suggest__crumb:last-child { flex-shrink: 1; min-width: 3em; }
76
+ .uix-search-suggest__crumb:only-child { min-width: 0; }
77
+ .uix-search-suggest__crumb + .uix-search-suggest__crumb::before { content: "›"; margin-inline: var(--uix-space-1); color: var(--uix-text-hushed); }
78
+
79
+ .uix-search-suggest__desc {
80
+ display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
81
+ font-size: var(--uix-text-meta); line-height: 1.45; color: var(--uix-text-muted);
82
+ }
83
+
84
+ /* matched letters: weight, not a highlighter — reads as Windows / Android settings search does */
85
+ .uix-search-suggest__match { background: none; color: inherit; font-weight: 700; }
86
+ .uix-search-suggest__desc .uix-search-suggest__match { color: var(--uix-text); font-weight: 600; }
87
+
88
+ .uix-search-suggest__footer {
89
+ margin-top: var(--uix-space-1); padding: var(--uix-space-2) var(--uix-space-3);
90
+ border-top: 1px solid var(--uix-border); border-radius: 0 0 var(--uix-radius-sm) var(--uix-radius-sm);
91
+ font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-link); cursor: pointer;
92
+ }
93
+ .uix-search-suggest__footer:first-child { margin-top: 0; border-top: 0; border-radius: var(--uix-radius-sm); }
94
+ .uix-search-suggest__footer[data-active] { background: var(--uix-bg-hover); }
95
+
96
+ .uix-search-suggest__state {
97
+ display: flex; align-items: center; justify-content: center; gap: var(--uix-space-2); flex-wrap: wrap;
98
+ padding: var(--uix-space-4) var(--uix-space-3); text-align: center; font-size: var(--uix-text-meta); color: var(--uix-text-muted);
99
+ }
100
+ .uix-search-suggest__state .uix-spinner { width: 16px; height: 16px; }
101
+
102
+ /* touch-sized rows on narrow screens */
103
+ @media (max-width: 640px) {
104
+ .uix-search-suggest__popup:not([hidden]) { max-height: 60vh; }
105
+ .uix-search-suggest__option { min-height: 44px; padding-block: var(--uix-space-3); }
106
+ }
107
+
108
+ @media (prefers-reduced-motion: reduce) {
109
+ .uix-search-suggest__popup:not([hidden]) { animation: none; }
110
+ }
111
+
112
+ @media (forced-colors: active) {
113
+ .uix-search-suggest__option[data-active], .uix-search-suggest__footer[data-active] { outline: 2px solid Highlight; outline-offset: -2px; }
114
+ .uix-search-suggest__match { text-decoration: underline; }
115
+ }
116
+ }