@hanzo/design 0.5.15 → 0.5.17
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/brand.cjs +62 -0
- package/dist/index.cjs +92 -0
- package/dist/preference.cjs +225 -0
- package/dist/tokens.gen.cjs +597 -0
- package/dist/tokens.gen.d.ts +4 -1
- package/dist/tokens.gen.d.ts.map +1 -1
- package/dist/tokens.gen.js +4 -1
- package/package.json +4 -3
- package/scripts/check-dist.mjs +20 -0
- package/scripts/cjs.mjs +43 -0
- package/src/tokens.gen.ts +2 -1
- package/styles.css +22 -1
- package/tailwind.css +22 -1
- package/tokens/base.css +22 -1
package/dist/brand.cjs
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// A brand's declared theme, projected onto the semantic tokens.
|
|
3
|
+
//
|
|
4
|
+
// A brand package (@luxfi/brand, @zooai/brand) carries its own light and dark
|
|
5
|
+
// theme in brand.json. This is the ONE place that says which semantic token each
|
|
6
|
+
// of those answers for — the design system owns the token contract, a brand owns
|
|
7
|
+
// the values, and neither holds a copy of the other.
|
|
8
|
+
//
|
|
9
|
+
// It exists because that mapping was about to be written twice: once in each
|
|
10
|
+
// brand package to generate a stylesheet, and once in every app that resolves its
|
|
11
|
+
// brand at runtime and cannot import a build-time stylesheet. Two copies of a
|
|
12
|
+
// mapping is how a brand comes to look like itself in one surface and not
|
|
13
|
+
// another.
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.themeToTokens = themeToTokens;
|
|
16
|
+
exports.applyBrandTheme = applyBrandTheme;
|
|
17
|
+
/** theme key → the semantic tokens it answers for. */
|
|
18
|
+
const OWNS = {
|
|
19
|
+
surface1: ['--background'],
|
|
20
|
+
surface2: ['--card', '--popover', '--muted'],
|
|
21
|
+
surface3: ['--accent'],
|
|
22
|
+
neutral1: ['--foreground', '--card-foreground', '--popover-foreground', '--accent-foreground'],
|
|
23
|
+
neutral2: ['--muted-foreground'],
|
|
24
|
+
neutral3: [],
|
|
25
|
+
accent1: ['--primary'],
|
|
26
|
+
accent2: [],
|
|
27
|
+
accent3: [],
|
|
28
|
+
border: ['--border'],
|
|
29
|
+
success: ['--state-success'],
|
|
30
|
+
warning: ['--state-warning'],
|
|
31
|
+
error: ['--state-error'],
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* The tokens a brand's theme sets, as `{ '--background': '#000', … }`.
|
|
35
|
+
*
|
|
36
|
+
* Only ground, ink, accent and the edges drawn on them. The radius scale, the
|
|
37
|
+
* type ramp, spacing, motion and z are NOT here and must not be: they are the
|
|
38
|
+
* system's grammar rather than a brand's voice, and a brand that redefines them
|
|
39
|
+
* is a fork wearing a stylesheet.
|
|
40
|
+
*/
|
|
41
|
+
function themeToTokens(theme) {
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const [key, tokens] of Object.entries(OWNS)) {
|
|
44
|
+
const value = theme[key];
|
|
45
|
+
if (!value)
|
|
46
|
+
continue;
|
|
47
|
+
for (const token of tokens)
|
|
48
|
+
out[token] = value;
|
|
49
|
+
}
|
|
50
|
+
// --primary carries ink on top of it, so the accent names its own contrast
|
|
51
|
+
// partner rather than leaving whatever the previous theme set.
|
|
52
|
+
if (theme.accent1 && theme.surface1)
|
|
53
|
+
out['--primary-foreground'] = theme.surface1;
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/** Apply a brand's theme to a live document — for an app that resolves its brand
|
|
57
|
+
* at runtime and so cannot import a build-time stylesheet. */
|
|
58
|
+
function applyBrandTheme(theme, el) {
|
|
59
|
+
for (const [name, value] of Object.entries(themeToTokens(theme))) {
|
|
60
|
+
el.style.setProperty(name, value);
|
|
61
|
+
}
|
|
62
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.RATIO_MAX = exports.RATIO_MIN = exports.TYPE_MAX = exports.TYPE_MIN = exports.isColor = exports.css = exports.vars = void 0;
|
|
18
|
+
exports.cssVar = cssVar;
|
|
19
|
+
exports.tokenValue = tokenValue;
|
|
20
|
+
exports.injectDesignCss = injectDesignCss;
|
|
21
|
+
// @hanzo/design — the ONE programmatic control plane for Hanzo's look & feel.
|
|
22
|
+
//
|
|
23
|
+
// The look/feel is authored ONCE as CSS custom properties in tokens/*.css
|
|
24
|
+
// (monochrome, dark-default — "one hue through an opacity ladder"). This module
|
|
25
|
+
// exposes those exact tokens to code, generated from the CSS so the two can
|
|
26
|
+
// never drift. Change a token in the CSS → the stylesheet AND every code
|
|
27
|
+
// consumer (the @hanzogui/shell theme, Tamagui, any TS surface) update together.
|
|
28
|
+
//
|
|
29
|
+
// import '@hanzo/design/styles.css' // the CSS layer (unchanged)
|
|
30
|
+
// import { colors, spacing, radius, cssVar } from '@hanzo/design' // the code layer
|
|
31
|
+
//
|
|
32
|
+
__exportStar(require("./tokens.gen.cjs"), exports);
|
|
33
|
+
__exportStar(require("./brand.cjs"), exports);
|
|
34
|
+
const tokens_gen_js_1 = require("./tokens.gen.cjs");
|
|
35
|
+
/**
|
|
36
|
+
* A `var(--name, <authored literal>)` reference to a token — the ONE way code
|
|
37
|
+
* should reach a token, so it resolves through the live CSS cascade (honoring
|
|
38
|
+
* the viewer's light/dark theme and any brand fork) rather than baking a value.
|
|
39
|
+
*
|
|
40
|
+
* background: cssVar('--background') // → "var(--background, #000000)"
|
|
41
|
+
* color: cssVar('foreground', '#fff')// → "var(--foreground, #fff)"
|
|
42
|
+
*
|
|
43
|
+
* The name is checked AGAINST THE STYLESHEET at compile time. That check used to
|
|
44
|
+
* be opted out of with `| (string & {})`, which is how `cssVar('surface-1')`
|
|
45
|
+
* shipped: the token did not exist, `var(--surface-1)` resolved to nothing, and
|
|
46
|
+
* a menu painted transparent with no error anywhere. An undefined custom
|
|
47
|
+
* property fails SILENTLY, so the type is the only place it can be caught.
|
|
48
|
+
*
|
|
49
|
+
* When no explicit fallback is given the token's own authored literal is used,
|
|
50
|
+
* so the reference still paints on a host that has not loaded the CSS layer.
|
|
51
|
+
*/
|
|
52
|
+
function cssVar(name, fallback) {
|
|
53
|
+
const n = (name.startsWith('--') ? name : `--${name}`);
|
|
54
|
+
const lit = fallback ?? tokens_gen_js_1.cssVars[n];
|
|
55
|
+
return lit ? `var(${n}, ${lit})` : `var(${n})`;
|
|
56
|
+
}
|
|
57
|
+
/** The raw authored value of a token (the literal from the CSS), or `undefined`. */
|
|
58
|
+
function tokenValue(name) {
|
|
59
|
+
return tokens_gen_js_1.cssVars[name];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Inject the design-system stylesheet from code (idempotent) for surfaces that
|
|
63
|
+
* cannot use a bundler CSS import (e.g. a runtime-mounted island). Prefer the
|
|
64
|
+
* static `import '@hanzo/design/styles.css'` where a bundler is available.
|
|
65
|
+
* No-op outside the browser.
|
|
66
|
+
*
|
|
67
|
+
* `href` is REQUIRED: this used to default to esm.sh, which silently made a
|
|
68
|
+
* third-party CDN the origin of the entire token layer for anyone who called it
|
|
69
|
+
* bare. Pass a URL you serve.
|
|
70
|
+
*/
|
|
71
|
+
function injectDesignCss(href) {
|
|
72
|
+
if (typeof document === 'undefined')
|
|
73
|
+
return;
|
|
74
|
+
if (document.querySelector('link[data-hanzo-design]'))
|
|
75
|
+
return;
|
|
76
|
+
const l = document.createElement('link');
|
|
77
|
+
l.rel = 'stylesheet';
|
|
78
|
+
l.href = href;
|
|
79
|
+
l.setAttribute('data-hanzo-design', '');
|
|
80
|
+
document.head.appendChild(l);
|
|
81
|
+
}
|
|
82
|
+
// A person's own reading of the system — type size, density, accent — as CSS
|
|
83
|
+
// custom properties. Pure: it maps a preference to variables and returns them,
|
|
84
|
+
// so an app, an embedded preview and a server render all apply it the same way.
|
|
85
|
+
var preference_js_1 = require("./preference.cjs");
|
|
86
|
+
Object.defineProperty(exports, "vars", { enumerable: true, get: function () { return preference_js_1.vars; } });
|
|
87
|
+
Object.defineProperty(exports, "css", { enumerable: true, get: function () { return preference_js_1.css; } });
|
|
88
|
+
Object.defineProperty(exports, "isColor", { enumerable: true, get: function () { return preference_js_1.isColor; } });
|
|
89
|
+
Object.defineProperty(exports, "TYPE_MIN", { enumerable: true, get: function () { return preference_js_1.TYPE_MIN; } });
|
|
90
|
+
Object.defineProperty(exports, "TYPE_MAX", { enumerable: true, get: function () { return preference_js_1.TYPE_MAX; } });
|
|
91
|
+
Object.defineProperty(exports, "RATIO_MIN", { enumerable: true, get: function () { return preference_js_1.RATIO_MIN; } });
|
|
92
|
+
Object.defineProperty(exports, "RATIO_MAX", { enumerable: true, get: function () { return preference_js_1.RATIO_MAX; } });
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A person's own reading of the system: type size, density, accent.
|
|
4
|
+
*
|
|
5
|
+
* Three knobs, and each is ONE multiplier on a whole axis — never a restated
|
|
6
|
+
* ramp. The ramps live in `tokens/*.css`, authored once, and each rung carries
|
|
7
|
+
* its own `calc(<base> * var(--type-scale, 1))`. So a preference sets three
|
|
8
|
+
* numbers and every rung follows, including rungs added later and rungs this
|
|
9
|
+
* file has never heard of.
|
|
10
|
+
*
|
|
11
|
+
* That is not a style choice; it is the fix for a real bug. The first version of
|
|
12
|
+
* this module kept its own copy of the type ramp so it could recompute each
|
|
13
|
+
* rung, and the copy was WRONG — it had `lg: 1rem` and `xl: 1.125rem` (16px and
|
|
14
|
+
* 18px) while `tokens/typography.css` says `0.9375rem` and `1.0625rem` (15px and
|
|
15
|
+
* 17px). Setting a preference of 1 — "leave it alone" — would have silently
|
|
16
|
+
* resized two rungs of the published design. A second copy of a value is a
|
|
17
|
+
* second source of truth, and it drifted before anyone used it.
|
|
18
|
+
*
|
|
19
|
+
* Because the knobs are plain multipliers, any OTHER ramp can opt in the same
|
|
20
|
+
* way. @hanzo/gui compiles its own `--f-size-*` scale for the 1600-odd
|
|
21
|
+
* `fontSize="$n"` call sites in the apps; an app that redeclares those as
|
|
22
|
+
* `calc(<its px> * var(--type-scale, 1))` gets the same control with no change
|
|
23
|
+
* at scale 1.
|
|
24
|
+
*
|
|
25
|
+
* It is a pure function on purpose: it maps a preference to custom properties
|
|
26
|
+
* and returns them, touching no document. That is what lets an app, an embedded
|
|
27
|
+
* preview and a server render apply it identically.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.MODULAR_MAX = exports.MODULAR_MIN = exports.RATIO_MAX = exports.RATIO_MIN = exports.TYPE_MAX = exports.TYPE_MIN = void 0;
|
|
31
|
+
exports.isColor = isColor;
|
|
32
|
+
exports.vars = vars;
|
|
33
|
+
exports.css = css;
|
|
34
|
+
/**
|
|
35
|
+
* The type multiplier is CLAMPED, and the bounds are not arbitrary.
|
|
36
|
+
*
|
|
37
|
+
* Below 0.85 the smallest rung (--text-xs, 11px) drops under 9.4px, which stops
|
|
38
|
+
* being small and starts being unreadable — and a preference that lets someone
|
|
39
|
+
* render their own tools illegible is a trap, not a choice. Above 1.4 the
|
|
40
|
+
* chrome stops fitting its own containers: this app's builder header already
|
|
41
|
+
* overlaps its actions below 1440px at scale 1.
|
|
42
|
+
*/
|
|
43
|
+
exports.TYPE_MIN = 0.85;
|
|
44
|
+
exports.TYPE_MAX = 1.4;
|
|
45
|
+
/**
|
|
46
|
+
* The ratio's bounds are looser than type's, because the ramp defends its own
|
|
47
|
+
* floor.
|
|
48
|
+
*
|
|
49
|
+
* `tokens/typography.css` floors --text-xs/sm with `max()`, so the failure mode
|
|
50
|
+
* that forces type's tight clamp — a knob quietly rendering 9px labels — cannot
|
|
51
|
+
* happen on this axis however it combines with type. What is left to bound is
|
|
52
|
+
* only whether the ramp still READS as a ramp: at 0.75 the app register is
|
|
53
|
+
* within a hair of uniform, and past 1.5 a page's h2 has left its own body text
|
|
54
|
+
* behind entirely.
|
|
55
|
+
*/
|
|
56
|
+
exports.RATIO_MIN = 0.75;
|
|
57
|
+
exports.RATIO_MAX = 1.5;
|
|
58
|
+
/**
|
|
59
|
+
* A MODULAR scale — the classical one, where each display rung is the one below
|
|
60
|
+
* it times a fixed ratio. Golden is 1.618; the musical intervals designers name
|
|
61
|
+
* are 1.2 (minor third), 1.25 (major third), 1.333 (perfect fourth) and 1.5
|
|
62
|
+
* (perfect fifth).
|
|
63
|
+
*
|
|
64
|
+
* This is a different RULE from `ratio`, not another dial on it. `ratio` tunes
|
|
65
|
+
* the contrast of the ramp `tokens/typography.css` authored; this REPLACES that
|
|
66
|
+
* ramp's display half with a geometric one. Naming a golden-ratio preset as a
|
|
67
|
+
* contrast value would have been the dishonest version of this feature.
|
|
68
|
+
*
|
|
69
|
+
* Bounded below 1.05 because a ratio at 1 is not a scale — every display rung
|
|
70
|
+
* collapses onto the one before it — and above 2 because doubling every step
|
|
71
|
+
* puts the fourth rung past a phone's whole width.
|
|
72
|
+
*
|
|
73
|
+
* Golden is exactly 1.618 here and is NOT clamped down to something tamer,
|
|
74
|
+
* because a scale that quietly gives you not-golden when you asked for golden is
|
|
75
|
+
* worse than one that refuses. What makes that safe is the ceiling below: this
|
|
76
|
+
* ramp has EIGHT display rungs and a classical modular scale is used with about
|
|
77
|
+
* four, so at 1.618 the eighth would be 799px. Measured, --text-8xl and
|
|
78
|
+
* --text-9xl are referenced in 15 files across the fleet, so that is a broken
|
|
79
|
+
* page and not a hypothetical.
|
|
80
|
+
*/
|
|
81
|
+
exports.MODULAR_MIN = 1.05;
|
|
82
|
+
exports.MODULAR_MAX = 2;
|
|
83
|
+
/**
|
|
84
|
+
* The rungs a modular scale REGENERATES, in order, and the one it starts from.
|
|
85
|
+
*
|
|
86
|
+
* It deliberately stops at the display register. A geometric scale through the
|
|
87
|
+
* interface rungs is unusable at any real ratio: at 1.25 from a 14px base the
|
|
88
|
+
* next rungs are 17.5 and 21.9, so the 13px nav label and the 15px lead — the
|
|
89
|
+
* near-linear steps a dense interface is built on — do not exist. `xl` is the
|
|
90
|
+
* anchor because it is the last interface rung, so the display half continues
|
|
91
|
+
* from where the interface ends rather than restarting under it.
|
|
92
|
+
*/
|
|
93
|
+
const DISPLAY_RUNGS = ["2xl", "3xl", "4xl", "5xl", "6xl", "7xl", "8xl", "9xl"];
|
|
94
|
+
const MODULAR_ANCHOR_REM = 1.0625; // --text-xl, 17px
|
|
95
|
+
/**
|
|
96
|
+
* Density moves SPACING only, and its range is much tighter than type's.
|
|
97
|
+
*
|
|
98
|
+
* Spacing compounds: a page nests padding inside gap inside margin, so a 0.75
|
|
99
|
+
* multiplier is already three-quarters of every one of those in sequence. Below
|
|
100
|
+
* that, touch targets fall under the 44px floor `base.css` sets for coarse
|
|
101
|
+
* pointers, and the control that promised comfort takes it away.
|
|
102
|
+
*/
|
|
103
|
+
const DENSITY = {
|
|
104
|
+
compact: 0.85,
|
|
105
|
+
default: 1,
|
|
106
|
+
comfortable: 1.15,
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* A face is chosen from the ones `tokens/fonts.css` already declares, and it is
|
|
110
|
+
* set by REFERENCE — `var(--font-serif)`, never a family list restated here.
|
|
111
|
+
*
|
|
112
|
+
* That is what keeps a preference from pinning a face: when the token file
|
|
113
|
+
* changes what "mono" means, or a brand overrides it, a person who chose mono
|
|
114
|
+
* follows. Writing `Georgia, serif` here would freeze this file's idea of serif
|
|
115
|
+
* into every document that ever stored the preference.
|
|
116
|
+
*
|
|
117
|
+
* `default` is deliberately absent from the map rather than mapped to
|
|
118
|
+
* `var(--font-sans)`: the axis writes `--font-sans`, so resolving it to itself
|
|
119
|
+
* is a cycle, and "no opinion" is already how every other axis says default.
|
|
120
|
+
*/
|
|
121
|
+
const FACE = {
|
|
122
|
+
system: "ui-sans-serif, system-ui, -apple-system, sans-serif",
|
|
123
|
+
serif: "var(--font-serif)",
|
|
124
|
+
mono: "var(--font-mono)",
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* The measure moves the CONTAINERS, not the columns.
|
|
128
|
+
*
|
|
129
|
+
* `--grid-columns` is 12 because layouts are authored against 12; changing it
|
|
130
|
+
* re-flows every span a page declares and is a different page, not a wider one.
|
|
131
|
+
* What a reader actually means by "wider" is how far the text runs before it
|
|
132
|
+
* wraps, which is `--container-*` — so that is the knob, and the grid inside it
|
|
133
|
+
* is untouched.
|
|
134
|
+
*/
|
|
135
|
+
const MEASURE = {
|
|
136
|
+
narrow: { max: "64rem", prose: "40rem", wide: "58rem" },
|
|
137
|
+
wide: { max: "96rem", prose: "56rem", wide: "86rem" },
|
|
138
|
+
};
|
|
139
|
+
const clamp = (n, lo, hi) => Math.min(hi, Math.max(lo, n));
|
|
140
|
+
/** Trim to 4dp so a multiplier cannot emit a 17-digit float into a stylesheet. */
|
|
141
|
+
const round = (n) => String(Math.round(n * 10000) / 10000);
|
|
142
|
+
/**
|
|
143
|
+
* Is this a colour, or is it something being smuggled into a style attribute?
|
|
144
|
+
*
|
|
145
|
+
* A preference is user input and its destination is CSS. `#fff`, `rgb(...)`,
|
|
146
|
+
* `oklch(...)` and the bare keywords are colours; anything carrying a `;`, a
|
|
147
|
+
* `}`, or a `url(` is trying to be a second declaration, and the answer is to
|
|
148
|
+
* drop the axis rather than to sanitise a string into something plausible.
|
|
149
|
+
*/
|
|
150
|
+
function isColor(v) {
|
|
151
|
+
const s = v.trim();
|
|
152
|
+
if (!s || s.length > 64)
|
|
153
|
+
return false;
|
|
154
|
+
if (/[;{}()]/.test(s) && !/^(rgb|rgba|hsl|hsla|oklch|oklab|lab|lch|color)\([^;{}]*\)$/i.test(s))
|
|
155
|
+
return false;
|
|
156
|
+
return (/^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(s) ||
|
|
157
|
+
/^(rgb|rgba|hsl|hsla|oklch|oklab|lab|lch|color)\([^;{}]*\)$/i.test(s) ||
|
|
158
|
+
/^[a-z]{3,20}$/i.test(s));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The custom properties a preference produces.
|
|
162
|
+
*
|
|
163
|
+
* Only the axes actually set appear, so an app can spread the result over
|
|
164
|
+
* whatever it already has without a default silently overriding a brand.
|
|
165
|
+
*/
|
|
166
|
+
function vars(p) {
|
|
167
|
+
const out = {};
|
|
168
|
+
if (typeof p.type === "number" && Number.isFinite(p.type)) {
|
|
169
|
+
out["--type-scale"] = round(clamp(p.type, exports.TYPE_MIN, exports.TYPE_MAX));
|
|
170
|
+
}
|
|
171
|
+
if (typeof p.ratio === "number" && Number.isFinite(p.ratio)) {
|
|
172
|
+
out["--type-ratio"] = round(clamp(p.ratio, exports.RATIO_MIN, exports.RATIO_MAX));
|
|
173
|
+
}
|
|
174
|
+
if (typeof p.modular === "number" && Number.isFinite(p.modular)) {
|
|
175
|
+
// Each display rung is the anchor times the ratio to its step, emitted as an
|
|
176
|
+
// explicit property. An INLINE custom property on :root outranks the
|
|
177
|
+
// stylesheet, so these simply replace the authored rungs — nothing has to be
|
|
178
|
+
// unset first, and the interface rungs the sheet declares are untouched
|
|
179
|
+
// because none is named here. It multiplies out with `--type-scale` for free,
|
|
180
|
+
// since every rung is still read through that ramp's own calc.
|
|
181
|
+
const r = clamp(p.modular, exports.MODULAR_MIN, exports.MODULAR_MAX);
|
|
182
|
+
DISPLAY_RUNGS.forEach((rung, i) => {
|
|
183
|
+
const rem = MODULAR_ANCHOR_REM * Math.pow(r, i + 1);
|
|
184
|
+
// THE SAME clamp the authored ramp carries, read from the same two names.
|
|
185
|
+
// A regenerated rung and an authored one must be bounded identically or
|
|
186
|
+
// the bound is a property of which code path produced the value, which is
|
|
187
|
+
// exactly the kind of "it depends" a design system exists to delete. The
|
|
188
|
+
// bounds are declared once, in tokens/typography.css, and referenced here
|
|
189
|
+
// — never restated, so moving one moves both.
|
|
190
|
+
out[`--text-${rung}`] =
|
|
191
|
+
`clamp(var(--text-floor), calc(${round(rem)}rem * var(--type-scale, 1)), var(--text-ceiling))`;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
if (p.density && p.density in DENSITY) {
|
|
195
|
+
out["--density"] = round(DENSITY[p.density]);
|
|
196
|
+
}
|
|
197
|
+
// Indexed, not `in`-checked: the maps omit `default`, so a lookup answers
|
|
198
|
+
// undefined for it and for anything stored that is not a face at all. One
|
|
199
|
+
// read, no cast, and an unknown value is refused by the same line that
|
|
200
|
+
// resolves a known one.
|
|
201
|
+
const face = p.font ? FACE[p.font] : undefined;
|
|
202
|
+
if (face)
|
|
203
|
+
out["--font-sans"] = face;
|
|
204
|
+
const measure = p.width ? MEASURE[p.width] : undefined;
|
|
205
|
+
if (measure) {
|
|
206
|
+
out["--container-max"] = measure.max;
|
|
207
|
+
out["--container-prose"] = measure.prose;
|
|
208
|
+
out["--container-wide"] = measure.wide;
|
|
209
|
+
}
|
|
210
|
+
if (p.accent && isColor(p.accent)) {
|
|
211
|
+
// Both names, because the ramp uses --primary for action surfaces and
|
|
212
|
+
// --accent for selection. One hue, stated once, landing on both.
|
|
213
|
+
out["--primary"] = p.accent.trim();
|
|
214
|
+
out["--accent"] = p.accent.trim();
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
/** `vars()` as a declaration block, for a <style> tag or an SSR inline. */
|
|
219
|
+
function css(p, selector = "html:root") {
|
|
220
|
+
const v = vars(p);
|
|
221
|
+
const keys = Object.keys(v);
|
|
222
|
+
if (!keys.length)
|
|
223
|
+
return "";
|
|
224
|
+
return `${selector}{${keys.map((k) => `${k}:${v[k]}`).join(";")}}`;
|
|
225
|
+
}
|
|
@@ -0,0 +1,597 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// AUTO-GENERATED by scripts/gen-tokens.mjs from tokens/*.css — DO NOT EDIT.
|
|
3
|
+
// Edit the token in tokens/<group>.css and re-run `npm run gen`.
|
|
4
|
+
/* eslint-disable */
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cssVars = exports.base = exports.fonts = exports.zIndex = exports.motion = exports.elevation = exports.radius = exports.grid = exports.spacing = exports.typography = exports.colors = void 0;
|
|
7
|
+
/** colors tokens (from tokens/colors.css). Values are raw CSS. */
|
|
8
|
+
exports.colors = {
|
|
9
|
+
'neutral-50': '#FAFAFA',
|
|
10
|
+
'neutral-100': '#F5F5F5',
|
|
11
|
+
'neutral-200': '#E5E5E5',
|
|
12
|
+
'neutral-300': '#D4D4D4',
|
|
13
|
+
'neutral-400': '#A3A3A3',
|
|
14
|
+
'neutral-500': '#737373',
|
|
15
|
+
'neutral-600': '#525252',
|
|
16
|
+
'neutral-700': '#404040',
|
|
17
|
+
'neutral-800': '#262626',
|
|
18
|
+
'neutral-900': '#171717',
|
|
19
|
+
'neutral-950': '#0A0A0A',
|
|
20
|
+
'pure-black': '#000000',
|
|
21
|
+
'pure-white': '#FFFFFF',
|
|
22
|
+
'hanzo-black': '#0A0A0B',
|
|
23
|
+
'hanzo-white': '#FFFFFF',
|
|
24
|
+
'white-03': 'rgb(255 255 255 / .03)',
|
|
25
|
+
'white-05': 'rgb(255 255 255 / .05)',
|
|
26
|
+
'white-06': 'rgb(255 255 255 / .06)',
|
|
27
|
+
'white-08': 'rgb(255 255 255 / .08)',
|
|
28
|
+
'white-10': 'rgb(255 255 255 / .10)',
|
|
29
|
+
'white-14': 'rgb(255 255 255 / .14)',
|
|
30
|
+
'white-15': 'rgb(255 255 255 / .15)',
|
|
31
|
+
'white-16': 'rgb(255 255 255 / .16)',
|
|
32
|
+
'white-18': 'rgb(255 255 255 / .18)',
|
|
33
|
+
'white-20': 'rgb(255 255 255 / .20)',
|
|
34
|
+
'white-22': 'rgb(255 255 255 / .22)',
|
|
35
|
+
'white-30': 'rgb(255 255 255 / .30)',
|
|
36
|
+
'white-40': 'rgb(255 255 255 / .40)',
|
|
37
|
+
'white-45': 'rgb(255 255 255 / .45)',
|
|
38
|
+
'white-55': 'rgb(255 255 255 / .55)',
|
|
39
|
+
'white-60': 'rgb(255 255 255 / .60)',
|
|
40
|
+
'white-78': 'rgb(255 255 255 / .78)',
|
|
41
|
+
'white-80': 'rgb(255 255 255 / .80)',
|
|
42
|
+
'white-92': 'rgb(255 255 255 / .92)',
|
|
43
|
+
'background': '#0a0a0a',
|
|
44
|
+
'foreground': '#e5e5e5',
|
|
45
|
+
'card': '#0f0f0f',
|
|
46
|
+
'card-foreground': '#e5e5e5',
|
|
47
|
+
'popover': '#0f0f0f',
|
|
48
|
+
'popover-foreground': '#e5e5e5',
|
|
49
|
+
'primary': '#fafafa',
|
|
50
|
+
'primary-hover': '#e5e5e5',
|
|
51
|
+
'primary-foreground': '#0a0a0a',
|
|
52
|
+
'secondary': '#262626',
|
|
53
|
+
'secondary-hover': '#333333',
|
|
54
|
+
'secondary-foreground': '#fafafa',
|
|
55
|
+
'muted': '#171717',
|
|
56
|
+
'muted-foreground': '#a3a3a3',
|
|
57
|
+
'accent': '#262626',
|
|
58
|
+
'accent-foreground': '#fafafa',
|
|
59
|
+
'destructive': 'var(--state-error)',
|
|
60
|
+
'destructive-hover': '#dc2626',
|
|
61
|
+
'destructive-foreground': '#fafafa',
|
|
62
|
+
'border': 'var(--white-10)',
|
|
63
|
+
'border-strong': 'var(--white-16)',
|
|
64
|
+
'border-control': 'var(--white-15)',
|
|
65
|
+
'border-focus': 'var(--white-22)',
|
|
66
|
+
'border-selected': 'var(--white-30)',
|
|
67
|
+
'input': 'var(--border-control)',
|
|
68
|
+
'ring': 'var(--white-40)',
|
|
69
|
+
'ring-halo': 'var(--white-10)',
|
|
70
|
+
'brand': '#e4e4e7',
|
|
71
|
+
'brand-foreground': '#09090b',
|
|
72
|
+
'brand-muted': '#a3a3a3',
|
|
73
|
+
'black': '#000000',
|
|
74
|
+
'white': '#fafafa',
|
|
75
|
+
'selection': 'var(--white-20)',
|
|
76
|
+
'glass': 'var(--white-05)',
|
|
77
|
+
'glass-strong': 'var(--white-08)',
|
|
78
|
+
'surface-page': 'var(--background)',
|
|
79
|
+
'surface-card': 'rgb(38 38 38 / .5)',
|
|
80
|
+
'surface-card-emphasis': 'rgb(38 38 38 / .75)',
|
|
81
|
+
'surface-card-quiet': 'rgb(38 38 38 / .35)',
|
|
82
|
+
'surface-overlay': 'rgb(23 23 23 / .92)',
|
|
83
|
+
'surface-header': 'rgb(0 0 0 / .7)',
|
|
84
|
+
'surface-scrim': 'rgb(0 0 0 / .8)',
|
|
85
|
+
'surface-0': 'var(--background)',
|
|
86
|
+
'surface-1': 'var(--card)',
|
|
87
|
+
'surface-2': 'var(--muted)',
|
|
88
|
+
'surface-3': 'var(--secondary)',
|
|
89
|
+
'text-primary': '#fafafa',
|
|
90
|
+
'text-secondary': 'var(--white-78)',
|
|
91
|
+
'text-tertiary': 'var(--white-55)',
|
|
92
|
+
'text-helper': 'var(--muted-foreground)',
|
|
93
|
+
'text-disabled': 'var(--white-30)',
|
|
94
|
+
'state-error': '#ef4444',
|
|
95
|
+
'state-error-text': '#fca5a5',
|
|
96
|
+
'state-error-bg': 'rgb(239 68 68 / .1)',
|
|
97
|
+
'state-online': '#4ade80',
|
|
98
|
+
'state-success': '#22c55e',
|
|
99
|
+
'chrome-dot-red': 'rgb(239 68 68 / .6)',
|
|
100
|
+
'chrome-dot-yellow': 'rgb(234 179 8 / .6)',
|
|
101
|
+
'chrome-dot-green': 'rgb(34 197 94 / .6)',
|
|
102
|
+
};
|
|
103
|
+
/** typography tokens (from tokens/typography.css). Values are raw CSS. */
|
|
104
|
+
exports.typography = {
|
|
105
|
+
'type-scale': '1',
|
|
106
|
+
'type-ratio': '1',
|
|
107
|
+
'text-floor': '0.625rem',
|
|
108
|
+
'text-ceiling': '30vw',
|
|
109
|
+
'text-xs': '0.6875rem',
|
|
110
|
+
'leading-xs': '1rem',
|
|
111
|
+
'text-sm': '0.8125rem',
|
|
112
|
+
'leading-sm': '1.15rem',
|
|
113
|
+
'text-base': '0.875rem',
|
|
114
|
+
'leading-base': '1.35rem',
|
|
115
|
+
'text-lg': '0.9375rem',
|
|
116
|
+
'leading-lg': '1.4rem',
|
|
117
|
+
'text-xl': '1.0625rem',
|
|
118
|
+
'leading-xl': '1.55rem',
|
|
119
|
+
'text-2xl': '1.3125rem',
|
|
120
|
+
'leading-2xl': '1.7rem',
|
|
121
|
+
'text-3xl': '1.625rem',
|
|
122
|
+
'leading-3xl': '1.95rem',
|
|
123
|
+
'text-4xl': '2rem',
|
|
124
|
+
'leading-4xl': '2.25rem',
|
|
125
|
+
'text-5xl': '2.5rem',
|
|
126
|
+
'leading-5xl': '1.05',
|
|
127
|
+
'text-6xl': '3.25rem',
|
|
128
|
+
'leading-6xl': '1',
|
|
129
|
+
'text-7xl': '4rem',
|
|
130
|
+
'leading-7xl': '1',
|
|
131
|
+
'text-8xl': '5.25rem',
|
|
132
|
+
'leading-8xl': '1',
|
|
133
|
+
'text-9xl': '7rem',
|
|
134
|
+
'leading-9xl': '1',
|
|
135
|
+
'font-size-xs': 'var(--text-xs)',
|
|
136
|
+
'font-size-sm': 'var(--text-sm)',
|
|
137
|
+
'font-size-base': 'var(--text-base)',
|
|
138
|
+
'font-size-lg': 'var(--text-lg)',
|
|
139
|
+
'font-size-xl': 'var(--text-xl)',
|
|
140
|
+
'font-size-2xl': 'var(--text-2xl)',
|
|
141
|
+
'font-size-3xl': 'var(--text-3xl)',
|
|
142
|
+
'font-size-4xl': 'var(--text-4xl)',
|
|
143
|
+
'font-size-5xl': 'var(--text-5xl)',
|
|
144
|
+
'font-size-6xl': 'var(--text-6xl)',
|
|
145
|
+
'font-size-7xl': 'var(--text-7xl)',
|
|
146
|
+
'font-size-8xl': 'var(--text-8xl)',
|
|
147
|
+
'font-size-9xl': 'var(--text-9xl)',
|
|
148
|
+
'text-control': 'var(--text-sm)',
|
|
149
|
+
'weight-normal': '400',
|
|
150
|
+
'weight-medium': '500',
|
|
151
|
+
'weight-semibold': '600',
|
|
152
|
+
'weight-bold': '700',
|
|
153
|
+
'tracking-tight': '-0.025em',
|
|
154
|
+
'tracking-normal': '0em',
|
|
155
|
+
'tracking-wide': '0.025em',
|
|
156
|
+
'tracking-widest': '0.1em',
|
|
157
|
+
'leading-none': '1',
|
|
158
|
+
'leading-tight': '1.25',
|
|
159
|
+
'leading-snug': '1.375',
|
|
160
|
+
'leading-normal': '1.5',
|
|
161
|
+
'leading-relaxed': '1.625',
|
|
162
|
+
'leading-golden': '1.618',
|
|
163
|
+
'type-hero': '600 var(--text-5xl)/1.05 var(--font-display)',
|
|
164
|
+
'type-h2': '700 var(--text-4xl)/var(--leading-4xl) var(--font-display)',
|
|
165
|
+
'type-h3': '600 var(--text-xl)/var(--leading-xl) var(--font-display)',
|
|
166
|
+
'type-lead': '400 var(--text-lg)/var(--leading-relaxed) var(--font-sans)',
|
|
167
|
+
'type-body': '400 var(--text-sm)/var(--leading-sm) var(--font-sans)',
|
|
168
|
+
'type-caption': '400 var(--text-xs)/var(--leading-xs) var(--font-sans)',
|
|
169
|
+
'type-code': '400 var(--text-sm)/var(--leading-relaxed) var(--font-mono)',
|
|
170
|
+
'type-eyebrow': '600 0.625rem/1 var(--font-sans)',
|
|
171
|
+
};
|
|
172
|
+
/** spacing tokens (from tokens/spacing.css). Values are raw CSS. */
|
|
173
|
+
exports.spacing = {
|
|
174
|
+
'density': '1',
|
|
175
|
+
'space-0': '0',
|
|
176
|
+
'space-1': '0.25rem',
|
|
177
|
+
'space-2': '0.5rem',
|
|
178
|
+
'space-3': '0.75rem',
|
|
179
|
+
'space-4': '1rem',
|
|
180
|
+
'space-5': '1.25rem',
|
|
181
|
+
'space-6': '1.5rem',
|
|
182
|
+
'space-8': '2rem',
|
|
183
|
+
'space-10': '2.5rem',
|
|
184
|
+
'space-12': '3rem',
|
|
185
|
+
'space-14': '3.5rem',
|
|
186
|
+
'space-16': '4rem',
|
|
187
|
+
'space-20': '5rem',
|
|
188
|
+
'space-24': '6rem',
|
|
189
|
+
'space-32': '8rem',
|
|
190
|
+
'golden-1': '0.25rem',
|
|
191
|
+
'golden-2': '0.405rem',
|
|
192
|
+
'golden-3': '0.654rem',
|
|
193
|
+
'golden-4': '1.059rem',
|
|
194
|
+
'golden-5': '1.713rem',
|
|
195
|
+
'golden-6': '2.772rem',
|
|
196
|
+
'golden-7': '4.487rem',
|
|
197
|
+
'golden-8': '7.26rem',
|
|
198
|
+
'golden-9': '11.749rem',
|
|
199
|
+
'golden-split': '38.2% 61.8%',
|
|
200
|
+
'container-max': '80rem',
|
|
201
|
+
'container-prose': '48rem',
|
|
202
|
+
'container-wide': '72rem',
|
|
203
|
+
'gutter': 'max(1rem,var(--safe-left),var(--safe-right))',
|
|
204
|
+
'gutter-sm': '1.5rem',
|
|
205
|
+
'gutter-lg': '2rem',
|
|
206
|
+
'section-y': '2.5rem',
|
|
207
|
+
'section-y-lg': '3.5rem',
|
|
208
|
+
'hero-y': '3rem',
|
|
209
|
+
'hero-y-lg': '4.5rem',
|
|
210
|
+
'header-height': '3.5rem',
|
|
211
|
+
'tap-target': '44px',
|
|
212
|
+
'control-height-sm': '32px',
|
|
213
|
+
'control-height': '36px',
|
|
214
|
+
'control-height-lg': '40px',
|
|
215
|
+
'control-height-xl': '52px',
|
|
216
|
+
'safe-top': 'env(safe-area-inset-top,0px)',
|
|
217
|
+
'safe-right': 'env(safe-area-inset-right,0px)',
|
|
218
|
+
'safe-bottom': 'env(safe-area-inset-bottom,0px)',
|
|
219
|
+
'safe-left': 'env(safe-area-inset-left,0px)',
|
|
220
|
+
};
|
|
221
|
+
/** grid tokens (from tokens/grid.css). Values are raw CSS. */
|
|
222
|
+
exports.grid = {
|
|
223
|
+
'grid-columns': '12',
|
|
224
|
+
'grid-gap': 'var(--space-6)',
|
|
225
|
+
'grid-gap-tight': 'var(--space-4)',
|
|
226
|
+
'grid-gap-loose': 'var(--space-8)',
|
|
227
|
+
'breakpoint-sm': '40rem',
|
|
228
|
+
'breakpoint-md': '48rem',
|
|
229
|
+
'breakpoint-lg': '64rem',
|
|
230
|
+
'breakpoint-xl': '80rem',
|
|
231
|
+
'breakpoint-2xl': '96rem',
|
|
232
|
+
'grid-card-min': '18rem',
|
|
233
|
+
'grid-card-min-wide': '24rem',
|
|
234
|
+
};
|
|
235
|
+
/** radius tokens (from tokens/radius.css). Values are raw CSS. */
|
|
236
|
+
exports.radius = {
|
|
237
|
+
'radius': '0.5rem',
|
|
238
|
+
'radius-sm': '0.375rem',
|
|
239
|
+
'radius-md': '0.5rem',
|
|
240
|
+
'radius-lg': '0.75rem',
|
|
241
|
+
'radius-xl': '1rem',
|
|
242
|
+
'radius-2xl': '1.5rem',
|
|
243
|
+
'radius-composer': '28px',
|
|
244
|
+
'radius-full': '9999px',
|
|
245
|
+
};
|
|
246
|
+
/** elevation tokens (from tokens/elevation.css). Values are raw CSS. */
|
|
247
|
+
exports.elevation = {
|
|
248
|
+
'shadow-none': 'none',
|
|
249
|
+
'shadow-floating': '0 24px 60px -16px rgb(0 0 0 / .75)',
|
|
250
|
+
'shadow-inset-hairline': 'inset 0 0 0 1px var(--white-10)',
|
|
251
|
+
'edge-highlight': 'inset 0 1px 0 0 rgb(255 255 255 / .10)',
|
|
252
|
+
'bloom': '0 0 24px -2px rgb(255 255 255 / .28)',
|
|
253
|
+
'ring-focus': '0 0 0 3px var(--ring-halo)',
|
|
254
|
+
'shadow-sm': '0 1px 2px 0 rgb(0 0 0 / .40)',
|
|
255
|
+
'shadow': '0 1px 3px 0 rgb(0 0 0 / .45), 0 1px 2px -1px rgb(0 0 0 / .45)',
|
|
256
|
+
'shadow-md': '0 4px 6px -1px rgb(0 0 0 / .50), 0 2px 4px -2px rgb(0 0 0 / .50)',
|
|
257
|
+
'shadow-lg': '0 10px 15px -3px rgb(0 0 0 / .55), 0 4px 6px -4px rgb(0 0 0 / .55)',
|
|
258
|
+
'shadow-xl': '0 20px 25px -5px rgb(0 0 0 / .60), 0 8px 10px -6px rgb(0 0 0 / .60)',
|
|
259
|
+
'shadow-2xl': 'var(--shadow-floating)',
|
|
260
|
+
'sheet-0': 'var(--surface-page)',
|
|
261
|
+
'sheet-1': 'var(--surface-card)',
|
|
262
|
+
'sheet-2': 'var(--surface-card-emphasis)',
|
|
263
|
+
'shadow-sheet-1': 'var(--edge-highlight),0 1px 2px 0 rgb(0 0 0 / .40)',
|
|
264
|
+
'shadow-sheet-2': 'var(--edge-highlight),0 10px 15px -3px rgb(0 0 0 / .55),0 4px 6px -4px rgb(0 0 0 / .55)',
|
|
265
|
+
'fold': '12px',
|
|
266
|
+
'fold-face': 'linear-gradient(315deg,var(--glass-strong) 0,var(--glass-strong) calc(var(--fold) - 1px),var(--border-strong) calc(var(--fold) - 1px),var(--border-strong) var(--fold),transparent var(--fold))',
|
|
267
|
+
'glow-hero': 'radial-gradient(circle,rgb(255 255 255 / .12) 0%,transparent 68%)',
|
|
268
|
+
'glow-hero-blur': '120px',
|
|
269
|
+
'sheen-card': 'radial-gradient(120% 120% at 80% 0%,rgb(255 255 255 / .08) 0%,transparent 55%)',
|
|
270
|
+
'sheen-edge': 'linear-gradient(90deg,transparent,rgb(255 255 255 / .14) 50%,transparent)',
|
|
271
|
+
'gradient-chrome': 'linear-gradient(to right,#ffffff,var(--white-80),var(--white-60))',
|
|
272
|
+
'gradient-chrome-2': 'linear-gradient(to right,#ffffff,var(--neutral-500))',
|
|
273
|
+
'gradient-protect': 'linear-gradient(to bottom,var(--white-10),transparent)',
|
|
274
|
+
};
|
|
275
|
+
/** motion tokens (from tokens/motion.css). Values are raw CSS. */
|
|
276
|
+
exports.motion = {
|
|
277
|
+
'duration-fast': '150ms',
|
|
278
|
+
'duration-base': '300ms',
|
|
279
|
+
'duration-slow': '400ms',
|
|
280
|
+
'duration-slower': '500ms',
|
|
281
|
+
'duration-glow': '9s',
|
|
282
|
+
'duration-press': '90ms',
|
|
283
|
+
'ease-out': 'cubic-bezier(0,0,0.2,1)',
|
|
284
|
+
'ease-in-out': 'cubic-bezier(0.4,0,0.2,1)',
|
|
285
|
+
'ease-emphasis': 'cubic-bezier(0.16,1,0.3,1)',
|
|
286
|
+
'stagger': '60ms',
|
|
287
|
+
'entry-rise': '16px',
|
|
288
|
+
'entry-rise-lg': '24px',
|
|
289
|
+
};
|
|
290
|
+
/** zIndex tokens (from tokens/z.css). Values are raw CSS. */
|
|
291
|
+
exports.zIndex = {
|
|
292
|
+
'z-base': '0',
|
|
293
|
+
'z-raised': '10',
|
|
294
|
+
'z-sticky': '200',
|
|
295
|
+
'z-header': '300',
|
|
296
|
+
'z-dropdown': '400',
|
|
297
|
+
'z-overlay': '500',
|
|
298
|
+
'z-modal': '600',
|
|
299
|
+
'z-popover': '700',
|
|
300
|
+
'z-toast': '800',
|
|
301
|
+
'z-tooltip': 'var(--z-popover)',
|
|
302
|
+
'z-notification': 'var(--z-toast)',
|
|
303
|
+
};
|
|
304
|
+
/** fonts tokens (from tokens/fonts.css). Values are raw CSS. */
|
|
305
|
+
exports.fonts = {
|
|
306
|
+
'font-sans': '"Geist","Geist Sans",ui-sans-serif,system-ui,sans-serif',
|
|
307
|
+
'font-display': 'var(--font-sans)',
|
|
308
|
+
'font-mono': '"Geist Mono",ui-monospace,SFMono-Regular,monospace',
|
|
309
|
+
'font-serif': 'Georgia,serif',
|
|
310
|
+
'font-feature-settings': '"ss01","ss02","cv01","cv02","cv03"',
|
|
311
|
+
};
|
|
312
|
+
/** base tokens (from tokens/base.css). Values are raw CSS. */
|
|
313
|
+
exports.base = {
|
|
314
|
+
'ring-offset': '-2px',
|
|
315
|
+
};
|
|
316
|
+
/** Every token, keyed by its literal CSS custom-property name ('--background', …). */
|
|
317
|
+
exports.cssVars = {
|
|
318
|
+
'--neutral-50': '#FAFAFA',
|
|
319
|
+
'--neutral-100': '#F5F5F5',
|
|
320
|
+
'--neutral-200': '#E5E5E5',
|
|
321
|
+
'--neutral-300': '#D4D4D4',
|
|
322
|
+
'--neutral-400': '#A3A3A3',
|
|
323
|
+
'--neutral-500': '#737373',
|
|
324
|
+
'--neutral-600': '#525252',
|
|
325
|
+
'--neutral-700': '#404040',
|
|
326
|
+
'--neutral-800': '#262626',
|
|
327
|
+
'--neutral-900': '#171717',
|
|
328
|
+
'--neutral-950': '#0A0A0A',
|
|
329
|
+
'--pure-black': '#000000',
|
|
330
|
+
'--pure-white': '#FFFFFF',
|
|
331
|
+
'--hanzo-black': '#0A0A0B',
|
|
332
|
+
'--hanzo-white': '#FFFFFF',
|
|
333
|
+
'--white-03': 'rgb(255 255 255 / .03)',
|
|
334
|
+
'--white-05': 'rgb(255 255 255 / .05)',
|
|
335
|
+
'--white-06': 'rgb(255 255 255 / .06)',
|
|
336
|
+
'--white-08': 'rgb(255 255 255 / .08)',
|
|
337
|
+
'--white-10': 'rgb(255 255 255 / .10)',
|
|
338
|
+
'--white-14': 'rgb(255 255 255 / .14)',
|
|
339
|
+
'--white-15': 'rgb(255 255 255 / .15)',
|
|
340
|
+
'--white-16': 'rgb(255 255 255 / .16)',
|
|
341
|
+
'--white-18': 'rgb(255 255 255 / .18)',
|
|
342
|
+
'--white-20': 'rgb(255 255 255 / .20)',
|
|
343
|
+
'--white-22': 'rgb(255 255 255 / .22)',
|
|
344
|
+
'--white-30': 'rgb(255 255 255 / .30)',
|
|
345
|
+
'--white-40': 'rgb(255 255 255 / .40)',
|
|
346
|
+
'--white-45': 'rgb(255 255 255 / .45)',
|
|
347
|
+
'--white-55': 'rgb(255 255 255 / .55)',
|
|
348
|
+
'--white-60': 'rgb(255 255 255 / .60)',
|
|
349
|
+
'--white-78': 'rgb(255 255 255 / .78)',
|
|
350
|
+
'--white-80': 'rgb(255 255 255 / .80)',
|
|
351
|
+
'--white-92': 'rgb(255 255 255 / .92)',
|
|
352
|
+
'--background': '#0a0a0a',
|
|
353
|
+
'--foreground': '#e5e5e5',
|
|
354
|
+
'--card': '#0f0f0f',
|
|
355
|
+
'--card-foreground': '#e5e5e5',
|
|
356
|
+
'--popover': '#0f0f0f',
|
|
357
|
+
'--popover-foreground': '#e5e5e5',
|
|
358
|
+
'--primary': '#fafafa',
|
|
359
|
+
'--primary-hover': '#e5e5e5',
|
|
360
|
+
'--primary-foreground': '#0a0a0a',
|
|
361
|
+
'--secondary': '#262626',
|
|
362
|
+
'--secondary-hover': '#333333',
|
|
363
|
+
'--secondary-foreground': '#fafafa',
|
|
364
|
+
'--muted': '#171717',
|
|
365
|
+
'--muted-foreground': '#a3a3a3',
|
|
366
|
+
'--accent': '#262626',
|
|
367
|
+
'--accent-foreground': '#fafafa',
|
|
368
|
+
'--destructive': 'var(--state-error)',
|
|
369
|
+
'--destructive-hover': '#dc2626',
|
|
370
|
+
'--destructive-foreground': '#fafafa',
|
|
371
|
+
'--border': 'var(--white-10)',
|
|
372
|
+
'--border-strong': 'var(--white-16)',
|
|
373
|
+
'--border-control': 'var(--white-15)',
|
|
374
|
+
'--border-focus': 'var(--white-22)',
|
|
375
|
+
'--border-selected': 'var(--white-30)',
|
|
376
|
+
'--input': 'var(--border-control)',
|
|
377
|
+
'--ring': 'var(--white-40)',
|
|
378
|
+
'--ring-halo': 'var(--white-10)',
|
|
379
|
+
'--brand': '#e4e4e7',
|
|
380
|
+
'--brand-foreground': '#09090b',
|
|
381
|
+
'--brand-muted': '#a3a3a3',
|
|
382
|
+
'--black': '#000000',
|
|
383
|
+
'--white': '#fafafa',
|
|
384
|
+
'--selection': 'var(--white-20)',
|
|
385
|
+
'--glass': 'var(--white-05)',
|
|
386
|
+
'--glass-strong': 'var(--white-08)',
|
|
387
|
+
'--surface-page': 'var(--background)',
|
|
388
|
+
'--surface-card': 'rgb(38 38 38 / .5)',
|
|
389
|
+
'--surface-card-emphasis': 'rgb(38 38 38 / .75)',
|
|
390
|
+
'--surface-card-quiet': 'rgb(38 38 38 / .35)',
|
|
391
|
+
'--surface-overlay': 'rgb(23 23 23 / .92)',
|
|
392
|
+
'--surface-header': 'rgb(0 0 0 / .7)',
|
|
393
|
+
'--surface-scrim': 'rgb(0 0 0 / .8)',
|
|
394
|
+
'--surface-0': 'var(--background)',
|
|
395
|
+
'--surface-1': 'var(--card)',
|
|
396
|
+
'--surface-2': 'var(--muted)',
|
|
397
|
+
'--surface-3': 'var(--secondary)',
|
|
398
|
+
'--text-primary': '#fafafa',
|
|
399
|
+
'--text-secondary': 'var(--white-78)',
|
|
400
|
+
'--text-tertiary': 'var(--white-55)',
|
|
401
|
+
'--text-helper': 'var(--muted-foreground)',
|
|
402
|
+
'--text-disabled': 'var(--white-30)',
|
|
403
|
+
'--state-error': '#ef4444',
|
|
404
|
+
'--state-error-text': '#fca5a5',
|
|
405
|
+
'--state-error-bg': 'rgb(239 68 68 / .1)',
|
|
406
|
+
'--state-online': '#4ade80',
|
|
407
|
+
'--state-success': '#22c55e',
|
|
408
|
+
'--chrome-dot-red': 'rgb(239 68 68 / .6)',
|
|
409
|
+
'--chrome-dot-yellow': 'rgb(234 179 8 / .6)',
|
|
410
|
+
'--chrome-dot-green': 'rgb(34 197 94 / .6)',
|
|
411
|
+
'--type-scale': '1',
|
|
412
|
+
'--type-ratio': '1',
|
|
413
|
+
'--text-floor': '0.625rem',
|
|
414
|
+
'--text-ceiling': '30vw',
|
|
415
|
+
'--text-xs': '0.6875rem',
|
|
416
|
+
'--leading-xs': '1rem',
|
|
417
|
+
'--text-sm': '0.8125rem',
|
|
418
|
+
'--leading-sm': '1.15rem',
|
|
419
|
+
'--text-base': '0.875rem',
|
|
420
|
+
'--leading-base': '1.35rem',
|
|
421
|
+
'--text-lg': '0.9375rem',
|
|
422
|
+
'--leading-lg': '1.4rem',
|
|
423
|
+
'--text-xl': '1.0625rem',
|
|
424
|
+
'--leading-xl': '1.55rem',
|
|
425
|
+
'--text-2xl': '1.3125rem',
|
|
426
|
+
'--leading-2xl': '1.7rem',
|
|
427
|
+
'--text-3xl': '1.625rem',
|
|
428
|
+
'--leading-3xl': '1.95rem',
|
|
429
|
+
'--text-4xl': '2rem',
|
|
430
|
+
'--leading-4xl': '2.25rem',
|
|
431
|
+
'--text-5xl': '2.5rem',
|
|
432
|
+
'--leading-5xl': '1.05',
|
|
433
|
+
'--text-6xl': '3.25rem',
|
|
434
|
+
'--leading-6xl': '1',
|
|
435
|
+
'--text-7xl': '4rem',
|
|
436
|
+
'--leading-7xl': '1',
|
|
437
|
+
'--text-8xl': '5.25rem',
|
|
438
|
+
'--leading-8xl': '1',
|
|
439
|
+
'--text-9xl': '7rem',
|
|
440
|
+
'--leading-9xl': '1',
|
|
441
|
+
'--font-size-xs': 'var(--text-xs)',
|
|
442
|
+
'--font-size-sm': 'var(--text-sm)',
|
|
443
|
+
'--font-size-base': 'var(--text-base)',
|
|
444
|
+
'--font-size-lg': 'var(--text-lg)',
|
|
445
|
+
'--font-size-xl': 'var(--text-xl)',
|
|
446
|
+
'--font-size-2xl': 'var(--text-2xl)',
|
|
447
|
+
'--font-size-3xl': 'var(--text-3xl)',
|
|
448
|
+
'--font-size-4xl': 'var(--text-4xl)',
|
|
449
|
+
'--font-size-5xl': 'var(--text-5xl)',
|
|
450
|
+
'--font-size-6xl': 'var(--text-6xl)',
|
|
451
|
+
'--font-size-7xl': 'var(--text-7xl)',
|
|
452
|
+
'--font-size-8xl': 'var(--text-8xl)',
|
|
453
|
+
'--font-size-9xl': 'var(--text-9xl)',
|
|
454
|
+
'--text-control': 'var(--text-sm)',
|
|
455
|
+
'--weight-normal': '400',
|
|
456
|
+
'--weight-medium': '500',
|
|
457
|
+
'--weight-semibold': '600',
|
|
458
|
+
'--weight-bold': '700',
|
|
459
|
+
'--tracking-tight': '-0.025em',
|
|
460
|
+
'--tracking-normal': '0em',
|
|
461
|
+
'--tracking-wide': '0.025em',
|
|
462
|
+
'--tracking-widest': '0.1em',
|
|
463
|
+
'--leading-none': '1',
|
|
464
|
+
'--leading-tight': '1.25',
|
|
465
|
+
'--leading-snug': '1.375',
|
|
466
|
+
'--leading-normal': '1.5',
|
|
467
|
+
'--leading-relaxed': '1.625',
|
|
468
|
+
'--leading-golden': '1.618',
|
|
469
|
+
'--type-hero': '600 var(--text-5xl)/1.05 var(--font-display)',
|
|
470
|
+
'--type-h2': '700 var(--text-4xl)/var(--leading-4xl) var(--font-display)',
|
|
471
|
+
'--type-h3': '600 var(--text-xl)/var(--leading-xl) var(--font-display)',
|
|
472
|
+
'--type-lead': '400 var(--text-lg)/var(--leading-relaxed) var(--font-sans)',
|
|
473
|
+
'--type-body': '400 var(--text-sm)/var(--leading-sm) var(--font-sans)',
|
|
474
|
+
'--type-caption': '400 var(--text-xs)/var(--leading-xs) var(--font-sans)',
|
|
475
|
+
'--type-code': '400 var(--text-sm)/var(--leading-relaxed) var(--font-mono)',
|
|
476
|
+
'--type-eyebrow': '600 0.625rem/1 var(--font-sans)',
|
|
477
|
+
'--density': '1',
|
|
478
|
+
'--space-0': '0',
|
|
479
|
+
'--space-1': '0.25rem',
|
|
480
|
+
'--space-2': '0.5rem',
|
|
481
|
+
'--space-3': '0.75rem',
|
|
482
|
+
'--space-4': '1rem',
|
|
483
|
+
'--space-5': '1.25rem',
|
|
484
|
+
'--space-6': '1.5rem',
|
|
485
|
+
'--space-8': '2rem',
|
|
486
|
+
'--space-10': '2.5rem',
|
|
487
|
+
'--space-12': '3rem',
|
|
488
|
+
'--space-14': '3.5rem',
|
|
489
|
+
'--space-16': '4rem',
|
|
490
|
+
'--space-20': '5rem',
|
|
491
|
+
'--space-24': '6rem',
|
|
492
|
+
'--space-32': '8rem',
|
|
493
|
+
'--golden-1': '0.25rem',
|
|
494
|
+
'--golden-2': '0.405rem',
|
|
495
|
+
'--golden-3': '0.654rem',
|
|
496
|
+
'--golden-4': '1.059rem',
|
|
497
|
+
'--golden-5': '1.713rem',
|
|
498
|
+
'--golden-6': '2.772rem',
|
|
499
|
+
'--golden-7': '4.487rem',
|
|
500
|
+
'--golden-8': '7.26rem',
|
|
501
|
+
'--golden-9': '11.749rem',
|
|
502
|
+
'--golden-split': '38.2% 61.8%',
|
|
503
|
+
'--container-max': '80rem',
|
|
504
|
+
'--container-prose': '48rem',
|
|
505
|
+
'--container-wide': '72rem',
|
|
506
|
+
'--gutter': 'max(1rem,var(--safe-left),var(--safe-right))',
|
|
507
|
+
'--gutter-sm': '1.5rem',
|
|
508
|
+
'--gutter-lg': '2rem',
|
|
509
|
+
'--section-y': '2.5rem',
|
|
510
|
+
'--section-y-lg': '3.5rem',
|
|
511
|
+
'--hero-y': '3rem',
|
|
512
|
+
'--hero-y-lg': '4.5rem',
|
|
513
|
+
'--header-height': '3.5rem',
|
|
514
|
+
'--tap-target': '44px',
|
|
515
|
+
'--control-height-sm': '32px',
|
|
516
|
+
'--control-height': '36px',
|
|
517
|
+
'--control-height-lg': '40px',
|
|
518
|
+
'--control-height-xl': '52px',
|
|
519
|
+
'--safe-top': 'env(safe-area-inset-top,0px)',
|
|
520
|
+
'--safe-right': 'env(safe-area-inset-right,0px)',
|
|
521
|
+
'--safe-bottom': 'env(safe-area-inset-bottom,0px)',
|
|
522
|
+
'--safe-left': 'env(safe-area-inset-left,0px)',
|
|
523
|
+
'--grid-columns': '12',
|
|
524
|
+
'--grid-gap': 'var(--space-6)',
|
|
525
|
+
'--grid-gap-tight': 'var(--space-4)',
|
|
526
|
+
'--grid-gap-loose': 'var(--space-8)',
|
|
527
|
+
'--breakpoint-sm': '40rem',
|
|
528
|
+
'--breakpoint-md': '48rem',
|
|
529
|
+
'--breakpoint-lg': '64rem',
|
|
530
|
+
'--breakpoint-xl': '80rem',
|
|
531
|
+
'--breakpoint-2xl': '96rem',
|
|
532
|
+
'--grid-card-min': '18rem',
|
|
533
|
+
'--grid-card-min-wide': '24rem',
|
|
534
|
+
'--radius': '0.5rem',
|
|
535
|
+
'--radius-sm': '0.375rem',
|
|
536
|
+
'--radius-md': '0.5rem',
|
|
537
|
+
'--radius-lg': '0.75rem',
|
|
538
|
+
'--radius-xl': '1rem',
|
|
539
|
+
'--radius-2xl': '1.5rem',
|
|
540
|
+
'--radius-composer': '28px',
|
|
541
|
+
'--radius-full': '9999px',
|
|
542
|
+
'--shadow-none': 'none',
|
|
543
|
+
'--shadow-floating': '0 24px 60px -16px rgb(0 0 0 / .75)',
|
|
544
|
+
'--shadow-inset-hairline': 'inset 0 0 0 1px var(--white-10)',
|
|
545
|
+
'--edge-highlight': 'inset 0 1px 0 0 rgb(255 255 255 / .10)',
|
|
546
|
+
'--bloom': '0 0 24px -2px rgb(255 255 255 / .28)',
|
|
547
|
+
'--ring-focus': '0 0 0 3px var(--ring-halo)',
|
|
548
|
+
'--shadow-sm': '0 1px 2px 0 rgb(0 0 0 / .40)',
|
|
549
|
+
'--shadow': '0 1px 3px 0 rgb(0 0 0 / .45), 0 1px 2px -1px rgb(0 0 0 / .45)',
|
|
550
|
+
'--shadow-md': '0 4px 6px -1px rgb(0 0 0 / .50), 0 2px 4px -2px rgb(0 0 0 / .50)',
|
|
551
|
+
'--shadow-lg': '0 10px 15px -3px rgb(0 0 0 / .55), 0 4px 6px -4px rgb(0 0 0 / .55)',
|
|
552
|
+
'--shadow-xl': '0 20px 25px -5px rgb(0 0 0 / .60), 0 8px 10px -6px rgb(0 0 0 / .60)',
|
|
553
|
+
'--shadow-2xl': 'var(--shadow-floating)',
|
|
554
|
+
'--sheet-0': 'var(--surface-page)',
|
|
555
|
+
'--sheet-1': 'var(--surface-card)',
|
|
556
|
+
'--sheet-2': 'var(--surface-card-emphasis)',
|
|
557
|
+
'--shadow-sheet-1': 'var(--edge-highlight),0 1px 2px 0 rgb(0 0 0 / .40)',
|
|
558
|
+
'--shadow-sheet-2': 'var(--edge-highlight),0 10px 15px -3px rgb(0 0 0 / .55),0 4px 6px -4px rgb(0 0 0 / .55)',
|
|
559
|
+
'--fold': '12px',
|
|
560
|
+
'--fold-face': 'linear-gradient(315deg,var(--glass-strong) 0,var(--glass-strong) calc(var(--fold) - 1px),var(--border-strong) calc(var(--fold) - 1px),var(--border-strong) var(--fold),transparent var(--fold))',
|
|
561
|
+
'--glow-hero': 'radial-gradient(circle,rgb(255 255 255 / .12) 0%,transparent 68%)',
|
|
562
|
+
'--glow-hero-blur': '120px',
|
|
563
|
+
'--sheen-card': 'radial-gradient(120% 120% at 80% 0%,rgb(255 255 255 / .08) 0%,transparent 55%)',
|
|
564
|
+
'--sheen-edge': 'linear-gradient(90deg,transparent,rgb(255 255 255 / .14) 50%,transparent)',
|
|
565
|
+
'--gradient-chrome': 'linear-gradient(to right,#ffffff,var(--white-80),var(--white-60))',
|
|
566
|
+
'--gradient-chrome-2': 'linear-gradient(to right,#ffffff,var(--neutral-500))',
|
|
567
|
+
'--gradient-protect': 'linear-gradient(to bottom,var(--white-10),transparent)',
|
|
568
|
+
'--duration-fast': '150ms',
|
|
569
|
+
'--duration-base': '300ms',
|
|
570
|
+
'--duration-slow': '400ms',
|
|
571
|
+
'--duration-slower': '500ms',
|
|
572
|
+
'--duration-glow': '9s',
|
|
573
|
+
'--duration-press': '90ms',
|
|
574
|
+
'--ease-out': 'cubic-bezier(0,0,0.2,1)',
|
|
575
|
+
'--ease-in-out': 'cubic-bezier(0.4,0,0.2,1)',
|
|
576
|
+
'--ease-emphasis': 'cubic-bezier(0.16,1,0.3,1)',
|
|
577
|
+
'--stagger': '60ms',
|
|
578
|
+
'--entry-rise': '16px',
|
|
579
|
+
'--entry-rise-lg': '24px',
|
|
580
|
+
'--z-base': '0',
|
|
581
|
+
'--z-raised': '10',
|
|
582
|
+
'--z-sticky': '200',
|
|
583
|
+
'--z-header': '300',
|
|
584
|
+
'--z-dropdown': '400',
|
|
585
|
+
'--z-overlay': '500',
|
|
586
|
+
'--z-modal': '600',
|
|
587
|
+
'--z-popover': '700',
|
|
588
|
+
'--z-toast': '800',
|
|
589
|
+
'--z-tooltip': 'var(--z-popover)',
|
|
590
|
+
'--z-notification': 'var(--z-toast)',
|
|
591
|
+
'--font-sans': '"Geist","Geist Sans",ui-sans-serif,system-ui,sans-serif',
|
|
592
|
+
'--font-display': 'var(--font-sans)',
|
|
593
|
+
'--font-mono': '"Geist Mono",ui-monospace,SFMono-Regular,monospace',
|
|
594
|
+
'--font-serif': 'Georgia,serif',
|
|
595
|
+
'--font-feature-settings': '"ss01","ss02","cv01","cv02","cv03"',
|
|
596
|
+
'--ring-offset': '-2px',
|
|
597
|
+
};
|
package/dist/tokens.gen.d.ts
CHANGED
|
@@ -304,7 +304,9 @@ export declare const fonts: {
|
|
|
304
304
|
readonly 'font-feature-settings': "\"ss01\",\"ss02\",\"cv01\",\"cv02\",\"cv03\"";
|
|
305
305
|
};
|
|
306
306
|
/** base tokens (from tokens/base.css). Values are raw CSS. */
|
|
307
|
-
export declare const base: {
|
|
307
|
+
export declare const base: {
|
|
308
|
+
readonly 'ring-offset': "-2px";
|
|
309
|
+
};
|
|
308
310
|
/** Every token, keyed by its literal CSS custom-property name ('--background', …). */
|
|
309
311
|
export declare const cssVars: {
|
|
310
312
|
readonly '--neutral-50': "#FAFAFA";
|
|
@@ -585,6 +587,7 @@ export declare const cssVars: {
|
|
|
585
587
|
readonly '--font-mono': "\"Geist Mono\",ui-monospace,SFMono-Regular,monospace";
|
|
586
588
|
readonly '--font-serif': "Georgia,serif";
|
|
587
589
|
readonly '--font-feature-settings': "\"ss01\",\"ss02\",\"cv01\",\"cv02\",\"cv03\"";
|
|
590
|
+
readonly '--ring-offset': "-2px";
|
|
588
591
|
};
|
|
589
592
|
export type CssVarName = keyof typeof cssVars;
|
|
590
593
|
//# sourceMappingURL=tokens.gen.d.ts.map
|
package/dist/tokens.gen.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.gen.d.ts","sourceRoot":"","sources":["../src/tokens.gen.ts"],"names":[],"mappings":"AAIA,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8FT,CAAA;AAEV,0EAA0E;AAC1E,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEb,CAAA;AAEV,oEAAoE;AACpE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CV,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI;;;;;;;;;;;;CAYP,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;CAST,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BZ,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;CAaT,CAAA;AAEV,6DAA6D;AAC7D,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYT,CAAA;AAEV,gEAAgE;AAChE,eAAO,MAAM,KAAK;;;;;;CAMR,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"tokens.gen.d.ts","sourceRoot":"","sources":["../src/tokens.gen.ts"],"names":[],"mappings":"AAIA,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8FT,CAAA;AAEV,0EAA0E;AAC1E,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmEb,CAAA;AAEV,oEAAoE;AACpE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+CV,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI;;;;;;;;;;;;CAYP,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;CAST,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BZ,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;CAaT,CAAA;AAEV,6DAA6D;AAC7D,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYT,CAAA;AAEV,gEAAgE;AAChE,eAAO,MAAM,KAAK;;;;;;CAMR,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI;;CAEP,CAAA;AAEV,sFAAsF;AACtF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwRV,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAA"}
|
package/dist/tokens.gen.js
CHANGED
|
@@ -307,7 +307,9 @@ export const fonts = {
|
|
|
307
307
|
'font-feature-settings': '"ss01","ss02","cv01","cv02","cv03"',
|
|
308
308
|
};
|
|
309
309
|
/** base tokens (from tokens/base.css). Values are raw CSS. */
|
|
310
|
-
export const base = {
|
|
310
|
+
export const base = {
|
|
311
|
+
'ring-offset': '-2px',
|
|
312
|
+
};
|
|
311
313
|
/** Every token, keyed by its literal CSS custom-property name ('--background', …). */
|
|
312
314
|
export const cssVars = {
|
|
313
315
|
'--neutral-50': '#FAFAFA',
|
|
@@ -588,4 +590,5 @@ export const cssVars = {
|
|
|
588
590
|
'--font-mono': '"Geist Mono",ui-monospace,SFMono-Regular,monospace',
|
|
589
591
|
'--font-serif': 'Georgia,serif',
|
|
590
592
|
'--font-feature-settings': '"ss01","ss02","cv01","cv02","cv03"',
|
|
593
|
+
'--ring-offset': '-2px',
|
|
591
594
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzo/design",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.17",
|
|
4
4
|
"packageManager": "pnpm@11.17.0",
|
|
5
5
|
"description": "Hanzo Design System \u2014 monochrome, dark-default tokens + components + brand assets, the single source of truth for every Hanzo surface. CSS + typed programmatic tokens.",
|
|
6
6
|
"license": "MIT OR Apache-2.0",
|
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
"sideEffects": [
|
|
14
14
|
"*.css"
|
|
15
15
|
],
|
|
16
|
-
"main": "./dist/index.
|
|
16
|
+
"main": "./dist/index.cjs",
|
|
17
17
|
"module": "./dist/index.js",
|
|
18
18
|
"types": "./dist/index.d.ts",
|
|
19
19
|
"exports": {
|
|
20
20
|
".": {
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"import": "./dist/index.js",
|
|
23
|
+
"require": "./dist/index.cjs",
|
|
23
24
|
"default": "./dist/index.js"
|
|
24
25
|
},
|
|
25
26
|
"./package.json": "./package.json",
|
|
@@ -35,7 +36,7 @@
|
|
|
35
36
|
"scripts": {
|
|
36
37
|
"gen": "node scripts/gen-tokens.mjs",
|
|
37
38
|
"test": "node scripts/check-tokens.mjs && node scripts/check-preference.mjs && node scripts/lint.mjs .",
|
|
38
|
-
"build": "pnpm gen && pnpm test && tsc -p tsconfig.json && node scripts/check-dist.mjs",
|
|
39
|
+
"build": "rm -rf dist dist-cjs && pnpm gen && pnpm test && tsc -p tsconfig.json && tsc -p tsconfig.cjs.json --noCheck && node scripts/cjs.mjs && node scripts/check-dist.mjs",
|
|
39
40
|
"prepublishOnly": "pnpm build",
|
|
40
41
|
"lint": "node scripts/lint.mjs"
|
|
41
42
|
},
|
package/scripts/check-dist.mjs
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* A test that reads source cannot see that. This one loads the artifact.
|
|
13
13
|
*/
|
|
14
14
|
import { readFileSync, existsSync } from 'node:fs'
|
|
15
|
+
import { createRequire } from 'node:module'
|
|
15
16
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
16
17
|
import { dirname, join } from 'node:path'
|
|
17
18
|
|
|
@@ -58,6 +59,25 @@ await check('the barrel IMPORTS — the check that 0.4.10 and 0.4.11 needed', as
|
|
|
58
59
|
if (v['--type-scale'] !== '1.2') throw new Error(`built vars() returned ${JSON.stringify(v)}`)
|
|
59
60
|
})
|
|
60
61
|
|
|
62
|
+
await check('the barrel REQUIRES, with the same names it imports', async () => {
|
|
63
|
+
// `type: module` makes every `.js` here ESM, so a CommonJS consumer cannot read
|
|
64
|
+
// the barrel at all — it parses `export` as a syntax error and reports the line
|
|
65
|
+
// in OUR file. Plain Node hides this now that `require(esm)` works, but jest
|
|
66
|
+
// still loads a dependency as CommonJS, so `require('@hanzo/design')` in a
|
|
67
|
+
// jsdom test died at `dist/index.js:12` through 0.5.16.
|
|
68
|
+
//
|
|
69
|
+
// Same names from both formats, checked against each other rather than a list:
|
|
70
|
+
// a list is a third copy that goes stale the next time an export is added.
|
|
71
|
+
const esm = await import(pathToFileURL(join(root, 'dist/index.js')).href)
|
|
72
|
+
const cjs = createRequire(import.meta.url)(join(root, 'dist/index.cjs'))
|
|
73
|
+
const names = (m) => Object.keys(m).filter((k) => k !== 'default' && k !== '__esModule').sort()
|
|
74
|
+
const missing = names(esm).filter((n) => !(n in cjs))
|
|
75
|
+
if (missing.length) throw new Error(`dist/index.cjs is missing ${missing.join(', ')}`)
|
|
76
|
+
if (typeof cjs.vars !== 'function') throw new Error('vars is not callable from the CommonJS build')
|
|
77
|
+
if (cjs.vars({ type: 1.2, density: 'compact' })['--type-scale'] !== '1.2')
|
|
78
|
+
throw new Error('the CommonJS build computes a different preference than the ESM one')
|
|
79
|
+
})
|
|
80
|
+
|
|
61
81
|
await check('no emitted module uses an extensionless relative specifier', () => {
|
|
62
82
|
// The class of bug, not just the one instance: Node ESM resolves relative
|
|
63
83
|
// specifiers literally, so a missing `.js` is always a runtime failure.
|
package/scripts/cjs.mjs
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fold the CommonJS pass into `dist` as `.cjs`.
|
|
3
|
+
*
|
|
4
|
+
* `tsc` emits one module format per outDir, so the CJS build lands in
|
|
5
|
+
* `dist-cjs` beside the ESM one. Both halves ship from `dist`, distinguished by
|
|
6
|
+
* extension — `.cjs` is CommonJS whatever the package `type` says, which is the
|
|
7
|
+
* only way an ESM-typed package can hand a `require()` consumer real CJS.
|
|
8
|
+
*
|
|
9
|
+
* Specifiers are rewritten on the way in. The sources name siblings with an
|
|
10
|
+
* explicit `./x.js`, which `tsc` copies through verbatim, so an unrewritten
|
|
11
|
+
* `dist/index.cjs` would `require('./tokens.gen.js')` — the ESM copy sitting
|
|
12
|
+
* right next to it. That either throws or loads a SECOND instance of every
|
|
13
|
+
* token, so the extension has to travel with the file.
|
|
14
|
+
*/
|
|
15
|
+
import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'
|
|
16
|
+
import { dirname, join, relative } from 'node:path'
|
|
17
|
+
import { fileURLToPath } from 'node:url'
|
|
18
|
+
|
|
19
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
20
|
+
const dist = join(root, 'dist')
|
|
21
|
+
const cjs = join(root, 'dist-cjs')
|
|
22
|
+
|
|
23
|
+
const files = (dir, out = []) => {
|
|
24
|
+
for (const name of readdirSync(dir)) {
|
|
25
|
+
const p = join(dir, name)
|
|
26
|
+
statSync(p).isDirectory() ? files(p, out) : out.push(p)
|
|
27
|
+
}
|
|
28
|
+
return out
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// `from './x.js'`, `import './x.js'`, `import('./x.js')`, `require('./x.js')`
|
|
32
|
+
const SPECIFIER = /(\bfrom\s*|\bimport\s*\(?\s*|\brequire\s*\(\s*)(['"])(\.[^'"]*)\.js\2/g
|
|
33
|
+
|
|
34
|
+
for (const f of files(cjs)) {
|
|
35
|
+
if (!f.endsWith('.js')) continue
|
|
36
|
+
const src = readFileSync(f, 'utf8')
|
|
37
|
+
const out = src.replace(SPECIFIER, (_, head, q, spec) => `${head}${q}${spec}.cjs${q}`)
|
|
38
|
+
const dest = join(dist, relative(cjs, f)).replace(/\.js$/, '.cjs')
|
|
39
|
+
mkdirSync(dirname(dest), { recursive: true })
|
|
40
|
+
writeFileSync(dest, out)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
rmSync(cjs, { recursive: true, force: true })
|
package/src/tokens.gen.ts
CHANGED
|
@@ -318,7 +318,7 @@ export const fonts = {
|
|
|
318
318
|
|
|
319
319
|
/** base tokens (from tokens/base.css). Values are raw CSS. */
|
|
320
320
|
export const base = {
|
|
321
|
-
|
|
321
|
+
'ring-offset': '-2px',
|
|
322
322
|
} as const
|
|
323
323
|
|
|
324
324
|
/** Every token, keyed by its literal CSS custom-property name ('--background', …). */
|
|
@@ -601,6 +601,7 @@ export const cssVars = {
|
|
|
601
601
|
'--font-mono': '"Geist Mono",ui-monospace,SFMono-Regular,monospace',
|
|
602
602
|
'--font-serif': 'Georgia,serif',
|
|
603
603
|
'--font-feature-settings': '"ss01","ss02","cv01","cv02","cv03"',
|
|
604
|
+
'--ring-offset': '-2px',
|
|
604
605
|
} as const
|
|
605
606
|
|
|
606
607
|
export type CssVarName = keyof typeof cssVars
|
package/styles.css
CHANGED
|
@@ -979,6 +979,22 @@
|
|
|
979
979
|
its buttons at 8-10px and nothing at 6px except 22px chips. */
|
|
980
980
|
border-radius:var(--radius-md);
|
|
981
981
|
padding:0 var(--space-3);
|
|
982
|
+
/* A field's ring is drawn INSIDE its own box. The one focus rule below
|
|
983
|
+
reads this; nothing else about the indicator changes.
|
|
984
|
+
|
|
985
|
+
A field lives in containers a button does not — composers, palettes and
|
|
986
|
+
panels that round their corners with `overflow:hidden`. An outline at a
|
|
987
|
+
POSITIVE offset is painted outside the border box, so any such ancestor
|
|
988
|
+
clips it, and the computed style still says `2px solid` while nothing is
|
|
989
|
+
drawn: a chat composer measured byte-identical screenshots focused and
|
|
990
|
+
unfocused, and a search pill kept only its left and right edges. A
|
|
991
|
+
negative offset cannot be clipped by anything, so a field needs to know
|
|
992
|
+
nothing about what contains it.
|
|
993
|
+
|
|
994
|
+
-2 against a 2px ring lays the outline over the outermost 2px of the box,
|
|
995
|
+
so it REPLACES the 1px edge for as long as focus is there rather than
|
|
996
|
+
drawing a second line a pixel inside the first. */
|
|
997
|
+
--ring-offset:-2px;
|
|
982
998
|
}
|
|
983
999
|
:where(textarea){padding:var(--space-2) var(--space-3);resize:vertical}
|
|
984
1000
|
/* A field has NO focus rule of its own — see the ring at the bottom of this
|
|
@@ -1045,6 +1061,11 @@
|
|
|
1045
1061
|
canvas and clears the 2px perimeter WCAG 2.4.13 asks for; the gate in
|
|
1046
1062
|
check-tokens holds --ring to that and nothing else here may weaken it.
|
|
1047
1063
|
|
|
1064
|
+
WHERE the ring sits is the one thing that varies, and it varies as a VALUE
|
|
1065
|
+
the element carries, never as a second rule: `--ring-offset` defaults to 2
|
|
1066
|
+
and a field sets it to -2 (see the field block above). Two rules is what
|
|
1067
|
+
0.4.9 removed, and a second one here would be the same defect again.
|
|
1068
|
+
|
|
1048
1069
|
There were two rules until 0.4.9, and they collided invisibly. Both computed
|
|
1049
1070
|
to (0,1,0) — :where() zeroes whatever it wraps, leaving one pseudo-class on
|
|
1050
1071
|
each side — so the cascade fell through to SOURCE ORDER inside this layer,
|
|
@@ -1053,7 +1074,7 @@
|
|
|
1053
1074
|
drew BOTH the ring and the edge+halo. Each rule read as correct alone, which
|
|
1054
1075
|
is why it survived review in both files; the defect existed only in their
|
|
1055
1076
|
order. One rule cannot disagree with itself. */
|
|
1056
|
-
:focus-visible{outline:2px solid var(--ring);outline-offset:2px}
|
|
1077
|
+
:focus-visible{outline:2px solid var(--ring);outline-offset:var(--ring-offset,2px)}
|
|
1057
1078
|
/* --white-20 is white-on-white in the light theme, so selection reads through
|
|
1058
1079
|
--selection, which BOTH themes define. */
|
|
1059
1080
|
::selection{background:var(--selection);color:var(--text-primary)}
|
package/tailwind.css
CHANGED
|
@@ -1002,6 +1002,22 @@
|
|
|
1002
1002
|
its buttons at 8-10px and nothing at 6px except 22px chips. */
|
|
1003
1003
|
border-radius:var(--radius-md);
|
|
1004
1004
|
padding:0 var(--space-3);
|
|
1005
|
+
/* A field's ring is drawn INSIDE its own box. The one focus rule below
|
|
1006
|
+
reads this; nothing else about the indicator changes.
|
|
1007
|
+
|
|
1008
|
+
A field lives in containers a button does not — composers, palettes and
|
|
1009
|
+
panels that round their corners with `overflow:hidden`. An outline at a
|
|
1010
|
+
POSITIVE offset is painted outside the border box, so any such ancestor
|
|
1011
|
+
clips it, and the computed style still says `2px solid` while nothing is
|
|
1012
|
+
drawn: a chat composer measured byte-identical screenshots focused and
|
|
1013
|
+
unfocused, and a search pill kept only its left and right edges. A
|
|
1014
|
+
negative offset cannot be clipped by anything, so a field needs to know
|
|
1015
|
+
nothing about what contains it.
|
|
1016
|
+
|
|
1017
|
+
-2 against a 2px ring lays the outline over the outermost 2px of the box,
|
|
1018
|
+
so it REPLACES the 1px edge for as long as focus is there rather than
|
|
1019
|
+
drawing a second line a pixel inside the first. */
|
|
1020
|
+
--ring-offset:-2px;
|
|
1005
1021
|
}
|
|
1006
1022
|
:where(textarea){padding:var(--space-2) var(--space-3);resize:vertical}
|
|
1007
1023
|
/* A field has NO focus rule of its own — see the ring at the bottom of this
|
|
@@ -1068,6 +1084,11 @@
|
|
|
1068
1084
|
canvas and clears the 2px perimeter WCAG 2.4.13 asks for; the gate in
|
|
1069
1085
|
check-tokens holds --ring to that and nothing else here may weaken it.
|
|
1070
1086
|
|
|
1087
|
+
WHERE the ring sits is the one thing that varies, and it varies as a VALUE
|
|
1088
|
+
the element carries, never as a second rule: `--ring-offset` defaults to 2
|
|
1089
|
+
and a field sets it to -2 (see the field block above). Two rules is what
|
|
1090
|
+
0.4.9 removed, and a second one here would be the same defect again.
|
|
1091
|
+
|
|
1071
1092
|
There were two rules until 0.4.9, and they collided invisibly. Both computed
|
|
1072
1093
|
to (0,1,0) — :where() zeroes whatever it wraps, leaving one pseudo-class on
|
|
1073
1094
|
each side — so the cascade fell through to SOURCE ORDER inside this layer,
|
|
@@ -1076,7 +1097,7 @@
|
|
|
1076
1097
|
drew BOTH the ring and the edge+halo. Each rule read as correct alone, which
|
|
1077
1098
|
is why it survived review in both files; the defect existed only in their
|
|
1078
1099
|
order. One rule cannot disagree with itself. */
|
|
1079
|
-
:focus-visible{outline:2px solid var(--ring);outline-offset:2px}
|
|
1100
|
+
:focus-visible{outline:2px solid var(--ring);outline-offset:var(--ring-offset,2px)}
|
|
1080
1101
|
/* --white-20 is white-on-white in the light theme, so selection reads through
|
|
1081
1102
|
--selection, which BOTH themes define. */
|
|
1082
1103
|
::selection{background:var(--selection);color:var(--text-primary)}
|
package/tokens/base.css
CHANGED
|
@@ -97,6 +97,22 @@
|
|
|
97
97
|
its buttons at 8-10px and nothing at 6px except 22px chips. */
|
|
98
98
|
border-radius:var(--radius-md);
|
|
99
99
|
padding:0 var(--space-3);
|
|
100
|
+
/* A field's ring is drawn INSIDE its own box. The one focus rule below
|
|
101
|
+
reads this; nothing else about the indicator changes.
|
|
102
|
+
|
|
103
|
+
A field lives in containers a button does not — composers, palettes and
|
|
104
|
+
panels that round their corners with `overflow:hidden`. An outline at a
|
|
105
|
+
POSITIVE offset is painted outside the border box, so any such ancestor
|
|
106
|
+
clips it, and the computed style still says `2px solid` while nothing is
|
|
107
|
+
drawn: a chat composer measured byte-identical screenshots focused and
|
|
108
|
+
unfocused, and a search pill kept only its left and right edges. A
|
|
109
|
+
negative offset cannot be clipped by anything, so a field needs to know
|
|
110
|
+
nothing about what contains it.
|
|
111
|
+
|
|
112
|
+
-2 against a 2px ring lays the outline over the outermost 2px of the box,
|
|
113
|
+
so it REPLACES the 1px edge for as long as focus is there rather than
|
|
114
|
+
drawing a second line a pixel inside the first. */
|
|
115
|
+
--ring-offset:-2px;
|
|
100
116
|
}
|
|
101
117
|
:where(textarea){padding:var(--space-2) var(--space-3);resize:vertical}
|
|
102
118
|
/* A field has NO focus rule of its own — see the ring at the bottom of this
|
|
@@ -163,6 +179,11 @@
|
|
|
163
179
|
canvas and clears the 2px perimeter WCAG 2.4.13 asks for; the gate in
|
|
164
180
|
check-tokens holds --ring to that and nothing else here may weaken it.
|
|
165
181
|
|
|
182
|
+
WHERE the ring sits is the one thing that varies, and it varies as a VALUE
|
|
183
|
+
the element carries, never as a second rule: `--ring-offset` defaults to 2
|
|
184
|
+
and a field sets it to -2 (see the field block above). Two rules is what
|
|
185
|
+
0.4.9 removed, and a second one here would be the same defect again.
|
|
186
|
+
|
|
166
187
|
There were two rules until 0.4.9, and they collided invisibly. Both computed
|
|
167
188
|
to (0,1,0) — :where() zeroes whatever it wraps, leaving one pseudo-class on
|
|
168
189
|
each side — so the cascade fell through to SOURCE ORDER inside this layer,
|
|
@@ -171,7 +192,7 @@
|
|
|
171
192
|
drew BOTH the ring and the edge+halo. Each rule read as correct alone, which
|
|
172
193
|
is why it survived review in both files; the defect existed only in their
|
|
173
194
|
order. One rule cannot disagree with itself. */
|
|
174
|
-
:focus-visible{outline:2px solid var(--ring);outline-offset:2px}
|
|
195
|
+
:focus-visible{outline:2px solid var(--ring);outline-offset:var(--ring-offset,2px)}
|
|
175
196
|
/* --white-20 is white-on-white in the light theme, so selection reads through
|
|
176
197
|
--selection, which BOTH themes define. */
|
|
177
198
|
::selection{background:var(--selection);color:var(--text-primary)}
|