@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.
@@ -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
@@ -0,0 +1,6 @@
1
+ @layer tokens, primitives, patterns, components;
2
+
3
+ @import "./generated/tokens.css";
4
+ @import "./primitives.css";
5
+ @import "./patterns.css";
6
+ @import "./components.css";
@@ -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
+ }