transitions-refine 0.3.2 → 0.3.4

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 +98 -55
  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 ── */
@@ -415,14 +415,14 @@
415
415
  @media (prefers-reduced-motion: reduce) { .tl-col-resizer-line { transition: none; } }
416
416
 
417
417
  /* ── value field (slider + input) — exact Figma "Value slider and input" ── */
418
- .tl-field-wrap { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
419
- .tl-field { position: relative; flex: 1; min-width: 0; height: 36px; border-radius: 8px;
418
+ .tl-field-wrap { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
419
+ .tl-field { position: relative; flex: 1; min-width: 0; height: 32px; border-radius: 8px;
420
420
  background: var(--c-field-bg); transition: box-shadow 0.12s ease; }
421
421
  /* focused: dual inset ring (Figma Focused state) */
422
422
  .tl-field.is-editing { box-shadow: inset 0 0 0 1px rgba(0,0,0,0.14), inset 0 0 0 0.5px rgba(255,255,255,0.06); }
423
423
  /* inner slider fill — Figma button/tiny: soft drop shadow + inset ring give the
424
424
  "raised block" look (shadow 0 1px 3px @4%, hairline border, bottom 1px). */
425
- .tl-field-fill { position: absolute; left: 0; top: 0; bottom: 0; min-width: 36px; border-radius: 8px;
425
+ .tl-field-fill { position: absolute; left: 0; top: 0; bottom: 0; min-width: 32px; border-radius: 8px;
426
426
  background: var(--c-fill);
427
427
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.02), inset 0 -1px 0 0 rgba(0,0,0,0.08), inset 0 0 0 1px rgba(191,191,191,0.10), 0 1px 3px 0 rgba(0,0,0,0.06);
428
428
  pointer-events: none; transition: background 0.12s ease, opacity 0.12s ease; z-index: 1; }
@@ -439,13 +439,13 @@
439
439
  text-align: right; border: none; background: transparent; font: inherit; font-size: 13px; font-weight: 500;
440
440
  color: var(--c-text); outline: none; z-index: 4; font-variant-numeric: tabular-nums; }
441
441
  /* thumb at the right edge of the fill (Figma #767676 2×20px, inset 8px, hover 60% / drag 100%) */
442
- .tl-field-thumb { position: absolute; right: 8px; top: 8px; height: 20px; width: 2px;
442
+ .tl-field-thumb { position: absolute; right: 8px; top: 7px; height: 18px; width: 2px;
443
443
  background: var(--c-thumb); border-radius: 20px; opacity: 0; pointer-events: none;
444
444
  transition: opacity 0.12s ease; z-index: 3; }
445
445
  .tl-field:hover .tl-field-thumb { opacity: 0.6; }
446
446
  .tl-field.is-dragging .tl-field-thumb { opacity: 1; }
447
447
  .tl-field.is-editing .tl-field-thumb { opacity: 0; }
448
- .tl-field-chevron { flex: none; width: 36px; height: 36px; border-radius: 8px; display: flex;
448
+ .tl-field-chevron { flex: none; width: 32px; height: 32px; border-radius: 8px; display: flex;
449
449
  align-items: center; justify-content: center; border: none; background: var(--c-field-bg);
450
450
  color: var(--c-ruler); cursor: pointer; transition: background 0.12s ease, scale 0.12s ease; }
451
451
  .tl-field-chevron:hover { background: var(--c-sec-h); }
@@ -492,7 +492,7 @@
492
492
  }
493
493
  /* easing select trigger (custom dropdown) */
494
494
  /* select trigger — Logram design system (node 13064:2418): flat #f7f7f7 fill */
495
- .tl-select { display: flex; align-items: center; justify-content: space-between; width: 100%; height: 36px;
495
+ .tl-select { display: flex; align-items: center; justify-content: space-between; width: 100%; height: 32px;
496
496
  border: none; border-radius: 8px; background: #f7f7f7; padding: 6px 10px 6px 12px;
497
497
  font: inherit; font-size: 13px; font-weight: 500; line-height: 16px; color: #1b1b1b; cursor: pointer; text-align: left;
498
498
  transition: background 0.12s ease; }
@@ -520,35 +520,84 @@
520
520
  .tl-custom-input { height: 30px; border: none; border-radius: 6px; background: var(--c-field-bg); padding: 0 8px;
521
521
  font: inherit; font-size: 12px; font-family: monospace; color: var(--c-text); outline: none;
522
522
  box-shadow: inset 0 0 0 1px rgba(0,0,0,0.04); }
523
- .tl-bounce { background: #fff; border-radius: 8px; box-shadow: inset 0 0 0 1px var(--c-hairline);
524
- padding: 8px 10px; display: flex; flex-direction: column; gap: 6px; }
525
- .tl-bounce-title { font-size: 11px; color: var(--c-text-mut); font-weight: 600; }
526
- .tl-bounce-row { display: flex; align-items: center; gap: 8px; }
527
- .tl-bounce-row label { font-size: 11px; color: #737373; width: 54px; flex: none; }
528
- .tl-bounce-row input[type="range"] { flex: 1; height: 4px; -webkit-appearance: none; appearance: none;
529
- background: #e3e3e8; border-radius: 2px; outline: none; }
523
+ .tl-bounce { background: #fff; border-radius: 10px; box-shadow: inset 0 0 0 1px var(--c-hairline);
524
+ padding: 12px; display: flex; flex-direction: column; gap: 11px; }
525
+ .tl-bounce-title { font-size: 11px; color: var(--c-text-mut); font-weight: 600; letter-spacing: 0.01em; }
526
+ .tl-bounce-row { display: flex; align-items: center; gap: 10px; }
527
+ .tl-bounce-row label { font-size: 12px; color: #585858; font-weight: 500; width: 58px; flex: none; }
528
+ .tl-bounce-row input[type="range"] { flex: 1; height: 5px; -webkit-appearance: none; appearance: none;
529
+ background: #e7e7ec; border-radius: 3px; outline: none; cursor: pointer; transition: filter 0.12s ease; }
530
+ .tl-bounce-row input[type="range"]:hover { filter: brightness(0.98); }
530
531
  .tl-bounce-row input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none;
531
- width: 12px; height: 12px; border-radius: 50%; background: var(--c-blue); cursor: pointer; }
532
- .tl-bounce-val { font-size: 11px; color: var(--c-blue); width: 34px; text-align: right; }
532
+ width: 14px; height: 14px; border-radius: 50%; background: var(--c-blue); cursor: pointer;
533
+ border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0,113,226,0.4), 0 0 0 0.5px rgba(0,0,0,0.04);
534
+ transition: transform 0.12s cubic-bezier(0.22,1,0.36,1); }
535
+ .tl-bounce-row input[type="range"]::-webkit-slider-thumb:hover { transform: scale(1.12); }
536
+ .tl-bounce-row input[type="range"]:active::-webkit-slider-thumb { transform: scale(1.18); }
537
+ .tl-bounce-row input[type="range"]::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%;
538
+ background: var(--c-blue); cursor: pointer; border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0,113,226,0.4); }
539
+ .tl-bounce-val { font-size: 12px; font-weight: 600; color: var(--c-blue); width: 38px; text-align: right;
540
+ font-variant-numeric: tabular-nums; }
533
541
  .tl-bounce select { height: 26px; border: none; border-radius: 6px; background: var(--c-field-bg);
534
542
  font: inherit; font-size: 11px; color: var(--c-text); outline: none; box-shadow: inset 0 0 0 1px rgba(0,0,0,0.04); flex: 1; }
535
543
 
536
544
  /* ── Easing / Springs tabs — Logram design system (node 13064:2552): trackless toggle pills ── */
537
- .tl-seg { display: flex; align-items: center; gap: 4px; margin-top: 12px; }
545
+ .tl-seg { display: flex; align-items: center; gap: 4px; margin-top: 10px; }
538
546
  .tl-seg-btn { height: 32px; padding: 6px 12px; border: none; border-radius: 8px; background: transparent;
539
547
  font: inherit; font-size: 13px; font-weight: 500; line-height: 14px; color: #676767; cursor: pointer;
540
548
  transition: background 0.14s ease, color 0.14s ease; }
541
549
  .tl-seg-btn:hover:not(.is-active) { background: rgba(170,170,170,0.06); color: #17181c; }
542
550
  .tl-seg-btn.is-active { background: rgba(170,170,170,0.1); color: #17181c; }
543
551
 
552
+ /* position preview (animated marker à la easing.dev) — collapsible accordion
553
+ (transitions.dev · 21-accordion: grid-rows 0fr↔1fr + vertical chevron flip) */
554
+ .tl-preview { margin-top: 10px; background: #fff; border-radius: 10px;
555
+ box-shadow: inset 0 0 0 1px var(--c-hairline); overflow: hidden;
556
+ --acc-dur: 260ms; --acc-ease: cubic-bezier(0.22, 1, 0.36, 1); }
557
+ .tl-preview-head { display: flex; align-items: center; justify-content: space-between; width: 100%;
558
+ padding: 9px 12px; border: none; background: transparent; cursor: pointer; font: inherit;
559
+ border-radius: 10px; transition: background 0.12s ease; }
560
+ .tl-preview-head:hover { background: rgba(170,170,170,0.06); }
561
+ .tl-preview-title { font-size: 11px; font-weight: 600; color: var(--c-text-mut); letter-spacing: 0.01em; }
562
+ .tl-preview-chevron { display: inline-flex; color: var(--c-ruler);
563
+ transform: scaleY(1); transform-origin: center; transition: transform var(--acc-dur) var(--acc-ease); }
564
+ .tl-preview[data-open="true"] .tl-preview-chevron { transform: scaleY(-1); }
565
+ .tl-preview-panel { display: grid; grid-template-rows: 0fr;
566
+ transition: grid-template-rows var(--acc-dur) var(--acc-ease); }
567
+ .tl-preview[data-open="true"] .tl-preview-panel { grid-template-rows: 1fr; }
568
+ .tl-preview-panel-inner { overflow: hidden; opacity: 0; filter: blur(2px); padding: 0 12px 12px;
569
+ transition: opacity var(--acc-dur) var(--acc-ease), filter var(--acc-dur) var(--acc-ease); }
570
+ .tl-preview[data-open="true"] .tl-preview-panel-inner { opacity: 1; filter: blur(0); }
571
+ .tl-preview-controls { display: flex; justify-content: flex-end; margin-bottom: 10px; }
572
+ .tl-preview-btn { display: inline-flex; align-items: center; gap: 5px; height: 22px; padding: 0 8px 0 7px;
573
+ border: none; border-radius: 6px; background: var(--c-field-bg); color: var(--c-text-mut2);
574
+ font: inherit; font-size: 11px; font-weight: 500; cursor: pointer;
575
+ transition: background 0.12s ease, scale 0.12s ease; }
576
+ .tl-preview-btn:hover { background: var(--c-sec-h); }
577
+ .tl-preview-btn:active { scale: 0.96; }
578
+ .tl-preview-track { position: relative; height: 22px; }
579
+ .tl-preview-rail { position: absolute; left: 0; right: 0; top: 50%; height: 2px; transform: translateY(-50%);
580
+ background: var(--c-track); border-radius: 2px; }
581
+ .tl-preview-end { position: absolute; top: 50%; width: 2px; height: 10px; transform: translateY(-50%);
582
+ background: #d0d0d6; border-radius: 2px; }
583
+ .tl-preview-end.left { left: 0; }
584
+ .tl-preview-end.right { right: 0; }
585
+ .tl-preview-dot { position: absolute; left: 0; top: 50%; width: 18px; height: 18px; margin-top: -9px;
586
+ border-radius: 50%; background: var(--c-blue); border: 2px solid #fff;
587
+ box-shadow: 0 2px 6px rgba(0,113,226,0.4), 0 0 0 0.5px rgba(0,0,0,0.05);
588
+ will-change: transform; }
589
+ @media (prefers-reduced-motion: reduce) {
590
+ .tl-preview-panel, .tl-preview-panel-inner, .tl-preview-chevron { transition: none !important; }
591
+ }
592
+
544
593
  /* menu section header (non-clickable) — Figma node 580:1696 dropdown */
545
594
  .tl-menu-group { padding: 12px 8px 8px; font-size: 11px; font-weight: 400; line-height: 14px;
546
595
  color: #8b8b8b; pointer-events: none; }
547
596
  .tl-menu-group:first-child { padding-top: 4px; }
548
597
 
549
598
  /* spring params box (reuses bounce row layout) */
550
- .tl-spring-dur { display: flex; align-items: baseline; gap: 6px; font-size: 11px; color: var(--c-text-mut);
551
- padding-top: 2px; border-top: 1px solid var(--c-hairline); margin-top: 2px; }
599
+ .tl-spring-dur { display: flex; align-items: baseline; gap: 6px; font-size: 12px; color: var(--c-text-mut);
600
+ padding-top: 10px; border-top: 1px solid var(--c-hairline); margin-top: 0; }
552
601
  .tl-spring-dur b { color: var(--c-text); font-weight: 600; font-variant-numeric: tabular-nums; }
553
602
  .tl-spring-dur .tl-spring-dur-hint { color: var(--c-text-faint); }
554
603
 
@@ -592,9 +641,6 @@
592
641
  .tl-menu-item-label { flex: 1; min-width: 0; display: flex; align-items: center; }
593
642
  .tl-menu-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
594
643
  .tl-menu-dim { color: #979797; }
595
- .tl-menu-help { color: #c4c4cc; margin-left: 10px; flex: none; cursor: help; }
596
- .tl-menu-help:hover { color: var(--c-ruler); }
597
- .tl-menu-help svg { display: block; }
598
644
  .tl-menu-check { display: flex; color: var(--c-text-strong); flex: none; }
599
645
  .tl-menu-empty { padding: 10px 8px; color: var(--c-disabled); font-size: 13px; }
600
646
  .tl-menu-section { padding: 12px 8px 8px; font-size: 11px; font-weight: 400; line-height: 14px;
@@ -702,11 +748,6 @@
702
748
  }
703
749
  /* below-variant for triggers near the panel top edge */
704
750
  .t-tt.tl-tt-below { bottom: auto; top: calc(100% + 8px); transform-origin: 50% 0; font-size: 12px; }
705
- /* usage-variant: right-anchored, multi-line copy for token help icons */
706
- .t-tt.tl-tt-usage { left: auto; right: -6px; width: 224px; white-space: normal; text-align: left;
707
- font-size: 12px; line-height: 1.45; padding: 9px 11px; transform-origin: 100% 100%;
708
- text-wrap: balance; transform: translate(0, 4px) scale(var(--tt-scale)); }
709
- .t-tt-wrap:hover .t-tt.tl-tt-usage { transform: translate(0, 0) scale(1); }
710
751
 
711
752
  /* ═════ transitions.dev — panel reveal (per-phase distance/ease/scale) ═════ */
712
753
  /* base = closed / close-end state: resolved travel + scale come from the
@@ -1076,23 +1117,32 @@
1076
1117
  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
1118
 
1078
1119
  // 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.
1120
+ // The "Motion tokens (transitions.dev)" set is verbatim from the transitions.dev
1121
+ // skill's Easings table (name, value and usage all match the skill); the
1122
+ // "Standard" set is the five native CSS timing-function keywords.
1081
1123
  const EASING_LIBRARY = [
1082
1124
  { 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." },
1125
+ { label:"Smooth ease out", value:"cubic-bezier(0.22, 1, 0.36, 1)", usage:"Modal / dropdown / panel open + close, page slide, resize, position change." },
1126
+ { label:"Ease in out", value:"ease-in-out", usage:"Icon swap, text swap, text reveal, skeleton reveal." },
1127
+ { label:"Ease out", value:"ease-out", usage:"Tooltip open / close." },
1128
+ { label:"Linear", value:"linear", usage:"Shimmer, skeleton pulse, spinner." },
1129
+ { label:"Bouncy overshoot", value:"cubic-bezier(0.34, 1.36, 0.64, 1)", usage:"Badge pop open — a small overshoot past the target." },
1130
+ { label:"Strong bouncy overshoot", value:"cubic-bezier(0.34, 3.85, 0.64, 1)", usage:"Bouncy hover-out (avatar return) aggressive, spring-like overshoot." },
1131
+ { group:"Standard" },
1132
+ { label:"ease", value:"ease", usage:"CSS default — gentle ease in, ease out." },
1133
+ { label:"ease-in", value:"ease-in", usage:"Accelerate from rest — slow start, fast finish." },
1134
+ { label:"ease-out", value:"ease-out", usage:"Decelerate to rest — fast start, slow finish." },
1135
+ { label:"ease-in-out", value:"ease-in-out", usage:"Accelerate then decelerate — symmetric." },
1136
+ { label:"linear", value:"linear", usage:"Constant speed — no acceleration." },
1090
1137
  { group:"Custom" },
1091
1138
  { label:"cubic-bezier(\u2026)", value:"__cubic" },
1092
1139
  { label:"custom", value:"__custom" },
1093
1140
  ];
1094
1141
  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]));
1142
+ // First occurrence wins, so a shared keyword (e.g. ease-out) shows its
1143
+ // semantic transitions.dev name rather than the bare Standard keyword.
1144
+ const EASING_LABEL = EASING_LIBRARY.filter(o=>o.value&&o.value[0]!=="_")
1145
+ .reduce((m,o)=>{const k=normEase(o.value);if(!m.has(k))m.set(k,o.label);return m;},new Map());
1096
1146
  function easingLabel(v){ return EASING_LABEL.get(normEase(v)) || null; }
1097
1147
 
1098
1148
  // Most-common predefined springs. tension/friction follow react-spring's
@@ -1329,6 +1379,8 @@
1329
1379
  };
1330
1380
  ICONS.minimize = ICONS.chevron;
1331
1381
  ICONS.close = {vb:"0 0 16 16", svg:`<path d="M4 4L12 12M12 4L4 12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>`};
1382
+ ICONS.play = {vb:"0 0 16 16", svg:`<path d="M5 3.5L12 8L5 12.5V3.5Z" fill="currentColor"/>`};
1383
+ ICONS.pause = {vb:"0 0 16 16", svg:`<path d="M5 3.5H6.8V12.5H5V3.5ZM9.2 3.5H11V12.5H9.2V3.5Z" fill="currentColor"/>`};
1332
1384
  // dots-vertical (Figma node 580:4819) — vertical "⋮" overflow icon
1333
1385
  ICONS.dotsv = {vb:"0 0 16 16", svg:`<path fill-rule="evenodd" clip-rule="evenodd" d="M6.66667 8C6.66667 7.26362 7.26362 6.66667 8 6.66667C8.73638 6.66667 9.33333 7.26362 9.33333 8C9.33333 8.73638 8.73638 9.33333 8 9.33333C7.26362 9.33333 6.66667 8.73638 6.66667 8Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M6.66667 3.33333C6.66667 2.59695 7.26362 2 8 2C8.73638 2 9.33333 2.59695 9.33333 3.33333C9.33333 4.06971 8.73638 4.66667 8 4.66667C7.26362 4.66667 6.66667 4.06971 6.66667 3.33333Z" fill="currentColor"/><path fill-rule="evenodd" clip-rule="evenodd" d="M6.66667 12.6667C6.66667 11.9303 7.26362 11.3333 8 11.3333C8.73638 11.3333 9.33333 11.9303 9.33333 12.6667C9.33333 13.403 8.73638 14 8 14C7.26362 14 6.66667 13.403 6.66667 12.6667Z" fill="currentColor"/>`};
1334
1386
  function Ic({name, size=16}){
@@ -1711,7 +1763,7 @@
1711
1763
  fFlat.length>0&&fGroups.length>0&&h("div",{className:"tl-menu-section"},"Ungrouped"),
1712
1764
  ...fFlat.map(flatItem))),
1713
1765
  h("span",{className:"tl-header-count"},
1714
- scanning?"Grouping…":entries.length+" transition"+(entries.length===1?"":"s")+" found"),
1766
+ scanning?"Scanning transitions…":entries.length+" transition"+(entries.length===1?"":"s")+" found"),
1715
1767
  h("button",{ref:gearRef,className:cx("tl-icon-btn",setg&&"is-active"),title:"Settings",onClick:()=>setSetg(v=>!v)},h(Ic,{name:"dotsv"})),
1716
1768
  h(Dropdown,{open:setg,onClose:()=>setSetg(false),triggerRef:gearRef,width:210,align:"right"},
1717
1769
  h(MenuItem,{onClick:()=>setSnap(v=>!v),right:snap&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},"Snap to grid"),
@@ -1859,11 +1911,7 @@
1859
1911
  width:(wrapRef.current&&wrapRef.current.offsetWidth)||220,align:"right"},
1860
1912
  (tokens||[]).map(tk=>h(MenuItem,{key:tk.label,active:value===tk.ms,onClick:()=>{onChange(tk.ms);setMenu(false);},
1861
1913
  right:value===tk.ms&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},
1862
- h("span",{className:"tl-menu-text"},tk.label,h("span",{className:"tl-menu-dim"}," "+tk.ms+"ms")),
1863
- tk.usage&&h("span",{className:"t-tt-wrap tl-menu-help",
1864
- onClick:e=>e.stopPropagation(),onMouseDown:e=>e.stopPropagation()},
1865
- h(Ic,{name:"help",size:13}),
1866
- h("span",{className:"t-tt tl-tt-usage",role:"tooltip"},tk.usage)))) ),
1914
+ h("span",{className:"tl-menu-text"},tk.label,h("span",{className:"tl-menu-dim"}," "+tk.ms+"ms")))) ),
1867
1915
  readOnly&&readOnlyHint&&h("span",{className:"t-tt",role:"tooltip"},readOnlyHint),
1868
1916
  );
1869
1917
  }
@@ -1943,6 +1991,9 @@
1943
1991
  const easeRef = useRef(null);
1944
1992
  const [easeOpen, setEaseOpen] = useState(false);
1945
1993
  const selLabel = easingLabel(easing) || (isCubic ? "cubic-bezier(\u2026)" : easing ? easing : "custom");
1994
+ // first selectable row whose value matches — so a keyword shared between the
1995
+ // transitions.dev and Standard groups only checks once (the first one).
1996
+ const selEaseIdx = EASING_LIBRARY.findIndex(o=>o.value&&o.value[0]!=="_"&&normEase(o.value)===normEase(easing));
1946
1997
  const pickEase = useCallback(v=>{
1947
1998
  if(v==="__cubic") setEasing(`cubic-bezier(${cb.join(", ")})`);
1948
1999
  else if(v==="__custom") setEasing("");
@@ -1996,14 +2047,10 @@
1996
2047
  width:Math.max(248,(easeRef.current&&easeRef.current.offsetWidth)||248),align:"left"},
1997
2048
  EASING_LIBRARY.map((o,i)=> o.group
1998
2049
  ? 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),
2050
+ : h(MenuItem,{key:"e"+i,active:selEaseIdx>=0?i===selEaseIdx:(o.value===mode),
2000
2051
  onClick:()=>pickEase(o.value),
2001
- right:(normEase(o.value)===normEase(easing))&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},
2002
- h("span",{className:"tl-menu-text"},o.label),
2003
- o.usage&&h("span",{className:"t-tt-wrap tl-menu-help",
2004
- onClick:e=>e.stopPropagation(),onMouseDown:e=>e.stopPropagation()},
2005
- h(Ic,{name:"help",size:13}),
2006
- h("span",{className:"t-tt tl-tt-usage",role:"tooltip"},o.usage))))),
2052
+ right:(i===selEaseIdx)&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},
2053
+ h("span",{className:"tl-menu-text"},o.label)))),
2007
2054
  h("div",{className:"tl-cubic-row"},
2008
2055
  ...[0,1,2,3].map(i=>h("input",{key:i,type:"number",step:0.05,min:i%2===0?0:undefined,max:i%2===0?1:undefined,
2009
2056
  value:cb[i],onChange:e=>setCubicVal(i,e.target.value)})),
@@ -2068,11 +2115,7 @@
2068
2115
  SPRING_PRESETS.map(p=>h(MenuItem,{key:p.label,active:p.label===presetName,
2069
2116
  onClick:()=>{applySpring(p.stiffness,p.damping,p.mass,p.label);setSpOpen(false);},
2070
2117
  right:p.label===presetName&&h("span",{className:"tl-menu-check"},h(Ic,{name:"check"}))},
2071
- h("span",{className:"tl-menu-text"},p.label),
2072
- p.usage&&h("span",{className:"t-tt-wrap tl-menu-help",
2073
- onClick:e=>e.stopPropagation(),onMouseDown:e=>e.stopPropagation()},
2074
- h(Ic,{name:"help",size:13}),
2075
- h("span",{className:"t-tt tl-tt-usage",role:"tooltip"},p.usage))))),
2118
+ h("span",{className:"tl-menu-text"},p.label)))),
2076
2119
  h("div",{className:"tl-bounce"},
2077
2120
  h("div",{className:"tl-bounce-title"},"Spring physics"),
2078
2121
  h("div",{className:"tl-bounce-row"},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "transitions-refine",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
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": {