@lukasmurdock/styles 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 +22 -0
- package/package.json +39 -0
- package/src/components.css +3376 -0
- package/src/generated/tokens.css +28 -0
- package/src/index.css +6 -0
- package/src/patterns.css +15 -0
- package/src/primitives.css +93 -0
- package/src/scripts/build-tokens.mjs +61 -0
- package/src/scripts/check-css-order.mjs +27 -0
- package/src/tokens/tokens.json +38 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
@layer tokens {
|
|
2
|
+
:root {
|
|
3
|
+
--rf-color-gray-50: #f8fafc;
|
|
4
|
+
--rf-color-gray-100: #f1f5f9;
|
|
5
|
+
--rf-color-gray-300: #cbd5e1;
|
|
6
|
+
--rf-color-gray-700: #334155;
|
|
7
|
+
--rf-color-gray-900: #0f172a;
|
|
8
|
+
--rf-color-blue-500: #2563eb;
|
|
9
|
+
--rf-color-blue-600: #1d4ed8;
|
|
10
|
+
--rf-color-red-600: #dc2626;
|
|
11
|
+
--rf-surface-default: var(--rf-color-gray-50);
|
|
12
|
+
--rf-surface-inverse: var(--rf-color-gray-900);
|
|
13
|
+
--rf-text-default: var(--rf-color-gray-900);
|
|
14
|
+
--rf-text-inverse: var(--rf-color-gray-50);
|
|
15
|
+
--rf-border-default: var(--rf-color-gray-300);
|
|
16
|
+
--rf-brand-default: var(--rf-color-blue-500);
|
|
17
|
+
--rf-brand-strong: var(--rf-color-blue-600);
|
|
18
|
+
--rf-danger-default: var(--rf-color-red-600);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
[data-theme="dark"] {
|
|
22
|
+
--rf-surface-default: var(--rf-color-gray-900);
|
|
23
|
+
--rf-surface-inverse: var(--rf-color-gray-50);
|
|
24
|
+
--rf-text-default: var(--rf-color-gray-50);
|
|
25
|
+
--rf-text-inverse: var(--rf-color-gray-900);
|
|
26
|
+
--rf-border-default: var(--rf-color-gray-700);
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/index.css
ADDED
package/src/patterns.css
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
@layer patterns {
|
|
2
|
+
.rf-field {
|
|
3
|
+
display: grid;
|
|
4
|
+
gap: 0.375rem;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.rf-input-base {
|
|
8
|
+
border: 1px solid var(--rf-border-default);
|
|
9
|
+
border-radius: 0.5rem;
|
|
10
|
+
min-height: 2.5rem;
|
|
11
|
+
padding: 0 0.75rem;
|
|
12
|
+
color: var(--rf-text-default);
|
|
13
|
+
background: var(--rf-surface-default);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
@layer primitives {
|
|
2
|
+
*,
|
|
3
|
+
*::before,
|
|
4
|
+
*::after {
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
html {
|
|
9
|
+
-moz-text-size-adjust: none;
|
|
10
|
+
-webkit-text-size-adjust: none;
|
|
11
|
+
text-size-adjust: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body,
|
|
15
|
+
h1,
|
|
16
|
+
h2,
|
|
17
|
+
h3,
|
|
18
|
+
h4,
|
|
19
|
+
p,
|
|
20
|
+
figure,
|
|
21
|
+
blockquote,
|
|
22
|
+
dl,
|
|
23
|
+
dd {
|
|
24
|
+
margin-block-end: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
ul[role="list"],
|
|
28
|
+
ol[role="list"] {
|
|
29
|
+
list-style: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
body {
|
|
33
|
+
min-height: 100vh;
|
|
34
|
+
line-height: 1.5;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
h1,
|
|
38
|
+
h2,
|
|
39
|
+
h3,
|
|
40
|
+
h4,
|
|
41
|
+
button,
|
|
42
|
+
input,
|
|
43
|
+
label {
|
|
44
|
+
line-height: 1.1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
h1,
|
|
48
|
+
h2,
|
|
49
|
+
h3,
|
|
50
|
+
h4 {
|
|
51
|
+
text-wrap: balance;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
a:not([class]) {
|
|
55
|
+
text-decoration-skip-ink: auto;
|
|
56
|
+
color: currentcolor;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
img,
|
|
60
|
+
picture {
|
|
61
|
+
max-width: 100%;
|
|
62
|
+
display: block;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
input,
|
|
66
|
+
button,
|
|
67
|
+
textarea,
|
|
68
|
+
select {
|
|
69
|
+
font-family: inherit;
|
|
70
|
+
font-size: inherit;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
textarea:not([rows]) {
|
|
74
|
+
min-height: 10em;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
:target {
|
|
78
|
+
scroll-margin-block: 5ex;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.rf-reset-button {
|
|
82
|
+
border: 0;
|
|
83
|
+
background: transparent;
|
|
84
|
+
color: inherit;
|
|
85
|
+
font: inherit;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.rf-focus-ring:focus-visible {
|
|
90
|
+
outline: 2px solid var(--rf-brand-default);
|
|
91
|
+
outline-offset: 2px;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { readFile, writeFile } from "node:fs/promises"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
const root = path.resolve(__dirname, "..")
|
|
7
|
+
const tokensPath = path.join(root, "tokens", "tokens.json")
|
|
8
|
+
const outPath = path.join(root, "generated", "tokens.css")
|
|
9
|
+
|
|
10
|
+
const json = JSON.parse(await readFile(tokensPath, "utf8"))
|
|
11
|
+
|
|
12
|
+
function flatten(obj, parent = []) {
|
|
13
|
+
const out = {}
|
|
14
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
15
|
+
const next = [...parent, key]
|
|
16
|
+
if (typeof value === "string") {
|
|
17
|
+
out[next.join(".")] = value
|
|
18
|
+
continue
|
|
19
|
+
}
|
|
20
|
+
Object.assign(out, flatten(value, next))
|
|
21
|
+
}
|
|
22
|
+
return out
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const primitives = flatten(json.color)
|
|
26
|
+
const semantic = flatten(json.semantic)
|
|
27
|
+
|
|
28
|
+
function toVarName(name) {
|
|
29
|
+
return `--rf-${name.replaceAll(".", "-")}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function resolveSemantic(value) {
|
|
33
|
+
const match = /^\{(.+)\}$/.exec(value)
|
|
34
|
+
if (!match) return value
|
|
35
|
+
return `var(${toVarName(match[1])})`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const lines = []
|
|
39
|
+
lines.push("@layer tokens {")
|
|
40
|
+
lines.push(" :root {")
|
|
41
|
+
|
|
42
|
+
for (const [name, value] of Object.entries(primitives)) {
|
|
43
|
+
lines.push(` ${toVarName(`color.${name}`)}: ${value};`)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for (const [name, value] of Object.entries(semantic)) {
|
|
47
|
+
lines.push(` ${toVarName(name)}: ${resolveSemantic(value)};`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
lines.push(" }")
|
|
51
|
+
lines.push("")
|
|
52
|
+
lines.push(' [data-theme="dark"] {')
|
|
53
|
+
lines.push(" --rf-surface-default: var(--rf-color-gray-900);")
|
|
54
|
+
lines.push(" --rf-surface-inverse: var(--rf-color-gray-50);")
|
|
55
|
+
lines.push(" --rf-text-default: var(--rf-color-gray-50);")
|
|
56
|
+
lines.push(" --rf-text-inverse: var(--rf-color-gray-900);")
|
|
57
|
+
lines.push(" --rf-border-default: var(--rf-color-gray-700);")
|
|
58
|
+
lines.push(" }")
|
|
59
|
+
lines.push("}")
|
|
60
|
+
|
|
61
|
+
await writeFile(outPath, `${lines.join("\n")}\n`)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
const indexPath = path.resolve(__dirname, "..", "index.css")
|
|
7
|
+
const css = await readFile(indexPath, "utf8")
|
|
8
|
+
|
|
9
|
+
const expected = [
|
|
10
|
+
'@import "./generated/tokens.css";',
|
|
11
|
+
'@import "./primitives.css";',
|
|
12
|
+
'@import "./patterns.css";',
|
|
13
|
+
'@import "./components.css";',
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
const indexes = expected.map((line) => css.indexOf(line))
|
|
17
|
+
if (indexes.some((n) => n === -1)) {
|
|
18
|
+
throw new Error("CSS import contract is incomplete")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
for (let i = 1; i < indexes.length; i++) {
|
|
22
|
+
if (indexes[i] < indexes[i - 1]) {
|
|
23
|
+
throw new Error("CSS import contract is out of order")
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log("CSS import order contract is valid")
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"color": {
|
|
3
|
+
"gray": {
|
|
4
|
+
"50": "#f8fafc",
|
|
5
|
+
"100": "#f1f5f9",
|
|
6
|
+
"300": "#cbd5e1",
|
|
7
|
+
"700": "#334155",
|
|
8
|
+
"900": "#0f172a"
|
|
9
|
+
},
|
|
10
|
+
"blue": {
|
|
11
|
+
"500": "#2563eb",
|
|
12
|
+
"600": "#1d4ed8"
|
|
13
|
+
},
|
|
14
|
+
"red": {
|
|
15
|
+
"600": "#dc2626"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"semantic": {
|
|
19
|
+
"surface": {
|
|
20
|
+
"default": "{color.gray.50}",
|
|
21
|
+
"inverse": "{color.gray.900}"
|
|
22
|
+
},
|
|
23
|
+
"text": {
|
|
24
|
+
"default": "{color.gray.900}",
|
|
25
|
+
"inverse": "{color.gray.50}"
|
|
26
|
+
},
|
|
27
|
+
"border": {
|
|
28
|
+
"default": "{color.gray.300}"
|
|
29
|
+
},
|
|
30
|
+
"brand": {
|
|
31
|
+
"default": "{color.blue.500}",
|
|
32
|
+
"strong": "{color.blue.600}"
|
|
33
|
+
},
|
|
34
|
+
"danger": {
|
|
35
|
+
"default": "{color.red.600}"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|