@nibin-org/tokens 1.0.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/dist/index.js ADDED
@@ -0,0 +1,662 @@
1
+ "use client";
2
+
3
+ // src/components/TokenDocumentation.tsx
4
+ import { useState as useState5, useMemo } from "react";
5
+
6
+ // src/components/ColorGrid.tsx
7
+ import { useState, useCallback } from "react";
8
+
9
+ // src/utils.ts
10
+ function isTokenValue(obj) {
11
+ return typeof obj === "object" && obj !== null && "value" in obj && "type" in obj;
12
+ }
13
+ function parseNumericValue(value) {
14
+ const match = value.match(/^([\d.]+)/);
15
+ return match ? parseFloat(match[1]) : 0;
16
+ }
17
+ function getContrastColor(hexColor) {
18
+ const hex = hexColor.replace("#", "");
19
+ const r = parseInt(hex.substring(0, 2), 16);
20
+ const g = parseInt(hex.substring(2, 4), 16);
21
+ const b = parseInt(hex.substring(4, 6), 16);
22
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
23
+ return luminance > 0.5 ? "black" : "white";
24
+ }
25
+ function parseBaseColors(tokens) {
26
+ const families = [];
27
+ for (const [familyName, shades] of Object.entries(tokens)) {
28
+ if (typeof shades !== "object" || shades === null) continue;
29
+ const family = {
30
+ name: familyName,
31
+ primaryColor: "",
32
+ shades: []
33
+ };
34
+ for (const [shadeName, token] of Object.entries(shades)) {
35
+ if (isTokenValue(token)) {
36
+ const colorToken = {
37
+ name: `${familyName}-${shadeName}`,
38
+ value: token.value,
39
+ cssVariable: `--base-${familyName}-${shadeName}`,
40
+ shade: shadeName,
41
+ family: familyName
42
+ };
43
+ family.shades.push(colorToken);
44
+ if (shadeName === "50") {
45
+ family.primaryColor = token.value;
46
+ }
47
+ }
48
+ }
49
+ family.shades.sort((a, b) => {
50
+ const aNum = parseInt(a.shade || "0");
51
+ const bNum = parseInt(b.shade || "0");
52
+ return aNum - bNum;
53
+ });
54
+ if (!family.primaryColor && family.shades.length > 0) {
55
+ family.primaryColor = family.shades[Math.floor(family.shades.length / 2)]?.value || "";
56
+ }
57
+ if (family.shades.length > 0) {
58
+ families.push(family);
59
+ }
60
+ }
61
+ return families;
62
+ }
63
+ function parseSemanticColors(tokens, prefix) {
64
+ const colors = [];
65
+ for (const [name, token] of Object.entries(tokens)) {
66
+ if (isTokenValue(token)) {
67
+ let value = token.value;
68
+ if (value.startsWith("{") && value.endsWith("}")) {
69
+ value = token.value;
70
+ }
71
+ colors.push({
72
+ name,
73
+ value,
74
+ cssVariable: `--${prefix}-${name}`
75
+ });
76
+ }
77
+ }
78
+ return colors;
79
+ }
80
+ function parseSpacingTokens(tokens) {
81
+ const spacings = [];
82
+ for (const [name, token] of Object.entries(tokens)) {
83
+ if (isTokenValue(token)) {
84
+ const cleanName = name.replace(/^space-/, "");
85
+ spacings.push({
86
+ name: cleanName,
87
+ value: token.value,
88
+ cssVariable: `--space-${cleanName}`,
89
+ numericValue: parseNumericValue(token.value)
90
+ });
91
+ }
92
+ }
93
+ return spacings.sort((a, b) => a.numericValue - b.numericValue);
94
+ }
95
+ function parseRadiusTokens(tokens) {
96
+ const radiuses = [];
97
+ for (const [name, token] of Object.entries(tokens)) {
98
+ if (isTokenValue(token)) {
99
+ const cleanName = name.replace(/^radius-/, "");
100
+ radiuses.push({
101
+ name: cleanName,
102
+ value: token.value,
103
+ cssVariable: `--radius-${cleanName}`,
104
+ numericValue: parseNumericValue(token.value)
105
+ });
106
+ }
107
+ }
108
+ return radiuses.sort((a, b) => a.numericValue - b.numericValue);
109
+ }
110
+ function parseSizeTokens(tokens) {
111
+ const sizes = [];
112
+ for (const [name, token] of Object.entries(tokens)) {
113
+ if (isTokenValue(token)) {
114
+ const cleanName = name.replace(/^size-/, "");
115
+ sizes.push({
116
+ name: cleanName,
117
+ value: token.value,
118
+ cssVariable: `--size-${cleanName}`,
119
+ numericValue: parseNumericValue(token.value)
120
+ });
121
+ }
122
+ }
123
+ return sizes.sort((a, b) => a.numericValue - b.numericValue);
124
+ }
125
+ async function copyToClipboard(text) {
126
+ try {
127
+ await navigator.clipboard.writeText(text);
128
+ return true;
129
+ } catch {
130
+ const textarea = document.createElement("textarea");
131
+ textarea.value = text;
132
+ document.body.appendChild(textarea);
133
+ textarea.select();
134
+ const success = document.execCommand("copy");
135
+ document.body.removeChild(textarea);
136
+ return success;
137
+ }
138
+ }
139
+
140
+ // src/components/ColorGrid.tsx
141
+ import { jsx, jsxs } from "react/jsx-runtime";
142
+ function ColorGrid({
143
+ baseColors,
144
+ fillColors,
145
+ strokeColors,
146
+ textColors,
147
+ onColorClick
148
+ }) {
149
+ const [copiedValue, setCopiedValue] = useState(null);
150
+ const handleCopy = useCallback(async (color) => {
151
+ const success = await copyToClipboard(color.value);
152
+ if (success) {
153
+ setCopiedValue(color.value);
154
+ setTimeout(() => setCopiedValue(null), 2e3);
155
+ }
156
+ onColorClick?.(color);
157
+ }, [onColorClick]);
158
+ const colorFamilies = baseColors ? parseBaseColors(baseColors) : [];
159
+ const semanticFill = fillColors ? parseSemanticColors(fillColors, "fill") : [];
160
+ const semanticStroke = strokeColors ? parseSemanticColors(strokeColors, "stroke") : [];
161
+ const semanticText = textColors ? parseSemanticColors(textColors, "text") : [];
162
+ return /* @__PURE__ */ jsxs("div", { className: "ftd-color-container", children: [
163
+ colorFamilies.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ftd-section", children: [
164
+ /* @__PURE__ */ jsxs("div", { className: "ftd-section-header", children: [
165
+ /* @__PURE__ */ jsx("div", { className: "ftd-section-icon", children: "\u{1F3A8}" }),
166
+ /* @__PURE__ */ jsx("h3", { className: "ftd-section-title", children: "Base Colors" }),
167
+ /* @__PURE__ */ jsxs("span", { className: "ftd-section-count", children: [
168
+ colorFamilies.length,
169
+ " families"
170
+ ] })
171
+ ] }),
172
+ colorFamilies.map((family) => /* @__PURE__ */ jsxs("div", { className: "ftd-color-family", children: [
173
+ /* @__PURE__ */ jsxs("div", { className: "ftd-color-family-header", children: [
174
+ /* @__PURE__ */ jsx(
175
+ "div",
176
+ {
177
+ className: "ftd-color-family-swatch",
178
+ style: { backgroundColor: family.primaryColor }
179
+ }
180
+ ),
181
+ /* @__PURE__ */ jsx("h4", { className: "ftd-color-family-name", children: family.name })
182
+ ] }),
183
+ /* @__PURE__ */ jsx("div", { className: "ftd-color-scale", children: family.shades.map((shade) => /* @__PURE__ */ jsxs(
184
+ "div",
185
+ {
186
+ className: "ftd-color-shade",
187
+ style: {
188
+ backgroundColor: shade.value,
189
+ color: getContrastColor(shade.value)
190
+ },
191
+ onClick: () => handleCopy(shade),
192
+ title: `Click to copy: ${shade.value}`,
193
+ children: [
194
+ /* @__PURE__ */ jsx("span", { className: "ftd-color-shade-label", children: shade.shade }),
195
+ /* @__PURE__ */ jsx("span", { className: "ftd-color-shade-value", children: shade.value.substring(0, 7) })
196
+ ]
197
+ },
198
+ shade.name
199
+ )) })
200
+ ] }, family.name))
201
+ ] }),
202
+ semanticFill.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ftd-section", children: [
203
+ /* @__PURE__ */ jsxs("div", { className: "ftd-section-header", children: [
204
+ /* @__PURE__ */ jsx("div", { className: "ftd-section-icon", children: "\u{1F5BC}\uFE0F" }),
205
+ /* @__PURE__ */ jsx("h3", { className: "ftd-section-title", children: "Fill Colors" }),
206
+ /* @__PURE__ */ jsxs("span", { className: "ftd-section-count", children: [
207
+ semanticFill.length,
208
+ " tokens"
209
+ ] })
210
+ ] }),
211
+ /* @__PURE__ */ jsx("div", { className: "ftd-token-grid", children: semanticFill.map((color) => /* @__PURE__ */ jsx(
212
+ ColorCard,
213
+ {
214
+ color,
215
+ onClick: () => handleCopy(color)
216
+ },
217
+ color.name
218
+ )) })
219
+ ] }),
220
+ semanticStroke.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ftd-section", children: [
221
+ /* @__PURE__ */ jsxs("div", { className: "ftd-section-header", children: [
222
+ /* @__PURE__ */ jsx("div", { className: "ftd-section-icon", children: "\u270F\uFE0F" }),
223
+ /* @__PURE__ */ jsx("h3", { className: "ftd-section-title", children: "Stroke Colors" }),
224
+ /* @__PURE__ */ jsxs("span", { className: "ftd-section-count", children: [
225
+ semanticStroke.length,
226
+ " tokens"
227
+ ] })
228
+ ] }),
229
+ /* @__PURE__ */ jsx("div", { className: "ftd-token-grid", children: semanticStroke.map((color) => /* @__PURE__ */ jsx(
230
+ ColorCard,
231
+ {
232
+ color,
233
+ onClick: () => handleCopy(color)
234
+ },
235
+ color.name
236
+ )) })
237
+ ] }),
238
+ semanticText.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ftd-section", children: [
239
+ /* @__PURE__ */ jsxs("div", { className: "ftd-section-header", children: [
240
+ /* @__PURE__ */ jsx("div", { className: "ftd-section-icon", children: "\u{1F4DD}" }),
241
+ /* @__PURE__ */ jsx("h3", { className: "ftd-section-title", children: "Text Colors" }),
242
+ /* @__PURE__ */ jsxs("span", { className: "ftd-section-count", children: [
243
+ semanticText.length,
244
+ " tokens"
245
+ ] })
246
+ ] }),
247
+ /* @__PURE__ */ jsx("div", { className: "ftd-token-grid", children: semanticText.map((color) => /* @__PURE__ */ jsx(
248
+ ColorCard,
249
+ {
250
+ color,
251
+ onClick: () => handleCopy(color)
252
+ },
253
+ color.name
254
+ )) })
255
+ ] }),
256
+ copiedValue && /* @__PURE__ */ jsxs("div", { className: "ftd-copied-toast", children: [
257
+ "\u2713 Copied: ",
258
+ copiedValue
259
+ ] })
260
+ ] });
261
+ }
262
+ function ColorCard({ color, onClick }) {
263
+ const isAlias = color.value.startsWith("{");
264
+ const displayValue = isAlias ? color.value : color.value.substring(0, 9);
265
+ return /* @__PURE__ */ jsxs("div", { className: "ftd-token-card", onClick, children: [
266
+ /* @__PURE__ */ jsx(
267
+ "div",
268
+ {
269
+ className: "ftd-token-swatch",
270
+ style: {
271
+ backgroundColor: isAlias ? "var(--ftd-bg-tertiary)" : color.value
272
+ },
273
+ children: isAlias && /* @__PURE__ */ jsx("span", { style: {
274
+ fontSize: "0.625rem",
275
+ color: "var(--ftd-text-secondary)",
276
+ padding: "4px"
277
+ }, children: "Alias \u2192" })
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsxs("div", { className: "ftd-token-info", children: [
281
+ /* @__PURE__ */ jsx("p", { className: "ftd-token-name", children: color.name }),
282
+ /* @__PURE__ */ jsxs("p", { className: "ftd-token-value", children: [
283
+ displayValue,
284
+ /* @__PURE__ */ jsxs(
285
+ "svg",
286
+ {
287
+ className: "ftd-copy-icon",
288
+ width: "12",
289
+ height: "12",
290
+ viewBox: "0 0 24 24",
291
+ fill: "none",
292
+ stroke: "currentColor",
293
+ strokeWidth: "2",
294
+ children: [
295
+ /* @__PURE__ */ jsx("rect", { x: "9", y: "9", width: "13", height: "13", rx: "2", ry: "2" }),
296
+ /* @__PURE__ */ jsx("path", { d: "M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" })
297
+ ]
298
+ }
299
+ )
300
+ ] })
301
+ ] })
302
+ ] });
303
+ }
304
+
305
+ // src/components/SpacingScale.tsx
306
+ import { useState as useState2, useCallback as useCallback2 } from "react";
307
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
308
+ function SpacingScale({ tokens, onTokenClick }) {
309
+ const [copiedValue, setCopiedValue] = useState2(null);
310
+ const spacingTokens = parseSpacingTokens(tokens);
311
+ const maxValue = Math.max(...spacingTokens.map((t) => t.numericValue), 1);
312
+ const handleCopy = useCallback2(async (token) => {
313
+ const success = await copyToClipboard(token.value);
314
+ if (success) {
315
+ setCopiedValue(token.value);
316
+ setTimeout(() => setCopiedValue(null), 2e3);
317
+ }
318
+ onTokenClick?.(token);
319
+ }, [onTokenClick]);
320
+ if (spacingTokens.length === 0) {
321
+ return /* @__PURE__ */ jsxs2("div", { className: "ftd-empty", children: [
322
+ /* @__PURE__ */ jsx2("div", { className: "ftd-empty-icon", children: "\u{1F4CF}" }),
323
+ /* @__PURE__ */ jsx2("h4", { className: "ftd-empty-title", children: "No spacing tokens found" }),
324
+ /* @__PURE__ */ jsx2("p", { className: "ftd-empty-text", children: "Add spacing tokens to your tokens.json file" })
325
+ ] });
326
+ }
327
+ return /* @__PURE__ */ jsxs2("div", { className: "ftd-section", children: [
328
+ /* @__PURE__ */ jsxs2("div", { className: "ftd-section-header", children: [
329
+ /* @__PURE__ */ jsx2("div", { className: "ftd-section-icon", children: "\u{1F4CF}" }),
330
+ /* @__PURE__ */ jsx2("h3", { className: "ftd-section-title", children: "Spacing Scale" }),
331
+ /* @__PURE__ */ jsxs2("span", { className: "ftd-section-count", children: [
332
+ spacingTokens.length,
333
+ " tokens"
334
+ ] })
335
+ ] }),
336
+ /* @__PURE__ */ jsx2("div", { className: "ftd-spacing-list", children: spacingTokens.map((token) => {
337
+ const widthPercent = token.numericValue / maxValue * 100;
338
+ return /* @__PURE__ */ jsxs2(
339
+ "div",
340
+ {
341
+ className: "ftd-spacing-item",
342
+ onClick: () => handleCopy(token),
343
+ style: { cursor: "pointer" },
344
+ children: [
345
+ /* @__PURE__ */ jsx2("span", { className: "ftd-spacing-label", children: token.name }),
346
+ /* @__PURE__ */ jsx2("div", { className: "ftd-spacing-bar-container", children: /* @__PURE__ */ jsx2(
347
+ "div",
348
+ {
349
+ className: "ftd-spacing-bar",
350
+ style: { width: `${Math.max(widthPercent, 5)}%` }
351
+ }
352
+ ) }),
353
+ /* @__PURE__ */ jsx2("span", { className: "ftd-spacing-value", children: token.value })
354
+ ]
355
+ },
356
+ token.name
357
+ );
358
+ }) }),
359
+ copiedValue && /* @__PURE__ */ jsxs2("div", { className: "ftd-copied-toast", children: [
360
+ "\u2713 Copied: ",
361
+ copiedValue
362
+ ] })
363
+ ] });
364
+ }
365
+
366
+ // src/components/RadiusShowcase.tsx
367
+ import { useState as useState3, useCallback as useCallback3 } from "react";
368
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
369
+ function RadiusShowcase({ tokens, onTokenClick }) {
370
+ const [copiedValue, setCopiedValue] = useState3(null);
371
+ const radiusTokens = parseRadiusTokens(tokens);
372
+ const handleCopy = useCallback3(async (token) => {
373
+ const success = await copyToClipboard(token.value);
374
+ if (success) {
375
+ setCopiedValue(token.value);
376
+ setTimeout(() => setCopiedValue(null), 2e3);
377
+ }
378
+ onTokenClick?.(token);
379
+ }, [onTokenClick]);
380
+ if (radiusTokens.length === 0) {
381
+ return /* @__PURE__ */ jsxs3("div", { className: "ftd-empty", children: [
382
+ /* @__PURE__ */ jsx3("div", { className: "ftd-empty-icon", children: "\u2B1C" }),
383
+ /* @__PURE__ */ jsx3("h4", { className: "ftd-empty-title", children: "No radius tokens found" }),
384
+ /* @__PURE__ */ jsx3("p", { className: "ftd-empty-text", children: "Add radius tokens to your tokens.json file" })
385
+ ] });
386
+ }
387
+ return /* @__PURE__ */ jsxs3("div", { className: "ftd-section", children: [
388
+ /* @__PURE__ */ jsxs3("div", { className: "ftd-section-header", children: [
389
+ /* @__PURE__ */ jsx3("div", { className: "ftd-section-icon", children: "\u2B1C" }),
390
+ /* @__PURE__ */ jsx3("h3", { className: "ftd-section-title", children: "Border Radius" }),
391
+ /* @__PURE__ */ jsxs3("span", { className: "ftd-section-count", children: [
392
+ radiusTokens.length,
393
+ " tokens"
394
+ ] })
395
+ ] }),
396
+ /* @__PURE__ */ jsx3("div", { className: "ftd-radius-grid", children: radiusTokens.map((token) => /* @__PURE__ */ jsxs3(
397
+ "div",
398
+ {
399
+ className: "ftd-radius-item",
400
+ onClick: () => handleCopy(token),
401
+ style: { cursor: "pointer" },
402
+ children: [
403
+ /* @__PURE__ */ jsx3(
404
+ "div",
405
+ {
406
+ className: "ftd-radius-preview",
407
+ style: { borderRadius: token.value }
408
+ }
409
+ ),
410
+ /* @__PURE__ */ jsx3("p", { className: "ftd-radius-label", children: token.name }),
411
+ /* @__PURE__ */ jsx3("p", { className: "ftd-radius-value", children: token.value })
412
+ ]
413
+ },
414
+ token.name
415
+ )) }),
416
+ copiedValue && /* @__PURE__ */ jsxs3("div", { className: "ftd-copied-toast", children: [
417
+ "\u2713 Copied: ",
418
+ copiedValue
419
+ ] })
420
+ ] });
421
+ }
422
+
423
+ // src/components/SizeScale.tsx
424
+ import { useState as useState4, useCallback as useCallback4 } from "react";
425
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
426
+ function SizeScale({ tokens, onTokenClick }) {
427
+ const [copiedValue, setCopiedValue] = useState4(null);
428
+ const sizeTokens = parseSizeTokens(tokens);
429
+ const maxValue = Math.max(...sizeTokens.map((t) => t.numericValue), 1);
430
+ const handleCopy = useCallback4(async (token) => {
431
+ const success = await copyToClipboard(token.value);
432
+ if (success) {
433
+ setCopiedValue(token.value);
434
+ setTimeout(() => setCopiedValue(null), 2e3);
435
+ }
436
+ onTokenClick?.(token);
437
+ }, [onTokenClick]);
438
+ if (sizeTokens.length === 0) {
439
+ return /* @__PURE__ */ jsxs4("div", { className: "ftd-empty", children: [
440
+ /* @__PURE__ */ jsx4("div", { className: "ftd-empty-icon", children: "\u{1F4D0}" }),
441
+ /* @__PURE__ */ jsx4("h4", { className: "ftd-empty-title", children: "No size tokens found" }),
442
+ /* @__PURE__ */ jsx4("p", { className: "ftd-empty-text", children: "Add size tokens to your tokens.json file" })
443
+ ] });
444
+ }
445
+ return /* @__PURE__ */ jsxs4("div", { className: "ftd-section", children: [
446
+ /* @__PURE__ */ jsxs4("div", { className: "ftd-section-header", children: [
447
+ /* @__PURE__ */ jsx4("div", { className: "ftd-section-icon", children: "\u{1F4D0}" }),
448
+ /* @__PURE__ */ jsx4("h3", { className: "ftd-section-title", children: "Size Scale" }),
449
+ /* @__PURE__ */ jsxs4("span", { className: "ftd-section-count", children: [
450
+ sizeTokens.length,
451
+ " tokens"
452
+ ] })
453
+ ] }),
454
+ /* @__PURE__ */ jsx4("div", { className: "ftd-size-grid", children: sizeTokens.map((token) => {
455
+ const heightPercent = token.numericValue / maxValue * 200;
456
+ return /* @__PURE__ */ jsxs4(
457
+ "div",
458
+ {
459
+ className: "ftd-size-item",
460
+ onClick: () => handleCopy(token),
461
+ style: { cursor: "pointer" },
462
+ title: `${token.name}: ${token.value}`,
463
+ children: [
464
+ /* @__PURE__ */ jsx4(
465
+ "div",
466
+ {
467
+ className: "ftd-size-bar",
468
+ style: {
469
+ height: `${Math.max(heightPercent, 8)}px`,
470
+ width: "32px"
471
+ }
472
+ }
473
+ ),
474
+ /* @__PURE__ */ jsx4("span", { className: "ftd-size-label", children: token.name })
475
+ ]
476
+ },
477
+ token.name
478
+ );
479
+ }) }),
480
+ /* @__PURE__ */ jsx4("div", { style: { marginTop: "24px" }, children: /* @__PURE__ */ jsx4("div", { className: "ftd-spacing-list", children: sizeTokens.map((token) => /* @__PURE__ */ jsxs4(
481
+ "div",
482
+ {
483
+ className: "ftd-spacing-item",
484
+ onClick: () => handleCopy(token),
485
+ style: { cursor: "pointer" },
486
+ children: [
487
+ /* @__PURE__ */ jsx4("span", { className: "ftd-spacing-label", children: token.name }),
488
+ /* @__PURE__ */ jsx4("div", { className: "ftd-spacing-bar-container", children: /* @__PURE__ */ jsx4(
489
+ "div",
490
+ {
491
+ className: "ftd-spacing-bar",
492
+ style: { width: `${token.numericValue / maxValue * 100}%` }
493
+ }
494
+ ) }),
495
+ /* @__PURE__ */ jsx4("span", { className: "ftd-spacing-value", children: token.value })
496
+ ]
497
+ },
498
+ token.name
499
+ )) }) }),
500
+ copiedValue && /* @__PURE__ */ jsxs4("div", { className: "ftd-copied-toast", children: [
501
+ "\u2713 Copied: ",
502
+ copiedValue
503
+ ] })
504
+ ] });
505
+ }
506
+
507
+ // src/components/TokenDocumentation.tsx
508
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
509
+ function TokenDocumentation({
510
+ tokens,
511
+ title = "Design Tokens",
512
+ subtitle = "Interactive documentation for your design system",
513
+ defaultTab = "colors",
514
+ showSearch = true,
515
+ darkMode: initialDarkMode = false,
516
+ onTokenClick
517
+ }) {
518
+ const [activeTab, setActiveTab] = useState5(defaultTab);
519
+ const [searchQuery, setSearchQuery] = useState5("");
520
+ const [isDarkMode, setIsDarkMode] = useState5(initialDarkMode);
521
+ const colorsValue = tokens["Colors/Value"];
522
+ const spacingTokens = tokens["Spacing/Mode 1"] || {};
523
+ const sizeTokens = tokens["Size/Mode 1"] || {};
524
+ const radiusTokens = tokens["Radius/Mode 1"] || {};
525
+ const availableTabs = useMemo(() => {
526
+ const tabs = [];
527
+ if (colorsValue) {
528
+ tabs.push({ id: "colors", label: "Colors", icon: "\u{1F3A8}" });
529
+ }
530
+ if (Object.keys(spacingTokens).length > 0) {
531
+ tabs.push({ id: "spacing", label: "Spacing", icon: "\u{1F4CF}" });
532
+ }
533
+ if (Object.keys(sizeTokens).length > 0) {
534
+ tabs.push({ id: "sizes", label: "Sizes", icon: "\u{1F4D0}" });
535
+ }
536
+ if (Object.keys(radiusTokens).length > 0) {
537
+ tabs.push({ id: "radius", label: "Radius", icon: "\u2B1C" });
538
+ }
539
+ return tabs;
540
+ }, [colorsValue, spacingTokens, sizeTokens, radiusTokens]);
541
+ const validActiveTab = availableTabs.some((t) => t.id === activeTab) ? activeTab : availableTabs[0]?.id || "colors";
542
+ const toggleDarkMode = () => {
543
+ setIsDarkMode(!isDarkMode);
544
+ };
545
+ return /* @__PURE__ */ jsxs5("div", { className: "ftd-container", "data-theme": isDarkMode ? "dark" : "light", children: [
546
+ /* @__PURE__ */ jsxs5("header", { className: "ftd-header", children: [
547
+ /* @__PURE__ */ jsxs5("div", { children: [
548
+ /* @__PURE__ */ jsx5("h1", { className: "ftd-title", children: title }),
549
+ /* @__PURE__ */ jsx5("p", { className: "ftd-subtitle", children: subtitle })
550
+ ] }),
551
+ /* @__PURE__ */ jsxs5(
552
+ "button",
553
+ {
554
+ className: "ftd-theme-toggle",
555
+ onClick: toggleDarkMode,
556
+ "aria-label": isDarkMode ? "Switch to light mode" : "Switch to dark mode",
557
+ children: [
558
+ isDarkMode ? "\u2600\uFE0F" : "\u{1F319}",
559
+ /* @__PURE__ */ jsx5("span", { children: isDarkMode ? "Light" : "Dark" })
560
+ ]
561
+ }
562
+ )
563
+ ] }),
564
+ showSearch && /* @__PURE__ */ jsx5("div", { className: "ftd-search-container", children: /* @__PURE__ */ jsxs5("div", { className: "ftd-search-wrapper", children: [
565
+ /* @__PURE__ */ jsxs5(
566
+ "svg",
567
+ {
568
+ className: "ftd-search-icon",
569
+ width: "16",
570
+ height: "16",
571
+ viewBox: "0 0 24 24",
572
+ fill: "none",
573
+ stroke: "currentColor",
574
+ strokeWidth: "2",
575
+ children: [
576
+ /* @__PURE__ */ jsx5("circle", { cx: "11", cy: "11", r: "8" }),
577
+ /* @__PURE__ */ jsx5("path", { d: "M21 21l-4.35-4.35" })
578
+ ]
579
+ }
580
+ ),
581
+ /* @__PURE__ */ jsx5(
582
+ "input",
583
+ {
584
+ type: "text",
585
+ className: "ftd-search-input",
586
+ placeholder: "Search tokens...",
587
+ value: searchQuery,
588
+ onChange: (e) => setSearchQuery(e.target.value)
589
+ }
590
+ )
591
+ ] }) }),
592
+ availableTabs.length > 1 && /* @__PURE__ */ jsx5("nav", { className: "ftd-tabs", role: "tablist", children: availableTabs.map((tab) => /* @__PURE__ */ jsxs5(
593
+ "button",
594
+ {
595
+ className: `ftd-tab ${validActiveTab === tab.id ? "active" : ""}`,
596
+ onClick: () => setActiveTab(tab.id),
597
+ role: "tab",
598
+ "aria-selected": validActiveTab === tab.id,
599
+ children: [
600
+ /* @__PURE__ */ jsx5("span", { style: { marginRight: "8px" }, children: tab.icon }),
601
+ tab.label
602
+ ]
603
+ },
604
+ tab.id
605
+ )) }),
606
+ /* @__PURE__ */ jsxs5("div", { role: "tabpanel", children: [
607
+ validActiveTab === "colors" && colorsValue && /* @__PURE__ */ jsx5(
608
+ ColorGrid,
609
+ {
610
+ baseColors: colorsValue.base,
611
+ fillColors: colorsValue.fill,
612
+ strokeColors: colorsValue.stroke,
613
+ textColors: colorsValue.text,
614
+ onColorClick: onTokenClick
615
+ }
616
+ ),
617
+ validActiveTab === "spacing" && /* @__PURE__ */ jsx5(
618
+ SpacingScale,
619
+ {
620
+ tokens: spacingTokens,
621
+ onTokenClick
622
+ }
623
+ ),
624
+ validActiveTab === "sizes" && /* @__PURE__ */ jsx5(
625
+ SizeScale,
626
+ {
627
+ tokens: sizeTokens,
628
+ onTokenClick
629
+ }
630
+ ),
631
+ validActiveTab === "radius" && /* @__PURE__ */ jsx5(
632
+ RadiusShowcase,
633
+ {
634
+ tokens: radiusTokens,
635
+ onTokenClick
636
+ }
637
+ )
638
+ ] }),
639
+ availableTabs.length === 0 && /* @__PURE__ */ jsxs5("div", { className: "ftd-empty", children: [
640
+ /* @__PURE__ */ jsx5("div", { className: "ftd-empty-icon", children: "\u{1F4E6}" }),
641
+ /* @__PURE__ */ jsx5("h4", { className: "ftd-empty-title", children: "No tokens found" }),
642
+ /* @__PURE__ */ jsx5("p", { className: "ftd-empty-text", children: "Pass a valid tokens.json file from Figma Token Studio" })
643
+ ] })
644
+ ] });
645
+ }
646
+ var TokenDocumentation_default = TokenDocumentation;
647
+ export {
648
+ ColorGrid,
649
+ RadiusShowcase,
650
+ SizeScale,
651
+ SpacingScale,
652
+ TokenDocumentation,
653
+ TokenDocumentation_default as TokenDocumentationDefault,
654
+ copyToClipboard,
655
+ getContrastColor,
656
+ parseBaseColors,
657
+ parseRadiusTokens,
658
+ parseSemanticColors,
659
+ parseSizeTokens,
660
+ parseSpacingTokens
661
+ };
662
+ //# sourceMappingURL=index.js.map