typewritingclass-compiler 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -31,15 +31,12 @@ import 'virtual:twc.css'
31
31
  ```ts
32
32
  twcPlugin({
33
33
  strict: true, // Error on dynamic values not wrapped with dynamic() (default: true)
34
- theme: { // Custom theme input
35
- colors: { brand: { 500: '#6366f1' } },
36
- },
37
34
  })
38
35
  ```
39
36
 
40
37
  ## How it works
41
38
 
42
- 1. **Static analysis** — the Rust extractor scans TS/JS files for `cx()`, `when()`, and utility calls
39
+ 1. **Static analysis** — the Rust extractor scans TS/JS files for `tw`, `cx()`, `when()`, and utility calls
43
40
  2. **CSS generation** — extracted rules are compiled into deterministic class names and CSS declarations
44
41
  3. **Code transform** — utility call sites are replaced with the generated class name strings
45
42
  4. **Virtual module** — `virtual:twc.css` aggregates all extracted CSS, respecting `@layer` ordering
package/package.json CHANGED
@@ -1,18 +1,27 @@
1
1
  {
2
2
  "name": "typewritingclass-compiler",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/corysimmons/typewritingclass",
8
+ "directory": "packages/typewritingclass-compiler"
9
+ },
5
10
  "exports": {
6
11
  ".": {
7
12
  "types": "./src/index.ts",
8
13
  "default": "./src/index.ts"
14
+ },
15
+ "./loadTheme": {
16
+ "types": "./src/loadTheme.ts",
17
+ "default": "./src/loadTheme.ts"
9
18
  }
10
19
  },
11
20
  "files": [
12
21
  "src"
13
22
  ],
14
23
  "napi": {
15
- "name": "typewritingclass-compiler-native",
24
+ "name": "index",
16
25
  "triples": {}
17
26
  },
18
27
  "peerDependencies": {
@@ -20,7 +29,7 @@
20
29
  },
21
30
  "dependencies": {
22
31
  "magic-string": "^0.30.21",
23
- "typewritingclass": "0.2.0"
32
+ "typewritingclass": "0.2.2"
24
33
  },
25
34
  "devDependencies": {
26
35
  "@types/node": "^25.2.2",
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ import MagicString from 'magic-string'
3
3
  import { createRequire } from 'module'
4
4
  import { resolve, dirname } from 'path'
5
5
  import { fileURLToPath } from 'url'
6
+ import { loadTheme } from './loadTheme.ts'
6
7
 
7
8
  // Load native addon
8
9
  const require = createRequire(import.meta.url)
@@ -146,117 +147,3 @@ export default function twcPlugin(options?: TwcPluginOptions): Plugin {
146
147
  }
147
148
  }
148
149
 
149
- /**
150
- * Load theme data from the typewritingclass package.
151
- * This dynamically imports the theme modules so values come from the TS source,
152
- * not hardcoded in the compiler.
153
- */
154
- async function loadTheme(): Promise<import('../index.d.ts').ThemeInput> {
155
- // Import all theme modules from the TS package
156
- const [colorsModule, spacingModule, typographyModule, sizesModule, shadowsModule, bordersModule] =
157
- await Promise.all([
158
- import('typewritingclass/theme/colors'),
159
- import('typewritingclass/theme'),
160
- import('typewritingclass/theme/typography'),
161
- import('typewritingclass/theme/sizes'),
162
- import('typewritingclass/theme/shadows'),
163
- import('typewritingclass/theme/borders'),
164
- ])
165
-
166
- // Build color scales map
167
- const colorScaleNames = [
168
- 'slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber',
169
- 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue',
170
- 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose',
171
- ]
172
- const colors: Record<string, Record<string, string>> = {}
173
- for (const name of colorScaleNames) {
174
- const scale = (colorsModule as Record<string, any>)[name]
175
- if (scale && typeof scale === 'object') {
176
- colors[name] = {}
177
- for (const [shade, hex] of Object.entries(scale)) {
178
- colors[name][String(shade)] = hex as string
179
- }
180
- }
181
- }
182
-
183
- // Named colors
184
- const namedColors: Record<string, string> = {
185
- white: colorsModule.white,
186
- black: colorsModule.black,
187
- transparent: colorsModule.transparent,
188
- currentColor: colorsModule.currentColor,
189
- }
190
-
191
- // Spacing scale
192
- const { spacing: spacingNs } = spacingModule as any
193
- const spacing: Record<string, string> = {}
194
- if (spacingNs && spacingNs.spacingScale) {
195
- for (const [key, val] of Object.entries(spacingNs.spacingScale)) {
196
- spacing[String(key)] = val as string
197
- }
198
- }
199
-
200
- // Text sizes
201
- const textSizeNames = ['xs', 'sm', 'base', 'lg', 'xl', '_2xl', '_3xl', '_4xl', '_5xl', '_6xl', '_7xl', '_8xl', '_9xl']
202
- const textSizes: Record<string, { fontSize: string; lineHeight: string }> = {}
203
- for (const name of textSizeNames) {
204
- const token = (typographyModule as Record<string, any>)[name]
205
- if (token && typeof token === 'object' && 'fontSize' in token) {
206
- textSizes[name] = { fontSize: token.fontSize, lineHeight: token.lineHeight }
207
- }
208
- }
209
-
210
- // Font weights
211
- const weightNames = ['thin', 'extralight', 'light', 'normal', 'medium', 'semibold', 'bold', 'extrabold', 'black_']
212
- const fontWeights: Record<string, string> = {}
213
- for (const name of weightNames) {
214
- const val = (typographyModule as Record<string, any>)[name]
215
- if (typeof val === 'string') {
216
- fontWeights[name] = val
217
- }
218
- }
219
-
220
- // Border radii
221
- const radiusNames = ['none', 'sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', '_3xl', 'full']
222
- const radii: Record<string, string> = {}
223
- for (const name of radiusNames) {
224
- const val = (bordersModule as Record<string, any>)[name]
225
- if (typeof val === 'string') {
226
- radii[name] = val
227
- }
228
- }
229
-
230
- // Shadows
231
- const shadowNames = ['sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', 'inner', 'none']
232
- const shadows: Record<string, string> = {}
233
- for (const name of shadowNames) {
234
- const val = (shadowsModule as Record<string, any>)[name]
235
- if (typeof val === 'string') {
236
- shadows[name] = val
237
- }
238
- }
239
-
240
- // Sizes
241
- const sizeNames = ['full', 'screen', 'screenH', 'min', 'max', 'fit', 'auto']
242
- const sizes: Record<string, string> = {}
243
- for (const name of sizeNames) {
244
- const val = (sizesModule as Record<string, any>)[name]
245
- if (typeof val === 'string') {
246
- sizes[name] = val
247
- }
248
- }
249
-
250
- return {
251
- colors: JSON.stringify(colors),
252
- namedColors: JSON.stringify(namedColors),
253
- spacing: JSON.stringify(spacing),
254
- textSizes: JSON.stringify(textSizes),
255
- fontWeights: JSON.stringify(fontWeights),
256
- radii: JSON.stringify(radii),
257
- shadows: JSON.stringify(shadows),
258
- sizes: JSON.stringify(sizes),
259
- defaultRadius: radii['DEFAULT'] ?? '0.25rem',
260
- defaultShadow: shadows['DEFAULT'] ?? '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
261
- }
262
- }
@@ -0,0 +1,116 @@
1
+ import type { ThemeInput } from '../index.d.ts'
2
+
3
+ /**
4
+ * Load theme data from the typewritingclass package.
5
+ * This dynamically imports the theme modules so values come from the TS source,
6
+ * not hardcoded in the compiler.
7
+ */
8
+ export async function loadTheme(): Promise<ThemeInput> {
9
+ // Import all theme modules from the TS package
10
+ const [colorsModule, spacingModule, typographyModule, sizesModule, shadowsModule, bordersModule] =
11
+ await Promise.all([
12
+ import('typewritingclass/theme/colors'),
13
+ import('typewritingclass/theme'),
14
+ import('typewritingclass/theme/typography'),
15
+ import('typewritingclass/theme/sizes'),
16
+ import('typewritingclass/theme/shadows'),
17
+ import('typewritingclass/theme/borders'),
18
+ ])
19
+
20
+ // Build color scales map
21
+ const colorScaleNames = [
22
+ 'slate', 'gray', 'zinc', 'neutral', 'stone', 'red', 'orange', 'amber',
23
+ 'yellow', 'lime', 'green', 'emerald', 'teal', 'cyan', 'sky', 'blue',
24
+ 'indigo', 'violet', 'purple', 'fuchsia', 'pink', 'rose',
25
+ ]
26
+ const colors: Record<string, Record<string, string>> = {}
27
+ for (const name of colorScaleNames) {
28
+ const scale = (colorsModule as Record<string, any>)[name]
29
+ if (scale && typeof scale === 'object') {
30
+ colors[name] = {}
31
+ for (const [shade, hex] of Object.entries(scale)) {
32
+ colors[name][String(shade)] = hex as string
33
+ }
34
+ }
35
+ }
36
+
37
+ // Named colors
38
+ const namedColors: Record<string, string> = {
39
+ white: colorsModule.white,
40
+ black: colorsModule.black,
41
+ transparent: colorsModule.transparent,
42
+ currentColor: colorsModule.currentColor,
43
+ }
44
+
45
+ // Spacing scale
46
+ const { spacing: spacingNs } = spacingModule as any
47
+ const spacing: Record<string, string> = {}
48
+ if (spacingNs && spacingNs.spacingScale) {
49
+ for (const [key, val] of Object.entries(spacingNs.spacingScale)) {
50
+ spacing[String(key)] = val as string
51
+ }
52
+ }
53
+
54
+ // Text sizes
55
+ const textSizeNames = ['xs', 'sm', 'base', 'lg', 'xl', '_2xl', '_3xl', '_4xl', '_5xl', '_6xl', '_7xl', '_8xl', '_9xl']
56
+ const textSizes: Record<string, { fontSize: string; lineHeight: string }> = {}
57
+ for (const name of textSizeNames) {
58
+ const token = (typographyModule as Record<string, any>)[name]
59
+ if (token && typeof token === 'object' && 'fontSize' in token) {
60
+ textSizes[name] = { fontSize: token.fontSize, lineHeight: token.lineHeight }
61
+ }
62
+ }
63
+
64
+ // Font weights
65
+ const weightNames = ['thin', 'extralight', 'light', 'normal', 'medium', 'semibold', 'bold', 'extrabold', 'black_']
66
+ const fontWeights: Record<string, string> = {}
67
+ for (const name of weightNames) {
68
+ const val = (typographyModule as Record<string, any>)[name]
69
+ if (typeof val === 'string') {
70
+ fontWeights[name] = val
71
+ }
72
+ }
73
+
74
+ // Border radii
75
+ const radiusNames = ['none', 'sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', '_3xl', 'full']
76
+ const radii: Record<string, string> = {}
77
+ for (const name of radiusNames) {
78
+ const val = (bordersModule as Record<string, any>)[name]
79
+ if (typeof val === 'string') {
80
+ radii[name] = val
81
+ }
82
+ }
83
+
84
+ // Shadows
85
+ const shadowNames = ['sm', 'DEFAULT', 'md', 'lg', 'xl', '_2xl', 'inner', 'none']
86
+ const shadows: Record<string, string> = {}
87
+ for (const name of shadowNames) {
88
+ const val = (shadowsModule as Record<string, any>)[name]
89
+ if (typeof val === 'string') {
90
+ shadows[name] = val
91
+ }
92
+ }
93
+
94
+ // Sizes
95
+ const sizeNames = ['full', 'screen', 'screenH', 'min', 'max', 'fit', 'auto']
96
+ const sizes: Record<string, string> = {}
97
+ for (const name of sizeNames) {
98
+ const val = (sizesModule as Record<string, any>)[name]
99
+ if (typeof val === 'string') {
100
+ sizes[name] = val
101
+ }
102
+ }
103
+
104
+ return {
105
+ colors: JSON.stringify(colors),
106
+ namedColors: JSON.stringify(namedColors),
107
+ spacing: JSON.stringify(spacing),
108
+ textSizes: JSON.stringify(textSizes),
109
+ fontWeights: JSON.stringify(fontWeights),
110
+ radii: JSON.stringify(radii),
111
+ shadows: JSON.stringify(shadows),
112
+ sizes: JSON.stringify(sizes),
113
+ defaultRadius: radii['DEFAULT'] ?? '0.25rem',
114
+ defaultShadow: shadows['DEFAULT'] ?? '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
115
+ }
116
+ }