rafters 0.0.71 → 0.0.72
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/index.js +383 -138
- package/dist/registry/types.d.ts +9 -1
- package/dist/registry/types.js +3 -2
- package/package.json +14 -14
package/dist/index.js
CHANGED
|
@@ -437,7 +437,7 @@ function generateThemeInlineBlock(semanticTokens) {
|
|
|
437
437
|
function generateRootBlock(semanticTokens, darkMode = "class") {
|
|
438
438
|
const semanticMappings = getSemanticMappingsFromTokens(semanticTokens);
|
|
439
439
|
const lines = [];
|
|
440
|
-
lines.push(":root {");
|
|
440
|
+
lines.push(":root, :host {");
|
|
441
441
|
for (const [name, mapping] of Object.entries(semanticMappings)) {
|
|
442
442
|
lines.push(` --rafters-${name}: var(--color-${mapping.light});`);
|
|
443
443
|
}
|
|
@@ -750,6 +750,37 @@ function generateTypographyCompositeUtilities(compositeTokens) {
|
|
|
750
750
|
}
|
|
751
751
|
return lines.join("\n");
|
|
752
752
|
}
|
|
753
|
+
function generateMotionUtilities(motionTokens) {
|
|
754
|
+
const semanticTokens = motionTokens.filter((t) => t.name.startsWith("motion-semantic-"));
|
|
755
|
+
if (semanticTokens.length === 0) {
|
|
756
|
+
return "";
|
|
757
|
+
}
|
|
758
|
+
const lines = ["/* Semantic motion utilities -- transition longhand per token */"];
|
|
759
|
+
for (const token of semanticTokens) {
|
|
760
|
+
if (typeof token.value !== "string") continue;
|
|
761
|
+
let spec;
|
|
762
|
+
try {
|
|
763
|
+
spec = JSON.parse(token.value);
|
|
764
|
+
} catch {
|
|
765
|
+
continue;
|
|
766
|
+
}
|
|
767
|
+
const className = token.name.replace("motion-semantic-", "motion-");
|
|
768
|
+
lines.push(`@utility ${className} {`);
|
|
769
|
+
lines.push(` transition-property: ${spec.properties.join(", ")};`);
|
|
770
|
+
lines.push(` transition-duration: var(--duration-${spec.durationTier});`);
|
|
771
|
+
lines.push(` transition-timing-function: var(--ease-${spec.curve});`);
|
|
772
|
+
if (spec.reducedMotion) {
|
|
773
|
+
lines.push(" @media (prefers-reduced-motion: reduce) {");
|
|
774
|
+
lines.push(` transition-property: ${spec.reducedMotion.properties.join(", ")};`);
|
|
775
|
+
if (typeof spec.reducedMotion.ms === "number") {
|
|
776
|
+
lines.push(` transition-duration: ${spec.reducedMotion.ms}ms;`);
|
|
777
|
+
}
|
|
778
|
+
lines.push(" }");
|
|
779
|
+
}
|
|
780
|
+
lines.push("}");
|
|
781
|
+
}
|
|
782
|
+
return lines.join("\n");
|
|
783
|
+
}
|
|
753
784
|
function overridePropertyToUtility(property, value) {
|
|
754
785
|
switch (property) {
|
|
755
786
|
case "fontFamily":
|
|
@@ -825,6 +856,11 @@ function tokensToTailwind(tokens, options = {}, typographyOverrides = []) {
|
|
|
825
856
|
sections.push("");
|
|
826
857
|
sections.push(depthUtilities);
|
|
827
858
|
}
|
|
859
|
+
const motionUtilities = generateMotionUtilities(groups.motion);
|
|
860
|
+
if (motionUtilities) {
|
|
861
|
+
sections.push("");
|
|
862
|
+
sections.push(motionUtilities);
|
|
863
|
+
}
|
|
828
864
|
const overrideCSS = generateTypographyOverrideCSS(typographyOverrides);
|
|
829
865
|
if (overrideCSS) {
|
|
830
866
|
sections.push("");
|
|
@@ -910,6 +946,13 @@ function escapeStringValue(value) {
|
|
|
910
946
|
}
|
|
911
947
|
return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
912
948
|
}
|
|
949
|
+
var VALID_IDENTIFIER = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
950
|
+
function namespaceKey(namespace) {
|
|
951
|
+
return VALID_IDENTIFIER.test(namespace) ? namespace : `'${namespace}'`;
|
|
952
|
+
}
|
|
953
|
+
function namespaceAccess(namespace) {
|
|
954
|
+
return VALID_IDENTIFIER.test(namespace) ? `tokens.${namespace}` : `tokens['${namespace}']`;
|
|
955
|
+
}
|
|
913
956
|
function namespaceToTypeName(namespace) {
|
|
914
957
|
return namespace.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
915
958
|
}
|
|
@@ -930,7 +973,7 @@ function generateTokensObject(tokensByNamespace, includeJSDoc) {
|
|
|
930
973
|
const namespaces = Array.from(tokensByNamespace.keys()).sort();
|
|
931
974
|
for (const namespace of namespaces) {
|
|
932
975
|
const tokens = tokensByNamespace.get(namespace) || [];
|
|
933
|
-
lines.push(` ${namespace}: {`);
|
|
976
|
+
lines.push(` ${namespaceKey(namespace)}: {`);
|
|
934
977
|
for (const token of tokens) {
|
|
935
978
|
const value = tokenValueToTS(token);
|
|
936
979
|
if (includeJSDoc && token.semanticMeaning) {
|
|
@@ -949,7 +992,7 @@ function generateTypeAliases(namespaces) {
|
|
|
949
992
|
lines.push("");
|
|
950
993
|
for (const namespace of namespaces) {
|
|
951
994
|
const typeName = `${namespaceToTypeName(namespace)}Token`;
|
|
952
|
-
lines.push(`export type ${typeName} = keyof typeof
|
|
995
|
+
lines.push(`export type ${typeName} = keyof (typeof ${namespaceAccess(namespace)});`);
|
|
953
996
|
}
|
|
954
997
|
if (namespaces.length > 0) {
|
|
955
998
|
lines.push("");
|
|
@@ -1124,15 +1167,21 @@ var DEPTH_LEVELS = [
|
|
|
1124
1167
|
"tooltip",
|
|
1125
1168
|
"overlay"
|
|
1126
1169
|
];
|
|
1127
|
-
var MOTION_DURATION_SCALE = [
|
|
1170
|
+
var MOTION_DURATION_SCALE = [
|
|
1171
|
+
"instant",
|
|
1172
|
+
"micro",
|
|
1173
|
+
"fast",
|
|
1174
|
+
"moderate",
|
|
1175
|
+
"normal",
|
|
1176
|
+
"slow"
|
|
1177
|
+
];
|
|
1128
1178
|
var EASING_CURVES = [
|
|
1179
|
+
"standard",
|
|
1180
|
+
"enter",
|
|
1181
|
+
"exit",
|
|
1129
1182
|
"linear",
|
|
1130
|
-
"
|
|
1131
|
-
"
|
|
1132
|
-
"ease-in-out",
|
|
1133
|
-
"productive",
|
|
1134
|
-
"expressive",
|
|
1135
|
-
"spring"
|
|
1183
|
+
"spring-smooth",
|
|
1184
|
+
"spring-snappy"
|
|
1136
1185
|
];
|
|
1137
1186
|
var BREAKPOINT_SCALE = ["sm", "md", "lg", "xl", "2xl"];
|
|
1138
1187
|
|
|
@@ -21442,6 +21491,13 @@ var ExampleSchema = external_exports.object({
|
|
|
21442
21491
|
description: external_exports.string().optional()
|
|
21443
21492
|
});
|
|
21444
21493
|
var ColorIntelligenceSchema = external_exports.object({
|
|
21494
|
+
// Designer-facing evocative handle ("Aged Terracotta", "Solar Citrine") from
|
|
21495
|
+
// the intelligence generator. Language, not identity: the deterministic
|
|
21496
|
+
// `name` on ColorValue is the stable, parseable address; `label` is the
|
|
21497
|
+
// voice. Optional because pre-label intelligence persists in Vectorize and
|
|
21498
|
+
// token files. Backported from platform's generateColorIntelligence, which
|
|
21499
|
+
// requires it on generation.
|
|
21500
|
+
label: external_exports.string().optional(),
|
|
21445
21501
|
reasoning: external_exports.string(),
|
|
21446
21502
|
emotionalImpact: external_exports.string(),
|
|
21447
21503
|
culturalContext: external_exports.string(),
|
|
@@ -21684,7 +21740,7 @@ var TokenSchema = external_exports.object({
|
|
|
21684
21740
|
motionIntent: external_exports.enum(["enter", "exit", "emphasis", "transition"]).optional(),
|
|
21685
21741
|
easingCurve: external_exports.tuple([external_exports.number(), external_exports.number(), external_exports.number(), external_exports.number()]).optional(),
|
|
21686
21742
|
// cubicBezier [x1, y1, x2, y2]
|
|
21687
|
-
easingName: external_exports.enum(["
|
|
21743
|
+
easingName: external_exports.enum(["standard", "enter", "exit", "linear", "spring-smooth", "spring-snappy"]).optional(),
|
|
21688
21744
|
delayMs: external_exports.number().optional(),
|
|
21689
21745
|
// Delay before animation starts
|
|
21690
21746
|
// Keyframe tokens (CSS @keyframes content / animation step definitions)
|
|
@@ -22301,78 +22357,216 @@ var DEFAULT_SHADOW_DEFINITIONS = {
|
|
|
22301
22357
|
};
|
|
22302
22358
|
var DEFAULT_DURATION_DEFINITIONS = {
|
|
22303
22359
|
instant: {
|
|
22304
|
-
|
|
22305
|
-
|
|
22306
|
-
|
|
22360
|
+
ms: 0,
|
|
22361
|
+
band: "",
|
|
22362
|
+
meaning: "No perceptible transition. Cursor changes, text selection, badge counts. Below all perception -- there is nothing to track, so nothing is communicated.",
|
|
22363
|
+
contexts: ["disabled-motion", "prefers-reduced-motion", "cursor", "badge-count"],
|
|
22364
|
+
motionIntent: "transition"
|
|
22365
|
+
},
|
|
22366
|
+
micro: {
|
|
22367
|
+
ms: 100,
|
|
22368
|
+
band: "at the instantaneous threshold (Nielsen 0.1s)",
|
|
22369
|
+
meaning: "Immediate but visible. Focus rings and press feedback. At the instantaneous threshold -- acknowledgment that input landed, not communication of a change.",
|
|
22370
|
+
contexts: ["focus", "press", "micro-feedback"],
|
|
22307
22371
|
motionIntent: "transition"
|
|
22308
22372
|
},
|
|
22309
22373
|
fast: {
|
|
22310
|
-
|
|
22311
|
-
|
|
22312
|
-
|
|
22374
|
+
ms: 150,
|
|
22375
|
+
band: "below the communicative window",
|
|
22376
|
+
meaning: "Hover states. The cursor is already there, so the response must match its speed. Below the communicative window -- acknowledgment, not communication.",
|
|
22377
|
+
contexts: ["hover", "micro-feedback"],
|
|
22313
22378
|
motionIntent: "transition"
|
|
22314
22379
|
},
|
|
22315
|
-
|
|
22316
|
-
|
|
22317
|
-
|
|
22318
|
-
|
|
22380
|
+
moderate: {
|
|
22381
|
+
ms: 250,
|
|
22382
|
+
band: "communicative (~200-300ms)",
|
|
22383
|
+
meaning: "Dropdowns, tab switches, small reveals. The communicative window: fast enough to feel responsive, slow enough for the eye to track a trajectory and build a spatial model.",
|
|
22384
|
+
contexts: ["dropdowns", "tab-switches", "small-reveals"],
|
|
22319
22385
|
motionIntent: "transition"
|
|
22320
22386
|
},
|
|
22321
|
-
|
|
22322
|
-
|
|
22323
|
-
|
|
22324
|
-
|
|
22387
|
+
normal: {
|
|
22388
|
+
ms: 350,
|
|
22389
|
+
band: "communicative, larger movement",
|
|
22390
|
+
meaning: "The workhorse -- modal entrances, toggles, standard state transitions. The communicative window for larger movement.",
|
|
22391
|
+
contexts: ["modals", "toggles", "state-changes"],
|
|
22325
22392
|
motionIntent: "enter"
|
|
22326
22393
|
},
|
|
22327
|
-
|
|
22328
|
-
|
|
22329
|
-
|
|
22330
|
-
|
|
22331
|
-
|
|
22394
|
+
slow: {
|
|
22395
|
+
ms: 500,
|
|
22396
|
+
band: "at the sluggish boundary",
|
|
22397
|
+
meaning: "Sheets, page transitions, large spatial movement where the user needs orientation. At the sluggish boundary -- the ceiling for anything but full-screen spatial transitions.",
|
|
22398
|
+
contexts: ["sheets", "page-transitions", "large-spatial-movement"],
|
|
22399
|
+
motionIntent: "enter"
|
|
22332
22400
|
}
|
|
22333
22401
|
};
|
|
22334
22402
|
var DEFAULT_EASING_DEFINITIONS = {
|
|
22403
|
+
standard: {
|
|
22404
|
+
curve: [0.25, 0.1, 0.25, 1],
|
|
22405
|
+
meaning: "Precision -- arrives exactly where it should, engineered rather than thrown. Decelerates into its final position. General-purpose state transitions and hover.",
|
|
22406
|
+
contexts: ["state-changes", "hover", "general-purpose"],
|
|
22407
|
+
css: "cubic-bezier(0.25, 0.1, 0.25, 1)"
|
|
22408
|
+
},
|
|
22409
|
+
enter: {
|
|
22410
|
+
curve: [0, 0, 0.2, 1],
|
|
22411
|
+
meaning: "Arrival, welcome, settling into place. The fast start communicates responsiveness; the slow finish communicates care. Anything entering the viewport. Paired with `exit` as a deliberately asymmetric couple. (Dragicevic 2011: slow-in/slow-out outperforms constant speed for tracking.)",
|
|
22412
|
+
contexts: ["enter-animations", "elements-appearing"],
|
|
22413
|
+
css: "cubic-bezier(0, 0, 0.2, 1)"
|
|
22414
|
+
},
|
|
22415
|
+
exit: {
|
|
22416
|
+
curve: [0.4, 0, 1, 1],
|
|
22417
|
+
meaning: "Withdrawal, giving space. The brief hesitation acknowledges the user; the fast departure avoids lingering. Anything leaving the viewport. Paired with `enter` as a deliberately asymmetric couple -- exits are faster than entrances by design.",
|
|
22418
|
+
contexts: ["exit-animations", "elements-leaving"],
|
|
22419
|
+
css: "cubic-bezier(0.4, 0, 1, 1)"
|
|
22420
|
+
},
|
|
22335
22421
|
linear: {
|
|
22336
22422
|
curve: [0, 0, 1, 1],
|
|
22337
|
-
meaning: "
|
|
22338
|
-
contexts: ["progress-bars", "loading-spinners", "opacity-fades"],
|
|
22423
|
+
meaning: "Mechanical, procedural, without personality -- a process, not a gesture. Progress and loading, where the system is working rather than interacting. Never for interactive spatial transitions.",
|
|
22424
|
+
contexts: ["progress-bars", "loading-spinners", "opacity-fades", "focus-ring-fade"],
|
|
22339
22425
|
css: "linear"
|
|
22340
22426
|
},
|
|
22341
|
-
"
|
|
22342
|
-
curve: [0.
|
|
22343
|
-
meaning: "
|
|
22344
|
-
contexts: ["
|
|
22345
|
-
css: "cubic-bezier(0.
|
|
22427
|
+
"spring-smooth": {
|
|
22428
|
+
curve: [0.2, 0.9, 0.3, 1],
|
|
22429
|
+
meaning: "Alive, coming physically to rest -- a critically-damped spring with no overshoot. Page transitions, sheets, large tracked spatial movement. (Johansson 1973 / Pratt 2010: animate motion is perceived as alive and captures attention.)",
|
|
22430
|
+
contexts: ["page-transitions", "sheets", "large-spatial-movement"],
|
|
22431
|
+
css: "cubic-bezier(0.2, 0.9, 0.3, 1)"
|
|
22346
22432
|
},
|
|
22347
|
-
"
|
|
22348
|
-
curve: [0, 0, 0.
|
|
22349
|
-
meaning: "
|
|
22350
|
-
contexts: ["
|
|
22351
|
-
css: "cubic-bezier(0, 0, 0.
|
|
22352
|
-
}
|
|
22353
|
-
|
|
22354
|
-
|
|
22355
|
-
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
|
|
22359
|
-
|
|
22360
|
-
|
|
22361
|
-
|
|
22362
|
-
|
|
22363
|
-
|
|
22364
|
-
},
|
|
22365
|
-
|
|
22366
|
-
|
|
22367
|
-
|
|
22368
|
-
|
|
22369
|
-
|
|
22370
|
-
|
|
22371
|
-
|
|
22372
|
-
|
|
22373
|
-
|
|
22374
|
-
|
|
22375
|
-
|
|
22433
|
+
"spring-snappy": {
|
|
22434
|
+
curve: [0.2, 0.8, 0.2, 1],
|
|
22435
|
+
meaning: "Alive, tight, following input closely -- a tighter spring with less settle and no overshoot. Toggles, presses, interactions that track input.",
|
|
22436
|
+
contexts: ["toggles", "presses", "input-tracking"],
|
|
22437
|
+
css: "cubic-bezier(0.2, 0.8, 0.2, 1)"
|
|
22438
|
+
}
|
|
22439
|
+
};
|
|
22440
|
+
var DEFAULT_MOTION_SEMANTIC_MAPPINGS = {
|
|
22441
|
+
hover: {
|
|
22442
|
+
properties: ["color", "background-color", "border-color"],
|
|
22443
|
+
durationTier: "fast",
|
|
22444
|
+
curve: "standard",
|
|
22445
|
+
reducedMotion: null,
|
|
22446
|
+
category: "interaction",
|
|
22447
|
+
sizeReasoning: "Colour only, no movement -- the cursor is already on target, so the response matches its speed at the fast tier.",
|
|
22448
|
+
meaning: "Hover-state colour transition. Acknowledges pointer presence.",
|
|
22449
|
+
contexts: ["hover", "links", "interactive-surfaces"]
|
|
22450
|
+
},
|
|
22451
|
+
focus: {
|
|
22452
|
+
properties: ["box-shadow", "outline-color"],
|
|
22453
|
+
durationTier: "micro",
|
|
22454
|
+
curve: "linear",
|
|
22455
|
+
reducedMotion: null,
|
|
22456
|
+
category: "interaction",
|
|
22457
|
+
sizeReasoning: "A ring appearing, not moving -- micro tier at linear velocity reads as the system marking focus, not a gesture. (Tailwind ring is box-shadow.)",
|
|
22458
|
+
meaning: "Focus-ring transition. Marks the focused element.",
|
|
22459
|
+
contexts: ["focus-visible", "keyboard-navigation"]
|
|
22460
|
+
},
|
|
22461
|
+
press: {
|
|
22462
|
+
properties: ["transform", "color", "background-color"],
|
|
22463
|
+
durationTier: "micro",
|
|
22464
|
+
curve: "spring-snappy",
|
|
22465
|
+
reducedMotion: { properties: ["color", "background-color"] },
|
|
22466
|
+
category: "interaction",
|
|
22467
|
+
sizeReasoning: "The fastest, tightest feedback -- micro tier with a snappy spring follows the finger. Under reduced motion the transform drops; the colour change survives.",
|
|
22468
|
+
meaning: "Press/active feedback. Confirms the input was received.",
|
|
22469
|
+
contexts: ["press", "active", "buttons"]
|
|
22470
|
+
},
|
|
22471
|
+
toggle: {
|
|
22472
|
+
properties: ["color", "background-color", "transform"],
|
|
22473
|
+
durationTier: "moderate",
|
|
22474
|
+
curve: "spring-snappy",
|
|
22475
|
+
reducedMotion: { properties: ["color", "background-color"] },
|
|
22476
|
+
category: "interaction",
|
|
22477
|
+
sizeReasoning: "A thumb travelling a track is a small, tracked movement -- moderate tier, snappy spring. Reduced motion drops the transform to a colour cross-fade.",
|
|
22478
|
+
meaning: "Toggle/switch state change. Shows the new state.",
|
|
22479
|
+
contexts: ["switch", "toggle", "checkbox"]
|
|
22480
|
+
},
|
|
22481
|
+
"dropdown-in": {
|
|
22482
|
+
properties: ["opacity", "transform"],
|
|
22483
|
+
durationTier: "moderate",
|
|
22484
|
+
curve: "enter",
|
|
22485
|
+
reducedMotion: { properties: ["opacity"], ms: 100 },
|
|
22486
|
+
category: "enter",
|
|
22487
|
+
sizeReasoning: "A dropdown is small and travels a short distance -- moderate tier, one step below the modal, with the arrival curve.",
|
|
22488
|
+
meaning: "Dropdown/menu entrance.",
|
|
22489
|
+
contexts: ["dropdown", "menu", "select", "popover"]
|
|
22490
|
+
},
|
|
22491
|
+
"dropdown-out": {
|
|
22492
|
+
properties: ["opacity", "transform"],
|
|
22493
|
+
durationTier: "fast",
|
|
22494
|
+
curve: "exit",
|
|
22495
|
+
reducedMotion: { properties: ["opacity"], ms: 100 },
|
|
22496
|
+
category: "exit",
|
|
22497
|
+
sizeReasoning: "The exit of a small element -- fast tier (shorter than its moderate entrance) with the departure curve. The user already chose to dismiss it.",
|
|
22498
|
+
meaning: "Dropdown/menu exit.",
|
|
22499
|
+
contexts: ["dropdown", "menu", "select", "popover"]
|
|
22500
|
+
},
|
|
22501
|
+
"modal-in": {
|
|
22502
|
+
properties: ["opacity", "transform"],
|
|
22503
|
+
durationTier: "normal",
|
|
22504
|
+
curve: "enter",
|
|
22505
|
+
reducedMotion: { properties: ["opacity"], ms: 150 },
|
|
22506
|
+
category: "enter",
|
|
22507
|
+
sizeReasoning: "A modal is larger and travels farther than a dropdown -- normal tier, one step up, with the arrival curve. Size and distance produce the longer duration.",
|
|
22508
|
+
meaning: "Modal/dialog entrance.",
|
|
22509
|
+
contexts: ["modal", "dialog", "alert-dialog"]
|
|
22510
|
+
},
|
|
22511
|
+
"modal-out": {
|
|
22512
|
+
properties: ["opacity", "transform"],
|
|
22513
|
+
durationTier: "moderate",
|
|
22514
|
+
curve: "exit",
|
|
22515
|
+
reducedMotion: { properties: ["opacity"], ms: 150 },
|
|
22516
|
+
category: "exit",
|
|
22517
|
+
sizeReasoning: "The modal exit -- moderate tier (shorter than its normal entrance) with the departure curve.",
|
|
22518
|
+
meaning: "Modal/dialog exit.",
|
|
22519
|
+
contexts: ["modal", "dialog", "alert-dialog"]
|
|
22520
|
+
},
|
|
22521
|
+
"sheet-in": {
|
|
22522
|
+
properties: ["transform"],
|
|
22523
|
+
durationTier: "slow",
|
|
22524
|
+
curve: "spring-smooth",
|
|
22525
|
+
reducedMotion: { properties: ["opacity"], ms: 250 },
|
|
22526
|
+
category: "enter",
|
|
22527
|
+
sizeReasoning: "A sheet is the largest spatial movement -- slow tier with the physical settle of a smooth spring, because the user must track it into place. Reduced motion becomes a cross-fade.",
|
|
22528
|
+
meaning: "Sheet/drawer entrance.",
|
|
22529
|
+
contexts: ["sheet", "drawer", "side-panel"]
|
|
22530
|
+
},
|
|
22531
|
+
"sheet-out": {
|
|
22532
|
+
properties: ["transform"],
|
|
22533
|
+
durationTier: "normal",
|
|
22534
|
+
curve: "exit",
|
|
22535
|
+
reducedMotion: { properties: ["opacity"], ms: 250 },
|
|
22536
|
+
category: "exit",
|
|
22537
|
+
sizeReasoning: "The sheet exit -- normal tier (shorter than its slow entrance) with the departure curve.",
|
|
22538
|
+
meaning: "Sheet/drawer exit.",
|
|
22539
|
+
contexts: ["sheet", "drawer", "side-panel"]
|
|
22540
|
+
},
|
|
22541
|
+
expand: {
|
|
22542
|
+
properties: ["grid-template-rows", "opacity"],
|
|
22543
|
+
durationTier: "normal",
|
|
22544
|
+
curve: "enter",
|
|
22545
|
+
reducedMotion: { properties: ["opacity"] },
|
|
22546
|
+
category: "enter",
|
|
22547
|
+
sizeReasoning: "Content unfolding to its natural height -- normal tier with the arrival curve. Transitions grid-template-rows (0fr->1fr), the transitionable stand-in for height:auto. Reduced motion snaps the rows and fades opacity.",
|
|
22548
|
+
meaning: "Expand/reveal collapsible content (accordion, disclosure).",
|
|
22549
|
+
contexts: ["accordion", "collapsible", "disclosure"]
|
|
22550
|
+
},
|
|
22551
|
+
collapse: {
|
|
22552
|
+
properties: ["grid-template-rows", "opacity"],
|
|
22553
|
+
durationTier: "moderate",
|
|
22554
|
+
curve: "exit",
|
|
22555
|
+
reducedMotion: { properties: ["opacity"] },
|
|
22556
|
+
category: "exit",
|
|
22557
|
+
sizeReasoning: "Content folding away -- moderate tier (shorter than its normal expansion) with the departure curve. Reduced motion snaps the rows.",
|
|
22558
|
+
meaning: "Collapse/hide collapsible content (accordion, disclosure).",
|
|
22559
|
+
contexts: ["accordion", "collapsible", "disclosure"]
|
|
22560
|
+
},
|
|
22561
|
+
page: {
|
|
22562
|
+
properties: ["opacity", "transform"],
|
|
22563
|
+
durationTier: "slow",
|
|
22564
|
+
curve: "spring-smooth",
|
|
22565
|
+
reducedMotion: { properties: ["opacity"], ms: 200 },
|
|
22566
|
+
category: "enter",
|
|
22567
|
+
sizeReasoning: "A whole-view transition -- slow tier with the physical settle of a smooth spring, because the user reorients across the largest possible distance.",
|
|
22568
|
+
meaning: "Page/route transition.",
|
|
22569
|
+
contexts: ["page-transition", "route-change", "view-switch"]
|
|
22376
22570
|
}
|
|
22377
22571
|
};
|
|
22378
22572
|
var DEFAULT_DELAY_DEFINITIONS = {
|
|
@@ -24997,7 +25191,14 @@ function tryParseUnit(cssValue, registry2 = DEFAULT_UNITS) {
|
|
|
24997
25191
|
}
|
|
24998
25192
|
|
|
24999
25193
|
// ../design-tokens/src/generators/motion.ts
|
|
25000
|
-
|
|
25194
|
+
var LEGACY_EASING_REMAP = {
|
|
25195
|
+
linear: "linear",
|
|
25196
|
+
"ease-out": "enter",
|
|
25197
|
+
"ease-in": "exit",
|
|
25198
|
+
"ease-in-out": "standard",
|
|
25199
|
+
spring: "spring-snappy"
|
|
25200
|
+
};
|
|
25201
|
+
function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, semanticMappings) {
|
|
25001
25202
|
const tokens = [];
|
|
25002
25203
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
25003
25204
|
const { baseTransitionDuration, progressionRatio } = config2;
|
|
@@ -25009,52 +25210,44 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs) {
|
|
|
25009
25210
|
value: `${baseTransitionDuration}ms`,
|
|
25010
25211
|
category: "motion",
|
|
25011
25212
|
namespace: "motion",
|
|
25012
|
-
semanticMeaning: "
|
|
25013
|
-
usageContext: ["calculation-reference"],
|
|
25213
|
+
semanticMeaning: "Legacy base transition duration. The perceptual duration scale (motion-duration-*) no longer derives from this; retained only as a reference value and delay-progression base.",
|
|
25214
|
+
usageContext: ["calculation-reference", "delay-base"],
|
|
25014
25215
|
progressionSystem: progressionRatio,
|
|
25015
|
-
description: `Base duration (${baseTransitionDuration}ms).
|
|
25216
|
+
description: `Base duration (${baseTransitionDuration}ms). Delay tokens use ${progressionRatio} progression (ratio ${ratioVal}); duration tiers are perceptually derived literals.`,
|
|
25016
25217
|
generatedAt: timestamp,
|
|
25017
25218
|
containerQueryAware: false,
|
|
25018
25219
|
reducedMotionAware: true,
|
|
25019
25220
|
userOverride: null,
|
|
25020
25221
|
usagePatterns: {
|
|
25021
|
-
do: ["Reference as the
|
|
25022
|
-
never: ["
|
|
25222
|
+
do: ["Reference as the delay-progression base"],
|
|
25223
|
+
never: ["Assume the perceptual duration tiers derive from this"]
|
|
25023
25224
|
}
|
|
25024
25225
|
});
|
|
25025
25226
|
for (const scale2 of MOTION_DURATION_SCALE) {
|
|
25026
25227
|
const def = durationDefs[scale2];
|
|
25027
25228
|
if (!def) continue;
|
|
25028
25229
|
const scaleIndex = MOTION_DURATION_SCALE.indexOf(scale2);
|
|
25029
|
-
|
|
25030
|
-
|
|
25031
|
-
if (def.step === "instant") {
|
|
25032
|
-
durationMs = 0;
|
|
25033
|
-
mathRelationship = "0";
|
|
25034
|
-
} else {
|
|
25035
|
-
durationMs = Math.round(computeStep(baseTransitionDuration, def.step));
|
|
25036
|
-
mathRelationship = def.step === 0 ? `${baseTransitionDuration}ms (base)` : `${baseTransitionDuration} \xD7 ${ratioVal}^${def.step}`;
|
|
25037
|
-
}
|
|
25230
|
+
const durationMs = def.ms;
|
|
25231
|
+
const bandNote = def.band ? ` Band: ${def.band}.` : "";
|
|
25038
25232
|
tokens.push({
|
|
25039
25233
|
name: `motion-duration-${scale2}`,
|
|
25040
|
-
value:
|
|
25234
|
+
value: `${durationMs}ms`,
|
|
25041
25235
|
category: "motion",
|
|
25042
25236
|
namespace: "motion",
|
|
25043
|
-
semanticMeaning: def.meaning
|
|
25237
|
+
semanticMeaning: `${def.meaning}${bandNote}`,
|
|
25044
25238
|
usageContext: def.contexts,
|
|
25045
25239
|
scalePosition: scaleIndex,
|
|
25046
|
-
progressionSystem: progressionRatio,
|
|
25047
25240
|
motionIntent: def.motionIntent,
|
|
25048
25241
|
motionDuration: durationMs,
|
|
25049
|
-
mathRelationship
|
|
25050
|
-
dependsOn:
|
|
25051
|
-
description: `Duration ${scale2}: ${durationMs}ms
|
|
25242
|
+
mathRelationship: def.band ? `${durationMs}ms (perceptual: ${def.band})` : `${durationMs}ms`,
|
|
25243
|
+
dependsOn: [],
|
|
25244
|
+
description: `Duration ${scale2}: ${durationMs}ms.${bandNote} ${def.meaning}`,
|
|
25052
25245
|
generatedAt: timestamp,
|
|
25053
25246
|
containerQueryAware: false,
|
|
25054
25247
|
reducedMotionAware: true,
|
|
25055
25248
|
userOverride: null,
|
|
25056
25249
|
usagePatterns: {
|
|
25057
|
-
do: scale2 === "instant" ? ["Use for prefers-reduced-motion", "Use for disabled animations"] : scale2 === "
|
|
25250
|
+
do: scale2 === "instant" ? ["Use for prefers-reduced-motion", "Use for disabled animations"] : scale2 === "micro" || scale2 === "fast" ? ["Use for acknowledgment feedback (hover, focus, press)"] : ["Use for communicative transitions where the user must track the change"],
|
|
25058
25251
|
never: ["Ignore prefers-reduced-motion", "Use slow animations for frequent actions"]
|
|
25059
25252
|
}
|
|
25060
25253
|
});
|
|
@@ -25077,10 +25270,10 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs) {
|
|
|
25077
25270
|
reducedMotionAware: true,
|
|
25078
25271
|
userOverride: null,
|
|
25079
25272
|
usagePatterns: {
|
|
25080
|
-
do: curve === "linear" ? ["Use for
|
|
25273
|
+
do: curve === "linear" ? ["Use for progress and loading, where the system is working not interacting"] : curve === "enter" ? ["Use for anything entering the viewport"] : curve === "exit" ? ["Use for anything leaving the viewport"] : ["Match the curve register to the interaction feel"],
|
|
25081
25274
|
never: [
|
|
25082
|
-
"Use
|
|
25083
|
-
"Use
|
|
25275
|
+
"Use exit for entering (arrives reluctantly)",
|
|
25276
|
+
"Use linear for interactive spatial transitions (reads as mechanical)"
|
|
25084
25277
|
]
|
|
25085
25278
|
}
|
|
25086
25279
|
});
|
|
@@ -25417,13 +25610,13 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs) {
|
|
|
25417
25610
|
} else {
|
|
25418
25611
|
const durationDef = durationDefs[anim.duration];
|
|
25419
25612
|
if (!durationDef) continue;
|
|
25420
|
-
|
|
25421
|
-
durationValue = `${durationMs}ms`;
|
|
25613
|
+
durationValue = `${durationDef.ms}ms`;
|
|
25422
25614
|
durationRef = `var(--motion-duration-${anim.duration})`;
|
|
25423
25615
|
}
|
|
25424
|
-
const
|
|
25616
|
+
const easingKey = LEGACY_EASING_REMAP[anim.easing] ?? anim.easing;
|
|
25617
|
+
const easingDef = easingDefs[easingKey];
|
|
25425
25618
|
if (!easingDef) continue;
|
|
25426
|
-
const easingRef = `var(--motion-easing-${
|
|
25619
|
+
const easingRef = `var(--motion-easing-${easingKey})`;
|
|
25427
25620
|
const iterations = anim.iterations || "";
|
|
25428
25621
|
const animValue = iterations ? `${anim.keyframe} ${durationRef} ${easingRef} ${iterations}` : `${anim.keyframe} ${durationRef} ${easingRef}`;
|
|
25429
25622
|
tokens.push({
|
|
@@ -25441,7 +25634,7 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs) {
|
|
|
25441
25634
|
dependsOn: [
|
|
25442
25635
|
`motion-keyframe-${anim.keyframe}`,
|
|
25443
25636
|
...anim.duration.endsWith("s") || anim.duration.endsWith("ms") ? [] : [`motion-duration-${anim.duration}`],
|
|
25444
|
-
`motion-easing-${
|
|
25637
|
+
`motion-easing-${easingKey}`
|
|
25445
25638
|
],
|
|
25446
25639
|
description: `Animation ${anim.name}: ${anim.meaning}`,
|
|
25447
25640
|
generatedAt: timestamp,
|
|
@@ -25489,14 +25682,10 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs) {
|
|
|
25489
25682
|
];
|
|
25490
25683
|
for (const comp of composites2) {
|
|
25491
25684
|
const durationDef = durationDefs[comp.duration];
|
|
25492
|
-
const
|
|
25685
|
+
const easingKey = LEGACY_EASING_REMAP[comp.easing] ?? comp.easing;
|
|
25686
|
+
const easingDef = easingDefs[easingKey];
|
|
25493
25687
|
if (!durationDef || !easingDef) continue;
|
|
25494
|
-
|
|
25495
|
-
if (durationDef.step === "instant") {
|
|
25496
|
-
durationMs = 0;
|
|
25497
|
-
} else {
|
|
25498
|
-
durationMs = Math.round(computeStep(baseTransitionDuration, durationDef.step));
|
|
25499
|
-
}
|
|
25688
|
+
const durationMs = durationDef.ms;
|
|
25500
25689
|
tokens.push({
|
|
25501
25690
|
name: comp.name,
|
|
25502
25691
|
value: `${durationMs}ms ${easingDef.css}`,
|
|
@@ -25506,27 +25695,54 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs) {
|
|
|
25506
25695
|
usageContext: comp.contexts,
|
|
25507
25696
|
motionDuration: durationMs,
|
|
25508
25697
|
easingCurve: easingDef.curve,
|
|
25509
|
-
easingName:
|
|
25510
|
-
dependsOn: [`motion-duration-${comp.duration}`, `motion-easing-${
|
|
25511
|
-
description: `${comp.meaning}. Combines ${comp.duration} duration with ${
|
|
25698
|
+
easingName: easingKey,
|
|
25699
|
+
dependsOn: [`motion-duration-${comp.duration}`, `motion-easing-${easingKey}`],
|
|
25700
|
+
description: `${comp.meaning}. Combines ${comp.duration} duration with ${easingKey} easing.`,
|
|
25512
25701
|
generatedAt: timestamp,
|
|
25513
25702
|
containerQueryAware: false,
|
|
25514
25703
|
reducedMotionAware: true,
|
|
25515
25704
|
userOverride: null
|
|
25516
25705
|
});
|
|
25517
25706
|
}
|
|
25707
|
+
for (const [name, mapping] of Object.entries(semanticMappings)) {
|
|
25708
|
+
tokens.push({
|
|
25709
|
+
name: `motion-semantic-${name}`,
|
|
25710
|
+
value: JSON.stringify({
|
|
25711
|
+
properties: mapping.properties,
|
|
25712
|
+
durationTier: mapping.durationTier,
|
|
25713
|
+
curve: mapping.curve,
|
|
25714
|
+
reducedMotion: mapping.reducedMotion
|
|
25715
|
+
}),
|
|
25716
|
+
category: "motion",
|
|
25717
|
+
namespace: "motion",
|
|
25718
|
+
semanticMeaning: `${mapping.meaning} ${mapping.sizeReasoning}`,
|
|
25719
|
+
usageContext: mapping.contexts,
|
|
25720
|
+
motionIntent: mapping.category === "enter" ? "enter" : mapping.category === "exit" ? "exit" : "transition",
|
|
25721
|
+
generateUtilityClass: true,
|
|
25722
|
+
dependsOn: [`motion-duration-${mapping.durationTier}`, `motion-easing-${mapping.curve}`],
|
|
25723
|
+
description: `Semantic motion motion-${name}: ${mapping.properties.join(", ")} over ${mapping.durationTier} with ${mapping.curve}. ${mapping.sizeReasoning}`,
|
|
25724
|
+
generatedAt: timestamp,
|
|
25725
|
+
containerQueryAware: false,
|
|
25726
|
+
reducedMotionAware: true,
|
|
25727
|
+
userOverride: null,
|
|
25728
|
+
usagePatterns: {
|
|
25729
|
+
do: [`Apply class motion-${name} and let a state/presence change trigger the transition`],
|
|
25730
|
+
never: ["Hardcode a raw numeric duration in place of this token"]
|
|
25731
|
+
}
|
|
25732
|
+
});
|
|
25733
|
+
}
|
|
25518
25734
|
tokens.push({
|
|
25519
25735
|
name: "motion-progression",
|
|
25520
25736
|
value: JSON.stringify({
|
|
25521
25737
|
ratio: progressionRatio,
|
|
25522
25738
|
ratioValue: ratioVal,
|
|
25523
25739
|
baseDuration: baseTransitionDuration,
|
|
25524
|
-
note: "
|
|
25740
|
+
note: "Duration tiers are perceptually derived literals (docs/MOTION.md); delay tokens use the workspace progression ratio from the base duration."
|
|
25525
25741
|
}),
|
|
25526
25742
|
category: "motion",
|
|
25527
25743
|
namespace: "motion",
|
|
25528
|
-
semanticMeaning: "Metadata about the motion
|
|
25529
|
-
description: `
|
|
25744
|
+
semanticMeaning: "Metadata about the motion system",
|
|
25745
|
+
description: `Duration tiers are perceptual literals; delays use ${progressionRatio} progression from ${baseTransitionDuration}ms base.`,
|
|
25530
25746
|
generatedAt: timestamp,
|
|
25531
25747
|
containerQueryAware: false,
|
|
25532
25748
|
userOverride: null
|
|
@@ -26436,7 +26652,8 @@ function createGeneratorDefs(colorPaletteBases) {
|
|
|
26436
26652
|
config2,
|
|
26437
26653
|
DEFAULT_DURATION_DEFINITIONS,
|
|
26438
26654
|
DEFAULT_EASING_DEFINITIONS,
|
|
26439
|
-
DEFAULT_DELAY_DEFINITIONS
|
|
26655
|
+
DEFAULT_DELAY_DEFINITIONS,
|
|
26656
|
+
DEFAULT_MOTION_SEMANTIC_MAPPINGS
|
|
26440
26657
|
)
|
|
26441
26658
|
},
|
|
26442
26659
|
{
|
|
@@ -27444,7 +27661,7 @@ var RegistryFileSchema = external_exports.object({
|
|
|
27444
27661
|
devDependencies: external_exports.array(external_exports.string()).default([])
|
|
27445
27662
|
// e.g., ["vitest"] - from @devDependencies JSDoc
|
|
27446
27663
|
});
|
|
27447
|
-
var RegistryItemTypeSchema = external_exports.enum(["ui", "primitive", "composite", "rule"]);
|
|
27664
|
+
var RegistryItemTypeSchema = external_exports.enum(["ui", "primitive", "composite", "rule", "substrate"]);
|
|
27448
27665
|
var RegistryItemIntelligenceSchema = external_exports.object({
|
|
27449
27666
|
cognitiveLoad: external_exports.number().optional(),
|
|
27450
27667
|
attentionEconomics: external_exports.string().optional(),
|
|
@@ -27472,7 +27689,8 @@ var RegistryIndexSchema = external_exports.object({
|
|
|
27472
27689
|
components: external_exports.array(external_exports.string()),
|
|
27473
27690
|
primitives: external_exports.array(external_exports.string()),
|
|
27474
27691
|
composites: external_exports.array(external_exports.string()).default([]),
|
|
27475
|
-
rules: external_exports.array(external_exports.string()).default([])
|
|
27692
|
+
rules: external_exports.array(external_exports.string()).default([]),
|
|
27693
|
+
substrate: external_exports.array(external_exports.string()).default([])
|
|
27476
27694
|
});
|
|
27477
27695
|
|
|
27478
27696
|
// src/registry/client.ts
|
|
@@ -27481,7 +27699,8 @@ var REGISTRY_SOURCE = {
|
|
|
27481
27699
|
ui: { folder: "components", label: "Component" },
|
|
27482
27700
|
primitive: { folder: "primitives", label: "Primitive" },
|
|
27483
27701
|
composite: { folder: "composites", label: "Composite" },
|
|
27484
|
-
rule: { folder: "rules", label: "Rule" }
|
|
27702
|
+
rule: { folder: "rules", label: "Rule" },
|
|
27703
|
+
substrate: { folder: "substrate", label: "Substrate" }
|
|
27485
27704
|
};
|
|
27486
27705
|
var FETCH_ORDER = Object.keys(REGISTRY_SOURCE);
|
|
27487
27706
|
var RegistryClient = class {
|
|
@@ -27517,7 +27736,8 @@ var RegistryClient = class {
|
|
|
27517
27736
|
ui: fetchFrom("ui"),
|
|
27518
27737
|
primitive: fetchFrom("primitive"),
|
|
27519
27738
|
composite: fetchFrom("composite"),
|
|
27520
|
-
rule: fetchFrom("rule")
|
|
27739
|
+
rule: fetchFrom("rule"),
|
|
27740
|
+
substrate: fetchFrom("substrate")
|
|
27521
27741
|
};
|
|
27522
27742
|
this.fetchComponent = this.fetchByType.ui;
|
|
27523
27743
|
this.fetchPrimitive = this.fetchByType.primitive;
|
|
@@ -28488,6 +28708,7 @@ function isSharedFile(path) {
|
|
|
28488
28708
|
}
|
|
28489
28709
|
return false;
|
|
28490
28710
|
}
|
|
28711
|
+
var REACT_FALLBACK_TARGETS = /* @__PURE__ */ new Set(["astro", "vue", "svelte"]);
|
|
28491
28712
|
function selectFilesForFramework(files, target) {
|
|
28492
28713
|
const preferredExt = targetToExtension(target);
|
|
28493
28714
|
const shared = files.filter((f) => isSharedFile(f.path));
|
|
@@ -28495,12 +28716,15 @@ function selectFilesForFramework(files, target) {
|
|
|
28495
28716
|
if (matched.length > 0) {
|
|
28496
28717
|
return { files: [...matched, ...shared], fallback: false };
|
|
28497
28718
|
}
|
|
28498
|
-
if (target
|
|
28719
|
+
if (REACT_FALLBACK_TARGETS.has(target)) {
|
|
28499
28720
|
const fallbackFiles = files.filter((f) => f.path.endsWith(".tsx"));
|
|
28500
28721
|
if (fallbackFiles.length > 0) {
|
|
28501
28722
|
return { files: [...fallbackFiles, ...shared], fallback: true };
|
|
28502
28723
|
}
|
|
28503
28724
|
}
|
|
28725
|
+
if (target !== "react" && !REACT_FALLBACK_TARGETS.has(target)) {
|
|
28726
|
+
return { files: shared, fallback: false };
|
|
28727
|
+
}
|
|
28504
28728
|
return { files, fallback: false };
|
|
28505
28729
|
}
|
|
28506
28730
|
var TARGET_GATED_COMPOSITE_FILES = [
|
|
@@ -28515,12 +28739,13 @@ function selectCompositeFiles(files, target) {
|
|
|
28515
28739
|
var FOLDER_NAMES = /* @__PURE__ */ new Set(["composites"]);
|
|
28516
28740
|
function isAlreadyInstalled(config2, item) {
|
|
28517
28741
|
if (!config2?.installed) return false;
|
|
28518
|
-
const { components, primitives, composites: composites2, rules } = config2.installed;
|
|
28742
|
+
const { components, primitives, composites: composites2, rules, substrate } = config2.installed;
|
|
28519
28743
|
const bucketByType = {
|
|
28520
28744
|
ui: components,
|
|
28521
28745
|
primitive: primitives,
|
|
28522
28746
|
composite: composites2 ?? [],
|
|
28523
|
-
rule: rules ?? []
|
|
28747
|
+
rule: rules ?? [],
|
|
28748
|
+
substrate: substrate ?? []
|
|
28524
28749
|
};
|
|
28525
28750
|
return bucketByType[item.type].includes(item.name);
|
|
28526
28751
|
}
|
|
@@ -28539,11 +28764,13 @@ function trackInstalled(config2, items) {
|
|
|
28539
28764
|
const installed = config2.installed;
|
|
28540
28765
|
if (!installed.composites) installed.composites = [];
|
|
28541
28766
|
if (!installed.rules) installed.rules = [];
|
|
28767
|
+
if (!installed.substrate) installed.substrate = [];
|
|
28542
28768
|
const bucketByType = {
|
|
28543
28769
|
ui: installed.components,
|
|
28544
28770
|
primitive: installed.primitives,
|
|
28545
28771
|
composite: installed.composites,
|
|
28546
|
-
rule: installed.rules
|
|
28772
|
+
rule: installed.rules,
|
|
28773
|
+
substrate: installed.substrate
|
|
28547
28774
|
};
|
|
28548
28775
|
for (const item of items) {
|
|
28549
28776
|
const bucket = bucketByType[item.type];
|
|
@@ -28553,11 +28780,12 @@ function trackInstalled(config2, items) {
|
|
|
28553
28780
|
installed.primitives.sort();
|
|
28554
28781
|
installed.composites.sort();
|
|
28555
28782
|
installed.rules.sort();
|
|
28783
|
+
installed.substrate.sort();
|
|
28556
28784
|
}
|
|
28557
28785
|
function rootFor(field, cwd, fallback) {
|
|
28558
28786
|
return field === void 0 ? fallback : resolveRoot(field, cwd, fallback);
|
|
28559
28787
|
}
|
|
28560
|
-
function transformPath(registryPath, config2, cwd) {
|
|
28788
|
+
function transformPath(registryPath, config2, cwd = process.cwd()) {
|
|
28561
28789
|
if (!config2) return registryPath;
|
|
28562
28790
|
const replacements = [
|
|
28563
28791
|
["components/ui/", config2.componentsPath, "components/ui"],
|
|
@@ -28572,10 +28800,16 @@ function transformPath(registryPath, config2, cwd) {
|
|
|
28572
28800
|
}
|
|
28573
28801
|
return registryPath;
|
|
28574
28802
|
}
|
|
28803
|
+
function substrateProjectPath(registryPath, config2, cwd = process.cwd()) {
|
|
28804
|
+
const componentsResolved = rootFor(config2?.componentsPath, cwd, "components/ui");
|
|
28805
|
+
const sourceRoot = componentsResolved.replace(/\/?components\/ui$/, "");
|
|
28806
|
+
return sourceRoot ? join7(sourceRoot, registryPath) : registryPath;
|
|
28807
|
+
}
|
|
28575
28808
|
function fileExists(cwd, relativePath) {
|
|
28576
28809
|
return existsSync3(join7(cwd, relativePath));
|
|
28577
28810
|
}
|
|
28578
|
-
function transformFileContent(content, config2, fileType = "component", cwd = process.cwd()) {
|
|
28811
|
+
function transformFileContent(content, config2, fileType = "component", cwd = process.cwd(), opts = {}) {
|
|
28812
|
+
const { substrateKinds = [], installPath } = opts;
|
|
28579
28813
|
let transformed = content;
|
|
28580
28814
|
const componentsPath = rootFor(config2?.componentsPath, cwd, "components/ui");
|
|
28581
28815
|
const primitivesPath = rootFor(config2?.primitivesPath, cwd, "lib/primitives");
|
|
@@ -28590,26 +28824,23 @@ function transformFileContent(content, config2, fileType = "component", cwd = pr
|
|
|
28590
28824
|
/from\s+['"]\.\.\/primitives\/([^'"]+)['"]/g,
|
|
28591
28825
|
`from '@/${aliasPrimitives}/$1'`
|
|
28592
28826
|
);
|
|
28593
|
-
const
|
|
28827
|
+
const substrateOwnDir = fileType === "substrate" && installPath ? stripSourceRoot(dirname(installPath)) : null;
|
|
28828
|
+
const aliasSibling = fileType === "primitive" ? aliasPrimitives : substrateOwnDir ?? aliasComponents;
|
|
28594
28829
|
transformed = transformed.replace(/from\s+['"]\.\/([^'"]+)['"]/g, `from '@/${aliasSibling}/$1'`);
|
|
28595
|
-
|
|
28596
|
-
|
|
28597
|
-
|
|
28598
|
-
|
|
28599
|
-
|
|
28600
|
-
|
|
28601
|
-
|
|
28602
|
-
transformed = transformed.replace(
|
|
28603
|
-
/from\s+['"]\.\.\/hooks\/([^'"]+)['"]/g,
|
|
28604
|
-
`from '@/${aliasHooks}/$1'`
|
|
28605
|
-
);
|
|
28830
|
+
if (substrateKinds.length > 0) {
|
|
28831
|
+
const kindAlternation = substrateKinds.join("|");
|
|
28832
|
+
transformed = transformed.replace(
|
|
28833
|
+
new RegExp(`from\\s+['"](?:\\.\\./){1,2}(${kindAlternation})/([^'"]+)['"]`, "g"),
|
|
28834
|
+
"from '@/$1/$2'"
|
|
28835
|
+
);
|
|
28836
|
+
}
|
|
28606
28837
|
transformed = transformed.replace(
|
|
28607
|
-
/from\s+['"]\.\.\/(
|
|
28838
|
+
/from\s+['"]\.\.\/([^'"]+)['"]/g,
|
|
28608
28839
|
`from '@/${aliasComponents}/$1'`
|
|
28609
28840
|
);
|
|
28610
28841
|
return transformed;
|
|
28611
28842
|
}
|
|
28612
|
-
async function installItem(cwd, item, options, config2) {
|
|
28843
|
+
async function installItem(cwd, item, options, config2, substrateKinds = []) {
|
|
28613
28844
|
const installedFiles = [];
|
|
28614
28845
|
let skipped = false;
|
|
28615
28846
|
let filesToInstall = item.files;
|
|
@@ -28625,11 +28856,17 @@ async function installItem(cwd, item, options, config2) {
|
|
|
28625
28856
|
message: `No ${targetToExtension(target)} version available for ${item.name}. Installing React version.`
|
|
28626
28857
|
});
|
|
28627
28858
|
}
|
|
28859
|
+
const hasComponentFile = selection.files.some((f) => !isSharedFile(f.path));
|
|
28860
|
+
if (!hasComponentFile) {
|
|
28861
|
+
throw new Error(
|
|
28862
|
+
`No ${targetToExtension(target)} version available for "${item.name}" and no compatible fallback exists.`
|
|
28863
|
+
);
|
|
28864
|
+
}
|
|
28628
28865
|
} else if (item.type === "composite") {
|
|
28629
28866
|
filesToInstall = selectCompositeFiles(item.files, getComponentTarget(config2));
|
|
28630
28867
|
}
|
|
28631
28868
|
for (const file2 of filesToInstall) {
|
|
28632
|
-
const projectPath2 = transformPath(file2.path, config2, cwd);
|
|
28869
|
+
const projectPath2 = item.type === "substrate" ? substrateProjectPath(file2.path, config2, cwd) : transformPath(file2.path, config2, cwd);
|
|
28633
28870
|
const targetPath = join7(cwd, projectPath2);
|
|
28634
28871
|
if (fileExists(cwd, projectPath2)) {
|
|
28635
28872
|
if (!options.overwrite) {
|
|
@@ -28644,8 +28881,11 @@ async function installItem(cwd, item, options, config2) {
|
|
|
28644
28881
|
}
|
|
28645
28882
|
}
|
|
28646
28883
|
await mkdir2(dirname(targetPath), { recursive: true });
|
|
28647
|
-
const fileType = item.type === "primitive" ? "primitive" : "component";
|
|
28648
|
-
const transformedContent = transformFileContent(file2.content, config2, fileType, cwd
|
|
28884
|
+
const fileType = item.type === "primitive" ? "primitive" : item.type === "substrate" ? "substrate" : "component";
|
|
28885
|
+
const transformedContent = transformFileContent(file2.content, config2, fileType, cwd, {
|
|
28886
|
+
substrateKinds,
|
|
28887
|
+
installPath: file2.path
|
|
28888
|
+
});
|
|
28649
28889
|
await writeFile2(targetPath, transformedContent, "utf-8");
|
|
28650
28890
|
installedFiles.push(projectPath2);
|
|
28651
28891
|
}
|
|
@@ -28758,6 +28998,11 @@ async function add(componentArgs, options) {
|
|
|
28758
28998
|
return;
|
|
28759
28999
|
}
|
|
28760
29000
|
}
|
|
29001
|
+
const substrateKinds = [
|
|
29002
|
+
...new Set(
|
|
29003
|
+
allItems.filter((item) => item.type === "substrate").map((item) => item.files[0]?.path.split("/")[0]).filter((segment) => Boolean(segment))
|
|
29004
|
+
)
|
|
29005
|
+
];
|
|
28761
29006
|
const installed = [];
|
|
28762
29007
|
const skipped = [];
|
|
28763
29008
|
const installedItems = [];
|
|
@@ -28781,7 +29026,7 @@ async function add(componentArgs, options) {
|
|
|
28781
29026
|
});
|
|
28782
29027
|
}
|
|
28783
29028
|
try {
|
|
28784
|
-
const result = await installItem(cwd, item, options, config2);
|
|
29029
|
+
const result = await installItem(cwd, item, options, config2, substrateKinds);
|
|
28785
29030
|
if (result.installed) {
|
|
28786
29031
|
installed.push(item.name);
|
|
28787
29032
|
installedItems.push(item);
|
package/dist/registry/types.d.ts
CHANGED
|
@@ -19,13 +19,19 @@ declare const RegistryFileSchema: z.ZodObject<{
|
|
|
19
19
|
}, z.core.$strip>;
|
|
20
20
|
type RegistryFile = z.infer<typeof RegistryFileSchema>;
|
|
21
21
|
/**
|
|
22
|
-
* Item type in registry
|
|
22
|
+
* Item type in registry.
|
|
23
|
+
* `substrate` is the behavior-layer runtime (the score contract, compose
|
|
24
|
+
* slices, reactive hooks -- everything under ui/src outside components /
|
|
25
|
+
* primitives / composites). It is a copy-in shared dependency resolved like a
|
|
26
|
+
* primitive; the specific dir it installs into (`@/lib`, `@/hooks`, ...) is
|
|
27
|
+
* carried in the item's file path, so the type never grows per kind.
|
|
23
28
|
*/
|
|
24
29
|
declare const RegistryItemTypeSchema: z.ZodEnum<{
|
|
25
30
|
ui: "ui";
|
|
26
31
|
primitive: "primitive";
|
|
27
32
|
composite: "composite";
|
|
28
33
|
rule: "rule";
|
|
34
|
+
substrate: "substrate";
|
|
29
35
|
}>;
|
|
30
36
|
type RegistryItemType = z.infer<typeof RegistryItemTypeSchema>;
|
|
31
37
|
/**
|
|
@@ -59,6 +65,7 @@ declare const RegistryItemSchema: z.ZodObject<{
|
|
|
59
65
|
primitive: "primitive";
|
|
60
66
|
composite: "composite";
|
|
61
67
|
rule: "rule";
|
|
68
|
+
substrate: "substrate";
|
|
62
69
|
}>;
|
|
63
70
|
description: z.ZodOptional<z.ZodString>;
|
|
64
71
|
primitives: z.ZodArray<z.ZodString>;
|
|
@@ -93,6 +100,7 @@ declare const RegistryIndexSchema: z.ZodObject<{
|
|
|
93
100
|
primitives: z.ZodArray<z.ZodString>;
|
|
94
101
|
composites: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
95
102
|
rules: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
103
|
+
substrate: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
96
104
|
}, z.core.$strip>;
|
|
97
105
|
type RegistryIndex = z.infer<typeof RegistryIndexSchema>;
|
|
98
106
|
|
package/dist/registry/types.js
CHANGED
|
@@ -8,7 +8,7 @@ var RegistryFileSchema = z.object({
|
|
|
8
8
|
devDependencies: z.array(z.string()).default([])
|
|
9
9
|
// e.g., ["vitest"] - from @devDependencies JSDoc
|
|
10
10
|
});
|
|
11
|
-
var RegistryItemTypeSchema = z.enum(["ui", "primitive", "composite", "rule"]);
|
|
11
|
+
var RegistryItemTypeSchema = z.enum(["ui", "primitive", "composite", "rule", "substrate"]);
|
|
12
12
|
var RegistryItemIntelligenceSchema = z.object({
|
|
13
13
|
cognitiveLoad: z.number().optional(),
|
|
14
14
|
attentionEconomics: z.string().optional(),
|
|
@@ -36,7 +36,8 @@ var RegistryIndexSchema = z.object({
|
|
|
36
36
|
components: z.array(z.string()),
|
|
37
37
|
primitives: z.array(z.string()),
|
|
38
38
|
composites: z.array(z.string()).default([]),
|
|
39
|
-
rules: z.array(z.string()).default([])
|
|
39
|
+
rules: z.array(z.string()).default([]),
|
|
40
|
+
substrate: z.array(z.string()).default([])
|
|
40
41
|
});
|
|
41
42
|
export {
|
|
42
43
|
RegistryFileSchema,
|
package/package.json
CHANGED
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rafters",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.72",
|
|
4
4
|
"description": "Design Intelligence CLI. Scaffold tokens, import existing shadcn/Tailwind v4 sources, add components, and serve an MCP server so AI agents read decisions instead of guessing.",
|
|
5
5
|
"homepage": "https://rafters.studio",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/rafters-studio/rafters.git",
|
|
10
|
+
"directory": "packages/cli"
|
|
11
|
+
},
|
|
8
12
|
"bin": {
|
|
9
13
|
"rafters": "./dist/index.js"
|
|
10
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
11
20
|
"exports": {
|
|
12
21
|
".": "./dist/index.js",
|
|
13
22
|
"./registry/types": {
|
|
@@ -15,10 +24,9 @@
|
|
|
15
24
|
"import": "./dist/registry/types.js"
|
|
16
25
|
}
|
|
17
26
|
},
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
|
|
21
|
-
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
22
30
|
"scripts": {
|
|
23
31
|
"build": "tsup",
|
|
24
32
|
"dev": "tsup --watch",
|
|
@@ -57,13 +65,5 @@
|
|
|
57
65
|
"typescript": "catalog:",
|
|
58
66
|
"vitest": "catalog:",
|
|
59
67
|
"zocker": "catalog:"
|
|
60
|
-
},
|
|
61
|
-
"repository": {
|
|
62
|
-
"type": "git",
|
|
63
|
-
"url": "git+https://github.com/rafters-studio/rafters.git",
|
|
64
|
-
"directory": "packages/cli"
|
|
65
|
-
},
|
|
66
|
-
"publishConfig": {
|
|
67
|
-
"access": "public"
|
|
68
68
|
}
|
|
69
69
|
}
|