shru-design-system 0.1.9 → 0.1.11

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.mjs CHANGED
@@ -735,6 +735,331 @@ async function getTheme(category, themeId) {
735
735
  return categories[category]?.themes[themeId] || null;
736
736
  }
737
737
 
738
+ // src/tokens/base.json
739
+ var base_default = {
740
+ _createdBy: "shru-design-system library",
741
+ color: {
742
+ primary: "{palette.blue.500}",
743
+ "primary-hover": "{palette.blue.600}",
744
+ "primary-foreground": "{palette.white}",
745
+ secondary: "{palette.gray.100}",
746
+ "secondary-foreground": "{palette.gray.900}",
747
+ background: "{palette.white}",
748
+ foreground: "{palette.gray.900}",
749
+ card: "{palette.white}",
750
+ "card-foreground": "{palette.gray.900}",
751
+ popover: "{palette.white}",
752
+ "popover-foreground": "{palette.gray.900}",
753
+ muted: "{palette.gray.100}",
754
+ "muted-foreground": "{palette.gray.500}",
755
+ accent: "{palette.gray.100}",
756
+ "accent-foreground": "{palette.gray.900}",
757
+ destructive: "{palette.red.500}",
758
+ "destructive-foreground": "{palette.white}",
759
+ border: "{palette.gray.200}",
760
+ input: "{palette.gray.200}",
761
+ ring: "{palette.gray.400}",
762
+ skeleton: "{palette.gray.200}"
763
+ },
764
+ spacing: {
765
+ component: {
766
+ xs: "0.25rem",
767
+ sm: "0.5rem",
768
+ md: "1rem",
769
+ lg: "1.5rem",
770
+ xl: "2rem"
771
+ },
772
+ base: "0.25rem"
773
+ },
774
+ font: {
775
+ body: "var(--font-sans)",
776
+ sans: "var(--font-sans)",
777
+ mono: "var(--font-mono)"
778
+ },
779
+ radius: {
780
+ button: "0.375rem",
781
+ card: "0.5rem",
782
+ input: "0.375rem"
783
+ }
784
+ };
785
+
786
+ // src/tokens/palettes.json
787
+ var palettes_default = {
788
+ _createdBy: "shru-design-system library",
789
+ palette: {
790
+ white: "#ffffff",
791
+ black: "#000000",
792
+ transparent: "transparent",
793
+ gray: {
794
+ "50": "#f9fafb",
795
+ "100": "#f3f4f6",
796
+ "200": "#e5e7eb",
797
+ "300": "#d1d5db",
798
+ "400": "#9ca3af",
799
+ "500": "#6b7280",
800
+ "600": "#4b5563",
801
+ "700": "#374151",
802
+ "800": "#1f2937",
803
+ "900": "#111827",
804
+ "950": "#030712"
805
+ },
806
+ blue: {
807
+ "50": "#eff6ff",
808
+ "100": "#dbeafe",
809
+ "200": "#bfdbfe",
810
+ "300": "#93c5fd",
811
+ "400": "#60a5fa",
812
+ "500": "#3b82f6",
813
+ "600": "#2563eb",
814
+ "700": "#1d4ed8",
815
+ "800": "#1e40af",
816
+ "900": "#1e3a8a",
817
+ "950": "#172554"
818
+ },
819
+ red: {
820
+ "50": "#fef2f2",
821
+ "100": "#fee2e2",
822
+ "200": "#fecaca",
823
+ "300": "#fca5a5",
824
+ "400": "#f87171",
825
+ "500": "#ef4444",
826
+ "600": "#dc2626",
827
+ "700": "#b91c1c",
828
+ "800": "#991b1b",
829
+ "900": "#7f1d1d",
830
+ "950": "#450a0a"
831
+ },
832
+ purple: {
833
+ "50": "#faf5ff",
834
+ "100": "#f3e8ff",
835
+ "200": "#e9d5ff",
836
+ "300": "#d8b4fe",
837
+ "400": "#c084fc",
838
+ "500": "#a855f7",
839
+ "600": "#9333ea",
840
+ "700": "#7e22ce",
841
+ "800": "#6b21a8",
842
+ "900": "#581c87",
843
+ "950": "#3b0764"
844
+ },
845
+ pink: {
846
+ "50": "#fdf2f8",
847
+ "100": "#fce7f3",
848
+ "200": "#fbcfe8",
849
+ "300": "#f9a8d4",
850
+ "400": "#f472b6",
851
+ "500": "#ec4899",
852
+ "600": "#db2777",
853
+ "700": "#be185d",
854
+ "800": "#9f1239",
855
+ "900": "#831843",
856
+ "950": "#500724"
857
+ }
858
+ }
859
+ };
860
+
861
+ // src/tokens/themes/color/dark.json
862
+ var dark_default = {
863
+ _createdBy: "shru-design-system library",
864
+ color: {
865
+ primary: "{palette.blue.400}",
866
+ "primary-foreground": "{palette.gray.900}",
867
+ background: "{palette.gray.900}",
868
+ foreground: "{palette.gray.50}",
869
+ card: "{palette.gray.800}",
870
+ "card-foreground": "{palette.gray.50}",
871
+ popover: "{palette.gray.800}",
872
+ "popover-foreground": "{palette.gray.50}",
873
+ secondary: "{palette.gray.800}",
874
+ "secondary-foreground": "{palette.gray.50}",
875
+ muted: "{palette.gray.800}",
876
+ "muted-foreground": "{palette.gray.400}",
877
+ accent: "{palette.gray.800}",
878
+ "accent-foreground": "{palette.gray.50}",
879
+ destructive: "{palette.red.500}",
880
+ "destructive-foreground": "{palette.white}",
881
+ border: "{palette.gray.700}",
882
+ input: "{palette.gray.700}",
883
+ ring: "{palette.gray.600}",
884
+ skeleton: "{palette.gray.700}"
885
+ }
886
+ };
887
+
888
+ // src/tokens/themes/color/white.json
889
+ var white_default = {
890
+ _createdBy: "shru-design-system library",
891
+ color: {
892
+ primary: "{palette.blue.500}",
893
+ "primary-foreground": "{palette.white}",
894
+ background: "{palette.white}",
895
+ foreground: "{palette.gray.900}",
896
+ card: "{palette.white}",
897
+ "card-foreground": "{palette.gray.900}",
898
+ popover: "{palette.white}",
899
+ "popover-foreground": "{palette.gray.900}",
900
+ secondary: "{palette.gray.100}",
901
+ "secondary-foreground": "{palette.gray.900}",
902
+ muted: "{palette.gray.100}",
903
+ "muted-foreground": "{palette.gray.500}",
904
+ accent: "{palette.gray.100}",
905
+ "accent-foreground": "{palette.gray.900}",
906
+ destructive: "{palette.red.500}",
907
+ "destructive-foreground": "{palette.white}",
908
+ border: "{palette.gray.200}",
909
+ input: "{palette.gray.200}",
910
+ ring: "{palette.gray.400}",
911
+ skeleton: "{palette.gray.200}"
912
+ }
913
+ };
914
+
915
+ // src/tokens/themes/typography/sans.json
916
+ var sans_default = {
917
+ _createdBy: "shru-design-system library",
918
+ font: {
919
+ body: "system-ui, -apple-system, sans-serif",
920
+ sans: "system-ui, -apple-system, sans-serif"
921
+ }
922
+ };
923
+
924
+ // src/tokens/themes/typography/serif.json
925
+ var serif_default = {
926
+ _createdBy: "shru-design-system library",
927
+ font: {
928
+ body: "Georgia, serif",
929
+ sans: "Georgia, serif"
930
+ }
931
+ };
932
+
933
+ // src/tokens/themes/shape/smooth.json
934
+ var smooth_default = {
935
+ _createdBy: "shru-design-system library",
936
+ radius: {
937
+ button: "0.5rem",
938
+ card: "0.75rem",
939
+ input: "0.5rem"
940
+ }
941
+ };
942
+
943
+ // src/tokens/themes/shape/sharp.json
944
+ var sharp_default = {
945
+ _createdBy: "shru-design-system library",
946
+ radius: {
947
+ button: "0",
948
+ card: "0",
949
+ input: "0"
950
+ }
951
+ };
952
+
953
+ // src/tokens/themes/density/comfortable.json
954
+ var comfortable_default = {
955
+ _createdBy: "shru-design-system library",
956
+ spacing: {
957
+ component: {
958
+ xs: "0.5rem",
959
+ sm: "0.75rem",
960
+ md: "1.25rem",
961
+ lg: "2rem",
962
+ xl: "2.5rem"
963
+ }
964
+ }
965
+ };
966
+
967
+ // src/tokens/themes/density/compact.json
968
+ var compact_default = {
969
+ _createdBy: "shru-design-system library",
970
+ spacing: {
971
+ component: {
972
+ xs: "0.25rem",
973
+ sm: "0.5rem",
974
+ md: "0.75rem",
975
+ lg: "1rem",
976
+ xl: "1.5rem"
977
+ }
978
+ }
979
+ };
980
+
981
+ // src/tokens/themes/animation/gentle.json
982
+ var gentle_default = {
983
+ _createdBy: "shru-design-system library",
984
+ animation: {
985
+ duration: {
986
+ fast: "150ms",
987
+ normal: "300ms",
988
+ slow: "500ms"
989
+ }
990
+ }
991
+ };
992
+
993
+ // src/tokens/themes/animation/brisk.json
994
+ var brisk_default = {
995
+ _createdBy: "shru-design-system library",
996
+ animation: {
997
+ duration: {
998
+ fast: "100ms",
999
+ normal: "200ms",
1000
+ slow: "300ms"
1001
+ }
1002
+ }
1003
+ };
1004
+
1005
+ // src/tokens/themes/custom/brand.json
1006
+ var brand_default = {
1007
+ _createdBy: "shru-design-system library",
1008
+ color: {
1009
+ primary: "{palette.purple.600}",
1010
+ "primary-foreground": "{palette.white}",
1011
+ accent: "{palette.pink.500}",
1012
+ "accent-foreground": "{palette.white}"
1013
+ },
1014
+ radius: {
1015
+ button: "0.5rem",
1016
+ card: "0.75rem"
1017
+ }
1018
+ };
1019
+
1020
+ // src/tokens/themes/custom/minimal.json
1021
+ var minimal_default = {
1022
+ _createdBy: "shru-design-system library",
1023
+ color: {
1024
+ primary: "{palette.gray.700}",
1025
+ "primary-foreground": "{palette.white}",
1026
+ background: "{palette.white}",
1027
+ foreground: "{palette.gray.900}"
1028
+ },
1029
+ spacing: {
1030
+ component: {
1031
+ xs: "0.375rem",
1032
+ sm: "0.5rem",
1033
+ md: "0.75rem"
1034
+ }
1035
+ }
1036
+ };
1037
+
1038
+ // src/themes/tokenLoader.ts
1039
+ var EMBEDDED_TOKEN_BASE = "__EMBEDDED__";
1040
+ var EMBEDDED_TOKENS = {
1041
+ "base.json": base_default,
1042
+ "palettes.json": palettes_default,
1043
+ "themes/color/dark.json": dark_default,
1044
+ "themes/color/white.json": white_default,
1045
+ "themes/typography/sans.json": sans_default,
1046
+ "themes/typography/serif.json": serif_default,
1047
+ "themes/shape/smooth.json": smooth_default,
1048
+ "themes/shape/sharp.json": sharp_default,
1049
+ "themes/density/comfortable.json": comfortable_default,
1050
+ "themes/density/compact.json": compact_default,
1051
+ "themes/animation/gentle.json": gentle_default,
1052
+ "themes/animation/brisk.json": brisk_default,
1053
+ "themes/custom/brand.json": brand_default,
1054
+ "themes/custom/minimal.json": minimal_default
1055
+ };
1056
+ function normalizeTokenPath(path) {
1057
+ return path.replace(/^\/?tokens\//, "");
1058
+ }
1059
+ function getEmbeddedToken(normalizedPath) {
1060
+ return EMBEDDED_TOKENS[normalizedPath];
1061
+ }
1062
+
738
1063
  // src/themes/themeUtils.ts
739
1064
  function getThemeName(selectedThemes) {
740
1065
  const parts = [];
@@ -797,31 +1122,57 @@ function deepMerge(target, source) {
797
1122
  return output;
798
1123
  }
799
1124
  var tokenCache = /* @__PURE__ */ new Map();
1125
+ function getTokenBaseCandidates() {
1126
+ const bases = [];
1127
+ if (typeof window !== "undefined" && window.__THEME_TOKENS_BASE__) {
1128
+ bases.push(window.__THEME_TOKENS_BASE__);
1129
+ }
1130
+ const env = typeof globalThis !== "undefined" ? globalThis.process?.env : void 0;
1131
+ if (env?.DESIGN_SYSTEM_TOKENS_BASE) {
1132
+ bases.push(env.DESIGN_SYSTEM_TOKENS_BASE);
1133
+ }
1134
+ bases.push(EMBEDDED_TOKEN_BASE);
1135
+ bases.push("/tokens");
1136
+ return Array.from(new Set(bases.filter(Boolean)));
1137
+ }
800
1138
  async function loadTokenFile(path) {
801
- if (tokenCache.has(path)) {
802
- return deepClone(tokenCache.get(path));
1139
+ const normalizedPath = normalizeTokenPath(path);
1140
+ if (tokenCache.has(normalizedPath)) {
1141
+ return deepClone(tokenCache.get(normalizedPath));
803
1142
  }
804
- try {
805
- const response = await fetch(path);
806
- if (!response.ok) {
807
- if (response.status === 404) {
808
- return null;
1143
+ const bases = getTokenBaseCandidates();
1144
+ for (const base of bases) {
1145
+ if (base === EMBEDDED_TOKEN_BASE) {
1146
+ const embedded = getEmbeddedToken(normalizedPath);
1147
+ if (embedded) {
1148
+ tokenCache.set(normalizedPath, embedded);
1149
+ return deepClone(embedded);
809
1150
  }
810
- throw new Error(`Failed to load ${path}: ${response.statusText}`);
811
- }
812
- const contentType = response.headers.get("content-type");
813
- if (!contentType || !contentType.includes("application/json")) {
814
- return null;
1151
+ continue;
815
1152
  }
816
- const data = await response.json();
817
- tokenCache.set(path, data);
818
- return deepClone(data);
819
- } catch (error) {
820
- if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
821
- console.warn(`Error loading token file ${path}:`, error);
1153
+ const url = base.endsWith("/") ? `${base}${normalizedPath}` : `${base}/${normalizedPath}`;
1154
+ try {
1155
+ const response = await fetch(url);
1156
+ if (!response.ok) {
1157
+ if (response.status === 404) {
1158
+ continue;
1159
+ }
1160
+ throw new Error(`Failed to load ${url}: ${response.statusText}`);
1161
+ }
1162
+ const contentType = response.headers.get("content-type");
1163
+ if (!contentType || !contentType.includes("application/json")) {
1164
+ continue;
1165
+ }
1166
+ const data = await response.json();
1167
+ tokenCache.set(normalizedPath, data);
1168
+ return deepClone(data);
1169
+ } catch (error) {
1170
+ if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
1171
+ console.warn(`Error loading token file ${url}:`, error);
1172
+ }
822
1173
  }
823
- return null;
824
1174
  }
1175
+ return null;
825
1176
  }
826
1177
  function resolveReferences(tokens, palette) {
827
1178
  const resolved = JSON.parse(JSON.stringify(tokens));
@@ -1468,10 +1819,24 @@ function ThemeRingAsync({
1468
1819
 
1469
1820
  // src/themes/applyThemeSync.ts
1470
1821
  var STORAGE_KEY2 = "design-system-theme";
1822
+ function getTokenBaseCandidatesSync() {
1823
+ const bases = [];
1824
+ if (typeof window !== "undefined" && window.__THEME_TOKENS_BASE__) {
1825
+ bases.push(window.__THEME_TOKENS_BASE__);
1826
+ }
1827
+ const env = typeof globalThis !== "undefined" ? globalThis.process?.env : void 0;
1828
+ if (env?.DESIGN_SYSTEM_TOKENS_BASE) {
1829
+ bases.push(env.DESIGN_SYSTEM_TOKENS_BASE);
1830
+ }
1831
+ bases.push(EMBEDDED_TOKEN_BASE);
1832
+ bases.push("/tokens");
1833
+ return Array.from(new Set(bases.filter(Boolean)));
1834
+ }
1471
1835
  function applyThemeSync() {
1472
1836
  if (typeof window === "undefined" || typeof document === "undefined") {
1473
1837
  return;
1474
1838
  }
1839
+ const tokenBases = getTokenBaseCandidatesSync();
1475
1840
  let selectedThemes = getDefaultThemes();
1476
1841
  try {
1477
1842
  const stored = localStorage.getItem(STORAGE_KEY2);
@@ -1481,17 +1846,17 @@ function applyThemeSync() {
1481
1846
  } catch {
1482
1847
  }
1483
1848
  try {
1484
- const base = loadJSONSync("/tokens/base.json");
1849
+ const base = loadJSONSync("/tokens/base.json", tokenBases);
1485
1850
  if (!base) {
1486
1851
  return;
1487
1852
  }
1488
- const palettes = loadJSONSync("/tokens/palettes.json");
1853
+ const palettes = loadJSONSync("/tokens/palettes.json", tokenBases);
1489
1854
  const palette = palettes?.palette || {};
1490
1855
  let merged = deepMergeSync(base, { palette });
1491
1856
  for (const category of THEME_CATEGORY_ORDER) {
1492
1857
  const themeId = selectedThemes[category];
1493
1858
  if (!themeId) continue;
1494
- const themeData = loadJSONSync(`/tokens/themes/${category}/${themeId}.json`);
1859
+ const themeData = loadJSONSync(`/tokens/themes/${category}/${themeId}.json`, tokenBases);
1495
1860
  if (themeData) {
1496
1861
  merged = deepMergeSync(merged, themeData);
1497
1862
  }
@@ -1506,8 +1871,8 @@ ${Object.entries(mappedVars).map(([key, value]) => ` ${key}: ${value};`).join("
1506
1871
  if (!styleTag) {
1507
1872
  styleTag = document.createElement("style");
1508
1873
  styleTag.id = "dynamic-theme";
1509
- document.head.insertBefore(styleTag, document.head.firstChild);
1510
1874
  }
1875
+ document.head.appendChild(styleTag);
1511
1876
  styleTag.textContent = css;
1512
1877
  } catch (error) {
1513
1878
  if (typeof window !== "undefined" && window.__DESIGN_SYSTEM_DEBUG__) {
@@ -1515,22 +1880,33 @@ ${Object.entries(mappedVars).map(([key, value]) => ` ${key}: ${value};`).join("
1515
1880
  }
1516
1881
  }
1517
1882
  }
1518
- function loadJSONSync(path) {
1519
- try {
1520
- const xhr = new XMLHttpRequest();
1521
- xhr.open("GET", path, false);
1522
- xhr.send(null);
1523
- if (xhr.status === 404) {
1524
- return null;
1525
- }
1526
- if (xhr.status === 200 || xhr.status === 0) {
1527
- const contentType = xhr.getResponseHeader("content-type");
1528
- if (contentType && contentType.includes("application/json")) {
1529
- return JSON.parse(xhr.responseText);
1883
+ function loadJSONSync(path, bases) {
1884
+ const normalizedPath = normalizeTokenPath(path);
1885
+ for (const base of bases) {
1886
+ if (base === EMBEDDED_TOKEN_BASE) {
1887
+ const embedded = getEmbeddedToken(normalizedPath);
1888
+ if (embedded) {
1889
+ return deepCloneSync(embedded);
1530
1890
  }
1531
- return null;
1891
+ continue;
1892
+ }
1893
+ try {
1894
+ const xhr = new XMLHttpRequest();
1895
+ const url = base.endsWith("/") ? `${base}${normalizedPath}` : `${base}/${normalizedPath}`;
1896
+ xhr.open("GET", url, false);
1897
+ xhr.send(null);
1898
+ if (xhr.status === 404) {
1899
+ continue;
1900
+ }
1901
+ if (xhr.status === 200 || xhr.status === 0) {
1902
+ const contentType = xhr.getResponseHeader("content-type");
1903
+ if (contentType && contentType.includes("application/json")) {
1904
+ return JSON.parse(xhr.responseText);
1905
+ }
1906
+ continue;
1907
+ }
1908
+ } catch {
1532
1909
  }
1533
- } catch {
1534
1910
  }
1535
1911
  return null;
1536
1912
  }
@@ -1551,6 +1927,9 @@ function deepMergeSync(target, source) {
1551
1927
  }
1552
1928
  return output;
1553
1929
  }
1930
+ function deepCloneSync(value) {
1931
+ return JSON.parse(JSON.stringify(value));
1932
+ }
1554
1933
  function isObjectSync(item) {
1555
1934
  return item && typeof item === "object" && !Array.isArray(item);
1556
1935
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shru-design-system",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "description": "A React component library with atoms and molecules built on Radix UI and Tailwind CSS",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -42,6 +42,20 @@
42
42
  // 2. scripts/themeConfig.js - THEME_CATEGORY_ORDER (JavaScript version)
43
43
  const THEME_CATEGORY_ORDER = ['color', 'typography', 'shape', 'density', 'animation', 'custom'];
44
44
 
45
+ // Token base resolution (standalone script cannot import helpers)
46
+ // Order: consumer override → env override → public fallback.
47
+ function getTokenBaseCandidates() {
48
+ var bases = [];
49
+ if (typeof window !== 'undefined' && window.__THEME_TOKENS_BASE__) {
50
+ bases.push(window.__THEME_TOKENS_BASE__);
51
+ }
52
+ if (typeof process !== 'undefined' && process.env && process.env.DESIGN_SYSTEM_TOKENS_BASE) {
53
+ bases.push(process.env.DESIGN_SYSTEM_TOKENS_BASE);
54
+ }
55
+ bases.push('/tokens');
56
+ return Array.from(new Set(bases.filter(Boolean)));
57
+ }
58
+
45
59
  // Get theme from localStorage (optimized - single read)
46
60
  var selectedThemes = DEFAULT_THEMES;
47
61
  try {
@@ -71,27 +85,33 @@
71
85
  return output;
72
86
  }
73
87
 
74
- function loadJSONSync(path) {
75
- try {
76
- var xhr = new XMLHttpRequest();
77
- xhr.open('GET', path, false);
78
- xhr.send(null);
79
-
80
- // 404 means file doesn't exist - return null
81
- if (xhr.status === 404) {
82
- return null;
83
- }
84
-
85
- if (xhr.status === 200 || xhr.status === 0) {
86
- var contentType = xhr.getResponseHeader('content-type');
87
- // Check if response is actually JSON (not HTML error page)
88
- if (contentType && contentType.includes('application/json')) {
89
- return JSON.parse(xhr.responseText);
88
+ function loadJSONSync(relativePath, bases) {
89
+ for (var i = 0; i < bases.length; i++) {
90
+ var base = bases[i];
91
+ try {
92
+ var url = base.endsWith('/') ? base + relativePath : base + '/' + relativePath;
93
+ var xhr = new XMLHttpRequest();
94
+ xhr.open('GET', url, false);
95
+ xhr.send(null);
96
+
97
+ // 404 means file doesn't exist - try next base
98
+ if (xhr.status === 404) {
99
+ continue;
100
+ }
101
+
102
+ if (xhr.status === 200 || xhr.status === 0) {
103
+ var contentType = xhr.getResponseHeader('content-type');
104
+ // Check if response is actually JSON (not HTML error page)
105
+ if (contentType && contentType.includes('application/json')) {
106
+ return JSON.parse(xhr.responseText);
107
+ }
108
+ // If not JSON (likely HTML error page), try next base
109
+ continue;
90
110
  }
91
- // If not JSON (likely HTML error page), return null
92
- return null;
111
+ } catch (e) {
112
+ // Try next base
93
113
  }
94
- } catch (e) {}
114
+ }
95
115
  return null;
96
116
  }
97
117
 
@@ -252,10 +272,11 @@
252
272
 
253
273
  // Apply theme synchronously (optimized)
254
274
  try {
255
- var base = loadJSONSync('/tokens/base.json');
275
+ var tokenBases = getTokenBaseCandidates();
276
+ var base = loadJSONSync('base.json', tokenBases);
256
277
  if (!base) return;
257
278
 
258
- var palettes = loadJSONSync('/tokens/palettes.json');
279
+ var palettes = loadJSONSync('palettes.json', tokenBases);
259
280
  var palette = (palettes && palettes.palette) || {};
260
281
  var merged = deepMerge(base, { palette: palette });
261
282
 
@@ -265,7 +286,7 @@
265
286
  var themeId = selectedThemes[category];
266
287
  if (!themeId) continue;
267
288
 
268
- var themeData = loadJSONSync('/tokens/themes/' + category + '/' + themeId + '.json');
289
+ var themeData = loadJSONSync('themes/' + category + '/' + themeId + '.json', tokenBases);
269
290
  if (themeData) merged = deepMerge(merged, themeData);
270
291
  // If themeData is null, file doesn't exist - skip silently (custom themes are optional)
271
292
  }
@@ -287,8 +308,9 @@
287
308
  if (!styleTag) {
288
309
  styleTag = document.createElement('style');
289
310
  styleTag.id = 'dynamic-theme';
290
- document.head.insertBefore(styleTag, document.head.firstChild);
291
311
  }
312
+ // Always append (moves it to the end) so vars win over earlier styles
313
+ document.head.appendChild(styleTag);
292
314
  styleTag.textContent = css;
293
315
  } catch (error) {
294
316
  // Silently fail - theme will apply via React hook