@motion-proto/live-tokens 0.13.2 → 0.14.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.
@@ -635,7 +635,18 @@ function themeFileApi(opts) {
635
635
  const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? import_path3.default.resolve(opts.tokensGeneratedCssPath) : import_path3.default.join(dataDirs.dataDir, "tokens.generated.css");
636
636
  const FONTS_CSS_PATH = opts.fontsCssPath ? import_path3.default.resolve(opts.fontsCssPath) : import_path3.default.join(import_path3.default.dirname(CSS_PATH), "fonts.css");
637
637
  const API_BASE = opts.apiBase ?? "/api/live-tokens";
638
- const COMPONENTS_SRC_DIR = opts.componentsSrcDir ? import_path3.default.resolve(opts.componentsSrcDir) : import_path3.default.resolve("src/system/components");
638
+ const consumerComponentsDir = opts.componentsSrcDir ? import_path3.default.resolve(opts.componentsSrcDir) : import_path3.default.resolve("src/system/components");
639
+ const packageComponentsDir = import_path3.default.resolve(
640
+ import_path3.default.dirname((0, import_node_url.fileURLToPath)(import_meta.url)),
641
+ "..",
642
+ "src",
643
+ "system",
644
+ "components"
645
+ );
646
+ const COMPONENTS_SCAN_DIRS = [consumerComponentsDir];
647
+ if (packageComponentsDir !== consumerComponentsDir && import_fs3.default.existsSync(packageComponentsDir)) {
648
+ COMPONENTS_SCAN_DIRS.push(packageComponentsDir);
649
+ }
639
650
  const LEGACY_PRESETS_DIR = import_path3.default.resolve("presets");
640
651
  const themesResource = versionedFileResourceServer({
641
652
  dir: THEMES_DIR
@@ -836,8 +847,16 @@ function themeFileApi(opts) {
836
847
  return import_path3.default.basename(filePath, ".svelte").toLowerCase();
837
848
  }
838
849
  function listComponentSourcePaths() {
839
- if (!import_fs3.default.existsSync(COMPONENTS_SRC_DIR)) return [];
840
- return import_fs3.default.readdirSync(COMPONENTS_SRC_DIR).filter((f) => f.endsWith(".svelte")).map((f) => import_path3.default.join(COMPONENTS_SRC_DIR, f));
850
+ const byName = /* @__PURE__ */ new Map();
851
+ for (const dir of COMPONENTS_SCAN_DIRS) {
852
+ if (!import_fs3.default.existsSync(dir)) continue;
853
+ for (const f of import_fs3.default.readdirSync(dir)) {
854
+ if (!f.endsWith(".svelte")) continue;
855
+ const name = componentNameFromFile(f);
856
+ if (!byName.has(name)) byName.set(name, import_path3.default.join(dir, f));
857
+ }
858
+ }
859
+ return Array.from(byName.values());
841
860
  }
842
861
  function listComponentNames() {
843
862
  return listComponentSourcePaths().map(componentNameFromFile);
@@ -1674,7 +1693,7 @@ function themeFileApi(opts) {
1674
1693
  },
1675
1694
  handleHotUpdate(ctx) {
1676
1695
  const normalized = import_path3.default.resolve(ctx.file);
1677
- if (!normalized.startsWith(COMPONENTS_SRC_DIR)) return;
1696
+ if (!COMPONENTS_SCAN_DIRS.some((d) => normalized.startsWith(d))) return;
1678
1697
  if (!normalized.endsWith(".svelte")) return;
1679
1698
  const comp = componentNameFromFile(normalized);
1680
1699
  generateDefaultConfig(comp, normalized);
@@ -598,7 +598,18 @@ function themeFileApi(opts) {
598
598
  const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? path3.resolve(opts.tokensGeneratedCssPath) : path3.join(dataDirs.dataDir, "tokens.generated.css");
599
599
  const FONTS_CSS_PATH = opts.fontsCssPath ? path3.resolve(opts.fontsCssPath) : path3.join(path3.dirname(CSS_PATH), "fonts.css");
600
600
  const API_BASE = opts.apiBase ?? "/api/live-tokens";
601
- const COMPONENTS_SRC_DIR = opts.componentsSrcDir ? path3.resolve(opts.componentsSrcDir) : path3.resolve("src/system/components");
601
+ const consumerComponentsDir = opts.componentsSrcDir ? path3.resolve(opts.componentsSrcDir) : path3.resolve("src/system/components");
602
+ const packageComponentsDir = path3.resolve(
603
+ path3.dirname(fileURLToPath(import.meta.url)),
604
+ "..",
605
+ "src",
606
+ "system",
607
+ "components"
608
+ );
609
+ const COMPONENTS_SCAN_DIRS = [consumerComponentsDir];
610
+ if (packageComponentsDir !== consumerComponentsDir && fs3.existsSync(packageComponentsDir)) {
611
+ COMPONENTS_SCAN_DIRS.push(packageComponentsDir);
612
+ }
602
613
  const LEGACY_PRESETS_DIR = path3.resolve("presets");
603
614
  const themesResource = versionedFileResourceServer({
604
615
  dir: THEMES_DIR
@@ -799,8 +810,16 @@ function themeFileApi(opts) {
799
810
  return path3.basename(filePath, ".svelte").toLowerCase();
800
811
  }
801
812
  function listComponentSourcePaths() {
802
- if (!fs3.existsSync(COMPONENTS_SRC_DIR)) return [];
803
- return fs3.readdirSync(COMPONENTS_SRC_DIR).filter((f) => f.endsWith(".svelte")).map((f) => path3.join(COMPONENTS_SRC_DIR, f));
813
+ const byName = /* @__PURE__ */ new Map();
814
+ for (const dir of COMPONENTS_SCAN_DIRS) {
815
+ if (!fs3.existsSync(dir)) continue;
816
+ for (const f of fs3.readdirSync(dir)) {
817
+ if (!f.endsWith(".svelte")) continue;
818
+ const name = componentNameFromFile(f);
819
+ if (!byName.has(name)) byName.set(name, path3.join(dir, f));
820
+ }
821
+ }
822
+ return Array.from(byName.values());
804
823
  }
805
824
  function listComponentNames() {
806
825
  return listComponentSourcePaths().map(componentNameFromFile);
@@ -1637,7 +1656,7 @@ function themeFileApi(opts) {
1637
1656
  },
1638
1657
  handleHotUpdate(ctx) {
1639
1658
  const normalized = path3.resolve(ctx.file);
1640
- if (!normalized.startsWith(COMPONENTS_SRC_DIR)) return;
1659
+ if (!COMPONENTS_SCAN_DIRS.some((d) => normalized.startsWith(d))) return;
1641
1660
  if (!normalized.endsWith(".svelte")) return;
1642
1661
  const comp = componentNameFromFile(normalized);
1643
1662
  generateDefaultConfig(comp, normalized);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@motion-proto/live-tokens",
3
- "version": "0.13.2",
3
+ "version": "0.14.0",
4
4
  "type": "module",
5
5
  "description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 6/7.",
6
6
  "keywords": [
@@ -30,7 +30,8 @@
30
30
  "!**/*.spec.ts",
31
31
  "!**/__tests__/**",
32
32
  "!src/system/components/Stat.svelte",
33
- "!src/system/components/StatEditor.svelte"
33
+ "!src/system/components/StatEditor.svelte",
34
+ "!src/system/styles/fonts/**"
34
35
  ],
35
36
  "bin": {
36
37
  "live-tokens": "./bin/cli.mjs"
@@ -1,15 +1,15 @@
1
1
  import type { FontFamily, FontSource, FontStack, Theme } from '../themes/themeTypes';
2
2
 
3
- // Stable relative paths. fonts.css and fonts/ ship colocated under
4
- // src/system/styles/ in this package, so `./fonts/...` resolves correctly
5
- // whether the css is served from the repo's own dev server, from inside
6
- // node_modules in a consumer, or from a hashed asset in a production build.
7
- // (Previously these were Vite `?url` imports those resolved to absolute
8
- // paths like `/src/system/styles/fonts/...` that worked inside live-tokens
9
- // but 404'd for any consumer importing the bundled fonts.css.)
10
- const FRAUNCES_ROMAN_LATIN = './fonts/Fraunces/Fraunces-roman-latin.woff2';
11
- const FRAUNCES_ITALIC_LATIN = './fonts/Fraunces/Fraunces-italic-latin.woff2';
12
- const MANROPE_LATIN = './fonts/Manrope/Manrope-latin.woff2';
3
+ // Google Fonts CDN URLs for the default font families. We used to ship local
4
+ // woff2 files and emit @font-face blocks pointing at them, but Vite's url()
5
+ // rewriting for @font-face refs from CSS bundled inside node_modules turned
6
+ // out to be brittle in consumer setups (paths leaked through unrewritten and
7
+ // resolved against the consumer's server root). Switching to Google Fonts
8
+ // CDN imports sidesteps the rewriting entirely.
9
+ const MANROPE_GFONTS_URL =
10
+ 'https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap';
11
+ const FRAUNCES_GFONTS_URL =
12
+ 'https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap';
13
13
 
14
14
  function makeId(prefix: string): string {
15
15
  return `${prefix}_${Math.random().toString(36).slice(2, 10)}`;
@@ -30,13 +30,12 @@ function fam(sourceId: string, name: string, cssName?: string, weights?: number[
30
30
  }
31
31
 
32
32
  /**
33
- * Build the default fontSources that match the hand-written src/styles/fonts.css.
34
- * Used when a theme has no fontSources yet.
33
+ * Build the default fontSources. Used when a theme has no fontSources yet.
35
34
  */
36
35
  export function defaultFontSources(): FontSource[] {
37
36
  const typekitId = 'src_typekit_jes8oow';
38
- const frauncesId = 'src_fraunces_local';
39
- const manropeId = 'src_manrope_local';
37
+ const frauncesId = 'src_fraunces_gfonts';
38
+ const manropeId = 'src_manrope_gfonts';
40
39
 
41
40
  return [
42
41
  {
@@ -50,18 +49,18 @@ export function defaultFontSources(): FontSource[] {
50
49
  },
51
50
  {
52
51
  id: frauncesId,
53
- kind: 'font-face',
54
- cssText: `@font-face {\n font-family: "Fraunces";\n src: url('${FRAUNCES_ROMAN_LATIN}') format('woff2');\n font-weight: 100 900;\n font-style: normal;\n font-display: swap;\n}\n@font-face {\n font-family: "Fraunces";\n src: url('${FRAUNCES_ITALIC_LATIN}') format('woff2');\n font-weight: 100 900;\n font-style: italic;\n font-display: swap;\n}`,
55
- label: 'Local',
52
+ kind: 'google',
53
+ url: FRAUNCES_GFONTS_URL,
54
+ label: 'Google Fonts',
56
55
  families: [
57
56
  fam(frauncesId, 'Fraunces', '"Fraunces"', [100, 200, 300, 400, 500, 600, 700, 800, 900]),
58
57
  ],
59
58
  },
60
59
  {
61
60
  id: manropeId,
62
- kind: 'font-face',
63
- cssText: `@font-face {\n font-family: "Manrope";\n src: url('${MANROPE_LATIN}') format('woff2');\n font-weight: 200 800;\n font-style: normal;\n font-display: swap;\n}`,
64
- label: 'Local',
61
+ kind: 'google',
62
+ url: MANROPE_GFONTS_URL,
63
+ label: 'Google Fonts',
65
64
  families: [
66
65
  fam(manropeId, 'Manrope', '"Manrope"', [200, 300, 400, 500, 600, 700, 800]),
67
66
  ],
@@ -119,19 +118,36 @@ export function defaultFontStacks(sources: FontSource[]): FontStack[] {
119
118
  ];
120
119
  }
121
120
 
121
+ // Older themes have `kind: 'font-face'` sources with embedded cssText that
122
+ // references local woff2 files. The url() resolution for those embedded refs
123
+ // is fragile in consumers, so swap any font-face source whose cssText is for
124
+ // Manrope or Fraunces over to the Google Fonts URL equivalent. Source ids
125
+ // and family ids are preserved so downstream fontStacks keep working.
126
+ function migrateLegacyLocalFonts(src: FontSource): boolean {
127
+ if (src.kind !== 'font-face' || !src.cssText) return false;
128
+ if (/font-family:\s*["']Manrope["']/.test(src.cssText)) {
129
+ (src as FontSource).kind = 'google';
130
+ src.url = MANROPE_GFONTS_URL;
131
+ src.label = 'Google Fonts';
132
+ delete src.cssText;
133
+ return true;
134
+ }
135
+ if (/font-family:\s*["']Fraunces["']/.test(src.cssText)) {
136
+ (src as FontSource).kind = 'google';
137
+ src.url = FRAUNCES_GFONTS_URL;
138
+ src.label = 'Google Fonts';
139
+ delete src.cssText;
140
+ return true;
141
+ }
142
+ return false;
143
+ }
144
+
122
145
  /**
123
146
  * Ensure the loaded Theme has fontSources and fontStacks. Mutates in place
124
147
  * only when missing; safe to call on already-migrated themes. Also strips any
125
- * stale --font-* entries from cssVariables since those are now derived.
148
+ * stale --font-* entries from cssVariables since those are now derived, and
149
+ * migrates legacy local-font sources to Google Fonts URL sources.
126
150
  */
127
- // Older themes (built before relative font paths) baked absolute Vite-resolved
128
- // URLs into fontSources[].cssText, e.g. `/src/system/styles/fonts/...` or
129
- // `/src/live-tokens/system/styles/fonts/...`. Those paths only resolve inside
130
- // the live-tokens repo or a consumer that vendored the source; in any package
131
- // consumer they 404. Normalise to the package-relative `./fonts/...` form on
132
- // theme load.
133
- const ABSOLUTE_FONT_PATH_PATTERN = /'\/src\/(?:live-tokens\/)?system\/styles\/fonts\//g;
134
-
135
151
  export function migrateThemeFonts(theme: Theme): { migrated: boolean } {
136
152
  let migrated = false;
137
153
  if (!theme.fontSources || theme.fontSources.length === 0) {
@@ -139,12 +155,7 @@ export function migrateThemeFonts(theme: Theme): { migrated: boolean } {
139
155
  migrated = true;
140
156
  } else {
141
157
  for (const src of theme.fontSources) {
142
- if (!src.cssText) continue;
143
- const rewritten = src.cssText.replace(ABSOLUTE_FONT_PATH_PATTERN, "'./fonts/");
144
- if (rewritten !== src.cssText) {
145
- src.cssText = rewritten;
146
- migrated = true;
147
- }
158
+ if (migrateLegacyLocalFonts(src)) migrated = true;
148
159
  }
149
160
  }
150
161
  if (!theme.fontStacks || theme.fontStacks.length === 0) {
@@ -1,5 +1,4 @@
1
1
  /* Generated from the production theme by syncFontsToCss. Do not edit. */
2
- /* Both fonts.css and fonts/ are in dist/, so relative paths work at runtime. */
3
2
 
4
3
  /* Adobe Typekit — fira-code */
5
4
  @import url('https://use.typekit.net/jes8oow.css');
@@ -10,11 +9,8 @@
10
9
  /* Google Fonts — GFS Didot */
11
10
  @import url('https://fonts.googleapis.com/css2?family=GFS+Didot&display=swap');
12
11
 
13
- /* LocalManrope */
14
- @font-face {
15
- font-family: "Manrope";
16
- src: url('./fonts/Manrope/Manrope-latin.woff2') format('woff2');
17
- font-weight: 200 800;
18
- font-style: normal;
19
- font-display: swap;
20
- }
12
+ /* Google Fonts Fraunces */
13
+ @import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,100..900;1,9..144,100..900&display=swap');
14
+
15
+ /* Google Fonts — Manrope */
16
+ @import url('https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap');