@loworbitstudio/visor 0.10.0 → 0.10.2
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/CHANGELOG.json +1 -1
- package/dist/index.js +32 -22
- package/dist/registry.json +1 -1
- package/dist/visor-manifest.json +1 -1
- package/package.json +2 -2
package/dist/CHANGELOG.json
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
import { readFileSync as readFileSync22 } from "fs";
|
|
5
|
+
import { dirname as dirname8, join as join20 } from "path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4
7
|
import { Command as Command2 } from "commander";
|
|
5
8
|
|
|
6
9
|
// src/commands/check.ts
|
|
@@ -1173,9 +1176,9 @@ function readPackageJson(cwd) {
|
|
|
1173
1176
|
return JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
1174
1177
|
}
|
|
1175
1178
|
function isPackageInstalled(packageName, cwd) {
|
|
1176
|
-
const
|
|
1177
|
-
if (!
|
|
1178
|
-
return !!(
|
|
1179
|
+
const pkg2 = readPackageJson(cwd);
|
|
1180
|
+
if (!pkg2) return false;
|
|
1181
|
+
return !!(pkg2.dependencies?.[packageName] || pkg2.devDependencies?.[packageName]);
|
|
1179
1182
|
}
|
|
1180
1183
|
function hasVisorTokens(cwd) {
|
|
1181
1184
|
return isPackageInstalled("@loworbitstudio/visor-core", cwd);
|
|
@@ -1439,9 +1442,9 @@ function readVisorCliVersion() {
|
|
|
1439
1442
|
const segments = new Array(i).fill("..");
|
|
1440
1443
|
const candidate = join6(here, ...segments, "package.json");
|
|
1441
1444
|
try {
|
|
1442
|
-
const
|
|
1443
|
-
if (
|
|
1444
|
-
return
|
|
1445
|
+
const pkg2 = JSON.parse(readFileSync6(candidate, "utf-8"));
|
|
1446
|
+
if (pkg2.name === "@loworbitstudio/visor" && pkg2.version) {
|
|
1447
|
+
return pkg2.version;
|
|
1445
1448
|
}
|
|
1446
1449
|
} catch {
|
|
1447
1450
|
}
|
|
@@ -2459,7 +2462,9 @@ function themeApplyCommand(file, cwd, options) {
|
|
|
2459
2462
|
};
|
|
2460
2463
|
switch (options.adapter) {
|
|
2461
2464
|
case "nextjs":
|
|
2462
|
-
css = nextjsAdapter2(adapterInput
|
|
2465
|
+
css = nextjsAdapter2(adapterInput, {
|
|
2466
|
+
scopePrefix: options.scopePrefix
|
|
2467
|
+
});
|
|
2463
2468
|
break;
|
|
2464
2469
|
case "fumadocs":
|
|
2465
2470
|
css = fumadocsAdapter(adapterInput);
|
|
@@ -3177,8 +3182,8 @@ function extractFontHints(targetDir) {
|
|
|
3177
3182
|
const pkgPath = join11(targetDir, "package.json");
|
|
3178
3183
|
if (!existsSync9(pkgPath)) return void 0;
|
|
3179
3184
|
try {
|
|
3180
|
-
const
|
|
3181
|
-
const allDeps = { ...
|
|
3185
|
+
const pkg2 = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
3186
|
+
const allDeps = { ...pkg2.dependencies, ...pkg2.devDependencies };
|
|
3182
3187
|
const fonts2 = [];
|
|
3183
3188
|
for (const [dep, _] of Object.entries(allDeps)) {
|
|
3184
3189
|
const family = FONT_PACKAGE_MAP[dep];
|
|
@@ -3216,9 +3221,9 @@ function inferThemeName(targetDir) {
|
|
|
3216
3221
|
const pkgPath = join11(targetDir, "package.json");
|
|
3217
3222
|
if (existsSync9(pkgPath)) {
|
|
3218
3223
|
try {
|
|
3219
|
-
const
|
|
3220
|
-
if (
|
|
3221
|
-
const name =
|
|
3224
|
+
const pkg2 = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
3225
|
+
if (pkg2.name) {
|
|
3226
|
+
const name = pkg2.name.replace(/^@[\w-]+\//, "");
|
|
3222
3227
|
return `${name}-theme`;
|
|
3223
3228
|
}
|
|
3224
3229
|
} catch {
|
|
@@ -3448,11 +3453,11 @@ function detectVisorWorkspace(cwd) {
|
|
|
3448
3453
|
const pkgPath = join12(current, "package.json");
|
|
3449
3454
|
if (existsSync10(pkgPath)) {
|
|
3450
3455
|
try {
|
|
3451
|
-
const
|
|
3452
|
-
const workspaces =
|
|
3456
|
+
const pkg2 = JSON.parse(readFileSync13(pkgPath, "utf-8"));
|
|
3457
|
+
const workspaces = pkg2.workspaces ?? [];
|
|
3453
3458
|
const hasCli = workspaces.some((w) => w.includes("packages/cli"));
|
|
3454
3459
|
const hasEngine = workspaces.some((w) => w.includes("packages/theme-engine"));
|
|
3455
|
-
if (
|
|
3460
|
+
if (pkg2.name === "visor" && hasCli && hasEngine) {
|
|
3456
3461
|
return current;
|
|
3457
3462
|
}
|
|
3458
3463
|
} catch {
|
|
@@ -3840,7 +3845,7 @@ import {
|
|
|
3840
3845
|
} from "fs";
|
|
3841
3846
|
import { join as join15, basename as basename3, resolve as resolve11, sep } from "path";
|
|
3842
3847
|
import { parse as parseYaml2 } from "yaml";
|
|
3843
|
-
import { generateThemeData as generateThemeData4, validateFontCoverage } from "@loworbitstudio/visor-theme-engine";
|
|
3848
|
+
import { generateThemeData as generateThemeData4, validateFontCoverage, formatFontCoverageError } from "@loworbitstudio/visor-theme-engine";
|
|
3844
3849
|
import { docsAdapter as docsAdapter3 } from "@loworbitstudio/visor-theme-engine/adapters";
|
|
3845
3850
|
var PRIVATE_THEMES_REPO_URL = "git@github.com:low-orbit-studio/visor-themes-private.git";
|
|
3846
3851
|
var PRIVATE_THEMES_ENV_VAR = "VISOR_THEMES_PRIVATE_PATH";
|
|
@@ -4239,9 +4244,7 @@ function themeSyncCommand(cwd, options) {
|
|
|
4239
4244
|
const coverage = validateFontCoverage(css);
|
|
4240
4245
|
if (coverage.errors.length > 0) {
|
|
4241
4246
|
for (const e of coverage.errors) {
|
|
4242
|
-
errors.push(
|
|
4243
|
-
`${basename3(filePath)}: ${e.declaredAt} declares "${e.family}" with no matching @font-face. Set typography.<slot>.source: visor-fonts (with org:) or google-fonts, or pick a system font.`
|
|
4244
|
-
);
|
|
4247
|
+
errors.push(formatFontCoverageError(basename3(filePath), e.declaredAt, e.family));
|
|
4245
4248
|
}
|
|
4246
4249
|
return;
|
|
4247
4250
|
}
|
|
@@ -4921,8 +4924,8 @@ async function doctorCommand(cwd, options, cliVersion) {
|
|
|
4921
4924
|
}
|
|
4922
4925
|
const pkgJsonPath = path.join(cwd, "package.json");
|
|
4923
4926
|
try {
|
|
4924
|
-
const
|
|
4925
|
-
const reactVersion =
|
|
4927
|
+
const pkg2 = JSON.parse(fs.readFileSync(pkgJsonPath, "utf-8"));
|
|
4928
|
+
const reactVersion = pkg2.dependencies?.react ?? pkg2.devDependencies?.react ?? "";
|
|
4926
4929
|
const versionNum = parseFloat(reactVersion.replace(/[^0-9.]/g, ""));
|
|
4927
4930
|
if (!reactVersion) {
|
|
4928
4931
|
checks.push({
|
|
@@ -5720,8 +5723,12 @@ function migrateTokenSubstitutionCommand(targetArg, cwd, options) {
|
|
|
5720
5723
|
}
|
|
5721
5724
|
|
|
5722
5725
|
// src/index.ts
|
|
5726
|
+
var __dirname2 = dirname8(fileURLToPath3(import.meta.url));
|
|
5727
|
+
var pkg = JSON.parse(
|
|
5728
|
+
readFileSync22(join20(__dirname2, "..", "package.json"), "utf-8")
|
|
5729
|
+
);
|
|
5723
5730
|
var program = new Command2();
|
|
5724
|
-
program.name("visor").description("CLI for the Visor design system").version(
|
|
5731
|
+
program.name("visor").description("CLI for the Visor design system").version(pkg.version);
|
|
5725
5732
|
program.addCommand(checkCommand());
|
|
5726
5733
|
program.command("init").description("Initialize Visor \u2014 with --template nextjs, scaffolds a complete runnable Borealis-native Next.js app in one command").option("--template <name>", "scaffold a complete runnable app (templates: nextjs)").option("--json", "output structured JSON (for AI agents)").action((options) => {
|
|
5727
5734
|
initCommand(process.cwd(), options);
|
|
@@ -5753,6 +5760,9 @@ theme.command("apply").description(
|
|
|
5753
5760
|
).option("--json", "output structured JSON (for AI agents)").option(
|
|
5754
5761
|
"--adapter <name>",
|
|
5755
5762
|
"target adapter: nextjs, fumadocs, deck, docs, flutter"
|
|
5763
|
+
).option(
|
|
5764
|
+
"--scope-prefix <selector>",
|
|
5765
|
+
"(nextjs) CSS selector to wrap all rules under (e.g. 'body.blacklight-theme'); enables body-class theme swap. Default: :root"
|
|
5756
5766
|
).option(
|
|
5757
5767
|
"--package-name <name>",
|
|
5758
5768
|
"(flutter) Dart package name for generated pubspec.yaml (default: ui)"
|
package/dist/registry.json
CHANGED
|
@@ -3470,7 +3470,7 @@
|
|
|
3470
3470
|
{
|
|
3471
3471
|
"path": "blocks/design-system-specimen/specimen-data.ts",
|
|
3472
3472
|
"type": "registry:block",
|
|
3473
|
-
"content": "/**\n * Design System Specimen — Data\n *\n * Typed data arrays for all specimen sections.\n * Values sourced from packages/tokens/src/tokens/primitives.ts and semantic.ts.\n */\n\n// ─── Interfaces ──────────────────────────────────────────────────────────────\n\nexport interface ColorSwatchData {\n token: string\n hex: string\n name: string\n lightText?: boolean\n /** When true, ColorSwatch reads the live computed value instead of displaying the fallback hex */\n dynamic?: boolean\n}\n\nexport interface ColorScaleData {\n name: string\n swatches: ColorSwatchData[]\n /** When set, renders a featured brand swatch above the scale reading this token */\n brandToken?: string\n}\n\nexport interface SemanticColorData {\n token: string\n label: string\n category: string\n}\n\nexport interface TypeSpecimenData {\n token: string\n label: string\n sizePx: number\n sampleText: string\n}\n\nexport interface SpacingStepData {\n token: string\n name: string\n px: number\n rem: string\n}\n\nexport interface ShadowLevelData {\n token: string\n name: string\n value: string\n}\n\nexport interface SurfaceData {\n token: string\n name: string\n lightText?: boolean\n}\n\nexport interface RadiusStepData {\n token: string\n name: string\n px: number\n}\n\nexport interface MotionDurationData {\n token: string\n name: string\n ms: number\n}\n\nexport interface EasingData {\n token: string\n name: string\n value: string\n}\n\nexport interface ContrastPairData {\n fgToken: string\n bgToken: string\n fgLabel: string\n bgLabel: string\n ratio: number\n wcagAA: boolean\n wcagAAA: boolean\n}\n\nexport interface IconSpecimenData {\n name: string\n phosphorName: string\n usage: string\n}\n\nexport interface FontWeightData {\n label: string\n value: number\n}\n\nexport interface FontFamilyData {\n /** CSS custom property token (e.g. \"--font-heading\") */\n token: string\n /** Display role (e.g. \"Heading & Body\", \"Monospace\") */\n role: string\n /** Font family display name — omit to read dynamically from the CSS token */\n familyName?: string\n /** Available weights */\n weights: FontWeightData[]\n}\n\n// ─── Color Scales ────────────────────────────────────────────────────────────\n\nexport interface StatusColorScaleData extends ColorScaleData {\n /** Semantic role label (e.g. \"Success\", \"Warning\") */\n role: string\n}\n\nexport const THEME_COLOR_SCALES: ColorScaleData[] = [\n {\n name: \"Primary\",\n brandToken: \"--interactive-primary-bg\",\n swatches: [\n { token: \"--color-primary-100\", hex: \"#cfdfe7\", name: \"100\", dynamic: true },\n { token: \"--color-primary-200\", hex: \"#adc8d5\", name: \"200\", dynamic: true },\n { token: \"--color-primary-300\", hex: \"#89aec0\", name: \"300\", dynamic: true },\n { token: \"--color-primary-400\", hex: \"#6093aa\", name: \"400\", dynamic: true },\n { token: \"--color-primary-500\", hex: \"#397a96\", name: \"500\", lightText: true, dynamic: true },\n { token: \"--color-primary-600\", hex: \"#2a647c\", name: \"600\", lightText: true, dynamic: true },\n { token: \"--color-primary-700\", hex: \"#1a4e64\", name: \"700\", lightText: true, dynamic: true },\n { token: \"--color-primary-800\", hex: \"#0b3a4c\", name: \"800\", lightText: true, dynamic: true },\n { token: \"--color-primary-900\", hex: \"#002938\", name: \"900\", lightText: true, dynamic: true },\n { token: \"--color-primary-950\", hex: \"#001c29\", name: \"950\", lightText: true, dynamic: true },\n ],\n },\n {\n name: \"Neutral\",\n swatches: [\n { token: \"--color-gray-100\", hex: \"#f3f4f6\", name: \"100\" },\n { token: \"--color-gray-200\", hex: \"#e5e7eb\", name: \"200\" },\n { token: \"--color-gray-300\", hex: \"#d1d5db\", name: \"300\" },\n { token: \"--color-gray-400\", hex: \"#9ca3af\", name: \"400\" },\n { token: \"--color-gray-500\", hex: \"#6b7280\", name: \"500\", lightText: true },\n { token: \"--color-gray-600\", hex: \"#4b5563\", name: \"600\", lightText: true },\n { token: \"--color-gray-700\", hex: \"#374151\", name: \"700\", lightText: true },\n { token: \"--color-gray-800\", hex: \"#1f2937\", name: \"800\", lightText: true },\n { token: \"--color-gray-900\", hex: \"#111827\", name: \"900\", lightText: true },\n { token: \"--color-gray-950\", hex: \"#030712\", name: \"950\", lightText: true },\n ],\n },\n]\n\nexport const STATUS_COLOR_SCALES: StatusColorScaleData[] = [\n {\n name: \"Success\",\n role: \"Success\",\n swatches: [\n { token: \"--color-green-50\", hex: \"#f0fdf4\", name: \"50\" },\n { token: \"--color-green-100\", hex: \"#dcfce7\", name: \"100\" },\n { token: \"--color-green-500\", hex: \"#22c55e\", name: \"500\", lightText: true },\n { token: \"--color-green-600\", hex: \"#16a34a\", name: \"600\", lightText: true },\n { token: \"--color-green-700\", hex: \"#15803d\", name: \"700\", lightText: true },\n { token: \"--color-green-900\", hex: \"#14532d\", name: \"900\", lightText: true },\n ],\n },\n {\n name: \"Warning\",\n role: \"Warning\",\n swatches: [\n { token: \"--color-amber-50\", hex: \"#fffbeb\", name: \"50\" },\n { token: \"--color-amber-100\", hex: \"#fef3c7\", name: \"100\" },\n { token: \"--color-amber-500\", hex: \"#f59e0b\", name: \"500\" },\n { token: \"--color-amber-600\", hex: \"#d97706\", name: \"600\", lightText: true },\n { token: \"--color-amber-700\", hex: \"#b45309\", name: \"700\", lightText: true },\n { token: \"--color-amber-900\", hex: \"#78350f\", name: \"900\", lightText: true },\n ],\n },\n {\n name: \"Error\",\n role: \"Error\",\n swatches: [\n { token: \"--color-red-50\", hex: \"#fef2f2\", name: \"50\" },\n { token: \"--color-red-100\", hex: \"#fee2e2\", name: \"100\" },\n { token: \"--color-red-500\", hex: \"#ef4444\", name: \"500\", lightText: true },\n { token: \"--color-red-600\", hex: \"#dc2626\", name: \"600\", lightText: true },\n { token: \"--color-red-700\", hex: \"#b91c1c\", name: \"700\", lightText: true },\n { token: \"--color-red-900\", hex: \"#7f1d1d\", name: \"900\", lightText: true },\n ],\n },\n {\n name: \"Info\",\n role: \"Info\",\n swatches: [\n { token: \"--color-sky-50\", hex: \"#f0f9ff\", name: \"50\" },\n { token: \"--color-sky-100\", hex: \"#e0f2fe\", name: \"100\" },\n { token: \"--color-sky-500\", hex: \"#0ea5e9\", name: \"500\", lightText: true },\n { token: \"--color-sky-600\", hex: \"#0284c7\", name: \"600\", lightText: true },\n { token: \"--color-sky-700\", hex: \"#0369a1\", name: \"700\", lightText: true },\n { token: \"--color-sky-900\", hex: \"#0c4a6e\", name: \"900\", lightText: true },\n ],\n },\n]\n\nexport const SEMANTIC_COLORS: SemanticColorData[] = [\n // Text\n { token: \"--text-primary\", label: \"text-primary\", category: \"Text\" },\n { token: \"--text-secondary\", label: \"text-secondary\", category: \"Text\" },\n { token: \"--text-tertiary\", label: \"text-tertiary\", category: \"Text\" },\n { token: \"--text-disabled\", label: \"text-disabled\", category: \"Text\" },\n { token: \"--text-inverse\", label: \"text-inverse\", category: \"Text\" },\n { token: \"--text-link\", label: \"text-link\", category: \"Text\" },\n { token: \"--text-success\", label: \"text-success\", category: \"Text\" },\n { token: \"--text-warning\", label: \"text-warning\", category: \"Text\" },\n { token: \"--text-error\", label: \"text-error\", category: \"Text\" },\n { token: \"--text-info\", label: \"text-info\", category: \"Text\" },\n // Surface\n { token: \"--surface-page\", label: \"surface-page\", category: \"Surface\" },\n { token: \"--surface-card\", label: \"surface-card\", category: \"Surface\" },\n { token: \"--surface-subtle\", label: \"surface-subtle\", category: \"Surface\" },\n { token: \"--surface-muted\", label: \"surface-muted\", category: \"Surface\" },\n { token: \"--surface-overlay\", label: \"surface-overlay\", category: \"Surface\" },\n { token: \"--surface-accent-subtle\", label: \"surface-accent-subtle\", category: \"Surface\" },\n { token: \"--surface-accent-default\", label: \"surface-accent-default\", category: \"Surface\" },\n { token: \"--surface-accent-strong\", label: \"surface-accent-strong\", category: \"Surface\" },\n // Border\n { token: \"--border-default\", label: \"border-default\", category: \"Border\" },\n { token: \"--border-muted\", label: \"border-muted\", category: \"Border\" },\n { token: \"--border-strong\", label: \"border-strong\", category: \"Border\" },\n { token: \"--border-focus\", label: \"border-focus\", category: \"Border\" },\n]\n\n// ─── Typography ──────────────────────────────────────────────────────────────\n\n/**\n * Canonical CSS weight labels keyed by numeric weight. Used to label specimen\n * rows derived from a theme's actual loaded weights (VI-356, D2). Uses the\n * standard CSS Fonts Module names — \"Regular\" not \"Book\", \"Semibold\" not\n * \"Demibold\" — so the operator sees one consistent vocabulary regardless of\n * what a foundry calls the cut.\n */\nexport const WEIGHT_LABELS: Record<number, string> = {\n 100: \"Thin\",\n 200: \"Extra Light\",\n 300: \"Light\",\n 400: \"Regular\",\n 500: \"Medium\",\n 600: \"Semibold\",\n 700: \"Bold\",\n 800: \"Extra Bold\",\n 900: \"Black\",\n}\n\nexport function labelForWeight(weight: number): string {\n return WEIGHT_LABELS[weight] ?? `W${weight}`\n}\n\n/** Typography slot data — matches the manifest shape emitted by the docs site for private themes (VI-356). */\nexport interface ThemeTypographySlot {\n family: string\n weights: number[]\n}\n\nexport interface ThemeTypographyManifest {\n heading?: ThemeTypographySlot\n display?: ThemeTypographySlot\n body?: ThemeTypographySlot\n mono?: ThemeTypographySlot\n}\n\n/**\n * Derive Font Families specimen rows from a theme's typography manifest.\n *\n * - `--font-heading` row uses the body slot's weights when present (the theme's\n * --font-heading variable resolves to body family in the engine), falling\n * back to display or heading slot weights if body is absent.\n * - `--font-mono` row uses the mono slot's weights when present, falling back\n * to body weights, then the default.\n *\n * Any slot the manifest doesn't cover gets the corresponding fallback row from\n * `defaults`. This keeps stock themes (no `weights` in YAML) on the existing\n * 4+3 grid while themes like Blacklight render their five actual weights.\n */\nexport function deriveFontFamiliesFromTypography(\n manifest: ThemeTypographyManifest | undefined,\n defaults: FontFamilyData[],\n): FontFamilyData[] {\n if (!manifest) return defaults\n\n const headingDefault = defaults.find((f) => f.token === \"--font-heading\")\n const monoDefault = defaults.find((f) => f.token === \"--font-mono\")\n\n const headingSlot = manifest.body ?? manifest.display ?? manifest.heading\n const monoSlot = manifest.mono ?? manifest.body ?? manifest.display ?? manifest.heading\n\n const next: FontFamilyData[] = []\n if (headingDefault) {\n next.push(\n headingSlot\n ? {\n token: \"--font-heading\",\n role: headingDefault.role,\n familyName: headingSlot.family || headingDefault.familyName,\n weights: headingSlot.weights.map((w) => ({ label: labelForWeight(w), value: w })),\n }\n : headingDefault,\n )\n }\n if (monoDefault) {\n next.push(\n monoSlot\n ? {\n token: \"--font-mono\",\n role: monoDefault.role,\n familyName: monoSlot.family || monoDefault.familyName,\n weights: monoSlot.weights.map((w) => ({ label: labelForWeight(w), value: w })),\n }\n : monoDefault,\n )\n }\n return next\n}\n\n/**\n * Fallback weight rows for the Font Families specimen, used when a theme does\n * not declare per-slot `weights` in its `.visor.yaml`. Stock public themes\n * (Blackout, Borderless, Modern Minimal, Neutral, Space) all fall through to\n * these defaults since they rely on system-ui / default weights.\n */\nexport const FONT_FAMILIES: FontFamilyData[] = [\n {\n token: \"--font-heading\",\n role: \"Heading & Body\",\n weights: [\n { label: \"Regular\", value: 400 },\n { label: \"Medium\", value: 500 },\n { label: \"Semibold\", value: 600 },\n { label: \"Bold\", value: 700 },\n ],\n },\n {\n token: \"--font-mono\",\n role: \"Monospace\",\n weights: [\n { label: \"Regular\", value: 400 },\n { label: \"Medium\", value: 500 },\n { label: \"Bold\", value: 700 },\n ],\n },\n]\n\nexport const TYPE_SPECIMENS: TypeSpecimenData[] = [\n { token: \"--font-size-4xl\", label: \"4xl\", sizePx: 36, sampleText: \"Display text\" },\n { token: \"--font-size-3xl\", label: \"3xl\", sizePx: 30, sampleText: \"Page heading\" },\n { token: \"--font-size-2xl\", label: \"2xl\", sizePx: 24, sampleText: \"Section heading\" },\n { token: \"--font-size-xl\", label: \"xl\", sizePx: 20, sampleText: \"Subsection heading\" },\n { token: \"--font-size-lg\", label: \"lg\", sizePx: 18, sampleText: \"Large body text\" },\n { token: \"--font-size-base\", label: \"base\", sizePx: 16, sampleText: \"Default body text for reading\" },\n { token: \"--font-size-sm\", label: \"sm\", sizePx: 14, sampleText: \"Small text, labels, and captions\" },\n { token: \"--font-size-xs\", label: \"xs\", sizePx: 12, sampleText: \"Fine print and metadata\" },\n]\n\n// ─── Spacing ─────────────────────────────────────────────────────────────────\n\nexport const SPACING_STEPS: SpacingStepData[] = [\n { token: \"--spacing-0\", name: \"0\", px: 0, rem: \"0\" },\n { token: \"--spacing-1\", name: \"1\", px: 4, rem: \"0.25rem\" },\n { token: \"--spacing-2\", name: \"2\", px: 8, rem: \"0.5rem\" },\n { token: \"--spacing-3\", name: \"3\", px: 12, rem: \"0.75rem\" },\n { token: \"--spacing-4\", name: \"4\", px: 16, rem: \"1rem\" },\n { token: \"--spacing-5\", name: \"5\", px: 20, rem: \"1.25rem\" },\n { token: \"--spacing-6\", name: \"6\", px: 24, rem: \"1.5rem\" },\n { token: \"--spacing-8\", name: \"8\", px: 32, rem: \"2rem\" },\n { token: \"--spacing-10\", name: \"10\", px: 40, rem: \"2.5rem\" },\n { token: \"--spacing-12\", name: \"12\", px: 48, rem: \"3rem\" },\n { token: \"--spacing-16\", name: \"16\", px: 64, rem: \"4rem\" },\n { token: \"--spacing-20\", name: \"20\", px: 80, rem: \"5rem\" },\n { token: \"--spacing-24\", name: \"24\", px: 96, rem: \"6rem\" },\n]\n\n// ─── Shadows ─────────────────────────────────────────────────────────────────\n\nexport const SHADOW_LEVELS: ShadowLevelData[] = [\n { token: \"--shadow-xs\", name: \"xs\", value: \"0 1px 1px 0 rgba(0, 0, 0, 0.04)\" },\n { token: \"--shadow-sm\", name: \"sm\", value: \"0 1px 2px 0 rgba(0, 0, 0, 0.05)\" },\n { token: \"--shadow-md\", name: \"md\", value: \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)\" },\n { token: \"--shadow-lg\", name: \"lg\", value: \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)\" },\n { token: \"--shadow-xl\", name: \"xl\", value: \"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)\" },\n]\n\n// ─── Surfaces ────────────────────────────────────────────────────────────────\n\nexport const SURFACES: SurfaceData[] = [\n { token: \"--surface-page\", name: \"Page\" },\n { token: \"--surface-card\", name: \"Card\" },\n { token: \"--surface-subtle\", name: \"Subtle\" },\n { token: \"--surface-muted\", name: \"Muted\" },\n { token: \"--surface-overlay\", name: \"Overlay\", lightText: true },\n { token: \"--surface-accent-subtle\", name: \"Accent Subtle\" },\n { token: \"--surface-accent-default\", name: \"Accent Default\", lightText: true },\n { token: \"--surface-accent-strong\", name: \"Accent Strong\", lightText: true },\n]\n\n// ─── Border Radius ───────────────────────────────────────────────────────────\n\nexport const RADIUS_STEPS: RadiusStepData[] = [\n { token: \"--radius-none\", name: \"none\", px: 0 },\n { token: \"--radius-sm\", name: \"sm\", px: 2 },\n { token: \"--radius-md\", name: \"md\", px: 4 },\n { token: \"--radius-lg\", name: \"lg\", px: 8 },\n { token: \"--radius-xl\", name: \"xl\", px: 12 },\n { token: \"--radius-2xl\", name: \"2xl\", px: 16 },\n { token: \"--radius-3xl\", name: \"3xl\", px: 24 },\n { token: \"--radius-full\", name: \"full\", px: 9999 },\n]\n\n// ─── Motion ──────────────────────────────────────────────────────────────────\n\nexport const MOTION_DURATIONS: MotionDurationData[] = [\n { token: \"--motion-duration-100\", name: \"100\", ms: 100 },\n { token: \"--motion-duration-150\", name: \"150\", ms: 150 },\n { token: \"--motion-duration-200\", name: \"200\", ms: 200 },\n { token: \"--motion-duration-300\", name: \"300\", ms: 300 },\n { token: \"--motion-duration-500\", name: \"500\", ms: 500 },\n { token: \"--motion-duration-800\", name: \"800\", ms: 800 },\n]\n\nexport const EASINGS: EasingData[] = [\n { token: \"--motion-easing-linear\", name: \"linear\", value: \"linear\" },\n { token: \"--motion-easing-ease-in\", name: \"ease-in\", value: \"cubic-bezier(0.4, 0, 1, 1)\" },\n { token: \"--motion-easing-ease-out\", name: \"ease-out\", value: \"cubic-bezier(0, 0, 0.2, 1)\" },\n { token: \"--motion-easing-ease-in-out\", name: \"ease-in-out\", value: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n { token: \"--motion-easing-spring\", name: \"spring\", value: \"cubic-bezier(0.34, 1.56, 0.64, 1)\" },\n]\n\n// ─── Accessibility ───────────────────────────────────────────────────────────\n\nexport const CONTRAST_PAIRS: ContrastPairData[] = [\n { fgToken: \"--text-primary\", bgToken: \"--surface-page\", fgLabel: \"text-primary\", bgLabel: \"surface-page\", ratio: 15.4, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-primary\", bgToken: \"--surface-card\", fgLabel: \"text-primary\", bgLabel: \"surface-card\", ratio: 15.4, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-secondary\", bgToken: \"--surface-page\", fgLabel: \"text-secondary\", bgLabel: \"surface-page\", ratio: 5.74, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-tertiary\", bgToken: \"--surface-page\", fgLabel: \"text-tertiary\", bgLabel: \"surface-page\", ratio: 4.75, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-link\", bgToken: \"--surface-page\", fgLabel: \"text-link\", bgLabel: \"surface-page\", ratio: 4.62, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-inverse\", bgToken: \"--surface-overlay\", fgLabel: \"text-inverse\", bgLabel: \"surface-overlay\", ratio: 14.7, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-success\", bgToken: \"--surface-page\", fgLabel: \"text-success\", bgLabel: \"surface-page\", ratio: 4.49, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-error\", bgToken: \"--surface-page\", fgLabel: \"text-error\", bgLabel: \"surface-page\", ratio: 5.25, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-warning\", bgToken: \"--surface-page\", fgLabel: \"text-warning\", bgLabel: \"surface-page\", ratio: 4.01, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-primary\", bgToken: \"--surface-subtle\", fgLabel: \"text-primary\", bgLabel: \"surface-subtle\", ratio: 14.9, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-primary\", bgToken: \"--surface-muted\", fgLabel: \"text-primary\", bgLabel: \"surface-muted\", ratio: 13.8, wcagAA: true, wcagAAA: true },\n]\n\n// ─── Icons ───────────────────────────────────────────────────────────────────\n\nexport const ICON_SPECIMENS: IconSpecimenData[] = [\n { name: \"House\", phosphorName: \"House\", usage: \"Home / dashboard\" },\n { name: \"MagnifyingGlass\", phosphorName: \"MagnifyingGlass\", usage: \"Search\" },\n { name: \"Gear\", phosphorName: \"Gear\", usage: \"Settings\" },\n { name: \"User\", phosphorName: \"User\", usage: \"Profile / account\" },\n { name: \"Bell\", phosphorName: \"Bell\", usage: \"Notifications\" },\n { name: \"EnvelopeSimple\", phosphorName: \"EnvelopeSimple\", usage: \"Messages / email\" },\n { name: \"Plus\", phosphorName: \"Plus\", usage: \"Add / create\" },\n { name: \"X\", phosphorName: \"X\", usage: \"Close / dismiss\" },\n { name: \"Check\", phosphorName: \"Check\", usage: \"Confirm / success\" },\n { name: \"Warning\", phosphorName: \"Warning\", usage: \"Warning / caution\" },\n { name: \"Info\", phosphorName: \"Info\", usage: \"Information\" },\n { name: \"ArrowRight\", phosphorName: \"ArrowRight\", usage: \"Navigate / next\" },\n { name: \"CaretDown\", phosphorName: \"CaretDown\", usage: \"Expand / dropdown\" },\n { name: \"DotsThree\", phosphorName: \"DotsThree\", usage: \"More actions\" },\n { name: \"PencilSimple\", phosphorName: \"PencilSimple\", usage: \"Edit\" },\n { name: \"Trash\", phosphorName: \"Trash\", usage: \"Delete\" },\n]\n\n// ─── Icon sizes for the size scale demo ──────────────────────────────────────\n\nexport const ICON_SIZES = [16, 20, 24, 32] as const\n"
|
|
3473
|
+
"content": "/**\n * Design System Specimen — Data\n *\n * Typed data arrays for all specimen sections.\n * Values sourced from packages/tokens/src/tokens/primitives.ts and semantic.ts.\n */\n\n// ─── Interfaces ──────────────────────────────────────────────────────────────\n\nexport interface ColorSwatchData {\n token: string\n hex: string\n name: string\n lightText?: boolean\n /** When true, ColorSwatch reads the live computed value instead of displaying the fallback hex */\n dynamic?: boolean\n}\n\nexport interface ColorScaleData {\n name: string\n swatches: ColorSwatchData[]\n /** When set, renders a featured brand swatch above the scale reading this token */\n brandToken?: string\n}\n\nexport interface SemanticColorData {\n token: string\n label: string\n category: string\n}\n\nexport interface TypeSpecimenData {\n token: string\n label: string\n sizePx: number\n sampleText: string\n}\n\nexport interface SpacingStepData {\n token: string\n name: string\n px: number\n rem: string\n}\n\nexport interface ShadowLevelData {\n token: string\n name: string\n value: string\n}\n\nexport interface SurfaceData {\n token: string\n name: string\n lightText?: boolean\n}\n\nexport interface RadiusStepData {\n token: string\n name: string\n px: number\n}\n\nexport interface MotionDurationData {\n token: string\n name: string\n ms: number\n}\n\nexport interface EasingData {\n token: string\n name: string\n value: string\n}\n\nexport interface ContrastPairData {\n fgToken: string\n bgToken: string\n fgLabel: string\n bgLabel: string\n ratio: number\n wcagAA: boolean\n wcagAAA: boolean\n}\n\nexport interface IconSpecimenData {\n name: string\n phosphorName: string\n usage: string\n}\n\nexport interface FontWeightData {\n label: string\n value: number\n}\n\nexport interface FontFamilyData {\n /** CSS custom property token (e.g. \"--font-heading\") */\n token: string\n /** Display role (e.g. \"Heading & Body\", \"Monospace\") */\n role: string\n /** Font family display name — omit to read dynamically from the CSS token */\n familyName?: string\n /** Available weights */\n weights: FontWeightData[]\n}\n\n// ─── Color Scales ────────────────────────────────────────────────────────────\n\nexport interface StatusColorScaleData extends ColorScaleData {\n /** Semantic role label (e.g. \"Success\", \"Warning\") */\n role: string\n}\n\nexport const THEME_COLOR_SCALES: ColorScaleData[] = [\n {\n name: \"Primary\",\n brandToken: \"--interactive-primary-bg\",\n swatches: [\n { token: \"--color-primary-100\", hex: \"#cfdfe7\", name: \"100\", dynamic: true },\n { token: \"--color-primary-200\", hex: \"#adc8d5\", name: \"200\", dynamic: true },\n { token: \"--color-primary-300\", hex: \"#89aec0\", name: \"300\", dynamic: true },\n { token: \"--color-primary-400\", hex: \"#6093aa\", name: \"400\", dynamic: true },\n { token: \"--color-primary-500\", hex: \"#397a96\", name: \"500\", lightText: true, dynamic: true },\n { token: \"--color-primary-600\", hex: \"#2a647c\", name: \"600\", lightText: true, dynamic: true },\n { token: \"--color-primary-700\", hex: \"#1a4e64\", name: \"700\", lightText: true, dynamic: true },\n { token: \"--color-primary-800\", hex: \"#0b3a4c\", name: \"800\", lightText: true, dynamic: true },\n { token: \"--color-primary-900\", hex: \"#002938\", name: \"900\", lightText: true, dynamic: true },\n { token: \"--color-primary-950\", hex: \"#001c29\", name: \"950\", lightText: true, dynamic: true },\n ],\n },\n {\n name: \"Neutral\",\n swatches: [\n { token: \"--color-gray-100\", hex: \"#f3f4f6\", name: \"100\" },\n { token: \"--color-gray-200\", hex: \"#e5e7eb\", name: \"200\" },\n { token: \"--color-gray-300\", hex: \"#d1d5db\", name: \"300\" },\n { token: \"--color-gray-400\", hex: \"#9ca3af\", name: \"400\" },\n { token: \"--color-gray-500\", hex: \"#6b7280\", name: \"500\", lightText: true },\n { token: \"--color-gray-600\", hex: \"#4b5563\", name: \"600\", lightText: true },\n { token: \"--color-gray-700\", hex: \"#374151\", name: \"700\", lightText: true },\n { token: \"--color-gray-800\", hex: \"#1f2937\", name: \"800\", lightText: true },\n { token: \"--color-gray-900\", hex: \"#111827\", name: \"900\", lightText: true },\n { token: \"--color-gray-950\", hex: \"#030712\", name: \"950\", lightText: true },\n ],\n },\n]\n\nexport const STATUS_COLOR_SCALES: StatusColorScaleData[] = [\n {\n name: \"Success\",\n role: \"Success\",\n swatches: [\n { token: \"--color-green-50\", hex: \"#f0fdf4\", name: \"50\" },\n { token: \"--color-green-100\", hex: \"#dcfce7\", name: \"100\" },\n { token: \"--color-green-500\", hex: \"#22c55e\", name: \"500\", lightText: true },\n { token: \"--color-green-600\", hex: \"#16a34a\", name: \"600\", lightText: true },\n { token: \"--color-green-700\", hex: \"#15803d\", name: \"700\", lightText: true },\n { token: \"--color-green-900\", hex: \"#14532d\", name: \"900\", lightText: true },\n ],\n },\n {\n name: \"Warning\",\n role: \"Warning\",\n swatches: [\n { token: \"--color-amber-50\", hex: \"#fffbeb\", name: \"50\" },\n { token: \"--color-amber-100\", hex: \"#fef3c7\", name: \"100\" },\n { token: \"--color-amber-500\", hex: \"#f59e0b\", name: \"500\" },\n { token: \"--color-amber-600\", hex: \"#d97706\", name: \"600\", lightText: true },\n { token: \"--color-amber-700\", hex: \"#b45309\", name: \"700\", lightText: true },\n { token: \"--color-amber-900\", hex: \"#78350f\", name: \"900\", lightText: true },\n ],\n },\n {\n name: \"Error\",\n role: \"Error\",\n swatches: [\n { token: \"--color-red-50\", hex: \"#fef2f2\", name: \"50\" },\n { token: \"--color-red-100\", hex: \"#fee2e2\", name: \"100\" },\n { token: \"--color-red-500\", hex: \"#ef4444\", name: \"500\", lightText: true },\n { token: \"--color-red-600\", hex: \"#dc2626\", name: \"600\", lightText: true },\n { token: \"--color-red-700\", hex: \"#b91c1c\", name: \"700\", lightText: true },\n { token: \"--color-red-900\", hex: \"#7f1d1d\", name: \"900\", lightText: true },\n ],\n },\n {\n name: \"Info\",\n role: \"Info\",\n swatches: [\n { token: \"--color-sky-50\", hex: \"#f0f9ff\", name: \"50\" },\n { token: \"--color-sky-100\", hex: \"#e0f2fe\", name: \"100\" },\n { token: \"--color-sky-500\", hex: \"#0ea5e9\", name: \"500\", lightText: true },\n { token: \"--color-sky-600\", hex: \"#0284c7\", name: \"600\", lightText: true },\n { token: \"--color-sky-700\", hex: \"#0369a1\", name: \"700\", lightText: true },\n { token: \"--color-sky-900\", hex: \"#0c4a6e\", name: \"900\", lightText: true },\n ],\n },\n]\n\nexport const SEMANTIC_COLORS: SemanticColorData[] = [\n // Text\n { token: \"--text-primary\", label: \"text-primary\", category: \"Text\" },\n { token: \"--text-secondary\", label: \"text-secondary\", category: \"Text\" },\n { token: \"--text-tertiary\", label: \"text-tertiary\", category: \"Text\" },\n { token: \"--text-disabled\", label: \"text-disabled\", category: \"Text\" },\n { token: \"--text-inverse\", label: \"text-inverse\", category: \"Text\" },\n { token: \"--text-link\", label: \"text-link\", category: \"Text\" },\n { token: \"--text-success\", label: \"text-success\", category: \"Text\" },\n { token: \"--text-warning\", label: \"text-warning\", category: \"Text\" },\n { token: \"--text-error\", label: \"text-error\", category: \"Text\" },\n { token: \"--text-info\", label: \"text-info\", category: \"Text\" },\n // Surface\n { token: \"--surface-page\", label: \"surface-page\", category: \"Surface\" },\n { token: \"--surface-card\", label: \"surface-card\", category: \"Surface\" },\n { token: \"--surface-subtle\", label: \"surface-subtle\", category: \"Surface\" },\n { token: \"--surface-muted\", label: \"surface-muted\", category: \"Surface\" },\n { token: \"--surface-overlay\", label: \"surface-overlay\", category: \"Surface\" },\n { token: \"--surface-accent-subtle\", label: \"surface-accent-subtle\", category: \"Surface\" },\n { token: \"--surface-accent-default\", label: \"surface-accent-default\", category: \"Surface\" },\n { token: \"--surface-accent-strong\", label: \"surface-accent-strong\", category: \"Surface\" },\n // Border\n { token: \"--border-default\", label: \"border-default\", category: \"Border\" },\n { token: \"--border-muted\", label: \"border-muted\", category: \"Border\" },\n { token: \"--border-strong\", label: \"border-strong\", category: \"Border\" },\n { token: \"--border-focus\", label: \"border-focus\", category: \"Border\" },\n]\n\n// ─── Typography ──────────────────────────────────────────────────────────────\n\n/**\n * Canonical CSS weight labels keyed by numeric weight. Used to label specimen\n * rows derived from a theme's actual loaded weights (VI-356, D2). Uses the\n * standard CSS Fonts Module names — \"Regular\" not \"Book\", \"Semibold\" not\n * \"Demibold\" — so the operator sees one consistent vocabulary regardless of\n * what a foundry calls the cut.\n */\nexport const WEIGHT_LABELS: Record<number, string> = {\n 100: \"Thin\",\n 200: \"Extra Light\",\n 300: \"Light\",\n 400: \"Regular\",\n 500: \"Medium\",\n 600: \"Semibold\",\n 700: \"Bold\",\n 800: \"Extra Bold\",\n 900: \"Black\",\n}\n\nexport function labelForWeight(weight: number): string {\n return WEIGHT_LABELS[weight] ?? `W${weight}`\n}\n\n/** Typography slot data — matches the manifest shape emitted by the docs site for private themes (VI-356). */\nexport interface ThemeTypographySlot {\n family: string\n weights: number[]\n}\n\nexport interface ThemeTypographyManifest {\n heading?: ThemeTypographySlot\n display?: ThemeTypographySlot\n body?: ThemeTypographySlot\n mono?: ThemeTypographySlot\n}\n\n/**\n * Derive Font Families specimen rows from a theme's typography manifest.\n *\n * - `--font-heading` row uses the heading slot's family and weights when\n * present, falling back to display, then body. Post-VI-355 the engine\n * resolves `--font-heading` from `typography.heading.family` directly;\n * earlier the docs adapter aliased it to `var(--font-sans)` (body),\n * which is why this used to read body first.\n * - `--font-mono` row uses the mono slot's weights when present, falling back\n * to body weights, then the default.\n *\n * Any slot the manifest doesn't cover gets the corresponding fallback row from\n * `defaults`. This keeps stock themes (no `weights` in YAML) on the existing\n * 4+3 grid while themes like Blacklight render their five actual weights.\n */\nexport function deriveFontFamiliesFromTypography(\n manifest: ThemeTypographyManifest | undefined,\n defaults: FontFamilyData[],\n): FontFamilyData[] {\n if (!manifest) return defaults\n\n const headingDefault = defaults.find((f) => f.token === \"--font-heading\")\n const monoDefault = defaults.find((f) => f.token === \"--font-mono\")\n\n const headingSlot = manifest.heading ?? manifest.display ?? manifest.body\n const monoSlot = manifest.mono ?? manifest.body ?? manifest.display ?? manifest.heading\n\n const next: FontFamilyData[] = []\n if (headingDefault) {\n next.push(\n headingSlot\n ? {\n token: \"--font-heading\",\n role: headingDefault.role,\n familyName: headingSlot.family || headingDefault.familyName,\n weights: headingSlot.weights.map((w) => ({ label: labelForWeight(w), value: w })),\n }\n : headingDefault,\n )\n }\n if (monoDefault) {\n next.push(\n monoSlot\n ? {\n token: \"--font-mono\",\n role: monoDefault.role,\n familyName: monoSlot.family || monoDefault.familyName,\n weights: monoSlot.weights.map((w) => ({ label: labelForWeight(w), value: w })),\n }\n : monoDefault,\n )\n }\n return next\n}\n\n/**\n * Fallback weight rows for the Font Families specimen, used when a theme does\n * not declare per-slot `weights` in its `.visor.yaml`. Stock public themes\n * (Blackout, Borderless, Modern Minimal, Neutral, Space) all fall through to\n * these defaults since they rely on system-ui / default weights.\n */\nexport const FONT_FAMILIES: FontFamilyData[] = [\n {\n token: \"--font-heading\",\n role: \"Heading & Body\",\n weights: [\n { label: \"Regular\", value: 400 },\n { label: \"Medium\", value: 500 },\n { label: \"Semibold\", value: 600 },\n { label: \"Bold\", value: 700 },\n ],\n },\n {\n token: \"--font-mono\",\n role: \"Monospace\",\n weights: [\n { label: \"Regular\", value: 400 },\n { label: \"Medium\", value: 500 },\n { label: \"Bold\", value: 700 },\n ],\n },\n]\n\nexport const TYPE_SPECIMENS: TypeSpecimenData[] = [\n { token: \"--font-size-4xl\", label: \"4xl\", sizePx: 36, sampleText: \"Display text\" },\n { token: \"--font-size-3xl\", label: \"3xl\", sizePx: 30, sampleText: \"Page heading\" },\n { token: \"--font-size-2xl\", label: \"2xl\", sizePx: 24, sampleText: \"Section heading\" },\n { token: \"--font-size-xl\", label: \"xl\", sizePx: 20, sampleText: \"Subsection heading\" },\n { token: \"--font-size-lg\", label: \"lg\", sizePx: 18, sampleText: \"Large body text\" },\n { token: \"--font-size-base\", label: \"base\", sizePx: 16, sampleText: \"Default body text for reading\" },\n { token: \"--font-size-sm\", label: \"sm\", sizePx: 14, sampleText: \"Small text, labels, and captions\" },\n { token: \"--font-size-xs\", label: \"xs\", sizePx: 12, sampleText: \"Fine print and metadata\" },\n]\n\n// ─── Spacing ─────────────────────────────────────────────────────────────────\n\nexport const SPACING_STEPS: SpacingStepData[] = [\n { token: \"--spacing-0\", name: \"0\", px: 0, rem: \"0\" },\n { token: \"--spacing-1\", name: \"1\", px: 4, rem: \"0.25rem\" },\n { token: \"--spacing-2\", name: \"2\", px: 8, rem: \"0.5rem\" },\n { token: \"--spacing-3\", name: \"3\", px: 12, rem: \"0.75rem\" },\n { token: \"--spacing-4\", name: \"4\", px: 16, rem: \"1rem\" },\n { token: \"--spacing-5\", name: \"5\", px: 20, rem: \"1.25rem\" },\n { token: \"--spacing-6\", name: \"6\", px: 24, rem: \"1.5rem\" },\n { token: \"--spacing-8\", name: \"8\", px: 32, rem: \"2rem\" },\n { token: \"--spacing-10\", name: \"10\", px: 40, rem: \"2.5rem\" },\n { token: \"--spacing-12\", name: \"12\", px: 48, rem: \"3rem\" },\n { token: \"--spacing-16\", name: \"16\", px: 64, rem: \"4rem\" },\n { token: \"--spacing-20\", name: \"20\", px: 80, rem: \"5rem\" },\n { token: \"--spacing-24\", name: \"24\", px: 96, rem: \"6rem\" },\n]\n\n// ─── Shadows ─────────────────────────────────────────────────────────────────\n\nexport const SHADOW_LEVELS: ShadowLevelData[] = [\n { token: \"--shadow-xs\", name: \"xs\", value: \"0 1px 1px 0 rgba(0, 0, 0, 0.04)\" },\n { token: \"--shadow-sm\", name: \"sm\", value: \"0 1px 2px 0 rgba(0, 0, 0, 0.05)\" },\n { token: \"--shadow-md\", name: \"md\", value: \"0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)\" },\n { token: \"--shadow-lg\", name: \"lg\", value: \"0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)\" },\n { token: \"--shadow-xl\", name: \"xl\", value: \"0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)\" },\n]\n\n// ─── Surfaces ────────────────────────────────────────────────────────────────\n\nexport const SURFACES: SurfaceData[] = [\n { token: \"--surface-page\", name: \"Page\" },\n { token: \"--surface-card\", name: \"Card\" },\n { token: \"--surface-subtle\", name: \"Subtle\" },\n { token: \"--surface-muted\", name: \"Muted\" },\n { token: \"--surface-overlay\", name: \"Overlay\", lightText: true },\n { token: \"--surface-accent-subtle\", name: \"Accent Subtle\" },\n { token: \"--surface-accent-default\", name: \"Accent Default\", lightText: true },\n { token: \"--surface-accent-strong\", name: \"Accent Strong\", lightText: true },\n]\n\n// ─── Border Radius ───────────────────────────────────────────────────────────\n\nexport const RADIUS_STEPS: RadiusStepData[] = [\n { token: \"--radius-none\", name: \"none\", px: 0 },\n { token: \"--radius-sm\", name: \"sm\", px: 2 },\n { token: \"--radius-md\", name: \"md\", px: 4 },\n { token: \"--radius-lg\", name: \"lg\", px: 8 },\n { token: \"--radius-xl\", name: \"xl\", px: 12 },\n { token: \"--radius-2xl\", name: \"2xl\", px: 16 },\n { token: \"--radius-3xl\", name: \"3xl\", px: 24 },\n { token: \"--radius-full\", name: \"full\", px: 9999 },\n]\n\n// ─── Motion ──────────────────────────────────────────────────────────────────\n\nexport const MOTION_DURATIONS: MotionDurationData[] = [\n { token: \"--motion-duration-100\", name: \"100\", ms: 100 },\n { token: \"--motion-duration-150\", name: \"150\", ms: 150 },\n { token: \"--motion-duration-200\", name: \"200\", ms: 200 },\n { token: \"--motion-duration-300\", name: \"300\", ms: 300 },\n { token: \"--motion-duration-500\", name: \"500\", ms: 500 },\n { token: \"--motion-duration-800\", name: \"800\", ms: 800 },\n]\n\nexport const EASINGS: EasingData[] = [\n { token: \"--motion-easing-linear\", name: \"linear\", value: \"linear\" },\n { token: \"--motion-easing-ease-in\", name: \"ease-in\", value: \"cubic-bezier(0.4, 0, 1, 1)\" },\n { token: \"--motion-easing-ease-out\", name: \"ease-out\", value: \"cubic-bezier(0, 0, 0.2, 1)\" },\n { token: \"--motion-easing-ease-in-out\", name: \"ease-in-out\", value: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n { token: \"--motion-easing-spring\", name: \"spring\", value: \"cubic-bezier(0.34, 1.56, 0.64, 1)\" },\n]\n\n// ─── Accessibility ───────────────────────────────────────────────────────────\n\nexport const CONTRAST_PAIRS: ContrastPairData[] = [\n { fgToken: \"--text-primary\", bgToken: \"--surface-page\", fgLabel: \"text-primary\", bgLabel: \"surface-page\", ratio: 15.4, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-primary\", bgToken: \"--surface-card\", fgLabel: \"text-primary\", bgLabel: \"surface-card\", ratio: 15.4, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-secondary\", bgToken: \"--surface-page\", fgLabel: \"text-secondary\", bgLabel: \"surface-page\", ratio: 5.74, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-tertiary\", bgToken: \"--surface-page\", fgLabel: \"text-tertiary\", bgLabel: \"surface-page\", ratio: 4.75, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-link\", bgToken: \"--surface-page\", fgLabel: \"text-link\", bgLabel: \"surface-page\", ratio: 4.62, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-inverse\", bgToken: \"--surface-overlay\", fgLabel: \"text-inverse\", bgLabel: \"surface-overlay\", ratio: 14.7, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-success\", bgToken: \"--surface-page\", fgLabel: \"text-success\", bgLabel: \"surface-page\", ratio: 4.49, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-error\", bgToken: \"--surface-page\", fgLabel: \"text-error\", bgLabel: \"surface-page\", ratio: 5.25, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-warning\", bgToken: \"--surface-page\", fgLabel: \"text-warning\", bgLabel: \"surface-page\", ratio: 4.01, wcagAA: true, wcagAAA: false },\n { fgToken: \"--text-primary\", bgToken: \"--surface-subtle\", fgLabel: \"text-primary\", bgLabel: \"surface-subtle\", ratio: 14.9, wcagAA: true, wcagAAA: true },\n { fgToken: \"--text-primary\", bgToken: \"--surface-muted\", fgLabel: \"text-primary\", bgLabel: \"surface-muted\", ratio: 13.8, wcagAA: true, wcagAAA: true },\n]\n\n// ─── Icons ───────────────────────────────────────────────────────────────────\n\nexport const ICON_SPECIMENS: IconSpecimenData[] = [\n { name: \"House\", phosphorName: \"House\", usage: \"Home / dashboard\" },\n { name: \"MagnifyingGlass\", phosphorName: \"MagnifyingGlass\", usage: \"Search\" },\n { name: \"Gear\", phosphorName: \"Gear\", usage: \"Settings\" },\n { name: \"User\", phosphorName: \"User\", usage: \"Profile / account\" },\n { name: \"Bell\", phosphorName: \"Bell\", usage: \"Notifications\" },\n { name: \"EnvelopeSimple\", phosphorName: \"EnvelopeSimple\", usage: \"Messages / email\" },\n { name: \"Plus\", phosphorName: \"Plus\", usage: \"Add / create\" },\n { name: \"X\", phosphorName: \"X\", usage: \"Close / dismiss\" },\n { name: \"Check\", phosphorName: \"Check\", usage: \"Confirm / success\" },\n { name: \"Warning\", phosphorName: \"Warning\", usage: \"Warning / caution\" },\n { name: \"Info\", phosphorName: \"Info\", usage: \"Information\" },\n { name: \"ArrowRight\", phosphorName: \"ArrowRight\", usage: \"Navigate / next\" },\n { name: \"CaretDown\", phosphorName: \"CaretDown\", usage: \"Expand / dropdown\" },\n { name: \"DotsThree\", phosphorName: \"DotsThree\", usage: \"More actions\" },\n { name: \"PencilSimple\", phosphorName: \"PencilSimple\", usage: \"Edit\" },\n { name: \"Trash\", phosphorName: \"Trash\", usage: \"Delete\" },\n]\n\n// ─── Icon sizes for the size scale demo ──────────────────────────────────────\n\nexport const ICON_SIZES = [16, 20, 24, 32] as const\n"
|
|
3474
3474
|
},
|
|
3475
3475
|
{
|
|
3476
3476
|
"path": "blocks/design-system-specimen/token-specimens.tsx",
|
package/dist/visor-manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loworbitstudio/visor",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "CLI for the Visor design system — add components, hooks, and utilities to your project.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@aws-sdk/client-s3": "^3.1021.0",
|
|
47
47
|
"@babel/parser": "^7.26.0",
|
|
48
|
-
"@loworbitstudio/visor-theme-engine": "^0.
|
|
48
|
+
"@loworbitstudio/visor-theme-engine": "^0.8.0",
|
|
49
49
|
"commander": "^13.1.0",
|
|
50
50
|
"diff": "^8.0.4",
|
|
51
51
|
"picocolors": "^1.1.1",
|