tokka 0.3.1 → 0.4.1
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/compiler/index.d.ts +4 -5
- package/compiler/index.js +18 -12
- package/components/calendar.tsx +25 -19
- package/dist/index.js +200 -46
- package/package.json +1 -1
- package/systems/corporate/tokens/primitives.json +29 -1
package/compiler/index.d.ts
CHANGED
|
@@ -403,11 +403,7 @@ declare function resolveTokens(tokens: Token[], graph: Map<string, Set<string>>)
|
|
|
403
403
|
interface CSSGeneratorOptions {
|
|
404
404
|
modeSelector?: {
|
|
405
405
|
strategy: "class" | "data-attribute";
|
|
406
|
-
selectors?:
|
|
407
|
-
light: string;
|
|
408
|
-
dark: string;
|
|
409
|
-
[key: string]: string;
|
|
410
|
-
};
|
|
406
|
+
selectors?: Record<string, string>;
|
|
411
407
|
};
|
|
412
408
|
}
|
|
413
409
|
/**
|
|
@@ -443,6 +439,9 @@ declare function generateCSSOutput(tokens: ResolvedToken[], system: System, opti
|
|
|
443
439
|
declare function generateTailwindConfig(tokens: ResolvedToken[], _system: System): Record<string, any>;
|
|
444
440
|
/**
|
|
445
441
|
* Generate Tailwind config file content
|
|
442
|
+
*
|
|
443
|
+
* Note: This generates a Tailwind CSS v3-compatible config.
|
|
444
|
+
* Tailwind v4 support (CSS-first configuration) is planned for a future update.
|
|
446
445
|
*/
|
|
447
446
|
declare function generateTailwindOutput(tokens: ResolvedToken[], system: System): string;
|
|
448
447
|
|
package/compiler/index.js
CHANGED
|
@@ -419,24 +419,25 @@ function generateCSS(tokens, system, options = {}) {
|
|
|
419
419
|
output.push(" * Generated by figma-base - do not edit directly");
|
|
420
420
|
output.push(" */");
|
|
421
421
|
output.push("");
|
|
422
|
-
const
|
|
422
|
+
const defaultMode = system.modes[0];
|
|
423
|
+
const nonDefaultModes = system.modes.slice(1);
|
|
423
424
|
const rootOptions = {
|
|
424
425
|
...options,
|
|
425
426
|
modeSelector: {
|
|
426
427
|
strategy: "class",
|
|
427
428
|
selectors: {
|
|
428
|
-
|
|
429
|
-
|
|
429
|
+
...system.modes.reduce((acc, mode) => {
|
|
430
|
+
acc[mode] = mode === defaultMode ? ":root" : `.${mode}`;
|
|
431
|
+
return acc;
|
|
432
|
+
}, {}),
|
|
430
433
|
...options.modeSelector?.selectors || {}
|
|
431
434
|
}
|
|
432
435
|
}
|
|
433
436
|
};
|
|
434
|
-
output.push(generateCSSForMode(tokens,
|
|
435
|
-
for (const mode of
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
output.push(generateCSSForMode(tokens, mode, options));
|
|
439
|
-
}
|
|
437
|
+
output.push(generateCSSForMode(tokens, defaultMode, rootOptions));
|
|
438
|
+
for (const mode of nonDefaultModes) {
|
|
439
|
+
output.push("");
|
|
440
|
+
output.push(generateCSSForMode(tokens, mode, options));
|
|
440
441
|
}
|
|
441
442
|
return output.join("\n");
|
|
442
443
|
}
|
|
@@ -514,6 +515,8 @@ function generateTailwindOutput(tokens, system) {
|
|
|
514
515
|
return `/**
|
|
515
516
|
* Tailwind config for ${system.name}
|
|
516
517
|
* Generated by figma-base - do not edit directly
|
|
518
|
+
*
|
|
519
|
+
* Compatible with Tailwind CSS v3.x
|
|
517
520
|
*/
|
|
518
521
|
export default ${JSON.stringify(config, null, 2)}
|
|
519
522
|
`;
|
|
@@ -603,6 +606,9 @@ function formatColorValue(value) {
|
|
|
603
606
|
return value;
|
|
604
607
|
}
|
|
605
608
|
function formatTokenValue(token, value) {
|
|
609
|
+
if (!value) {
|
|
610
|
+
return "";
|
|
611
|
+
}
|
|
606
612
|
if (value.startsWith("{") && value.endsWith("}")) {
|
|
607
613
|
return value;
|
|
608
614
|
}
|
|
@@ -627,7 +633,7 @@ function generateFigmaTokens(tokens, _system) {
|
|
|
627
633
|
current = current[parts[i]];
|
|
628
634
|
}
|
|
629
635
|
const lastPart = parts[parts.length - 1];
|
|
630
|
-
const rawValue = token.resolvedValue || token.value;
|
|
636
|
+
const rawValue = token.resolvedValue || token.value || "";
|
|
631
637
|
const formattedValue = formatTokenValue(token, rawValue);
|
|
632
638
|
current[lastPart] = {
|
|
633
639
|
value: formattedValue,
|
|
@@ -647,7 +653,7 @@ function generateFigmaTokens(tokens, _system) {
|
|
|
647
653
|
current = current[parts[i]];
|
|
648
654
|
}
|
|
649
655
|
const lastPart = parts[parts.length - 1];
|
|
650
|
-
const rawValue = token.references && token.references.length > 0 ? `{${token.references[0]}}` : token.resolvedValue || token.value;
|
|
656
|
+
const rawValue = token.references && token.references.length > 0 ? `{${token.references[0]}}` : token.resolvedValue || token.value || "";
|
|
651
657
|
const formattedValue = formatTokenValue(token, rawValue);
|
|
652
658
|
current[lastPart] = {
|
|
653
659
|
value: formattedValue,
|
|
@@ -668,7 +674,7 @@ function generateFigmaTokens(tokens, _system) {
|
|
|
668
674
|
current = current[parts[i]];
|
|
669
675
|
}
|
|
670
676
|
const lastPart = parts[parts.length - 1];
|
|
671
|
-
const rawValue = token.references && token.references.length > 0 ? `{${token.references[0]}}` : token.resolvedValue || token.value;
|
|
677
|
+
const rawValue = token.references && token.references.length > 0 ? `{${token.references[0]}}` : token.resolvedValue || token.value || "";
|
|
672
678
|
const formattedValue = formatTokenValue(token, rawValue);
|
|
673
679
|
current[lastPart] = {
|
|
674
680
|
value: formattedValue,
|
package/components/calendar.tsx
CHANGED
|
@@ -22,37 +22,43 @@ function Calendar({
|
|
|
22
22
|
caption: "flex justify-center pt-1 relative items-center",
|
|
23
23
|
caption_label: "text-sm font-medium",
|
|
24
24
|
nav: "space-x-1 flex items-center",
|
|
25
|
-
|
|
25
|
+
button_previous: cn(
|
|
26
26
|
buttonVariants({ variant: "outline" }),
|
|
27
|
-
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
|
27
|
+
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute left-1"
|
|
28
28
|
),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
button_next: cn(
|
|
30
|
+
buttonVariants({ variant: "outline" }),
|
|
31
|
+
"size-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute right-1"
|
|
32
|
+
),
|
|
33
|
+
month_grid: "w-full border-collapse space-y-1",
|
|
34
|
+
weekdays: "flex",
|
|
35
|
+
weekday:
|
|
34
36
|
"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
week: "flex w-full mt-2",
|
|
38
|
+
day: "size-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
|
|
39
|
+
day_button: cn(
|
|
38
40
|
buttonVariants({ variant: "ghost" }),
|
|
39
41
|
"size-9 p-0 font-normal aria-selected:opacity-100"
|
|
40
42
|
),
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
range_end: "day-range-end",
|
|
44
|
+
selected:
|
|
43
45
|
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
today: "bg-accent text-accent-foreground",
|
|
47
|
+
outside:
|
|
46
48
|
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
disabled: "text-muted-foreground opacity-50",
|
|
50
|
+
range_middle:
|
|
49
51
|
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
|
50
|
-
|
|
52
|
+
hidden: "invisible",
|
|
51
53
|
...classNames,
|
|
52
54
|
}}
|
|
53
55
|
components={{
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
Chevron: (props) => {
|
|
57
|
+
if (props.orientation === "left") {
|
|
58
|
+
return <ChevronLeft className="size-4" />
|
|
59
|
+
}
|
|
60
|
+
return <ChevronRight className="size-4" />
|
|
61
|
+
},
|
|
56
62
|
}}
|
|
57
63
|
{...props}
|
|
58
64
|
/>
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { Command } from "commander";
|
|
|
7
7
|
import fs from "fs-extra";
|
|
8
8
|
import path from "path";
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
|
+
import { execSync } from "child_process";
|
|
10
11
|
import prompts from "prompts";
|
|
11
12
|
import ora from "ora";
|
|
12
13
|
import kleur from "kleur";
|
|
@@ -53,7 +54,34 @@ Setting up ${selectedSystem.name}...
|
|
|
53
54
|
await fs.ensureDir(path.join(cwd, "dist"));
|
|
54
55
|
if (options.packageManager !== "skip") {
|
|
55
56
|
spinner.start("Installing dependencies...");
|
|
56
|
-
|
|
57
|
+
try {
|
|
58
|
+
const REQUIRED_DEPS = [
|
|
59
|
+
"@radix-ui/react-slot",
|
|
60
|
+
"class-variance-authority",
|
|
61
|
+
"clsx",
|
|
62
|
+
"tailwind-merge"
|
|
63
|
+
];
|
|
64
|
+
const DEV_DEPS = ["tailwindcss", "postcss", "autoprefixer"];
|
|
65
|
+
let installCmd;
|
|
66
|
+
let devInstallCmd;
|
|
67
|
+
if (options.packageManager === "npm") {
|
|
68
|
+
installCmd = `npm install ${REQUIRED_DEPS.join(" ")}`;
|
|
69
|
+
devInstallCmd = `npm install -D ${DEV_DEPS.join(" ")}`;
|
|
70
|
+
} else if (options.packageManager === "yarn") {
|
|
71
|
+
installCmd = `yarn add ${REQUIRED_DEPS.join(" ")}`;
|
|
72
|
+
devInstallCmd = `yarn add -D ${DEV_DEPS.join(" ")}`;
|
|
73
|
+
} else {
|
|
74
|
+
installCmd = `pnpm add ${REQUIRED_DEPS.join(" ")}`;
|
|
75
|
+
devInstallCmd = `pnpm add -D ${DEV_DEPS.join(" ")}`;
|
|
76
|
+
}
|
|
77
|
+
execSync(installCmd, { cwd, stdio: "pipe" });
|
|
78
|
+
execSync(devInstallCmd, { cwd, stdio: "pipe" });
|
|
79
|
+
spinner.succeed("Dependencies installed");
|
|
80
|
+
} catch (error) {
|
|
81
|
+
spinner.warn("Failed to install dependencies - please install manually");
|
|
82
|
+
console.log(kleur.dim(" npm install @radix-ui/react-slot class-variance-authority clsx tailwind-merge"));
|
|
83
|
+
console.log(kleur.dim(" npm install -D tailwindcss postcss autoprefixer"));
|
|
84
|
+
}
|
|
57
85
|
}
|
|
58
86
|
spinner.start("Building tokens...");
|
|
59
87
|
try {
|
|
@@ -86,6 +114,36 @@ Setting up ${selectedSystem.name}...
|
|
|
86
114
|
console.error(kleur.red(error.message));
|
|
87
115
|
process.exit(1);
|
|
88
116
|
}
|
|
117
|
+
spinner.start("Creating Tailwind config...");
|
|
118
|
+
try {
|
|
119
|
+
const tailwindConfig = `/** @type {import('tailwindcss').Config} */
|
|
120
|
+
module.exports = {
|
|
121
|
+
darkMode: ["class"],
|
|
122
|
+
content: [
|
|
123
|
+
"./src/**/*.{ts,tsx}",
|
|
124
|
+
"./components/**/*.{ts,tsx}",
|
|
125
|
+
"./app/**/*.{ts,tsx}",
|
|
126
|
+
],
|
|
127
|
+
theme: {
|
|
128
|
+
extend: require("./dist/tailwind/tokens.tailwind.js"),
|
|
129
|
+
},
|
|
130
|
+
plugins: [],
|
|
131
|
+
}
|
|
132
|
+
`;
|
|
133
|
+
await fs.writeFile(path.join(cwd, "tailwind.config.js"), tailwindConfig);
|
|
134
|
+
const postcssConfig = `module.exports = {
|
|
135
|
+
plugins: {
|
|
136
|
+
tailwindcss: {},
|
|
137
|
+
autoprefixer: {},
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
`;
|
|
141
|
+
await fs.writeFile(path.join(cwd, "postcss.config.js"), postcssConfig);
|
|
142
|
+
spinner.succeed("Tailwind config created (v3 format)");
|
|
143
|
+
console.log(kleur.dim(" Note: Tailwind v4 support coming soon"));
|
|
144
|
+
} catch (error) {
|
|
145
|
+
spinner.warn("Failed to create Tailwind config - please create manually");
|
|
146
|
+
}
|
|
89
147
|
const lockFile = {
|
|
90
148
|
version: "1",
|
|
91
149
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -98,6 +156,15 @@ Setting up ${selectedSystem.name}...
|
|
|
98
156
|
}
|
|
99
157
|
};
|
|
100
158
|
await fs.writeJSON(path.join(cwd, "tokka.lock"), lockFile, { spaces: 2 });
|
|
159
|
+
if (options.demo) {
|
|
160
|
+
spinner.start("Creating demo page...");
|
|
161
|
+
try {
|
|
162
|
+
await createDemoApp(cwd, selectedSystem.name);
|
|
163
|
+
spinner.succeed("Demo page created");
|
|
164
|
+
} catch (error) {
|
|
165
|
+
spinner.warn("Failed to create demo page - you can create it manually");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
101
168
|
console.log(kleur.green().bold("\n\u2713 All done!\n"));
|
|
102
169
|
console.log("Next steps:");
|
|
103
170
|
console.log(kleur.cyan(" 1. ") + "Import tokens in your CSS:");
|
|
@@ -105,6 +172,10 @@ Setting up ${selectedSystem.name}...
|
|
|
105
172
|
console.log(kleur.cyan(" 2. ") + "Add components:");
|
|
106
173
|
console.log(kleur.dim(" tokka add button input card"));
|
|
107
174
|
console.log(kleur.cyan(" 3. ") + "Start building!");
|
|
175
|
+
if (options.demo) {
|
|
176
|
+
console.log(kleur.cyan(" 4. ") + "Check out the demo page:");
|
|
177
|
+
console.log(kleur.dim(" Open demo.html in your browser"));
|
|
178
|
+
}
|
|
108
179
|
console.log("");
|
|
109
180
|
}
|
|
110
181
|
async function loadSystems(systemsDir) {
|
|
@@ -121,6 +192,111 @@ async function loadSystems(systemsDir) {
|
|
|
121
192
|
}
|
|
122
193
|
return systems;
|
|
123
194
|
}
|
|
195
|
+
async function createDemoApp(cwd, systemName) {
|
|
196
|
+
const demoHtml = `<!DOCTYPE html>
|
|
197
|
+
<html lang="en" class="light">
|
|
198
|
+
<head>
|
|
199
|
+
<meta charset="UTF-8">
|
|
200
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
201
|
+
<title>tokka Demo - ${systemName}</title>
|
|
202
|
+
<link rel="stylesheet" href="./dist/css/tokens.css">
|
|
203
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
204
|
+
<script>
|
|
205
|
+
tailwind.config = ${JSON.stringify(
|
|
206
|
+
{
|
|
207
|
+
darkMode: ["class"],
|
|
208
|
+
theme: {
|
|
209
|
+
extend: {}
|
|
210
|
+
// Token classes will work via CSS custom properties
|
|
211
|
+
}
|
|
212
|
+
},
|
|
213
|
+
null,
|
|
214
|
+
2
|
|
215
|
+
)}
|
|
216
|
+
</script>
|
|
217
|
+
<style>
|
|
218
|
+
body {
|
|
219
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
220
|
+
}
|
|
221
|
+
</style>
|
|
222
|
+
</head>
|
|
223
|
+
<body class="bg-background text-foreground">
|
|
224
|
+
<main class="min-h-screen p-8">
|
|
225
|
+
<div class="max-w-4xl mx-auto space-y-8">
|
|
226
|
+
<div class="space-y-2">
|
|
227
|
+
<h1 class="text-4xl font-bold">tokka Demo</h1>
|
|
228
|
+
<p class="text-lg text-muted-foreground">
|
|
229
|
+
${systemName} design system
|
|
230
|
+
</p>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<div class="bg-card text-card-foreground border border-border rounded-lg p-6 space-y-4">
|
|
234
|
+
<div>
|
|
235
|
+
<h2 class="text-xl font-semibold">Buttons</h2>
|
|
236
|
+
<p class="text-sm text-muted-foreground">Different button variants using semantic tokens</p>
|
|
237
|
+
</div>
|
|
238
|
+
<div class="flex flex-wrap gap-4">
|
|
239
|
+
<button class="bg-primary text-primary-foreground px-4 py-2 rounded-md hover:bg-primary/90">
|
|
240
|
+
Default
|
|
241
|
+
</button>
|
|
242
|
+
<button class="bg-secondary text-secondary-foreground px-4 py-2 rounded-md hover:bg-secondary/80">
|
|
243
|
+
Secondary
|
|
244
|
+
</button>
|
|
245
|
+
<button class="bg-destructive text-destructive-foreground px-4 py-2 rounded-md hover:bg-destructive/90">
|
|
246
|
+
Destructive
|
|
247
|
+
</button>
|
|
248
|
+
<button class="border border-input bg-background px-4 py-2 rounded-md hover:bg-accent hover:text-accent-foreground">
|
|
249
|
+
Outline
|
|
250
|
+
</button>
|
|
251
|
+
</div>
|
|
252
|
+
</div>
|
|
253
|
+
|
|
254
|
+
<div class="bg-card text-card-foreground border border-border rounded-lg p-6 space-y-4">
|
|
255
|
+
<div>
|
|
256
|
+
<h2 class="text-xl font-semibold">Inputs</h2>
|
|
257
|
+
<p class="text-sm text-muted-foreground">Input fields using semantic tokens</p>
|
|
258
|
+
</div>
|
|
259
|
+
<div class="space-y-4">
|
|
260
|
+
<input
|
|
261
|
+
type="text"
|
|
262
|
+
placeholder="Default input"
|
|
263
|
+
class="w-full px-3 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring"
|
|
264
|
+
/>
|
|
265
|
+
<input
|
|
266
|
+
type="email"
|
|
267
|
+
placeholder="Email input"
|
|
268
|
+
class="w-full px-3 py-2 border border-input rounded-md bg-background focus:outline-none focus:ring-2 focus:ring-ring"
|
|
269
|
+
/>
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
|
|
273
|
+
<div class="bg-card text-card-foreground border border-border rounded-lg p-6 space-y-4">
|
|
274
|
+
<div>
|
|
275
|
+
<h2 class="text-xl font-semibold">Theme Toggle</h2>
|
|
276
|
+
<p class="text-sm text-muted-foreground">Switch between light and dark mode</p>
|
|
277
|
+
</div>
|
|
278
|
+
<button
|
|
279
|
+
onclick="document.documentElement.classList.toggle('dark'); document.documentElement.classList.toggle('light');"
|
|
280
|
+
class="bg-secondary text-secondary-foreground px-4 py-2 rounded-md hover:bg-secondary/80"
|
|
281
|
+
>
|
|
282
|
+
Toggle Dark Mode
|
|
283
|
+
</button>
|
|
284
|
+
</div>
|
|
285
|
+
|
|
286
|
+
<div class="bg-muted text-muted-foreground border border-border rounded-lg p-6">
|
|
287
|
+
<div class="space-y-2">
|
|
288
|
+
<h3 class="font-semibold text-foreground">Next Steps</h3>
|
|
289
|
+
<p class="text-sm">Add React components with: <code class="bg-background px-2 py-1 rounded">tokka add button input card</code></p>
|
|
290
|
+
<p class="text-sm">View all components: <code class="bg-background px-2 py-1 rounded">tokka list components</code></p>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
</main>
|
|
295
|
+
</body>
|
|
296
|
+
</html>
|
|
297
|
+
`;
|
|
298
|
+
await fs.writeFile(path.join(cwd, "demo.html"), demoHtml);
|
|
299
|
+
}
|
|
124
300
|
|
|
125
301
|
// src/commands/add.ts
|
|
126
302
|
import fs2 from "fs-extra";
|
|
@@ -188,6 +364,13 @@ async function addCommand(components) {
|
|
|
188
364
|
const spinner = ora2();
|
|
189
365
|
const componentsDir = path2.join(cwd, "components");
|
|
190
366
|
await fs2.ensureDir(componentsDir);
|
|
367
|
+
const libDir = path2.join(componentsDir, "lib");
|
|
368
|
+
await fs2.ensureDir(libDir);
|
|
369
|
+
const utilsSource = path2.join(__dirname2, "../components/lib/utils.ts");
|
|
370
|
+
const utilsTarget = path2.join(libDir, "utils.ts");
|
|
371
|
+
if (!await fs2.pathExists(utilsTarget)) {
|
|
372
|
+
await fs2.copy(utilsSource, utilsTarget);
|
|
373
|
+
}
|
|
191
374
|
for (const component of components) {
|
|
192
375
|
if (!COMPONENT_REGISTRY[component]) {
|
|
193
376
|
console.error(kleur2.red(`\u2716 Component "${component}" not found`));
|
|
@@ -393,13 +576,10 @@ async function listSystems(json) {
|
|
|
393
576
|
}
|
|
394
577
|
}
|
|
395
578
|
async function listComponents(json) {
|
|
396
|
-
const components =
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
{ name: "dialog", status: "coming-soon" },
|
|
401
|
-
{ name: "select", status: "coming-soon" }
|
|
402
|
-
];
|
|
579
|
+
const components = Object.keys(COMPONENT_REGISTRY).map((name) => ({
|
|
580
|
+
name,
|
|
581
|
+
status: "available"
|
|
582
|
+
}));
|
|
403
583
|
if (json) {
|
|
404
584
|
console.log(JSON.stringify(components, null, 2));
|
|
405
585
|
return;
|
|
@@ -426,56 +606,31 @@ async function loadSystemsMetadata(systemsDir) {
|
|
|
426
606
|
return systems;
|
|
427
607
|
}
|
|
428
608
|
|
|
429
|
-
// src/commands/
|
|
609
|
+
// src/commands/enable.ts
|
|
430
610
|
import fs7 from "fs-extra";
|
|
431
611
|
import path7 from "path";
|
|
432
612
|
import kleur7 from "kleur";
|
|
433
|
-
async function
|
|
434
|
-
if (
|
|
435
|
-
console.error(kleur7.red(`\u2716 Unknown
|
|
613
|
+
async function enableCommand(feature) {
|
|
614
|
+
if (feature !== "advanced") {
|
|
615
|
+
console.error(kleur7.red(`\u2716 Unknown feature: ${feature}`));
|
|
436
616
|
process.exit(1);
|
|
437
617
|
}
|
|
438
618
|
const cwd = process.cwd();
|
|
439
619
|
const configPath = path7.join(cwd, ".figmabase");
|
|
620
|
+
console.log(kleur7.cyan("\n\u{1F680} Enabling advanced mode...\n"));
|
|
440
621
|
let config = {};
|
|
441
622
|
if (await fs7.pathExists(configPath)) {
|
|
442
623
|
config = await fs7.readJSON(configPath);
|
|
443
624
|
}
|
|
444
|
-
if (!config.advanced) {
|
|
445
|
-
console.error(kleur7.red("\n\u2716 Type generation requires advanced mode"));
|
|
446
|
-
console.error(kleur7.dim(" Run: tokka enable advanced"));
|
|
447
|
-
process.exit(1);
|
|
448
|
-
}
|
|
449
|
-
console.log(kleur7.cyan("\n\u{1F527} Generating TypeScript types from manifests...\n"));
|
|
450
|
-
console.log(kleur7.yellow("\u26A0 Type generation not yet implemented"));
|
|
451
|
-
console.log(kleur7.dim(" Coming in a future update"));
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// src/commands/enable.ts
|
|
455
|
-
import fs8 from "fs-extra";
|
|
456
|
-
import path8 from "path";
|
|
457
|
-
import kleur8 from "kleur";
|
|
458
|
-
async function enableCommand(feature) {
|
|
459
|
-
if (feature !== "advanced") {
|
|
460
|
-
console.error(kleur8.red(`\u2716 Unknown feature: ${feature}`));
|
|
461
|
-
process.exit(1);
|
|
462
|
-
}
|
|
463
|
-
const cwd = process.cwd();
|
|
464
|
-
const configPath = path8.join(cwd, ".figmabase");
|
|
465
|
-
console.log(kleur8.cyan("\n\u{1F680} Enabling advanced mode...\n"));
|
|
466
|
-
let config = {};
|
|
467
|
-
if (await fs8.pathExists(configPath)) {
|
|
468
|
-
config = await fs8.readJSON(configPath);
|
|
469
|
-
}
|
|
470
625
|
config.advanced = true;
|
|
471
|
-
await
|
|
472
|
-
const componentsDir =
|
|
473
|
-
await
|
|
474
|
-
console.log(
|
|
626
|
+
await fs7.writeJSON(configPath, config, { spaces: 2 });
|
|
627
|
+
const componentsDir = path7.join(cwd, "tokens/components");
|
|
628
|
+
await fs7.ensureDir(componentsDir);
|
|
629
|
+
console.log(kleur7.green("\u2713 Advanced mode enabled\n"));
|
|
475
630
|
console.log("Advanced features now available:");
|
|
476
|
-
console.log(
|
|
477
|
-
console.log(
|
|
478
|
-
console.log(
|
|
631
|
+
console.log(kleur7.cyan(" \u2022 ") + "tokka validate - Strict validation");
|
|
632
|
+
console.log(kleur7.cyan(" \u2022 ") + "tokka gen types - Generate TypeScript types");
|
|
633
|
+
console.log(kleur7.cyan(" \u2022 ") + "Component token catalogs (tokens/components/)");
|
|
479
634
|
console.log("");
|
|
480
635
|
}
|
|
481
636
|
|
|
@@ -489,5 +644,4 @@ program.command("list").description("List available systems or components").argu
|
|
|
489
644
|
program.command("export").description("Export Figma artifacts").argument("<target>", "Export target (figma)").option("-o, --output <dir>", "Output directory").action(exportCommand);
|
|
490
645
|
program.command("enable").description("Enable advanced features").argument("<feature>", "Feature to enable (advanced)").action(enableCommand);
|
|
491
646
|
program.command("validate").description("Validate tokens and manifests (requires advanced mode)").action(validateCommand);
|
|
492
|
-
program.command("gen").description("Generate code from manifests").argument("<target>", "What to generate (types)").action(genCommand);
|
|
493
647
|
program.parse();
|
package/package.json
CHANGED
|
@@ -28,6 +28,20 @@
|
|
|
28
28
|
"source": "primitive",
|
|
29
29
|
"value": "0 0% 100%"
|
|
30
30
|
},
|
|
31
|
+
{
|
|
32
|
+
"id": "color.blue.600",
|
|
33
|
+
"type": "color",
|
|
34
|
+
"description": "Dark brand blue",
|
|
35
|
+
"source": "primitive",
|
|
36
|
+
"value": "220 90% 48%"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "color.red.600",
|
|
40
|
+
"type": "color",
|
|
41
|
+
"description": "Dark error red",
|
|
42
|
+
"source": "primitive",
|
|
43
|
+
"value": "0 72% 45%"
|
|
44
|
+
},
|
|
31
45
|
{
|
|
32
46
|
"id": "space.1",
|
|
33
47
|
"type": "dimension",
|
|
@@ -42,12 +56,19 @@
|
|
|
42
56
|
"source": "primitive",
|
|
43
57
|
"value": "0.5rem"
|
|
44
58
|
},
|
|
59
|
+
{
|
|
60
|
+
"id": "space.3",
|
|
61
|
+
"type": "dimension",
|
|
62
|
+
"description": "Medium spacing",
|
|
63
|
+
"source": "primitive",
|
|
64
|
+
"value": "0.75rem"
|
|
65
|
+
},
|
|
45
66
|
{
|
|
46
67
|
"id": "space.4",
|
|
47
68
|
"type": "dimension",
|
|
48
69
|
"description": "Base spacing",
|
|
49
70
|
"source": "primitive",
|
|
50
|
-
"value": "
|
|
71
|
+
"value": "1rem"
|
|
51
72
|
},
|
|
52
73
|
{
|
|
53
74
|
"id": "radius.none",
|
|
@@ -55,6 +76,13 @@
|
|
|
55
76
|
"description": "No radius",
|
|
56
77
|
"source": "primitive",
|
|
57
78
|
"value": "0"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "radius.sm",
|
|
82
|
+
"type": "radius",
|
|
83
|
+
"description": "Small radius",
|
|
84
|
+
"source": "primitive",
|
|
85
|
+
"value": "0.125rem"
|
|
58
86
|
}
|
|
59
87
|
]
|
|
60
88
|
}
|