@hanzo/design 0.1.0 → 0.3.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/LICENSE CHANGED
@@ -1,21 +1,28 @@
1
- MIT License
1
+ BSD 3-Clause License
2
2
 
3
3
  Copyright (c) 2026 Hanzo AI, Inc.
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
11
7
 
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
14
10
 
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md CHANGED
@@ -12,12 +12,40 @@ The single source of truth for how every Hanzo surface looks — tokens, compone
12
12
 
13
13
  ## Use it
14
14
 
15
- One import pulls in the whole token layer (fonts, color, type, spacing, radius, elevation, motion):
15
+ One import pulls in the whole token layer fonts, colour, type, spacing, radius,
16
+ elevation, motion, **z**, base:
16
17
 
17
18
  ```css
18
- @import "@hanzoai/design/styles.css";
19
+ @import "@hanzo/design/styles.css";
19
20
  ```
20
21
 
22
+ Import the **whole** file. Cherry-picking `tokens/*.css` is how surfaces ended up
23
+ without the z ladder or the elevation ramp. The fonts are self-hosted, so this
24
+ makes **no third-party request** — there is no longer a reason to skip a part of it.
25
+
26
+ ### Programmatic tokens (control look & feel from code)
27
+
28
+ The same tokens are exposed to TypeScript — **generated from the CSS**, so the two
29
+ can never drift. Edit a token in `tokens/*.css`, run `npm run build`, and both the
30
+ stylesheet and the code API update together. This is the one place to drive Hanzo's
31
+ look & feel programmatically (the `@hanzogui/shell` theme, Tamagui, any TS surface):
32
+
33
+ ```ts
34
+ import { colors, spacing, radius, zIndex, cssVar } from '@hanzo/design'
35
+
36
+ spacing['space-4'] // "1rem"
37
+ radius['radius-full'] // "9999px"
38
+ zIndex['z-header'] // 300
39
+
40
+ // Prefer cssVar() so a value resolves through the live cascade (honors light/dark):
41
+ element.style.background = cssVar('--background') // "var(--background)"
42
+ element.style.color = cssVar('--foreground', '#fff') // with a fallback
43
+ ```
44
+
45
+ Groups: `colors`, `typography`, `spacing`, `radius`, `elevation`, `motion`, `zIndex`,
46
+ `fonts`, `base` (semantic aliases), plus `cssVars` (every token by its literal
47
+ `--name`). All authored **once** in the token CSS — the single source of truth.
48
+
21
49
  Everything below is expressed as CSS custom properties, so code copies over 1:1 — the semantic names match `hanzo.ai`'s variables exactly.
22
50
 
23
51
  ```jsx
@@ -38,13 +66,42 @@ import { HanzoLogo } from "@hanzoai/design/components/core/HanzoLogo.jsx";
38
66
  | `content/` | The words — brand voice and taglines. |
39
67
  | `docs/` | How to use the system — integrate the tokens, theme, extend. |
40
68
  | `guidelines/` | Specimen cards — color, type, spacing, brand, iconography — the visual reference. |
69
+ | `assets/fonts/` | Geist Sans + Geist Mono, self-hosted (two variable `.woff2`, 141 KB, SIL OFL-1.1). No Google Fonts request. |
41
70
  | `assets/` | The mark, wordmark, favicon, provider + partner logos, brand imagery. |
71
+ | `scripts/check-tokens.mjs` | The gate: every token file is served, every internal `var()` resolves, and the contrast floors hold. Runs on `npm run build`. |
42
72
  | `ui_kits/` | Composed surfaces (e.g. `SiteChrome`) assembled from the components. |
43
73
 
74
+ ## Two kinds of boundary
75
+
76
+ Not interchangeable, and the difference is a conformance requirement rather than
77
+ a matter of taste:
78
+
79
+ | Token | Kind | Contrast |
80
+ |---|---|---|
81
+ | `--border`, `--border-hairline`, `--border-card` | **decorative** — separates content | none required |
82
+ | `--border-strong` | **perceivable** — identifies a *control* (input edge, switch, checkbox) | ≥ 3:1, WCAG 1.4.11 |
83
+ | `--ring` | the focus indicator | ≥ 3:1, WCAG 2.4.11 |
84
+
85
+ Reach for `--border-strong` whenever the boundary **is** the affordance. Both
86
+ conformant tokens resolve to `--neutral-500`, the only rung on this ladder that
87
+ clears 3:1 on every surface in **both** themes — `scripts/check-tokens.mjs`
88
+ measures this on every build and fails if it ever stops being true.
89
+
90
+ Note that the `--white-*` opacity ladder does **not** invert in light theme, so
91
+ `--white-40` is white-on-white there. Anything needing a visible edge in both
92
+ themes must use `--border-strong`.
93
+
44
94
  ## Principles
45
95
 
46
96
  - **Monochrome by construction** — one neutral ladder plus an opacity ladder is the entire palette. Color appears only as genuine semantics (live/error/warning).
47
97
  - **Dark is the default theme** — surfaces mount dark-first; light is the override.
98
+ - **A token that is referenced must resolve** — an undefined custom property paints
99
+ *nothing*, silently. `cssVar()` therefore accepts only real token names (a typo
100
+ is a compile error) and emits the authored literal as a fallback, so a reference
101
+ still paints on a host that has not loaded the CSS.
102
+ - **White-label by fork** — `@luxfi/design` and `@zooai/design` carry the same token
103
+ *names* over their own values. A change here must be measured against all three
104
+ before it ships; one that fixes Hanzo and breaks Zoo is a regression.
48
105
  - **Self-contained components** — inline styles, no CSS-framework coupling, so a component drops into any host (Next, Vite, Tamagui, none) and renders identically.
49
106
  - **Every component ships its own `.prompt.md`** — a one-screen usage guide for humans and AI alike.
50
107
 
@@ -54,4 +111,4 @@ Tokens track `hanzo.ai` (`app/globals.css`, `tailwind.config.ts`, `DESIGN.md`) a
54
111
 
55
112
  ## License
56
113
 
57
- MIT. Brand marks (the Hanzo logo, partner and provider logos) are the property of their respective owners and are provided for identification.
114
+ BSD-3-Clause. Brand marks (the Hanzo logo, partner and provider logos) are the property of their respective owners and are provided for identification.
@@ -0,0 +1,92 @@
1
+ Copyright (c) 2023 Vercel, in collaboration with basement.studio
2
+
3
+ This Font Software is licensed under the SIL Open Font License, Version 1.1.
4
+ This license is copied below, and is also available with a FAQ at:
5
+ http://scripts.sil.org/OFL
6
+
7
+ -----------------------------------------------------------
8
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9
+ -----------------------------------------------------------
10
+
11
+ PREAMBLE
12
+ The goals of the Open Font License (OFL) are to stimulate worldwide
13
+ development of collaborative font projects, to support the font creation
14
+ efforts of academic and linguistic communities, and to provide a free and
15
+ open framework in which fonts may be shared and improved in partnership
16
+ with others.
17
+
18
+ The OFL allows the licensed fonts to be used, studied, modified and
19
+ redistributed freely as long as they are not sold by themselves. The
20
+ fonts, including any derivative works, can be bundled, embedded,
21
+ redistributed and/or sold with any software provided that any reserved
22
+ names are not used by derivative works. The fonts and derivatives,
23
+ however, cannot be released under any other type of license. The
24
+ requirement for fonts to remain under this license does not apply
25
+ to any document created using the fonts or their derivatives.
26
+
27
+ DEFINITIONS
28
+ "Font Software" refers to the set of files released by the Copyright
29
+ Holder(s) under this license and clearly marked as such. This may
30
+ include source files, build scripts and documentation.
31
+
32
+ "Reserved Font Name" refers to any names specified as such after the
33
+ copyright statement(s).
34
+
35
+ "Original Version" refers to the collection of Font Software components as
36
+ distributed by the Copyright Holder(s).
37
+
38
+ "Modified Version" refers to any derivative made by adding to, deleting,
39
+ or substituting -- in part or in whole -- any of the components of the
40
+ Original Version, by changing formats or by porting the Font Software to a
41
+ new environment.
42
+
43
+ "Author" refers to any designer, engineer, programmer, technical
44
+ writer or other person who contributed to the Font Software.
45
+
46
+ PERMISSION AND CONDITIONS
47
+ Permission is hereby granted, free of charge, to any person obtaining
48
+ a copy of the Font Software, to use, study, copy, merge, embed, modify,
49
+ redistribute, and sell modified and unmodified copies of the Font
50
+ Software, subject to the following conditions:
51
+
52
+ 1) Neither the Font Software nor any of its individual components,
53
+ in Original or Modified Versions, may be sold by itself.
54
+
55
+ 2) Original or Modified Versions of the Font Software may be bundled,
56
+ redistributed and/or sold with any software, provided that each copy
57
+ contains the above copyright notice and this license. These can be
58
+ included either as stand-alone text files, human-readable headers or
59
+ in the appropriate machine-readable metadata fields within text or
60
+ binary files as long as those fields can be easily viewed by the user.
61
+
62
+ 3) No Modified Version of the Font Software may use the Reserved Font
63
+ Name(s) unless explicit written permission is granted by the corresponding
64
+ Copyright Holder. This restriction only applies to the primary font name as
65
+ presented to the users.
66
+
67
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68
+ Software shall not be used to promote, endorse or advertise any
69
+ Modified Version, except to acknowledge the contribution(s) of the
70
+ Copyright Holder(s) and the Author(s) or with their explicit written
71
+ permission.
72
+
73
+ 5) The Font Software, modified or unmodified, in part or in whole,
74
+ must be distributed entirely under this license, and must not be
75
+ distributed under any other license. The requirement for fonts to
76
+ remain under this license does not apply to any document created
77
+ using the Font Software.
78
+
79
+ TERMINATION
80
+ This license becomes null and void if any of the above conditions are
81
+ not met.
82
+
83
+ DISCLAIMER
84
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92
+ OTHER DEALINGS IN THE FONT SOFTWARE.
@@ -0,0 +1,36 @@
1
+ export * from './tokens.gen.js';
2
+ import { type CssVarName } from './tokens.gen.js';
3
+ /** A token name with the leading `--` omitted: `'background'` for `'--background'`. */
4
+ export type TokenName = CssVarName extends `--${infer N}` ? N : never;
5
+ /**
6
+ * A `var(--name, <authored literal>)` reference to a token — the ONE way code
7
+ * should reach a token, so it resolves through the live CSS cascade (honoring
8
+ * the viewer's light/dark theme and any brand fork) rather than baking a value.
9
+ *
10
+ * background: cssVar('--background') // → "var(--background, #000000)"
11
+ * color: cssVar('foreground', '#fff')// → "var(--foreground, #fff)"
12
+ *
13
+ * The name is checked AGAINST THE STYLESHEET at compile time. That check used to
14
+ * be opted out of with `| (string & {})`, which is how `cssVar('surface-1')`
15
+ * shipped: the token did not exist, `var(--surface-1)` resolved to nothing, and
16
+ * a menu painted transparent with no error anywhere. An undefined custom
17
+ * property fails SILENTLY, so the type is the only place it can be caught.
18
+ *
19
+ * When no explicit fallback is given the token's own authored literal is used,
20
+ * so the reference still paints on a host that has not loaded the CSS layer.
21
+ */
22
+ export declare function cssVar(name: CssVarName | TokenName, fallback?: string): string;
23
+ /** The raw authored value of a token (the literal from the CSS), or `undefined`. */
24
+ export declare function tokenValue(name: CssVarName): string | undefined;
25
+ /**
26
+ * Inject the design-system stylesheet from code (idempotent) for surfaces that
27
+ * cannot use a bundler CSS import (e.g. a runtime-mounted island). Prefer the
28
+ * static `import '@hanzo/design/styles.css'` where a bundler is available.
29
+ * No-op outside the browser.
30
+ *
31
+ * `href` is REQUIRED: this used to default to esm.sh, which silently made a
32
+ * third-party CDN the origin of the entire token layer for anyone who called it
33
+ * bare. Pass a URL you serve.
34
+ */
35
+ export declare function injectDesignCss(href: string): void;
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,cAAc,iBAAiB,CAAA;AAC/B,OAAO,EAAW,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE1D,uFAAuF;AACvF,MAAM,MAAM,SAAS,GAAG,UAAU,SAAS,KAAK,MAAM,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK,CAAA;AAErE;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAI9E;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAE/D;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAQlD"}
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ // @hanzo/design — the ONE programmatic control plane for Hanzo's look & feel.
2
+ //
3
+ // The look/feel is authored ONCE as CSS custom properties in tokens/*.css
4
+ // (monochrome, dark-default — "one hue through an opacity ladder"). This module
5
+ // exposes those exact tokens to code, generated from the CSS so the two can
6
+ // never drift. Change a token in the CSS → the stylesheet AND every code
7
+ // consumer (the @hanzogui/shell theme, Tamagui, any TS surface) update together.
8
+ //
9
+ // import '@hanzo/design/styles.css' // the CSS layer (unchanged)
10
+ // import { colors, spacing, radius, cssVar } from '@hanzo/design' // the code layer
11
+ //
12
+ export * from './tokens.gen.js';
13
+ import { cssVars } from './tokens.gen.js';
14
+ /**
15
+ * A `var(--name, <authored literal>)` reference to a token — the ONE way code
16
+ * should reach a token, so it resolves through the live CSS cascade (honoring
17
+ * the viewer's light/dark theme and any brand fork) rather than baking a value.
18
+ *
19
+ * background: cssVar('--background') // → "var(--background, #000000)"
20
+ * color: cssVar('foreground', '#fff')// → "var(--foreground, #fff)"
21
+ *
22
+ * The name is checked AGAINST THE STYLESHEET at compile time. That check used to
23
+ * be opted out of with `| (string & {})`, which is how `cssVar('surface-1')`
24
+ * shipped: the token did not exist, `var(--surface-1)` resolved to nothing, and
25
+ * a menu painted transparent with no error anywhere. An undefined custom
26
+ * property fails SILENTLY, so the type is the only place it can be caught.
27
+ *
28
+ * When no explicit fallback is given the token's own authored literal is used,
29
+ * so the reference still paints on a host that has not loaded the CSS layer.
30
+ */
31
+ export function cssVar(name, fallback) {
32
+ const n = (name.startsWith('--') ? name : `--${name}`);
33
+ const lit = fallback ?? cssVars[n];
34
+ return lit ? `var(${n}, ${lit})` : `var(${n})`;
35
+ }
36
+ /** The raw authored value of a token (the literal from the CSS), or `undefined`. */
37
+ export function tokenValue(name) {
38
+ return cssVars[name];
39
+ }
40
+ /**
41
+ * Inject the design-system stylesheet from code (idempotent) for surfaces that
42
+ * cannot use a bundler CSS import (e.g. a runtime-mounted island). Prefer the
43
+ * static `import '@hanzo/design/styles.css'` where a bundler is available.
44
+ * No-op outside the browser.
45
+ *
46
+ * `href` is REQUIRED: this used to default to esm.sh, which silently made a
47
+ * third-party CDN the origin of the entire token layer for anyone who called it
48
+ * bare. Pass a URL you serve.
49
+ */
50
+ export function injectDesignCss(href) {
51
+ if (typeof document === 'undefined')
52
+ return;
53
+ if (document.querySelector('link[data-hanzo-design]'))
54
+ return;
55
+ const l = document.createElement('link');
56
+ l.rel = 'stylesheet';
57
+ l.href = href;
58
+ l.setAttribute('data-hanzo-design', '');
59
+ document.head.appendChild(l);
60
+ }