@ponchia/ui 0.2.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 +21 -0
- package/README.md +160 -0
- package/behaviors/index.d.ts +40 -0
- package/behaviors/index.js +139 -0
- package/classes/index.d.ts +69 -0
- package/classes/index.js +159 -0
- package/css/app.css +309 -0
- package/css/base.css +206 -0
- package/css/cards.css +336 -0
- package/css/core.css +22 -0
- package/css/dots.css +159 -0
- package/css/fonts.css +60 -0
- package/css/forms.css +194 -0
- package/css/index.css +5 -0
- package/css/layout.css +219 -0
- package/css/motion.css +268 -0
- package/css/navigation.css +146 -0
- package/css/primitives.css +321 -0
- package/css/responsive.css +157 -0
- package/css/table.css +102 -0
- package/css/tokens.css +182 -0
- package/css/typography.css +139 -0
- package/fonts/doto-400.ttf +0 -0
- package/fonts/doto-500.ttf +0 -0
- package/fonts/doto-600.ttf +0 -0
- package/fonts/doto-700.ttf +0 -0
- package/fonts/doto-800.ttf +0 -0
- package/fonts/doto-900.ttf +0 -0
- package/package.json +77 -0
- package/tokens/index.d.ts +21 -0
- package/tokens/index.js +141 -0
- package/tokens/index.json +214 -0
package/css/tokens.css
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
@ponchia/ui — design tokens
|
|
3
|
+
Nothing-inspired: monochrome surfaces, single red accent, dot-matrix type.
|
|
4
|
+
Dual light/dark. Variable names are stable so semantic classes inherit.
|
|
5
|
+
The Doto @font-face declarations live in fonts.css (bundled by
|
|
6
|
+
core.css/index.css) so font hosting is decoupled from these tokens —
|
|
7
|
+
a consumer can self-host Doto and still use the token layer by
|
|
8
|
+
overriding --display / --dot-font.
|
|
9
|
+
========================================================================== */
|
|
10
|
+
|
|
11
|
+
:root {
|
|
12
|
+
/* Sharp, near-zero radii — Nothing surfaces are crisp, not pill-soft. */
|
|
13
|
+
--radius-xl: 4px;
|
|
14
|
+
--radius-lg: 3px;
|
|
15
|
+
--radius-md: 2px;
|
|
16
|
+
--radius-sm: 1px;
|
|
17
|
+
--radius-pill: 999px;
|
|
18
|
+
|
|
19
|
+
/* Spacing scale */
|
|
20
|
+
--space-2xs: 0.25rem;
|
|
21
|
+
--space-xs: 0.5rem;
|
|
22
|
+
--space-sm: 0.75rem;
|
|
23
|
+
--space-md: 1rem;
|
|
24
|
+
--space-lg: 1.35rem;
|
|
25
|
+
--space-xl: 1.75rem;
|
|
26
|
+
--space-2xl: 2.5rem;
|
|
27
|
+
|
|
28
|
+
/* Type — Doto is the dot-matrix display face; body stays mono-grotesque. */
|
|
29
|
+
--mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace;
|
|
30
|
+
--sans:
|
|
31
|
+
'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
|
|
32
|
+
--display: 'Doto', var(--mono);
|
|
33
|
+
--dot-font: 'Doto', var(--mono);
|
|
34
|
+
--text-2xs: 0.68rem;
|
|
35
|
+
--text-xs: 0.76rem;
|
|
36
|
+
--text-sm: 0.86rem;
|
|
37
|
+
--text-base: 0.95rem;
|
|
38
|
+
--text-lg: 1.15rem;
|
|
39
|
+
--text-xl: 1.45rem;
|
|
40
|
+
--tracking-wide: 0.14em;
|
|
41
|
+
--tracking-wider: 0.22em;
|
|
42
|
+
|
|
43
|
+
/* Motion — restrained, spring-tipped. */
|
|
44
|
+
--ease-standard: cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
45
|
+
--ease-spring: cubic-bezier(0.16, 1, 0.3, 1);
|
|
46
|
+
--ease-out: cubic-bezier(0.33, 1, 0.68, 1);
|
|
47
|
+
--duration-fast: 130ms;
|
|
48
|
+
--duration-base: 200ms;
|
|
49
|
+
--duration-slow: 360ms;
|
|
50
|
+
|
|
51
|
+
/* Dot-matrix motif sizing */
|
|
52
|
+
--dot-size: 2px;
|
|
53
|
+
--dot-gap: 14px;
|
|
54
|
+
|
|
55
|
+
/* Aliases kept for back-compat with existing semantic classes */
|
|
56
|
+
--surface: var(--panel);
|
|
57
|
+
--surface-raised: var(--panel-strong);
|
|
58
|
+
--surface-muted: var(--panel-soft);
|
|
59
|
+
--border: var(--line);
|
|
60
|
+
--border-strong: var(--line-strong);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* --------------------------------------------------------------------------
|
|
64
|
+
Light — paper white / ink. Color is rationed: red accent only.
|
|
65
|
+
-------------------------------------------------------------------------- */
|
|
66
|
+
:root,
|
|
67
|
+
:root[data-theme='light'] {
|
|
68
|
+
color-scheme: light;
|
|
69
|
+
|
|
70
|
+
--bg: #f4f4f2;
|
|
71
|
+
--bg-elevated: #fbfbfa;
|
|
72
|
+
--bg-accent: rgba(215, 25, 33, 0.06);
|
|
73
|
+
--panel: #ffffff;
|
|
74
|
+
--panel-strong: #ffffff;
|
|
75
|
+
--panel-soft: #ececea;
|
|
76
|
+
--line: #d8d8d4;
|
|
77
|
+
--line-strong: #a8a8a2;
|
|
78
|
+
--text: #0a0a0a;
|
|
79
|
+
--text-soft: #353533;
|
|
80
|
+
--text-dim: #7a7a75;
|
|
81
|
+
--accent: #d71921;
|
|
82
|
+
--accent-strong: #b3141b;
|
|
83
|
+
--accent-soft: rgba(215, 25, 33, 0.1);
|
|
84
|
+
--success: #2f7d4f;
|
|
85
|
+
--success-soft: rgba(47, 125, 79, 0.12);
|
|
86
|
+
--warning: #8a6d1c;
|
|
87
|
+
--warning-soft: rgba(138, 109, 28, 0.13);
|
|
88
|
+
--orange: #a85f32;
|
|
89
|
+
--orange-soft: rgba(168, 95, 50, 0.13);
|
|
90
|
+
--danger: #c01622;
|
|
91
|
+
--danger-soft: rgba(192, 22, 34, 0.1);
|
|
92
|
+
--code-bg: rgba(10, 10, 10, 0.05);
|
|
93
|
+
--button-text: #ffffff;
|
|
94
|
+
--field-dot: rgba(10, 10, 10, 0.16);
|
|
95
|
+
--field-dot-hot: rgba(10, 10, 10, 0.4);
|
|
96
|
+
--field-dot-accent: rgba(215, 25, 33, 0.78);
|
|
97
|
+
--focus-ring: rgba(215, 25, 33, 0.5);
|
|
98
|
+
--shadow: none;
|
|
99
|
+
--shadow-raised: 0 0 0 1px var(--line-strong);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* --------------------------------------------------------------------------
|
|
103
|
+
Dark — true black. The Nothing default.
|
|
104
|
+
|
|
105
|
+
The palette below is intentionally written twice: once under
|
|
106
|
+
`prefers-color-scheme: dark` (system default, unless overridden to light)
|
|
107
|
+
and once under `[data-theme='dark']` (explicit opt-in). Vanilla CSS can't
|
|
108
|
+
share one declaration block between a media query and a top-level selector
|
|
109
|
+
without a build step or nesting, neither of which this zero-dep package
|
|
110
|
+
has. Keep the two blocks in sync when editing dark tokens.
|
|
111
|
+
-------------------------------------------------------------------------- */
|
|
112
|
+
@media (prefers-color-scheme: dark) {
|
|
113
|
+
:root:not([data-theme='light']) {
|
|
114
|
+
color-scheme: dark;
|
|
115
|
+
|
|
116
|
+
--bg: #000000;
|
|
117
|
+
--bg-elevated: #0a0a0a;
|
|
118
|
+
--bg-accent: rgba(255, 59, 65, 0.08);
|
|
119
|
+
--panel: #0c0c0c;
|
|
120
|
+
--panel-strong: #141414;
|
|
121
|
+
--panel-soft: #1a1a1a;
|
|
122
|
+
--line: #2a2a2a;
|
|
123
|
+
--line-strong: #444444;
|
|
124
|
+
--text: #f2f2f2;
|
|
125
|
+
--text-soft: #c4c4c4;
|
|
126
|
+
--text-dim: #7d7d7d;
|
|
127
|
+
--accent: #ff3b41;
|
|
128
|
+
--accent-strong: #ff5b60;
|
|
129
|
+
--accent-soft: rgba(255, 59, 65, 0.14);
|
|
130
|
+
--success: #4ec27e;
|
|
131
|
+
--success-soft: rgba(78, 194, 126, 0.14);
|
|
132
|
+
--warning: #d8bd72;
|
|
133
|
+
--warning-soft: rgba(216, 189, 114, 0.14);
|
|
134
|
+
--orange: #d08c5b;
|
|
135
|
+
--orange-soft: rgba(208, 140, 91, 0.15);
|
|
136
|
+
--danger: #ff4d54;
|
|
137
|
+
--danger-soft: rgba(255, 77, 84, 0.15);
|
|
138
|
+
--code-bg: rgba(255, 255, 255, 0.05);
|
|
139
|
+
--button-text: #000000;
|
|
140
|
+
--field-dot: rgba(242, 242, 242, 0.14);
|
|
141
|
+
--field-dot-hot: rgba(242, 242, 242, 0.36);
|
|
142
|
+
--field-dot-accent: rgba(255, 59, 65, 0.82);
|
|
143
|
+
--focus-ring: rgba(255, 59, 65, 0.55);
|
|
144
|
+
--shadow: none;
|
|
145
|
+
--shadow-raised: 0 0 0 1px var(--line-strong);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
:root[data-theme='dark'] {
|
|
150
|
+
color-scheme: dark;
|
|
151
|
+
|
|
152
|
+
--bg: #000000;
|
|
153
|
+
--bg-elevated: #0a0a0a;
|
|
154
|
+
--bg-accent: rgba(255, 59, 65, 0.08);
|
|
155
|
+
--panel: #0c0c0c;
|
|
156
|
+
--panel-strong: #141414;
|
|
157
|
+
--panel-soft: #1a1a1a;
|
|
158
|
+
--line: #2a2a2a;
|
|
159
|
+
--line-strong: #444444;
|
|
160
|
+
--text: #f2f2f2;
|
|
161
|
+
--text-soft: #c4c4c4;
|
|
162
|
+
--text-dim: #7d7d7d;
|
|
163
|
+
--accent: #ff3b41;
|
|
164
|
+
--accent-strong: #ff5b60;
|
|
165
|
+
--accent-soft: rgba(255, 59, 65, 0.14);
|
|
166
|
+
--success: #4ec27e;
|
|
167
|
+
--success-soft: rgba(78, 194, 126, 0.14);
|
|
168
|
+
--warning: #d8bd72;
|
|
169
|
+
--warning-soft: rgba(216, 189, 114, 0.14);
|
|
170
|
+
--orange: #d08c5b;
|
|
171
|
+
--orange-soft: rgba(208, 140, 91, 0.15);
|
|
172
|
+
--danger: #ff4d54;
|
|
173
|
+
--danger-soft: rgba(255, 77, 84, 0.15);
|
|
174
|
+
--code-bg: rgba(255, 255, 255, 0.05);
|
|
175
|
+
--button-text: #000000;
|
|
176
|
+
--field-dot: rgba(242, 242, 242, 0.14);
|
|
177
|
+
--field-dot-hot: rgba(242, 242, 242, 0.36);
|
|
178
|
+
--field-dot-accent: rgba(255, 59, 65, 0.82);
|
|
179
|
+
--focus-ring: rgba(255, 59, 65, 0.55);
|
|
180
|
+
--shadow: none;
|
|
181
|
+
--shadow-raised: 0 0 0 1px var(--line-strong);
|
|
182
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
.hero__copy h1 {
|
|
2
|
+
max-width: 10ch;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.display-heading {
|
|
6
|
+
font-family: var(--display);
|
|
7
|
+
font-weight: 700;
|
|
8
|
+
letter-spacing: 0;
|
|
9
|
+
line-height: 1.05;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.hero__lede,
|
|
13
|
+
.page-head p {
|
|
14
|
+
font-size: 1.08rem;
|
|
15
|
+
max-width: 68ch;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.eyebrow,
|
|
19
|
+
.post-header__eyebrow,
|
|
20
|
+
.worklog-summary__eyebrow,
|
|
21
|
+
.callout__title,
|
|
22
|
+
.metric-tile__label,
|
|
23
|
+
.project-card__index,
|
|
24
|
+
.project-card__category,
|
|
25
|
+
.signal-panel__label,
|
|
26
|
+
.focus-panel__title,
|
|
27
|
+
.section-link,
|
|
28
|
+
.profile-link-list dt {
|
|
29
|
+
color: var(--accent);
|
|
30
|
+
font-family: var(--display);
|
|
31
|
+
font-size: 0.8rem;
|
|
32
|
+
font-weight: 700;
|
|
33
|
+
letter-spacing: var(--tracking-wide);
|
|
34
|
+
margin: 0;
|
|
35
|
+
text-transform: uppercase;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.eyebrow--tight {
|
|
39
|
+
font-size: 0.75rem;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.action-row {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-wrap: wrap;
|
|
45
|
+
gap: 0.55rem;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.button {
|
|
49
|
+
background: var(--accent);
|
|
50
|
+
border: 1px solid var(--line);
|
|
51
|
+
border-radius: var(--radius-md);
|
|
52
|
+
color: var(--button-text);
|
|
53
|
+
cursor: pointer;
|
|
54
|
+
display: inline-flex;
|
|
55
|
+
font-family: var(--mono);
|
|
56
|
+
font-size: 0.86rem;
|
|
57
|
+
font-weight: 600;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
letter-spacing: var(--tracking-wide);
|
|
60
|
+
line-height: 1;
|
|
61
|
+
text-transform: uppercase;
|
|
62
|
+
min-height: 2.4rem;
|
|
63
|
+
min-width: 8.2rem;
|
|
64
|
+
padding: 0.62rem 0.8rem;
|
|
65
|
+
transition:
|
|
66
|
+
background-color var(--duration-fast) var(--ease-standard),
|
|
67
|
+
border-color var(--duration-fast) var(--ease-standard),
|
|
68
|
+
color var(--duration-fast) var(--ease-standard),
|
|
69
|
+
transform var(--duration-fast) var(--ease-standard);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.button:not(.button--ghost) {
|
|
73
|
+
background: var(--accent);
|
|
74
|
+
border-color: var(--accent);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.button:hover {
|
|
78
|
+
background: var(--accent-strong);
|
|
79
|
+
border-color: var(--accent-strong);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.button--ghost {
|
|
83
|
+
background: var(--panel-strong);
|
|
84
|
+
border-color: var(--line);
|
|
85
|
+
color: var(--text);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.button--ghost:hover {
|
|
89
|
+
background: var(--panel-soft);
|
|
90
|
+
border-color: var(--line-strong);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.button:active {
|
|
94
|
+
transform: translateY(0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.section-link {
|
|
98
|
+
align-items: center;
|
|
99
|
+
display: inline-flex;
|
|
100
|
+
gap: 0.38rem;
|
|
101
|
+
justify-self: start;
|
|
102
|
+
text-decoration: underline;
|
|
103
|
+
text-decoration-color: color-mix(in srgb, var(--accent) 38%, transparent);
|
|
104
|
+
text-underline-offset: 0.22rem;
|
|
105
|
+
transition:
|
|
106
|
+
color var(--duration-fast) var(--ease-standard),
|
|
107
|
+
text-decoration-color var(--duration-fast) var(--ease-standard);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.section-link::after {
|
|
111
|
+
border-right: 1px solid currentColor;
|
|
112
|
+
border-top: 1px solid currentColor;
|
|
113
|
+
content: '';
|
|
114
|
+
height: 0.42rem;
|
|
115
|
+
transform: rotate(45deg);
|
|
116
|
+
transition: transform var(--duration-fast) var(--ease-standard);
|
|
117
|
+
width: 0.42rem;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.section-link:hover {
|
|
121
|
+
color: var(--accent-strong);
|
|
122
|
+
text-decoration-color: var(--accent-strong);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.section-link:hover::after {
|
|
126
|
+
transform: translateX(0.12rem) rotate(45deg);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
@media (hover: hover) {
|
|
130
|
+
.button:hover {
|
|
131
|
+
transform: translateY(-1px);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.hero__microcopy {
|
|
136
|
+
font-size: 0.96rem;
|
|
137
|
+
margin: 0;
|
|
138
|
+
max-width: 56ch;
|
|
139
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ponchia/ui",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Shared Bronto UI framework — Nothing-inspired monochrome CSS theme, dot-matrix motifs, admin shell.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/Ponchia/bronto-ui.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/Ponchia/bronto-ui#readme",
|
|
12
|
+
"bugs": "https://github.com/Ponchia/bronto-ui/issues",
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public",
|
|
15
|
+
"provenance": true
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": [
|
|
18
|
+
"**/*.css"
|
|
19
|
+
],
|
|
20
|
+
"files": [
|
|
21
|
+
"css",
|
|
22
|
+
"fonts",
|
|
23
|
+
"tokens",
|
|
24
|
+
"classes",
|
|
25
|
+
"behaviors"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"lint": "stylelint \"css/**/*.css\"",
|
|
29
|
+
"lint:fix": "stylelint \"css/**/*.css\" --fix",
|
|
30
|
+
"tokens:build": "node scripts/gen-tokens-json.mjs",
|
|
31
|
+
"check:exports": "node scripts/check-exports.mjs",
|
|
32
|
+
"check:tokens": "node scripts/check-tokens.mjs",
|
|
33
|
+
"check:classes": "node scripts/check-classes.mjs",
|
|
34
|
+
"check:pack": "node scripts/check-pack.mjs",
|
|
35
|
+
"check": "npm run lint && npm run check:exports && npm run check:tokens && npm run check:classes && npm run check:pack",
|
|
36
|
+
"test": "node --test \"test/*.test.mjs\"",
|
|
37
|
+
"prepack": "npm run tokens:build"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"jsdom": "^25.0.1",
|
|
41
|
+
"stylelint": "^16.10.0",
|
|
42
|
+
"stylelint-config-standard": "^36.0.1"
|
|
43
|
+
},
|
|
44
|
+
"exports": {
|
|
45
|
+
"./css": "./css/index.css",
|
|
46
|
+
"./css/index.css": "./css/index.css",
|
|
47
|
+
"./css/core.css": "./css/core.css",
|
|
48
|
+
"./css/tokens.css": "./css/tokens.css",
|
|
49
|
+
"./css/fonts.css": "./css/fonts.css",
|
|
50
|
+
"./css/base.css": "./css/base.css",
|
|
51
|
+
"./css/motion.css": "./css/motion.css",
|
|
52
|
+
"./css/dots.css": "./css/dots.css",
|
|
53
|
+
"./css/layout.css": "./css/layout.css",
|
|
54
|
+
"./css/navigation.css": "./css/navigation.css",
|
|
55
|
+
"./css/typography.css": "./css/typography.css",
|
|
56
|
+
"./css/primitives.css": "./css/primitives.css",
|
|
57
|
+
"./css/forms.css": "./css/forms.css",
|
|
58
|
+
"./css/table.css": "./css/table.css",
|
|
59
|
+
"./css/cards.css": "./css/cards.css",
|
|
60
|
+
"./css/app.css": "./css/app.css",
|
|
61
|
+
"./css/responsive.css": "./css/responsive.css",
|
|
62
|
+
"./tokens": {
|
|
63
|
+
"types": "./tokens/index.d.ts",
|
|
64
|
+
"default": "./tokens/index.js"
|
|
65
|
+
},
|
|
66
|
+
"./tokens.json": "./tokens/index.json",
|
|
67
|
+
"./classes": {
|
|
68
|
+
"types": "./classes/index.d.ts",
|
|
69
|
+
"default": "./classes/index.js"
|
|
70
|
+
},
|
|
71
|
+
"./behaviors": {
|
|
72
|
+
"types": "./behaviors/index.d.ts",
|
|
73
|
+
"default": "./behaviors/index.js"
|
|
74
|
+
},
|
|
75
|
+
"./fonts/*": "./fonts/*"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** @ponchia/ui — design token data types. */
|
|
2
|
+
|
|
3
|
+
export type ThemeName = 'light' | 'dark';
|
|
4
|
+
|
|
5
|
+
/** Exact mirror of the :root blocks in css/tokens.css. */
|
|
6
|
+
export declare const cssVars: {
|
|
7
|
+
global: Record<`--${string}`, string>;
|
|
8
|
+
light: Record<`--${string}`, string>;
|
|
9
|
+
dark: Record<`--${string}`, string>;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/** Ergonomic view derived from {@link cssVars} (custom-property `--` prefix stripped). */
|
|
13
|
+
export declare const tokens: {
|
|
14
|
+
scale: Record<string, string>;
|
|
15
|
+
color: { light: Record<string, string>; dark: Record<string, string> };
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** Resolve the palette for a theme. Unknown values fall back to light. */
|
|
19
|
+
export declare function themeColor(theme?: string): Record<string, string>;
|
|
20
|
+
|
|
21
|
+
export default tokens;
|
package/tokens/index.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @ponchia/ui — design tokens as data.
|
|
3
|
+
*
|
|
4
|
+
* For consumers that need token values in JS rather than CSS: charting,
|
|
5
|
+
* canvas, inline styles, theme-aware logic, Style Dictionary / Figma sync.
|
|
6
|
+
*
|
|
7
|
+
* `cssVars` is the canonical, exact mirror of the :root blocks in
|
|
8
|
+
* css/tokens.css — keyed by the real custom-property name, values are
|
|
9
|
+
* the verbatim CSS strings. scripts/check-tokens.mjs fails CI if this
|
|
10
|
+
* drifts from the stylesheet, so the two cannot silently diverge.
|
|
11
|
+
*
|
|
12
|
+
* `tokens` is an ergonomic view derived programmatically from `cssVars`
|
|
13
|
+
* (no second hand-maintained copy, so nothing to keep in sync).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Exact mirror of css/tokens.css. Do not reshape — the sync check is literal. */
|
|
17
|
+
export const cssVars = {
|
|
18
|
+
// Global :root — scales, shared with both themes.
|
|
19
|
+
global: {
|
|
20
|
+
'--radius-xl': '4px',
|
|
21
|
+
'--radius-lg': '3px',
|
|
22
|
+
'--radius-md': '2px',
|
|
23
|
+
'--radius-sm': '1px',
|
|
24
|
+
'--radius-pill': '999px',
|
|
25
|
+
'--space-2xs': '0.25rem',
|
|
26
|
+
'--space-xs': '0.5rem',
|
|
27
|
+
'--space-sm': '0.75rem',
|
|
28
|
+
'--space-md': '1rem',
|
|
29
|
+
'--space-lg': '1.35rem',
|
|
30
|
+
'--space-xl': '1.75rem',
|
|
31
|
+
'--space-2xl': '2.5rem',
|
|
32
|
+
'--mono': "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', ui-monospace, monospace",
|
|
33
|
+
'--sans':
|
|
34
|
+
"'Inter', 'SF Pro Text', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
|
|
35
|
+
'--display': "'Doto', var(--mono)",
|
|
36
|
+
'--dot-font': "'Doto', var(--mono)",
|
|
37
|
+
'--text-2xs': '0.68rem',
|
|
38
|
+
'--text-xs': '0.76rem',
|
|
39
|
+
'--text-sm': '0.86rem',
|
|
40
|
+
'--text-base': '0.95rem',
|
|
41
|
+
'--text-lg': '1.15rem',
|
|
42
|
+
'--text-xl': '1.45rem',
|
|
43
|
+
'--tracking-wide': '0.14em',
|
|
44
|
+
'--tracking-wider': '0.22em',
|
|
45
|
+
'--ease-standard': 'cubic-bezier(0.2, 0.8, 0.2, 1)',
|
|
46
|
+
'--ease-spring': 'cubic-bezier(0.16, 1, 0.3, 1)',
|
|
47
|
+
'--ease-out': 'cubic-bezier(0.33, 1, 0.68, 1)',
|
|
48
|
+
'--duration-fast': '130ms',
|
|
49
|
+
'--duration-base': '200ms',
|
|
50
|
+
'--duration-slow': '360ms',
|
|
51
|
+
'--dot-size': '2px',
|
|
52
|
+
'--dot-gap': '14px',
|
|
53
|
+
'--surface': 'var(--panel)',
|
|
54
|
+
'--surface-raised': 'var(--panel-strong)',
|
|
55
|
+
'--surface-muted': 'var(--panel-soft)',
|
|
56
|
+
'--border': 'var(--line)',
|
|
57
|
+
'--border-strong': 'var(--line-strong)',
|
|
58
|
+
},
|
|
59
|
+
// Light palette — :root, :root[data-theme='light'].
|
|
60
|
+
light: {
|
|
61
|
+
'--bg': '#f4f4f2',
|
|
62
|
+
'--bg-elevated': '#fbfbfa',
|
|
63
|
+
'--bg-accent': 'rgba(215, 25, 33, 0.06)',
|
|
64
|
+
'--panel': '#ffffff',
|
|
65
|
+
'--panel-strong': '#ffffff',
|
|
66
|
+
'--panel-soft': '#ececea',
|
|
67
|
+
'--line': '#d8d8d4',
|
|
68
|
+
'--line-strong': '#a8a8a2',
|
|
69
|
+
'--text': '#0a0a0a',
|
|
70
|
+
'--text-soft': '#353533',
|
|
71
|
+
'--text-dim': '#7a7a75',
|
|
72
|
+
'--accent': '#d71921',
|
|
73
|
+
'--accent-strong': '#b3141b',
|
|
74
|
+
'--accent-soft': 'rgba(215, 25, 33, 0.1)',
|
|
75
|
+
'--success': '#2f7d4f',
|
|
76
|
+
'--success-soft': 'rgba(47, 125, 79, 0.12)',
|
|
77
|
+
'--warning': '#8a6d1c',
|
|
78
|
+
'--warning-soft': 'rgba(138, 109, 28, 0.13)',
|
|
79
|
+
'--orange': '#a85f32',
|
|
80
|
+
'--orange-soft': 'rgba(168, 95, 50, 0.13)',
|
|
81
|
+
'--danger': '#c01622',
|
|
82
|
+
'--danger-soft': 'rgba(192, 22, 34, 0.1)',
|
|
83
|
+
'--code-bg': 'rgba(10, 10, 10, 0.05)',
|
|
84
|
+
'--button-text': '#ffffff',
|
|
85
|
+
'--field-dot': 'rgba(10, 10, 10, 0.16)',
|
|
86
|
+
'--field-dot-hot': 'rgba(10, 10, 10, 0.4)',
|
|
87
|
+
'--field-dot-accent': 'rgba(215, 25, 33, 0.78)',
|
|
88
|
+
'--focus-ring': 'rgba(215, 25, 33, 0.5)',
|
|
89
|
+
'--shadow': 'none',
|
|
90
|
+
'--shadow-raised': '0 0 0 1px var(--line-strong)',
|
|
91
|
+
},
|
|
92
|
+
// Dark palette — both the prefers-color-scheme and [data-theme='dark'] blocks.
|
|
93
|
+
dark: {
|
|
94
|
+
'--bg': '#000000',
|
|
95
|
+
'--bg-elevated': '#0a0a0a',
|
|
96
|
+
'--bg-accent': 'rgba(255, 59, 65, 0.08)',
|
|
97
|
+
'--panel': '#0c0c0c',
|
|
98
|
+
'--panel-strong': '#141414',
|
|
99
|
+
'--panel-soft': '#1a1a1a',
|
|
100
|
+
'--line': '#2a2a2a',
|
|
101
|
+
'--line-strong': '#444444',
|
|
102
|
+
'--text': '#f2f2f2',
|
|
103
|
+
'--text-soft': '#c4c4c4',
|
|
104
|
+
'--text-dim': '#7d7d7d',
|
|
105
|
+
'--accent': '#ff3b41',
|
|
106
|
+
'--accent-strong': '#ff5b60',
|
|
107
|
+
'--accent-soft': 'rgba(255, 59, 65, 0.14)',
|
|
108
|
+
'--success': '#4ec27e',
|
|
109
|
+
'--success-soft': 'rgba(78, 194, 126, 0.14)',
|
|
110
|
+
'--warning': '#d8bd72',
|
|
111
|
+
'--warning-soft': 'rgba(216, 189, 114, 0.14)',
|
|
112
|
+
'--orange': '#d08c5b',
|
|
113
|
+
'--orange-soft': 'rgba(208, 140, 91, 0.15)',
|
|
114
|
+
'--danger': '#ff4d54',
|
|
115
|
+
'--danger-soft': 'rgba(255, 77, 84, 0.15)',
|
|
116
|
+
'--code-bg': 'rgba(255, 255, 255, 0.05)',
|
|
117
|
+
'--button-text': '#000000',
|
|
118
|
+
'--field-dot': 'rgba(242, 242, 242, 0.14)',
|
|
119
|
+
'--field-dot-hot': 'rgba(242, 242, 242, 0.36)',
|
|
120
|
+
'--field-dot-accent': 'rgba(255, 59, 65, 0.82)',
|
|
121
|
+
'--focus-ring': 'rgba(255, 59, 65, 0.55)',
|
|
122
|
+
'--shadow': 'none',
|
|
123
|
+
'--shadow-raised': '0 0 0 1px var(--line-strong)',
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const strip = (obj) =>
|
|
128
|
+
Object.fromEntries(Object.entries(obj).map(([k, v]) => [k.replace(/^--/, ''), v]));
|
|
129
|
+
|
|
130
|
+
/** Ergonomic view, derived from cssVars (single source — never edit directly). */
|
|
131
|
+
export const tokens = {
|
|
132
|
+
scale: strip(cssVars.global),
|
|
133
|
+
color: { light: strip(cssVars.light), dark: strip(cssVars.dark) },
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/** Resolve the palette for a theme: themeColor('dark').accent === '#ff3b41'. */
|
|
137
|
+
export function themeColor(theme = 'light') {
|
|
138
|
+
return tokens.color[theme === 'dark' ? 'dark' : 'light'];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export default tokens;
|