@motion-proto/live-tokens 0.56.1 → 0.58.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/.claude/skills/live-tokens-create-component/SKILL.md +13 -2
- package/.claude/skills/live-tokens-create-component/references/sketch-mode.md +202 -0
- package/.claude/skills/live-tokens-pair-fonts/SKILL.md +2 -2
- package/.claude/skills/live-tokens-pick-component/SKILL.md +1 -1
- package/CHANGELOG.md +192 -0
- package/README.md +1 -1
- package/bin/cli.mjs +2 -1
- package/dist-plugin/adjust/index.cjs +1 -0
- package/dist-plugin/adjust/index.d.cts +2 -2
- package/dist-plugin/adjust/index.d.ts +2 -2
- package/dist-plugin/adjust/index.js +1 -1
- package/dist-plugin/{chunk-TKZBVIW5.js → chunk-E5QYON4L.js} +59 -2
- package/dist-plugin/{chunk-PB2JTK2H.js → chunk-LW4SR7AZ.js} +39 -6
- package/dist-plugin/{chunk-YR6GPXW2.js → chunk-XWXIMTWZ.js} +0 -5
- package/dist-plugin/{chunk-D3ZVKOR4.js → chunk-Y5CNFSSV.js} +1 -0
- package/dist-plugin/{dataPaths-DBN0RPuT.d.cts → dataPaths-CRfD1LdA.d.cts} +3 -0
- package/dist-plugin/{dataPaths-DBN0RPuT.d.ts → dataPaths-CRfD1LdA.d.ts} +3 -0
- package/dist-plugin/fontPairing/index.cjs +4 -2
- package/dist-plugin/fontPairing/index.d.cts +3 -3
- package/dist-plugin/fontPairing/index.d.ts +3 -3
- package/dist-plugin/fontPairing/index.js +4 -3
- package/dist-plugin/generateColorsAndType/index.cjs +22 -9
- package/dist-plugin/generateColorsAndType/index.d.cts +2 -2
- package/dist-plugin/generateColorsAndType/index.d.ts +2 -2
- package/dist-plugin/generateColorsAndType/index.js +8 -5
- package/dist-plugin/index.cjs +158 -9
- package/dist-plugin/index.d.cts +1 -1
- package/dist-plugin/index.d.ts +1 -1
- package/dist-plugin/index.js +71 -4
- package/dist-plugin/migrateData/index.cjs +1 -0
- package/dist-plugin/migrateData/index.d.cts +1 -1
- package/dist-plugin/migrateData/index.d.ts +1 -1
- package/dist-plugin/migrateData/index.js +1 -1
- package/dist-plugin/{themeTypes-BAqtv4XO.d.cts → themeTypes-DSV3Zisf.d.cts} +12 -1
- package/dist-plugin/{themeTypes-BAqtv4XO.d.ts → themeTypes-DSV3Zisf.d.ts} +12 -1
- package/dist-plugin/tokensCssMigrations/index.cjs +58 -1
- package/dist-plugin/tokensCssMigrations/index.d.cts +1 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +1 -1
- package/dist-plugin/tokensCssMigrations/index.js +3 -3
- package/package.json +3 -1
- package/src/editor/core/fonts/applyFontPairing.ts +3 -2
- package/src/editor/core/fonts/fontLoader.ts +1 -0
- package/src/editor/core/fonts/fontMigration.ts +31 -1
- package/src/editor/core/palettes/paletteDerivation.ts +9 -2
- package/src/editor/core/sketch/maskField.ts +385 -0
- package/src/editor/core/sketch/sketchLayer.ts +1106 -0
- package/src/editor/core/sketch/sketchPresetService.ts +65 -0
- package/src/editor/core/sketch/sketchPresets.ts +345 -0
- package/src/editor/core/sketch/sketchStore.ts +190 -0
- package/src/editor/core/store/editorPersistence.ts +28 -12
- package/src/editor/core/store/editorTypes.ts +4 -1
- package/src/editor/core/store/editorViewStore.ts +2 -2
- package/src/editor/core/store/gradientSource.ts +15 -1
- package/src/editor/core/themes/parsers/gradient.ts +62 -4
- package/src/editor/core/themes/slices/gradients.ts +75 -14
- package/src/editor/core/themes/themeTypes.ts +6 -1
- package/src/editor/docs/Docs.svelte +4 -3
- package/src/editor/docs/chapters.ts +1 -0
- package/src/editor/docs/content/01-overview.md +2 -1
- package/src/editor/docs/content/editing-tokens.md +5 -1
- package/src/editor/docs/content/sketch-mode.md +183 -0
- package/src/editor/docs/content.generated.ts +3 -2
- package/src/editor/overlay/LiveEditorOverlay.svelte +15 -0
- package/src/editor/pages/EditorShell.svelte +43 -0
- package/src/editor/ui/EditorViewSwitcher.svelte +30 -17
- package/src/editor/ui/FontStackEditor.svelte +3 -0
- package/src/editor/ui/GradientEditor.svelte +38 -1
- package/src/editor/ui/UIReveal.svelte +7 -1
- package/src/editor/ui/UISegmentedControl.svelte +4 -8
- package/src/editor/ui/sections/GradientsSection.svelte +47 -1
- package/src/editor/ui/sketch/SketchDial.svelte +124 -0
- package/src/editor/ui/sketch/SketchPreview.svelte +119 -0
- package/src/editor/ui/sketch/SketchRange.svelte +185 -0
- package/src/editor/ui/sketch/SketchTab.svelte +1264 -0
- package/src/live-tokens/data/colors-and-type/autumn.json +17 -0
- package/src/live-tokens/data/colors-and-type/default.json +17 -0
- package/src/live-tokens/data/colors-and-type/halloween.json +17 -0
- package/src/live-tokens/data/colors-and-type/midnight-study.json +17 -0
- package/src/live-tokens/data/colors-and-type/ocean.json +17 -0
- package/src/live-tokens/data/colors-and-type/royal-velvet.json +17 -0
- package/src/live-tokens/data/colors-and-type/sketchy.json +2520 -0
- package/src/live-tokens/data/colors-and-type/spring-meadow.json +17 -0
- package/src/live-tokens/data/colors-and-type/sunset.json +17 -0
- package/src/live-tokens/data/themes/autumn.json +17 -0
- package/src/live-tokens/data/themes/halloween.json +17 -0
- package/src/live-tokens/data/themes/midnight-study.json +17 -0
- package/src/live-tokens/data/themes/ocean.json +17 -0
- package/src/live-tokens/data/themes/royal-velvet.json +17 -0
- package/src/live-tokens/data/themes/sketchy.json +3984 -0
- package/src/live-tokens/data/themes/spring-meadow.json +17 -0
- package/src/live-tokens/data/themes/sunset.json +17 -0
- package/src/live-tokens/data/tokens.generated.css +1 -0
- package/src/system/components/Card.svelte +12 -1
- package/src/system/components/SectionDivider.svelte +4 -0
- package/src/system/styles/tokens.css +15 -2
package/dist-plugin/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
parseGradientValue,
|
|
6
6
|
reconcilePalettesFromCssVars,
|
|
7
7
|
sanitizeFileName
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-LW4SR7AZ.js";
|
|
9
9
|
import {
|
|
10
10
|
THEME_SCHEMA_VERSION,
|
|
11
11
|
detectLegacyLayout,
|
|
@@ -23,13 +23,13 @@ import {
|
|
|
23
23
|
runAdditiveTokensCssMigrations,
|
|
24
24
|
runTokensCssMigrations,
|
|
25
25
|
validateTokensCss
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-E5QYON4L.js";
|
|
27
27
|
import {
|
|
28
28
|
hexToOklch
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-XWXIMTWZ.js";
|
|
30
30
|
import {
|
|
31
31
|
resolveDataDirs
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-Y5CNFSSV.js";
|
|
33
33
|
|
|
34
34
|
// vite-plugin/themeFileApi.ts
|
|
35
35
|
import fs from "fs";
|
|
@@ -137,6 +137,7 @@ function themeFileApi(opts) {
|
|
|
137
137
|
const COLORS_AND_TYPE_DIR = dataDirs.colorsAndTypeDir;
|
|
138
138
|
const COMPONENT_CONFIGS_DIR = dataDirs.componentConfigsDir;
|
|
139
139
|
const THEMES_DIR = dataDirs.themesDir;
|
|
140
|
+
const SKETCH_PRESETS_DIR = dataDirs.sketchPresetsDir;
|
|
140
141
|
const CSS_PATH = path.resolve(opts.tokensCssPath);
|
|
141
142
|
const GENERATED_CSS_PATH = opts.tokensGeneratedCssPath ? path.resolve(opts.tokensGeneratedCssPath) : path.join(dataDirs.dataDir, "tokens.generated.css");
|
|
142
143
|
const FONTS_CSS_PATH = opts.fontsCssPath ? path.resolve(opts.fontsCssPath) : path.join(path.dirname(CSS_PATH), "fonts.css");
|
|
@@ -194,6 +195,7 @@ function themeFileApi(opts) {
|
|
|
194
195
|
dir: THEMES_DIR,
|
|
195
196
|
packageDir: packageThemesDir
|
|
196
197
|
});
|
|
198
|
+
const sketchPresetsResource = versionedFileResourceServer({ dir: SKETCH_PRESETS_DIR });
|
|
197
199
|
function ensureColorsAndTypeDir() {
|
|
198
200
|
colorsAndTypeResource.ensureDir();
|
|
199
201
|
}
|
|
@@ -759,6 +761,8 @@ ${lines.join("\n")}
|
|
|
759
761
|
const THEME_EXPORT_REGEX = new RegExp(`^${escapedBase}/themes/([a-z0-9\\-_]+)/export$`);
|
|
760
762
|
const THEME_IMPORT_ROUTE = `${API_BASE}/themes/import`;
|
|
761
763
|
const THEME_BY_NAME_REGEX = new RegExp(`^${escapedBase}/themes/([a-z0-9\\-_]+)$`);
|
|
764
|
+
const SKETCH_PRESETS_ROUTE = `${API_BASE}/sketch-presets`;
|
|
765
|
+
const SKETCH_PRESET_BY_NAME_REGEX = new RegExp(`^${escapedBase}/sketch-presets/([a-z0-9\\-_]+)$`);
|
|
762
766
|
const PRODUCTION_ROUTE = `${API_BASE}/production`;
|
|
763
767
|
async function handleListColorsAndType(_ctx) {
|
|
764
768
|
const files = colorsAndTypeResource.listNames().map((fileName) => {
|
|
@@ -1290,6 +1294,61 @@ ${lines.join("\n")}
|
|
|
1290
1294
|
}
|
|
1291
1295
|
});
|
|
1292
1296
|
}
|
|
1297
|
+
async function handleListSketchPresets({ res }) {
|
|
1298
|
+
const files = sketchPresetsResource.listNames().map((fileName) => {
|
|
1299
|
+
let data = null;
|
|
1300
|
+
try {
|
|
1301
|
+
data = sketchPresetsResource.readJson(fileName);
|
|
1302
|
+
} catch {
|
|
1303
|
+
}
|
|
1304
|
+
return {
|
|
1305
|
+
name: data?.name || fileName,
|
|
1306
|
+
fileName,
|
|
1307
|
+
updatedAt: data?.updatedAt || ""
|
|
1308
|
+
};
|
|
1309
|
+
});
|
|
1310
|
+
jsonResponse(res, 200, { files });
|
|
1311
|
+
}
|
|
1312
|
+
async function handleSketchPresetByName({ params, req, res }) {
|
|
1313
|
+
const [fileName] = params;
|
|
1314
|
+
if (rejectReservedName(res, fileName)) return;
|
|
1315
|
+
const filePath = sketchPresetsResource.filePath(fileName);
|
|
1316
|
+
if (req.method === "GET") {
|
|
1317
|
+
const raw = sketchPresetsResource.readJson(fileName);
|
|
1318
|
+
if (!raw) {
|
|
1319
|
+
jsonResponse(res, 404, { error: "Not found" });
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
jsonResponse(res, 200, { ...raw, _fileName: fileName });
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
if (req.method === "PUT") {
|
|
1326
|
+
const body = JSON.parse(await readBody(req));
|
|
1327
|
+
if (!body || typeof body !== "object" || !body.settings || typeof body.settings !== "object") {
|
|
1328
|
+
jsonResponse(res, 400, { error: "A sketch preset needs a settings object" });
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
body.name = String(body.name || fileName);
|
|
1332
|
+
body.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1333
|
+
if (fs.existsSync(filePath)) {
|
|
1334
|
+
try {
|
|
1335
|
+
const existing = JSON.parse(fs.readFileSync(filePath, "utf-8"));
|
|
1336
|
+
if (existing.createdAt) body.createdAt = existing.createdAt;
|
|
1337
|
+
} catch {
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
if (!body.createdAt) body.createdAt = body.updatedAt;
|
|
1341
|
+
sketchPresetsResource.ensureDir();
|
|
1342
|
+
fs.writeFileSync(filePath, JSON.stringify(body, null, 2));
|
|
1343
|
+
jsonResponse(res, 200, { ok: true, fileName });
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
if (req.method === "DELETE") {
|
|
1347
|
+
if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
1348
|
+
jsonResponse(res, 200, { ok: true });
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1293
1352
|
function methodNotAllowed({ res }) {
|
|
1294
1353
|
jsonResponse(res, 405, { error: "Method not allowed" });
|
|
1295
1354
|
}
|
|
@@ -1366,6 +1425,14 @@ ${lines.join("\n")}
|
|
|
1366
1425
|
{ method: "PUT", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
|
|
1367
1426
|
{ method: "DELETE", pattern: THEME_BY_NAME_REGEX, handler: handleThemeByName },
|
|
1368
1427
|
// Production — the whole-look adopt door
|
|
1428
|
+
{ method: "GET", pattern: SKETCH_PRESETS_ROUTE, handler: handleListSketchPresets },
|
|
1429
|
+
{ method: "PUT", pattern: SKETCH_PRESETS_ROUTE, handler: methodNotAllowed },
|
|
1430
|
+
{ method: "POST", pattern: SKETCH_PRESETS_ROUTE, handler: methodNotAllowed },
|
|
1431
|
+
{ method: "DELETE", pattern: SKETCH_PRESETS_ROUTE, handler: methodNotAllowed },
|
|
1432
|
+
{ method: "GET", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: handleSketchPresetByName },
|
|
1433
|
+
{ method: "PUT", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: handleSketchPresetByName },
|
|
1434
|
+
{ method: "DELETE", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: handleSketchPresetByName },
|
|
1435
|
+
{ method: "POST", pattern: SKETCH_PRESET_BY_NAME_REGEX, handler: methodNotAllowed },
|
|
1369
1436
|
{ method: "PUT", pattern: PRODUCTION_ROUTE, handler: handleAdoptLook },
|
|
1370
1437
|
{ method: "GET", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
|
|
1371
1438
|
{ method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
|
|
@@ -1659,6 +1659,7 @@ function resolveDataDirs(opts = {}) {
|
|
|
1659
1659
|
colorsAndTypeDir: opts.colorsAndTypeDir ? import_path4.default.resolve(opts.colorsAndTypeDir) : fileConfig.colorsAndTypeDir ? import_path4.default.resolve(fileConfig.colorsAndTypeDir) : sub("colors-and-type"),
|
|
1660
1660
|
componentConfigsDir: opts.componentConfigsDir ? import_path4.default.resolve(opts.componentConfigsDir) : fileConfig.componentConfigsDir ? import_path4.default.resolve(fileConfig.componentConfigsDir) : sub("component-configs"),
|
|
1661
1661
|
themesDir: opts.themesDir ? import_path4.default.resolve(opts.themesDir) : fileConfig.themesDir ? import_path4.default.resolve(fileConfig.themesDir) : sub("themes"),
|
|
1662
|
+
sketchPresetsDir: sub("sketch-presets"),
|
|
1662
1663
|
legacyManifestsDir: fileConfig.manifestsDir ? import_path4.default.resolve(fileConfig.manifestsDir) : void 0
|
|
1663
1664
|
};
|
|
1664
1665
|
}
|
|
@@ -7,6 +7,13 @@ interface CurveAnchor {
|
|
|
7
7
|
outDy: number;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/** The `to <side-or-corner>` keywords CSS accepts in place of an angle. A
|
|
11
|
+
* keyword angles the gradient line off the box's own diagonal, so it tracks
|
|
12
|
+
* the element's aspect ratio where a fixed angle cannot: `to bottom right`
|
|
13
|
+
* reads as ~95deg across a wide heading and ~111deg once that heading wraps.
|
|
14
|
+
* That is the whole reason to carry them — a degree cannot express it. */
|
|
15
|
+
declare const LINEAR_DIRECTIONS: readonly ["to top", "to top right", "to right", "to bottom right", "to bottom", "to bottom left", "to left", "to top left"];
|
|
16
|
+
type LinearDirection = (typeof LINEAR_DIRECTIONS)[number];
|
|
10
17
|
interface GradientStop$1 {
|
|
11
18
|
/** 0–100 percentage along the gradient axis. */
|
|
12
19
|
position: number;
|
|
@@ -25,6 +32,10 @@ interface GradientStop$1 {
|
|
|
25
32
|
interface GradientValue {
|
|
26
33
|
type: 'linear' | 'radial' | 'solid' | 'none';
|
|
27
34
|
angle: number;
|
|
35
|
+
/** Emitted in place of `angle` on a `linear` gradient. `angle` is retained
|
|
36
|
+
* underneath so clearing the direction restores the user's degrees, the
|
|
37
|
+
* same way a radial keeps its angle. */
|
|
38
|
+
direction?: LinearDirection;
|
|
28
39
|
radius?: number;
|
|
29
40
|
centerX?: number;
|
|
30
41
|
aspectX?: number;
|
|
@@ -136,7 +147,7 @@ interface FontSource {
|
|
|
136
147
|
}
|
|
137
148
|
type SystemCascadePreset = 'system-ui-sans' | 'system-ui-serif' | 'system-ui-mono';
|
|
138
149
|
type GenericFamily = 'sans-serif' | 'serif' | 'monospace' | 'cursive' | 'fantasy';
|
|
139
|
-
type FontStackVariable = '--font-display' | '--font-sans' | '--font-serif' | '--font-mono';
|
|
150
|
+
type FontStackVariable = '--font-display' | '--font-sans' | '--font-serif' | '--font-mono' | '--font-editorial';
|
|
140
151
|
type FontStackSlot = {
|
|
141
152
|
kind: 'project';
|
|
142
153
|
familyId: string;
|
|
@@ -7,6 +7,13 @@ interface CurveAnchor {
|
|
|
7
7
|
outDy: number;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/** The `to <side-or-corner>` keywords CSS accepts in place of an angle. A
|
|
11
|
+
* keyword angles the gradient line off the box's own diagonal, so it tracks
|
|
12
|
+
* the element's aspect ratio where a fixed angle cannot: `to bottom right`
|
|
13
|
+
* reads as ~95deg across a wide heading and ~111deg once that heading wraps.
|
|
14
|
+
* That is the whole reason to carry them — a degree cannot express it. */
|
|
15
|
+
declare const LINEAR_DIRECTIONS: readonly ["to top", "to top right", "to right", "to bottom right", "to bottom", "to bottom left", "to left", "to top left"];
|
|
16
|
+
type LinearDirection = (typeof LINEAR_DIRECTIONS)[number];
|
|
10
17
|
interface GradientStop$1 {
|
|
11
18
|
/** 0–100 percentage along the gradient axis. */
|
|
12
19
|
position: number;
|
|
@@ -25,6 +32,10 @@ interface GradientStop$1 {
|
|
|
25
32
|
interface GradientValue {
|
|
26
33
|
type: 'linear' | 'radial' | 'solid' | 'none';
|
|
27
34
|
angle: number;
|
|
35
|
+
/** Emitted in place of `angle` on a `linear` gradient. `angle` is retained
|
|
36
|
+
* underneath so clearing the direction restores the user's degrees, the
|
|
37
|
+
* same way a radial keeps its angle. */
|
|
38
|
+
direction?: LinearDirection;
|
|
28
39
|
radius?: number;
|
|
29
40
|
centerX?: number;
|
|
30
41
|
aspectX?: number;
|
|
@@ -136,7 +147,7 @@ interface FontSource {
|
|
|
136
147
|
}
|
|
137
148
|
type SystemCascadePreset = 'system-ui-sans' | 'system-ui-serif' | 'system-ui-mono';
|
|
138
149
|
type GenericFamily = 'sans-serif' | 'serif' | 'monospace' | 'cursive' | 'fantasy';
|
|
139
|
-
type FontStackVariable = '--font-display' | '--font-sans' | '--font-serif' | '--font-mono';
|
|
150
|
+
type FontStackVariable = '--font-display' | '--font-sans' | '--font-serif' | '--font-mono' | '--font-editorial';
|
|
140
151
|
type FontStackSlot = {
|
|
141
152
|
kind: 'project';
|
|
142
153
|
familyId: string;
|
|
@@ -462,6 +462,61 @@ var tokensCssMigration_2026_08_19_oklchColorValues = {
|
|
|
462
462
|
}
|
|
463
463
|
};
|
|
464
464
|
|
|
465
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-08-25-editorial-type-role.ts
|
|
466
|
+
var STACK = [{ name: "--font-editorial", value: "var(--font-sans)" }];
|
|
467
|
+
var BUNDLE2 = [
|
|
468
|
+
{ name: "--editorial-font-family", value: "var(--font-editorial)" },
|
|
469
|
+
{ name: "--editorial-font-size", value: "var(--font-size-md)" },
|
|
470
|
+
{ name: "--editorial-font-weight", value: "var(--font-weight-normal)" },
|
|
471
|
+
{ name: "--editorial-line-height", value: "var(--line-height-normal)" },
|
|
472
|
+
{ name: "--editorial-letter-spacing", value: "var(--letter-spacing-normal)" }
|
|
473
|
+
];
|
|
474
|
+
var tokensCssMigration_2026_08_25_editorialTypeRole = {
|
|
475
|
+
id: "2026-08-25-editorial-type-role",
|
|
476
|
+
kind: "additive",
|
|
477
|
+
description: "Add the editorial type role (--font-editorial and the --editorial-* bundle)",
|
|
478
|
+
apply(css) {
|
|
479
|
+
const withStack = ensureScale(css, {
|
|
480
|
+
anchorPrefixes: ["--font-mono", "--font-serif", "--font-sans", "--font-display"],
|
|
481
|
+
entries: STACK
|
|
482
|
+
});
|
|
483
|
+
return ensureScale(withStack, {
|
|
484
|
+
sectionComment: "Editorial \u2014 the long-reading role, body face until repointed",
|
|
485
|
+
anchorPrefixes: [
|
|
486
|
+
"--eyebrow-",
|
|
487
|
+
"--code-",
|
|
488
|
+
"--body-",
|
|
489
|
+
"--heading-",
|
|
490
|
+
"--letter-spacing-",
|
|
491
|
+
"--line-height-",
|
|
492
|
+
"--font-weight-",
|
|
493
|
+
"--font-size-",
|
|
494
|
+
"--font-"
|
|
495
|
+
],
|
|
496
|
+
entries: BUNDLE2
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
// vite-plugin/tokensCssMigrations/migrations/2026-08-26-gradient-stops.ts
|
|
502
|
+
var STOPS_RE = /^(?:linear|radial)-gradient\(\s*[^,]+,\s*(.+)\)$/i;
|
|
503
|
+
var tokensCssMigration_2026_08_26_gradientStops = {
|
|
504
|
+
id: "2026-08-26-gradient-stops",
|
|
505
|
+
kind: "additive",
|
|
506
|
+
description: "Add --gradient-N-stops companions to the gradient slots",
|
|
507
|
+
apply(css) {
|
|
508
|
+
const values = collectTokenValues(css);
|
|
509
|
+
const entries = [];
|
|
510
|
+
for (const [name, value] of values) {
|
|
511
|
+
if (!/^--gradient-\d+$/.test(name)) continue;
|
|
512
|
+
const stops = value.match(STOPS_RE);
|
|
513
|
+
if (stops) entries.push({ name: `${name}-stops`, value: stops[1].trim() });
|
|
514
|
+
}
|
|
515
|
+
if (entries.length === 0) return css;
|
|
516
|
+
return ensureScale(css, { anchorPrefixes: ["--gradient-"], entries });
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
|
|
465
520
|
// vite-plugin/files/dataPaths.ts
|
|
466
521
|
var import_fs = __toESM(require("fs"), 1);
|
|
467
522
|
var import_path = __toESM(require("path"), 1);
|
|
@@ -505,7 +560,9 @@ var TOKENS_CSS_MIGRATIONS = [
|
|
|
505
560
|
tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions,
|
|
506
561
|
tokensCssMigration_2026_07_20_lineHeightRename,
|
|
507
562
|
tokensCssMigration_2026_07_20_semanticTextStyles,
|
|
508
|
-
tokensCssMigration_2026_08_19_oklchColorValues
|
|
563
|
+
tokensCssMigration_2026_08_19_oklchColorValues,
|
|
564
|
+
tokensCssMigration_2026_08_25_editorialTypeRole,
|
|
565
|
+
tokensCssMigration_2026_08_26_gradientStops
|
|
509
566
|
];
|
|
510
567
|
function runTokensCssMigrations(css) {
|
|
511
568
|
return foldMigrations(css, () => true);
|
|
@@ -13,11 +13,11 @@ import {
|
|
|
13
13
|
runTokensCssMigrations,
|
|
14
14
|
semverBumpType,
|
|
15
15
|
validateTokensCss
|
|
16
|
-
} from "../chunk-
|
|
17
|
-
import "../chunk-
|
|
16
|
+
} from "../chunk-E5QYON4L.js";
|
|
17
|
+
import "../chunk-XWXIMTWZ.js";
|
|
18
18
|
import {
|
|
19
19
|
readLiveTokensConfig
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-Y5CNFSSV.js";
|
|
21
21
|
export {
|
|
22
22
|
TOKENS_CSS_MIGRATIONS,
|
|
23
23
|
collectDefinedTokens,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motion-proto/live-tokens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
|
|
6
6
|
"keywords": [
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"src/live-tokens/data/colors-and-type/midnight-study.json",
|
|
31
31
|
"src/live-tokens/data/colors-and-type/ocean.json",
|
|
32
32
|
"src/live-tokens/data/colors-and-type/royal-velvet.json",
|
|
33
|
+
"src/live-tokens/data/colors-and-type/sketchy.json",
|
|
33
34
|
"src/live-tokens/data/colors-and-type/spring-meadow.json",
|
|
34
35
|
"src/live-tokens/data/colors-and-type/sunset.json",
|
|
35
36
|
"src/live-tokens/data/themes/autumn.json",
|
|
@@ -37,6 +38,7 @@
|
|
|
37
38
|
"src/live-tokens/data/themes/midnight-study.json",
|
|
38
39
|
"src/live-tokens/data/themes/ocean.json",
|
|
39
40
|
"src/live-tokens/data/themes/royal-velvet.json",
|
|
41
|
+
"src/live-tokens/data/themes/sketchy.json",
|
|
40
42
|
"src/live-tokens/data/themes/spring-meadow.json",
|
|
41
43
|
"src/live-tokens/data/themes/sunset.json",
|
|
42
44
|
"dist-plugin",
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
import { parseGoogleFontsUrl } from './fontParse';
|
|
9
9
|
import { familyIndex, resolvedFaceName } from './fontPairing';
|
|
10
10
|
|
|
11
|
-
export type PairingSlot = 'display' | 'body' | 'serif' | 'mono';
|
|
11
|
+
export type PairingSlot = 'display' | 'body' | 'serif' | 'mono' | 'editorial';
|
|
12
12
|
|
|
13
13
|
export interface PairingFace {
|
|
14
14
|
name: string;
|
|
@@ -44,13 +44,14 @@ export interface FontPairingResult {
|
|
|
44
44
|
|
|
45
45
|
/** Slot order is also the order stamped sources land in `fontSources`;
|
|
46
46
|
* `check:preset-themes` reads the preset pair back out positionally. */
|
|
47
|
-
export const SLOT_ORDER: PairingSlot[] = ['display', 'body', 'serif', 'mono'];
|
|
47
|
+
export const SLOT_ORDER: PairingSlot[] = ['display', 'body', 'serif', 'mono', 'editorial'];
|
|
48
48
|
|
|
49
49
|
export const SLOT_VARIABLES: Record<PairingSlot, FontStackVariable> = {
|
|
50
50
|
display: '--font-display',
|
|
51
51
|
body: '--font-sans',
|
|
52
52
|
serif: '--font-serif',
|
|
53
53
|
mono: '--font-mono',
|
|
54
|
+
editorial: '--font-editorial',
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
export function slugifyFamily(name: string): string {
|
|
@@ -115,9 +115,37 @@ export function defaultFontStacks(sources: FontSource[]): FontStack[] {
|
|
|
115
115
|
{ kind: 'generic', value: 'monospace' },
|
|
116
116
|
],
|
|
117
117
|
},
|
|
118
|
+
{
|
|
119
|
+
variable: '--font-editorial',
|
|
120
|
+
slots: [
|
|
121
|
+
...pick('Manrope'),
|
|
122
|
+
{ kind: 'system', preset: 'system-ui-sans' },
|
|
123
|
+
{ kind: 'generic', value: 'sans-serif' },
|
|
124
|
+
],
|
|
125
|
+
},
|
|
118
126
|
];
|
|
119
127
|
}
|
|
120
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Seed `--font-editorial` from `--font-sans` on files written before the
|
|
131
|
+
* editorial role existed. The role ships as "the body face until a consumer
|
|
132
|
+
* repoints it", so cloning the body stack is the migration: a theme that never
|
|
133
|
+
* touches editorial keeps rendering exactly as it did.
|
|
134
|
+
*
|
|
135
|
+
* Presence-based like the rest of this module, so re-running is a no-op and no
|
|
136
|
+
* schemaVersion step is needed.
|
|
137
|
+
*/
|
|
138
|
+
function ensureEditorialStack(stacks: FontStack[]): boolean {
|
|
139
|
+
if (stacks.some((s) => s.variable === '--font-editorial')) return false;
|
|
140
|
+
const sans = stacks.find((s) => s.variable === '--font-sans');
|
|
141
|
+
if (!sans) return false;
|
|
142
|
+
stacks.push({
|
|
143
|
+
variable: '--font-editorial',
|
|
144
|
+
slots: sans.slots.map((slot) => ({ ...slot })),
|
|
145
|
+
});
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
121
149
|
// Older themes have `kind: 'font-face'` sources with embedded cssText that
|
|
122
150
|
// references local woff2 files. The url() resolution for those embedded refs
|
|
123
151
|
// is fragile in consumers, so swap any font-face source whose cssText is for
|
|
@@ -161,9 +189,11 @@ export function migrateColorsAndTypeFonts(colorsAndType: ColorsAndType): { migra
|
|
|
161
189
|
if (!colorsAndType.fontStacks || colorsAndType.fontStacks.length === 0) {
|
|
162
190
|
colorsAndType.fontStacks = defaultFontStacks(colorsAndType.fontSources);
|
|
163
191
|
migrated = true;
|
|
192
|
+
} else if (ensureEditorialStack(colorsAndType.fontStacks)) {
|
|
193
|
+
migrated = true;
|
|
164
194
|
}
|
|
165
195
|
if (colorsAndType.cssVariables) {
|
|
166
|
-
for (const key of ['--font-display', '--font-sans', '--font-serif', '--font-mono']) {
|
|
196
|
+
for (const key of ['--font-display', '--font-sans', '--font-serif', '--font-mono', '--font-editorial']) {
|
|
167
197
|
if (key in colorsAndType.cssVariables) {
|
|
168
198
|
delete colorsAndType.cssVariables[key];
|
|
169
199
|
migrated = true;
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* derives the same CSS vars from the persisted config.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { cssColorToOklch,
|
|
16
|
+
import { cssColorToOklch, oklchToCss, gamutClamp, type Oklch } from './oklch';
|
|
17
17
|
import { type CurveAnchor, sampleCurve, makeAnchor, tangentAnchor, resmoothAutoCurve } from '../../ui/curveEngine';
|
|
18
18
|
import type { PaletteConfig } from '../themes/themeTypes';
|
|
19
19
|
|
|
@@ -204,7 +204,14 @@ export type DerivedValue =
|
|
|
204
204
|
* then serialized as `oklch()`. Idempotent on the already-in-gamut per-step
|
|
205
205
|
* derivation output. `raw` passes through untouched. */
|
|
206
206
|
export function serializeDerivedValue(value: DerivedValue): string {
|
|
207
|
-
|
|
207
|
+
// Emitted unclamped: the stored basis is OKLCH, and clamping into sRGB threw
|
|
208
|
+
// away chroma a wide-gamut display can actually show. Values already inside
|
|
209
|
+
// sRGB serialize identically (`gamutClamp` returns them untouched), so this
|
|
210
|
+
// moves nothing in an existing theme; only intent authored beyond sRGB — a
|
|
211
|
+
// Tailwind v4 ramp, say — now survives to the browser, which does its own
|
|
212
|
+
// gamut mapping at paint. `oklchToCssClamped` still backs the hex readouts,
|
|
213
|
+
// where a clamped projection is the whole point.
|
|
214
|
+
return value.kind === 'raw' ? value.css : oklchToCss(value.l, value.c, value.h);
|
|
208
215
|
}
|
|
209
216
|
|
|
210
217
|
export function computePaletteOklch(
|