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 CHANGED
@@ -152,6 +152,22 @@ declare function getThemesForCategory(category: string): Promise<Record<string,
152
152
  */
153
153
  declare function getTheme(category: string, themeId: string): Promise<ThemeMetadata | null>;
154
154
 
155
+ /**
156
+ * Theme Utilities
157
+ * Pure utility functions for theme management
158
+ * Note: generateAndApplyTheme has side effects (modifies DOM) but is the main theme application utility
159
+ */
160
+
161
+ /**
162
+ * Debug helper: Enable debug mode to see all CSS variables in console
163
+ * Call this in browser console: window.__DESIGN_SYSTEM_DEBUG__ = true
164
+ */
165
+ declare function enableDebugMode(): void;
166
+ /**
167
+ * Debug helper: Get all current CSS variables
168
+ */
169
+ declare function getCurrentCSSVariables(): Record<string, string>;
170
+
155
171
  /**
156
172
  * Synchronous theme application for blocking script execution
157
173
  * This runs before React hydrates to prevent theme flash
@@ -162,4 +178,4 @@ declare function getTheme(category: string, themeId: string): Promise<ThemeMetad
162
178
  */
163
179
  declare function applyThemeSync(): void;
164
180
 
165
- export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
181
+ export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
package/dist/index.d.ts CHANGED
@@ -152,6 +152,22 @@ declare function getThemesForCategory(category: string): Promise<Record<string,
152
152
  */
153
153
  declare function getTheme(category: string, themeId: string): Promise<ThemeMetadata | null>;
154
154
 
155
+ /**
156
+ * Theme Utilities
157
+ * Pure utility functions for theme management
158
+ * Note: generateAndApplyTheme has side effects (modifies DOM) but is the main theme application utility
159
+ */
160
+
161
+ /**
162
+ * Debug helper: Enable debug mode to see all CSS variables in console
163
+ * Call this in browser console: window.__DESIGN_SYSTEM_DEBUG__ = true
164
+ */
165
+ declare function enableDebugMode(): void;
166
+ /**
167
+ * Debug helper: Get all current CSS variables
168
+ */
169
+ declare function getCurrentCSSVariables(): Record<string, string>;
170
+
155
171
  /**
156
172
  * Synchronous theme application for blocking script execution
157
173
  * This runs before React hydrates to prevent theme flash
@@ -162,4 +178,4 @@ declare function getTheme(category: string, themeId: string): Promise<ThemeMetad
162
178
  */
163
179
  declare function applyThemeSync(): void;
164
180
 
165
- export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
181
+ export { Badge, Button, Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalOverlay, ModalPortal, ModalTitle, ModalTrigger, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, type ThemeMetadata$1 as ThemeMetadata, type ThemeSelection, ThemeToggle, type ThemeToggleProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, applyThemeSync, badgeVariants, buttonVariants, enableDebugMode, getCurrentCSSVariables, getTheme, getThemeCategories, getThemeFilePath, getThemesForCategory, registerTheme, useTheme, useThemeToggle };
package/dist/index.js CHANGED
@@ -524,26 +524,11 @@ var baseThemeCategories = {
524
524
  description: "Fast, brisk animations"
525
525
  }
526
526
  }
527
- },
528
- custom: {
529
- name: "Custom",
530
- order: 10,
531
- // Highest priority
532
- themes: {
533
- brand: {
534
- name: "Brand",
535
- file: "custom/brand.json",
536
- icon: "\u{1F3AF}",
537
- description: "Brand-specific theme"
538
- },
539
- minimal: {
540
- name: "Minimal",
541
- file: "custom/minimal.json",
542
- icon: "\u{1F3AA}",
543
- description: "Minimal theme"
544
- }
545
- }
546
527
  }
528
+ // Custom themes are not included in base config
529
+ // They should be discovered dynamically or registered by users
530
+ // Users can add custom themes by creating files in /tokens/themes/custom/
531
+ // and registering them using registerTheme()
547
532
  };
548
533
  var discoveredThemesCache = null;
549
534
  async function discoverThemes() {
@@ -560,7 +545,9 @@ async function discoverThemes() {
560
545
  discoveredThemesCache = discovered;
561
546
  return discovered;
562
547
  } catch (error) {
563
- console.warn("Error discovering themes:", error);
548
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
549
+ console.warn("Error discovering themes:", error);
550
+ }
564
551
  return baseThemeCategories;
565
552
  }
566
553
  }
@@ -672,14 +659,23 @@ async function loadTokenFile(path) {
672
659
  try {
673
660
  const response = await fetch(path);
674
661
  if (!response.ok) {
662
+ if (response.status === 404) {
663
+ return null;
664
+ }
675
665
  throw new Error(`Failed to load ${path}: ${response.statusText}`);
676
666
  }
667
+ const contentType = response.headers.get("content-type");
668
+ if (!contentType || !contentType.includes("application/json")) {
669
+ return null;
670
+ }
677
671
  const data = await response.json();
678
672
  tokenCache.set(path, data);
679
673
  return deepClone(data);
680
674
  } catch (error) {
681
- console.error(`Error loading token file ${path}:`, error);
682
- throw error;
675
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
676
+ console.warn(`Error loading token file ${path}:`, error);
677
+ }
678
+ return null;
683
679
  }
684
680
  }
685
681
  function resolveReferences(tokens, palette) {
@@ -694,7 +690,9 @@ function resolveReferences(tokens, palette) {
694
690
  if (current && typeof current === "object" && key in current) {
695
691
  current = current[key];
696
692
  } else {
697
- console.warn(`Token reference not found: {${match[1]}}`);
693
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
694
+ console.warn(`Token reference not found: {${match[1]}}`);
695
+ }
698
696
  return value;
699
697
  }
700
698
  }
@@ -779,49 +777,31 @@ function flattenToCSS(tokens, prefix = "", result = {}, isColorContext = false)
779
777
  }
780
778
  function mapToTailwindVars(cssVars) {
781
779
  const mapped = { ...cssVars };
782
- if (cssVars["--radius-button"]) {
780
+ if (cssVars["--radius-button"] && !cssVars["--radius"]) {
783
781
  mapped["--radius"] = cssVars["--radius-button"];
784
782
  }
785
- if (cssVars["--radius-card"]) {
783
+ if (cssVars["--radius-card"] && !cssVars["--radius-lg"]) {
786
784
  mapped["--radius-lg"] = cssVars["--radius-card"];
787
785
  }
788
- if (cssVars["--font-body"]) {
786
+ if (cssVars["--font-body"] && !cssVars["--font-sans"]) {
789
787
  mapped["--font-sans"] = cssVars["--font-body"];
790
788
  }
791
- if (cssVars["--spacing-base"]) {
789
+ if (cssVars["--spacing-base"] && !cssVars["--spacing"]) {
792
790
  mapped["--spacing"] = cssVars["--spacing-base"];
793
- } else if (cssVars["--spacing-component-md"]) {
791
+ } else if (cssVars["--spacing-component-md"] && !cssVars["--spacing"]) {
794
792
  mapped["--spacing"] = cssVars["--spacing-component-md"];
795
793
  }
796
- if (cssVars["--spacing-component-xs"]) {
797
- mapped["--spacing-component-xs"] = cssVars["--spacing-component-xs"];
798
- }
799
- if (cssVars["--spacing-component-sm"]) {
800
- mapped["--spacing-component-sm"] = cssVars["--spacing-component-sm"];
801
- }
802
- if (cssVars["--spacing-component-md"]) {
803
- mapped["--spacing-component-md"] = cssVars["--spacing-component-md"];
804
- }
805
- if (cssVars["--spacing-component-lg"]) {
806
- mapped["--spacing-component-lg"] = cssVars["--spacing-component-lg"];
807
- }
808
- if (cssVars["--spacing-component-xl"]) {
809
- mapped["--spacing-component-xl"] = cssVars["--spacing-component-xl"];
810
- }
811
- if (cssVars["--duration-fast"]) {
812
- mapped["--duration-fast"] = cssVars["--duration-fast"];
813
- }
814
- if (cssVars["--duration-normal"]) {
815
- mapped["--duration-normal"] = cssVars["--duration-normal"];
816
- }
817
- if (cssVars["--duration-slow"]) {
818
- mapped["--duration-slow"] = cssVars["--duration-slow"];
819
- }
820
794
  return mapped;
821
795
  }
822
796
  function generateCSSString(cssVars) {
823
797
  const mappedVars = mapToTailwindVars(cssVars);
824
- const vars = Object.entries(mappedVars).map(([key, value]) => ` ${key}: ${value};`).join("\n");
798
+ const vars = Object.entries(mappedVars).sort(([a], [b]) => a.localeCompare(b)).map(([key, value]) => ` ${key}: ${value};`).join("\n");
799
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
800
+ console.group("\u{1F3A8} Design System CSS Variables");
801
+ console.table(mappedVars);
802
+ console.log("Total variables:", Object.keys(mappedVars).length);
803
+ console.groupEnd();
804
+ }
825
805
  return `:root {
826
806
  ${vars}
827
807
  }`;
@@ -835,16 +815,49 @@ function applyThemeCSS(css) {
835
815
  }
836
816
  styleTag.textContent = css;
837
817
  }
818
+ function enableDebugMode() {
819
+ if (typeof window !== "undefined") {
820
+ window.__DESIGN_SYSTEM_DEBUG__ = true;
821
+ console.log("\u{1F50D} Design System debug mode enabled");
822
+ console.log("CSS variables will be logged when themes change");
823
+ }
824
+ }
825
+ function getCurrentCSSVariables() {
826
+ if (typeof window === "undefined") return {};
827
+ const styleTag = document.getElementById("dynamic-theme");
828
+ if (!styleTag) return {};
829
+ const cssText = styleTag.textContent || "";
830
+ const vars = {};
831
+ const matches = cssText.matchAll(/--([^:]+):\s*([^;]+);/g);
832
+ for (const match of matches) {
833
+ vars[`--${match[1].trim()}`] = match[2].trim();
834
+ }
835
+ return vars;
836
+ }
838
837
  async function generateAndApplyTheme(selectedThemes = {}) {
839
838
  try {
840
839
  const themeCategories = await getThemeCategories();
841
840
  const validation = validateThemeSelection(selectedThemes, themeCategories);
842
841
  if (!validation.valid) {
843
- console.error("Invalid theme selection:", validation.errors);
844
- throw new Error(`Invalid theme selection: ${validation.errors.join(", ")}`);
842
+ const nonCustomErrors = validation.errors.filter((err) => !err.includes("custom"));
843
+ if (nonCustomErrors.length > 0) {
844
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
845
+ console.error("Invalid theme selection:", nonCustomErrors);
846
+ }
847
+ throw new Error(`Invalid theme selection: ${nonCustomErrors.join(", ")}`);
848
+ }
849
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
850
+ console.warn("Custom theme files not found, continuing without them:", validation.errors);
851
+ }
845
852
  }
846
853
  const base = await loadTokenFile("/tokens/base.json");
854
+ if (!base) {
855
+ throw new Error("Failed to load base tokens from /tokens/base.json");
856
+ }
847
857
  const palettes = await loadTokenFile("/tokens/palettes.json");
858
+ if (!palettes || !palettes.palette) {
859
+ throw new Error("Failed to load palette from /tokens/palettes.json");
860
+ }
848
861
  const palette = palettes.palette;
849
862
  let merged = deepMerge(base, { palette });
850
863
  const categoryOrder = Object.values(themeCategories).sort((a, b) => a.order - b.order).map((cat) => cat.name.toLowerCase());
@@ -854,18 +867,30 @@ async function generateAndApplyTheme(selectedThemes = {}) {
854
867
  if (!themeId) continue;
855
868
  const themePath = `/tokens/themes/${category}/${themeId}.json`;
856
869
  const themeData = await loadTokenFile(themePath);
857
- merged = deepMerge(merged, themeData);
870
+ if (themeData) {
871
+ merged = deepMerge(merged, themeData);
872
+ } else if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
873
+ console.warn(`Theme file not found: ${themePath}`);
874
+ }
858
875
  }
859
876
  if (selectedThemes.custom) {
860
877
  const customPath = `/tokens/themes/custom/${selectedThemes.custom}.json`;
861
878
  const customData = await loadTokenFile(customPath);
862
- merged = deepMerge(merged, customData);
879
+ if (customData) {
880
+ merged = deepMerge(merged, customData);
881
+ } else if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
882
+ console.warn(`Custom theme file not found: ${customPath} (this is normal if you haven't created it yet)`);
883
+ }
863
884
  }
864
885
  const resolved = resolveReferences(merged, palette);
865
886
  const cssVars = flattenToCSS(resolved);
866
887
  const css = generateCSSString(cssVars);
867
888
  if (typeof document !== "undefined") {
868
889
  applyThemeCSS(css);
890
+ if (window.__DESIGN_SYSTEM_DEBUG__) {
891
+ window.__DESIGN_SYSTEM_VARS__ = cssVars;
892
+ console.log("\u{1F4A1} Access CSS variables via: window.__DESIGN_SYSTEM_VARS__");
893
+ }
869
894
  }
870
895
  return {
871
896
  success: true,
@@ -873,7 +898,9 @@ async function generateAndApplyTheme(selectedThemes = {}) {
873
898
  cssVars
874
899
  };
875
900
  } catch (error) {
876
- console.error("Error generating theme:", error);
901
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
902
+ console.error("Error generating theme:", error);
903
+ }
877
904
  throw error;
878
905
  }
879
906
  }
@@ -895,7 +922,9 @@ function useTheme() {
895
922
  } catch (err) {
896
923
  const errorMessage = err instanceof Error ? err.message : "Failed to apply theme";
897
924
  setError(errorMessage);
898
- console.error("Theme application error:", err);
925
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
926
+ console.error("Theme application error:", err);
927
+ }
899
928
  } finally {
900
929
  setIsLoading(false);
901
930
  }
@@ -1303,28 +1332,25 @@ function applyThemeSync() {
1303
1332
  }
1304
1333
  try {
1305
1334
  const base = loadJSONSync("/tokens/base.json");
1335
+ if (!base) {
1336
+ return;
1337
+ }
1306
1338
  const palettes = loadJSONSync("/tokens/palettes.json");
1307
1339
  const palette = palettes?.palette || {};
1308
- let merged = deepMergeSync(base || {}, { palette });
1340
+ let merged = deepMergeSync(base, { palette });
1309
1341
  const categoryOrder = ["color", "typography", "shape", "density", "animation"];
1310
1342
  for (const category of categoryOrder) {
1311
1343
  const themeId = selectedThemes[category];
1312
1344
  if (!themeId) continue;
1313
- try {
1314
- const themeData = loadJSONSync(`/tokens/themes/${category}/${themeId}.json`);
1315
- if (themeData) {
1316
- merged = deepMergeSync(merged, themeData);
1317
- }
1318
- } catch {
1345
+ const themeData = loadJSONSync(`/tokens/themes/${category}/${themeId}.json`);
1346
+ if (themeData) {
1347
+ merged = deepMergeSync(merged, themeData);
1319
1348
  }
1320
1349
  }
1321
1350
  if (selectedThemes.custom) {
1322
- try {
1323
- const customData = loadJSONSync(`/tokens/themes/custom/${selectedThemes.custom}.json`);
1324
- if (customData) {
1325
- merged = deepMergeSync(merged, customData);
1326
- }
1327
- } catch {
1351
+ const customData = loadJSONSync(`/tokens/themes/custom/${selectedThemes.custom}.json`);
1352
+ if (customData) {
1353
+ merged = deepMergeSync(merged, customData);
1328
1354
  }
1329
1355
  }
1330
1356
  const resolved = resolveReferencesSync(merged, palette);
@@ -1341,7 +1367,9 @@ ${Object.entries(mappedVars).map(([key, value]) => ` ${key}: ${value};`).join("
1341
1367
  }
1342
1368
  styleTag.textContent = css;
1343
1369
  } catch (error) {
1344
- console.warn("Sync theme application failed, will apply via React:", error);
1370
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
1371
+ console.warn("Sync theme application failed, will apply via React:", error);
1372
+ }
1345
1373
  }
1346
1374
  }
1347
1375
  function loadJSONSync(path) {
@@ -1349,8 +1377,15 @@ function loadJSONSync(path) {
1349
1377
  const xhr = new XMLHttpRequest();
1350
1378
  xhr.open("GET", path, false);
1351
1379
  xhr.send(null);
1380
+ if (xhr.status === 404) {
1381
+ return null;
1382
+ }
1352
1383
  if (xhr.status === 200 || xhr.status === 0) {
1353
- return JSON.parse(xhr.responseText);
1384
+ const contentType = xhr.getResponseHeader("content-type");
1385
+ if (contentType && contentType.includes("application/json")) {
1386
+ return JSON.parse(xhr.responseText);
1387
+ }
1388
+ return null;
1354
1389
  }
1355
1390
  } catch {
1356
1391
  }
@@ -1472,44 +1507,20 @@ function flattenToCSSSync(tokens, prefix = "", result = {}, isColorContext = fal
1472
1507
  }
1473
1508
  function mapToTailwindVarsSync(cssVars) {
1474
1509
  const mapped = { ...cssVars };
1475
- if (cssVars["--radius-button"]) {
1510
+ if (cssVars["--radius-button"] && !cssVars["--radius"]) {
1476
1511
  mapped["--radius"] = cssVars["--radius-button"];
1477
1512
  }
1478
- if (cssVars["--radius-card"]) {
1513
+ if (cssVars["--radius-card"] && !cssVars["--radius-lg"]) {
1479
1514
  mapped["--radius-lg"] = cssVars["--radius-card"];
1480
1515
  }
1481
- if (cssVars["--font-body"]) {
1516
+ if (cssVars["--font-body"] && !cssVars["--font-sans"]) {
1482
1517
  mapped["--font-sans"] = cssVars["--font-body"];
1483
1518
  }
1484
- if (cssVars["--spacing-base"]) {
1519
+ if (cssVars["--spacing-base"] && !cssVars["--spacing"]) {
1485
1520
  mapped["--spacing"] = cssVars["--spacing-base"];
1486
- } else if (cssVars["--spacing-component-md"]) {
1521
+ } else if (cssVars["--spacing-component-md"] && !cssVars["--spacing"]) {
1487
1522
  mapped["--spacing"] = cssVars["--spacing-component-md"];
1488
1523
  }
1489
- if (cssVars["--spacing-component-xs"]) {
1490
- mapped["--spacing-component-xs"] = cssVars["--spacing-component-xs"];
1491
- }
1492
- if (cssVars["--spacing-component-sm"]) {
1493
- mapped["--spacing-component-sm"] = cssVars["--spacing-component-sm"];
1494
- }
1495
- if (cssVars["--spacing-component-md"]) {
1496
- mapped["--spacing-component-md"] = cssVars["--spacing-component-md"];
1497
- }
1498
- if (cssVars["--spacing-component-lg"]) {
1499
- mapped["--spacing-component-lg"] = cssVars["--spacing-component-lg"];
1500
- }
1501
- if (cssVars["--spacing-component-xl"]) {
1502
- mapped["--spacing-component-xl"] = cssVars["--spacing-component-xl"];
1503
- }
1504
- if (cssVars["--duration-fast"]) {
1505
- mapped["--duration-fast"] = cssVars["--duration-fast"];
1506
- }
1507
- if (cssVars["--duration-normal"]) {
1508
- mapped["--duration-normal"] = cssVars["--duration-normal"];
1509
- }
1510
- if (cssVars["--duration-slow"]) {
1511
- mapped["--duration-slow"] = cssVars["--duration-slow"];
1512
- }
1513
1524
  return mapped;
1514
1525
  }
1515
1526
 
@@ -1543,6 +1554,8 @@ exports.TooltipTrigger = TooltipTrigger;
1543
1554
  exports.applyThemeSync = applyThemeSync;
1544
1555
  exports.badgeVariants = badgeVariants;
1545
1556
  exports.buttonVariants = buttonVariants;
1557
+ exports.enableDebugMode = enableDebugMode;
1558
+ exports.getCurrentCSSVariables = getCurrentCSSVariables;
1546
1559
  exports.getTheme = getTheme;
1547
1560
  exports.getThemeCategories = getThemeCategories;
1548
1561
  exports.getThemeFilePath = getThemeFilePath;