@cardenelabs/cdl 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,29 @@ CDL (Chainome Diagram Language) の主要変更履歴。
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.38.0] - 2026-09-07
9
+
10
+ ### Fixed
11
+
12
+ - **図を描く動きが前半に寄って読めないのを直した** (#711)
13
+
14
+ 段の進みは `easeOutQuint` を通っており、`1.2s` の段で半分に達するのが 158 ms だった
15
+ (直線なら 600 ms)。 値が落ち着く動きには合う曲線だが、線を引く動きはペンの速さなので、
16
+ 同じ曲線を当てると飛び出して這う。
17
+
18
+ 折れ線は線の先が点に届いた時に値の字を出すが、5 点のうち 4 点が 292 ms の間に出て、
19
+ 最後の 1 点まで 908 ms 空いていた。「1 つずつ現れる」 という読ませ方が成立していない。
20
+
21
+ `Timeline` が曲げる前の進み (`phaseLinearProgress`) も持つようにし、描く動き
22
+ (`draw` の node と、その段で初めて出る矢印) だけがそれを読む。 値の補間は今までどおり
23
+ 曲げた進みで動く。
24
+
25
+ 直線にしたのは、5 点が等間隔の時刻に出る唯一の曲線だったため (実測 = 直線 294 ms 間隔、
26
+ `easeOut` は 188 / 219 / 275 / 518、`easeInOut` は真ん中の 3 点が寄る)。
27
+
28
+ `drawRatio` も直っている。 曲げた進みで割っていたため `0.4` と書くと段の 4.8% で
29
+ 描き終わっていた。 これからは書いた割合が実時間の割合になる。
30
+
8
31
  ## [0.37.0] - 2026-09-07
9
32
 
10
33
  ### Added
@@ -1717,7 +1740,8 @@ Initial OSS release.
1717
1740
  使わない = annotated tag を push しても GitHub Release は作られず、 Release を作っていない版で
1718
1741
  行き止まりになる。
1719
1742
 
1720
- [Unreleased]: https://github.com/cardene777/cdl/compare/v0.37.0...HEAD
1743
+ [Unreleased]: https://github.com/cardene777/cdl/compare/v0.38.0...HEAD
1744
+ [0.38.0]: https://github.com/cardene777/cdl/compare/v0.37.0...v0.38.0
1721
1745
  [0.37.0]: https://github.com/cardene777/cdl/compare/v0.36.0...v0.37.0
1722
1746
  [0.36.0]: https://github.com/cardene777/cdl/compare/v0.35.0...v0.36.0
1723
1747
  [0.35.0]: https://github.com/cardene777/cdl/compare/v0.34.0...v0.35.0
package/dist/index.cjs CHANGED
@@ -14158,6 +14158,8 @@ var Timeline = class {
14158
14158
  rafHandle = null;
14159
14159
  phaseIndex = 0;
14160
14160
  phaseProgress = 0;
14161
+ /** 曲線を通す前の進み (cdl#711)。 経過時間そのものの割合で、 描く動きが読む */
14162
+ phaseLinearProgress = 0;
14161
14163
  phaseStartedAt = 0;
14162
14164
  status = "idle";
14163
14165
  /**
@@ -14186,12 +14188,12 @@ var Timeline = class {
14186
14188
  const initial = options.initialPhaseIndex;
14187
14189
  if (initial != null && initial > 0 && initial < phases.length) {
14188
14190
  this.phaseIndex = initial;
14189
- this.phaseProgress = 1;
14191
+ this.setProgress(1);
14190
14192
  this.status = initial === phases.length - 1 ? "settled" : "paused";
14191
14193
  }
14192
14194
  this.initialState = {
14193
14195
  phaseIndex: this.phaseIndex,
14194
- phaseProgress: this.phaseProgress,
14196
+ phaseLinearProgress: this.phaseLinearProgress,
14195
14197
  status: this.status
14196
14198
  };
14197
14199
  }
@@ -14213,13 +14215,14 @@ var Timeline = class {
14213
14215
  }
14214
14216
  snapshot() {
14215
14217
  const cached = this.cachedSnapshot;
14216
- if (cached && cached.status === this.status && cached.phaseIndex === this.phaseIndex && cached.phaseProgress === this.phaseProgress && cached.totalPhases === this.phases.length) {
14218
+ if (cached && cached.status === this.status && cached.phaseIndex === this.phaseIndex && cached.phaseProgress === this.phaseProgress && cached.phaseLinearProgress === this.phaseLinearProgress && cached.totalPhases === this.phases.length) {
14217
14219
  return cached;
14218
14220
  }
14219
14221
  const next = {
14220
14222
  status: this.status,
14221
14223
  phaseIndex: this.phaseIndex,
14222
14224
  phaseProgress: this.phaseProgress,
14225
+ phaseLinearProgress: this.phaseLinearProgress,
14223
14226
  totalPhases: this.phases.length
14224
14227
  };
14225
14228
  this.cachedSnapshot = next;
@@ -14242,7 +14245,7 @@ var Timeline = class {
14242
14245
  const clamped = Math.max(0, Math.min(this.phases.length - 1, index));
14243
14246
  this.cancelRaf();
14244
14247
  this.phaseIndex = clamped;
14245
- this.phaseProgress = 1;
14248
+ this.setProgress(1);
14246
14249
  this.status = clamped === this.phases.length - 1 ? "settled" : "paused";
14247
14250
  this.emit();
14248
14251
  }
@@ -14282,14 +14285,14 @@ var Timeline = class {
14282
14285
  if (this.phaseIndex <= 0) return;
14283
14286
  this.cancelRaf();
14284
14287
  this.phaseIndex -= 1;
14285
- this.phaseProgress = 1;
14288
+ this.setProgress(1);
14286
14289
  this.status = "paused";
14287
14290
  this.emit();
14288
14291
  }
14289
14292
  reset() {
14290
14293
  this.cancelRaf();
14291
14294
  this.phaseIndex = 0;
14292
- this.phaseProgress = 0;
14295
+ this.setProgress(0);
14293
14296
  this.status = "idle";
14294
14297
  this.emit();
14295
14298
  }
@@ -14310,7 +14313,7 @@ var Timeline = class {
14310
14313
  this.subscribers.clear();
14311
14314
  this.status = this.initialState.status;
14312
14315
  this.phaseIndex = this.initialState.phaseIndex;
14313
- this.phaseProgress = this.initialState.phaseProgress;
14316
+ this.setProgress(this.initialState.phaseLinearProgress);
14314
14317
  }
14315
14318
  // ─── internals ───────────────────────────────────────────────
14316
14319
  advancePhase() {
@@ -14346,20 +14349,20 @@ var Timeline = class {
14346
14349
  }, ms);
14347
14350
  }
14348
14351
  beginPhaseTransition() {
14349
- this.phaseProgress = 0;
14352
+ this.setProgress(0);
14350
14353
  this.phaseStartedAt = performance.now();
14351
14354
  this.cancelRaf();
14352
14355
  const step = (now) => {
14353
14356
  const duration = this.autoAdvanceMsOverride ?? this.getPhase().durationMs ?? 600;
14354
14357
  const elapsed = now - this.phaseStartedAt;
14355
14358
  const linearT = clamp01(elapsed / duration);
14356
- this.phaseProgress = this.easing(linearT);
14359
+ this.setProgress(linearT);
14357
14360
  this.emit();
14358
14361
  if (linearT < 1) {
14359
14362
  this.rafHandle = requestAnimationFrame(step);
14360
14363
  return;
14361
14364
  }
14362
- this.phaseProgress = 1;
14365
+ this.setProgress(1);
14363
14366
  this.emit();
14364
14367
  if (this.status === "playing") {
14365
14368
  if (this.phaseIndex < this.phases.length - 1) {
@@ -14374,6 +14377,19 @@ var Timeline = class {
14374
14377
  };
14375
14378
  this.rafHandle = requestAnimationFrame(step);
14376
14379
  }
14380
+ /**
14381
+ * 段の進みを 2 つ同時に置く (cdl#711)。
14382
+ *
14383
+ * **代入する場所を 1 つに閉じる**。 曲げた進みと曲げる前の進みを別々に書くと、
14384
+ * どちらかを更新し忘れた経路が「前の段の値のまま」 で残る。
14385
+ *
14386
+ * 両端 (0 と 1) は曲線を通さず、 そのまま置く。 曲線は差し替えられる欄なので、
14387
+ * `easing(1)` が 1 を返す保証がない。 段の始まりと終わりの値は曲線に委ねない。
14388
+ */
14389
+ setProgress(linear2) {
14390
+ this.phaseLinearProgress = linear2;
14391
+ this.phaseProgress = linear2 <= 0 ? 0 : linear2 >= 1 ? 1 : this.easing(linear2);
14392
+ }
14377
14393
  cancelRaf() {
14378
14394
  if (this.rafHandle != null) {
14379
14395
  cancelAnimationFrame(this.rafHandle);
@@ -30647,6 +30663,7 @@ function CdlStage({
30647
30663
  laid,
30648
30664
  currentPhase,
30649
30665
  progress,
30666
+ drawProgress,
30650
30667
  stateValues,
30651
30668
  debug,
30652
30669
  compact = false,
@@ -30704,7 +30721,8 @@ function CdlStage({
30704
30721
  }
30705
30722
  return scales;
30706
30723
  }, [laid]);
30707
- const \u63CF\u304F\u9032\u307F = \u63CF\u304F\u9032\u307F\u306B\u76F4\u3059(progress, currentPhase?.drawRatio);
30724
+ const \u63CF\u304F\u7D20\u306E\u9032\u307F = drawProgress ?? progress;
30725
+ const \u63CF\u304F\u9032\u307F = \u63CF\u304F\u9032\u307F\u306B\u76F4\u3059(\u63CF\u304F\u7D20\u306E\u9032\u307F, currentPhase?.drawRatio);
30708
30726
  const { lifelineStarts, uniformFooterTop } = react.useMemo(() => {
30709
30727
  const starts = lifelineStartYs(laid.nodes);
30710
30728
  return {
@@ -30883,7 +30901,7 @@ function CdlStage({
30883
30901
  edge,
30884
30902
  active: activeSet.has(edge.id),
30885
30903
  drawing: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id),
30886
- progress,
30904
+ progress: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id) ? \u63CF\u304F\u9032\u307F : progress,
30887
30905
  stateValues
30888
30906
  },
30889
30907
  edge.id
@@ -31114,6 +31132,7 @@ function CdlDiagramView({ diagram: diagram2, laid: laidProp, hideHeader = false,
31114
31132
  const phaseIdx = focusPhaseId ? laid.phases.findIndex((p) => p.id === focusPhaseId) : state.phaseIndex;
31115
31133
  const currentPhase = laid.phases[Math.max(0, phaseIdx)] ?? laid.phases[0];
31116
31134
  const progress = reduced ? 1 : state.phaseProgress;
31135
+ const drawProgress = reduced ? 1 : state.phaseLinearProgress;
31117
31136
  const baseStateValues = computeStateValues(laid, phaseIdx, progress);
31118
31137
  const isInteractive = hasInteractivePrimitives(diagram2);
31119
31138
  const interactive = useInteractiveIntegration(
@@ -31155,7 +31174,7 @@ function CdlDiagramView({ diagram: diagram2, laid: laidProp, hideHeader = false,
31155
31174
  }
31156
31175
  ),
31157
31176
  isInteractive && interactive.panel,
31158
- /* @__PURE__ */ jsxRuntime.jsx(CdlStage, { laid, currentPhase, progress, stateValues, debug, compact: hideHeader, svgRef: isInteractive ? interactive.svgRef : void 0 }),
31177
+ /* @__PURE__ */ jsxRuntime.jsx(CdlStage, { laid, currentPhase, progress, drawProgress, stateValues, debug, compact: hideHeader, svgRef: isInteractive ? interactive.svgRef : void 0 }),
31159
31178
  hideHeader && !hideMiniPhaseIndicator && currentPhase && laid.phases.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 border-t border-[var(--cdl-divider,#d4d4d8)]/40 bg-[var(--cdl-stage-bg,#f1f5f9)]/50 px-3 py-2 text-xs", children: [
31160
31179
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
31161
31180
  laid.phases.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(