@motion-proto/live-tokens 0.33.1 → 0.35.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-build-page/SKILL.md +3 -3
- package/.claude/skills/live-tokens-create-component/SKILL.md +3 -3
- package/CHANGELOG.md +59 -0
- package/README.md +8 -6
- package/bin/cli.mjs +19 -5
- package/bin/migrate-routes.mjs +179 -0
- package/dist-plugin/{chunk-MJO4T3CM.js → chunk-D77VD4Z6.js} +55 -0
- package/dist-plugin/index.cjs +27 -0
- package/dist-plugin/index.d.cts +1 -0
- package/dist-plugin/index.d.ts +1 -0
- package/dist-plugin/index.js +17 -1
- package/dist-plugin/tokensCssMigrations/index.cjs +59 -0
- package/dist-plugin/tokensCssMigrations/index.d.cts +55 -1
- package/dist-plugin/tokensCssMigrations/index.d.ts +55 -1
- package/dist-plugin/tokensCssMigrations/index.js +9 -1
- package/package.json +3 -2
- package/src/editor/core/cssVarSync.ts +3 -3
- package/src/editor/core/routing/ownedRoutes.ts +11 -0
- package/src/editor/core/routing/router.ts +2 -1
- package/src/editor/docs/Docs.svelte +3 -2
- package/src/editor/docs/content/creating-components.md +2 -2
- package/src/editor/docs/content/getting-started.md +2 -2
- package/src/editor/docs/content.generated.ts +2 -2
- package/src/editor/overlay/LiveEditorOverlay.svelte +8 -5
- package/src/editor/overlay/LiveTokensRouter.svelte +12 -9
- package/src/editor/pages/Editor.svelte +2 -1
- package/src/editor/ui/EditorViewSwitcher.svelte +7 -4
- package/template/README.md +5 -4
- package/template/src/App.svelte +4 -3
- package/template/src/pages/Home.svelte +2 -2
|
@@ -33,12 +33,16 @@ __export(tokensCssMigrations_exports, {
|
|
|
33
33
|
TOKENS_CSS_MIGRATIONS: () => TOKENS_CSS_MIGRATIONS,
|
|
34
34
|
collectDefinedTokens: () => collectDefinedTokens,
|
|
35
35
|
collectReferencedTokens: () => collectReferencedTokens,
|
|
36
|
+
enforceBreakingRequiresMajor: () => enforceBreakingRequiresMajor,
|
|
36
37
|
ensureScale: () => ensureScale,
|
|
38
|
+
findContractViolations: () => findContractViolations,
|
|
37
39
|
readLiveTokensConfig: () => readLiveTokensConfig,
|
|
38
40
|
removeToken: () => removeToken,
|
|
39
41
|
removeTokensMatching: () => removeTokensMatching,
|
|
40
42
|
renameToken: () => renameToken,
|
|
43
|
+
runAdditiveTokensCssMigrations: () => runAdditiveTokensCssMigrations,
|
|
41
44
|
runTokensCssMigrations: () => runTokensCssMigrations,
|
|
45
|
+
semverBumpType: () => semverBumpType,
|
|
42
46
|
validateTokensCss: () => validateTokensCss
|
|
43
47
|
});
|
|
44
48
|
module.exports = __toCommonJS(tokensCssMigrations_exports);
|
|
@@ -151,6 +155,7 @@ function escapeRe(s) {
|
|
|
151
155
|
// vite-plugin/tokensCssMigrations/migrations/2026-05-29-typography-scale-additions.ts
|
|
152
156
|
var tokensCssMigration_2026_05_29_typographyScaleAdditions = {
|
|
153
157
|
id: "2026-05-29-typography-scale-additions",
|
|
158
|
+
kind: "additive",
|
|
154
159
|
description: "Add --line-height-{xs..xl}, --letter-spacing-* and --ease-out-quart scales",
|
|
155
160
|
apply(css) {
|
|
156
161
|
let out = css;
|
|
@@ -189,6 +194,7 @@ var tokensCssMigration_2026_05_29_typographyScaleAdditions = {
|
|
|
189
194
|
var KEEP_SEGMENTS = /* @__PURE__ */ new Set(["lg", "md", "sm"]);
|
|
190
195
|
var tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup = {
|
|
191
196
|
id: "2026-05-29-sectiondivider-legacy-axis-cleanup",
|
|
197
|
+
kind: "breaking",
|
|
192
198
|
description: "Remove legacy --sectiondivider-* tokens not on the lg/md/sm axis",
|
|
193
199
|
apply(css) {
|
|
194
200
|
return removeTokensMatching(css, (name) => {
|
|
@@ -202,6 +208,7 @@ var tokensCssMigration_2026_05_29_sectiondividerLegacyAxisCleanup = {
|
|
|
202
208
|
// vite-plugin/tokensCssMigrations/migrations/2026-06-03-transform-scale-additions.ts
|
|
203
209
|
var tokensCssMigration_2026_06_03_transformScaleAdditions = {
|
|
204
210
|
id: "2026-06-03-transform-scale-additions",
|
|
211
|
+
kind: "additive",
|
|
205
212
|
description: "Add the --scale-{sm..2xl} transform-multiplier scale",
|
|
206
213
|
apply(css) {
|
|
207
214
|
return ensureScale(css, {
|
|
@@ -221,6 +228,7 @@ var tokensCssMigration_2026_06_03_transformScaleAdditions = {
|
|
|
221
228
|
// vite-plugin/tokensCssMigrations/migrations/2026-06-04-remove-dead-size-icon-scale.ts
|
|
222
229
|
var tokensCssMigration_2026_06_04_removeDeadSizeIconScale = {
|
|
223
230
|
id: "2026-06-04-remove-dead-size-icon-scale",
|
|
231
|
+
kind: "breaking",
|
|
224
232
|
description: "Remove the unused --size-icon-* scale (live scale is --icon-size-*)",
|
|
225
233
|
apply(css) {
|
|
226
234
|
return removeTokensMatching(css, (name) => name.startsWith("--size-icon-"));
|
|
@@ -230,6 +238,7 @@ var tokensCssMigration_2026_06_04_removeDeadSizeIconScale = {
|
|
|
230
238
|
// vite-plugin/tokensCssMigrations/migrations/2026-06-04-easing-color-and-typescale-additions.ts
|
|
231
239
|
var tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions = {
|
|
232
240
|
id: "2026-06-04-easing-color-and-typescale-additions",
|
|
241
|
+
kind: "additive",
|
|
233
242
|
description: "Add the full --ease-* scale, --color-white/black, and --font-size-7xl",
|
|
234
243
|
apply(css) {
|
|
235
244
|
let out = css;
|
|
@@ -345,9 +354,16 @@ var TOKENS_CSS_MIGRATIONS = [
|
|
|
345
354
|
tokensCssMigration_2026_06_04_easingColorAndTypescaleAdditions
|
|
346
355
|
];
|
|
347
356
|
function runTokensCssMigrations(css) {
|
|
357
|
+
return foldMigrations(css, () => true);
|
|
358
|
+
}
|
|
359
|
+
function runAdditiveTokensCssMigrations(css) {
|
|
360
|
+
return foldMigrations(css, (m) => m.kind === "additive");
|
|
361
|
+
}
|
|
362
|
+
function foldMigrations(css, include) {
|
|
348
363
|
let out = css;
|
|
349
364
|
const applied = [];
|
|
350
365
|
for (const m of TOKENS_CSS_MIGRATIONS) {
|
|
366
|
+
if (!include(m)) continue;
|
|
351
367
|
const next = m.apply(out);
|
|
352
368
|
if (next !== out) {
|
|
353
369
|
applied.push(m.id);
|
|
@@ -356,6 +372,45 @@ function runTokensCssMigrations(css) {
|
|
|
356
372
|
}
|
|
357
373
|
return { css: out, applied, changed: out !== css };
|
|
358
374
|
}
|
|
375
|
+
function findContractViolations(canonicalCss) {
|
|
376
|
+
const violations = [];
|
|
377
|
+
for (const m of TOKENS_CSS_MIGRATIONS) {
|
|
378
|
+
if (m.kind !== "additive") continue;
|
|
379
|
+
const before = collectDefinedTokens(canonicalCss);
|
|
380
|
+
const after = collectDefinedTokens(m.apply(canonicalCss));
|
|
381
|
+
const removed = [...before].filter((t) => !after.has(t)).sort();
|
|
382
|
+
if (removed.length) violations.push({ id: m.id, removed });
|
|
383
|
+
}
|
|
384
|
+
return violations;
|
|
385
|
+
}
|
|
386
|
+
function semverBumpType(prev, next) {
|
|
387
|
+
const p = parseSemver(prev);
|
|
388
|
+
const n = parseSemver(next);
|
|
389
|
+
if (n.major > p.major) return "major";
|
|
390
|
+
if (n.major === p.major && n.minor > p.minor) return "minor";
|
|
391
|
+
if (n.major === p.major && n.minor === p.minor && n.patch > p.patch) return "patch";
|
|
392
|
+
return "none";
|
|
393
|
+
}
|
|
394
|
+
function parseSemver(v) {
|
|
395
|
+
const [core] = v.replace(/^v/, "").split(/[-+]/);
|
|
396
|
+
const [major = 0, minor = 0, patch = 0] = core.split(".").map((n) => Number(n) || 0);
|
|
397
|
+
return { major, minor, patch };
|
|
398
|
+
}
|
|
399
|
+
function enforceBreakingRequiresMajor(args) {
|
|
400
|
+
const breakingIds = args.newMigrations.filter((m) => m.kind === "breaking").map((m) => m.id);
|
|
401
|
+
const bump = semverBumpType(args.prevVersion, args.nextVersion);
|
|
402
|
+
if (breakingIds.length === 0 || bump === "major") {
|
|
403
|
+
return { level: "ok", breakingIds, bump, message: "" };
|
|
404
|
+
}
|
|
405
|
+
const pre1 = parseSemver(args.nextVersion).major < 1;
|
|
406
|
+
const ids = breakingIds.join(", ");
|
|
407
|
+
return {
|
|
408
|
+
level: pre1 ? "warn" : "error",
|
|
409
|
+
breakingIds,
|
|
410
|
+
bump,
|
|
411
|
+
message: `Breaking token migration(s) [${ids}] are shipping in a ${bump} bump (${args.prevVersion} -> ${args.nextVersion}). Token names are public API; ` + (pre1 ? `pre-1.0 this is allowed, but the CHANGELOG must flag it under "Changed (breaking)".` : `from 1.0.0 a breaking token change requires a major bump.`)
|
|
412
|
+
};
|
|
413
|
+
}
|
|
359
414
|
function validateTokensCss(input) {
|
|
360
415
|
const defined = /* @__PURE__ */ new Set([
|
|
361
416
|
...collectDefinedTokens(input.tokensCss),
|
|
@@ -385,11 +440,15 @@ function validateTokensCss(input) {
|
|
|
385
440
|
TOKENS_CSS_MIGRATIONS,
|
|
386
441
|
collectDefinedTokens,
|
|
387
442
|
collectReferencedTokens,
|
|
443
|
+
enforceBreakingRequiresMajor,
|
|
388
444
|
ensureScale,
|
|
445
|
+
findContractViolations,
|
|
389
446
|
readLiveTokensConfig,
|
|
390
447
|
removeToken,
|
|
391
448
|
removeTokensMatching,
|
|
392
449
|
renameToken,
|
|
450
|
+
runAdditiveTokensCssMigrations,
|
|
393
451
|
runTokensCssMigrations,
|
|
452
|
+
semverBumpType,
|
|
394
453
|
validateTokensCss
|
|
395
454
|
});
|
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
interface TokensCssMigration {
|
|
17
17
|
/** Unique id; convention: `YYYY-MM-DD-<short-name>`. */
|
|
18
18
|
id: string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether this migration is backward-compatible.
|
|
21
|
+
*
|
|
22
|
+
* Token names are public API (see TOKENS.md). `'additive'` only ever inserts
|
|
23
|
+
* new names, so it is safe to auto-apply to a consumer's vendored `tokens.css`
|
|
24
|
+
* (the dev plugin's `autoMigrate`). `'breaking'` renames or removes a name a
|
|
25
|
+
* consumer may reference, so it ships only with a major version (post-1.0) and
|
|
26
|
+
* is never auto-applied — it rides an explicit `live-tokens migrate`.
|
|
27
|
+
*/
|
|
28
|
+
kind: 'additive' | 'breaking';
|
|
19
29
|
/** One-line summary shown by the CLI when the migration applies. */
|
|
20
30
|
description: string;
|
|
21
31
|
/** Pure, idempotent transform on the `tokens.css` source. */
|
|
@@ -113,6 +123,50 @@ interface RunResult {
|
|
|
113
123
|
}
|
|
114
124
|
/** Fold every registered migration over `css`. Pure and idempotent. */
|
|
115
125
|
declare function runTokensCssMigrations(css: string): RunResult;
|
|
126
|
+
/**
|
|
127
|
+
* Fold only the `additive` migrations. Additive changes only insert new token
|
|
128
|
+
* names, so applying them to a consumer's vendored `tokens.css` is always
|
|
129
|
+
* backward-compatible — this is what the dev plugin's `autoMigrate` runs. The
|
|
130
|
+
* `breaking` migrations (rename/remove) are deliberately skipped; they ride an
|
|
131
|
+
* explicit `live-tokens migrate` during a major upgrade.
|
|
132
|
+
*/
|
|
133
|
+
declare function runAdditiveTokensCssMigrations(css: string): RunResult;
|
|
134
|
+
interface ContractViolation {
|
|
135
|
+
id: string;
|
|
136
|
+
/** Token names the migration removed or renamed away despite declaring `additive`. */
|
|
137
|
+
removed: string[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Guardrail for the token-as-API contract: an `additive` migration must never
|
|
141
|
+
* remove or rename a token. We verify behaviorally rather than trusting the
|
|
142
|
+
* label — apply each additive migration to the package's own canonical
|
|
143
|
+
* `tokens.css` (which defines the full current vocabulary) and flag any token
|
|
144
|
+
* that disappears. A rename surfaces as the removal of its old name, so it is
|
|
145
|
+
* caught too. This catches the dangerous direction: a breaking change shipped as
|
|
146
|
+
* a backward-compatible one. (Over-labeling a no-op as `breaking` is harmless
|
|
147
|
+
* and not checked.)
|
|
148
|
+
*/
|
|
149
|
+
declare function findContractViolations(canonicalCss: string): ContractViolation[];
|
|
150
|
+
type SemverBump = 'major' | 'minor' | 'patch' | 'none';
|
|
151
|
+
/** Classify the bump from `prev` to `next` (leading `v` and pre-release tags ignored). */
|
|
152
|
+
declare function semverBumpType(prev: string, next: string): SemverBump;
|
|
153
|
+
interface BreakingGateResult {
|
|
154
|
+
level: 'ok' | 'warn' | 'error';
|
|
155
|
+
breakingIds: string[];
|
|
156
|
+
bump: SemverBump;
|
|
157
|
+
message: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The version side of the token contract: a `breaking` migration introduced in a
|
|
161
|
+
* release requires a major version bump. Pre-1.0 (next major is 0) this is only
|
|
162
|
+
* a warning, since semver permits breaking changes in 0.x minors; from 1.0.0 on
|
|
163
|
+
* it is an error. Pure so the release check and its tests share one rule.
|
|
164
|
+
*/
|
|
165
|
+
declare function enforceBreakingRequiresMajor(args: {
|
|
166
|
+
newMigrations: TokensCssMigration[];
|
|
167
|
+
prevVersion: string;
|
|
168
|
+
nextVersion: string;
|
|
169
|
+
}): BreakingGateResult;
|
|
116
170
|
interface ComponentSource {
|
|
117
171
|
name: string;
|
|
118
172
|
source: string;
|
|
@@ -141,4 +195,4 @@ interface ValidateInput {
|
|
|
141
195
|
*/
|
|
142
196
|
declare function validateTokensCss(input: ValidateInput): MissingToken[];
|
|
143
197
|
|
|
144
|
-
export { type ComponentSource, type MissingToken, type RunResult, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, ensureScale, readLiveTokensConfig, removeToken, removeTokensMatching, renameToken, runTokensCssMigrations, validateTokensCss };
|
|
198
|
+
export { type BreakingGateResult, type ComponentSource, type ContractViolation, type MissingToken, type RunResult, type SemverBump, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, enforceBreakingRequiresMajor, ensureScale, findContractViolations, readLiveTokensConfig, removeToken, removeTokensMatching, renameToken, runAdditiveTokensCssMigrations, runTokensCssMigrations, semverBumpType, validateTokensCss };
|
|
@@ -16,6 +16,16 @@
|
|
|
16
16
|
interface TokensCssMigration {
|
|
17
17
|
/** Unique id; convention: `YYYY-MM-DD-<short-name>`. */
|
|
18
18
|
id: string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether this migration is backward-compatible.
|
|
21
|
+
*
|
|
22
|
+
* Token names are public API (see TOKENS.md). `'additive'` only ever inserts
|
|
23
|
+
* new names, so it is safe to auto-apply to a consumer's vendored `tokens.css`
|
|
24
|
+
* (the dev plugin's `autoMigrate`). `'breaking'` renames or removes a name a
|
|
25
|
+
* consumer may reference, so it ships only with a major version (post-1.0) and
|
|
26
|
+
* is never auto-applied — it rides an explicit `live-tokens migrate`.
|
|
27
|
+
*/
|
|
28
|
+
kind: 'additive' | 'breaking';
|
|
19
29
|
/** One-line summary shown by the CLI when the migration applies. */
|
|
20
30
|
description: string;
|
|
21
31
|
/** Pure, idempotent transform on the `tokens.css` source. */
|
|
@@ -113,6 +123,50 @@ interface RunResult {
|
|
|
113
123
|
}
|
|
114
124
|
/** Fold every registered migration over `css`. Pure and idempotent. */
|
|
115
125
|
declare function runTokensCssMigrations(css: string): RunResult;
|
|
126
|
+
/**
|
|
127
|
+
* Fold only the `additive` migrations. Additive changes only insert new token
|
|
128
|
+
* names, so applying them to a consumer's vendored `tokens.css` is always
|
|
129
|
+
* backward-compatible — this is what the dev plugin's `autoMigrate` runs. The
|
|
130
|
+
* `breaking` migrations (rename/remove) are deliberately skipped; they ride an
|
|
131
|
+
* explicit `live-tokens migrate` during a major upgrade.
|
|
132
|
+
*/
|
|
133
|
+
declare function runAdditiveTokensCssMigrations(css: string): RunResult;
|
|
134
|
+
interface ContractViolation {
|
|
135
|
+
id: string;
|
|
136
|
+
/** Token names the migration removed or renamed away despite declaring `additive`. */
|
|
137
|
+
removed: string[];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Guardrail for the token-as-API contract: an `additive` migration must never
|
|
141
|
+
* remove or rename a token. We verify behaviorally rather than trusting the
|
|
142
|
+
* label — apply each additive migration to the package's own canonical
|
|
143
|
+
* `tokens.css` (which defines the full current vocabulary) and flag any token
|
|
144
|
+
* that disappears. A rename surfaces as the removal of its old name, so it is
|
|
145
|
+
* caught too. This catches the dangerous direction: a breaking change shipped as
|
|
146
|
+
* a backward-compatible one. (Over-labeling a no-op as `breaking` is harmless
|
|
147
|
+
* and not checked.)
|
|
148
|
+
*/
|
|
149
|
+
declare function findContractViolations(canonicalCss: string): ContractViolation[];
|
|
150
|
+
type SemverBump = 'major' | 'minor' | 'patch' | 'none';
|
|
151
|
+
/** Classify the bump from `prev` to `next` (leading `v` and pre-release tags ignored). */
|
|
152
|
+
declare function semverBumpType(prev: string, next: string): SemverBump;
|
|
153
|
+
interface BreakingGateResult {
|
|
154
|
+
level: 'ok' | 'warn' | 'error';
|
|
155
|
+
breakingIds: string[];
|
|
156
|
+
bump: SemverBump;
|
|
157
|
+
message: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* The version side of the token contract: a `breaking` migration introduced in a
|
|
161
|
+
* release requires a major version bump. Pre-1.0 (next major is 0) this is only
|
|
162
|
+
* a warning, since semver permits breaking changes in 0.x minors; from 1.0.0 on
|
|
163
|
+
* it is an error. Pure so the release check and its tests share one rule.
|
|
164
|
+
*/
|
|
165
|
+
declare function enforceBreakingRequiresMajor(args: {
|
|
166
|
+
newMigrations: TokensCssMigration[];
|
|
167
|
+
prevVersion: string;
|
|
168
|
+
nextVersion: string;
|
|
169
|
+
}): BreakingGateResult;
|
|
116
170
|
interface ComponentSource {
|
|
117
171
|
name: string;
|
|
118
172
|
source: string;
|
|
@@ -141,4 +195,4 @@ interface ValidateInput {
|
|
|
141
195
|
*/
|
|
142
196
|
declare function validateTokensCss(input: ValidateInput): MissingToken[];
|
|
143
197
|
|
|
144
|
-
export { type ComponentSource, type MissingToken, type RunResult, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, ensureScale, readLiveTokensConfig, removeToken, removeTokensMatching, renameToken, runTokensCssMigrations, validateTokensCss };
|
|
198
|
+
export { type BreakingGateResult, type ComponentSource, type ContractViolation, type MissingToken, type RunResult, type SemverBump, TOKENS_CSS_MIGRATIONS, type TokensCssMigration, type ValidateInput, collectDefinedTokens, collectReferencedTokens, enforceBreakingRequiresMajor, ensureScale, findContractViolations, readLiveTokensConfig, removeToken, removeTokensMatching, renameToken, runAdditiveTokensCssMigrations, runTokensCssMigrations, semverBumpType, validateTokensCss };
|
|
@@ -2,23 +2,31 @@ import {
|
|
|
2
2
|
TOKENS_CSS_MIGRATIONS,
|
|
3
3
|
collectDefinedTokens,
|
|
4
4
|
collectReferencedTokens,
|
|
5
|
+
enforceBreakingRequiresMajor,
|
|
5
6
|
ensureScale,
|
|
7
|
+
findContractViolations,
|
|
6
8
|
readLiveTokensConfig,
|
|
7
9
|
removeToken,
|
|
8
10
|
removeTokensMatching,
|
|
9
11
|
renameToken,
|
|
12
|
+
runAdditiveTokensCssMigrations,
|
|
10
13
|
runTokensCssMigrations,
|
|
14
|
+
semverBumpType,
|
|
11
15
|
validateTokensCss
|
|
12
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-D77VD4Z6.js";
|
|
13
17
|
export {
|
|
14
18
|
TOKENS_CSS_MIGRATIONS,
|
|
15
19
|
collectDefinedTokens,
|
|
16
20
|
collectReferencedTokens,
|
|
21
|
+
enforceBreakingRequiresMajor,
|
|
17
22
|
ensureScale,
|
|
23
|
+
findContractViolations,
|
|
18
24
|
readLiveTokensConfig,
|
|
19
25
|
removeToken,
|
|
20
26
|
removeTokensMatching,
|
|
21
27
|
renameToken,
|
|
28
|
+
runAdditiveTokensCssMigrations,
|
|
22
29
|
runTokensCssMigrations,
|
|
30
|
+
semverBumpType,
|
|
23
31
|
validateTokensCss
|
|
24
32
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motion-proto/live-tokens",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Design token editor with live CSS variable editing. Svelte 5 + Vite 8.",
|
|
6
6
|
"keywords": [
|
|
@@ -101,12 +101,13 @@
|
|
|
101
101
|
"check:component-defaults": "node scripts/sync-component-defaults.mjs --check",
|
|
102
102
|
"check:production-is-default": "node scripts/check-production-is-default.mjs",
|
|
103
103
|
"check:docs-content": "node scripts/sync-docs.mjs --check",
|
|
104
|
+
"check:token-contract": "node scripts/check-token-contract.mjs",
|
|
104
105
|
"sync:component-defaults": "node scripts/sync-component-defaults.mjs --write",
|
|
105
106
|
"sync:docs": "node scripts/sync-docs.mjs --write",
|
|
106
107
|
"collapse:manifest": "node scripts/collapse-manifest-to-default.mjs",
|
|
107
108
|
"check:smoke-install": "bash scripts/smoke-install.sh",
|
|
108
109
|
"check:smoke-create": "bash scripts/smoke-create.sh",
|
|
109
|
-
"prepublishOnly": "npm run check:no-style-imports && npm run check:slot-prose && npm run check:overlay-portal && npm run check:editor-font-isolation && npm run check:component-defaults && npm run check:production-is-default && npm run check:docs-content && npm run build:lib && npm run check:smoke-install && npm run check:smoke-create"
|
|
110
|
+
"prepublishOnly": "npm run check:no-style-imports && npm run check:slot-prose && npm run check:overlay-portal && npm run check:editor-font-isolation && npm run check:component-defaults && npm run check:production-is-default && npm run check:docs-content && npm run build:lib && npm run check:token-contract && npm run check:smoke-install && npm run check:smoke-create"
|
|
110
111
|
},
|
|
111
112
|
"peerDependencies": {
|
|
112
113
|
"@sveltejs/vite-plugin-svelte": "^7.0",
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* Writes to document.documentElement and — when running inside a same-origin
|
|
5
5
|
* iframe (the live-preview overlay) — also writes to
|
|
6
6
|
* window.parent.document.documentElement. This lets the overlay editor at
|
|
7
|
-
* /editor drive the host site's :root in real time without any
|
|
8
|
-
* infrastructure.
|
|
7
|
+
* /live-tokens/editor drive the host site's :root in real time without any
|
|
8
|
+
* message-passing infrastructure.
|
|
9
9
|
*
|
|
10
|
-
* When the editor runs standalone at /editor (not inside the overlay iframe),
|
|
10
|
+
* When the editor runs standalone at /live-tokens/editor (not inside the overlay iframe),
|
|
11
11
|
* parentRoot is null and every call is a plain single-root write.
|
|
12
12
|
*
|
|
13
13
|
* Roots are resolved lazily — `init()` (or any setter call) populates them on
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// The package's dev-only editor surfaces live under a reserved `/live-tokens/*`
|
|
2
|
+
// namespace so they can never collide with a consumer's own routes — the
|
|
3
|
+
// consumer owns the rest of the URL space. Keeping the defaults in one place
|
|
4
|
+
// is the guard against the nav rail and the dispatcher drifting onto different
|
|
5
|
+
// paths (the collision/shadow class these constants exist to prevent).
|
|
6
|
+
//
|
|
7
|
+
// A consumer relocates or disables each surface via the `editorRoutes` prop on
|
|
8
|
+
// <LiveTokensRouter>; these are only the defaults.
|
|
9
|
+
export const DEFAULT_EDITOR_PATH = '/live-tokens/editor';
|
|
10
|
+
export const DEFAULT_COMPONENTS_PATH = '/live-tokens/components';
|
|
11
|
+
export const DEFAULT_DOCS_PATH = '/live-tokens/docs';
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { writable } from 'svelte/store';
|
|
2
2
|
import { storageKey } from '../store/editorConfig';
|
|
3
|
+
import { DEFAULT_EDITOR_PATH } from './ownedRoutes';
|
|
3
4
|
|
|
4
5
|
function prevKey(): string {
|
|
5
6
|
return storageKey('prev-route');
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
function rememberPrev(current: string) {
|
|
9
|
-
if (current ===
|
|
10
|
+
if (current === DEFAULT_EDITOR_PATH) return;
|
|
10
11
|
try { sessionStorage.setItem(prevKey(), current); } catch { /* ignore */ }
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
<script lang="ts">
|
|
40
40
|
import { onMount, tick } from 'svelte';
|
|
41
41
|
import { marked, type Tokens } from 'marked';
|
|
42
|
+
import { DEFAULT_COMPONENTS_PATH } from '../core/routing/ownedRoutes';
|
|
42
43
|
|
|
43
44
|
import Button from '../../system/components/Button.svelte';
|
|
44
45
|
import CodeSnippet from '../../system/components/CodeSnippet.svelte';
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
let error = $state<string | null>(null);
|
|
69
70
|
let chapterMeta = $state<Chapter | null>(null);
|
|
70
71
|
|
|
71
|
-
/* Parse `/docs#editing-tokens~palettes` → chapter `editing-tokens`, anchor `palettes`.
|
|
72
|
+
/* Parse `/live-tokens/docs#editing-tokens~palettes` → chapter `editing-tokens`, anchor `palettes`.
|
|
72
73
|
Using `~` as the delimiter keeps each part valid for an HTML id. */
|
|
73
74
|
let parsedHash = $derived.by(() => {
|
|
74
75
|
const raw = hash.replace(/^#/, '');
|
|
@@ -269,7 +270,7 @@
|
|
|
269
270
|
Demo Site
|
|
270
271
|
</Button>
|
|
271
272
|
</a>
|
|
272
|
-
<a href=
|
|
273
|
+
<a href={DEFAULT_COMPONENTS_PATH} class="rail-action">
|
|
273
274
|
<Button variant="outline" size="small" icon="fas fa-puzzle-piece" fullWidth>
|
|
274
275
|
Components
|
|
275
276
|
</Button>
|
|
@@ -26,13 +26,13 @@ Describe what you want in plain English. Phrases like these trigger the skill:
|
|
|
26
26
|
|
|
27
27
|
Claude asks any clarifying questions it needs (which variants, which states,
|
|
28
28
|
which parts), then writes the component, registers it with the editor, and runs
|
|
29
|
-
its verification checklist. When it finishes, open `/components` to see your new
|
|
29
|
+
its verification checklist. When it finishes, open `/live-tokens/components` to see your new
|
|
30
30
|
component in the editor and confirm everything works.
|
|
31
31
|
|
|
32
32
|
## What you get
|
|
33
33
|
|
|
34
34
|
- A runtime component whose editable properties default to your theme tokens.
|
|
35
|
-
- An editor entry that appears under **Custom** in the `/components` view.
|
|
35
|
+
- An editor entry that appears under **Custom** in the `/live-tokens/components` view.
|
|
36
36
|
- The naming and wiring handled for you, so the component fits the system.
|
|
37
37
|
|
|
38
38
|
Advanced authors who want to write a component by hand can read the naming and
|
|
@@ -28,14 +28,14 @@ version upgrades never touch your styles. The package code stays in
|
|
|
28
28
|
| Path | What it is |
|
|
29
29
|
|------|------------|
|
|
30
30
|
| `src/pages/Home.svelte` | The starter page. Replace it with your own content. |
|
|
31
|
-
| `src/App.svelte` | Your routes. `<LiveTokensRouter>` adds
|
|
31
|
+
| `src/App.svelte` | Your routes. `<LiveTokensRouter>` adds dev-only routes under a reserved `/live-tokens/*` namespace: `/live-tokens/editor`, `/live-tokens/components`, and `/live-tokens/docs`. |
|
|
32
32
|
| `src/system/styles/tokens.css` | Your base token vocabulary, hand-authored. |
|
|
33
33
|
| `src/styles/site.css` | Themed page typography, yours to edit. |
|
|
34
34
|
|
|
35
35
|
## Your first edit
|
|
36
36
|
|
|
37
37
|
1. Run `npm run dev` and open the home page.
|
|
38
|
-
2. Click **Open Token Editor**, or visit `/editor`. The editor opens beside
|
|
38
|
+
2. Click **Open Token Editor**, or visit `/live-tokens/editor`. The editor opens beside
|
|
39
39
|
the page.
|
|
40
40
|
3. Open **Palettes**, pick **Brand**, and change the base hex. The page
|
|
41
41
|
repaints as you type.
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
export const docContent: Record<string, string> = {
|
|
5
5
|
"01-overview": "# Overview\n\nLive Tokens is a design system for building Svelte microsites quickly. You\nstyle your site by editing tokens and components in a live editor. When it looks right, you save the manifest and ship it.\n\n## How it works\n\n- The editor runs in your dev server, on top of your real pages. You style in\n context, not in a separate sandbox.\n- Every change updates a CSS variable, so the page repaints instantly. No\n reload, no build step.\n- Saving writes a small JSON file into your project. Shipping bakes your chosen\n theme into a plain CSS file that the build bundles.\n- The editor is dev-only. Production ships plain CSS variables and the\n components you used, nothing else.\n\n## What you can edit\n\n- **Tokens**: the design-system primitives, colour palettes, type, spacing,\n radius, shadow, and gradients, that apply across your whole site.\n- **Components**: the package ships about 25 editable components (Button, Card,\n Dialog, Table, and more).You style components by changing the tokens assigned to each property.\n\n## Where to go next\n\n- **[Getting started](getting-started.md)**: scaffold a project and make your\n first edit.\n- **[Editing tokens](editing-tokens.md)**: a tour of the editor.\n- **[Themes](themes-workflow.md)**: save, switch, and ship.\n- **[Creating components](creating-components.md)**: make your own components\n editable.\n",
|
|
6
|
-
"creating-components": "# Creating components\n\nThe package ships about 25 editable components. When you need one it doesn't\nhave, you can make your own Svelte component editable, so anyone using the\neditor can re-point its colours, type, and spacing without touching code.\n\nThe simplest way is to ask Claude. The package bundles a Claude Code skill that\nknows the conventions, writes the files, and checks the result for you.\n\n## Install the skills\n\n```bash\nnpx @motion-proto/live-tokens setup-claude\n```\n\nThis copies the bundled skills into your project's `.claude/skills/`. Once\nthey're there, Claude Code picks them up automatically.\n\n## Ask for a component\n\nDescribe what you want in plain English. Phrases like these trigger the skill:\n\n- \"Add a Toggle component to live-tokens\"\n- \"Make this Svelte component editable in the live-tokens editor\"\n- \"Create a Stat component with a value and a label\"\n\nClaude asks any clarifying questions it needs (which variants, which states,\nwhich parts), then writes the component, registers it with the editor, and runs\nits verification checklist. When it finishes, open `/components` to see your new\ncomponent in the editor and confirm everything works.\n\n## What you get\n\n- A runtime component whose editable properties default to your theme tokens.\n- An editor entry that appears under **Custom** in the `/components` view.\n- The naming and wiring handled for you, so the component fits the system.\n\nAdvanced authors who want to write a component by hand can read the naming and\nstate-model conventions shipped in the package\n(`src/system/styles/CONVENTIONS.md` and the skill's own `SKILL.md`).\n",
|
|
6
|
+
"creating-components": "# Creating components\n\nThe package ships about 25 editable components. When you need one it doesn't\nhave, you can make your own Svelte component editable, so anyone using the\neditor can re-point its colours, type, and spacing without touching code.\n\nThe simplest way is to ask Claude. The package bundles a Claude Code skill that\nknows the conventions, writes the files, and checks the result for you.\n\n## Install the skills\n\n```bash\nnpx @motion-proto/live-tokens setup-claude\n```\n\nThis copies the bundled skills into your project's `.claude/skills/`. Once\nthey're there, Claude Code picks them up automatically.\n\n## Ask for a component\n\nDescribe what you want in plain English. Phrases like these trigger the skill:\n\n- \"Add a Toggle component to live-tokens\"\n- \"Make this Svelte component editable in the live-tokens editor\"\n- \"Create a Stat component with a value and a label\"\n\nClaude asks any clarifying questions it needs (which variants, which states,\nwhich parts), then writes the component, registers it with the editor, and runs\nits verification checklist. When it finishes, open `/live-tokens/components` to see your new\ncomponent in the editor and confirm everything works.\n\n## What you get\n\n- A runtime component whose editable properties default to your theme tokens.\n- An editor entry that appears under **Custom** in the `/live-tokens/components` view.\n- The naming and wiring handled for you, so the component fits the system.\n\nAdvanced authors who want to write a component by hand can read the naming and\nstate-model conventions shipped in the package\n(`src/system/styles/CONVENTIONS.md` and the skill's own `SKILL.md`).\n",
|
|
7
7
|
"editing-tokens": "# Editing tokens\n\nA tour of the editor. The page behind it repaints on every change; saving\nwrites a theme file you can reload later.\n\nThe editor has two views:\n\n- **Tokens**: the design-system primitives (colour, type, spacing, and so on).\n They apply everywhere your site uses them.\n- **Components**: per-component editors. Re-Assign what tokens a component uses\n without changing the underlying system.\n\nThis page covers **Tokens**. For components, see\n[Creating components](creating-components.md).\n\n## Palettes\n\nMost colour work happens here. Each palette (Brand, Accent, Neutral, Canvas,\nSuccess, Warning, Info, Danger, and a few more) has:\n\n- **Base colour.** Pick a hex; the palette derives an 11-step ramp (100 to 950)\n from it.\n- **Curves.** Two curves shape how lightness and saturation fall off across the\n ramp. Drag the handles to bias it darker, lighter, or more saturated.\n- **Overrides.** Lock a single step to a hand-picked hex when the curve doesn't\n land where you want.\n\nEditing a palette base ripples through every colour that depends on it, in real\ntime. Colours use OKLCH, so the ramp stays perceptually even across hues\nwithout muddy mid-tones.\n\n## Type\n\n- **Fonts.** Add sources from Google Fonts, Adobe (Typekit), a CSS URL, or an\n inline `@font-face`. The font loads in the page as soon as you add it.\n- **Stacks.** Named font cascades you reference by token, such as a display\n stack and a body stack.\n- **Sizes and weights.** A t-shirt scale (xs, sm, md, lg, xl, 2xl…) for size and\n a numeric scale (100 to 900) for weight.\n\n## Spacing, radius, shadow\n\nNumeric scales with a slider per step.\n\n- **Spacing**: the padding, gap, and margin scale.\n- **Radius**: none through full.\n- **Shadow**: colour, offset, blur, spread, and opacity per step, with stacked\n shadows supported.\n\nChange a step and every element using it repaints.\n\n## Overlays and gradients\n\n- **Overlays** are translucent tints layered over surfaces, like the subtle\n tint a card gets on hover. Set a colour and opacity per state.\n- **Gradients** are reusable gradient tokens with a stop list and direction, for\n hero panels and accent backgrounds.\n\n## Columns\n\nThe page-grid overlay. Set column count, gutter, and outer margin, and toggle\nthe visual guide with `Cmd/Ctrl+G`. Pages built on the column system reflow\nlive.\n\n## Saving\n\nThe editor saves to your browser continuously, so work survives a reload\nmid-edit. **Save** is a separate step: it writes a named theme file under\n`src/live-tokens/data/themes/`.\n\nThe header gives you undo/redo (`Cmd/Ctrl+Z`, `Cmd/Ctrl+Shift+Z`) and a file\nmenu for New, Save, Save as, Switch, and Delete. You can keep many themes side\nby side; one is active at a time. See [Themes](themes-workflow.md) for the full\nlifecycle.\n",
|
|
8
|
-
"getting-started": "# Getting started\n\nScaffold a live token site in a moments. You need Node 20 or later, a\npackage manager (npm, pnpm, or yarn), and a browser. Open claude code in your repo and start building.\n\n## Scaffold a new app\n\n```bash\nnpm create @motion-proto/live-tokens@latest my-app\ncd my-app\nnpm install\nnpm run dev\n```\n\nOpen the URL Vite prints (usually `http://localhost:5173`). You get a\none-page Svelte + Vite app that depends on the published package, with the\neditor wired up and the full component set ready to import.\n\n`npx @motion-proto/live-tokens create my-app` runs the same scaffold without\nthe initialiser package.\n\n### What the scaffold gives you\n\nEvery editable file lives under `src/` and is committed, so `npm install` and\nversion upgrades never touch your styles. The package code stays in\n`node_modules`.\n\n| Path | What it is |\n|------|------------|\n| `src/pages/Home.svelte` | The starter page. Replace it with your own content. |\n| `src/App.svelte` | Your routes. `<LiveTokensRouter>` adds
|
|
8
|
+
"getting-started": "# Getting started\n\nScaffold a live token site in a moments. You need Node 20 or later, a\npackage manager (npm, pnpm, or yarn), and a browser. Open claude code in your repo and start building.\n\n## Scaffold a new app\n\n```bash\nnpm create @motion-proto/live-tokens@latest my-app\ncd my-app\nnpm install\nnpm run dev\n```\n\nOpen the URL Vite prints (usually `http://localhost:5173`). You get a\none-page Svelte + Vite app that depends on the published package, with the\neditor wired up and the full component set ready to import.\n\n`npx @motion-proto/live-tokens create my-app` runs the same scaffold without\nthe initialiser package.\n\n### What the scaffold gives you\n\nEvery editable file lives under `src/` and is committed, so `npm install` and\nversion upgrades never touch your styles. The package code stays in\n`node_modules`.\n\n| Path | What it is |\n|------|------------|\n| `src/pages/Home.svelte` | The starter page. Replace it with your own content. |\n| `src/App.svelte` | Your routes. `<LiveTokensRouter>` adds dev-only routes under a reserved `/live-tokens/*` namespace: `/live-tokens/editor`, `/live-tokens/components`, and `/live-tokens/docs`. |\n| `src/system/styles/tokens.css` | Your base token vocabulary, hand-authored. |\n| `src/styles/site.css` | Themed page typography, yours to edit. |\n\n## Your first edit\n\n1. Run `npm run dev` and open the home page.\n2. Click **Open Token Editor**, or visit `/live-tokens/editor`. The editor opens beside\n the page.\n3. Open **Palettes**, pick **Brand**, and change the base hex. The page\n repaints as you type.\n4. Open the file menu and choose **Save as**. A theme appears as JSON under\n `src/live-tokens/data/themes/`.\n5. Reload. Your saved theme is the active theme, so the page returns as you\n left it.\n\n## What you just changed\n\nEvery edit sets a CSS custom property on `:root`. Your components read those\nproperties through `var(--...)`. There is no token build step and no\npreprocessor rewriting your code: the page renders against plain CSS variables\nthe editor swaps live.\n\nTo ship, promote a theme to production in the editor. That bakes the theme's\nvariables into `src/live-tokens/data/tokens.generated.css`, which your build\nbundles alongside `tokens.css`. The editor itself never reaches production.\n\nAlready have a Svelte 5 + Vite app? The\n[README](https://github.com/motionproto/live-tokens#readme) covers installing\ninto an existing project.\n\n## Where to go next\n\n- **[Editing tokens](editing-tokens.md)**: a tour of the editor.\n- **[Themes](themes-workflow.md)**: save, switch, and ship.\n- **[Creating components](creating-components.md)**: make your own component\n editable.\n",
|
|
9
9
|
"themes-workflow": "# Themes\n\nSave your work, switch between themes, and ship one to production.\n\n## How themes work\n\n- **Your live edits** are what the page shows right now. They save to your\n browser automatically and survive a reload, but they are not yet a file.\n- **A saved theme** is a named JSON file in `src/live-tokens/data/themes/`. You\n create one with **Save as**.\n- **The active theme** is the saved theme the page loads at startup. Exactly one\n at a time.\n- **The production theme** is the one that ships. Promoting sets it.\n\n## Saving\n\nIn the editor header:\n\n- **Save** updates the current theme.\n- **Save as** names a new theme. Use it for your first save and for forking.\n\nNames are tidied to lowercase with underscores, so \"My Brand!\" becomes\n`my_brand`. There is a built-in `default` theme you can always return to; the\neditor never overwrites it.\n\n## Switching\n\nThe file menu lists every saved theme. Pick one to make it active; the page\nreloads with it applied. Your current edits are saved to the previous theme\nfirst, so you don't lose work.\n\n## Shipping\n\n**Promote to production** is the \"ship it\" step. It bakes the theme's variables\ninto `src/live-tokens/data/tokens.generated.css`, which your build bundles\nalongside `tokens.css`. Fonts regenerate to match.\n\nProduction builds (`npm run build`) ship only that plain CSS and your\ncomponents. No editor, no JSON loading, no runtime indirection. If you save\nwhile the production theme is active, the generated CSS updates immediately,\nwith no separate promote step.\n\n## Manifests\n\nA **manifest** bundles one theme plus a config for each component into a single\nnamed set. Useful when you run several brands and want each to apply its theme\nand component tweaks in one move. There is a protected default and an active\nmanifest; applying one swaps everything at once.\n\n## Keeping your work safe\n\nEverything under `src/live-tokens/data/` is plain JSON, so commit it. Themes\nshow up as readable diffs you can review per branch. There are no automatic\nbackups: git is your safety net. To experiment freely, **Save as** a new name\nfirst, then edit.\n\n## Where to go next\n\n- **[Creating components](creating-components.md)**: make your own components\n editable in the same editor.\n",
|
|
10
10
|
};
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import { fade } from 'svelte/transition';
|
|
16
16
|
import { cubicInOut } from 'svelte/easing';
|
|
17
17
|
import { route, navigate } from '../core/routing/router';
|
|
18
|
+
import { DEFAULT_EDITOR_PATH, DEFAULT_COMPONENTS_PATH } from '../core/routing/ownedRoutes';
|
|
18
19
|
import { editorView } from '../core/store/editorViewStore';
|
|
19
20
|
import { columnsVisible, toggleColumns } from './columnsOverlay';
|
|
20
21
|
import { storageKey } from '../core/store/editorConfig';
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
interface Props {
|
|
28
29
|
open?: boolean | undefined;
|
|
29
30
|
editorPath?: string;
|
|
31
|
+
componentsPath?: string;
|
|
30
32
|
navLinks?: NavLink[];
|
|
31
33
|
pageSources?: Record<string, string>;
|
|
32
34
|
hidePageSourceOn?: string[];
|
|
@@ -35,7 +37,8 @@
|
|
|
35
37
|
|
|
36
38
|
let {
|
|
37
39
|
open = $bindable(undefined),
|
|
38
|
-
editorPath =
|
|
40
|
+
editorPath = DEFAULT_EDITOR_PATH,
|
|
41
|
+
componentsPath = DEFAULT_COMPONENTS_PATH,
|
|
39
42
|
navLinks = [],
|
|
40
43
|
pageSources = {},
|
|
41
44
|
hidePageSourceOn = [],
|
|
@@ -62,9 +65,9 @@
|
|
|
62
65
|
overlayOpen.set(!!open);
|
|
63
66
|
});
|
|
64
67
|
|
|
65
|
-
// The
|
|
66
|
-
// overlay's components view. Pair them: on entering
|
|
67
|
-
//
|
|
68
|
+
// The components route renders the same component-editor surface as the
|
|
69
|
+
// overlay's components view. Pair them: on entering it, flip the overlay to
|
|
70
|
+
// tokens so the two surfaces don't stack. Fires only on route
|
|
68
71
|
// change, not on every editorView change — otherwise cross-window storage
|
|
69
72
|
// sync re-triggers the rule, which writes editorView, which fires another
|
|
70
73
|
// storage event, which fires the rule again. The result is heavy re-render
|
|
@@ -75,7 +78,7 @@
|
|
|
75
78
|
const r = $route;
|
|
76
79
|
if (r === prevRoute) return;
|
|
77
80
|
prevRoute = r;
|
|
78
|
-
if (r ===
|
|
81
|
+
if (r === componentsPath) {
|
|
79
82
|
editorView.update((v) => (v === 'components' ? 'tokens' : v));
|
|
80
83
|
}
|
|
81
84
|
});
|
|
@@ -28,9 +28,11 @@
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* Override the
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* Override the package's dev-only routes, which default to the reserved
|
|
32
|
+
* `/live-tokens/*` namespace (`/live-tokens/editor`, `/live-tokens/components`,
|
|
33
|
+
* `/live-tokens/docs`) so they never collide with consumer pages. Pass a
|
|
34
|
+
* string to relocate a route; pass `false` to disable it entirely (no
|
|
35
|
+
* dispatch and, for `components`/`docs`, no auto-injected nav-rail entry).
|
|
34
36
|
*/
|
|
35
37
|
export interface EditorRouteOverrides {
|
|
36
38
|
editor?: string | false;
|
|
@@ -40,8 +42,8 @@
|
|
|
40
42
|
|
|
41
43
|
/**
|
|
42
44
|
* Resolve a path to the single entry that renders it. Precedence, after the
|
|
43
|
-
* package-owned routes (
|
|
44
|
-
* matched by the component:
|
|
45
|
+
* package-owned `/live-tokens/*` routes (editor, components, docs) have
|
|
46
|
+
* already been matched by the component:
|
|
45
47
|
*
|
|
46
48
|
* 1. `pages[route]` — exact static match.
|
|
47
49
|
* 2. `resolve(route)` — consumer code, where params / prefixes / gating
|
|
@@ -66,6 +68,7 @@
|
|
|
66
68
|
import LiveEditorOverlay from './LiveEditorOverlay.svelte';
|
|
67
69
|
import ColumnsOverlay from './ColumnsOverlay.svelte';
|
|
68
70
|
import { route, navigate } from '../core/routing/router';
|
|
71
|
+
import { DEFAULT_EDITOR_PATH, DEFAULT_COMPONENTS_PATH, DEFAULT_DOCS_PATH } from '../core/routing/ownedRoutes';
|
|
69
72
|
|
|
70
73
|
interface Props {
|
|
71
74
|
pages: Record<string, RouteEntry>;
|
|
@@ -84,9 +87,9 @@
|
|
|
84
87
|
let editorEnabled = $derived(editorRoutes.editor !== false);
|
|
85
88
|
let componentsEnabled = $derived(editorRoutes.components !== false);
|
|
86
89
|
let docsEnabled = $derived(editorRoutes.docs !== false);
|
|
87
|
-
let editorPath = $derived(typeof editorRoutes.editor === 'string' ? editorRoutes.editor :
|
|
88
|
-
let componentsPath = $derived(typeof editorRoutes.components === 'string' ? editorRoutes.components :
|
|
89
|
-
let docsPath = $derived(typeof editorRoutes.docs === 'string' ? editorRoutes.docs :
|
|
90
|
+
let editorPath = $derived(typeof editorRoutes.editor === 'string' ? editorRoutes.editor : DEFAULT_EDITOR_PATH);
|
|
91
|
+
let componentsPath = $derived(typeof editorRoutes.components === 'string' ? editorRoutes.components : DEFAULT_COMPONENTS_PATH);
|
|
92
|
+
let docsPath = $derived(typeof editorRoutes.docs === 'string' ? editorRoutes.docs : DEFAULT_DOCS_PATH);
|
|
90
93
|
|
|
91
94
|
const isDev = import.meta.env.DEV;
|
|
92
95
|
let isEditor = $derived(isDev && editorEnabled && $route === editorPath);
|
|
@@ -176,7 +179,7 @@
|
|
|
176
179
|
class:is-component-editor={isComponentEditor}
|
|
177
180
|
onclick={handleClick}
|
|
178
181
|
>
|
|
179
|
-
<LiveEditorOverlay {navLinks} {pageSources} {hidePageSourceOn} {editorPath} />
|
|
182
|
+
<LiveEditorOverlay {navLinks} {pageSources} {hidePageSourceOn} {editorPath} {componentsPath} />
|
|
180
183
|
<ColumnsOverlay />
|
|
181
184
|
|
|
182
185
|
{#await pagePromise then m}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { installEditorKeybindings } from '../core/store/editorKeybindings';
|
|
6
6
|
import { initializeEditorStore } from '../core/store/editorStore';
|
|
7
7
|
import { storageKey } from '../core/store/editorConfig';
|
|
8
|
+
import { DEFAULT_EDITOR_PATH } from '../core/routing/ownedRoutes';
|
|
8
9
|
// Editor chrome + form controls + icon font must be JS imports (not @import
|
|
9
10
|
// inside the style block) so Vite resolves them via the module graph
|
|
10
11
|
// regardless of how the consumer compiles Svelte CSS (external ?lang.css vs
|
|
@@ -23,7 +24,7 @@
|
|
|
23
24
|
function pickBackHref(): string {
|
|
24
25
|
try {
|
|
25
26
|
const prev = sessionStorage.getItem(storageKey('prev-route'));
|
|
26
|
-
if (prev && prev !==
|
|
27
|
+
if (prev && prev !== DEFAULT_EDITOR_PATH) return prev;
|
|
27
28
|
} catch {
|
|
28
29
|
// ignore
|
|
29
30
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { editorView } from '../core/store/editorViewStore';
|
|
3
3
|
import { parentRoute } from '../core/routing/parentRouteStore';
|
|
4
|
+
import { DEFAULT_COMPONENTS_PATH } from '../core/routing/ownedRoutes';
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
condensed?: boolean;
|
|
@@ -8,11 +9,13 @@
|
|
|
8
9
|
|
|
9
10
|
let { condensed = false }: Props = $props();
|
|
10
11
|
|
|
11
|
-
// On
|
|
12
|
-
// overlay's components view would just stack on top
|
|
12
|
+
// On the components route the host page is already the components editor —
|
|
13
|
+
// the overlay's components view would just stack on top, so disable the
|
|
13
14
|
// switch. The switcher renders inside the editor iframe, so we read the
|
|
14
|
-
// *parent* route, not this iframe's own
|
|
15
|
-
|
|
15
|
+
// *parent* route, not this iframe's own. Compares the default path:
|
|
16
|
+
// editorRoutes.components relocation isn't plumbed across the iframe, so a
|
|
17
|
+
// relocated route won't disable the switch.
|
|
18
|
+
let componentsDisabled = $derived($parentRoute === DEFAULT_COMPONENTS_PATH);
|
|
16
19
|
|
|
17
20
|
function set(v: 'tokens' | 'components') {
|
|
18
21
|
editorView.set(v);
|