@cardenelabs/cdl 0.46.0 → 0.48.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/dist/react.cjs CHANGED
@@ -2423,6 +2423,7 @@ var EDGE_HEADS = [
2423
2423
  ];
2424
2424
  var EDGE_HEAD_FILL_DEFAULT = "solid";
2425
2425
  var EDGE_HEAD_FILLS = ["solid", "hollow"];
2426
+ var RELATION_FOCUS_DEFAULT = "off";
2426
2427
  var EDGE_REVEAL_DEFAULT = "phase";
2427
2428
 
2428
2429
  // src/kinds/text-width.ts
@@ -8281,33 +8282,73 @@ function placeAvoidingSiblingPaths(args) {
8281
8282
  }
8282
8283
  };
8283
8284
  consider([...wants]);
8285
+ const \u62BC\u3059\u91CF = (idx, side, pos) => {
8286
+ let \u8981\u308B = 0;
8287
+ for (const i of idx) {
8288
+ const box = boxes[i];
8289
+ const rect = { x: box.x, y: pos[i] - box.h / 2, w: box.w, h: box.h };
8290
+ for (const probe of probeSegs[i]) {
8291
+ if (measurePathLabelGapSegs(probe.segs, rect) >= CLEARANCE_PATH_LABEL) continue;
8292
+ let lo = Infinity;
8293
+ let hi = -Infinity;
8294
+ for (const seg of probe.segs) {
8295
+ const c = clipY(seg, box.x, box.x + box.w);
8296
+ if (!c) continue;
8297
+ lo = Math.min(lo, c.lo);
8298
+ hi = Math.max(hi, c.hi);
8299
+ }
8300
+ if (lo > hi) continue;
8301
+ const \u884C\u304D\u5148 = side === "above" ? lo - box.h / 2 - CLEARANCE_PATH_LABEL : hi + box.h / 2 + CLEARANCE_PATH_LABEL;
8302
+ \u8981\u308B = Math.max(\u8981\u308B, side === "above" ? pos[i] - \u884C\u304D\u5148 : \u884C\u304D\u5148 - pos[i]);
8303
+ }
8304
+ }
8305
+ return Math.max(0, \u8981\u308B);
8306
+ };
8284
8307
  if (bands.some((b) => b !== null)) {
8285
8308
  for (let split = 0; split <= order.length; split++) {
8286
8309
  const above = order.slice(0, split);
8287
8310
  const below = order.slice(split);
8288
- const out = new Array(members.length);
8289
- for (const [idx, side] of [
8290
- [above, "above"],
8291
- [below, "below"]
8292
- ]) {
8293
- if (idx.length === 0) continue;
8294
- const ys = spread(idx);
8295
- let shift = 0;
8296
- for (let k = 0; k < idx.length; k++) {
8297
- const band = bands[idx[k]];
8298
- if (!band) continue;
8299
- shift = side === "above" ? Math.min(shift, band.lo - ys[k]) : Math.max(shift, band.hi - ys[k]);
8300
- }
8301
- for (let k = 0; k < idx.length; k++) out[idx[k]] = ys[k] + shift;
8302
- }
8303
- if (above.length > 0 && below.length > 0) {
8311
+ const \u9593\u3092\u7A7A\u3051\u308B = (out) => {
8312
+ if (above.length === 0 || below.length === 0) return;
8304
8313
  const lastIdx = above[above.length - 1];
8305
8314
  const firstIdx = below[0];
8306
8315
  const need = (sizes[lastIdx] + sizes[firstIdx]) / 2 + CLEARANCE_LABEL_LABEL;
8307
8316
  const deficit = need - (out[firstIdx] - out[lastIdx]);
8308
- if (deficit > 0) for (const i of below) out[i] += deficit;
8309
- }
8310
- consider(out);
8317
+ if (deficit > 0) for (const i of below) out[i] = out[i] + deficit;
8318
+ };
8319
+ const \u5E2F\u3092\u8D8A\u3048\u308B = () => {
8320
+ const out = new Array(members.length);
8321
+ for (const [idx, side] of [
8322
+ [above, "above"],
8323
+ [below, "below"]
8324
+ ]) {
8325
+ if (idx.length === 0) continue;
8326
+ const ys = spread(idx);
8327
+ let shift = 0;
8328
+ for (let k = 0; k < idx.length; k++) {
8329
+ const band = bands[idx[k]];
8330
+ if (!band) continue;
8331
+ shift = side === "above" ? Math.min(shift, band.lo - ys[k]) : Math.max(shift, band.hi - ys[k]);
8332
+ }
8333
+ for (let k = 0; k < idx.length; k++) out[idx[k]] = ys[k] + shift;
8334
+ }
8335
+ \u9593\u3092\u7A7A\u3051\u308B(out);
8336
+ return out;
8337
+ };
8338
+ const \u62BC\u3057\u3066\u8D8A\u3048\u308B = () => {
8339
+ const out = \u5E2F\u3092\u8D8A\u3048\u308B();
8340
+ for (let round = 0; round < 4; round += 1) {
8341
+ const a = \u62BC\u3059\u91CF(above, "above", out);
8342
+ const b = \u62BC\u3059\u91CF(below, "below", out);
8343
+ if (a === 0 && b === 0) return out;
8344
+ for (const i of above) out[i] = out[i] - a;
8345
+ for (const i of below) out[i] = out[i] + b;
8346
+ }
8347
+ return \u62BC\u3059\u91CF(above, "above", out) === 0 && \u62BC\u3059\u91CF(below, "below", out) === 0 ? out : null;
8348
+ };
8349
+ consider(\u5E2F\u3092\u8D8A\u3048\u308B());
8350
+ const \u62BC\u3057\u305F = \u62BC\u3057\u3066\u8D8A\u3048\u308B();
8351
+ if (\u62BC\u3057\u305F) consider(\u62BC\u3057\u305F);
8311
8352
  }
8312
8353
  }
8313
8354
  const plain = spread(all);
@@ -9427,6 +9468,7 @@ function layout(diag) {
9427
9468
  ...diag.derived ? { derived: diag.derived } : {},
9428
9469
  // 矢印をいつ出すか (#582)。 描き手が読む欄なので、そのまま持ち越す
9429
9470
  ...diag.edgeReveal ? { edgeReveal: diag.edgeReveal } : {},
9471
+ ...diag.relationFocus ? { relationFocus: diag.relationFocus } : {},
9430
9472
  // どの配色で描くか (#1553)。 空文字は書かなかった扱いにする = 空の目印を出すと、
9431
9473
  // 消費側の `[data-cdl-palette]` が配色を書いていない図にも当たる。
9432
9474
  //
@@ -10300,7 +10342,8 @@ function CdlEdgeView({
10300
10342
  active,
10301
10343
  drawing,
10302
10344
  progress,
10303
- stateValues
10345
+ stateValues,
10346
+ flowing = false
10304
10347
  }) {
10305
10348
  const color = edgeColor(edge);
10306
10349
  const marker = edgeHeadMarkerName(edge.tone, edge.head, !active, edge.headFill);
@@ -10318,6 +10361,7 @@ function CdlEdgeView({
10318
10361
  "data-cdl-from": edge.from,
10319
10362
  "data-cdl-to": edge.to,
10320
10363
  "data-cdl-active": active ? "true" : "false",
10364
+ "data-cdl-flowing": flowing ? "true" : "false",
10321
10365
  "data-cdl-drawing": drawing ? "true" : "false",
10322
10366
  "data-cdl-path-d": edge.d,
10323
10367
  "data-cdl-label-x": edge.labelX,
@@ -10370,7 +10414,11 @@ function CdlEdgeView({
10370
10414
  strokeWidth: 14,
10371
10415
  strokeLinecap: "round"
10372
10416
  }
10373
- )
10417
+ ),
10418
+ flowing && !isDotted && /* @__PURE__ */ jsxRuntime.jsxs("g", { "data-cdl-role": "edge-flow", children: [
10419
+ /* @__PURE__ */ jsxRuntime.jsx("path", { id: glowPathId, d: edge.d, fill: "none", stroke: "none" }),
10420
+ /* @__PURE__ */ jsxRuntime.jsx(EdgeGlowCircles, { color, edgeId: edge.id })
10421
+ ] })
10374
10422
  ]
10375
10423
  }
10376
10424
  );
@@ -18143,7 +18191,8 @@ function CdlNodeView({
18143
18191
  progress,
18144
18192
  stateValues,
18145
18193
  currentPhaseId,
18146
- chartLineScale
18194
+ chartLineScale,
18195
+ \u95A2\u4FC2\u306E\u53D7\u3051\u53E3
18147
18196
  }) {
18148
18197
  const value = node.value ? interpolate(node.value, stateValues) : void 0;
18149
18198
  const rows = (node.rows ?? []).map((r) => interpolate(r, stateValues));
@@ -18465,6 +18514,23 @@ function CdlNodeView({
18465
18514
  "data-cdl-eyebrow": resolvedNode.eyebrow ?? "",
18466
18515
  "data-cdl-offset-x": offsetX || void 0,
18467
18516
  "data-cdl-offset-y": offsetY || void 0,
18517
+ ...\u95A2\u4FC2\u306E\u53D7\u3051\u53E3 === void 0 ? {} : {
18518
+ // 読み上げに「押せる」 ことを伝え、 tab でも辿れるようにする。
18519
+ role: "button",
18520
+ tabIndex: 0,
18521
+ "aria-pressed": \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u7126\u70B9 === node.id,
18522
+ style: { cursor: "pointer" },
18523
+ onPointerEnter: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u89E6\u308C\u305F(node.id),
18524
+ onPointerLeave: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u96E2\u308C\u305F(),
18525
+ onFocus: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u89E6\u308C\u305F(node.id),
18526
+ onBlur: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u96E2\u308C\u305F(),
18527
+ onClick: () => \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u62BC\u3057\u305F(node.id),
18528
+ onKeyDown: (e) => {
18529
+ if (e.key !== "Enter" && e.key !== " ") return;
18530
+ e.preventDefault();
18531
+ \u95A2\u4FC2\u306E\u53D7\u3051\u53E3.\u62BC\u3057\u305F(node.id);
18532
+ }
18533
+ },
18468
18534
  transform: hasOffset ? `translate(${offsetX}, ${offsetY})` : void 0,
18469
18535
  opacity: boundOpacity,
18470
18536
  "data-cdl-tone": node.tone,
@@ -18488,6 +18554,18 @@ function CdlNodeView({
18488
18554
  }
18489
18555
  );
18490
18556
  }
18557
+
18558
+ // src/render/relation-focus.ts
18559
+ function relatedFocusSet(edges, nodeId) {
18560
+ const \u96C6\u5408 = /* @__PURE__ */ new Set([nodeId]);
18561
+ for (const e of edges) {
18562
+ if (e.from !== nodeId && e.to !== nodeId) continue;
18563
+ \u96C6\u5408.add(e.id);
18564
+ \u96C6\u5408.add(e.from);
18565
+ \u96C6\u5408.add(e.to);
18566
+ }
18567
+ return \u96C6\u5408;
18568
+ }
18491
18569
  function CdlStage({
18492
18570
  laid,
18493
18571
  currentPhase,
@@ -18498,7 +18576,35 @@ function CdlStage({
18498
18576
  compact = false,
18499
18577
  svgRef
18500
18578
  }) {
18501
- const activeSet = new Set(currentPhase?.activate ?? []);
18579
+ const [\u7126\u70B9, set\u7126\u70B9] = react.useState(null);
18580
+ const \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B = (laid.relationFocus ?? RELATION_FOCUS_DEFAULT) === "hover";
18581
+ const \u52D5\u304D\u3092\u63A7\u3048\u308B = useReducedMotion();
18582
+ react.useEffect(() => {
18583
+ if (!\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B) set\u7126\u70B9(null);
18584
+ }, [\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B]);
18585
+ react.useEffect(() => {
18586
+ if (!\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B || \u7126\u70B9?.\u7559\u3081\u305F !== true) return;
18587
+ const \u62BC\u3057\u305F2 = (e) => {
18588
+ if (e.key === "Escape") set\u7126\u70B9(null);
18589
+ };
18590
+ window.addEventListener("keydown", \u62BC\u3057\u305F2);
18591
+ return () => window.removeEventListener("keydown", \u62BC\u3057\u305F2);
18592
+ }, [\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9?.\u7559\u3081\u305F]);
18593
+ const \u89E6\u308C\u305F = react.useCallback((id) => {
18594
+ set\u7126\u70B9((\u524D) => \u524D?.\u7559\u3081\u305F === true ? \u524D : { id, \u7559\u3081\u305F: false });
18595
+ }, []);
18596
+ const \u96E2\u308C\u305F = react.useCallback(() => {
18597
+ set\u7126\u70B9((\u524D) => \u524D?.\u7559\u3081\u305F === true ? \u524D : null);
18598
+ }, []);
18599
+ const \u62BC\u3057\u305F = react.useCallback((id) => {
18600
+ set\u7126\u70B9((\u524D) => \u524D?.id === id && \u524D.\u7559\u3081\u305F ? null : { id, \u7559\u3081\u305F: true });
18601
+ }, []);
18602
+ const \u7126\u70B9\u306E\u96C6\u5408 = react.useMemo(
18603
+ () => \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B && \u7126\u70B9 !== null ? relatedFocusSet(laid.edges, \u7126\u70B9.id) : null,
18604
+ [\u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B, \u7126\u70B9, laid.edges]
18605
+ );
18606
+ const activeSet = \u7126\u70B9\u306E\u96C6\u5408 ?? new Set(currentPhase?.activate ?? []);
18607
+ const \u7BB1\u306E\u53D7\u3051\u53E3 = \u95A2\u4FC2\u3092\u5149\u3089\u305B\u308B ? { \u89E6\u308C\u305F, \u96E2\u308C\u305F, \u62BC\u3057\u305F, \u7126\u70B9: \u7126\u70B9?.id ?? null } : void 0;
18502
18608
  const \u77E2\u5370\u306E\u51FA\u756A = react.useMemo(() => {
18503
18609
  const \u521D\u51FA = /* @__PURE__ */ new Map();
18504
18610
  laid.phases.forEach((p, i) => {
@@ -18729,6 +18835,7 @@ function CdlStage({
18729
18835
  {
18730
18836
  edge,
18731
18837
  active: activeSet.has(edge.id),
18838
+ flowing: \u7126\u70B9\u306E\u96C6\u5408?.has(edge.id) === true && !\u52D5\u304D\u3092\u63A7\u3048\u308B,
18732
18839
  drawing: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id),
18733
18840
  progress: \u77E2\u5370\u306E\u51FA\u756A.\u4F38\u3070\u3059\u304B(edge.id) ? \u63CF\u304F\u9032\u307F : progress,
18734
18841
  stateValues
@@ -18742,6 +18849,7 @@ function CdlStage({
18742
18849
  {
18743
18850
  node,
18744
18851
  active: activeSet.has(node.id),
18852
+ \u95A2\u4FC2\u306E\u53D7\u3051\u53E3: \u7BB1\u306E\u53D7\u3051\u53E3,
18745
18853
  drawing: \u63CF\u304F,
18746
18854
  progress: \u63CF\u304F ? \u63CF\u304F\u9032\u307F : progress,
18747
18855
  stateValues,