rafters 0.0.76 → 0.0.78

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.
Files changed (2) hide show
  1. package/dist/index.js +381 -376
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -968,12 +968,61 @@ var RADIUS_UTILITIES = [
968
968
  "rounded-bl"
969
969
  ];
970
970
  var STATE_VARIANTS = ["hover", "focus-visible", "focus", "active", "dark"];
971
+ var CONTAINER_LAYOUT_UTILITIES = [
972
+ "grid-cols",
973
+ "gap",
974
+ "p",
975
+ "px",
976
+ "py",
977
+ "pt",
978
+ "pr",
979
+ "pb",
980
+ "pl",
981
+ "h",
982
+ "w",
983
+ "max-w",
984
+ "flex-row",
985
+ "flex-col",
986
+ "flex-col-reverse",
987
+ "flex-wrap",
988
+ "items-center",
989
+ "justify-end",
990
+ "justify-center",
991
+ "justify-between",
992
+ "text-left",
993
+ "text-center",
994
+ "text-right",
995
+ "space-x",
996
+ "space-y",
997
+ "mt",
998
+ "rounded",
999
+ "rounded-sm",
1000
+ "rounded-md",
1001
+ "rounded-lg"
1002
+ ];
1003
+ function extractThemeBlocks(css) {
1004
+ const blocks = [];
1005
+ const re = /@theme\s*(?:inline\s*)?\{/g;
1006
+ let match;
1007
+ while ((match = re.exec(css)) !== null) {
1008
+ let depth = 1;
1009
+ const start = match.index + match[0].length;
1010
+ for (let i = start; i < css.length; i++) {
1011
+ if (css[i] === "{") depth++;
1012
+ if (css[i] === "}") {
1013
+ depth--;
1014
+ if (depth === 0) {
1015
+ blocks.push(css.slice(start, i));
1016
+ break;
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ return blocks;
1022
+ }
971
1023
  function deriveCandidates(themeCSS) {
972
1024
  const themeVarNames = [];
973
- const themeBlockRe = /@theme\s*(?:inline\s*)?\{([^}]*)\}/gs;
974
- let blockMatch;
975
- while ((blockMatch = themeBlockRe.exec(themeCSS)) !== null) {
976
- const block = blockMatch[1] ?? "";
1025
+ for (const block of extractThemeBlocks(themeCSS)) {
977
1026
  const varRe = /--([a-z][a-z0-9-]*)\s*:/g;
978
1027
  let varMatch;
979
1028
  while ((varMatch = varRe.exec(block)) !== null) {
@@ -1009,6 +1058,15 @@ function deriveCandidates(themeCSS) {
1009
1058
  candidates.add(`${variant}:${c4}`);
1010
1059
  }
1011
1060
  }
1061
+ const containerSizes = themeVarNames.filter((n2) => n2.startsWith("container-")).map((n2) => n2.slice(10));
1062
+ const layoutCandidates = base.filter(
1063
+ (c4) => CONTAINER_LAYOUT_UTILITIES.some((u) => c4 === u || c4.startsWith(`${u}-`))
1064
+ );
1065
+ for (const size of containerSizes) {
1066
+ for (const c4 of layoutCandidates) {
1067
+ candidates.add(`@${size}:${c4}`);
1068
+ }
1069
+ }
1012
1070
  return [...candidates];
1013
1071
  }
1014
1072
  async function registryToDocumentation(registry2, options = {}) {
@@ -22531,42 +22589,48 @@ var DEFAULT_SHADOW_DEFINITIONS = {
22531
22589
  };
22532
22590
  var DEFAULT_DURATION_DEFINITIONS = {
22533
22591
  instant: {
22534
- ms: 0,
22592
+ range: [0, 0],
22593
+ default: 0,
22535
22594
  band: "",
22536
22595
  meaning: "No perceptible transition. Cursor changes, text selection, badge counts. Below all perception -- there is nothing to track, so nothing is communicated.",
22537
22596
  contexts: ["disabled-motion", "prefers-reduced-motion", "cursor", "badge-count"],
22538
22597
  motionIntent: "transition"
22539
22598
  },
22540
22599
  micro: {
22541
- ms: 100,
22600
+ range: [50, 120],
22601
+ default: 100,
22542
22602
  band: "at the instantaneous threshold (Nielsen 0.1s)",
22543
22603
  meaning: "Immediate but visible. Focus rings and press feedback. At the instantaneous threshold -- acknowledgment that input landed, not communication of a change.",
22544
22604
  contexts: ["focus", "press", "micro-feedback"],
22545
22605
  motionIntent: "transition"
22546
22606
  },
22547
22607
  fast: {
22548
- ms: 150,
22608
+ range: [120, 200],
22609
+ default: 150,
22549
22610
  band: "below the communicative window",
22550
22611
  meaning: "Hover states. The cursor is already there, so the response must match its speed. Below the communicative window -- acknowledgment, not communication.",
22551
22612
  contexts: ["hover", "micro-feedback"],
22552
22613
  motionIntent: "transition"
22553
22614
  },
22554
22615
  moderate: {
22555
- ms: 250,
22616
+ range: [200, 300],
22617
+ default: 200,
22556
22618
  band: "communicative (~200-300ms)",
22557
22619
  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.",
22558
22620
  contexts: ["dropdowns", "tab-switches", "small-reveals"],
22559
22621
  motionIntent: "transition"
22560
22622
  },
22561
22623
  normal: {
22562
- ms: 350,
22624
+ range: [300, 400],
22625
+ default: 300,
22563
22626
  band: "communicative, larger movement",
22564
22627
  meaning: "The workhorse -- modal entrances, toggles, standard state transitions. The communicative window for larger movement.",
22565
22628
  contexts: ["modals", "toggles", "state-changes"],
22566
22629
  motionIntent: "enter"
22567
22630
  },
22568
22631
  slow: {
22569
- ms: 500,
22632
+ range: [400, 500],
22633
+ default: 400,
22570
22634
  band: "at the sluggish boundary",
22571
22635
  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.",
22572
22636
  contexts: ["sheets", "page-transitions", "large-spatial-movement"],
@@ -22575,10 +22639,10 @@ var DEFAULT_DURATION_DEFINITIONS = {
22575
22639
  };
22576
22640
  var DEFAULT_EASING_DEFINITIONS = {
22577
22641
  standard: {
22578
- curve: [0.25, 0.1, 0.25, 1],
22579
- meaning: "Precision -- arrives exactly where it should, engineered rather than thrown. Decelerates into its final position. General-purpose state transitions and hover.",
22642
+ curve: [0.4, 0, 0.2, 1],
22643
+ meaning: "Precision -- a responsive start that decelerates into place, engineered rather than thrown. The general-purpose workhorse for state transitions and hover: the fast start matches a cursor already on target, where a symmetric ease would drag.",
22580
22644
  contexts: ["state-changes", "hover", "general-purpose"],
22581
- css: "cubic-bezier(0.25, 0.1, 0.25, 1)"
22645
+ css: "cubic-bezier(0.4, 0, 0.2, 1)"
22582
22646
  },
22583
22647
  enter: {
22584
22648
  curve: [0, 0, 0.2, 1],
@@ -22611,6 +22675,252 @@ var DEFAULT_EASING_DEFINITIONS = {
22611
22675
  css: "cubic-bezier(0.2, 0.8, 0.2, 1)"
22612
22676
  }
22613
22677
  };
22678
+ var DEFAULT_KEYFRAME_DEFINITIONS = {
22679
+ "fade-in": {
22680
+ css: () => "from { opacity: 0; } to { opacity: 1; }",
22681
+ meaning: "Fade from transparent to opaque",
22682
+ contexts: ["enter", "appear", "show"]
22683
+ },
22684
+ "fade-out": {
22685
+ css: () => "from { opacity: 1; } to { opacity: 0; }",
22686
+ meaning: "Fade from opaque to transparent",
22687
+ contexts: ["exit", "disappear", "hide"]
22688
+ },
22689
+ "slide-in-from-top": {
22690
+ css: () => "from { transform: translateY(-100%); } to { transform: translateY(0); }",
22691
+ meaning: "Slide in from above",
22692
+ contexts: ["dropdown", "notification", "toast"]
22693
+ },
22694
+ "slide-in-from-bottom": {
22695
+ css: () => "from { transform: translateY(100%); } to { transform: translateY(0); }",
22696
+ meaning: "Slide in from below",
22697
+ contexts: ["sheet", "drawer", "mobile-menu"]
22698
+ },
22699
+ "slide-in-from-left": {
22700
+ css: () => "from { transform: translateX(-100%); } to { transform: translateX(0); }",
22701
+ meaning: "Slide in from left",
22702
+ contexts: ["sidebar", "panel", "drawer"]
22703
+ },
22704
+ "slide-in-from-right": {
22705
+ css: () => "from { transform: translateX(100%); } to { transform: translateX(0); }",
22706
+ meaning: "Slide in from right",
22707
+ contexts: ["sidebar", "panel", "drawer"]
22708
+ },
22709
+ "slide-out-to-top": {
22710
+ css: () => "from { transform: translateY(0); } to { transform: translateY(-100%); }",
22711
+ meaning: "Slide out upward",
22712
+ contexts: ["dropdown-exit", "notification-dismiss"]
22713
+ },
22714
+ "slide-out-to-bottom": {
22715
+ css: () => "from { transform: translateY(0); } to { transform: translateY(100%); }",
22716
+ meaning: "Slide out downward",
22717
+ contexts: ["sheet-exit", "drawer-close"]
22718
+ },
22719
+ "slide-out-to-left": {
22720
+ css: () => "from { transform: translateX(0); } to { transform: translateX(-100%); }",
22721
+ meaning: "Slide out to left",
22722
+ contexts: ["sidebar-close", "panel-exit"]
22723
+ },
22724
+ "slide-out-to-right": {
22725
+ css: () => "from { transform: translateX(0); } to { transform: translateX(100%); }",
22726
+ meaning: "Slide out to right",
22727
+ contexts: ["sidebar-close", "panel-exit"]
22728
+ },
22729
+ "scale-in": {
22730
+ css: (ctx) => `from { transform: scale(${ctx.scaleStart}); opacity: 0; } to { transform: scale(1); opacity: 1; }`,
22731
+ meaning: "Scale up while fading in",
22732
+ contexts: ["modal", "popover", "dialog"]
22733
+ },
22734
+ "scale-out": {
22735
+ css: (ctx) => `from { transform: scale(1); opacity: 1; } to { transform: scale(${ctx.scaleStart}); opacity: 0; }`,
22736
+ meaning: "Scale down while fading out",
22737
+ contexts: ["modal-exit", "popover-close"]
22738
+ },
22739
+ spin: {
22740
+ css: () => "from { transform: rotate(0deg); } to { transform: rotate(360deg); }",
22741
+ meaning: "Continuous rotation",
22742
+ contexts: ["loading", "spinner", "refresh"]
22743
+ },
22744
+ ping: {
22745
+ css: (ctx) => `75%, 100% { transform: scale(${ctx.pingScale}); opacity: 0; }`,
22746
+ meaning: "Expanding pulse that fades out",
22747
+ contexts: ["notification-badge", "attention", "pulse"]
22748
+ },
22749
+ pulse: {
22750
+ css: (ctx) => `0%, 100% { opacity: 1; } 50% { opacity: ${ctx.pulseOpacity}; }`,
22751
+ meaning: "Gentle opacity pulse",
22752
+ contexts: ["skeleton", "loading-placeholder"]
22753
+ },
22754
+ bounce: {
22755
+ // Inline beziers retained deliberately -- see the provenance note above.
22756
+ css: (ctx) => `0%, 100% { transform: translateY(-${ctx.bouncePercent}%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); } 50% { transform: translateY(0); animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }`,
22757
+ meaning: "Bouncing motion",
22758
+ contexts: ["attention", "scroll-indicator"]
22759
+ },
22760
+ "caret-blink": {
22761
+ css: () => "0%, 70%, 100% { opacity: 1; } 20%, 50% { opacity: 0; }",
22762
+ meaning: "Text cursor blinking",
22763
+ contexts: ["input-caret", "text-cursor"]
22764
+ }
22765
+ };
22766
+ var DEFAULT_ANIMATION_DEFINITIONS = {
22767
+ "fade-in": {
22768
+ keyframe: "fade-in",
22769
+ duration: { tier: "fast" },
22770
+ curve: "enter",
22771
+ meaning: "Fade in animation",
22772
+ contexts: ["enter", "appear"]
22773
+ },
22774
+ "fade-out": {
22775
+ keyframe: "fade-out",
22776
+ duration: { tier: "fast" },
22777
+ curve: "exit",
22778
+ meaning: "Fade out animation",
22779
+ contexts: ["exit", "disappear"]
22780
+ },
22781
+ "slide-in-from-top": {
22782
+ keyframe: "slide-in-from-top",
22783
+ duration: { tier: "normal" },
22784
+ curve: "enter",
22785
+ meaning: "Slide in from top",
22786
+ contexts: ["dropdown", "notification"]
22787
+ },
22788
+ "slide-in-from-bottom": {
22789
+ keyframe: "slide-in-from-bottom",
22790
+ duration: { tier: "normal" },
22791
+ curve: "enter",
22792
+ meaning: "Slide in from bottom",
22793
+ contexts: ["sheet", "drawer"]
22794
+ },
22795
+ "slide-in-from-left": {
22796
+ keyframe: "slide-in-from-left",
22797
+ duration: { tier: "normal" },
22798
+ curve: "enter",
22799
+ meaning: "Slide in from left",
22800
+ contexts: ["sidebar", "panel"]
22801
+ },
22802
+ "slide-in-from-right": {
22803
+ keyframe: "slide-in-from-right",
22804
+ duration: { tier: "normal" },
22805
+ curve: "enter",
22806
+ meaning: "Slide in from right",
22807
+ contexts: ["sidebar", "panel"]
22808
+ },
22809
+ "slide-out-to-top": {
22810
+ keyframe: "slide-out-to-top",
22811
+ duration: { tier: "fast" },
22812
+ curve: "exit",
22813
+ meaning: "Slide out to top",
22814
+ contexts: ["dropdown-exit"]
22815
+ },
22816
+ "slide-out-to-bottom": {
22817
+ keyframe: "slide-out-to-bottom",
22818
+ duration: { tier: "fast" },
22819
+ curve: "exit",
22820
+ meaning: "Slide out to bottom",
22821
+ contexts: ["sheet-exit"]
22822
+ },
22823
+ "slide-out-to-left": {
22824
+ keyframe: "slide-out-to-left",
22825
+ duration: { tier: "fast" },
22826
+ curve: "exit",
22827
+ meaning: "Slide out to left",
22828
+ contexts: ["sidebar-close"]
22829
+ },
22830
+ "slide-out-to-right": {
22831
+ keyframe: "slide-out-to-right",
22832
+ duration: { tier: "fast" },
22833
+ curve: "exit",
22834
+ meaning: "Slide out to right",
22835
+ contexts: ["sidebar-close"]
22836
+ },
22837
+ "scale-in": {
22838
+ keyframe: "scale-in",
22839
+ duration: { tier: "normal" },
22840
+ curve: "spring-snappy",
22841
+ meaning: "Scale in with spring",
22842
+ contexts: ["modal", "popover"]
22843
+ },
22844
+ "scale-out": {
22845
+ keyframe: "scale-out",
22846
+ duration: { tier: "fast" },
22847
+ curve: "exit",
22848
+ meaning: "Scale out",
22849
+ contexts: ["modal-exit"]
22850
+ },
22851
+ spin: {
22852
+ keyframe: "spin",
22853
+ duration: { loopPeriod: "1s" },
22854
+ curve: "linear",
22855
+ iterations: "infinite",
22856
+ meaning: "Continuous spin",
22857
+ contexts: ["loading", "spinner"]
22858
+ },
22859
+ ping: {
22860
+ keyframe: "ping",
22861
+ duration: { loopPeriod: "1s" },
22862
+ curve: "enter",
22863
+ iterations: "infinite",
22864
+ meaning: "Pinging pulse",
22865
+ contexts: ["notification"]
22866
+ },
22867
+ pulse: {
22868
+ keyframe: "pulse",
22869
+ duration: { loopPeriod: "2s" },
22870
+ curve: "standard",
22871
+ iterations: "infinite",
22872
+ meaning: "Gentle pulse",
22873
+ contexts: ["skeleton", "loading"]
22874
+ },
22875
+ bounce: {
22876
+ keyframe: "bounce",
22877
+ duration: { loopPeriod: "1s" },
22878
+ curve: "standard",
22879
+ iterations: "infinite",
22880
+ meaning: "Bouncing",
22881
+ contexts: ["attention"]
22882
+ },
22883
+ "caret-blink": {
22884
+ keyframe: "caret-blink",
22885
+ duration: { loopPeriod: "1.25s" },
22886
+ curve: "enter",
22887
+ iterations: "infinite",
22888
+ meaning: "Caret blinking",
22889
+ contexts: ["input"]
22890
+ }
22891
+ };
22892
+ var DEFAULT_MOTION_COMPOSITE_PRESETS = {
22893
+ "motion-fade-in": {
22894
+ durationTier: "fast",
22895
+ curve: "enter",
22896
+ meaning: "Fade in animation preset",
22897
+ contexts: ["fade-in", "appear"]
22898
+ },
22899
+ "motion-fade-out": {
22900
+ durationTier: "fast",
22901
+ curve: "exit",
22902
+ meaning: "Fade out animation preset",
22903
+ contexts: ["fade-out", "disappear"]
22904
+ },
22905
+ "motion-slide-in": {
22906
+ durationTier: "normal",
22907
+ curve: "enter",
22908
+ meaning: "Slide in animation preset",
22909
+ contexts: ["slide-in", "panel-enter", "modal-enter"]
22910
+ },
22911
+ "motion-slide-out": {
22912
+ durationTier: "fast",
22913
+ curve: "exit",
22914
+ meaning: "Slide out animation preset",
22915
+ contexts: ["slide-out", "panel-exit", "modal-exit"]
22916
+ },
22917
+ "motion-scale-in": {
22918
+ durationTier: "normal",
22919
+ curve: "spring-snappy",
22920
+ meaning: "Scale in with spring animation",
22921
+ contexts: ["pop-in", "button-press", "emphasis"]
22922
+ }
22923
+ };
22614
22924
  var DEFAULT_MOTION_SEMANTIC_MAPPINGS = {
22615
22925
  hover: {
22616
22926
  properties: ["color", "background-color", "border-color"],
@@ -22694,11 +23004,11 @@ var DEFAULT_MOTION_SEMANTIC_MAPPINGS = {
22694
23004
  },
22695
23005
  "sheet-in": {
22696
23006
  properties: ["transform"],
22697
- durationTier: "slow",
23007
+ durationTier: "normal",
22698
23008
  curve: "spring-smooth",
22699
23009
  reducedMotion: { properties: ["opacity"], ms: 250 },
22700
23010
  category: "enter",
22701
- 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.",
23011
+ sizeReasoning: "A sheet is a large spatial movement -- normal tier with the physical settle of a smooth spring, because the user must track it into place. Reduced motion becomes a cross-fade.",
22702
23012
  meaning: "Sheet/drawer entrance.",
22703
23013
  contexts: ["sheet", "drawer", "side-panel"]
22704
23014
  },
@@ -22734,11 +23044,11 @@ var DEFAULT_MOTION_SEMANTIC_MAPPINGS = {
22734
23044
  },
22735
23045
  page: {
22736
23046
  properties: ["opacity", "transform"],
22737
- durationTier: "slow",
23047
+ durationTier: "normal",
22738
23048
  curve: "spring-smooth",
22739
23049
  reducedMotion: { properties: ["opacity"], ms: 200 },
22740
23050
  category: "enter",
22741
- sizeReasoning: "A whole-view transition -- slow tier with the physical settle of a smooth spring, because the user reorients across the largest possible distance.",
23051
+ sizeReasoning: "A whole-view transition -- normal tier with the physical settle of a smooth spring, because the user reorients across a large distance.",
22742
23052
  meaning: "Page/route transition.",
22743
23053
  contexts: ["page-transition", "route-change", "view-switch"]
22744
23054
  }
@@ -25365,14 +25675,7 @@ function tryParseUnit(cssValue, registry2 = DEFAULT_UNITS) {
25365
25675
  }
25366
25676
 
25367
25677
  // ../design-tokens/src/generators/motion.ts
25368
- var LEGACY_EASING_REMAP = {
25369
- linear: "linear",
25370
- "ease-out": "enter",
25371
- "ease-in": "exit",
25372
- "ease-in-out": "standard",
25373
- spring: "spring-snappy"
25374
- };
25375
- function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, semanticMappings) {
25678
+ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, semanticMappings, keyframeDefs, animationDefs, compositePresets) {
25376
25679
  const tokens = [];
25377
25680
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
25378
25681
  const { baseTransitionDuration, progressionRatio } = config2;
@@ -25387,22 +25690,26 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, sema
25387
25690
  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.",
25388
25691
  usageContext: ["calculation-reference", "delay-base"],
25389
25692
  progressionSystem: progressionRatio,
25390
- description: `Base duration (${baseTransitionDuration}ms). Delay tokens use ${progressionRatio} progression (ratio ${ratioVal}); duration tiers are perceptually derived literals.`,
25693
+ description: `Base duration (${baseTransitionDuration}ms). Delay tokens use ${progressionRatio} progression (ratio ${ratioVal}); duration tiers are perceptual RANGES a designer sets within and do not derive from this base.`,
25391
25694
  generatedAt: timestamp,
25392
25695
  containerQueryAware: false,
25393
25696
  reducedMotionAware: true,
25394
25697
  userOverride: null,
25395
25698
  usagePatterns: {
25396
25699
  do: ["Reference as the delay-progression base"],
25397
- never: ["Assume the perceptual duration tiers derive from this"]
25700
+ never: [
25701
+ "Assume the perceptual duration tiers derive from this -- they are ranges a designer sets within, bounded by perception, not computed from this base"
25702
+ ]
25398
25703
  }
25399
25704
  });
25400
25705
  for (const scale2 of MOTION_DURATION_SCALE) {
25401
25706
  const def = durationDefs[scale2];
25402
25707
  if (!def) continue;
25403
25708
  const scaleIndex = MOTION_DURATION_SCALE.indexOf(scale2);
25404
- const durationMs = def.ms;
25709
+ const durationMs = def.default;
25710
+ const [rangeMin, rangeMax] = def.range;
25405
25711
  const bandNote = def.band ? ` Band: ${def.band}.` : "";
25712
+ const rangeNote = rangeMin === rangeMax ? " Fixed." : ` Range: ${rangeMin}-${rangeMax}ms.`;
25406
25713
  tokens.push({
25407
25714
  name: `motion-duration-${scale2}`,
25408
25715
  value: `${durationMs}ms`,
@@ -25413,9 +25720,9 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, sema
25413
25720
  scalePosition: scaleIndex,
25414
25721
  motionIntent: def.motionIntent,
25415
25722
  motionDuration: durationMs,
25416
- mathRelationship: def.band ? `${durationMs}ms (perceptual: ${def.band})` : `${durationMs}ms`,
25723
+ mathRelationship: def.band ? `${durationMs}ms within ${rangeMin}-${rangeMax}ms (perceptual: ${def.band})` : `${durationMs}ms (fixed)`,
25417
25724
  dependsOn: [],
25418
- description: `Duration ${scale2}: ${durationMs}ms.${bandNote} ${def.meaning}`,
25725
+ description: `Duration ${scale2}: ${durationMs}ms.${rangeNote}${bandNote} ${def.meaning}`,
25419
25726
  generatedAt: timestamp,
25420
25727
  containerQueryAware: false,
25421
25728
  reducedMotionAware: true,
@@ -25484,384 +25791,79 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, sema
25484
25791
  const pingScale = Math.round(ratioValue2 ** 3 * 10) / 10;
25485
25792
  const pulseOpacity = Math.round(1 / ratioValue2 ** 4 * 100) / 100;
25486
25793
  const bouncePercent = Math.round(100 / ratioValue2 ** 6);
25487
- const keyframes = [
25488
- {
25489
- name: "fade-in",
25490
- css: "from { opacity: 0; } to { opacity: 1; }",
25491
- meaning: "Fade from transparent to opaque",
25492
- contexts: ["enter", "appear", "show"]
25493
- },
25494
- {
25495
- name: "fade-out",
25496
- css: "from { opacity: 1; } to { opacity: 0; }",
25497
- meaning: "Fade from opaque to transparent",
25498
- contexts: ["exit", "disappear", "hide"]
25499
- },
25500
- {
25501
- name: "slide-in-from-top",
25502
- css: "from { transform: translateY(-100%); } to { transform: translateY(0); }",
25503
- meaning: "Slide in from above",
25504
- contexts: ["dropdown", "notification", "toast"]
25505
- },
25506
- {
25507
- name: "slide-in-from-bottom",
25508
- css: "from { transform: translateY(100%); } to { transform: translateY(0); }",
25509
- meaning: "Slide in from below",
25510
- contexts: ["sheet", "drawer", "mobile-menu"]
25511
- },
25512
- {
25513
- name: "slide-in-from-left",
25514
- css: "from { transform: translateX(-100%); } to { transform: translateX(0); }",
25515
- meaning: "Slide in from left",
25516
- contexts: ["sidebar", "panel", "drawer"]
25517
- },
25518
- {
25519
- name: "slide-in-from-right",
25520
- css: "from { transform: translateX(100%); } to { transform: translateX(0); }",
25521
- meaning: "Slide in from right",
25522
- contexts: ["sidebar", "panel", "drawer"]
25523
- },
25524
- {
25525
- name: "slide-out-to-top",
25526
- css: "from { transform: translateY(0); } to { transform: translateY(-100%); }",
25527
- meaning: "Slide out upward",
25528
- contexts: ["dropdown-exit", "notification-dismiss"]
25529
- },
25530
- {
25531
- name: "slide-out-to-bottom",
25532
- css: "from { transform: translateY(0); } to { transform: translateY(100%); }",
25533
- meaning: "Slide out downward",
25534
- contexts: ["sheet-exit", "drawer-close"]
25535
- },
25536
- {
25537
- name: "slide-out-to-left",
25538
- css: "from { transform: translateX(0); } to { transform: translateX(-100%); }",
25539
- meaning: "Slide out to left",
25540
- contexts: ["sidebar-close", "panel-exit"]
25541
- },
25542
- {
25543
- name: "slide-out-to-right",
25544
- css: "from { transform: translateX(0); } to { transform: translateX(100%); }",
25545
- meaning: "Slide out to right",
25546
- contexts: ["sidebar-close", "panel-exit"]
25547
- },
25548
- {
25549
- name: "scale-in",
25550
- css: `from { transform: scale(${scaleStart}); opacity: 0; } to { transform: scale(1); opacity: 1; }`,
25551
- meaning: "Scale up while fading in",
25552
- contexts: ["modal", "popover", "dialog"]
25553
- },
25554
- {
25555
- name: "scale-out",
25556
- css: `from { transform: scale(1); opacity: 1; } to { transform: scale(${scaleStart}); opacity: 0; }`,
25557
- meaning: "Scale down while fading out",
25558
- contexts: ["modal-exit", "popover-close"]
25559
- },
25560
- {
25561
- name: "spin",
25562
- css: "from { transform: rotate(0deg); } to { transform: rotate(360deg); }",
25563
- meaning: "Continuous rotation",
25564
- contexts: ["loading", "spinner", "refresh"]
25565
- },
25566
- {
25567
- name: "ping",
25568
- css: `75%, 100% { transform: scale(${pingScale}); opacity: 0; }`,
25569
- meaning: "Expanding pulse that fades out",
25570
- contexts: ["notification-badge", "attention", "pulse"]
25571
- },
25572
- {
25573
- name: "pulse",
25574
- css: `0%, 100% { opacity: 1; } 50% { opacity: ${pulseOpacity}; }`,
25575
- meaning: "Gentle opacity pulse",
25576
- contexts: ["skeleton", "loading-placeholder"]
25577
- },
25578
- {
25579
- name: "bounce",
25580
- css: `0%, 100% { transform: translateY(-${bouncePercent}%); animation-timing-function: cubic-bezier(0.8, 0, 1, 1); } 50% { transform: translateY(0); animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }`,
25581
- meaning: "Bouncing motion",
25582
- contexts: ["attention", "scroll-indicator"]
25583
- },
25584
- {
25585
- name: "accordion-down",
25586
- css: "from { height: 0; } to { height: var(--radix-accordion-content-height); }",
25587
- meaning: "Expand accordion content",
25588
- contexts: ["accordion", "collapsible", "expand"]
25589
- },
25590
- {
25591
- name: "accordion-up",
25592
- css: "from { height: var(--radix-accordion-content-height); } to { height: 0; }",
25593
- meaning: "Collapse accordion content",
25594
- contexts: ["accordion", "collapsible", "collapse"]
25595
- },
25596
- {
25597
- name: "caret-blink",
25598
- css: "0%, 70%, 100% { opacity: 1; } 20%, 50% { opacity: 0; }",
25599
- meaning: "Text cursor blinking",
25600
- contexts: ["input-caret", "text-cursor"]
25601
- }
25602
- ];
25603
- for (const kf of keyframes) {
25794
+ const keyframeContext = {
25795
+ scaleStart,
25796
+ pingScale,
25797
+ pulseOpacity,
25798
+ bouncePercent
25799
+ };
25800
+ for (const [name, kf] of Object.entries(keyframeDefs)) {
25604
25801
  tokens.push({
25605
- name: `motion-keyframe-${kf.name}`,
25606
- value: kf.css,
25802
+ name: `motion-keyframe-${name}`,
25803
+ value: kf.css(keyframeContext),
25607
25804
  category: "motion",
25608
25805
  namespace: "motion",
25609
25806
  semanticMeaning: kf.meaning,
25610
25807
  usageContext: kf.contexts,
25611
- keyframeName: kf.name,
25612
- description: `Keyframe ${kf.name}: ${kf.meaning}`,
25808
+ keyframeName: name,
25809
+ description: `Keyframe ${name}: ${kf.meaning}`,
25613
25810
  generatedAt: timestamp,
25614
25811
  containerQueryAware: false,
25615
25812
  reducedMotionAware: true,
25616
25813
  userOverride: null
25617
25814
  });
25618
25815
  }
25619
- const animations = [
25620
- {
25621
- name: "fade-in",
25622
- keyframe: "fade-in",
25623
- duration: "fast",
25624
- easing: "ease-out",
25625
- meaning: "Fade in animation",
25626
- contexts: ["enter", "appear"]
25627
- },
25628
- {
25629
- name: "fade-out",
25630
- keyframe: "fade-out",
25631
- duration: "fast",
25632
- easing: "ease-in",
25633
- meaning: "Fade out animation",
25634
- contexts: ["exit", "disappear"]
25635
- },
25636
- {
25637
- name: "slide-in-from-top",
25638
- keyframe: "slide-in-from-top",
25639
- duration: "normal",
25640
- easing: "ease-out",
25641
- meaning: "Slide in from top",
25642
- contexts: ["dropdown", "notification"]
25643
- },
25644
- {
25645
- name: "slide-in-from-bottom",
25646
- keyframe: "slide-in-from-bottom",
25647
- duration: "normal",
25648
- easing: "ease-out",
25649
- meaning: "Slide in from bottom",
25650
- contexts: ["sheet", "drawer"]
25651
- },
25652
- {
25653
- name: "slide-in-from-left",
25654
- keyframe: "slide-in-from-left",
25655
- duration: "normal",
25656
- easing: "ease-out",
25657
- meaning: "Slide in from left",
25658
- contexts: ["sidebar", "panel"]
25659
- },
25660
- {
25661
- name: "slide-in-from-right",
25662
- keyframe: "slide-in-from-right",
25663
- duration: "normal",
25664
- easing: "ease-out",
25665
- meaning: "Slide in from right",
25666
- contexts: ["sidebar", "panel"]
25667
- },
25668
- {
25669
- name: "slide-out-to-top",
25670
- keyframe: "slide-out-to-top",
25671
- duration: "fast",
25672
- easing: "ease-in",
25673
- meaning: "Slide out to top",
25674
- contexts: ["dropdown-exit"]
25675
- },
25676
- {
25677
- name: "slide-out-to-bottom",
25678
- keyframe: "slide-out-to-bottom",
25679
- duration: "fast",
25680
- easing: "ease-in",
25681
- meaning: "Slide out to bottom",
25682
- contexts: ["sheet-exit"]
25683
- },
25684
- {
25685
- name: "slide-out-to-left",
25686
- keyframe: "slide-out-to-left",
25687
- duration: "fast",
25688
- easing: "ease-in",
25689
- meaning: "Slide out to left",
25690
- contexts: ["sidebar-close"]
25691
- },
25692
- {
25693
- name: "slide-out-to-right",
25694
- keyframe: "slide-out-to-right",
25695
- duration: "fast",
25696
- easing: "ease-in",
25697
- meaning: "Slide out to right",
25698
- contexts: ["sidebar-close"]
25699
- },
25700
- {
25701
- name: "scale-in",
25702
- keyframe: "scale-in",
25703
- duration: "normal",
25704
- easing: "spring",
25705
- meaning: "Scale in with spring",
25706
- contexts: ["modal", "popover"]
25707
- },
25708
- {
25709
- name: "scale-out",
25710
- keyframe: "scale-out",
25711
- duration: "fast",
25712
- easing: "ease-in",
25713
- meaning: "Scale out",
25714
- contexts: ["modal-exit"]
25715
- },
25716
- {
25717
- name: "spin",
25718
- keyframe: "spin",
25719
- duration: "1s",
25720
- easing: "linear",
25721
- iterations: "infinite",
25722
- meaning: "Continuous spin",
25723
- contexts: ["loading", "spinner"]
25724
- },
25725
- {
25726
- name: "ping",
25727
- keyframe: "ping",
25728
- duration: "1s",
25729
- easing: "ease-out",
25730
- iterations: "infinite",
25731
- meaning: "Pinging pulse",
25732
- contexts: ["notification"]
25733
- },
25734
- {
25735
- name: "pulse",
25736
- keyframe: "pulse",
25737
- duration: "2s",
25738
- easing: "ease-in-out",
25739
- iterations: "infinite",
25740
- meaning: "Gentle pulse",
25741
- contexts: ["skeleton", "loading"]
25742
- },
25743
- {
25744
- name: "bounce",
25745
- keyframe: "bounce",
25746
- duration: "1s",
25747
- easing: "ease-in-out",
25748
- iterations: "infinite",
25749
- meaning: "Bouncing",
25750
- contexts: ["attention"]
25751
- },
25752
- {
25753
- name: "accordion-down",
25754
- keyframe: "accordion-down",
25755
- duration: "normal",
25756
- easing: "ease-out",
25757
- meaning: "Accordion expand",
25758
- contexts: ["accordion", "collapsible"]
25759
- },
25760
- {
25761
- name: "accordion-up",
25762
- keyframe: "accordion-up",
25763
- duration: "normal",
25764
- easing: "ease-out",
25765
- meaning: "Accordion collapse",
25766
- contexts: ["accordion", "collapsible"]
25767
- },
25768
- {
25769
- name: "caret-blink",
25770
- keyframe: "caret-blink",
25771
- duration: "1.25s",
25772
- easing: "ease-out",
25773
- iterations: "infinite",
25774
- meaning: "Caret blinking",
25775
- contexts: ["input"]
25776
- }
25777
- ];
25778
- for (const anim of animations) {
25816
+ for (const [name, anim] of Object.entries(animationDefs)) {
25779
25817
  let durationValue;
25780
25818
  let durationRef;
25781
- if (anim.duration.endsWith("s") || anim.duration.endsWith("ms")) {
25782
- durationValue = anim.duration;
25783
- durationRef = anim.duration;
25819
+ let durationDependency;
25820
+ if ("loopPeriod" in anim.duration) {
25821
+ durationValue = anim.duration.loopPeriod;
25822
+ durationRef = anim.duration.loopPeriod;
25823
+ durationDependency = [];
25784
25824
  } else {
25785
- const durationDef = durationDefs[anim.duration];
25825
+ const durationDef = durationDefs[anim.duration.tier];
25786
25826
  if (!durationDef) continue;
25787
- durationValue = `${durationDef.ms}ms`;
25788
- durationRef = `var(--motion-duration-${anim.duration})`;
25827
+ durationValue = `${durationDef.default}ms`;
25828
+ durationRef = `var(--motion-duration-${anim.duration.tier})`;
25829
+ durationDependency = [`motion-duration-${anim.duration.tier}`];
25789
25830
  }
25790
- const easingKey = LEGACY_EASING_REMAP[anim.easing] ?? anim.easing;
25791
- const easingDef = easingDefs[easingKey];
25831
+ const easingDef = easingDefs[anim.curve];
25792
25832
  if (!easingDef) continue;
25793
- const easingRef = `var(--motion-easing-${easingKey})`;
25833
+ const easingRef = `var(--motion-easing-${anim.curve})`;
25794
25834
  const iterations = anim.iterations || "";
25795
25835
  const animValue = iterations ? `${anim.keyframe} ${durationRef} ${easingRef} ${iterations}` : `${anim.keyframe} ${durationRef} ${easingRef}`;
25796
25836
  tokens.push({
25797
- name: `motion-animation-${anim.name}`,
25837
+ name: `motion-animation-${name}`,
25798
25838
  value: animValue,
25799
25839
  category: "motion",
25800
25840
  namespace: "motion",
25801
25841
  semanticMeaning: anim.meaning,
25802
25842
  usageContext: anim.contexts,
25803
- animationName: anim.name,
25843
+ animationName: name,
25804
25844
  keyframeName: anim.keyframe,
25805
25845
  animationDuration: durationValue,
25806
25846
  animationEasing: easingDef.css,
25807
25847
  animationIterations: anim.iterations || "1",
25808
25848
  dependsOn: [
25809
25849
  `motion-keyframe-${anim.keyframe}`,
25810
- ...anim.duration.endsWith("s") || anim.duration.endsWith("ms") ? [] : [`motion-duration-${anim.duration}`],
25811
- `motion-easing-${easingKey}`
25850
+ ...durationDependency,
25851
+ `motion-easing-${anim.curve}`
25812
25852
  ],
25813
- description: `Animation ${anim.name}: ${anim.meaning}`,
25853
+ description: `Animation ${name}: ${anim.meaning}`,
25814
25854
  generatedAt: timestamp,
25815
25855
  containerQueryAware: false,
25816
25856
  reducedMotionAware: true,
25817
25857
  userOverride: null
25818
25858
  });
25819
25859
  }
25820
- const composites2 = [
25821
- {
25822
- name: "motion-fade-in",
25823
- duration: "fast",
25824
- easing: "ease-out",
25825
- meaning: "Fade in animation preset",
25826
- contexts: ["fade-in", "appear"]
25827
- },
25828
- {
25829
- name: "motion-fade-out",
25830
- duration: "fast",
25831
- easing: "ease-in",
25832
- meaning: "Fade out animation preset",
25833
- contexts: ["fade-out", "disappear"]
25834
- },
25835
- {
25836
- name: "motion-slide-in",
25837
- duration: "normal",
25838
- easing: "ease-out",
25839
- meaning: "Slide in animation preset",
25840
- contexts: ["slide-in", "panel-enter", "modal-enter"]
25841
- },
25842
- {
25843
- name: "motion-slide-out",
25844
- duration: "fast",
25845
- easing: "ease-in",
25846
- meaning: "Slide out animation preset",
25847
- contexts: ["slide-out", "panel-exit", "modal-exit"]
25848
- },
25849
- {
25850
- name: "motion-scale-in",
25851
- duration: "normal",
25852
- easing: "spring",
25853
- meaning: "Scale in with spring animation",
25854
- contexts: ["pop-in", "button-press", "emphasis"]
25855
- }
25856
- ];
25857
- for (const comp of composites2) {
25858
- const durationDef = durationDefs[comp.duration];
25859
- const easingKey = LEGACY_EASING_REMAP[comp.easing] ?? comp.easing;
25860
- const easingDef = easingDefs[easingKey];
25860
+ for (const [name, comp] of Object.entries(compositePresets)) {
25861
+ const durationDef = durationDefs[comp.durationTier];
25862
+ const easingDef = easingDefs[comp.curve];
25861
25863
  if (!durationDef || !easingDef) continue;
25862
- const durationMs = durationDef.ms;
25864
+ const durationMs = durationDef.default;
25863
25865
  tokens.push({
25864
- name: comp.name,
25866
+ name,
25865
25867
  value: `${durationMs}ms ${easingDef.css}`,
25866
25868
  category: "motion",
25867
25869
  namespace: "motion",
@@ -25869,9 +25871,9 @@ function generateMotionTokens(config2, durationDefs, easingDefs, delayDefs, sema
25869
25871
  usageContext: comp.contexts,
25870
25872
  motionDuration: durationMs,
25871
25873
  easingCurve: easingDef.curve,
25872
- easingName: easingKey,
25873
- dependsOn: [`motion-duration-${comp.duration}`, `motion-easing-${easingKey}`],
25874
- description: `${comp.meaning}. Combines ${comp.duration} duration with ${easingKey} easing.`,
25874
+ easingName: comp.curve,
25875
+ dependsOn: [`motion-duration-${comp.durationTier}`, `motion-easing-${comp.curve}`],
25876
+ description: `${comp.meaning}. Combines ${comp.durationTier} duration with ${comp.curve} easing.`,
25875
25877
  generatedAt: timestamp,
25876
25878
  containerQueryAware: false,
25877
25879
  reducedMotionAware: true,
@@ -26827,7 +26829,10 @@ function createGeneratorDefs(colorPaletteBases) {
26827
26829
  DEFAULT_DURATION_DEFINITIONS,
26828
26830
  DEFAULT_EASING_DEFINITIONS,
26829
26831
  DEFAULT_DELAY_DEFINITIONS,
26830
- DEFAULT_MOTION_SEMANTIC_MAPPINGS
26832
+ DEFAULT_MOTION_SEMANTIC_MAPPINGS,
26833
+ DEFAULT_KEYFRAME_DEFINITIONS,
26834
+ DEFAULT_ANIMATION_DEFINITIONS,
26835
+ DEFAULT_MOTION_COMPOSITE_PRESETS
26831
26836
  )
26832
26837
  },
26833
26838
  {
@@ -27076,7 +27081,7 @@ function extractShadcnRoot(css) {
27076
27081
  var THEME_BLOCK = /@theme(?:\s+inline)?\s*\{([^}]*)\}/g;
27077
27082
  var COMMENT = /\/\*[\s\S]*?\*\//g;
27078
27083
  var DECLARATION = /--([A-Za-z_-][\w-]*)\s*:\s*([^;]+);/g;
27079
- function extractThemeBlocks(css) {
27084
+ function extractThemeBlocks2(css) {
27080
27085
  const out = [];
27081
27086
  for (const match of css.matchAll(THEME_BLOCK)) {
27082
27087
  const body = (match[1] ?? "").replace(COMMENT, "");
@@ -27093,7 +27098,7 @@ function extractThemeBlocks(css) {
27093
27098
  // ../design-tokens/src/importers/bases.ts
27094
27099
  var LENGTH = /^(-?\d+(?:\.\d+)?)\s*(rem|px|em)$/;
27095
27100
  function detectBase(css, names, parse7) {
27096
- const decls = [...extractShadcnRoot(css), ...extractThemeBlocks(css)];
27101
+ const decls = [...extractShadcnRoot(css), ...extractThemeBlocks2(css)];
27097
27102
  let last2 = null;
27098
27103
  for (const decl of decls) {
27099
27104
  if (names.includes(decl.name)) last2 = decl.value.trim();
@@ -27318,7 +27323,7 @@ function detectFonts(css) {
27318
27323
  accept(family, quoteIfNeeded(family));
27319
27324
  }
27320
27325
  const rootDecls = extractShadcnRoot(css);
27321
- const themeDecls = extractThemeBlocks(css);
27326
+ const themeDecls = extractThemeBlocks2(css);
27322
27327
  for (const decl of [...rootDecls, ...themeDecls]) {
27323
27328
  if (!decl.name.startsWith("font-")) continue;
27324
27329
  const first = firstFamilyFromStack(decl.value);
@@ -29986,7 +29991,7 @@ async function init(options) {
29986
29991
  }
29987
29992
  }
29988
29993
  {
29989
- const themeDecls = extractThemeBlocks(sourceCss);
29994
+ const themeDecls = extractThemeBlocks2(sourceCss);
29990
29995
  if (themeDecls.length > 0) {
29991
29996
  const POSITION_SUFFIX = new RegExp(`^(.+)-(${SCALE_POSITIONS.join("|")})$`);
29992
29997
  const familySeeds = /* @__PURE__ */ new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rafters",
3
- "version": "0.0.76",
3
+ "version": "0.0.78",
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",