transitions-refine 0.3.1 → 0.3.3

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/demo.html +36 -17
  2. package/package.json +1 -1
package/demo.html CHANGED
@@ -346,7 +346,7 @@
346
346
  .tl-main { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
347
347
  .tl-inspector { flex: 0 0 280px; padding: 14px 16px 18px; display: flex; flex-direction: column;
348
348
  border-left: 1px solid var(--c-line); min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
349
- .tl-insp-title { font-size: 13px; font-weight: 500; line-height: 18px; color: #171717; margin-bottom: 12px; text-transform: capitalize; }
349
+ .tl-insp-title { font-size: 13px; font-weight: 500; line-height: 18px; color: #171717; margin-bottom: 10px; text-transform: capitalize; }
350
350
  .tl-insp-label { font-size: 12px; line-height: 18px; color: #737373; margin: 10px 0 6px; }
351
351
 
352
352
  /* ── tracks / ruler ── */
@@ -1076,23 +1076,32 @@
1076
1076
  function easingToCubic(v) { const p=kwMap.get(v); if(p)return p.cubic; const m=v.match(/cubic-bezier\(\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*,\s*(-?[\d.]+)\s*\)/); if(m)return[parseFloat(m[1]),parseFloat(m[2]),parseFloat(m[3]),parseFloat(m[4])]; return null; }
1077
1077
 
1078
1078
  // Easing dropdown library. `group` rows are non-selectable section headers.
1079
- // Motion tokens are the verbatim cubic-beziers shipped by the transitions.dev
1080
- // skill (_root.css); the "Common" set are the standard easings.net curves.
1079
+ // The "Motion tokens (transitions.dev)" set is verbatim from the transitions.dev
1080
+ // skill's Easings table (name, value and usage all match the skill); the
1081
+ // "Standard" set is the five native CSS timing-function keywords.
1081
1082
  const EASING_LIBRARY = [
1082
1083
  { group:"Motion tokens (transitions.dev)" },
1083
- { label:"Smooth out", value:"cubic-bezier(0.22, 1, 0.36, 1)", usage:"The transitions.dev default — dropdown, modal, panel, tabs, page slides, accordion." },
1084
- { label:"Standard close", value:"cubic-bezier(0.4, 0, 0.2, 1)", usage:"Material-style accelerate→decelerate. Used for badge close / calm exits." },
1085
- { label:"Pop overshoot", value:"cubic-bezier(0.34, 1.36, 0.64, 1)", usage:"Notification badge pop-in — a small overshoot past the target." },
1086
- { label:"Digit pop", value:"cubic-bezier(0.34, 1.45, 0.64, 1)", usage:"Number pop-in slightly springier overshoot for counting digits." },
1087
- { label:"Morph open", value:"cubic-bezier(0.34, 1.25, 0.64, 1)", usage:"Plus-to-menu morph open — gentle bouncy expand." },
1088
- { label:"Check bob", value:"cubic-bezier(0.34, 1.35, 0.64, 1)", usage:"Success check bobplayful settle on confirmation." },
1089
- { label:"Big overshoot", value:"cubic-bezier(0.34, 3.85, 0.64, 1)", usage:"Avatar group hover return — aggressive, spring-like overshoot." },
1084
+ { label:"Smooth ease out", value:"cubic-bezier(0.22, 1, 0.36, 1)", usage:"Modal / dropdown / panel open + close, page slide, resize, position change." },
1085
+ { label:"Ease in out", value:"ease-in-out", usage:"Icon swap, text swap, text reveal, skeleton reveal." },
1086
+ { label:"Ease out", value:"ease-out", usage:"Tooltip open / close." },
1087
+ { label:"Linear", value:"linear", usage:"Shimmer, skeleton pulse, spinner." },
1088
+ { label:"Bouncy overshoot", value:"cubic-bezier(0.34, 1.36, 0.64, 1)", usage:"Badge pop open — a small overshoot past the target." },
1089
+ { label:"Strong bouncy overshoot", value:"cubic-bezier(0.34, 3.85, 0.64, 1)", usage:"Bouncy hover-out (avatar return) aggressive, spring-like overshoot." },
1090
+ { group:"Standard" },
1091
+ { label:"ease", value:"ease", usage:"CSS default — gentle ease in, ease out." },
1092
+ { label:"ease-in", value:"ease-in", usage:"Accelerate from rest — slow start, fast finish." },
1093
+ { label:"ease-out", value:"ease-out", usage:"Decelerate to rest — fast start, slow finish." },
1094
+ { label:"ease-in-out", value:"ease-in-out", usage:"Accelerate then decelerate — symmetric." },
1095
+ { label:"linear", value:"linear", usage:"Constant speed — no acceleration." },
1090
1096
  { group:"Custom" },
1091
1097
  { label:"cubic-bezier(\u2026)", value:"__cubic" },
1092
1098
  { label:"custom", value:"__custom" },
1093
1099
  ];
1094
1100
  const normEase = s => (s||"").replace(/\s+/g,"");
1095
- const EASING_LABEL = new Map(EASING_LIBRARY.filter(o=>o.value&&o.value[0]!=="_").map(o=>[normEase(o.value),o.label]));
1101
+ // First occurrence wins, so a shared keyword (e.g. ease-out) shows its
1102
+ // semantic transitions.dev name rather than the bare Standard keyword.
1103
+ const EASING_LABEL = EASING_LIBRARY.filter(o=>o.value&&o.value[0]!=="_")
1104
+ .reduce((m,o)=>{const k=normEase(o.value);if(!m.has(k))m.set(k,o.label);return m;},new Map());
1096
1105
  function easingLabel(v){ return EASING_LABEL.get(normEase(v)) || null; }
1097
1106
 
1098
1107
  // Most-common predefined springs. tension/friction follow react-spring's
@@ -1943,6 +1952,9 @@
1943
1952
  const easeRef = useRef(null);
1944
1953
  const [easeOpen, setEaseOpen] = useState(false);
1945
1954
  const selLabel = easingLabel(easing) || (isCubic ? "cubic-bezier(\u2026)" : easing ? easing : "custom");
1955
+ // first selectable row whose value matches — so a keyword shared between the
1956
+ // transitions.dev and Standard groups only checks once (the first one).
1957
+ const selEaseIdx = EASING_LIBRARY.findIndex(o=>o.value&&o.value[0]!=="_"&&normEase(o.value)===normEase(easing));
1946
1958
  const pickEase = useCallback(v=>{
1947
1959
  if(v==="__cubic") setEasing(`cubic-bezier(${cb.join(", ")})`);
1948
1960
  else if(v==="__custom") setEasing("");
@@ -1996,9 +2008,9 @@
1996
2008
  width:Math.max(248,(easeRef.current&&easeRef.current.offsetWidth)||248),align:"left"},
1997
2009
  EASING_LIBRARY.map((o,i)=> o.group
1998
2010
  ? h("div",{key:"g"+i,className:"tl-menu-group"},o.group)
1999
- : h(MenuItem,{key:o.value,active:normEase(o.value)===normEase(easing)||(o.value===mode),
2011
+ : h(MenuItem,{key:"e"+i,active:selEaseIdx>=0?i===selEaseIdx:(o.value===mode),
2000
2012
  onClick:()=>pickEase(o.value),
2001
- right:(normEase(o.value)===normEase(easing))&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},
2013
+ right:(i===selEaseIdx)&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},
2002
2014
  h("span",{className:"tl-menu-text"},o.label),
2003
2015
  o.usage&&h("span",{className:"t-tt-wrap tl-menu-help",
2004
2016
  onClick:e=>e.stopPropagation(),onMouseDown:e=>e.stopPropagation()},
@@ -2466,8 +2478,10 @@
2466
2478
  setGroupScanState("scanning");
2467
2479
  // wait for the flat DOM scan to settle (count stable twice) so the agent
2468
2480
  // sees every transition, not a partial set discovered progressively.
2469
- let prev=-1,stable=0;
2470
- while(scanTokenRef.current===token){
2481
+ // Capped (~12s) so a page with no resolvable flat entries can never hang
2482
+ // the panel on "Grouping…" — it falls through to the empty-flat check below.
2483
+ let prev=-1,stable=0,iters=0;
2484
+ while(scanTokenRef.current===token&&iters++<40){
2471
2485
  const n=registry.getAll().filter(e=>e.kind!=="phase").length;
2472
2486
  if(n>0&&n===prev){if(++stable>=2)break;}else stable=0;
2473
2487
  prev=n;
@@ -2503,11 +2517,16 @@
2503
2517
  setGroupScanState("error");
2504
2518
  }catch(e){ setGroupScanState("error"); /* relay down → stay flat, retry next open */ }
2505
2519
  },[registry,GROUP_STORE_KEY,flatSig,readGroupCache]);
2506
- // manual "Rescan transitions" — drop the cache and force a fresh agent scan
2520
+ // manual "Rescan transitions" — drop the cache AND clear the in-memory
2521
+ // groups first. Once groups claim every DOM transition the snapshot has no
2522
+ // "flat" entries left, so the settle loop above would otherwise spin forever
2523
+ // waiting for a flat count that never arrives. Clearing groups re-surfaces
2524
+ // the flat entries the agent needs to re-group.
2507
2525
  const rescanTransitions=useCallback(()=>{
2508
2526
  try{localStorage.removeItem(GROUP_STORE_KEY);}catch{}
2527
+ registry.clearGroups();
2509
2528
  runGroupScan();
2510
- },[runGroupScan,GROUP_STORE_KEY]);
2529
+ },[runGroupScan,GROUP_STORE_KEY,registry]);
2511
2530
  // On mount, run the group resolver once. It waits for the flat scan to
2512
2531
  // settle, then either re-applies cached groups (when the content signature
2513
2532
  // matches — a pure cache read, no agent) or kicks off a fresh agent scan
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transitions-refine",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "Live, agent-driven Refine panel for CSS/Motion transitions — injects a timeline + Refine UI and runs transitions.dev suggestions via your coding agent.",
5
5
  "type": "module",
6
6
  "bin": {