@tangle-network/brand 1.21.0 → 1.22.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/CHANGELOG.md +16 -0
- package/README.md +5 -8
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +1 -1
- package/src/palette.generated.ts +2 -2
- package/src/styles/globals.css +6 -0
- package/src/styles/legacy-light.css +10 -10
- package/src/styles/named-themes.css +1 -1
- package/src/styles/named-themes.test.ts +47 -0
- package/src/styles/theme.css +2 -2
- package/src/styles/tokens.css +9 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.22.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c94bde7: Fix shared defects from the Hospitality design audit.
|
|
8
|
+
|
|
9
|
+
Brand: dark `--destructive` is now a light red carrying dark ink (`0 90% 77%` on `0 60% 10%`), so `text-destructive` clears AA (at least 4.5:1) on the canvas, card, popover and muted planes of every dark theme; it measured 2.5:1 on Hospitality's dark card. Destructive fills keep their foreground at 8:1. The `--font-sans` and `--font-display` stacks name `"Inter Variable"` ahead of `"Inter"`, and the README now recommends `@fontsource-variable/inter` so apps render every weight the scale uses. Brand still loads no fonts itself.
|
|
10
|
+
|
|
11
|
+
UI: the `tabs` SegmentedControl scrolls the selected tab into view inside the strip (never the page) and fades the edge that has more tabs past it; tab items take a 44px hit height on coarse pointers; labels keep one weight in both variants, so changing the selection no longer shifts the row. SelectTrigger values end in an ellipsis with a gap before the chevron instead of clipping mid-glyph. Plain-text code fences (`text`, `txt`, `plain`, `plaintext`) show no language label.
|
|
12
|
+
|
|
13
|
+
## 1.21.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- ec74a23: One transcript size across products: `--transcript-font-size` is 16px, the size Agent App's `ChatMessages` and Hospitality's transcript already used, instead of the 15px message body that UI's `AgentTimeline` used, so every agent app reads its transcript at one size. Markdown inside a `tangle-transcript-text` container inherits its size and leading rather than `.tangle-prose`'s own 1.7.
|
|
18
|
+
|
|
3
19
|
## 1.21.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -105,7 +105,7 @@ Renderers that cannot read CSS variables (PDF, canvas, WebGL, email, the `theme-
|
|
|
105
105
|
|
|
106
106
|
The base surface ladder is the one GTM proved out: dark is indigo-lifted `#0a0a14` / `#191826` / `#221f33` / `#2c2942`; light is a cool `#eceef3` canvas, white paper cards and overlays, and `#f1f2f7` nested wells. The cast stays below 0.1 chroma and ink stays achromatic, so indigo still reads as the interaction accent, not the base field. Existing named products may supply deliberate surface overrides.
|
|
107
107
|
|
|
108
|
-
Chrome radii are 6/8/10/12px in both base modes; the composer has its own 26px role. Inter leads body and display stacks, with Geist fallbacks; Geist Mono leads code with JetBrains Mono and system fallbacks. Runtime font/radius registrations retain their public override names; tests keep Tailwind registration defaults aligned with the canonical declarations.
|
|
108
|
+
Chrome radii are 6/8/10/12px in both base modes; the composer has its own 26px role. Inter (variable, then static) leads body and display stacks, with Geist fallbacks; Geist Mono leads code with JetBrains Mono and system fallbacks. Runtime font/radius registrations retain their public override names; tests keep Tailwind registration defaults aligned with the canonical declarations.
|
|
109
109
|
|
|
110
110
|
Existing `--transition-*` values are preserved. The shared `--duration-*`, `--ease-*` and `--motion-*` vocabulary comes from the existing Agent App contract. It does not apply animations automatically. Reduced motion zeroes those durations and re-resolves composites at theme boundaries.
|
|
111
111
|
|
|
@@ -113,22 +113,19 @@ Focus uses `--focus-border`, `--focus-halo`, their danger variants, and `--borde
|
|
|
113
113
|
|
|
114
114
|
## Fonts
|
|
115
115
|
|
|
116
|
-
Fonts are referenced, **not bundled or remotely fetched**. Consumers own loading, privacy and network fallbacks.
|
|
116
|
+
Fonts are referenced, **not bundled or remotely fetched**. Consumers own loading, privacy and network fallbacks, and an app that loads nothing renders in the OS fallback (DejaVu, Segoe, SF), whose widths and weights the type scale was not tuned for. Load Inter in the app entry. The variable build is one file that renders every weight the scale uses, including in-between weights such as 650 that static files round to the nearest cut:
|
|
117
117
|
|
|
118
118
|
```sh
|
|
119
|
-
pnpm add @fontsource/inter @fontsource/geist-mono
|
|
119
|
+
pnpm add @fontsource-variable/inter @fontsource/geist-mono
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
```tsx
|
|
123
|
-
import "@fontsource/inter
|
|
124
|
-
import "@fontsource/inter/500.css";
|
|
125
|
-
import "@fontsource/inter/600.css";
|
|
126
|
-
import "@fontsource/inter/700.css";
|
|
123
|
+
import "@fontsource-variable/inter";
|
|
127
124
|
import "@fontsource/geist-mono/400.css";
|
|
128
125
|
import "@fontsource/geist-mono/500.css";
|
|
129
126
|
```
|
|
130
127
|
|
|
131
|
-
Omitted families fall back through the `--font-*` stacks. Keep external font imports out of library CSS: they can break reordered CSS imports and should not impose a
|
|
128
|
+
The `--font-sans` and `--font-display` stacks name `"Inter Variable"` (the family that package registers) ahead of `"Inter"`, so static `@fontsource/inter` imports keep working. Omitted families fall back through the `--font-*` stacks. Keep external font imports out of library CSS: they can break reordered CSS imports and should not impose a font download on every consumer.
|
|
132
129
|
|
|
133
130
|
## Policy and development
|
|
134
131
|
|
package/dist/index.d.ts
CHANGED
|
@@ -97,7 +97,7 @@ export declare const palettes: {
|
|
|
97
97
|
readonly accentHover: "#5a50d6";
|
|
98
98
|
readonly onAccent: "#ffffff";
|
|
99
99
|
readonly accentText: "#a5b4fc";
|
|
100
|
-
readonly danger: "#
|
|
100
|
+
readonly danger: "#f99090";
|
|
101
101
|
readonly successBg: "#2f5146";
|
|
102
102
|
readonly successBorder: "#3c7760";
|
|
103
103
|
readonly successText: "#5ed7a4";
|
|
@@ -163,7 +163,7 @@ export declare const palettes: {
|
|
|
163
163
|
readonly accentHover: "#5a50d6";
|
|
164
164
|
readonly onAccent: "#ffffff";
|
|
165
165
|
readonly accentText: "#a5b4fc";
|
|
166
|
-
readonly danger: "#
|
|
166
|
+
readonly danger: "#f99090";
|
|
167
167
|
readonly successBg: "#2f5146";
|
|
168
168
|
readonly successBorder: "#3c7760";
|
|
169
169
|
readonly successText: "#5ed7a4";
|
package/dist/index.js
CHANGED
|
@@ -156,7 +156,7 @@ const palettes = {
|
|
|
156
156
|
accentHover: "#5a50d6",
|
|
157
157
|
onAccent: "#ffffff",
|
|
158
158
|
accentText: "#a5b4fc",
|
|
159
|
-
danger: "#
|
|
159
|
+
danger: "#f99090",
|
|
160
160
|
successBg: "#2f5146",
|
|
161
161
|
successBorder: "#3c7760",
|
|
162
162
|
successText: "#5ed7a4",
|
|
@@ -222,7 +222,7 @@ const palettes = {
|
|
|
222
222
|
accentHover: "#5a50d6",
|
|
223
223
|
onAccent: "#ffffff",
|
|
224
224
|
accentText: "#a5b4fc",
|
|
225
|
-
danger: "#
|
|
225
|
+
danger: "#f99090",
|
|
226
226
|
successBg: "#2f5146",
|
|
227
227
|
successBorder: "#3c7760",
|
|
228
228
|
successText: "#5ed7a4",
|
package/package.json
CHANGED
package/src/palette.generated.ts
CHANGED
|
@@ -87,7 +87,7 @@ export const palettes = {
|
|
|
87
87
|
accentHover: "#5a50d6",
|
|
88
88
|
onAccent: "#ffffff",
|
|
89
89
|
accentText: "#a5b4fc",
|
|
90
|
-
danger: "#
|
|
90
|
+
danger: "#f99090",
|
|
91
91
|
successBg: "#2f5146",
|
|
92
92
|
successBorder: "#3c7760",
|
|
93
93
|
successText: "#5ed7a4",
|
|
@@ -153,7 +153,7 @@ export const palettes = {
|
|
|
153
153
|
accentHover: "#5a50d6",
|
|
154
154
|
onAccent: "#ffffff",
|
|
155
155
|
accentText: "#a5b4fc",
|
|
156
|
-
danger: "#
|
|
156
|
+
danger: "#f99090",
|
|
157
157
|
successBg: "#2f5146",
|
|
158
158
|
successBorder: "#3c7760",
|
|
159
159
|
successText: "#5ed7a4",
|
package/src/styles/globals.css
CHANGED
|
@@ -186,6 +186,12 @@
|
|
|
186
186
|
font-size: var(--transcript-font-size);
|
|
187
187
|
line-height: var(--transcript-line-height);
|
|
188
188
|
}
|
|
189
|
+
/* Markdown inside a transcript container reads at the container's size and
|
|
190
|
+
* leading, not .tangle-prose's own 1.7. */
|
|
191
|
+
.tangle-transcript-text .tangle-prose {
|
|
192
|
+
font-size: inherit;
|
|
193
|
+
line-height: inherit;
|
|
194
|
+
}
|
|
189
195
|
.tangle-prose > * + * { margin-top: 0.85em; }
|
|
190
196
|
.tangle-prose h1, .tangle-prose h2, .tangle-prose h3, .tangle-prose h4 {
|
|
191
197
|
font-weight: 600;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* GENERATED by scripts/gen-compat.mjs. Do not edit.
|
|
2
2
|
* Source: tokens.css + named-themes.css
|
|
3
|
-
* SHA-256:
|
|
3
|
+
* SHA-256: cf009734f12a6dcb94d31f9ee6c21583942f1b2b2be38454344d6c3403cd26b5
|
|
4
4
|
* Light-default compatibility; all explicit modes remain canonical.
|
|
5
5
|
*/
|
|
6
6
|
:where(:root),
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
--hsl-muted-foreground: 240 5% 68%;
|
|
75
75
|
--hsl-accent: 249 24% 16%;
|
|
76
76
|
--hsl-accent-foreground: 0 0% 90.1961%;
|
|
77
|
-
--hsl-destructive:
|
|
78
|
-
--hsl-destructive-foreground: 0
|
|
77
|
+
--hsl-destructive: 0 90% 77%;
|
|
78
|
+
--hsl-destructive-foreground: 0 60% 10%;
|
|
79
79
|
--hsl-border: 243 20% 20%;
|
|
80
80
|
--hsl-input: 244 29% 9%;
|
|
81
81
|
--hsl-ring: 233 100% 87%;
|
|
@@ -299,7 +299,7 @@
|
|
|
299
299
|
--content-max-width: 80rem;
|
|
300
300
|
--shell-header-height: 3.5rem;
|
|
301
301
|
--shell-inset-gutter: 0.5rem;
|
|
302
|
-
--transcript-font-size:
|
|
302
|
+
--transcript-font-size: 1rem;
|
|
303
303
|
--transcript-line-height: var(--line-height-base);
|
|
304
304
|
--font-size-xs: 0.6875rem;
|
|
305
305
|
--font-size-sm: 0.75rem;
|
|
@@ -365,8 +365,8 @@
|
|
|
365
365
|
--transition-fast: 0.1s ease;
|
|
366
366
|
--transition-default: 0.16s ease;
|
|
367
367
|
--transition-medium: 0.24s ease;
|
|
368
|
-
--font-sans: "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
369
|
-
--font-display: "Inter", "Geist", sans-serif;
|
|
368
|
+
--font-sans: "Inter Variable", "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
369
|
+
--font-display: "Inter Variable", "Inter", "Geist", sans-serif;
|
|
370
370
|
--font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
371
371
|
}
|
|
372
372
|
[data-sandbox-theme="vault"]:where(:not(.dark)),
|
|
@@ -610,8 +610,8 @@
|
|
|
610
610
|
--accent-surface-soft: rgba(76, 63, 198, 0.05);
|
|
611
611
|
--accent-surface-strong: rgba(76, 63, 198, 0.13);
|
|
612
612
|
--accent-text: #3c32e9;
|
|
613
|
-
--font-sans: "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
614
|
-
--font-display: "Inter", "Geist", sans-serif;
|
|
613
|
+
--font-sans: "Inter Variable", "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
614
|
+
--font-display: "Inter Variable", "Inter", "Geist", sans-serif;
|
|
615
615
|
--font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
616
616
|
--radius-sm: 6px;
|
|
617
617
|
--radius-md: 8px;
|
|
@@ -1152,8 +1152,8 @@
|
|
|
1152
1152
|
--hsl-muted-foreground: 240 5% 68%;
|
|
1153
1153
|
--hsl-accent: 249 24% 16%;
|
|
1154
1154
|
--hsl-accent-foreground: 0 0% 90.1961%;
|
|
1155
|
-
--hsl-destructive:
|
|
1156
|
-
--hsl-destructive-foreground: 0
|
|
1155
|
+
--hsl-destructive: 0 90% 77%;
|
|
1156
|
+
--hsl-destructive-foreground: 0 60% 10%;
|
|
1157
1157
|
--hsl-border: 243 20% 20%;
|
|
1158
1158
|
--hsl-input: 244 29% 9%;
|
|
1159
1159
|
--hsl-ring: 233 100% 87%;
|
|
@@ -243,7 +243,7 @@
|
|
|
243
243
|
--hsl-secondary: 249 24% 16%; --hsl-secondary-foreground: 0 0% 90.1961%;
|
|
244
244
|
--hsl-muted: 249 24% 16%; --hsl-muted-foreground: 240 5% 68%;
|
|
245
245
|
--hsl-accent: 249 24% 16%; --hsl-accent-foreground: 0 0% 90.1961%;
|
|
246
|
-
--hsl-destructive:
|
|
246
|
+
--hsl-destructive: 0 90% 77%; --hsl-destructive-foreground: 0 60% 10%;
|
|
247
247
|
--hsl-border: 243 20% 20%; --hsl-input: 244 29% 9%;
|
|
248
248
|
--hsl-ring: 233 100% 87%;
|
|
249
249
|
--depth-1: #0a0a14; --depth-2: #191826; --depth-3: #221f33; --depth-4: #2c2942;
|
|
@@ -4,6 +4,7 @@ import { describe, expect, it } from "vitest";
|
|
|
4
4
|
import {
|
|
5
5
|
blockIn,
|
|
6
6
|
blocksIn,
|
|
7
|
+
compositeOver,
|
|
7
8
|
contrastRatio,
|
|
8
9
|
declIn,
|
|
9
10
|
hexIn,
|
|
@@ -653,3 +654,49 @@ describe('named theme: [data-theme="website"]', () => {
|
|
|
653
654
|
}
|
|
654
655
|
});
|
|
655
656
|
});
|
|
657
|
+
|
|
658
|
+
describe("dark themes: destructive reads as text", () => {
|
|
659
|
+
// `text-destructive` is the error ink on cards, popovers and wells, and
|
|
660
|
+
// `bg-destructive text-destructive-foreground` is the destructive fill. In
|
|
661
|
+
// dark mode one token must serve both, so it is a light red carrying dark
|
|
662
|
+
// ink, as the dark primary does: 2.5:1 error text on a sage card shipped
|
|
663
|
+
// before every dark scope was checked here.
|
|
664
|
+
const scopes: Array<[string, string]> = [
|
|
665
|
+
[".dark", CANON],
|
|
666
|
+
...[
|
|
667
|
+
'[data-theme="tangle-dark"]',
|
|
668
|
+
'[data-theme="aubergine"]',
|
|
669
|
+
'[data-theme="arena"]',
|
|
670
|
+
'[data-theme="super"]',
|
|
671
|
+
'.dark[data-theme="intelligence"]',
|
|
672
|
+
'.dark[data-theme="hospitality"]',
|
|
673
|
+
'[data-theme="agents"]',
|
|
674
|
+
'.dark[data-theme="website"]',
|
|
675
|
+
].map((selector): [string, string] => {
|
|
676
|
+
const css = blocksIn(themes, selector).find((b) => b.includes("--hsl-background"));
|
|
677
|
+
if (!css) throw new Error(`missing dark theme block: ${selector}`);
|
|
678
|
+
return [selector, css];
|
|
679
|
+
}),
|
|
680
|
+
];
|
|
681
|
+
it.each(scopes)("%s holds AA for destructive text and its fill", (_selector, css) => {
|
|
682
|
+
const effective = (token: string) => {
|
|
683
|
+
try {
|
|
684
|
+
return hslToRgb(hslIn(css, token));
|
|
685
|
+
} catch {
|
|
686
|
+
return hslToRgb(hslIn(CANON, token));
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
const destructive = effective("hsl-destructive");
|
|
690
|
+
for (const plane of ["hsl-background", "hsl-card", "hsl-popover", "hsl-muted"]) {
|
|
691
|
+
const bg = effective(plane);
|
|
692
|
+
expect(contrastRatio(destructive, bg), `destructive text on ${plane}`).toBeGreaterThanOrEqual(4.5);
|
|
693
|
+
// Error rows commonly sit on a 10% destructive tint (bg-destructive/10).
|
|
694
|
+
const tint = compositeOver(destructive, bg, 0.1);
|
|
695
|
+
expect(contrastRatio(destructive, tint), `destructive text on its tint over ${plane}`).toBeGreaterThanOrEqual(4.5);
|
|
696
|
+
}
|
|
697
|
+
expect(
|
|
698
|
+
contrastRatio(effective("hsl-destructive-foreground"), destructive),
|
|
699
|
+
"destructive-foreground on the destructive fill",
|
|
700
|
+
).toBeGreaterThanOrEqual(4.5);
|
|
701
|
+
});
|
|
702
|
+
});
|
package/src/styles/theme.css
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* override --font-* / --radius-* on a subtree.
|
|
6
6
|
*/
|
|
7
7
|
@theme {
|
|
8
|
-
--font-sans: "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
9
|
-
--font-display: "Inter", "Geist", sans-serif;
|
|
8
|
+
--font-sans: "Inter Variable", "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
9
|
+
--font-display: "Inter Variable", "Inter", "Geist", sans-serif;
|
|
10
10
|
--font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
11
11
|
|
|
12
12
|
--text-display--line-height: 1.05;
|
package/src/styles/tokens.css
CHANGED
|
@@ -129,8 +129,10 @@
|
|
|
129
129
|
contrast floor against the L2 card. */
|
|
130
130
|
--hsl-accent: 249 24% 16%; /* neutral hover (indigo lives in accent-surface-strong) */
|
|
131
131
|
--hsl-accent-foreground: 0 0% 90.1961%;
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
/* Light red carrying dark ink, as the dark primary does: it must read as
|
|
133
|
+
* error TEXT on every dark plane (AA) and still carry its foreground as a fill. */
|
|
134
|
+
--hsl-destructive: 0 90% 77%;
|
|
135
|
+
--hsl-destructive-foreground: 0 60% 10%;
|
|
134
136
|
/* Quiet on purpose: 1.5:1 against the resting card. Shadow does no work on a
|
|
135
137
|
* dark canvas, so the hairline is what states where a plane ends. */
|
|
136
138
|
--hsl-border: 243 20% 20%; /* #2a293d = --md3-outline-variant */
|
|
@@ -464,7 +466,7 @@
|
|
|
464
466
|
--shell-inset-gutter: 0.5rem; /* 8px */
|
|
465
467
|
/* Transcript: the person's and the agent's messages share one family, size
|
|
466
468
|
and leading; they differ only by alignment and surface. */
|
|
467
|
-
--transcript-font-size:
|
|
469
|
+
--transcript-font-size: 1rem; /* 16px: the chat reading size */
|
|
468
470
|
--transcript-line-height: var(--line-height-base);
|
|
469
471
|
|
|
470
472
|
/* Typography scale — override per-app for custom type hierarchy.
|
|
@@ -548,8 +550,8 @@
|
|
|
548
550
|
--transition-medium: 0.24s ease;
|
|
549
551
|
|
|
550
552
|
/* Fonts — unified on Inter (dark + light) */
|
|
551
|
-
--font-sans: "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
552
|
-
--font-display: "Inter", "Geist", sans-serif;
|
|
553
|
+
--font-sans: "Inter Variable", "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
554
|
+
--font-display: "Inter Variable", "Inter", "Geist", sans-serif;
|
|
553
555
|
--font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
554
556
|
}
|
|
555
557
|
|
|
@@ -877,8 +879,8 @@
|
|
|
877
879
|
--accent-text: #3c32e9;
|
|
878
880
|
|
|
879
881
|
/* Typography — unified on Inter */
|
|
880
|
-
--font-sans: "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
881
|
-
--font-display: "Inter", "Geist", sans-serif;
|
|
882
|
+
--font-sans: "Inter Variable", "Inter", "Geist", ui-sans-serif, system-ui, -apple-system, sans-serif;
|
|
883
|
+
--font-display: "Inter Variable", "Inter", "Geist", sans-serif;
|
|
882
884
|
--font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, monospace;
|
|
883
885
|
|
|
884
886
|
/* Radius — unified chrome scale (matches dark; 8px md) */
|