graphen 1.10.19 → 2.0.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/dist/css.js +1 -1
- package/dist/scripts.js +1 -1
- package/package.json +1 -1
- package/src/components/Badge/index.tsx +29 -0
- package/src/components/Badge/styles/_styles.scss +38 -0
- package/src/components/Body/styles/_styles.scss +6 -2
- package/src/components/Button/styles/_styles.scss +63 -28
- package/src/components/Card/styles/_styles.scss +5 -6
- package/src/components/Dropdown/integration/dropdown.spec.js +9 -5
- package/src/components/Input/styles/_styles.scss +36 -9
- package/src/components/Link/styles/_styles.scss +5 -2
- package/src/components/Logo/index.tsx +2 -1
- package/src/components/Logo/styles/_styles.scss +24 -2
- package/src/components/SectionHeader/styles/_styles.scss +40 -0
- package/src/components/Separator/styles/_styles.scss +4 -3
- package/src/example/styles/_docs.scss +731 -0
- package/src/example/styles/_splash.scss +169 -0
- package/src/example/styles/_styles.scss +14 -0
- package/src/example.scss +5 -17
- package/src/example.tsx +928 -632
- package/src/index.ts +2 -0
- package/src/style.scss +2 -0
- package/src/variables/_brand.scss +2 -1
- package/src/variables/_sizes.scss +3 -3
- package/src/variables/integration/colors.spec.js +21 -17
- package/dist/18ca3004c8aec4f105976c8c7f11083b.jpg +0 -0
- package/dist/example.js +0 -2
- package/dist/example.js.LICENSE.txt +0 -44
- package/dist/styles.css +0 -1
- package/src/assets/splash.jpg +0 -0
package/src/example.tsx
CHANGED
|
@@ -1,663 +1,959 @@
|
|
|
1
|
-
/* eslint-disable */
|
|
2
|
-
import
|
|
3
|
-
import React, { useState } from "react";
|
|
1
|
+
/* eslint-disable jsx-a11y/anchor-is-valid, react/no-deprecated */
|
|
2
|
+
import React, { useEffect, useMemo, useState } from "react";
|
|
4
3
|
import { render } from "react-dom";
|
|
5
4
|
import {
|
|
5
|
+
Badge,
|
|
6
6
|
Button,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
Card,
|
|
8
|
+
Dropdown,
|
|
9
9
|
Input,
|
|
10
|
-
Image,
|
|
11
10
|
Link,
|
|
12
|
-
Loader,
|
|
13
|
-
Card,
|
|
14
|
-
Scroller,
|
|
15
|
-
Joystick,
|
|
16
|
-
Accordion,
|
|
17
|
-
Validation,
|
|
18
|
-
Tooltip,
|
|
19
11
|
Logo,
|
|
20
|
-
|
|
21
|
-
Switch,
|
|
22
|
-
Flex,
|
|
23
|
-
FlexItem,
|
|
24
|
-
Panel,
|
|
25
|
-
PanelFooter,
|
|
26
|
-
PanelContent,
|
|
27
|
-
PanelTitle,
|
|
28
|
-
Skeleton,
|
|
12
|
+
Separator,
|
|
29
13
|
constants,
|
|
30
14
|
} from "./index";
|
|
31
15
|
|
|
32
|
-
const
|
|
16
|
+
declare const GRAPHEN_VERSION: string;
|
|
17
|
+
|
|
18
|
+
const VERSION = GRAPHEN_VERSION;
|
|
19
|
+
|
|
20
|
+
const TOKENS = [
|
|
21
|
+
[
|
|
22
|
+
"#337ab7",
|
|
23
|
+
"Primary",
|
|
24
|
+
"Default brand color, links and primary actions",
|
|
25
|
+
"$gb-color-primary",
|
|
26
|
+
],
|
|
27
|
+
[
|
|
28
|
+
"#585858",
|
|
29
|
+
"Text",
|
|
30
|
+
"Body copy, headings, default foreground",
|
|
31
|
+
"$gb-color-text",
|
|
32
|
+
],
|
|
33
|
+
["#337ab7", "Link", "Inline and standalone hyperlinks", "$gb-color-link"],
|
|
34
|
+
[
|
|
35
|
+
"#f5f5f5",
|
|
36
|
+
"Component",
|
|
37
|
+
"Default surface for cards, inputs, buttons",
|
|
38
|
+
"$gb-color-component",
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
"#e5e5e5",
|
|
42
|
+
"Component dark",
|
|
43
|
+
"Hover state for component surfaces",
|
|
44
|
+
"$gb-color-component-dark",
|
|
45
|
+
],
|
|
46
|
+
[
|
|
47
|
+
"#0ea348",
|
|
48
|
+
"Success",
|
|
49
|
+
"Positive feedback, confirmation states",
|
|
50
|
+
"$gb-color-success",
|
|
51
|
+
],
|
|
52
|
+
["#337ab7", "Info", "Neutral messaging, hints", "$gb-color-info"],
|
|
53
|
+
["#db5551", "Danger", "Errors, destructive actions", "$gb-color-danger"],
|
|
54
|
+
] as const;
|
|
55
|
+
|
|
56
|
+
const TYPE_SCALE = [
|
|
57
|
+
{
|
|
58
|
+
meta: "36 / 1.1",
|
|
59
|
+
token: "$gb-fs-display",
|
|
60
|
+
style: { fontSize: 36, fontWeight: 500, letterSpacing: "-0.02em" },
|
|
61
|
+
sample: "The quick brown fox",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
meta: "22 / 1.3",
|
|
65
|
+
token: "$gb-fs-h1",
|
|
66
|
+
style: { fontSize: 22, fontWeight: 500 },
|
|
67
|
+
sample: "The quick brown fox jumps over",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
meta: "17 / 1.4",
|
|
71
|
+
token: "$gb-fs-h2",
|
|
72
|
+
style: { fontSize: 17, fontWeight: 500 },
|
|
73
|
+
sample: "The quick brown fox jumps over the lazy dog",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
meta: "15 / 1.55",
|
|
77
|
+
token: "$gb-fs-body",
|
|
78
|
+
style: {},
|
|
79
|
+
sample:
|
|
80
|
+
"The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
meta: "13 / 1.5",
|
|
84
|
+
token: "$gb-fs-small",
|
|
85
|
+
style: { fontSize: 13, color: "var(--text-muted)" },
|
|
86
|
+
sample:
|
|
87
|
+
"The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs.",
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const SPACING = [
|
|
92
|
+
["$gb-sp-1", "4 px", "0.25rem", 4],
|
|
93
|
+
["$gb-sp-2", "8 px", "0.5rem", 8],
|
|
94
|
+
["$gb-sp-3", "12 px", "0.75rem", 12],
|
|
95
|
+
["$gb-sp-4", "16 px", "1rem", 16],
|
|
96
|
+
["$gb-sp-6", "24 px", "1.5rem", 24],
|
|
97
|
+
["$gb-sp-8", "32 px", "2rem", 32],
|
|
98
|
+
["$gb-sp-12", "48 px", "3rem", 48],
|
|
99
|
+
["$gb-sp-16", "64 px", "4rem", 64],
|
|
100
|
+
] as const;
|
|
33
101
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
102
|
+
const RADIUS = [
|
|
103
|
+
["$gb-r-sm", "4 px", 4],
|
|
104
|
+
["$gb-r", "6 px", 6],
|
|
105
|
+
["$gb-r-lg", "10 px", 10],
|
|
106
|
+
["$gb-r-full", "9999 px", 999],
|
|
107
|
+
] as const;
|
|
38
108
|
|
|
109
|
+
const ICONS: ReadonlyArray<readonly [string, string]> = [
|
|
110
|
+
["chevron-up", "M6 15l6-6 6 6"],
|
|
111
|
+
["chevron-right", "M9 6l6 6-6 6"],
|
|
112
|
+
["chevron-down", "M6 9l6 6 6-6"],
|
|
113
|
+
["chevron-left", "M15 6l-6 6 6 6"],
|
|
114
|
+
["flame", "M12 3s4 4 4 8a4 4 0 0 1-8 0c0-2 1-3 1-3s0 2 2 2 1-3 1-7z"],
|
|
115
|
+
["user", ""],
|
|
116
|
+
["menu", "M4 7h16M4 12h16M4 17h16"],
|
|
117
|
+
["menu-add", "M4 7h16M4 12h10M4 17h16M17 12h5M19.5 9.5v5"],
|
|
118
|
+
["menu-sort", "M4 7h12M4 12h8M4 17h12 m6 -3 3 3-3 3"],
|
|
119
|
+
["thermometer", "M14 14V5a2 2 0 1 0-4 0v9a4 4 0 1 0 4 0z"],
|
|
120
|
+
["target", ""],
|
|
121
|
+
["record", ""],
|
|
122
|
+
["circle", ""],
|
|
123
|
+
["plus", "M12 5v14M5 12h14"],
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
const NAV = [
|
|
127
|
+
{
|
|
128
|
+
title: "Getting started",
|
|
129
|
+
items: [
|
|
130
|
+
{ id: "introduction", label: "Introduction" },
|
|
131
|
+
{ id: "installation", label: "Installation" },
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
title: "Foundations",
|
|
136
|
+
items: [
|
|
137
|
+
{ id: "colors", label: "Colors" },
|
|
138
|
+
{ id: "typography", label: "Typography" },
|
|
139
|
+
{ id: "spacing", label: "Spacing & radius" },
|
|
140
|
+
{ id: "iconography", label: "Iconography", count: "14" },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
title: "Components",
|
|
145
|
+
items: [
|
|
146
|
+
{ id: "logo", label: "Logo" },
|
|
147
|
+
{ id: "button", label: "Button" },
|
|
148
|
+
{ id: "link", label: "Link" },
|
|
149
|
+
{ id: "header-comp", label: "Header" },
|
|
150
|
+
{ id: "separator", label: "Separator" },
|
|
151
|
+
{ id: "input", label: "Input" },
|
|
152
|
+
{ id: "dropdown", label: "Dropdown" },
|
|
153
|
+
{ id: "card", label: "Card" },
|
|
154
|
+
{ id: "badge", label: "Badge" },
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
const TOC = [
|
|
160
|
+
["introduction", "Introduction"],
|
|
161
|
+
["colors", "Colors"],
|
|
162
|
+
["typography", "Typography"],
|
|
163
|
+
["spacing", "Spacing & radius"],
|
|
164
|
+
["iconography", "Iconography"],
|
|
165
|
+
["logo", "Logo"],
|
|
166
|
+
["button", "Button"],
|
|
167
|
+
["link", "Link"],
|
|
168
|
+
["header-comp", "Header"],
|
|
169
|
+
["separator", "Separator"],
|
|
170
|
+
["input", "Input"],
|
|
171
|
+
["dropdown", "Dropdown"],
|
|
172
|
+
["card", "Card"],
|
|
173
|
+
["badge", "Badge"],
|
|
174
|
+
] as const;
|
|
175
|
+
|
|
176
|
+
type IconProps = {
|
|
177
|
+
d?: string;
|
|
178
|
+
children?: React.ReactNode;
|
|
179
|
+
size?: number;
|
|
180
|
+
stroke?: number;
|
|
181
|
+
};
|
|
182
|
+
function StrokeIcon({ d, children, size = 16, stroke = 1.7 }: IconProps) {
|
|
39
183
|
return (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
</li>
|
|
266
|
-
</ul>
|
|
267
|
-
</div>
|
|
268
|
-
</article>
|
|
269
|
-
<article className="gc-panel gc-panel--separator">
|
|
270
|
-
<header className="gc-panel__title">Panel</header>
|
|
271
|
-
<div className="gc-panel__content">
|
|
272
|
-
<article className="gc-panel">
|
|
273
|
-
<header className="gc-panel__title">Panel title</header>
|
|
274
|
-
<div className="gc-panel__content">
|
|
275
|
-
<p>Panel content paragraph 1</p>
|
|
276
|
-
<p>Panel content paragraph 2</p>
|
|
277
|
-
</div>
|
|
278
|
-
</article>
|
|
279
|
-
</div>
|
|
280
|
-
</article>
|
|
281
|
-
<article className="gc-panel gc-panel--separator">
|
|
282
|
-
<header className="gc-panel__title">Buttons</header>
|
|
283
|
-
<div className="gc-panel__content">
|
|
284
|
-
<p>
|
|
285
|
-
<Button>Button</Button>{" "}
|
|
286
|
-
<Button className="gc-btn--danger">Button + danger</Button>{" "}
|
|
287
|
-
<Button className="gc-btn--primary">Button + primary</Button>{" "}
|
|
288
|
-
<Button className="gc-btn--secondary">Button + secondary</Button>{" "}
|
|
289
|
-
<Button className="gc-btn--tertiary">Button + tertiary</Button>
|
|
290
|
-
<Button isDisabled>Button + isDisabled</Button>
|
|
291
|
-
</p>
|
|
292
|
-
<p>
|
|
293
|
-
<Button className="gc-btn--small">Button + small</Button>{" "}
|
|
294
|
-
<Button className="gc-btn--small gc-btn--danger">
|
|
295
|
-
Button + small + danger
|
|
296
|
-
</Button>{" "}
|
|
297
|
-
<Button className="gc-btn--small gc-btn--primary">
|
|
298
|
-
Button + small + primary
|
|
299
|
-
</Button>{" "}
|
|
300
|
-
<Button className="gc-btn--small gc-btn--secondary">
|
|
301
|
-
Button + small + secondary
|
|
302
|
-
</Button>{" "}
|
|
303
|
-
<Button className="gc-btn--small gc-btn--tertiary">
|
|
304
|
-
Button + small + tertiary
|
|
305
|
-
</Button>
|
|
306
|
-
</p>
|
|
307
|
-
<p>
|
|
308
|
-
<Button className="gc-btn--full">Button + full</Button>
|
|
309
|
-
</p>
|
|
310
|
-
<p>
|
|
311
|
-
<Button className="gc-btn--full gc-btn--danger">
|
|
312
|
-
Button + full + danger
|
|
313
|
-
</Button>
|
|
314
|
-
</p>
|
|
315
|
-
<p>
|
|
316
|
-
<Button className="gc-btn--full gc-btn--primary">
|
|
317
|
-
Button + full + primary
|
|
318
|
-
</Button>
|
|
319
|
-
</p>
|
|
320
|
-
<p>
|
|
321
|
-
<Button className="gc-btn--full gc-btn--secondary">
|
|
322
|
-
Button + full + secondary
|
|
323
|
-
</Button>
|
|
324
|
-
</p>
|
|
325
|
-
<p>
|
|
326
|
-
<Button className="gc-btn--full gc-btn--tertiary">
|
|
327
|
-
Button + full + tertiary
|
|
328
|
-
</Button>
|
|
329
|
-
</p>
|
|
330
|
-
</div>
|
|
331
|
-
</article>
|
|
332
|
-
<article className="gc-panel gc-panel--separator">
|
|
333
|
-
<header className="gc-panel__title">Switches</header>
|
|
334
|
-
<div className="gc-panel__content">
|
|
335
|
-
<p>
|
|
336
|
-
<Switch /> <Switch type="success" isSwitched />{" "}
|
|
337
|
-
<Switch type="info" isSwitched />{" "}
|
|
338
|
-
<Switch type="danger" isSwitched />
|
|
339
|
-
</p>
|
|
340
|
-
</div>
|
|
341
|
-
</article>
|
|
342
|
-
<article className="gc-panel gc-panel--separator">
|
|
343
|
-
<header className="gc-panel__title">Images</header>
|
|
344
|
-
<div className="gc-panel__content">
|
|
345
|
-
<Image
|
|
346
|
-
className="gm-spacing-rl"
|
|
347
|
-
src="no-image.jpg"
|
|
348
|
-
height={200}
|
|
349
|
-
width={400}
|
|
350
|
-
/>
|
|
351
|
-
<Image
|
|
352
|
-
src="./can-t-look-over-1312680-639x469.jpg"
|
|
353
|
-
height={200}
|
|
354
|
-
width={400}
|
|
355
|
-
/>
|
|
184
|
+
<svg
|
|
185
|
+
width={size}
|
|
186
|
+
height={size}
|
|
187
|
+
viewBox="0 0 24 24"
|
|
188
|
+
fill="none"
|
|
189
|
+
stroke="currentColor"
|
|
190
|
+
strokeWidth={stroke}
|
|
191
|
+
strokeLinecap="round"
|
|
192
|
+
strokeLinejoin="round"
|
|
193
|
+
aria-hidden="true"
|
|
194
|
+
>
|
|
195
|
+
{d ? <path d={d} /> : children}
|
|
196
|
+
</svg>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function CopyButton({
|
|
201
|
+
value,
|
|
202
|
+
label = "copy",
|
|
203
|
+
}: {
|
|
204
|
+
value: string;
|
|
205
|
+
label?: string;
|
|
206
|
+
}) {
|
|
207
|
+
const [copied, setCopied] = useState(false);
|
|
208
|
+
return (
|
|
209
|
+
<button
|
|
210
|
+
type="button"
|
|
211
|
+
className={`docs-copy-btn${copied ? " copied" : ""}`}
|
|
212
|
+
onClick={async () => {
|
|
213
|
+
try {
|
|
214
|
+
await navigator.clipboard.writeText(value);
|
|
215
|
+
} catch {
|
|
216
|
+
/* noop */
|
|
217
|
+
}
|
|
218
|
+
setCopied(true);
|
|
219
|
+
window.setTimeout(() => setCopied(false), 1100);
|
|
220
|
+
}}
|
|
221
|
+
>
|
|
222
|
+
{copied ? "copied" : label}
|
|
223
|
+
</button>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
type DemoProps = {
|
|
228
|
+
code: React.ReactNode;
|
|
229
|
+
stageClass?: string;
|
|
230
|
+
children: React.ReactNode;
|
|
231
|
+
};
|
|
232
|
+
function Demo({ code, stageClass = "", children }: DemoProps) {
|
|
233
|
+
const [active, setActive] = useState<"preview" | "code">("preview");
|
|
234
|
+
return (
|
|
235
|
+
<div className="docs-demo" data-active={active}>
|
|
236
|
+
<div className="tabs" role="tablist">
|
|
237
|
+
<button
|
|
238
|
+
type="button"
|
|
239
|
+
role="tab"
|
|
240
|
+
className="tab"
|
|
241
|
+
aria-selected={active === "preview"}
|
|
242
|
+
onClick={() => setActive("preview")}
|
|
243
|
+
>
|
|
244
|
+
<svg
|
|
245
|
+
className="ico"
|
|
246
|
+
viewBox="0 0 24 24"
|
|
247
|
+
fill="none"
|
|
248
|
+
stroke="currentColor"
|
|
249
|
+
strokeWidth={2}
|
|
250
|
+
>
|
|
251
|
+
<circle cx="12" cy="12" r="3" />
|
|
252
|
+
<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z" />
|
|
253
|
+
</svg>
|
|
254
|
+
Preview
|
|
255
|
+
</button>
|
|
256
|
+
<button
|
|
257
|
+
type="button"
|
|
258
|
+
role="tab"
|
|
259
|
+
className="tab"
|
|
260
|
+
aria-selected={active === "code"}
|
|
261
|
+
onClick={() => setActive("code")}
|
|
262
|
+
>
|
|
263
|
+
<svg
|
|
264
|
+
className="ico"
|
|
265
|
+
viewBox="0 0 24 24"
|
|
266
|
+
fill="none"
|
|
267
|
+
stroke="currentColor"
|
|
268
|
+
strokeWidth={2}
|
|
269
|
+
strokeLinecap="round"
|
|
270
|
+
>
|
|
271
|
+
<path d="m8 6-6 6 6 6M16 6l6 6-6 6" />
|
|
272
|
+
</svg>
|
|
273
|
+
Code
|
|
274
|
+
</button>
|
|
275
|
+
</div>
|
|
276
|
+
<div className={`stage ${stageClass}`}>{children}</div>
|
|
277
|
+
<pre className="code">{code}</pre>
|
|
278
|
+
</div>
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function HexLogoMark() {
|
|
283
|
+
return (
|
|
284
|
+
<svg className="docs-hex" viewBox="0 0 24 24" aria-hidden="true">
|
|
285
|
+
<polygon
|
|
286
|
+
points="12,2 21,7 21,17 12,22 3,17 3,7"
|
|
287
|
+
fill="none"
|
|
288
|
+
stroke="currentColor"
|
|
289
|
+
strokeWidth={1.6}
|
|
290
|
+
strokeLinejoin="round"
|
|
291
|
+
/>
|
|
292
|
+
<polygon
|
|
293
|
+
points="12,7 17,9.5 17,14.5 12,17 7,14.5 7,9.5"
|
|
294
|
+
fill="currentColor"
|
|
295
|
+
opacity={0.18}
|
|
296
|
+
/>
|
|
297
|
+
</svg>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const INSTALL_CMDS: Record<string, string> = {
|
|
302
|
+
npm: "npm i graphen",
|
|
303
|
+
pnpm: "pnpm add graphen",
|
|
304
|
+
yarn: "yarn add graphen",
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
const DROPDOWN_ITEMS = [
|
|
308
|
+
{ value: "red", label: "Red" },
|
|
309
|
+
{ value: "blue", label: "Blue" },
|
|
310
|
+
{ value: "green", label: "Green" },
|
|
311
|
+
] as const;
|
|
312
|
+
|
|
313
|
+
function IconCell({ name, d }: { name: string; d: string }) {
|
|
314
|
+
const [copied, setCopied] = useState(false);
|
|
315
|
+
return (
|
|
316
|
+
<div
|
|
317
|
+
className="docs-icon-cell"
|
|
318
|
+
role="button"
|
|
319
|
+
tabIndex={0}
|
|
320
|
+
onClick={async () => {
|
|
321
|
+
try {
|
|
322
|
+
await navigator.clipboard.writeText(name);
|
|
323
|
+
} catch {
|
|
324
|
+
/* noop */
|
|
325
|
+
}
|
|
326
|
+
setCopied(true);
|
|
327
|
+
window.setTimeout(() => setCopied(false), 900);
|
|
328
|
+
}}
|
|
329
|
+
onKeyDown={(e) => {
|
|
330
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
331
|
+
e.preventDefault();
|
|
332
|
+
(e.currentTarget as HTMLDivElement).click();
|
|
333
|
+
}
|
|
334
|
+
}}
|
|
335
|
+
>
|
|
336
|
+
<svg
|
|
337
|
+
viewBox="0 0 24 24"
|
|
338
|
+
fill="none"
|
|
339
|
+
stroke="currentColor"
|
|
340
|
+
strokeWidth={1.6}
|
|
341
|
+
strokeLinecap="round"
|
|
342
|
+
strokeLinejoin="round"
|
|
343
|
+
>
|
|
344
|
+
<path d={d} />
|
|
345
|
+
</svg>
|
|
346
|
+
<span style={copied ? { color: "var(--gb-success)" } : undefined}>
|
|
347
|
+
{copied ? "copied!" : name}
|
|
348
|
+
</span>
|
|
349
|
+
</div>
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function App() {
|
|
354
|
+
const [theme, setTheme] = useState<"light" | "dark">(() => {
|
|
355
|
+
if (typeof localStorage === "undefined") return "light";
|
|
356
|
+
return (
|
|
357
|
+
(localStorage.getItem("graphen-theme") as "light" | "dark") || "light"
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
const [installTab, setInstallTab] =
|
|
361
|
+
useState<keyof typeof INSTALL_CMDS>("npm");
|
|
362
|
+
const [activeId, setActiveId] = useState<string>("introduction");
|
|
363
|
+
const [installCopied, setInstallCopied] = useState(false);
|
|
364
|
+
const [dropdownValue, setDropdownValue] = useState("red");
|
|
365
|
+
|
|
366
|
+
useEffect(() => {
|
|
367
|
+
document.documentElement.setAttribute("data-theme", theme);
|
|
368
|
+
try {
|
|
369
|
+
localStorage.setItem("graphen-theme", theme);
|
|
370
|
+
} catch {
|
|
371
|
+
/* noop */
|
|
372
|
+
}
|
|
373
|
+
}, [theme]);
|
|
374
|
+
|
|
375
|
+
useEffect(() => {
|
|
376
|
+
const sections = Array.from(
|
|
377
|
+
document.querySelectorAll<HTMLElement>("section.docs-section[id]")
|
|
378
|
+
);
|
|
379
|
+
if (sections.length === 0) return undefined;
|
|
380
|
+
const io = new IntersectionObserver(
|
|
381
|
+
(entries) => {
|
|
382
|
+
const visible = entries
|
|
383
|
+
.filter((e) => e.isIntersecting)
|
|
384
|
+
.sort((a, b) => a.boundingClientRect.top - b.boundingClientRect.top);
|
|
385
|
+
if (visible[0]) setActiveId(visible[0].target.id);
|
|
386
|
+
},
|
|
387
|
+
{ rootMargin: "-72px 0px -65% 0px", threshold: 0 }
|
|
388
|
+
);
|
|
389
|
+
sections.forEach((s) => io.observe(s));
|
|
390
|
+
return () => io.disconnect();
|
|
391
|
+
}, []);
|
|
392
|
+
|
|
393
|
+
const installCmd = INSTALL_CMDS[installTab];
|
|
394
|
+
|
|
395
|
+
const colorRows = useMemo(
|
|
396
|
+
() =>
|
|
397
|
+
TOKENS.map(([hex, name, desc, varName]) => (
|
|
398
|
+
<div className="docs-token-row" key={varName}>
|
|
399
|
+
<div className="swatch" style={{ background: hex }} />
|
|
400
|
+
<div className="name">
|
|
401
|
+
{name}
|
|
402
|
+
<span className="desc">{desc}</span>
|
|
403
|
+
</div>
|
|
404
|
+
<div className="var">{varName}</div>
|
|
405
|
+
<div className="docs-row" style={{ gap: 8 }}>
|
|
406
|
+
<span className="hex-val">{hex.toUpperCase()}</span>
|
|
407
|
+
<CopyButton value={hex.toUpperCase()} />
|
|
408
|
+
</div>
|
|
356
409
|
</div>
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
410
|
+
)),
|
|
411
|
+
[]
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
return (
|
|
415
|
+
<div className="docs">
|
|
416
|
+
<header className="docs-topbar">
|
|
417
|
+
<a href="#top" className="docs-brand">
|
|
418
|
+
<HexLogoMark />
|
|
419
|
+
<span>graphen</span>
|
|
420
|
+
<span className="ver">{VERSION}</span>
|
|
421
|
+
</a>
|
|
422
|
+
<div
|
|
423
|
+
className="docs-search"
|
|
424
|
+
role="search"
|
|
425
|
+
aria-label="Search documentation"
|
|
426
|
+
>
|
|
427
|
+
<StrokeIcon size={14} stroke={2}>
|
|
428
|
+
<circle cx="11" cy="11" r="7" />
|
|
429
|
+
<path d="m20 20-3.5-3.5" />
|
|
430
|
+
</StrokeIcon>
|
|
431
|
+
<span>Search components, tokens…</span>
|
|
432
|
+
<span className="kbd">
|
|
433
|
+
<span>⌘</span>
|
|
434
|
+
<span>K</span>
|
|
435
|
+
</span>
|
|
369
436
|
</div>
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
437
|
+
<div className="docs-tools">
|
|
438
|
+
<button
|
|
439
|
+
type="button"
|
|
440
|
+
className="docs-icon-btn"
|
|
441
|
+
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
|
|
442
|
+
aria-label="Toggle theme"
|
|
443
|
+
title="Toggle theme"
|
|
444
|
+
>
|
|
445
|
+
{theme === "dark" ? (
|
|
446
|
+
<StrokeIcon stroke={1.8}>
|
|
447
|
+
<circle cx="12" cy="12" r="4" />
|
|
448
|
+
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" />
|
|
449
|
+
</StrokeIcon>
|
|
450
|
+
) : (
|
|
451
|
+
<StrokeIcon stroke={1.8}>
|
|
452
|
+
<path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z" />
|
|
453
|
+
</StrokeIcon>
|
|
454
|
+
)}
|
|
455
|
+
</button>
|
|
456
|
+
<a
|
|
457
|
+
className="docs-icon-btn"
|
|
458
|
+
href="https://github.com/coda-it/graphen"
|
|
459
|
+
aria-label="GitHub"
|
|
460
|
+
title="GitHub"
|
|
461
|
+
>
|
|
462
|
+
<svg
|
|
463
|
+
width={16}
|
|
464
|
+
height={16}
|
|
465
|
+
viewBox="0 0 24 24"
|
|
466
|
+
fill="currentColor"
|
|
467
|
+
aria-hidden="true"
|
|
468
|
+
>
|
|
469
|
+
<path d="M12 .5a11.5 11.5 0 0 0-3.64 22.41c.58.1.79-.25.79-.56v-2c-3.21.7-3.88-1.55-3.88-1.55-.52-1.33-1.28-1.69-1.28-1.69-1.05-.72.08-.7.08-.7 1.16.08 1.78 1.2 1.78 1.2 1.03 1.77 2.7 1.26 3.36.96.1-.75.4-1.26.73-1.55-2.56-.29-5.26-1.28-5.26-5.69 0-1.26.45-2.29 1.18-3.1-.12-.29-.51-1.45.11-3.02 0 0 .97-.31 3.18 1.18a11 11 0 0 1 5.78 0c2.21-1.49 3.18-1.18 3.18-1.18.62 1.57.23 2.73.11 3.02.74.81 1.18 1.84 1.18 3.1 0 4.42-2.7 5.39-5.27 5.68.41.36.78 1.07.78 2.16v3.2c0 .31.21.67.8.55A11.5 11.5 0 0 0 12 .5z" />
|
|
470
|
+
</svg>
|
|
471
|
+
</a>
|
|
375
472
|
</div>
|
|
376
|
-
</
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
<
|
|
380
|
-
|
|
381
|
-
<div className="
|
|
382
|
-
<
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
<div className="gc-input gc-input--full">
|
|
396
|
-
<label htmlFor="input-3" className="gc-input__label">
|
|
397
|
-
Full Input
|
|
398
|
-
</label>
|
|
399
|
-
<input id="input-3" className="gc-input__field" />
|
|
473
|
+
</header>
|
|
474
|
+
|
|
475
|
+
<div className="docs-app" id="top">
|
|
476
|
+
<nav className="docs-sidebar" aria-label="Documentation">
|
|
477
|
+
{NAV.map((group) => (
|
|
478
|
+
<div className="group" key={group.title}>
|
|
479
|
+
<div className="group-title">{group.title}</div>
|
|
480
|
+
{group.items.map((item) => (
|
|
481
|
+
<a
|
|
482
|
+
key={item.id}
|
|
483
|
+
href={`#${item.id}`}
|
|
484
|
+
className={activeId === item.id ? "active" : ""}
|
|
485
|
+
>
|
|
486
|
+
{item.label}
|
|
487
|
+
{"count" in item && item.count ? (
|
|
488
|
+
<span className="count">{item.count}</span>
|
|
489
|
+
) : null}
|
|
490
|
+
</a>
|
|
491
|
+
))}
|
|
400
492
|
</div>
|
|
401
|
-
|
|
402
|
-
<
|
|
403
|
-
<div className="
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
/>
|
|
493
|
+
))}
|
|
494
|
+
<div className="group">
|
|
495
|
+
<div className="group-title">Resources</div>
|
|
496
|
+
<a href="https://github.com/coda-it/graphen">Source on GitHub ↗</a>
|
|
497
|
+
</div>
|
|
498
|
+
</nav>
|
|
499
|
+
|
|
500
|
+
<main className="docs-content">
|
|
501
|
+
<section className="docs-section" id="introduction">
|
|
502
|
+
<div className="docs-eyebrow">
|
|
503
|
+
<span className="dot" /> Component library · {VERSION} · MIT
|
|
413
504
|
</div>
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
</p>
|
|
436
|
-
<p>
|
|
437
|
-
<div className="gc-led gc-led--green" />{" "}
|
|
438
|
-
<div className="gc-led gc-led--green gc-led--blink" />
|
|
439
|
-
</p>
|
|
440
|
-
<p>
|
|
441
|
-
<div className="gc-led gc-led--blue" />{" "}
|
|
442
|
-
<div className="gc-led gc-led--blue gc-led--blink" />
|
|
443
|
-
</p>
|
|
444
|
-
</div>
|
|
445
|
-
</article>
|
|
446
|
-
<article className="gc-panel gc-panel--separator">
|
|
447
|
-
<header className="gc-panel__title">Card</header>
|
|
448
|
-
<div className="gc-panel__content">
|
|
449
|
-
<div className="gc-flex gm-spacing-bl">
|
|
450
|
-
<div className="gc-flex__item gc-card gc-panel">
|
|
451
|
-
<div className="gc-panel__title">Card</div>
|
|
452
|
-
<div className="gc-panel__content">
|
|
453
|
-
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|
454
|
-
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
|
|
455
|
-
enim ad minim veniam, quis nostrud exercitation ullamco laboris
|
|
456
|
-
nisi ut aliquip ex ea commodo consequat.
|
|
457
|
-
</div>
|
|
458
|
-
<div className="gc-panel__footer">
|
|
459
|
-
<button className="gc-btn">Button</button>
|
|
460
|
-
</div>
|
|
505
|
+
<h1 className="docs-title">
|
|
506
|
+
A minimal toolkit for clean interfaces.
|
|
507
|
+
</h1>
|
|
508
|
+
<p className="docs-lede">
|
|
509
|
+
Graphen is a small, opinionated set of UI primitives — built on
|
|
510
|
+
plain CSS variables and lightweight markup. No runtime, no theming
|
|
511
|
+
engine. Drop the stylesheet, use the classes, ship.
|
|
512
|
+
</p>
|
|
513
|
+
|
|
514
|
+
<div className="docs-meta-row">
|
|
515
|
+
<span>
|
|
516
|
+
<strong>14</strong> components
|
|
517
|
+
</span>
|
|
518
|
+
<span className="sep" />
|
|
519
|
+
<span>
|
|
520
|
+
<strong>32</strong> tokens
|
|
521
|
+
</span>
|
|
522
|
+
<span className="sep" />
|
|
523
|
+
<span>Zero runtime</span>
|
|
524
|
+
<span className="sep" />
|
|
525
|
+
<span>SCSS first</span>
|
|
461
526
|
</div>
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
527
|
+
|
|
528
|
+
<div
|
|
529
|
+
className="docs-install"
|
|
530
|
+
id="installation"
|
|
531
|
+
role="group"
|
|
532
|
+
aria-label="Install Graphen"
|
|
533
|
+
>
|
|
534
|
+
<div className="tabs" role="tablist">
|
|
535
|
+
{(
|
|
536
|
+
Object.keys(INSTALL_CMDS) as Array<keyof typeof INSTALL_CMDS>
|
|
537
|
+
).map((k) => (
|
|
538
|
+
<button
|
|
539
|
+
key={k}
|
|
540
|
+
type="button"
|
|
541
|
+
role="tab"
|
|
542
|
+
className="tab"
|
|
543
|
+
aria-selected={installTab === k}
|
|
544
|
+
onClick={() => setInstallTab(k)}
|
|
545
|
+
>
|
|
546
|
+
{k}
|
|
547
|
+
</button>
|
|
548
|
+
))}
|
|
469
549
|
</div>
|
|
470
|
-
<div className="
|
|
471
|
-
<
|
|
472
|
-
|
|
550
|
+
<div className="cmd">
|
|
551
|
+
<span className="prompt">$</span>
|
|
552
|
+
<span>{installCmd}</span>
|
|
553
|
+
<button
|
|
554
|
+
type="button"
|
|
555
|
+
aria-label="Copy install command"
|
|
556
|
+
title="Copy"
|
|
557
|
+
onClick={async () => {
|
|
558
|
+
try {
|
|
559
|
+
await navigator.clipboard.writeText(installCmd);
|
|
560
|
+
} catch {
|
|
561
|
+
/* noop */
|
|
562
|
+
}
|
|
563
|
+
setInstallCopied(true);
|
|
564
|
+
window.setTimeout(() => setInstallCopied(false), 900);
|
|
565
|
+
}}
|
|
566
|
+
style={
|
|
567
|
+
installCopied ? { color: "var(--gb-success)" } : undefined
|
|
568
|
+
}
|
|
569
|
+
>
|
|
570
|
+
<StrokeIcon size={14}>
|
|
571
|
+
<rect x="9" y="9" width="11" height="11" rx="2" />
|
|
572
|
+
<path d="M5 15V5a2 2 0 0 1 2-2h10" />
|
|
573
|
+
</StrokeIcon>
|
|
473
574
|
</button>
|
|
474
575
|
</div>
|
|
475
576
|
</div>
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
<
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
</
|
|
482
|
-
<
|
|
483
|
-
|
|
484
|
-
<
|
|
485
|
-
|
|
486
|
-
|
|
577
|
+
|
|
578
|
+
<div className="docs-comp-index" aria-label="Component index">
|
|
579
|
+
<a href="#colors">
|
|
580
|
+
<span className="nm">Colors</span>
|
|
581
|
+
<span className="st">8 tokens</span>
|
|
582
|
+
</a>
|
|
583
|
+
<a href="#typography">
|
|
584
|
+
<span className="nm">Typography</span>
|
|
585
|
+
<span className="st">5 sizes</span>
|
|
586
|
+
</a>
|
|
587
|
+
<a href="#button">
|
|
588
|
+
<span className="nm">Button</span>
|
|
589
|
+
<span className="st">5 variants</span>
|
|
590
|
+
</a>
|
|
591
|
+
<a href="#input">
|
|
592
|
+
<span className="nm">Input</span>
|
|
593
|
+
<span className="st">stable</span>
|
|
594
|
+
</a>
|
|
595
|
+
</div>
|
|
596
|
+
</section>
|
|
597
|
+
|
|
598
|
+
<section className="docs-section" id="colors">
|
|
599
|
+
<div className="docs-section-eyebrow">Foundations / 01</div>
|
|
600
|
+
<h2 className="docs-section-title">Colors</h2>
|
|
601
|
+
<p className="docs-section-desc">
|
|
602
|
+
Brand tokens are exposed as Sass variables and matching CSS custom
|
|
603
|
+
properties. Click any value to copy. Component tokens (
|
|
604
|
+
<code>$gb-color-component</code>) are the only colors used as
|
|
605
|
+
backgrounds for surfaces — everything else is reserved for accent
|
|
606
|
+
or status.
|
|
607
|
+
</p>
|
|
608
|
+
<div className="docs-tokens" role="table" aria-label="Color tokens">
|
|
609
|
+
{colorRows}
|
|
610
|
+
</div>
|
|
611
|
+
</section>
|
|
612
|
+
|
|
613
|
+
<section className="docs-section" id="typography">
|
|
614
|
+
<div className="docs-section-eyebrow">Foundations / 02</div>
|
|
615
|
+
<h2 className="docs-section-title">Typography</h2>
|
|
616
|
+
<p className="docs-section-desc">
|
|
617
|
+
Graphen uses the system font stack by default, with a single
|
|
618
|
+
optical scale of five steps. Numerics are tabular for tables;{" "}
|
|
619
|
+
<code>code</code> uses the monospace stack.
|
|
620
|
+
</p>
|
|
621
|
+
{TYPE_SCALE.map((row) => (
|
|
622
|
+
<div className="docs-type-row" key={row.token}>
|
|
623
|
+
<div className="meta">{row.meta}</div>
|
|
624
|
+
<div className="meta">{row.token}</div>
|
|
625
|
+
<div className="sample" style={row.style}>
|
|
626
|
+
{row.sample}
|
|
627
|
+
</div>
|
|
487
628
|
</div>
|
|
629
|
+
))}
|
|
630
|
+
</section>
|
|
631
|
+
|
|
632
|
+
<section className="docs-section" id="spacing">
|
|
633
|
+
<div className="docs-section-eyebrow">Foundations / 03</div>
|
|
634
|
+
<h2 className="docs-section-title">Spacing & radius</h2>
|
|
635
|
+
<p className="docs-section-desc">
|
|
636
|
+
A four-pixel base scale. Use the smallest token that still reads
|
|
637
|
+
as deliberate; double up rather than introduce new sizes.
|
|
638
|
+
</p>
|
|
639
|
+
<div className="docs-space-grid">
|
|
640
|
+
{SPACING.map(([token, px, rem, w]) => (
|
|
641
|
+
<div className="docs-space-row" key={token}>
|
|
642
|
+
<span className="token">{token}</span>
|
|
643
|
+
<span className="px">{px}</span>
|
|
644
|
+
<span className="px">{rem}</span>
|
|
645
|
+
<div className="vis" style={{ width: w }} />
|
|
646
|
+
</div>
|
|
647
|
+
))}
|
|
488
648
|
</div>
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
<
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
<article className="gc-panel gc-panel--separator">
|
|
510
|
-
<header className="gc-panel__title">Loader</header>
|
|
511
|
-
<div className="gc-panel__content">
|
|
512
|
-
<Loader />
|
|
513
|
-
</div>
|
|
514
|
-
</article>
|
|
515
|
-
<article className="gc-panel gc-panel--separator">
|
|
516
|
-
<header className="gc-panel__title">Scroller</header>
|
|
517
|
-
<div className="gc-panel__content">
|
|
518
|
-
<Scroller onScrollChange={_.noop} min={10} max={100} />
|
|
519
|
-
</div>
|
|
520
|
-
</article>
|
|
521
|
-
<article className="gc-panel gc-panel--separator">
|
|
522
|
-
<header className="gc-panel__title">Joystick</header>
|
|
523
|
-
<div className="gc-panel__content">
|
|
524
|
-
<Joystick onPositionChange={_.noop} isEnabled />
|
|
525
|
-
</div>
|
|
526
|
-
</article>
|
|
527
|
-
<article className="gc-panel gc-panel--separator">
|
|
528
|
-
<header className="gc-panel__title">Accordion</header>
|
|
529
|
-
<div className="gc-panel__content">
|
|
530
|
-
<Accordion title="Accordion title">
|
|
531
|
-
<p>
|
|
532
|
-
Some content <span>here</span>
|
|
649
|
+
<div className="docs-spacer-y" />
|
|
650
|
+
<h3 className="docs-subsection-title">Radius</h3>
|
|
651
|
+
<div className="docs-space-grid">
|
|
652
|
+
{RADIUS.map(([token, px, r]) => (
|
|
653
|
+
<div className="docs-space-row" key={token}>
|
|
654
|
+
<span className="token">{token}</span>
|
|
655
|
+
<span className="px">{px}</span>
|
|
656
|
+
<span className="px" />
|
|
657
|
+
<div className="swatch-radius" style={{ borderRadius: r }} />
|
|
658
|
+
</div>
|
|
659
|
+
))}
|
|
660
|
+
</div>
|
|
661
|
+
</section>
|
|
662
|
+
|
|
663
|
+
<section className="docs-section" id="iconography">
|
|
664
|
+
<div className="docs-section-eyebrow">Foundations / 04</div>
|
|
665
|
+
<h2 className="docs-section-title">Iconography</h2>
|
|
666
|
+
<p className="docs-section-desc">
|
|
667
|
+
Stroke-based, 24 × 24 viewBox, 1.6 px stroke. Inherit color from
|
|
668
|
+
the parent. Click an icon to copy its name.
|
|
533
669
|
</p>
|
|
534
|
-
<
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
<
|
|
542
|
-
<
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
670
|
+
<div className="docs-icon-grid">
|
|
671
|
+
{ICONS.map(([name, d]) => (
|
|
672
|
+
<IconCell key={name} name={name} d={d} />
|
|
673
|
+
))}
|
|
674
|
+
</div>
|
|
675
|
+
</section>
|
|
676
|
+
|
|
677
|
+
<section className="docs-section" id="logo">
|
|
678
|
+
<div className="docs-section-eyebrow">Components / 01</div>
|
|
679
|
+
<h2 className="docs-section-title">Logo</h2>
|
|
680
|
+
<p className="docs-section-desc">
|
|
681
|
+
A monospace wordmark with a single blinking-cursor accent. The
|
|
682
|
+
cursor blink is a CSS animation; pause it via{" "}
|
|
683
|
+
<code>prefers-reduced-motion</code>.
|
|
684
|
+
</p>
|
|
685
|
+
<Demo stageClass="center" code="<Logo />">
|
|
686
|
+
<Logo />
|
|
687
|
+
</Demo>
|
|
688
|
+
</section>
|
|
689
|
+
|
|
690
|
+
<section className="docs-section" id="button">
|
|
691
|
+
<div className="docs-section-eyebrow">Components / 02</div>
|
|
692
|
+
<h2 className="docs-section-title">Button</h2>
|
|
693
|
+
<p className="docs-section-desc">
|
|
694
|
+
Five visual variants and a small size. Buttons are{" "}
|
|
695
|
+
<code><button></code> elements; never wrap them in anchors.
|
|
696
|
+
</p>
|
|
697
|
+
|
|
698
|
+
<h3 className="docs-subsection-title">Variants</h3>
|
|
699
|
+
<Demo
|
|
700
|
+
code={`<Button className="gc-btn--primary">Primary</Button>
|
|
701
|
+
<Button>Default</Button>
|
|
702
|
+
<Button className="gc-btn--outline">Outline</Button>
|
|
703
|
+
<Button className="gc-btn--ghost">Ghost</Button>
|
|
704
|
+
<Button className="gc-btn--success">Success</Button>
|
|
705
|
+
<Button className="gc-btn--danger">Danger</Button>
|
|
706
|
+
<Button className="gc-btn--primary" isDisabled>Disabled</Button>`}
|
|
707
|
+
>
|
|
708
|
+
<Button className="gc-btn--primary">Primary</Button>
|
|
709
|
+
<Button>Default</Button>
|
|
710
|
+
<Button className="gc-btn--outline">Outline</Button>
|
|
711
|
+
<Button className="gc-btn--ghost">Ghost</Button>
|
|
712
|
+
<Button className="gc-btn--success">Success</Button>
|
|
713
|
+
<Button className="gc-btn--danger">Danger</Button>
|
|
714
|
+
<Button className="gc-btn--primary" isDisabled>
|
|
715
|
+
Disabled
|
|
556
716
|
</Button>
|
|
557
|
-
</
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
<
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
717
|
+
</Demo>
|
|
718
|
+
|
|
719
|
+
<h3 className="docs-subsection-title">Sizes</h3>
|
|
720
|
+
<Demo
|
|
721
|
+
code={`<Button className="gc-btn--small gc-btn--primary">Small</Button>
|
|
722
|
+
<Button className="gc-btn--primary">Default</Button>
|
|
723
|
+
<Button className="gc-btn--large gc-btn--primary">Large</Button>`}
|
|
724
|
+
>
|
|
725
|
+
<Button className="gc-btn--small gc-btn--primary">Small</Button>
|
|
726
|
+
<Button className="gc-btn--primary">Default</Button>
|
|
727
|
+
<Button className="gc-btn--large gc-btn--primary">Large</Button>
|
|
728
|
+
</Demo>
|
|
729
|
+
</section>
|
|
730
|
+
|
|
731
|
+
<section className="docs-section" id="link">
|
|
732
|
+
<div className="docs-section-eyebrow">Components / 03</div>
|
|
733
|
+
<h2 className="docs-section-title">Link</h2>
|
|
734
|
+
<p className="docs-section-desc">
|
|
735
|
+
Two flavors: <em>primary</em> (brand-colored, for navigation and
|
|
736
|
+
calls to action) and <em>default</em> (inherits text color, for
|
|
737
|
+
inline references).
|
|
738
|
+
</p>
|
|
739
|
+
<Demo
|
|
740
|
+
stageClass="column"
|
|
741
|
+
code={`<Link link="#">Primary link</Link>
|
|
742
|
+
<Link link="#" skin={constants.SKIN_DEFAULT}>Default link</Link>`}
|
|
743
|
+
>
|
|
744
|
+
<p style={{ margin: 0, maxWidth: "60ch" }}>
|
|
745
|
+
For more on the system, see{" "}
|
|
746
|
+
<Link link="#">the design principles</Link>, or read our{" "}
|
|
747
|
+
<Link link="#" skin={constants.SKIN_DEFAULT}>
|
|
748
|
+
release notes
|
|
749
|
+
</Link>{" "}
|
|
750
|
+
from last quarter.
|
|
751
|
+
</p>
|
|
752
|
+
</Demo>
|
|
753
|
+
</section>
|
|
754
|
+
|
|
755
|
+
<section className="docs-section" id="header-comp">
|
|
756
|
+
<div className="docs-section-eyebrow">Components / 04</div>
|
|
757
|
+
<h2 className="docs-section-title">Header</h2>
|
|
758
|
+
<p className="docs-section-desc">
|
|
759
|
+
A small section header pattern — icon, title, optional metadata.
|
|
760
|
+
Used to introduce dashboards, lists and panels.
|
|
761
|
+
</p>
|
|
762
|
+
<Demo
|
|
763
|
+
stageClass="column"
|
|
764
|
+
code={`<header className="gc-section-header">
|
|
765
|
+
<span className="gc-section-header__icon">…</span>
|
|
766
|
+
<span className="gc-section-header__title">Component overview</span>
|
|
767
|
+
<span className="gc-section-header__sub">14 items</span>
|
|
768
|
+
</header>`}
|
|
769
|
+
>
|
|
770
|
+
<header className="gc-section-header">
|
|
771
|
+
<span className="gc-section-header__icon">
|
|
772
|
+
<StrokeIcon stroke={1.8}>
|
|
773
|
+
<polygon points="12,3 21,7.5 21,16.5 12,21 3,16.5 3,7.5" />
|
|
774
|
+
</StrokeIcon>
|
|
775
|
+
</span>
|
|
776
|
+
<span className="gc-section-header__title">
|
|
777
|
+
Component overview
|
|
778
|
+
</span>
|
|
779
|
+
<span className="gc-section-header__sub">14 items</span>
|
|
780
|
+
</header>
|
|
781
|
+
<header className="gc-section-header gc-section-header--success">
|
|
782
|
+
<span className="gc-section-header__icon">
|
|
783
|
+
<StrokeIcon size={14} stroke={2.2}>
|
|
784
|
+
<path d="m5 12 5 5 9-11" />
|
|
785
|
+
</StrokeIcon>
|
|
786
|
+
</span>
|
|
787
|
+
<span className="gc-section-header__title">Build passing</span>
|
|
788
|
+
<span className="gc-section-header__sub">2 min ago</span>
|
|
789
|
+
</header>
|
|
790
|
+
</Demo>
|
|
791
|
+
</section>
|
|
792
|
+
|
|
793
|
+
<section className="docs-section" id="separator">
|
|
794
|
+
<div className="docs-section-eyebrow">Components / 05</div>
|
|
795
|
+
<h2 className="docs-section-title">Separator</h2>
|
|
796
|
+
<p className="docs-section-desc">
|
|
797
|
+
Horizontal dividers. Prefer over borders on parent containers when
|
|
798
|
+
content needs to feel grouped, not boxed.
|
|
799
|
+
</p>
|
|
800
|
+
<Demo stageClass="column" code="<Separator />">
|
|
801
|
+
<div style={{ width: "100%", maxWidth: 480 }}>
|
|
802
|
+
<div style={{ fontSize: 13.5, padding: "6px 0" }}>
|
|
803
|
+
Section A
|
|
804
|
+
</div>
|
|
805
|
+
<Separator />
|
|
806
|
+
<div style={{ fontSize: 13.5, padding: "6px 0" }}>
|
|
807
|
+
Section B
|
|
808
|
+
</div>
|
|
809
|
+
<Separator />
|
|
810
|
+
<div style={{ fontSize: 13.5, padding: "6px 0" }}>
|
|
811
|
+
Section C
|
|
812
|
+
</div>
|
|
813
|
+
</div>
|
|
814
|
+
</Demo>
|
|
815
|
+
</section>
|
|
816
|
+
|
|
817
|
+
<section className="docs-section" id="input">
|
|
818
|
+
<div className="docs-section-eyebrow">Components / 06</div>
|
|
819
|
+
<h2 className="docs-section-title">Input</h2>
|
|
820
|
+
<p className="docs-section-desc">
|
|
821
|
+
Single-line text input with focus ring keyed to the brand color.
|
|
822
|
+
Try typing — focus state is real.
|
|
823
|
+
</p>
|
|
824
|
+
<Demo
|
|
825
|
+
stageClass="column"
|
|
826
|
+
code={`<Input label="Search" type="text" />
|
|
827
|
+
<Input label="Email" type="email" validation="success" />`}
|
|
828
|
+
>
|
|
829
|
+
<Input label="Search" type="text" />
|
|
830
|
+
<Input label="Email" type="email" validation="success" />
|
|
831
|
+
</Demo>
|
|
832
|
+
</section>
|
|
833
|
+
|
|
834
|
+
<section className="docs-section" id="dropdown">
|
|
835
|
+
<div className="docs-section-eyebrow">Components / 07</div>
|
|
836
|
+
<h2 className="docs-section-title">Dropdown</h2>
|
|
837
|
+
<p className="docs-section-desc">
|
|
838
|
+
A compact selector for short option lists. Keep labels clear and
|
|
839
|
+
avoid using it when users need to compare many values at once.
|
|
840
|
+
</p>
|
|
841
|
+
<Demo
|
|
842
|
+
code={`<Dropdown
|
|
843
|
+
label="Theme accent"
|
|
844
|
+
initValue={{ value: "${dropdownValue}", label: "${
|
|
845
|
+
DROPDOWN_ITEMS.find((item) => item.value === dropdownValue)
|
|
846
|
+
?.label
|
|
847
|
+
}" }}
|
|
848
|
+
items={[
|
|
849
|
+
{ value: "red", label: "Red" },
|
|
850
|
+
{ value: "blue", label: "Blue" },
|
|
851
|
+
{ value: "green", label: "Green" },
|
|
852
|
+
]}
|
|
853
|
+
onChange={setDropdownValue}
|
|
854
|
+
/>`}
|
|
855
|
+
>
|
|
856
|
+
<Dropdown
|
|
857
|
+
label="Theme accent"
|
|
858
|
+
initValue={
|
|
859
|
+
DROPDOWN_ITEMS.find((item) => item.value === dropdownValue) ||
|
|
860
|
+
DROPDOWN_ITEMS[0]
|
|
861
|
+
}
|
|
862
|
+
items={DROPDOWN_ITEMS}
|
|
863
|
+
onChange={setDropdownValue}
|
|
864
|
+
/>
|
|
865
|
+
</Demo>
|
|
866
|
+
</section>
|
|
867
|
+
|
|
868
|
+
<section className="docs-section" id="card">
|
|
869
|
+
<div className="docs-section-eyebrow">Components / 08</div>
|
|
870
|
+
<h2 className="docs-section-title">Card</h2>
|
|
871
|
+
<p className="docs-section-desc">
|
|
872
|
+
A single-content surface. Don't nest cards. If a card has
|
|
873
|
+
more than one CTA, you probably want a list.
|
|
874
|
+
</p>
|
|
875
|
+
<Demo
|
|
876
|
+
code={`<Card>
|
|
877
|
+
<div className="docs-card-eyebrow">Release</div>
|
|
878
|
+
<h4>Graphen 1.0 is here</h4>
|
|
879
|
+
<p>A small, opinionated set …</p>
|
|
880
|
+
<Button className="gc-btn--small gc-btn--primary">Read announcement</Button>
|
|
881
|
+
</Card>`}
|
|
882
|
+
>
|
|
883
|
+
<Card>
|
|
884
|
+
<div className="docs-card-eyebrow">Release</div>
|
|
885
|
+
<h4 className="docs-card-title">Graphen 1.0 is here</h4>
|
|
886
|
+
<p className="docs-card-text">
|
|
887
|
+
A small, opinionated set of UI primitives — finally stable.
|
|
888
|
+
</p>
|
|
889
|
+
<Button className="gc-btn--small gc-btn--primary">
|
|
890
|
+
Read announcement
|
|
891
|
+
</Button>
|
|
892
|
+
</Card>
|
|
893
|
+
<Card>
|
|
894
|
+
<div className="docs-card-eyebrow">Tutorial</div>
|
|
895
|
+
<h4 className="docs-card-title">Theming with CSS variables</h4>
|
|
896
|
+
<p className="docs-card-text">
|
|
897
|
+
Override <code>--gb-primary</code> on <code>:root</code> to
|
|
898
|
+
retheme everything in one line.
|
|
899
|
+
</p>
|
|
900
|
+
<Button className="gc-btn--small gc-btn--secondary">
|
|
901
|
+
Open guide
|
|
902
|
+
</Button>
|
|
903
|
+
</Card>
|
|
904
|
+
</Demo>
|
|
905
|
+
</section>
|
|
906
|
+
|
|
907
|
+
<section className="docs-section" id="badge">
|
|
908
|
+
<div className="docs-section-eyebrow">Components / 09</div>
|
|
909
|
+
<h2 className="docs-section-title">Badge</h2>
|
|
910
|
+
<p className="docs-section-desc">
|
|
911
|
+
Small status pills. Use sparingly — one badge per row, never
|
|
912
|
+
decorative.
|
|
913
|
+
</p>
|
|
914
|
+
<Demo
|
|
915
|
+
code={`<Badge showPulse>idle</Badge>
|
|
916
|
+
<Badge type="info" showPulse>info</Badge>
|
|
917
|
+
<Badge type="success" showPulse>success</Badge>
|
|
918
|
+
<Badge type="danger" showPulse>danger</Badge>`}
|
|
919
|
+
>
|
|
920
|
+
<Badge showPulse>idle</Badge>
|
|
921
|
+
<Badge type="info" showPulse>
|
|
922
|
+
info
|
|
923
|
+
</Badge>
|
|
924
|
+
<Badge type="success" showPulse>
|
|
925
|
+
success
|
|
926
|
+
</Badge>
|
|
927
|
+
<Badge type="danger" showPulse>
|
|
928
|
+
danger
|
|
929
|
+
</Badge>
|
|
930
|
+
</Demo>
|
|
931
|
+
</section>
|
|
932
|
+
|
|
933
|
+
<footer className="docs-footer">
|
|
934
|
+
<div>graphen · {VERSION} · MIT</div>
|
|
935
|
+
<div>Built by the CODA_ team</div>
|
|
936
|
+
</footer>
|
|
937
|
+
</main>
|
|
938
|
+
|
|
939
|
+
<aside className="docs-toc" aria-label="On this page">
|
|
940
|
+
<div className="toc-title">On this page</div>
|
|
941
|
+
{TOC.map(([id, label]) => (
|
|
942
|
+
<a
|
|
943
|
+
key={id}
|
|
944
|
+
href={`#${id}`}
|
|
945
|
+
className={activeId === id ? "active" : ""}
|
|
946
|
+
>
|
|
947
|
+
{label}
|
|
948
|
+
</a>
|
|
949
|
+
))}
|
|
950
|
+
</aside>
|
|
951
|
+
</div>
|
|
952
|
+
</div>
|
|
652
953
|
);
|
|
653
954
|
}
|
|
654
955
|
|
|
956
|
+
const appContainer = document.querySelector(".js-example");
|
|
655
957
|
if (appContainer) {
|
|
656
|
-
render(
|
|
657
|
-
<section className="gc-page">
|
|
658
|
-
<ExampleApp />
|
|
659
|
-
</section>,
|
|
660
|
-
appContainer
|
|
661
|
-
);
|
|
958
|
+
render(<App />, appContainer);
|
|
662
959
|
}
|
|
663
|
-
/* eslint-enable */
|