@wtfalch/design 0.1.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 +147 -0
- package/dist/components/Brand.d.ts +10 -0
- package/dist/components/Brand.js +212 -0
- package/dist/components/Button.d.ts +63 -0
- package/dist/components/Button.js +74 -0
- package/dist/components/Callout.d.ts +37 -0
- package/dist/components/Callout.js +71 -0
- package/dist/components/Card.d.ts +42 -0
- package/dist/components/Card.js +30 -0
- package/dist/components/Checkbox.d.ts +32 -0
- package/dist/components/Checkbox.js +31 -0
- package/dist/components/DangerZone.d.ts +59 -0
- package/dist/components/DangerZone.js +50 -0
- package/dist/components/Dialog.d.ts +28 -0
- package/dist/components/Dialog.js +29 -0
- package/dist/components/Empty.d.ts +45 -0
- package/dist/components/Empty.js +35 -0
- package/dist/components/Field.d.ts +58 -0
- package/dist/components/Field.js +46 -0
- package/dist/components/Icon.d.ts +64 -0
- package/dist/components/Icon.js +235 -0
- package/dist/components/Illustration.d.ts +36 -0
- package/dist/components/Illustration.js +48 -0
- package/dist/components/Input.d.ts +14 -0
- package/dist/components/Input.js +65 -0
- package/dist/components/Markdown.d.ts +21 -0
- package/dist/components/Markdown.js +29 -0
- package/dist/components/Modal.d.ts +59 -0
- package/dist/components/Modal.js +72 -0
- package/dist/components/Pill.d.ts +40 -0
- package/dist/components/Pill.js +41 -0
- package/dist/components/Progress.d.ts +35 -0
- package/dist/components/Progress.js +27 -0
- package/dist/components/Rows.d.ts +101 -0
- package/dist/components/Rows.js +55 -0
- package/dist/components/Select.d.ts +28 -0
- package/dist/components/Select.js +56 -0
- package/dist/components/SizeGrid.d.ts +34 -0
- package/dist/components/SizeGrid.js +41 -0
- package/dist/components/Skeleton.d.ts +45 -0
- package/dist/components/Skeleton.js +47 -0
- package/dist/components/Slider.d.ts +70 -0
- package/dist/components/Slider.js +100 -0
- package/dist/components/Table.d.ts +43 -0
- package/dist/components/Table.js +13 -0
- package/dist/components/Tabs.d.ts +72 -0
- package/dist/components/Tabs.js +82 -0
- package/dist/components/Textarea.d.ts +9 -0
- package/dist/components/Textarea.js +22 -0
- package/dist/components/Toast.d.ts +43 -0
- package/dist/components/Toast.js +78 -0
- package/dist/components/Toggle.d.ts +56 -0
- package/dist/components/Toggle.js +189 -0
- package/dist/components/Tooltip.d.ts +22 -0
- package/dist/components/Tooltip.js +62 -0
- package/dist/components/Tour.d.ts +33 -0
- package/dist/components/Tour.js +108 -0
- package/dist/components/iconNames.d.ts +18 -0
- package/dist/components/iconNames.js +60 -0
- package/dist/components/tourMarker.d.ts +29 -0
- package/dist/components/tourMarker.js +58 -0
- package/dist/contrast.d.ts +18 -0
- package/dist/contrast.js +27 -0
- package/dist/hooks/useTrapFocus.d.ts +24 -0
- package/dist/hooks/useTrapFocus.js +67 -0
- package/dist/illustrations.d.ts +11 -0
- package/dist/illustrations.js +55 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +65 -0
- package/dist/styles/index.css +3124 -0
- package/dist/themes.d.ts +210 -0
- package/dist/themes.js +300 -0
- package/dist/tokens.css +251 -0
- package/package.json +74 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const GLYPHS = {
|
|
3
|
+
chat: {
|
|
4
|
+
view: '-0.9 -0.9 21.79 21.79',
|
|
5
|
+
d: [
|
|
6
|
+
'M1.5 12.102a2.5 2.5 0 0 0 2.5 2.5h.249c.307 1.238.741 1.898 1.455 1.898c.603 0 1.519-.62 2.94-1.898H16a2.5 2.5 0 0 0 2.5-2.5V6A2.5 2.5 0 0 0 16 3.5H4A2.5 2.5 0 0 0 1.5 6zm1 0V6A1.5 1.5 0 0 1 4 4.5h12A1.5 1.5 0 0 1 17.5 6v6.102a1.5 1.5 0 0 1-1.5 1.5H8.257l-.143.13C6.834 14.898 5.96 15.5 5.704 15.5c-.092 0-.35-.463-.567-1.5l-.083-.398H4a1.5 1.5 0 0 1-1.5-1.5',
|
|
7
|
+
],
|
|
8
|
+
dots: [
|
|
9
|
+
[7, 9, 1],
|
|
10
|
+
[10, 9, 1],
|
|
11
|
+
[13, 9, 1],
|
|
12
|
+
],
|
|
13
|
+
},
|
|
14
|
+
settings: {
|
|
15
|
+
view: '0.06 0.06 19.87 19.87',
|
|
16
|
+
d: [
|
|
17
|
+
'M8.232 11.768A2.5 2.5 0 0 0 10 12.5c.672 0 1.302-.267 1.768-.732A2.5 2.5 0 0 0 12.5 10c0-.672-.267-1.302-.732-1.768A2.5 2.5 0 0 0 10 7.5c-.672 0-1.302.267-1.768.732A2.5 2.5 0 0 0 7.5 10c0 .672.267 1.302.732 1.768m2.829-.707c-.28.28-.657.439-1.061.439s-.78-.16-1.06-.44s-.44-.656-.44-1.06s.16-.78.44-1.06s.656-.44 1.06-.44s.78.16 1.06.44s.44.656.44 1.06s-.16.78-.44 1.06',
|
|
18
|
+
'm14.216 3.773l-1.27.714a6.2 6.2 0 0 0-1.166-.48l-.47-1.414a.5.5 0 0 0-.474-.343H9.06a.5.5 0 0 0-.481.365l-.392 1.403a6.2 6.2 0 0 0-1.164.486L5.69 3.835a.5.5 0 0 0-.578.094L3.855 5.185a.5.5 0 0 0-.082.599l.714 1.27q-.3.556-.48 1.166l-1.414.47a.5.5 0 0 0-.343.474v1.777a.5.5 0 0 0 .365.481l1.403.392q.184.608.486 1.164l-.669 1.333a.5.5 0 0 0 .094.578l1.256 1.256a.5.5 0 0 0 .599.082l1.27-.714q.556.3 1.166.48l.47 1.414a.5.5 0 0 0 .474.343h1.777a.5.5 0 0 0 .481-.365l.392-1.403a6.2 6.2 0 0 0 1.164-.486l1.333.669a.5.5 0 0 0 .578-.093l1.256-1.257a.5.5 0 0 0 .082-.599l-.714-1.27q.3-.556.48-1.166l1.414-.47a.5.5 0 0 0 .343-.474V9.06a.5.5 0 0 0-.365-.481l-1.403-.392a6.2 6.2 0 0 0-.486-1.164l.669-1.333a.5.5 0 0 0-.093-.578l-1.257-1.256a.5.5 0 0 0-.599-.082m-1.024 1.724l1.184-.667l.733.733l-.627 1.25a.5.5 0 0 0 .019.482c.265.44.464.918.59 1.418a.5.5 0 0 0 .35.36l1.309.366v1.037l-1.327.44a.5.5 0 0 0-.328.354a5.2 5.2 0 0 1-.585 1.42a.5.5 0 0 0-.007.502l.667 1.184l-.733.733l-1.25-.627a.5.5 0 0 0-.482.019c-.44.265-.918.464-1.418.59a.5.5 0 0 0-.36.35l-.366 1.309H9.525l-.44-1.327a.5.5 0 0 0-.355-.328a5.2 5.2 0 0 1-1.42-.585a.5.5 0 0 0-.502-.007l-1.184.667l-.733-.733l.627-1.25a.5.5 0 0 0-.019-.482a5.2 5.2 0 0 1-.59-1.418a.5.5 0 0 0-.35-.36l-1.309-.366V9.525l1.327-.44a.5.5 0 0 0 .327-.355c.125-.5.323-.979.586-1.42a.5.5 0 0 0 .007-.502L4.83 5.624l.733-.733l1.25.627a.5.5 0 0 0 .482-.019c.44-.265.918-.464 1.418-.59a.5.5 0 0 0 .36-.35l.366-1.309h1.037l.44 1.327a.5.5 0 0 0 .354.327c.5.125.979.323 1.42.586a.5.5 0 0 0 .502.007',
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
refresh: {
|
|
22
|
+
view: '-1.16 -1.07 21.93 21.93',
|
|
23
|
+
d: [
|
|
24
|
+
'M5.254 14.596a.5.5 0 0 1 .707-.707A5.5 5.5 0 0 0 15.35 10a.5.5 0 0 1 .999.001a6.5 6.5 0 0 1-11.096 4.596',
|
|
25
|
+
'M13.131 12.416a.5.5 0 0 1-.555-.832l3-2a.5.5 0 1 1 .555.832z',
|
|
26
|
+
'M18.266 12.723a.5.5 0 1 1-.832.554l-2-3a.5.5 0 0 1 .832-.554zm-3.912-7.518a.5.5 0 0 1-.708.707a5.5 5.5 0 0 0-9.389 3.89a.5.5 0 0 1-1-.001a6.5 6.5 0 0 1 11.097-4.596',
|
|
27
|
+
'M6.476 7.385a.5.5 0 0 1 .555.832l-3 2a.5.5 0 1 1-.555-.832z',
|
|
28
|
+
'M1.341 7.078a.5.5 0 1 1 .832-.554l2 3a.5.5 0 0 1-.832.554z',
|
|
29
|
+
],
|
|
30
|
+
},
|
|
31
|
+
minimize: { view: '0 0 20 20', d: ['M5 10.5a.5.5 0 0 1 0-1h10a.5.5 0 0 1 0 1z'] },
|
|
32
|
+
code: {
|
|
33
|
+
view: '-0.47 -0.48 20.94 20.94',
|
|
34
|
+
d: [
|
|
35
|
+
'M1.962 9.666a.5.5 0 0 1 .706-.038l3.333 3a.5.5 0 1 1-.669.744l-3.333-3a.5.5 0 0 1-.037-.706',
|
|
36
|
+
'M6.038 6.666a.5.5 0 0 1-.037.706l-3.333 3a.5.5 0 0 1-.67-.744l3.334-3a.5.5 0 0 1 .706.038m12 3a.5.5 0 0 1-.037.706l-3.333 3a.5.5 0 0 1-.67-.744l3.334-3a.5.5 0 0 1 .706.038',
|
|
37
|
+
'M13.962 6.666a.5.5 0 0 1 .706-.038l3.333 3a.5.5 0 0 1-.669.744l-3.333-3a.5.5 0 0 1-.037-.706m-2.33-2.648a.5.5 0 0 1 .35.614l-3 11a.5.5 0 0 1-.964-.264l3-11a.5.5 0 0 1 .614-.35',
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
wifi: {
|
|
41
|
+
view: '-0.26 -0.06 20.51 20.51',
|
|
42
|
+
d: [
|
|
43
|
+
'M13.348 11.641a.5.5 0 0 1-.696.718a2 2 0 0 0-.136-.12a3 3 0 0 0-.753-.424A4.8 4.8 0 0 0 10 11.5c-1.022 0-1.951.285-2.516.739q-.073.06-.136.12a.5.5 0 0 1-.696-.718q.097-.094.206-.182c.754-.606 1.905-.959 3.142-.959c.765 0 1.5.134 2.132.385c.385.153.726.346 1.01.574q.109.089.206.182m2.508-2.601a.5.5 0 1 1-.712.7a5 5 0 0 0-.35-.32a5 5 0 0 0-.399-.298a6.6 6.6 0 0 0-1.449-.731a8 8 0 0 0-1.126-.319a9 9 0 0 0-1.205-.162a9.3 9.3 0 0 0-1.839.061a9 9 0 0 0-1.172.242a8 8 0 0 0-1.071.39a6.6 6.6 0 0 0-.928.519q-.21.143-.399.298q-.186.155-.35.32a.5.5 0 0 1-.712-.7q.198-.202.424-.39q.225-.186.474-.355a7 7 0 0 1 1.076-.602a8 8 0 0 1 1.215-.443a9 9 0 0 1 1.31-.27A10 10 0 0 1 10 6.89a10 10 0 0 1 1.357.09a10 10 0 0 1 1.31.27a9 9 0 0 1 1.215.443a7.6 7.6 0 0 1 1.076.602q.249.17.474.355q.226.188.424.39',
|
|
44
|
+
'M17.873 6.555a.5.5 0 1 1-.746.667a7 7 0 0 0-.492-.496a8 8 0 0 0-.557-.46a9 9 0 0 0-1.29-.794a9.5 9.5 0 0 0-1.484-.594a10.6 10.6 0 0 0-1.617-.366A11.4 11.4 0 0 0 10 4.389a12 12 0 0 0-1.687.123a11 11 0 0 0-1.617.366a10 10 0 0 0-1.483.595a9 9 0 0 0-.673.374a8 8 0 0 0-.618.42q-.294.22-.557.46q-.263.239-.492.495a.5.5 0 1 1-.746-.667q.264-.294.564-.568t.632-.521q.332-.249.694-.471a10 10 0 0 1 1.545-.775a11 11 0 0 1 1.709-.53a12 12 0 0 1 1.808-.268a12.7 12.7 0 0 1 2.754.1a12 12 0 0 1 1.767.401a11 11 0 0 1 1.635.656q.387.194.749.416q.36.222.693.47q.333.249.632.522q.3.274.564.568M11.75 15.25a1.75 1.75 0 1 1-3.5 0a1.75 1.75 0 0 1 3.5 0',
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
'wifi-off': {
|
|
48
|
+
view: '-1.54 -1.54 23.08 23.08',
|
|
49
|
+
d: [
|
|
50
|
+
'M13.348 11.641a.5.5 0 0 1-.696.718a2 2 0 0 0-.136-.12a3 3 0 0 0-.753-.424A4.8 4.8 0 0 0 10 11.5c-1.022 0-1.951.285-2.516.739q-.073.06-.136.12a.5.5 0 0 1-.696-.718q.097-.094.206-.182c.754-.606 1.905-.959 3.142-.959c.765 0 1.5.134 2.132.385c.385.153.726.346 1.01.574q.109.089.206.182m2.508-2.601a.5.5 0 1 1-.712.7a5 5 0 0 0-.35-.32a5 5 0 0 0-.399-.298a6.6 6.6 0 0 0-1.449-.731a8 8 0 0 0-1.126-.319a9 9 0 0 0-1.205-.162a9.3 9.3 0 0 0-1.839.061a9 9 0 0 0-1.172.242a8 8 0 0 0-1.071.39a6.6 6.6 0 0 0-.928.519q-.21.143-.399.298q-.186.155-.35.32a.5.5 0 0 1-.712-.7q.198-.202.424-.39q.225-.186.474-.355a7 7 0 0 1 1.076-.602a8 8 0 0 1 1.215-.443a9 9 0 0 1 1.31-.27A10 10 0 0 1 10 6.89a10 10 0 0 1 1.357.09a10 10 0 0 1 1.31.27a9 9 0 0 1 1.215.443a7.6 7.6 0 0 1 1.076.602q.249.17.474.355q.226.188.424.39',
|
|
51
|
+
'M17.873 6.555a.5.5 0 1 1-.746.667a7 7 0 0 0-.492-.496a8 8 0 0 0-.557-.46a9 9 0 0 0-1.29-.794a9.5 9.5 0 0 0-1.484-.594a10.6 10.6 0 0 0-1.617-.366A11.4 11.4 0 0 0 10 4.389a12 12 0 0 0-1.687.123a11 11 0 0 0-1.617.366a10 10 0 0 0-1.483.595a9 9 0 0 0-.673.374a8 8 0 0 0-.618.42q-.294.22-.557.46q-.263.239-.492.495a.5.5 0 1 1-.746-.667q.264-.294.564-.568t.632-.521q.332-.249.694-.471a10 10 0 0 1 1.545-.775a11 11 0 0 1 1.709-.53a12 12 0 0 1 1.808-.268a12.7 12.7 0 0 1 2.754.1a12 12 0 0 1 1.767.401a11 11 0 0 1 1.635.656q.387.194.749.416q.36.222.693.47q.333.249.632.522q.3.274.564.568M11.75 15.25a1.75 1.75 0 1 1-3.5 0a1.75 1.75 0 0 1 3.5 0',
|
|
52
|
+
'M1.15 1.878a.514.514 0 0 1 .728-.727l16.971 16.971a.514.514 0 0 1-.727.727z',
|
|
53
|
+
],
|
|
54
|
+
},
|
|
55
|
+
check: {
|
|
56
|
+
view: '2.44 2.94 14.12 14.12',
|
|
57
|
+
d: [
|
|
58
|
+
'm14.937 5.743l-5 9c-.324.583-1.198.097-.874-.486l5-9c.324-.583 1.198-.097.874.486',
|
|
59
|
+
'm4.812 10.11l5 4c.52.416-.104 1.197-.624.78l-5-4c-.52-.416.104-1.197.624-.78',
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
close: {
|
|
63
|
+
view: '3.1 3.1 13.79 13.79',
|
|
64
|
+
d: [
|
|
65
|
+
'M6.854 13.854a.5.5 0 0 1-.708-.708l7-7a.5.5 0 0 1 .708.708z',
|
|
66
|
+
'M6.146 6.854a.5.5 0 1 1 .708-.708l7 7a.5.5 0 0 1-.708.708z',
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
info: {
|
|
70
|
+
view: '-2.29 -2.29 30.59 30.59',
|
|
71
|
+
d: [
|
|
72
|
+
'M13.25 10.75a.75.75 0 0 1 .75.75v9a.75.75 0 0 1-1.5 0v-9a.75.75 0 0 1 .75-.75',
|
|
73
|
+
'M14.5 7.25a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0',
|
|
74
|
+
'M13 24.5c6.351 0 11.5-5.149 11.5-11.5S19.351 1.5 13 1.5S1.5 6.649 1.5 13S6.649 24.5 13 24.5m0 1c6.904 0 12.5-5.596 12.5-12.5S19.904.5 13 .5S.5 6.096.5 13S6.096 25.5 13 25.5',
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
warning: {
|
|
78
|
+
view: '-2.29 -2.29 30.59 30.59',
|
|
79
|
+
d: [
|
|
80
|
+
'M13.25 5.25A.75.75 0 0 1 14 6v9a.75.75 0 0 1-1.5 0V6a.75.75 0 0 1 .75-.75',
|
|
81
|
+
'M14.5 19.25a1.25 1.25 0 1 1-2.5 0a1.25 1.25 0 0 1 2.5 0',
|
|
82
|
+
'M13 24.5c6.351 0 11.5-5.149 11.5-11.5S19.351 1.5 13 1.5S1.5 6.649 1.5 13S6.649 24.5 13 24.5m0 1c6.904 0 12.5-5.596 12.5-12.5S19.904.5 13 .5S.5 6.096.5 13S6.096 25.5 13 25.5',
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
error: {
|
|
86
|
+
view: '0.38 0.38 19.23 19.23',
|
|
87
|
+
d: [
|
|
88
|
+
'M10 3.5a6.5 6.5 0 1 0 0 13a6.5 6.5 0 0 0 0-13M2.5 10a7.5 7.5 0 1 1 15 0a7.5 7.5 0 0 1-15 0',
|
|
89
|
+
'M15.304 4.697a.5.5 0 0 1 0 .707l-9.9 9.9a.5.5 0 1 1-.707-.707l9.9-9.9a.5.5 0 0 1 .707 0',
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
expand: {
|
|
93
|
+
view: '2.95 2.95 14.1 14.1',
|
|
94
|
+
d: [
|
|
95
|
+
'M11.354 9.354a.5.5 0 0 1-.708-.708l4-4a.5.5 0 0 1 .708.708zm-6 6a.5.5 0 0 1-.708-.708l4-4a.5.5 0 0 1 .708.708z',
|
|
96
|
+
'M5 15.5a.5.5 0 0 1 0-1h4a.5.5 0 0 1 0 1z',
|
|
97
|
+
'M5.5 15a.5.5 0 0 1-1 0v-4a.5.5 0 0 1 1 0zm10-6a.5.5 0 0 1-1 0V5a.5.5 0 0 1 1 0z',
|
|
98
|
+
'M11 5.5a.5.5 0 0 1 0-1h4a.5.5 0 0 1 0 1z',
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
download: {
|
|
102
|
+
view: '-0.26 0.25 20.52 20.52',
|
|
103
|
+
d: [
|
|
104
|
+
'M11 3h-1a4 4 0 0 0-3.874 3H6a4 4 0 1 0 0 8h8a4 4 0 0 0 .899-7.899A4 4 0 0 0 11 3M6.901 7l.193-.75A3 3 0 0 1 10 4h1c1.405 0 2.614.975 2.924 2.325l.14.61l.61.141A3.001 3.001 0 0 1 14 13H6a3 3 0 1 1 0-6z',
|
|
105
|
+
'M10 10a.5.5 0 0 1 1 0v7.5a.5.5 0 0 1-1 0z',
|
|
106
|
+
'M12.688 15.11a.5.5 0 0 1 .624.78l-2.5 2a.5.5 0 1 1-.624-.78z',
|
|
107
|
+
'M7.688 15.89a.5.5 0 0 1 .624-.78l2.5 2a.5.5 0 1 1-.624.78z',
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
image: {
|
|
111
|
+
view: '-0.9 -0.9 21.79 21.79',
|
|
112
|
+
d: [
|
|
113
|
+
'M8 8a1 1 0 1 0 0-2a1 1 0 0 0 0 2m0 1a2 2 0 1 0 0-4a2 2 0 0 0 0 4',
|
|
114
|
+
'M7.5 10.678L5.59 13.25H7.5l1.91 1H5.59a1 1 0 0 1-.802-1.596l1.909-2.572a1 1 0 0 1 1.606 0l.955 1.286l-.803.596z',
|
|
115
|
+
'M14.257 13.25L11.25 9.778L8.243 13.25zm-2.251-4.127a1 1 0 0 0-1.512 0l-3.007 3.472a1 1 0 0 0 .756 1.655h6.014a1 1 0 0 0 .756-1.655z',
|
|
116
|
+
'M17 2.5H3a.5.5 0 0 0-.5.5v14a.5.5 0 0 0 .5.5h14a.5.5 0 0 0 .5-.5V3a.5.5 0 0 0-.5-.5m-14-1A1.5 1.5 0 0 0 1.5 3v14A1.5 1.5 0 0 0 3 18.5h14a1.5 1.5 0 0 0 1.5-1.5V3A1.5 1.5 0 0 0 17 1.5z',
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
bolt: {
|
|
120
|
+
view: '-0.26 0.24 20.52 20.52',
|
|
121
|
+
d: [
|
|
122
|
+
'M15 8.5h-3.813l2.273-5.303A.5.5 0 0 0 13 2.5H8a.5.5 0 0 0-.46.303l-3 7A.5.5 0 0 0 5 10.5h2.474l-2.938 7.314c-.2.497.417.918.807.55l5.024-4.743l4.958-4.241A.5.5 0 0 0 15 8.5m-4.571 1h3.217l-3.948 3.378l-3.385 3.195l2.365-5.887a.5.5 0 0 0-.464-.686H5.758l2.572-6h3.912L9.969 8.803a.5.5 0 0 0 .46.697',
|
|
123
|
+
],
|
|
124
|
+
},
|
|
125
|
+
speaker: {
|
|
126
|
+
view: '-0.76 -1.26 20.51 20.51',
|
|
127
|
+
d: [
|
|
128
|
+
'M9.672 2.123L5.399 5.84H2a.5.5 0 0 0-.5.5v5.2a.5.5 0 0 0 .5.5h3.295l4.375 3.835a.5.5 0 0 0 .83-.376v-13a.5.5 0 0 0-.828-.377M5.884 6.745L9.5 3.598v10.799L6.014 11.34a.5.5 0 0 0-.458-.3H2.5v-4.2h2.894a.49.49 0 0 0 .49-.096',
|
|
129
|
+
'M13.326 11.88a.5.5 0 0 1-.652-.76q.06-.05.117-.11c.157-.162.295-.366.407-.602c.195-.409.302-.896.302-1.408c0-.817-.273-1.558-.709-2.01a2 2 0 0 0-.117-.11a.5.5 0 0 1 .652-.76q.096.083.185.176c.624.647.989 1.639.989 2.704c0 .66-.14 1.293-.399 1.838c-.157.33-.356.624-.59.866q-.09.093-.185.175',
|
|
130
|
+
'M14.274 14.918a.5.5 0 0 1-.548-.836a6.3 6.3 0 0 0 1.359-1.208a6.1 6.1 0 0 0 .942-1.537A5.9 5.9 0 0 0 16.5 9a6 6 0 0 0-.267-1.773a6 6 0 0 0-.783-1.62a6.1 6.1 0 0 0-1.232-1.33a6 6 0 0 0-.492-.359a.5.5 0 0 1 .548-.836a7.3 7.3 0 0 1 2.002 1.961a7.1 7.1 0 0 1 .913 1.889A7 7 0 0 1 17.5 9a7 7 0 0 1-.311 2.068a7 7 0 0 1-1.338 2.45a7.2 7.2 0 0 1-1.577 1.4',
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
mic: {
|
|
134
|
+
view: '0.39 -0.12 19.23 19.23',
|
|
135
|
+
d: [
|
|
136
|
+
'M7.75 4.25a2.25 2.25 0 0 1 4.5 0v3.5a2.25 2.25 0 0 1-4.5 0z',
|
|
137
|
+
'M10 17c-2.48 0-4-.217-4-1s1.52-1 4-1s4 .217 4 1s-1.52 1-4 1',
|
|
138
|
+
'M9.5 12.5h1V16h-1z',
|
|
139
|
+
'M14 7.5a.5.5 0 0 1 1 0v1.65c0 2.421-2.254 4.35-5 4.35s-5-1.929-5-4.35V7.5a.5.5 0 0 1 1 0v1.65c0 1.831 1.775 3.35 4 3.35s4-1.519 4-3.35z',
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
back: {
|
|
143
|
+
view: '2.96 2.95 14.09 14.09',
|
|
144
|
+
d: [
|
|
145
|
+
'M8.653 14.384a.5.5 0 0 1-.704-.064l-3.333-4a.5.5 0 0 1 .768-.64l3.333 4a.5.5 0 0 1-.064.704',
|
|
146
|
+
'M8.653 5.616a.5.5 0 0 1 .064.704l-3.333 4a.5.5 0 0 1-.768-.64l3.333-4a.5.5 0 0 1 .704-.064',
|
|
147
|
+
'M5 10a.5.5 0 0 1 .5-.5H15a.5.5 0 0 1 0 1H5.5A.5.5 0 0 1 5 10',
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
spinner: {
|
|
151
|
+
view: '2.03 1.03 17.93 17.93',
|
|
152
|
+
d: [
|
|
153
|
+
'M13.375 5.038a.5.5 0 0 1-.564.827A5 5 0 1 0 15 10a.5.5 0 0 1 1 0a6 6 0 1 1-2.626-4.962',
|
|
154
|
+
'M12.769 11.585a.5.5 0 1 1-.539-.842l3.482-2.227a.5.5 0 1 1 .539.842z',
|
|
155
|
+
'M17.947 12.114a.5.5 0 0 1-.913.407l-1.509-3.38a.5.5 0 1 1 .914-.408z',
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
folder: {
|
|
159
|
+
view: '-0.26 -0.01 20.51 20.51',
|
|
160
|
+
d: [
|
|
161
|
+
'M15.5 5.5h-5.281L9.51 4.26A2.5 2.5 0 0 0 7.34 3H4.5A2.5 2.5 0 0 0 2 5.5V15a2.5 2.5 0 0 0 2.5 2.5h11A2.5 2.5 0 0 0 18 15V8a2.5 2.5 0 0 0-2.5-2.5m-11 11A1.5 1.5 0 0 1 3 15V5.5A1.5 1.5 0 0 1 4.5 4h2.84a1.5 1.5 0 0 1 1.302.756l.852 1.492a.5.5 0 0 0 .435.252H15.5A1.5 1.5 0 0 1 17 8v7a1.5 1.5 0 0 1-1.5 1.5z',
|
|
162
|
+
],
|
|
163
|
+
},
|
|
164
|
+
book: {
|
|
165
|
+
view: '-1.76 -1.76 23.53 23.53',
|
|
166
|
+
d: [
|
|
167
|
+
'M10.08 4.304L2.244 3.019A1.5 1.5 0 0 0 .5 4.5v9.738a1.5 1.5 0 0 0 1.268 1.482l8.155 1.275a.5.5 0 0 0 .577-.494V4.797a.5.5 0 0 0-.42-.493m-8-.298L9.5 5.222v10.694L1.923 14.73a.5.5 0 0 1-.423-.493V4.5a.5.5 0 0 1 .58-.494',
|
|
168
|
+
'M18 3a1.5 1.5 0 0 0-.243.02L9.92 4.303a.5.5 0 0 0-.419.493V16.5a.5.5 0 0 0 .577.494l8.155-1.275a1.5 1.5 0 0 0 1.268-1.482V4.5A1.5 1.5 0 0 0 18 3m.077 11.73L10.5 15.917V5.222l7.42-1.216a.5.5 0 0 1 .58.494v9.737a.5.5 0 0 1-.423.493',
|
|
169
|
+
],
|
|
170
|
+
},
|
|
171
|
+
eye: {
|
|
172
|
+
view: '-0.9 -1.4 21.8 21.8',
|
|
173
|
+
d: [
|
|
174
|
+
'M10 16c4.658 0 8.5-2.161 8.5-5S14.658 6 10 6s-8.5 2.161-8.5 5s3.842 5 8.5 5m0-9c4.179 0 7.5 1.868 7.5 4s-3.321 4-7.5 4s-7.5-1.868-7.5-4S5.821 7 10 7',
|
|
175
|
+
'M9.5 3.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0zm4.01.402a.5.5 0 0 1 .98.196l-.5 2.5a.5.5 0 0 1-.98-.196zm-7.02 0a.5.5 0 0 0-.98.196l.5 2.5a.5.5 0 0 0 .98-.196zM2.429 5.243a.5.5 0 0 0-.858.514l1.5 2.5a.5.5 0 0 0 .858-.514zm15.142 0a.5.5 0 1 1 .858.514l-1.5 2.5a.5.5 0 1 1-.858-.514zM13 10.5a3 3 0 1 1-6 0a3 3 0 0 1 6 0',
|
|
176
|
+
],
|
|
177
|
+
},
|
|
178
|
+
/* The same eye with a line through it. Pepicons' `eye-off`, but drawn from
|
|
179
|
+
THIS file's `eye` plus the slash rather than copied whole: the set has
|
|
180
|
+
redrawn its lashes since the open eye was taken, and a pair that toggles
|
|
181
|
+
in one button must differ by the slash alone or the eye appears to jump.
|
|
182
|
+
For the same reason it shares `eye`'s `view` instead of a measured one --
|
|
183
|
+
the slash sits inside that box (0.8..18.5 on both axes), so nothing is
|
|
184
|
+
clipped, and the body of the eye does not move when the state does. */
|
|
185
|
+
'eye-off': {
|
|
186
|
+
view: '-0.9 -1.4 21.8 21.8',
|
|
187
|
+
d: [
|
|
188
|
+
'M10 16c4.658 0 8.5-2.161 8.5-5S14.658 6 10 6s-8.5 2.161-8.5 5s3.842 5 8.5 5m0-9c4.179 0 7.5 1.868 7.5 4s-3.321 4-7.5 4s-7.5-1.868-7.5-4S5.821 7 10 7',
|
|
189
|
+
'M9.5 3.5a.5.5 0 0 1 1 0v3a.5.5 0 0 1-1 0zm4.01.402a.5.5 0 0 1 .98.196l-.5 2.5a.5.5 0 0 1-.98-.196zm-7.02 0a.5.5 0 0 0-.98.196l.5 2.5a.5.5 0 0 0 .98-.196zM2.429 5.243a.5.5 0 0 0-.858.514l1.5 2.5a.5.5 0 0 0 .858-.514zm15.142 0a.5.5 0 1 1 .858.514l-1.5 2.5a.5.5 0 1 1-.858-.514zM13 10.5a3 3 0 1 1-6 0a3 3 0 0 1 6 0',
|
|
190
|
+
'M1.15 1.878a.514.514 0 0 1 .728-.727l16.971 16.971a.514.514 0 0 1-.727.727z',
|
|
191
|
+
],
|
|
192
|
+
},
|
|
193
|
+
palette: {
|
|
194
|
+
view: '-2.13 -2.1 23.53 23.53',
|
|
195
|
+
d: [
|
|
196
|
+
'M14.725 13.334c.97-3.623-1.336-7.377-5.135-8.395C5.323 3.795-.725 6.762.544 10.35c.383 1.084 1.134 1.341 2.682 1.363l.108.002c1.1.013 1.471.1 1.678.436c.214.348.216.756.054 1.788c-.067.422-.088.569-.113.794c-.145 1.3.067 2.274.89 3.16c2.584 2.784 7.788-.48 8.882-4.56M1.486 10.017c-.908-2.57 4.217-5.084 7.845-4.112c3.277.878 5.252 4.093 4.428 7.17c-.924 3.446-5.287 6.182-7.183 4.14c-.594-.64-.745-1.333-.63-2.37c.024-.205.044-.344.108-.75c.2-1.275.197-1.836-.19-2.467c-.465-.756-1.059-.894-2.517-.912l-.107-.002c-1.159-.016-1.562-.154-1.754-.697',
|
|
197
|
+
'M4.75 9.5a1.25 1.25 0 1 1 0-2.5a1.25 1.25 0 0 1 0 2.5m4 0a1.25 1.25 0 1 1 0-2.5a1.25 1.25 0 0 1 0 2.5m2.5 3a1.25 1.25 0 1 1 0-2.5a1.25 1.25 0 0 1 0 2.5M9.75 16a1.25 1.25 0 1 1 0-2.5a1.25 1.25 0 0 1 0 2.5m3.62-12.395a1 1 0 0 1 1.371.443l4.093 8.4a.652.652 0 0 1-1.149.611l-4.708-8.07a1 1 0 0 1 .394-1.384',
|
|
198
|
+
'M11.538 3.484c.486.915 1.305 1.171 2.097.75c.791-.42 1.038-1.243.551-2.158C13.63 1.028 12.438.078 11.648.497s-.668 1.939-.11 2.987m.882-.47a3.2 3.2 0 0 1-.32-1.137a2 2 0 0 1 .018-.496l.018.009c.05.024.205.096.403.254c.302.241.602.596.764.901c.229.43.164.646-.138.807c-.3.16-.516.092-.745-.337',
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
stars: {
|
|
202
|
+
view: '-1.95 -1.76 23.53 23.53',
|
|
203
|
+
d: [
|
|
204
|
+
'M9 .5a.5.5 0 0 1 .479.354l1.928 6.333l5.765 2.107a.5.5 0 0 1 .013.934l-5.727 2.275l-1.979 6.64a.5.5 0 0 1-.958 0l-1.979-6.64l-5.727-2.275a.5.5 0 0 1 .013-.934l5.765-2.107L8.522.854A.5.5 0 0 1 9 .5m0 2.216l-1.523 5a.5.5 0 0 1-.307.324L2.403 9.784l4.734 1.88a.5.5 0 0 1 .294.322l1.57 5.264l1.568-5.264a.5.5 0 0 1 .294-.322l4.734-1.88l-4.767-1.742a.5.5 0 0 1-.307-.324z',
|
|
205
|
+
'M16.75 19.12c-.1 0-.19-.08-.2-.18c-.18-1.82-.32-2.4-1.99-2.56c-.1-.01-.18-.1-.18-.2s.08-.19.18-.2c1.71-.16 1.81-.6 1.99-2.42c0-.1.1-.18.2-.18s.19.08.2.18c.18 1.82.29 2.26 1.99 2.42c.1.01.18.1.18.2s-.08.19-.18.2c-1.68.16-1.81.74-1.99 2.57c0 .1-.09.18-.2.18z',
|
|
206
|
+
],
|
|
207
|
+
},
|
|
208
|
+
wrench: {
|
|
209
|
+
view: '-0.17 -0.74 21.07 21.07',
|
|
210
|
+
d: [
|
|
211
|
+
'M11.876 7.574a3 3 0 0 0-.384-.382c.295-1.338-.066-2.802-1.014-3.93c-1.182-1.41-3.03-2-4.668-1.523a.5.5 0 0 0-.243.801l1.741 2.076a.5.5 0 0 1-.061.704l-.581.488a.5.5 0 0 1-.705-.062L4.22 3.671a.5.5 0 0 0-.832.1c-.755 1.531-.494 3.453.689 4.862c.935 1.114 2.29 1.724 3.645 1.683q.138.251.324.471l5.302 6.32a2.5 2.5 0 1 0 3.83-3.214zm-7.033.416c-.735-.875-1.016-1.99-.82-2.997l1.172 1.396a1.5 1.5 0 0 0 2.113.185l.582-.488a1.5 1.5 0 0 0 .184-2.113L6.903 2.577c1.025-.02 2.075.452 2.81 1.327c.813.97 1.077 2.24.732 3.34a.5.5 0 0 0 .208.571a2 2 0 0 1 .457.401l5.303 6.32a1.5 1.5 0 1 1-2.299 1.928l-5.302-6.32a2 2 0 0 1-.323-.538a.5.5 0 0 0-.522-.31c-1.133.133-2.32-.348-3.124-1.306',
|
|
212
|
+
],
|
|
213
|
+
},
|
|
214
|
+
file: {
|
|
215
|
+
view: '-1.54 -1.54 23.08 23.08',
|
|
216
|
+
d: [
|
|
217
|
+
'M6.5 12a.5.5 0 0 1 0-1h7a.5.5 0 0 1 0 1zm0 3a.5.5 0 0 1 0-1h7a.5.5 0 0 1 0 1z',
|
|
218
|
+
'M11.185 1H4.5A1.5 1.5 0 0 0 3 2.5v15A1.5 1.5 0 0 0 4.5 19h11a1.5 1.5 0 0 0 1.5-1.5V7.202a1.5 1.5 0 0 0-.395-1.014l-4.314-4.702A1.5 1.5 0 0 0 11.185 1M4 2.5a.5.5 0 0 1 .5-.5h6.685a.5.5 0 0 1 .369.162l4.314 4.702a.5.5 0 0 1 .132.338V17.5a.5.5 0 0 1-.5.5h-11a.5.5 0 0 1-.5-.5z',
|
|
219
|
+
'M11 7h5.5a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5v-6a.5.5 0 0 1 1 0z',
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
cloud: {
|
|
223
|
+
view: '-0.26 -1.76 20.52 20.52',
|
|
224
|
+
d: [
|
|
225
|
+
'M11 3h-1a4 4 0 0 0-3.874 3H6a4 4 0 1 0 0 8h8a4 4 0 0 0 .899-7.899A4 4 0 0 0 11 3M6.901 7l.193-.75A3 3 0 0 1 10 4h1c1.405 0 2.614.975 2.924 2.325l.14.61l.61.141A3.001 3.001 0 0 1 14 13H6a3 3 0 1 1 0-6z',
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
export default function Icon({ name, size = 18, className, title, }) {
|
|
230
|
+
const g = GLYPHS[name];
|
|
231
|
+
return (_jsxs("svg", { className: className, width: size, height: size, viewBox: g.view, fill: "currentColor",
|
|
232
|
+
/* Pepicons paths are self-intersecting outlines; without evenodd the
|
|
233
|
+
counters fill in and a gear becomes a blob. */
|
|
234
|
+
fillRule: "evenodd", clipRule: "evenodd", role: title ? 'img' : undefined, "aria-hidden": title ? undefined : true, "aria-label": title, children: [title && _jsx("title", { children: title }), g.d.map((d) => (_jsx("path", { d: d }, d))), g.dots?.map(([cx, cy, r]) => (_jsx("circle", { cx: cx, cy: cy, r: r }, `${cx},${cy},${r}`)))] }));
|
|
235
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The people. Open Peeps, wearing the theme.
|
|
3
|
+
*
|
|
4
|
+
* Twenty-one hand-drawn figures, and the reason they can be in the app at all
|
|
5
|
+
* is that they are two colours: black line and white fill, nothing else. That
|
|
6
|
+
* makes them recolourable, which a photograph or a flat-colour illustration is
|
|
7
|
+
* not -- and an app with several themes cannot carry artwork that only looks right
|
|
8
|
+
* in one of them.
|
|
9
|
+
*
|
|
10
|
+
* **They take `currentColor`.** The build swaps `#000` for `class="ink"` and
|
|
11
|
+
* `#FFF` for `class="paper"`, and the two rules in `styles.css` point those at
|
|
12
|
+
* `currentColor` and `--panel`. So a figure inherits the colour of whatever it
|
|
13
|
+
* sits in: grey in a muted block, accent when something is being pointed at,
|
|
14
|
+
* `--bad` on a failure screen. One file, every theme, no second export.
|
|
15
|
+
*
|
|
16
|
+
* **Inlined, not `<img>`.** An SVG behind an `<img>` is a separate document: it
|
|
17
|
+
* cannot see this page's custom properties, cannot inherit `currentColor`, and
|
|
18
|
+
* would need twenty-one more files to cover light and dark. They are read at
|
|
19
|
+
* build time and injected, which is what makes the colour work.
|
|
20
|
+
*
|
|
21
|
+
* **`aria-hidden` unless told otherwise.** These are decoration. A screen reader
|
|
22
|
+
* announcing "person shrugging" before the sentence that actually says what
|
|
23
|
+
* went wrong is noise; the caller passes `alt` only when the picture is the
|
|
24
|
+
* message, which so far it never is.
|
|
25
|
+
*/
|
|
26
|
+
import { type IllustrationName } from '../illustrations';
|
|
27
|
+
export type { IllustrationName };
|
|
28
|
+
export default function Illustration({ name, size, alt, className, }: {
|
|
29
|
+
name: IllustrationName;
|
|
30
|
+
/** Height in pixels. The width follows the drawing's own ratio. */
|
|
31
|
+
size?: number;
|
|
32
|
+
/** Given only when the picture carries meaning of its own. Omit for
|
|
33
|
+
* decoration, which is nearly always. */
|
|
34
|
+
alt?: string;
|
|
35
|
+
className?: string;
|
|
36
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The people. Open Peeps, wearing the theme.
|
|
4
|
+
*
|
|
5
|
+
* Twenty-one hand-drawn figures, and the reason they can be in the app at all
|
|
6
|
+
* is that they are two colours: black line and white fill, nothing else. That
|
|
7
|
+
* makes them recolourable, which a photograph or a flat-colour illustration is
|
|
8
|
+
* not -- and an app with several themes cannot carry artwork that only looks right
|
|
9
|
+
* in one of them.
|
|
10
|
+
*
|
|
11
|
+
* **They take `currentColor`.** The build swaps `#000` for `class="ink"` and
|
|
12
|
+
* `#FFF` for `class="paper"`, and the two rules in `styles.css` point those at
|
|
13
|
+
* `currentColor` and `--panel`. So a figure inherits the colour of whatever it
|
|
14
|
+
* sits in: grey in a muted block, accent when something is being pointed at,
|
|
15
|
+
* `--bad` on a failure screen. One file, every theme, no second export.
|
|
16
|
+
*
|
|
17
|
+
* **Inlined, not `<img>`.** An SVG behind an `<img>` is a separate document: it
|
|
18
|
+
* cannot see this page's custom properties, cannot inherit `currentColor`, and
|
|
19
|
+
* would need twenty-one more files to cover light and dark. They are read at
|
|
20
|
+
* build time and injected, which is what makes the colour work.
|
|
21
|
+
*
|
|
22
|
+
* **`aria-hidden` unless told otherwise.** These are decoration. A screen reader
|
|
23
|
+
* announcing "person shrugging" before the sentence that actually says what
|
|
24
|
+
* went wrong is noise; the caller passes `alt` only when the picture is the
|
|
25
|
+
* message, which so far it never is.
|
|
26
|
+
*/
|
|
27
|
+
import { ILLUSTRATION_SVG } from '../illustrations';
|
|
28
|
+
/* Read at build time and inlined, so there is no request and nothing to fail on
|
|
29
|
+
an offline first run -- which is the run these are most likely to appear on.
|
|
30
|
+
|
|
31
|
+
The app read them with Vite's `import.meta.glob('*.svg', {query: '?raw'})`,
|
|
32
|
+
which is a bundler feature rather than a language one: `tsc` emits it
|
|
33
|
+
untouched and the published `dist` would refer to twenty-one modules that do
|
|
34
|
+
not exist. `scripts/build-illustrations.mjs` generates a plain module
|
|
35
|
+
instead, which removes the dependency on a bundler rather than documenting
|
|
36
|
+
it. */
|
|
37
|
+
const BY_NAME = ILLUSTRATION_SVG;
|
|
38
|
+
export default function Illustration({ name, size = 160, alt, className, }) {
|
|
39
|
+
const svg = BY_NAME[name];
|
|
40
|
+
if (!svg)
|
|
41
|
+
return null;
|
|
42
|
+
return (_jsx("span", { className: `illo${className ? ` ${className}` : ''}`, style: { height: size }, role: alt ? 'img' : undefined, "aria-label": alt, "aria-hidden": alt ? undefined : true,
|
|
43
|
+
/* The file is ours: it comes off disk at build time, not from a model, an
|
|
44
|
+
applet or the network, so there is no untrusted string to sanitise
|
|
45
|
+
here. Anything that ever arrives at runtime must not use this path. */
|
|
46
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: the SVG comes off disk at build time via scripts/build-illustrations.mjs; nothing here arrives from a request.
|
|
47
|
+
dangerouslySetInnerHTML: { __html: svg } }));
|
|
48
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface Props extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'className'> {
|
|
2
|
+
/** The same three every control takes, so a row of mixed controls lines up
|
|
3
|
+
* without anyone measuring. */
|
|
4
|
+
size?: 'sm' | 'md' | 'lg';
|
|
5
|
+
/** Monospace, for a path, a token, an id — anything where the exact
|
|
6
|
+
* characters are the point. */
|
|
7
|
+
mono?: boolean;
|
|
8
|
+
/** Full width of whatever holds it. Inputs already are, by default; this is
|
|
9
|
+
* for the `size`d ones, which are not. */
|
|
10
|
+
block?: boolean;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
declare const Input: import("react").ForwardRefExoticComponent<Props & import("react").RefAttributes<HTMLInputElement>>;
|
|
14
|
+
export default Input;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The bare control `Field` wraps.
|
|
4
|
+
*
|
|
5
|
+
* Almost every input in the app was labelled by its placeholder, which
|
|
6
|
+
* disappears the moment you type — so the one time you want to know what a
|
|
7
|
+
* field was for is the one time it is gone. `Field` is the fix: it draws the
|
|
8
|
+
* label, wires the description and the error with `aria-describedby`, and
|
|
9
|
+
* hands this component the `id` and `aria-invalid` to carry. On its own,
|
|
10
|
+
* `Input` is for the rare box whose surroundings already name it, and it needs
|
|
11
|
+
* an `aria-label` then, because an input with no accessible name is the first
|
|
12
|
+
* thing an audit finds and the last thing a sighted person notices.
|
|
13
|
+
*
|
|
14
|
+
* **A plain `<input>`, deliberately.** The stylesheet styles inputs by element
|
|
15
|
+
* — hover, focus, disabled, the invalid ring inside `.field-bad` — and every
|
|
16
|
+
* one of those rules keeps working because nothing is wrapped. React Aria's
|
|
17
|
+
* `Input` exists to take state from a `TextField` context; this component takes
|
|
18
|
+
* its state from `Field`'s render prop instead, which works for a `Select` and
|
|
19
|
+
* a `SizeGrid` too, and that is the contract the app already has.
|
|
20
|
+
*
|
|
21
|
+
* `type="text"` is the default, the way `type="button"` is `Button`'s: stated
|
|
22
|
+
* so it is in the signature rather than inherited from the browser.
|
|
23
|
+
*
|
|
24
|
+
* **`type="password"` grows an eye.** A password field that cannot be read back
|
|
25
|
+
* is a field you retype until it takes; the toggle is the one control every
|
|
26
|
+
* sign-in form has grown and every hand-written one here lacked. The box is
|
|
27
|
+
* still the same `<input>` -- `Field`'s wiring, the element rules, the ref all
|
|
28
|
+
* land on it -- wrapped in a grid so the button can sit inside its right edge
|
|
29
|
+
* without absolute positioning against a height that changes with `size`.
|
|
30
|
+
*
|
|
31
|
+
* The eye is a React Aria `ToggleButton`, not `Button`: a show/hide is a
|
|
32
|
+
* pressed state, and `aria-pressed` is what a toggle announces. It is not
|
|
33
|
+
* passed as a prop because `filterDOMProps` would drop it in silence -- the
|
|
34
|
+
* same trap `aria-busy` fell into on `Button` -- and `ToggleButton` writes it
|
|
35
|
+
* itself. The label stays "Show password" in both states, as a toggle's should:
|
|
36
|
+
* a label that flips to "Hide password" *and* reads as pressed says the same
|
|
37
|
+
* thing twice, once of them backwards. Revealed text is also told to stop
|
|
38
|
+
* autocorrecting and capitalising, because a phone keyboard treats a visible
|
|
39
|
+
* field as prose and rewrites the password it was asked to show.
|
|
40
|
+
*/
|
|
41
|
+
import { forwardRef, useState } from 'react';
|
|
42
|
+
import { ToggleButton } from 'react-aria-components';
|
|
43
|
+
import Icon from './Icon';
|
|
44
|
+
const Input = forwardRef(function Input({ size = 'md', mono, block, className, type = 'text', ...rest }, ref) {
|
|
45
|
+
const classes = [
|
|
46
|
+
size === 'md' ? '' : `size-${size}`,
|
|
47
|
+
mono ? 'mono' : '',
|
|
48
|
+
block ? 'block' : '',
|
|
49
|
+
className ?? '',
|
|
50
|
+
]
|
|
51
|
+
.filter(Boolean)
|
|
52
|
+
.join(' ');
|
|
53
|
+
/* State lives here even for a text input, so switching a field's `type` at
|
|
54
|
+
run time does not remount it -- a hook count that changes with a prop is a
|
|
55
|
+
React error, and a remount would drop the caret. */
|
|
56
|
+
const [shown, setShown] = useState(false);
|
|
57
|
+
if (type !== 'password') {
|
|
58
|
+
return _jsx("input", { ref: ref, type: type, className: classes || undefined, ...rest });
|
|
59
|
+
}
|
|
60
|
+
return (_jsxs("span", { className: `secret secret-${size}${block ? ' block' : ''}`, children: [_jsx("input", { ref: ref, type: shown ? 'text' : 'password', className: classes || undefined,
|
|
61
|
+
/* Only while revealed: as a password these are moot, and setting them
|
|
62
|
+
on a password field makes some browsers stop offering to fill it. */
|
|
63
|
+
autoCapitalize: shown ? 'off' : undefined, autoCorrect: shown ? 'off' : undefined, spellCheck: shown ? false : undefined, ...rest }), _jsx(ToggleButton, { className: `icon-btn ghost secret-eye${size === 'md' ? '' : ` size-${size}`}`, "aria-label": "Show password", isSelected: shown, onChange: setShown, isDisabled: rest.disabled, children: _jsx(Icon, { name: shown ? 'eye-off' : 'eye', size: { sm: 14, md: 16, lg: 18 }[size] }) })] }));
|
|
64
|
+
});
|
|
65
|
+
export default Input;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import DOMPurify from 'dompurify';
|
|
2
|
+
/**
|
|
3
|
+
* Render model output as markdown.
|
|
4
|
+
*
|
|
5
|
+
* Sanitised without exception: this is text produced by a model, which may be
|
|
6
|
+
* echoing content it read from a file, so it is never trusted HTML.
|
|
7
|
+
*/
|
|
8
|
+
export default function Markdown({ text, sanitize, className, }: {
|
|
9
|
+
text: string;
|
|
10
|
+
/**
|
|
11
|
+
* What to allow through, on top of the defaults.
|
|
12
|
+
*
|
|
13
|
+
* The defaults forbid iframes, forms, controls, scripts and inline styles:
|
|
14
|
+
* prose, code and tables only. An app that renders trusted embeds can widen
|
|
15
|
+
* that here; one that wants less can forbid more. It is a prop rather than
|
|
16
|
+
* a constant because the sanitiser ships to other people's apps now, and
|
|
17
|
+
* what is "trusted" is a fact about the app, not the component.
|
|
18
|
+
*/
|
|
19
|
+
sanitize?: Parameters<typeof DOMPurify.sanitize>[1];
|
|
20
|
+
className?: string;
|
|
21
|
+
}): import("react").JSX.Element | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import DOMPurify from 'dompurify';
|
|
3
|
+
import { marked } from 'marked';
|
|
4
|
+
import { useMemo } from 'react';
|
|
5
|
+
marked.setOptions({ gfm: true, breaks: true });
|
|
6
|
+
/**
|
|
7
|
+
* Render model output as markdown.
|
|
8
|
+
*
|
|
9
|
+
* Sanitised without exception: this is text produced by a model, which may be
|
|
10
|
+
* echoing content it read from a file, so it is never trusted HTML.
|
|
11
|
+
*/
|
|
12
|
+
export default function Markdown({ text, sanitize, className, }) {
|
|
13
|
+
const html = useMemo(() => {
|
|
14
|
+
if (!text)
|
|
15
|
+
return '';
|
|
16
|
+
const raw = marked.parse(text, { async: false });
|
|
17
|
+
return DOMPurify.sanitize(raw, {
|
|
18
|
+
// No iframes, no forms, no event handlers -- prose, code and tables only.
|
|
19
|
+
FORBID_TAGS: ['style', 'iframe', 'form', 'input', 'button', 'script'],
|
|
20
|
+
FORBID_ATTR: ['style', 'onerror', 'onload', 'onclick'],
|
|
21
|
+
...sanitize,
|
|
22
|
+
});
|
|
23
|
+
}, [text, sanitize]);
|
|
24
|
+
if (!text)
|
|
25
|
+
return null;
|
|
26
|
+
return (_jsx("div", { className: `md${className ? ` ${className}` : ''}`,
|
|
27
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: the string is DOMPurify output, with the config above.
|
|
28
|
+
dangerouslySetInnerHTML: { __html: html } }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A window over the app, and the behaviour every one of them was missing.
|
|
3
|
+
*
|
|
4
|
+
* There are eight of these -- Settings, FirstRun, ViewSettings, DownloadModal,
|
|
5
|
+
* ModelSettings, AppletSettings, AppletReview, the studio -- and all eight were
|
|
6
|
+
* built by hand from `.backdrop` and `.modal`. Not one of them trapped focus.
|
|
7
|
+
*
|
|
8
|
+
* **That is not a detail.** Everything behind a modal is still in the tab
|
|
9
|
+
* order: still focusable, still clickable by a keyboard, and completely
|
|
10
|
+
* invisible under the scrim. Tab past the last button in Settings and you are
|
|
11
|
+
* somewhere on the dashboard you cannot see, operating controls you cannot
|
|
12
|
+
* read. Shift-Tab from the first does the same going the other way. The mouse
|
|
13
|
+
* never finds this, which is why it survived eight implementations.
|
|
14
|
+
*
|
|
15
|
+
* So: focus moves in, is kept in, and goes back where it came from when the
|
|
16
|
+
* window closes -- to the button that opened it, not to the top of the page.
|
|
17
|
+
* `role="dialog"` and `aria-modal` say the same thing to a screen reader, which
|
|
18
|
+
* otherwise reads the page underneath as though it were still there.
|
|
19
|
+
*
|
|
20
|
+
* **This is the workspace shape.** A title, a body, optionally a footer, sized
|
|
21
|
+
* to its content. `Dialog` is the narrow two-answer version and is built on
|
|
22
|
+
* this -- same trap, same restore, stricter about the scrim, because for "may
|
|
23
|
+
* this applet write to your files" a stray click on the background is a way of
|
|
24
|
+
* answering by accident.
|
|
25
|
+
*/
|
|
26
|
+
export default function Modal({ title, description, subtitle, head, children, footer, footerClass, onClose, closeDisabled, width, bodyClass, className, dismissOnScrim, closeButton, labelledBy, }: {
|
|
27
|
+
/** The window's name. Rendered as the heading and announced on open. */
|
|
28
|
+
title?: React.ReactNode;
|
|
29
|
+
/** A line under the title, saying what the window is for. The same slot
|
|
30
|
+
* `Card` has, for the same reason: a heading names a thing and a sentence
|
|
31
|
+
* says why you are looking at it, and every window that wanted one was
|
|
32
|
+
* putting it in the body where it read as the first item of content. */
|
|
33
|
+
description?: React.ReactNode;
|
|
34
|
+
/** Beside the title -- what this window is about, usually an id or a path. */
|
|
35
|
+
subtitle?: React.ReactNode;
|
|
36
|
+
/** Extra controls in the header, before the close button. */
|
|
37
|
+
head?: React.ReactNode;
|
|
38
|
+
children: React.ReactNode;
|
|
39
|
+
footer?: React.ReactNode;
|
|
40
|
+
footerClass?: string;
|
|
41
|
+
/** Escape, the close button, and the scrim all call this. Omit it and the
|
|
42
|
+
* window cannot be dismissed -- which is right for onboarding and wrong for
|
|
43
|
+
* everything else. */
|
|
44
|
+
onClose?: () => void;
|
|
45
|
+
/** While something is saving, closing would abandon it mid-flight. */
|
|
46
|
+
closeDisabled?: boolean;
|
|
47
|
+
width?: string;
|
|
48
|
+
/** For a body that is not a single column -- Settings' rail and pane. */
|
|
49
|
+
bodyClass?: string;
|
|
50
|
+
className?: string;
|
|
51
|
+
/** The scrim is the easiest thing on screen to hit by accident. True keeps
|
|
52
|
+
* today's behaviour for the workspaces; `Dialog` turns it off. */
|
|
53
|
+
dismissOnScrim?: boolean;
|
|
54
|
+
/** A question answers itself with its own buttons; a ✕ beside them is a third
|
|
55
|
+
* answer that means nothing. `Dialog` turns it off. */
|
|
56
|
+
closeButton?: boolean;
|
|
57
|
+
/** The id of whatever names this window, when it is not `title`. */
|
|
58
|
+
labelledBy?: string;
|
|
59
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* A window over the app, and the behaviour every one of them was missing.
|
|
4
|
+
*
|
|
5
|
+
* There are eight of these -- Settings, FirstRun, ViewSettings, DownloadModal,
|
|
6
|
+
* ModelSettings, AppletSettings, AppletReview, the studio -- and all eight were
|
|
7
|
+
* built by hand from `.backdrop` and `.modal`. Not one of them trapped focus.
|
|
8
|
+
*
|
|
9
|
+
* **That is not a detail.** Everything behind a modal is still in the tab
|
|
10
|
+
* order: still focusable, still clickable by a keyboard, and completely
|
|
11
|
+
* invisible under the scrim. Tab past the last button in Settings and you are
|
|
12
|
+
* somewhere on the dashboard you cannot see, operating controls you cannot
|
|
13
|
+
* read. Shift-Tab from the first does the same going the other way. The mouse
|
|
14
|
+
* never finds this, which is why it survived eight implementations.
|
|
15
|
+
*
|
|
16
|
+
* So: focus moves in, is kept in, and goes back where it came from when the
|
|
17
|
+
* window closes -- to the button that opened it, not to the top of the page.
|
|
18
|
+
* `role="dialog"` and `aria-modal` say the same thing to a screen reader, which
|
|
19
|
+
* otherwise reads the page underneath as though it were still there.
|
|
20
|
+
*
|
|
21
|
+
* **This is the workspace shape.** A title, a body, optionally a footer, sized
|
|
22
|
+
* to its content. `Dialog` is the narrow two-answer version and is built on
|
|
23
|
+
* this -- same trap, same restore, stricter about the scrim, because for "may
|
|
24
|
+
* this applet write to your files" a stray click on the background is a way of
|
|
25
|
+
* answering by accident.
|
|
26
|
+
*/
|
|
27
|
+
import { useEffect, useId, useRef } from 'react';
|
|
28
|
+
import { Modal as AriaModal, Dialog, Heading, ModalOverlay } from 'react-aria-components';
|
|
29
|
+
import Button from './Button';
|
|
30
|
+
import Icon from './Icon';
|
|
31
|
+
/* The trap is the same obligation wherever it applies, and the studio needs it
|
|
32
|
+
without being shaped like this, so it lives in a hook rather than here. */
|
|
33
|
+
export default function Modal({ title, description, subtitle, head, children, footer, footerClass, onClose, closeDisabled = false, width, bodyClass, className, dismissOnScrim = true, closeButton = true, labelledBy, }) {
|
|
34
|
+
const headingId = useId();
|
|
35
|
+
const canClose = Boolean(onClose) && !closeDisabled;
|
|
36
|
+
/* React Aria owns the three things every hand-built modal here got wrong.
|
|
37
|
+
|
|
38
|
+
`ModalOverlay` is the scrim: portalled, `position: fixed` from `.backdrop`,
|
|
39
|
+
and it closes on a press outside the box only when `isDismissable` -- so
|
|
40
|
+
`dismissOnScrim={false}` is a prop rather than a `mousedown` handler
|
|
41
|
+
checking `e.target === e.currentTarget`. `Modal` is the box. `Dialog` is
|
|
42
|
+
what makes it one to a screen reader -- `role="dialog"`, `aria-modal`,
|
|
43
|
+
and everything behind it made inert -- and it moves focus in on open,
|
|
44
|
+
keeps it in, and puts it back on the control that opened it when it
|
|
45
|
+
closes. `useTrapFocus` did all of that by hand and only for windows that
|
|
46
|
+
used it, which is how eight of them shipped without a trap; it stays
|
|
47
|
+
exported for a window that genuinely is not this shape.
|
|
48
|
+
|
|
49
|
+
`onClose` absent means the window cannot be dismissed at all: no scrim,
|
|
50
|
+
no Escape. `closeDisabled` means the same while something is saving. */
|
|
51
|
+
/* `aria-modal`, set on the element rather than passed as a prop. React Aria
|
|
52
|
+
hides the rest of the page with `aria-hidden` and does not set it -- and
|
|
53
|
+
its `filterDOMProps` drops the prop in silence, the same way it dropped
|
|
54
|
+
`aria-busy` on `Button`. Stated because the old component stated it, and
|
|
55
|
+
because axe reads it. */
|
|
56
|
+
const dialogRef = useRef(null);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
dialogRef.current?.setAttribute('aria-modal', 'true');
|
|
59
|
+
});
|
|
60
|
+
return (_jsx(ModalOverlay, { className: "backdrop", isOpen: true, isDismissable: canClose && dismissOnScrim, isKeyboardDismissDisabled: !canClose, onOpenChange: (open) => {
|
|
61
|
+
if (!open && canClose)
|
|
62
|
+
onClose?.();
|
|
63
|
+
}, children: _jsx(AriaModal, { className: `modal${className ? ` ${className}` : ''}`, style: width ? { width } : undefined, children: _jsxs(Dialog, { ref: dialogRef, className: "modal-dialog", "aria-labelledby": labelledBy ?? (title ? headingId : undefined), children: [(title || head || (onClose && closeButton)) && (_jsxs("header", { className: "modal-head", children: [title && (
|
|
64
|
+
/* `Heading` is what React Aria labels the dialog by, and it
|
|
65
|
+
renders an `<h2>` -- which the browser gives its own margins
|
|
66
|
+
and its own size (17px above and below, 21px type). The old
|
|
67
|
+
header was a bare `<strong>` and had neither. `.modal-title`
|
|
68
|
+
takes them back off so the `<strong>` inside draws exactly as
|
|
69
|
+
it did; without it every window opened with its title
|
|
70
|
+
floating in a band twice the height of the head. */
|
|
71
|
+
_jsx(Heading, { slot: "title", id: headingId, level: 2, className: "modal-title", children: _jsx("strong", { children: title }) })), subtitle, head, onClose && closeButton && (_jsx(Button, { iconOnly: true, className: "x", "aria-label": "Close", isDisabled: closeDisabled, onPress: () => onClose(), children: _jsx(Icon, { name: "close", size: 16 }) }))] })), description && _jsx("p", { className: "modal-desc", children: description }), _jsx("div", { className: `modal-body${bodyClass ? ` ${bodyClass}` : ''}`, children: children }), footer && (_jsx("footer", { className: `set-actions${footerClass ? ` ${footerClass}` : ''}`, children: footer }))] }) }) }));
|
|
72
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A word attached to a thing.
|
|
3
|
+
*
|
|
4
|
+
* Three jobs, three weights, and the weight is the whole design: a
|
|
5
|
+
* *measurement* is quiet, because there is nothing to act on and it should
|
|
6
|
+
* read as text that happens to sit in a row; a *capability* is a plain chip,
|
|
7
|
+
* because it is one of a set scanned across and none may be louder than the
|
|
8
|
+
* others; a *state* is the only one that takes colour, because it is the only
|
|
9
|
+
* one that can change.
|
|
10
|
+
*
|
|
11
|
+
* The four state tones are the ones `Callout` and `Toast` use, so one
|
|
12
|
+
* vocabulary covers the app: `warn` is a caution — the thing works, mind how —
|
|
13
|
+
* and `bad` is something that is actually not working.
|
|
14
|
+
*
|
|
15
|
+
* **Colour is never the only signal.** A state pill has a tint, a border and a
|
|
16
|
+
* word. The tint alone was 1.67:1 on Paper for weeks and looked fine on every
|
|
17
|
+
* dark theme anybody tested, which is why `pillTones.test.ts` measures every
|
|
18
|
+
* tone against every theme rather than trusting anyone's eye.
|
|
19
|
+
*
|
|
20
|
+
* **Tint into `--panel`, not `--panel-2`.** Mixing a mid tone into the darker
|
|
21
|
+
* surface moves the background towards the text; on a light theme that drops a
|
|
22
|
+
* label from 4.7:1 to 3.9:1. The tones mix at 10% into the panel for that
|
|
23
|
+
* reason and not for taste.
|
|
24
|
+
*
|
|
25
|
+
* This was the second-most-copied markup in the app — `<span className="pill
|
|
26
|
+
* pill-info">` at every call site, and a gallery page teaching it. A page that
|
|
27
|
+
* documents hand-written markup is a page that will be copied.
|
|
28
|
+
*/
|
|
29
|
+
export default function Pill({ tone, quiet, inRow, className, children, ...rest }: {
|
|
30
|
+
/** A state, and the only kind that takes colour. Absent, it is a capability. */
|
|
31
|
+
tone?: 'info' | 'good' | 'warn' | 'bad';
|
|
32
|
+
/** A measurement. No box at all — nothing to act on, so nothing to draw. */
|
|
33
|
+
quiet?: boolean;
|
|
34
|
+
/** Beside a name in a row. Adds the gap that keeps it off the text and sets
|
|
35
|
+
* it on the baseline rather than the middle, which is where a chip next to
|
|
36
|
+
* a word wants to be. */
|
|
37
|
+
inRow?: boolean;
|
|
38
|
+
className?: string;
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
} & Omit<React.HTMLAttributes<HTMLSpanElement>, 'className' | 'children'>): import("react").JSX.Element;
|