@loworbitstudio/visor 1.28.0 → 1.29.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.4.0",
3
- "generated_at": "2026-09-24T03:45:50.627Z",
3
+ "generated_at": "2026-09-24T04:59:55.147Z",
4
4
  "components": {
5
5
  "accessibility-specimen": {
6
6
  "changeType": "current",
package/dist/index.js CHANGED
@@ -9052,7 +9052,24 @@ var FIXTURES = {
9052
9052
  default: {
9053
9053
  export: "Badge",
9054
9054
  props: `{ children: "New" }`
9055
- }
9055
+ },
9056
+ // One fixture per non-default variant (VI-661 reads each variant's ground and ink).
9057
+ ...Object.fromEntries(
9058
+ [
9059
+ "secondary",
9060
+ "outline",
9061
+ "destructive",
9062
+ "success",
9063
+ "warning",
9064
+ "info",
9065
+ "neutral",
9066
+ "filled-destructive",
9067
+ "filled-success",
9068
+ "filled-warning",
9069
+ "filled-info",
9070
+ "filled-neutral"
9071
+ ].map((variant) => [variant, { export: "Badge", props: `{ variant: "${variant}", children: "New" }` }])
9072
+ )
9056
9073
  }
9057
9074
  };
9058
9075
  var VALID_MODES = /* @__PURE__ */ new Set(["light", "dark"]);
@@ -427,7 +427,7 @@
427
427
  {
428
428
  "path": "components/ui/badge/badge.module.css",
429
429
  "type": "registry:ui",
430
- "content": "/* Badge base — sizing (height, padding, font-size, gap) is driven by the\n * size classes below. Height is intrinsic (padding + line-height) so badges\n * stay correct when text wraps or icon slots are introduced. */\n.base {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n flex-shrink: 0;\n overflow: hidden;\n border-radius: var(--badge-radius, var(--radius-full, 9999px));\n border: var(--badge-border, 1px solid transparent);\n line-height: 1;\n /* Typography defaults. Under data-density=\"editorial\" on any ancestor,\n the density rules below override to uppercase/heavier/tracked.\n VI-625: the D3 Tier-2 badge treatment (--badge-text-transform /\n -letter-spacing / -font-size / -font-weight) is bound here. */\n font-family: var(--badge-font-family, inherit);\n font-weight: var(--badge-font-weight, var(--font-weight-medium, 500));\n text-transform: var(--badge-text-transform, none);\n letter-spacing: var(--badge-letter-spacing, normal);\n white-space: nowrap;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Editorial density: uppercase + heavier + tracked. Any ancestor with\n * data-density=\"editorial\" (for example the app root) activates this. */\n:global([data-density=\"editorial\"]) .base {\n /* Theme-invariant: the editorial treatment runs 600 even when a theme maps\n --font-weight-semibold heavier (entr: 700). density-literal */\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n\n/* Editorial density opt-out: sizeLg is intrinsically a label (never tag),\n * and caseSentence lets sm/md opt out per-usage. Both must win over the\n * editorial .base rule above (same specificity, placed after). */\n:global([data-density=\"editorial\"]) .sizeLg,\n:global([data-density=\"editorial\"]) .caseSentence {\n text-transform: none;\n letter-spacing: 0;\n}\n\n/* uppercase prop — directly sets text-transform so it composes cleanly with\n * the density axis. Specificity (0,2,0), placed after .base, wins over default. */\n.base.uppercase {\n text-transform: uppercase;\n}\n\n.base:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Sizes — token-driven padding + font-size + gap on the 4px grid.\n * No --spacing-1.5 token exists, so the 6px step uses\n * calc(--spacing-1 + --spacing-1/2) — mirrors the pattern used in kbd. */\n.sizeSm {\n gap: var(--spacing-1, 0.25rem);\n padding: 0 calc(var(--spacing-1, 0.25rem) + var(--spacing-1, 0.25rem) / 2);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n/* md — matches canonical rendering (1.25rem total height). Under\n data-density=\"editorial\", font-size steps down to 11px. A theme binding\n --badge-font-size retunes BOTH steps, which is the point: the badge type\n size becomes one dial instead of two. */\n.sizeMd {\n gap: var(--badge-md-gap, var(--spacing-1, 0.25rem));\n padding: var(--badge-md-padding, calc(var(--spacing-1, 0.25rem) / 2) var(--spacing-2, 0.5rem));\n font-size: var(--badge-font-size, var(--font-size-xs, 0.75rem));\n}\n\n:global([data-density=\"editorial\"]) .sizeMd {\n font-size: var(--badge-font-size, 11px);\n}\n\n.sizeLg {\n gap: calc(var(--spacing-1, 0.25rem) + var(--spacing-1, 0.25rem) / 2);\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n}\n\n/* Sentence case — opt OUT of any uppercase/tracking applied by the density\n * axis or the uppercase prop. The large size always opts out (it is\n * intrinsically a label); the .caseSentence class lets sm/md opt out\n * per-usage. The editorial-density opt-out mirror lives above, after the\n * editorial .base rule, ensuring it wins at equal specificity. */\n.sizeLg,\n.caseSentence {\n text-transform: none;\n letter-spacing: 0;\n}\n\n/* Icon scaling — leading glyphs track the per-size font-size step. */\n.sizeSm > svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.sizeMd > svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.sizeLg > svg {\n width: 1rem;\n height: 1rem;\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--interactive-primary-bg, currentColor);\n color: var(--interactive-primary-text, var(--text-inverse, #f9fafb));\n border-color: transparent;\n}\n\n.variantSecondary {\n background-color: var(--interactive-secondary-bg, var(--surface-subtle, transparent));\n color: var(--interactive-secondary-text, var(--text-primary, currentColor));\n border-color: transparent;\n}\n\n/* Editorial density: secondary surfaces sit on the card tier. Direct value —\n * the editorial design language owns control surfaces, so the theme's\n * --interactive-secondary-bg is deliberately bypassed (matches the blessed\n * overlay, which out-cascaded the palette at :root). */\n:global([data-density=\"editorial\"]) .variantSecondary {\n background-color: var(--surface-card, #ffffff);\n}\n\n.variantOutline {\n background-color: transparent;\n color: var(--text-primary, #111827);\n border-color: var(--border-default, #e5e7eb);\n}\n\n/* Tonal variants — canonical surface tokens as plain values. Under\n * data-density=\"editorial\", backgrounds switch to color-mix tints for\n * higher saturation at editorial admin density. Text colors are unchanged. */\n.variantDestructive {\n background-color: var(--surface-error-subtle, transparent);\n color: var(--text-error, currentColor);\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantDestructive {\n background-color: color-mix(in srgb, var(--destructive) 20%, transparent);\n}\n\n.variantSuccess {\n background-color: var(--surface-success-subtle, transparent);\n color: var(--text-success, currentColor);\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantSuccess {\n background-color: color-mix(in srgb, var(--success) 18%, transparent);\n}\n\n.variantWarning {\n background-color: var(--surface-warning-subtle, transparent);\n color: var(--text-warning, currentColor);\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantWarning {\n background-color: color-mix(in srgb, var(--warning) 20%, transparent);\n}\n\n.variantInfo {\n background-color: var(--surface-info-subtle, transparent);\n color: var(--text-info, currentColor);\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantInfo {\n background-color: color-mix(in srgb, var(--info) 18%, transparent);\n}\n\n.variantNeutral {\n background-color: var(--surface-muted, #f3f4f6);\n color: var(--text-secondary, var(--text-primary, #374151));\n border-color: transparent;\n}\n\n/* Filled variants — step 9 bg + contrast text */\n.variantFilledDestructive {\n background-color: var(--surface-error-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledSuccess {\n background-color: var(--surface-success-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledWarning {\n background-color: var(--surface-warning-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledInfo {\n background-color: var(--surface-info-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n/* filled-neutral — the saturated counterpart to `neutral`. Neutral has no\n * brand `-default` surface, so it uses a fixed neutral-600 fill. Because that\n * fill is dark in BOTH modes, text must stay white (not `--text-inverse`,\n * which flips to a dark value in dark mode). */\n.variantFilledNeutral {\n background-color: var(--color-neutral-600, #4b5563);\n color: var(--color-white, #ffffff);\n border-color: transparent;\n}\n\n/* Icon-only — a circular, fixed-square chip carrying a single centered glyph\n * (for example the filled-success check used by the Roles matrix active cell +\n * legend). Zero padding and a fixed glyph size keep it crisp at any density.\n * The glyph centers via the base flex; per-size svg rules are overridden here. */\n.iconOnly {\n width: 1.375rem;\n height: 1.375rem;\n min-width: 1.375rem;\n padding: 0;\n gap: 0;\n border-radius: var(--radius-full, 9999px);\n}\n\n.iconOnly > svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n"
430
+ "content": "/* Badge base — sizing (height, padding, font-size, gap) is driven by the\n * size classes below. Height is intrinsic (padding + line-height) so badges\n * stay correct when text wraps or icon slots are introduced. */\n.base {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n flex-shrink: 0;\n overflow: hidden;\n border-radius: var(--badge-radius, var(--radius-full, 9999px));\n border: var(--badge-border, 1px solid transparent);\n line-height: 1;\n /* Typography defaults. Under data-density=\"editorial\" on any ancestor,\n the density rules below override to uppercase/heavier/tracked.\n VI-625: the D3 Tier-2 badge treatment (--badge-text-transform /\n -letter-spacing / -font-size / -font-weight) is bound here. */\n font-family: var(--badge-font-family, inherit);\n font-weight: var(--badge-font-weight, var(--font-weight-medium, 500));\n text-transform: var(--badge-text-transform, none);\n letter-spacing: var(--badge-letter-spacing, normal);\n white-space: nowrap;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Editorial density: uppercase + heavier + tracked. Any ancestor with\n * data-density=\"editorial\" (for example the app root) activates this. */\n:global([data-density=\"editorial\"]) .base {\n /* Theme-invariant: the editorial treatment runs 600 even when a theme maps\n --font-weight-semibold heavier (entr: 700). density-literal */\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n\n/* Editorial density opt-out: sizeLg is intrinsically a label (never tag),\n * and caseSentence lets sm/md opt out per-usage. Both must win over the\n * editorial .base rule above (same specificity, placed after). */\n:global([data-density=\"editorial\"]) .sizeLg,\n:global([data-density=\"editorial\"]) .caseSentence {\n text-transform: none;\n letter-spacing: 0;\n}\n\n/* uppercase prop — directly sets text-transform so it composes cleanly with\n * the density axis. Specificity (0,2,0), placed after .base, wins over default. */\n.base.uppercase {\n text-transform: uppercase;\n}\n\n.base:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Sizes — token-driven padding + font-size + gap on the 4px grid.\n * No --spacing-1.5 token exists, so the 6px step uses\n * calc(--spacing-1 + --spacing-1/2) — mirrors the pattern used in kbd. */\n.sizeSm {\n gap: var(--spacing-1, 0.25rem);\n padding: 0 calc(var(--spacing-1, 0.25rem) + var(--spacing-1, 0.25rem) / 2);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n/* md — matches canonical rendering (1.25rem total height). Under\n data-density=\"editorial\", font-size steps down to 11px. A theme binding\n --badge-font-size retunes BOTH steps, which is the point: the badge type\n size becomes one dial instead of two. */\n.sizeMd {\n gap: var(--badge-md-gap, var(--spacing-1, 0.25rem));\n padding: var(--badge-md-padding, calc(var(--spacing-1, 0.25rem) / 2) var(--spacing-2, 0.5rem));\n font-size: var(--badge-font-size, var(--font-size-xs, 0.75rem));\n}\n\n:global([data-density=\"editorial\"]) .sizeMd {\n font-size: var(--badge-font-size, 11px);\n}\n\n.sizeLg {\n gap: calc(var(--spacing-1, 0.25rem) + var(--spacing-1, 0.25rem) / 2);\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n}\n\n/* Sentence case — opt OUT of any uppercase/tracking applied by the density\n * axis or the uppercase prop. The large size always opts out (it is\n * intrinsically a label); the .caseSentence class lets sm/md opt out\n * per-usage. The editorial-density opt-out mirror lives above, after the\n * editorial .base rule, ensuring it wins at equal specificity. */\n.sizeLg,\n.caseSentence {\n text-transform: none;\n letter-spacing: 0;\n}\n\n/* Icon scaling — leading glyphs track the per-size font-size step. */\n.sizeSm > svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.sizeMd > svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.sizeLg > svg {\n width: 1rem;\n height: 1rem;\n}\n\n/* Variants\n * VI-661: every variant reads its ground and ink through --badge-bg /\n * --badge-ink, falling back to the value it shipped with. Set either on a\n * badge or any ancestor to tint one badge (an on-image scrim, a status tint)\n * without a variant per tint; with neither set nothing changes. */\n.variantDefault {\n background-color: var(--badge-bg, var(--interactive-primary-bg, currentColor));\n color: var(--badge-ink, var(--interactive-primary-text, var(--text-inverse, #f9fafb)));\n border-color: transparent;\n}\n\n.variantSecondary {\n background-color: var(--badge-bg, var(--interactive-secondary-bg, var(--surface-subtle, transparent)));\n color: var(--badge-ink, var(--interactive-secondary-text, var(--text-primary, currentColor)));\n border-color: transparent;\n}\n\n/* Editorial density: secondary surfaces sit on the card tier. Direct value —\n * the editorial design language owns control surfaces, so the theme's\n * --interactive-secondary-bg is deliberately bypassed (matches the blessed\n * overlay, which out-cascaded the palette at :root). */\n:global([data-density=\"editorial\"]) .variantSecondary {\n background-color: var(--badge-bg, var(--surface-card, #ffffff));\n}\n\n.variantOutline {\n background-color: var(--badge-bg, transparent);\n color: var(--badge-ink, var(--text-primary, #111827));\n border-color: var(--border-default, #e5e7eb);\n}\n\n/* Tonal variants — canonical surface tokens as plain values. Under\n * data-density=\"editorial\", backgrounds switch to color-mix tints for\n * higher saturation at editorial admin density. Text colors are unchanged. */\n.variantDestructive {\n background-color: var(--badge-bg, var(--surface-error-subtle, transparent));\n color: var(--badge-ink, var(--text-error, currentColor));\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantDestructive {\n background-color: var(--badge-bg, color-mix(in srgb, var(--destructive) 20%, transparent));\n}\n\n.variantSuccess {\n background-color: var(--badge-bg, var(--surface-success-subtle, transparent));\n color: var(--badge-ink, var(--text-success, currentColor));\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantSuccess {\n background-color: var(--badge-bg, color-mix(in srgb, var(--success) 18%, transparent));\n}\n\n.variantWarning {\n background-color: var(--badge-bg, var(--surface-warning-subtle, transparent));\n color: var(--badge-ink, var(--text-warning, currentColor));\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantWarning {\n background-color: var(--badge-bg, color-mix(in srgb, var(--warning) 20%, transparent));\n}\n\n.variantInfo {\n background-color: var(--badge-bg, var(--surface-info-subtle, transparent));\n color: var(--badge-ink, var(--text-info, currentColor));\n border-color: transparent;\n}\n\n:global([data-density=\"editorial\"]) .variantInfo {\n background-color: var(--badge-bg, color-mix(in srgb, var(--info) 18%, transparent));\n}\n\n.variantNeutral {\n background-color: var(--badge-bg, var(--surface-muted, #f3f4f6));\n color: var(--badge-ink, var(--text-secondary, var(--text-primary, #374151)));\n border-color: transparent;\n}\n\n/* Filled variants — step 9 bg + contrast text */\n.variantFilledDestructive {\n background-color: var(--badge-bg, var(--surface-error-default, transparent));\n color: var(--badge-ink, var(--text-inverse, currentColor));\n border-color: transparent;\n}\n\n.variantFilledSuccess {\n background-color: var(--badge-bg, var(--surface-success-default, transparent));\n color: var(--badge-ink, var(--text-inverse, currentColor));\n border-color: transparent;\n}\n\n.variantFilledWarning {\n background-color: var(--badge-bg, var(--surface-warning-default, transparent));\n color: var(--badge-ink, var(--text-inverse, currentColor));\n border-color: transparent;\n}\n\n.variantFilledInfo {\n background-color: var(--badge-bg, var(--surface-info-default, transparent));\n color: var(--badge-ink, var(--text-inverse, currentColor));\n border-color: transparent;\n}\n\n/* filled-neutral — the saturated counterpart to `neutral`. Neutral has no\n * brand `-default` surface, so it uses a fixed neutral-600 fill. Because that\n * fill is dark in BOTH modes, text must stay white (not `--text-inverse`,\n * which flips to a dark value in dark mode). */\n.variantFilledNeutral {\n background-color: var(--badge-bg, var(--color-neutral-600, #4b5563));\n color: var(--badge-ink, var(--color-white, #ffffff));\n border-color: transparent;\n}\n\n/* Icon-only — a circular, fixed-square chip carrying a single centered glyph\n * (for example the filled-success check used by the Roles matrix active cell +\n * legend). Zero padding and a fixed glyph size keep it crisp at any density.\n * The glyph centers via the base flex; per-size svg rules are overridden here. */\n.iconOnly {\n width: 1.375rem;\n height: 1.375rem;\n min-width: 1.375rem;\n padding: 0;\n gap: 0;\n border-radius: var(--radius-full, 9999px);\n}\n\n.iconOnly > svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n"
431
431
  }
432
432
  ]
433
433
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.4.0",
3
- "generated_at": "2026-09-24T03:45:50.617Z",
3
+ "generated_at": "2026-09-24T04:59:55.138Z",
4
4
  "components": {
5
5
  "accessibility-specimen": {
6
6
  "category": "specimen",
@@ -394,10 +394,12 @@
394
394
  "class-variance-authority"
395
395
  ],
396
396
  "tokens_used": [
397
+ "--badge-bg",
397
398
  "--badge-border",
398
399
  "--badge-font-family",
399
400
  "--badge-font-size",
400
401
  "--badge-font-weight",
402
+ "--badge-ink",
401
403
  "--badge-letter-spacing",
402
404
  "--badge-md-gap",
403
405
  "--badge-md-padding",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loworbitstudio/visor",
3
- "version": "1.28.0",
3
+ "version": "1.29.0",
4
4
  "description": "CLI for the Visor design system — add components, hooks, and utilities to your project.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -46,7 +46,7 @@
46
46
  "dependencies": {
47
47
  "@aws-sdk/client-s3": "^3.1021.0",
48
48
  "@babel/parser": "^7.26.0",
49
- "@loworbitstudio/visor-theme-engine": "^0.22.0",
49
+ "@loworbitstudio/visor-theme-engine": "^0.23.0",
50
50
  "commander": "^13.1.0",
51
51
  "diff": "^8.0.4",
52
52
  "picocolors": "^1.1.1",