shru-design-system 0.1.4 → 0.1.6
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.d.mts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +116 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +115 -104
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/scripts/apply-theme-sync.js +28 -14
- package/scripts/init.js +78 -16
package/dist/index.mjs
CHANGED
|
@@ -500,26 +500,11 @@ var baseThemeCategories = {
|
|
|
500
500
|
description: "Fast, brisk animations"
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
|
-
},
|
|
504
|
-
custom: {
|
|
505
|
-
name: "Custom",
|
|
506
|
-
order: 10,
|
|
507
|
-
// Highest priority
|
|
508
|
-
themes: {
|
|
509
|
-
brand: {
|
|
510
|
-
name: "Brand",
|
|
511
|
-
file: "custom/brand.json",
|
|
512
|
-
icon: "\u{1F3AF}",
|
|
513
|
-
description: "Brand-specific theme"
|
|
514
|
-
},
|
|
515
|
-
minimal: {
|
|
516
|
-
name: "Minimal",
|
|
517
|
-
file: "custom/minimal.json",
|
|
518
|
-
icon: "\u{1F3AA}",
|
|
519
|
-
description: "Minimal theme"
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
503
|
}
|
|
504
|
+
// Custom themes are not included in base config
|
|
505
|
+
// They should be discovered dynamically or registered by users
|
|
506
|
+
// Users can add custom themes by creating files in /tokens/themes/custom/
|
|
507
|
+
// and registering them using registerTheme()
|
|
523
508
|
};
|
|
524
509
|
var discoveredThemesCache = null;
|
|
525
510
|
async function discoverThemes() {
|
|
@@ -536,7 +521,9 @@ async function discoverThemes() {
|
|
|
536
521
|
discoveredThemesCache = discovered;
|
|
537
522
|
return discovered;
|
|
538
523
|
} catch (error) {
|
|
539
|
-
|
|
524
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
525
|
+
console.warn("Error discovering themes:", error);
|
|
526
|
+
}
|
|
540
527
|
return baseThemeCategories;
|
|
541
528
|
}
|
|
542
529
|
}
|
|
@@ -648,14 +635,23 @@ async function loadTokenFile(path) {
|
|
|
648
635
|
try {
|
|
649
636
|
const response = await fetch(path);
|
|
650
637
|
if (!response.ok) {
|
|
638
|
+
if (response.status === 404) {
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
651
641
|
throw new Error(`Failed to load ${path}: ${response.statusText}`);
|
|
652
642
|
}
|
|
643
|
+
const contentType = response.headers.get("content-type");
|
|
644
|
+
if (!contentType || !contentType.includes("application/json")) {
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
653
647
|
const data = await response.json();
|
|
654
648
|
tokenCache.set(path, data);
|
|
655
649
|
return deepClone(data);
|
|
656
650
|
} catch (error) {
|
|
657
|
-
|
|
658
|
-
|
|
651
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
652
|
+
console.warn(`Error loading token file ${path}:`, error);
|
|
653
|
+
}
|
|
654
|
+
return null;
|
|
659
655
|
}
|
|
660
656
|
}
|
|
661
657
|
function resolveReferences(tokens, palette) {
|
|
@@ -670,7 +666,9 @@ function resolveReferences(tokens, palette) {
|
|
|
670
666
|
if (current && typeof current === "object" && key in current) {
|
|
671
667
|
current = current[key];
|
|
672
668
|
} else {
|
|
673
|
-
|
|
669
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
670
|
+
console.warn(`Token reference not found: {${match[1]}}`);
|
|
671
|
+
}
|
|
674
672
|
return value;
|
|
675
673
|
}
|
|
676
674
|
}
|
|
@@ -755,49 +753,31 @@ function flattenToCSS(tokens, prefix = "", result = {}, isColorContext = false)
|
|
|
755
753
|
}
|
|
756
754
|
function mapToTailwindVars(cssVars) {
|
|
757
755
|
const mapped = { ...cssVars };
|
|
758
|
-
if (cssVars["--radius-button"]) {
|
|
756
|
+
if (cssVars["--radius-button"] && !cssVars["--radius"]) {
|
|
759
757
|
mapped["--radius"] = cssVars["--radius-button"];
|
|
760
758
|
}
|
|
761
|
-
if (cssVars["--radius-card"]) {
|
|
759
|
+
if (cssVars["--radius-card"] && !cssVars["--radius-lg"]) {
|
|
762
760
|
mapped["--radius-lg"] = cssVars["--radius-card"];
|
|
763
761
|
}
|
|
764
|
-
if (cssVars["--font-body"]) {
|
|
762
|
+
if (cssVars["--font-body"] && !cssVars["--font-sans"]) {
|
|
765
763
|
mapped["--font-sans"] = cssVars["--font-body"];
|
|
766
764
|
}
|
|
767
|
-
if (cssVars["--spacing-base"]) {
|
|
765
|
+
if (cssVars["--spacing-base"] && !cssVars["--spacing"]) {
|
|
768
766
|
mapped["--spacing"] = cssVars["--spacing-base"];
|
|
769
|
-
} else if (cssVars["--spacing-component-md"]) {
|
|
767
|
+
} else if (cssVars["--spacing-component-md"] && !cssVars["--spacing"]) {
|
|
770
768
|
mapped["--spacing"] = cssVars["--spacing-component-md"];
|
|
771
769
|
}
|
|
772
|
-
if (cssVars["--spacing-component-xs"]) {
|
|
773
|
-
mapped["--spacing-component-xs"] = cssVars["--spacing-component-xs"];
|
|
774
|
-
}
|
|
775
|
-
if (cssVars["--spacing-component-sm"]) {
|
|
776
|
-
mapped["--spacing-component-sm"] = cssVars["--spacing-component-sm"];
|
|
777
|
-
}
|
|
778
|
-
if (cssVars["--spacing-component-md"]) {
|
|
779
|
-
mapped["--spacing-component-md"] = cssVars["--spacing-component-md"];
|
|
780
|
-
}
|
|
781
|
-
if (cssVars["--spacing-component-lg"]) {
|
|
782
|
-
mapped["--spacing-component-lg"] = cssVars["--spacing-component-lg"];
|
|
783
|
-
}
|
|
784
|
-
if (cssVars["--spacing-component-xl"]) {
|
|
785
|
-
mapped["--spacing-component-xl"] = cssVars["--spacing-component-xl"];
|
|
786
|
-
}
|
|
787
|
-
if (cssVars["--duration-fast"]) {
|
|
788
|
-
mapped["--duration-fast"] = cssVars["--duration-fast"];
|
|
789
|
-
}
|
|
790
|
-
if (cssVars["--duration-normal"]) {
|
|
791
|
-
mapped["--duration-normal"] = cssVars["--duration-normal"];
|
|
792
|
-
}
|
|
793
|
-
if (cssVars["--duration-slow"]) {
|
|
794
|
-
mapped["--duration-slow"] = cssVars["--duration-slow"];
|
|
795
|
-
}
|
|
796
770
|
return mapped;
|
|
797
771
|
}
|
|
798
772
|
function generateCSSString(cssVars) {
|
|
799
773
|
const mappedVars = mapToTailwindVars(cssVars);
|
|
800
|
-
const vars = Object.entries(mappedVars).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
774
|
+
const vars = Object.entries(mappedVars).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => ` ${key}: ${value};`).join("\n");
|
|
775
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
776
|
+
console.group("\u{1F3A8} Design System CSS Variables");
|
|
777
|
+
console.table(mappedVars);
|
|
778
|
+
console.log("Total variables:", Object.keys(mappedVars).length);
|
|
779
|
+
console.groupEnd();
|
|
780
|
+
}
|
|
801
781
|
return `:root {
|
|
802
782
|
${vars}
|
|
803
783
|
}`;
|
|
@@ -811,16 +791,49 @@ function applyThemeCSS(css) {
|
|
|
811
791
|
}
|
|
812
792
|
styleTag.textContent = css;
|
|
813
793
|
}
|
|
794
|
+
function enableDebugMode() {
|
|
795
|
+
if (typeof window !== "undefined") {
|
|
796
|
+
window.__DESIGN_SYSTEM_DEBUG__ = true;
|
|
797
|
+
console.log("\u{1F50D} Design System debug mode enabled");
|
|
798
|
+
console.log("CSS variables will be logged when themes change");
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
function getCurrentCSSVariables() {
|
|
802
|
+
if (typeof window === "undefined") return {};
|
|
803
|
+
const styleTag = document.getElementById("dynamic-theme");
|
|
804
|
+
if (!styleTag) return {};
|
|
805
|
+
const cssText = styleTag.textContent || "";
|
|
806
|
+
const vars = {};
|
|
807
|
+
const matches = cssText.matchAll(/--([^:]+):\s*([^;]+);/g);
|
|
808
|
+
for (const match of matches) {
|
|
809
|
+
vars[`--${match[1].trim()}`] = match[2].trim();
|
|
810
|
+
}
|
|
811
|
+
return vars;
|
|
812
|
+
}
|
|
814
813
|
async function generateAndApplyTheme(selectedThemes = {}) {
|
|
815
814
|
try {
|
|
816
815
|
const themeCategories = await getThemeCategories();
|
|
817
816
|
const validation = validateThemeSelection(selectedThemes, themeCategories);
|
|
818
817
|
if (!validation.valid) {
|
|
819
|
-
|
|
820
|
-
|
|
818
|
+
const nonCustomErrors = validation.errors.filter((err) => !err.includes("custom"));
|
|
819
|
+
if (nonCustomErrors.length > 0) {
|
|
820
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
821
|
+
console.error("Invalid theme selection:", nonCustomErrors);
|
|
822
|
+
}
|
|
823
|
+
throw new Error(`Invalid theme selection: ${nonCustomErrors.join(", ")}`);
|
|
824
|
+
}
|
|
825
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
826
|
+
console.warn("Custom theme files not found, continuing without them:", validation.errors);
|
|
827
|
+
}
|
|
821
828
|
}
|
|
822
829
|
const base = await loadTokenFile("/tokens/base.json");
|
|
830
|
+
if (!base) {
|
|
831
|
+
throw new Error("Failed to load base tokens from /tokens/base.json");
|
|
832
|
+
}
|
|
823
833
|
const palettes = await loadTokenFile("/tokens/palettes.json");
|
|
834
|
+
if (!palettes || !palettes.palette) {
|
|
835
|
+
throw new Error("Failed to load palette from /tokens/palettes.json");
|
|
836
|
+
}
|
|
824
837
|
const palette = palettes.palette;
|
|
825
838
|
let merged = deepMerge(base, { palette });
|
|
826
839
|
const categoryOrder = Object.values(themeCategories).sort((a, b) => a.order - b.order).map((cat) => cat.name.toLowerCase());
|
|
@@ -830,18 +843,30 @@ async function generateAndApplyTheme(selectedThemes = {}) {
|
|
|
830
843
|
if (!themeId) continue;
|
|
831
844
|
const themePath = `/tokens/themes/${category}/${themeId}.json`;
|
|
832
845
|
const themeData = await loadTokenFile(themePath);
|
|
833
|
-
|
|
846
|
+
if (themeData) {
|
|
847
|
+
merged = deepMerge(merged, themeData);
|
|
848
|
+
} else if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
849
|
+
console.warn(`Theme file not found: ${themePath}`);
|
|
850
|
+
}
|
|
834
851
|
}
|
|
835
852
|
if (selectedThemes.custom) {
|
|
836
853
|
const customPath = `/tokens/themes/custom/${selectedThemes.custom}.json`;
|
|
837
854
|
const customData = await loadTokenFile(customPath);
|
|
838
|
-
|
|
855
|
+
if (customData) {
|
|
856
|
+
merged = deepMerge(merged, customData);
|
|
857
|
+
} else if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
858
|
+
console.warn(`Custom theme file not found: ${customPath} (this is normal if you haven't created it yet)`);
|
|
859
|
+
}
|
|
839
860
|
}
|
|
840
861
|
const resolved = resolveReferences(merged, palette);
|
|
841
862
|
const cssVars = flattenToCSS(resolved);
|
|
842
863
|
const css = generateCSSString(cssVars);
|
|
843
864
|
if (typeof document !== "undefined") {
|
|
844
865
|
applyThemeCSS(css);
|
|
866
|
+
if (window.__DESIGN_SYSTEM_DEBUG__) {
|
|
867
|
+
window.__DESIGN_SYSTEM_VARS__ = cssVars;
|
|
868
|
+
console.log("\u{1F4A1} Access CSS variables via: window.__DESIGN_SYSTEM_VARS__");
|
|
869
|
+
}
|
|
845
870
|
}
|
|
846
871
|
return {
|
|
847
872
|
success: true,
|
|
@@ -849,7 +874,9 @@ async function generateAndApplyTheme(selectedThemes = {}) {
|
|
|
849
874
|
cssVars
|
|
850
875
|
};
|
|
851
876
|
} catch (error) {
|
|
852
|
-
|
|
877
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
878
|
+
console.error("Error generating theme:", error);
|
|
879
|
+
}
|
|
853
880
|
throw error;
|
|
854
881
|
}
|
|
855
882
|
}
|
|
@@ -871,7 +898,9 @@ function useTheme() {
|
|
|
871
898
|
} catch (err) {
|
|
872
899
|
const errorMessage = err instanceof Error ? err.message : "Failed to apply theme";
|
|
873
900
|
setError(errorMessage);
|
|
874
|
-
|
|
901
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
902
|
+
console.error("Theme application error:", err);
|
|
903
|
+
}
|
|
875
904
|
} finally {
|
|
876
905
|
setIsLoading(false);
|
|
877
906
|
}
|
|
@@ -1279,28 +1308,25 @@ function applyThemeSync() {
|
|
|
1279
1308
|
}
|
|
1280
1309
|
try {
|
|
1281
1310
|
const base = loadJSONSync("/tokens/base.json");
|
|
1311
|
+
if (!base) {
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1282
1314
|
const palettes = loadJSONSync("/tokens/palettes.json");
|
|
1283
1315
|
const palette = palettes?.palette || {};
|
|
1284
|
-
let merged = deepMergeSync(base
|
|
1316
|
+
let merged = deepMergeSync(base, { palette });
|
|
1285
1317
|
const categoryOrder = ["color", "typography", "shape", "density", "animation"];
|
|
1286
1318
|
for (const category of categoryOrder) {
|
|
1287
1319
|
const themeId = selectedThemes[category];
|
|
1288
1320
|
if (!themeId) continue;
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
merged = deepMergeSync(merged, themeData);
|
|
1293
|
-
}
|
|
1294
|
-
} catch {
|
|
1321
|
+
const themeData = loadJSONSync(`/tokens/themes/${category}/${themeId}.json`);
|
|
1322
|
+
if (themeData) {
|
|
1323
|
+
merged = deepMergeSync(merged, themeData);
|
|
1295
1324
|
}
|
|
1296
1325
|
}
|
|
1297
1326
|
if (selectedThemes.custom) {
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
merged = deepMergeSync(merged, customData);
|
|
1302
|
-
}
|
|
1303
|
-
} catch {
|
|
1327
|
+
const customData = loadJSONSync(`/tokens/themes/custom/${selectedThemes.custom}.json`);
|
|
1328
|
+
if (customData) {
|
|
1329
|
+
merged = deepMergeSync(merged, customData);
|
|
1304
1330
|
}
|
|
1305
1331
|
}
|
|
1306
1332
|
const resolved = resolveReferencesSync(merged, palette);
|
|
@@ -1317,7 +1343,9 @@ ${Object.entries(mappedVars).map(([key, value]) => ` ${key}: ${value};`).join("
|
|
|
1317
1343
|
}
|
|
1318
1344
|
styleTag.textContent = css;
|
|
1319
1345
|
} catch (error) {
|
|
1320
|
-
|
|
1346
|
+
if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
|
|
1347
|
+
console.warn("Sync theme application failed, will apply via React:", error);
|
|
1348
|
+
}
|
|
1321
1349
|
}
|
|
1322
1350
|
}
|
|
1323
1351
|
function loadJSONSync(path) {
|
|
@@ -1325,8 +1353,15 @@ function loadJSONSync(path) {
|
|
|
1325
1353
|
const xhr = new XMLHttpRequest();
|
|
1326
1354
|
xhr.open("GET", path, false);
|
|
1327
1355
|
xhr.send(null);
|
|
1356
|
+
if (xhr.status === 404) {
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1328
1359
|
if (xhr.status === 200 || xhr.status === 0) {
|
|
1329
|
-
|
|
1360
|
+
const contentType = xhr.getResponseHeader("content-type");
|
|
1361
|
+
if (contentType && contentType.includes("application/json")) {
|
|
1362
|
+
return JSON.parse(xhr.responseText);
|
|
1363
|
+
}
|
|
1364
|
+
return null;
|
|
1330
1365
|
}
|
|
1331
1366
|
} catch {
|
|
1332
1367
|
}
|
|
@@ -1448,47 +1483,23 @@ function flattenToCSSSync(tokens, prefix = "", result = {}, isColorContext = fal
|
|
|
1448
1483
|
}
|
|
1449
1484
|
function mapToTailwindVarsSync(cssVars) {
|
|
1450
1485
|
const mapped = { ...cssVars };
|
|
1451
|
-
if (cssVars["--radius-button"]) {
|
|
1486
|
+
if (cssVars["--radius-button"] && !cssVars["--radius"]) {
|
|
1452
1487
|
mapped["--radius"] = cssVars["--radius-button"];
|
|
1453
1488
|
}
|
|
1454
|
-
if (cssVars["--radius-card"]) {
|
|
1489
|
+
if (cssVars["--radius-card"] && !cssVars["--radius-lg"]) {
|
|
1455
1490
|
mapped["--radius-lg"] = cssVars["--radius-card"];
|
|
1456
1491
|
}
|
|
1457
|
-
if (cssVars["--font-body"]) {
|
|
1492
|
+
if (cssVars["--font-body"] && !cssVars["--font-sans"]) {
|
|
1458
1493
|
mapped["--font-sans"] = cssVars["--font-body"];
|
|
1459
1494
|
}
|
|
1460
|
-
if (cssVars["--spacing-base"]) {
|
|
1495
|
+
if (cssVars["--spacing-base"] && !cssVars["--spacing"]) {
|
|
1461
1496
|
mapped["--spacing"] = cssVars["--spacing-base"];
|
|
1462
|
-
} else if (cssVars["--spacing-component-md"]) {
|
|
1497
|
+
} else if (cssVars["--spacing-component-md"] && !cssVars["--spacing"]) {
|
|
1463
1498
|
mapped["--spacing"] = cssVars["--spacing-component-md"];
|
|
1464
1499
|
}
|
|
1465
|
-
if (cssVars["--spacing-component-xs"]) {
|
|
1466
|
-
mapped["--spacing-component-xs"] = cssVars["--spacing-component-xs"];
|
|
1467
|
-
}
|
|
1468
|
-
if (cssVars["--spacing-component-sm"]) {
|
|
1469
|
-
mapped["--spacing-component-sm"] = cssVars["--spacing-component-sm"];
|
|
1470
|
-
}
|
|
1471
|
-
if (cssVars["--spacing-component-md"]) {
|
|
1472
|
-
mapped["--spacing-component-md"] = cssVars["--spacing-component-md"];
|
|
1473
|
-
}
|
|
1474
|
-
if (cssVars["--spacing-component-lg"]) {
|
|
1475
|
-
mapped["--spacing-component-lg"] = cssVars["--spacing-component-lg"];
|
|
1476
|
-
}
|
|
1477
|
-
if (cssVars["--spacing-component-xl"]) {
|
|
1478
|
-
mapped["--spacing-component-xl"] = cssVars["--spacing-component-xl"];
|
|
1479
|
-
}
|
|
1480
|
-
if (cssVars["--duration-fast"]) {
|
|
1481
|
-
mapped["--duration-fast"] = cssVars["--duration-fast"];
|
|
1482
|
-
}
|
|
1483
|
-
if (cssVars["--duration-normal"]) {
|
|
1484
|
-
mapped["--duration-normal"] = cssVars["--duration-normal"];
|
|
1485
|
-
}
|
|
1486
|
-
if (cssVars["--duration-slow"]) {
|
|
1487
|
-
mapped["--duration-slow"] = cssVars["--duration-slow"];
|
|
1488
|
-
}
|
|
1489
1500
|
return mapped;
|
|
1490
1501
|
}
|
|
1491
1502
|
|
|
1492
|
-
export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ThemeToggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
|
|
1503
|
+
export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, ThemeToggle, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
|
|
1493
1504
|
//# sourceMappingURL=index.mjs.map
|
|
1494
1505
|
//# sourceMappingURL=index.mjs.map
|