@tensor_1/tokens 2.9.0 → 2.11.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.
@@ -456,7 +456,9 @@
456
456
  @layer uix.components {
457
457
  .uix-breadcrumbs { display: flex; align-items: center; gap: var(--uix-space-2); flex-wrap: wrap; font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
458
458
  .uix-breadcrumbs a { color: var(--uix-text-muted); text-decoration: none; }
459
- .uix-breadcrumbs a:hover { color: var(--uix-text); text-decoration: underline; }
459
+ /* already a quiet link by its own design — hover/focus parity with the quiet-link
460
+ contract in link.css, so the keyboard state matches the pointer state. */
461
+ .uix-breadcrumbs a:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
460
462
  .uix-breadcrumbs__sep { opacity: .55; }
461
463
  .uix-breadcrumbs [aria-current="page"] { color: var(--uix-text); font-weight: 500; }
462
464
  }
@@ -1651,7 +1653,8 @@
1651
1653
  .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); }
1652
1654
  .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); }
1653
1655
  .uix-section-link { color: var(--uix-text-hushed); font-size: var(--uix-text-meta); text-decoration: none; }
1654
- .uix-section-link:hover { color: var(--uix-text); }
1656
+ /* already a quiet link by its own design — hover/focus parity with link.css */
1657
+ .uix-section-link:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
1655
1658
 
1656
1659
  /* ── content grid + rail ───────────────────────────────────────────────────── */
1657
1660
  .uix-content-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, 0.75fr); gap: var(--uix-space-7); align-items: start; }
@@ -1755,36 +1758,90 @@
1755
1758
  * noise at list density (TENSOR INTRA-04, operator-rejected).
1756
1759
  *
1757
1760
  * A quiet link inherits the surrounding text colour and shows its underline on
1758
- * hover/focus. 1.4.1 is not in play: the link is the whole text of its block (a title,
1759
- * a cell), not a link inside body copy. NEVER quiet a link inside prose — in-text links
1760
- * keep the base blue + underline.
1761
+ * hover/focus. The global :focus-visible ring (base.css) still fires, so the keyboard
1762
+ * affordance never rests on the underline alone. WCAG 1.4.1 is not in play for anything
1763
+ * below: the link is the WHOLE text of its block — a title, a name, a data cell — or it
1764
+ * is the block itself. It is never a phrase inside a sentence.
1761
1765
  *
1762
- * Two forms:
1763
- * • `.uix-link--quiet` — the opt-in utility, for block links outside the scoped slots
1764
- * (whole-card links, event rows composed by hand, app-specific list patterns).
1765
- * • quiet BY DEFAULT below — the editorial-home title slots and table data cells,
1766
- * where every anchor is a block-level navigation target. `.uix-table td` keeps
1767
- * `:not([class])` so class-bearing anchors in cells (`.uix-btn--link`, pills)
1768
- * stay styled.
1766
+ * A slot earns quiet-BY-DEFAULT only when BOTH hold:
1767
+ * (i) the anchor fills a named title/name slot or a data cell — the link text IS the
1768
+ * block, not a phrase inside running copy; and
1769
+ * (ii) the surrounding row/card/tile already reads as interactive (hover state, cursor,
1770
+ * bordered unit), or the slot is that record's primary label.
1771
+ *
1772
+ * Deliberate exclusions, so the next person doesn't "finish the job":
1773
+ * • Prose and message bodies — .uix-prose, .uix-note, .uix-notice__copy,
1774
+ * .uix-timeline__body, .uix-audit__detail, .uix-notif copy. Links there sit inside
1775
+ * sentences: 1.4.1 applies and the base treatment is correct.
1776
+ * • .uix-alert, .uix-toast, .uix-peek__title — nothing else in those containers signals
1777
+ * that the link navigates, so the colour IS the affordance. peek.css sets --uix-link
1778
+ * on its title anchor on purpose; do not quiet it.
1779
+ * • .uix-comment__author — a byline renders "Author · 22m ago", so the name is a phrase
1780
+ * inside a text run, not the whole block, and .uix-comment__meta is not interactive.
1781
+ * It fails test (i) above. Products wanting the GitHub-style quiet byline opt in with
1782
+ * .uix-link--quiet; that is what the utility is for.
1783
+ * • .uix-navitem, .uix-breadcrumbs a, .uix-section-link are already quiet by their own
1784
+ * design and need no class here.
1785
+ *
1786
+ * Four forms:
1787
+ * 1 · `.uix-link--quiet` — the opt-in utility, for block links outside the registry.
1788
+ * 2 · TITLE / NAME SLOTS — quiet by default. `:not(.uix-btn)` so an anchor deliberately
1789
+ * styled as a button inside a title slot keeps its button treatment.
1790
+ * 3 · DATA CELLS — table cells and description-list values. `:not([class])` so
1791
+ * class-bearing anchors (`.uix-btn--link`, pills, tags) stay styled.
1792
+ * 4 · CONTAINER ANCHORS — the anchor IS the kit block (`<a class="uix-card">`). Without
1793
+ * this the base `a { color }` tints every word in the block brand-blue.
1769
1794
  * Depends only on --uix-* tokens. */
1770
1795
  @layer uix.components {
1771
1796
  .uix-link--quiet,
1772
- .uix-content-list__title a,
1773
- .uix-news-lead__title a,
1774
- .uix-rundown__item-title a,
1775
- .uix-event-row__title a,
1776
- .uix-table td a:not([class]) { color: inherit; text-decoration: none; }
1777
-
1778
- .uix-link--quiet:hover,
1779
- .uix-link--quiet:focus-visible,
1780
- .uix-content-list__title a:hover,
1781
- .uix-content-list__title a:focus-visible,
1782
- .uix-news-lead__title a:hover,
1783
- .uix-news-lead__title a:focus-visible,
1784
- .uix-rundown__item-title a:hover,
1785
- .uix-rundown__item-title a:focus-visible,
1786
- .uix-event-row__title a:hover,
1787
- .uix-event-row__title a:focus-visible,
1788
- .uix-table td a:not([class]):hover,
1789
- .uix-table td a:not([class]):focus-visible { text-decoration: underline; }
1797
+
1798
+ /* 2 · title / name slots */
1799
+ :is(
1800
+ /* editorial-home */
1801
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
1802
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
1803
+ .uix-status-row__name,
1804
+ /* records, rows, cards */
1805
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
1806
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
1807
+ .uix-audit__actor
1808
+ ) a:not(.uix-btn),
1809
+
1810
+ /* 3 · data cells */
1811
+ :is(.uix-table td, .uix-dl dd) a:not([class]),
1812
+
1813
+ /* 4 · container anchors */
1814
+ a:is(
1815
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
1816
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
1817
+ .uix-content-list__item, .uix-event-row, .uix-status-row
1818
+ ) { color: inherit; text-decoration: none; }
1819
+
1820
+ .uix-link--quiet:is(:hover, :focus-visible),
1821
+
1822
+ :is(
1823
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
1824
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
1825
+ .uix-status-row__name,
1826
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
1827
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
1828
+ .uix-audit__actor
1829
+ ) a:not(.uix-btn):is(:hover, :focus-visible),
1830
+
1831
+ :is(.uix-table td, .uix-dl dd) a:not([class]):is(:hover, :focus-visible) { text-decoration: underline; }
1832
+
1833
+ /* Container anchors never underline: the anchor wraps the whole block, so an underline
1834
+ would strike through every word in it. They take the kit's standard row-hover tint
1835
+ instead — the same --uix-bg-hover that .uix-list__item / .uix-inbox__item / .uix-cmdk__item
1836
+ already use, so containers with a hover of their own just restate it. */
1837
+ a:is(
1838
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
1839
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
1840
+ .uix-content-list__item, .uix-event-row, .uix-status-row
1841
+ ):is(:hover, :focus-visible) { background: var(--uix-bg-hover); }
1842
+
1843
+ /* Container anchors that declare no display of their own would render inline as an <a>.
1844
+ The rest of form 4 (flex/grid rows) set theirs already and must NOT be overridden —
1845
+ link.css is imported last, so a blanket display here would flatten them. */
1846
+ a:is(.uix-card, .uix-stat, .uix-kanban__card) { display: block; }
1790
1847
  }
@@ -752,7 +752,9 @@
752
752
  @layer uix.components {
753
753
  .uix-breadcrumbs { display: flex; align-items: center; gap: var(--uix-space-2); flex-wrap: wrap; font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
754
754
  .uix-breadcrumbs a { color: var(--uix-text-muted); text-decoration: none; }
755
- .uix-breadcrumbs a:hover { color: var(--uix-text); text-decoration: underline; }
755
+ /* already a quiet link by its own design — hover/focus parity with the quiet-link
756
+ contract in link.css, so the keyboard state matches the pointer state. */
757
+ .uix-breadcrumbs a:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
756
758
  .uix-breadcrumbs__sep { opacity: .55; }
757
759
  .uix-breadcrumbs [aria-current="page"] { color: var(--uix-text); font-weight: 500; }
758
760
  }
@@ -1992,7 +1994,8 @@
1992
1994
  .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); }
1993
1995
  .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); }
1994
1996
  .uix-section-link { color: var(--uix-text-hushed); font-size: var(--uix-text-meta); text-decoration: none; }
1995
- .uix-section-link:hover { color: var(--uix-text); }
1997
+ /* already a quiet link by its own design — hover/focus parity with link.css */
1998
+ .uix-section-link:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
1996
1999
 
1997
2000
  /* ── content grid + rail ───────────────────────────────────────────────────── */
1998
2001
  .uix-content-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, 0.75fr); gap: var(--uix-space-7); align-items: start; }
@@ -2096,36 +2099,90 @@
2096
2099
  * noise at list density (TENSOR INTRA-04, operator-rejected).
2097
2100
  *
2098
2101
  * A quiet link inherits the surrounding text colour and shows its underline on
2099
- * hover/focus. 1.4.1 is not in play: the link is the whole text of its block (a title,
2100
- * a cell), not a link inside body copy. NEVER quiet a link inside prose — in-text links
2101
- * keep the base blue + underline.
2102
+ * hover/focus. The global :focus-visible ring (base.css) still fires, so the keyboard
2103
+ * affordance never rests on the underline alone. WCAG 1.4.1 is not in play for anything
2104
+ * below: the link is the WHOLE text of its block — a title, a name, a data cell — or it
2105
+ * is the block itself. It is never a phrase inside a sentence.
2102
2106
  *
2103
- * Two forms:
2104
- * • `.uix-link--quiet` — the opt-in utility, for block links outside the scoped slots
2105
- * (whole-card links, event rows composed by hand, app-specific list patterns).
2106
- * • quiet BY DEFAULT below — the editorial-home title slots and table data cells,
2107
- * where every anchor is a block-level navigation target. `.uix-table td` keeps
2108
- * `:not([class])` so class-bearing anchors in cells (`.uix-btn--link`, pills)
2109
- * stay styled.
2107
+ * A slot earns quiet-BY-DEFAULT only when BOTH hold:
2108
+ * (i) the anchor fills a named title/name slot or a data cell — the link text IS the
2109
+ * block, not a phrase inside running copy; and
2110
+ * (ii) the surrounding row/card/tile already reads as interactive (hover state, cursor,
2111
+ * bordered unit), or the slot is that record's primary label.
2112
+ *
2113
+ * Deliberate exclusions, so the next person doesn't "finish the job":
2114
+ * • Prose and message bodies — .uix-prose, .uix-note, .uix-notice__copy,
2115
+ * .uix-timeline__body, .uix-audit__detail, .uix-notif copy. Links there sit inside
2116
+ * sentences: 1.4.1 applies and the base treatment is correct.
2117
+ * • .uix-alert, .uix-toast, .uix-peek__title — nothing else in those containers signals
2118
+ * that the link navigates, so the colour IS the affordance. peek.css sets --uix-link
2119
+ * on its title anchor on purpose; do not quiet it.
2120
+ * • .uix-comment__author — a byline renders "Author · 22m ago", so the name is a phrase
2121
+ * inside a text run, not the whole block, and .uix-comment__meta is not interactive.
2122
+ * It fails test (i) above. Products wanting the GitHub-style quiet byline opt in with
2123
+ * .uix-link--quiet; that is what the utility is for.
2124
+ * • .uix-navitem, .uix-breadcrumbs a, .uix-section-link are already quiet by their own
2125
+ * design and need no class here.
2126
+ *
2127
+ * Four forms:
2128
+ * 1 · `.uix-link--quiet` — the opt-in utility, for block links outside the registry.
2129
+ * 2 · TITLE / NAME SLOTS — quiet by default. `:not(.uix-btn)` so an anchor deliberately
2130
+ * styled as a button inside a title slot keeps its button treatment.
2131
+ * 3 · DATA CELLS — table cells and description-list values. `:not([class])` so
2132
+ * class-bearing anchors (`.uix-btn--link`, pills, tags) stay styled.
2133
+ * 4 · CONTAINER ANCHORS — the anchor IS the kit block (`<a class="uix-card">`). Without
2134
+ * this the base `a { color }` tints every word in the block brand-blue.
2110
2135
  * Depends only on --uix-* tokens. */
2111
2136
  @layer uix.components {
2112
2137
  .uix-link--quiet,
2113
- .uix-content-list__title a,
2114
- .uix-news-lead__title a,
2115
- .uix-rundown__item-title a,
2116
- .uix-event-row__title a,
2117
- .uix-table td a:not([class]) { color: inherit; text-decoration: none; }
2118
-
2119
- .uix-link--quiet:hover,
2120
- .uix-link--quiet:focus-visible,
2121
- .uix-content-list__title a:hover,
2122
- .uix-content-list__title a:focus-visible,
2123
- .uix-news-lead__title a:hover,
2124
- .uix-news-lead__title a:focus-visible,
2125
- .uix-rundown__item-title a:hover,
2126
- .uix-rundown__item-title a:focus-visible,
2127
- .uix-event-row__title a:hover,
2128
- .uix-event-row__title a:focus-visible,
2129
- .uix-table td a:not([class]):hover,
2130
- .uix-table td a:not([class]):focus-visible { text-decoration: underline; }
2138
+
2139
+ /* 2 · title / name slots */
2140
+ :is(
2141
+ /* editorial-home */
2142
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
2143
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
2144
+ .uix-status-row__name,
2145
+ /* records, rows, cards */
2146
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
2147
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
2148
+ .uix-audit__actor
2149
+ ) a:not(.uix-btn),
2150
+
2151
+ /* 3 · data cells */
2152
+ :is(.uix-table td, .uix-dl dd) a:not([class]),
2153
+
2154
+ /* 4 · container anchors */
2155
+ a:is(
2156
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
2157
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
2158
+ .uix-content-list__item, .uix-event-row, .uix-status-row
2159
+ ) { color: inherit; text-decoration: none; }
2160
+
2161
+ .uix-link--quiet:is(:hover, :focus-visible),
2162
+
2163
+ :is(
2164
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
2165
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
2166
+ .uix-status-row__name,
2167
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
2168
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
2169
+ .uix-audit__actor
2170
+ ) a:not(.uix-btn):is(:hover, :focus-visible),
2171
+
2172
+ :is(.uix-table td, .uix-dl dd) a:not([class]):is(:hover, :focus-visible) { text-decoration: underline; }
2173
+
2174
+ /* Container anchors never underline: the anchor wraps the whole block, so an underline
2175
+ would strike through every word in it. They take the kit's standard row-hover tint
2176
+ instead — the same --uix-bg-hover that .uix-list__item / .uix-inbox__item / .uix-cmdk__item
2177
+ already use, so containers with a hover of their own just restate it. */
2178
+ a:is(
2179
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
2180
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
2181
+ .uix-content-list__item, .uix-event-row, .uix-status-row
2182
+ ):is(:hover, :focus-visible) { background: var(--uix-bg-hover); }
2183
+
2184
+ /* Container anchors that declare no display of their own would render inline as an <a>.
2185
+ The rest of form 4 (flex/grid rows) set theirs already and must NOT be overridden —
2186
+ link.css is imported last, so a blanket display here would flatten them. */
2187
+ a:is(.uix-card, .uix-stat, .uix-kanban__card) { display: block; }
2131
2188
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensor_1/tokens",
3
- "version": "2.9.0",
3
+ "version": "2.11.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
  "license": "UNLICENSED",