@cardenelabs/cdl 0.5.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.
Files changed (108) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +343 -0
  3. package/SPEC.md +374 -0
  4. package/dist/index.cjs +28085 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.cts +3415 -0
  7. package/dist/index.d.ts +3415 -0
  8. package/dist/index.js +27962 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/react.cjs +23043 -0
  11. package/dist/react.cjs.map +1 -0
  12. package/dist/react.d.cts +2 -0
  13. package/dist/react.d.ts +2 -0
  14. package/dist/react.js +23041 -0
  15. package/dist/react.js.map +1 -0
  16. package/dist/render-C78lIXeC.d.cts +2449 -0
  17. package/dist/render-C78lIXeC.d.ts +2449 -0
  18. package/examples/quick-start.md +88 -0
  19. package/package.json +79 -0
  20. package/src/anim/core/easing.ts +77 -0
  21. package/src/anim/core/timeline.ts +335 -0
  22. package/src/anim/core/types.ts +42 -0
  23. package/src/anim/index.ts +20 -0
  24. package/src/anim/react/index.ts +3 -0
  25. package/src/anim/react/useReducedMotion.ts +27 -0
  26. package/src/anim/react/useTimeline.ts +48 -0
  27. package/src/assert-never.ts +16 -0
  28. package/src/author-intent-verify.ts +587 -0
  29. package/src/builder.ts +3740 -0
  30. package/src/compile.ts +12 -0
  31. package/src/dom-verify-core.ts +121 -0
  32. package/src/dom-verify-types.ts +21 -0
  33. package/src/dom-verify.ts +948 -0
  34. package/src/event-handler/index.ts +184 -0
  35. package/src/formula/ast.ts +46 -0
  36. package/src/formula/evaluator.ts +163 -0
  37. package/src/formula/formula-computeds.ts +83 -0
  38. package/src/formula/index.ts +5 -0
  39. package/src/formula/parser.ts +399 -0
  40. package/src/index.ts +284 -0
  41. package/src/input-signals.ts +74 -0
  42. package/src/kinds/actor.tsx +79 -0
  43. package/src/kinds/card.tsx +61 -0
  44. package/src/kinds/chart-bar.tsx +121 -0
  45. package/src/kinds/chart-line.tsx +163 -0
  46. package/src/kinds/chart-pie.tsx +107 -0
  47. package/src/kinds/compact-title.ts +164 -0
  48. package/src/kinds/dyn-shape.tsx +394 -0
  49. package/src/kinds/event.tsx +70 -0
  50. package/src/kinds/function.tsx +53 -0
  51. package/src/kinds/funnel.tsx +122 -0
  52. package/src/kinds/gantt.tsx +193 -0
  53. package/src/kinds/generic.tsx +368 -0
  54. package/src/kinds/mind-map.tsx +367 -0
  55. package/src/kinds/mind-radial.tsx +209 -0
  56. package/src/kinds/node-tone.ts +18 -0
  57. package/src/kinds/quadrant.tsx +164 -0
  58. package/src/kinds/row-align.ts +179 -0
  59. package/src/kinds/shape-basement.tsx +683 -0
  60. package/src/kinds/shape-blockchain.tsx +750 -0
  61. package/src/kinds/shape-commerce.tsx +553 -0
  62. package/src/kinds/shape-finance.tsx +706 -0
  63. package/src/kinds/shape-hardware.tsx +862 -0
  64. package/src/kinds/shape-people.tsx +439 -0
  65. package/src/kinds/shape-region.tsx +383 -0
  66. package/src/kinds/shape-software.tsx +859 -0
  67. package/src/kinds/storage.tsx +180 -0
  68. package/src/kinds/text-width.ts +73 -0
  69. package/src/kinds/tree.tsx +275 -0
  70. package/src/kinds/user-journey.tsx +240 -0
  71. package/src/label-text.ts +71 -0
  72. package/src/layout/clearance-constants.ts +47 -0
  73. package/src/layout/collisions.ts +2078 -0
  74. package/src/layout/edges.ts +2498 -0
  75. package/src/layout/footer-shape.ts +97 -0
  76. package/src/layout/geometry.ts +135 -0
  77. package/src/layout/label-shift.ts +28 -0
  78. package/src/layout/lanes.ts +328 -0
  79. package/src/layout/nodes.ts +190 -0
  80. package/src/layout/predict-bbox.ts +76 -0
  81. package/src/layout/px-projection.ts +176 -0
  82. package/src/layout/spec.ts +872 -0
  83. package/src/layout/text-width.ts +133 -0
  84. package/src/layout/tokens.ts +181 -0
  85. package/src/layout/viewbox.ts +47 -0
  86. package/src/layout-with-validation.ts +175 -0
  87. package/src/layout.ts +381 -0
  88. package/src/presets.ts +2108 -0
  89. package/src/reactive/batch.ts +48 -0
  90. package/src/reactive/computed.ts +85 -0
  91. package/src/reactive/effect.ts +145 -0
  92. package/src/reactive/index.ts +6 -0
  93. package/src/reactive/internal.ts +109 -0
  94. package/src/reactive/signal.ts +113 -0
  95. package/src/render/edges.tsx +318 -0
  96. package/src/render/header.tsx +146 -0
  97. package/src/render/interactive-panel.tsx +9620 -0
  98. package/src/render/nodes.tsx +319 -0
  99. package/src/render/stage.tsx +377 -0
  100. package/src/render/tone.ts +64 -0
  101. package/src/render/utils.ts +238 -0
  102. package/src/render.tsx +221 -0
  103. package/src/scroll-trigger/index.ts +109 -0
  104. package/src/scroll-trigger/progress.ts +49 -0
  105. package/src/thumbnail.tsx +114 -0
  106. package/src/types.ts +2371 -0
  107. package/src/validate.ts +268 -0
  108. package/src/visual-validate.ts +4381 -0
@@ -0,0 +1,319 @@
1
+ import type { JSX } from "react";
2
+ import { ActorNode } from "../kinds/actor";
3
+ import { CardNode } from "../kinds/card";
4
+ import { EventNode } from "../kinds/event";
5
+ import { FunctionNode } from "../kinds/function";
6
+ import { StorageNode } from "../kinds/storage";
7
+ import { GenericNode } from "../kinds/generic";
8
+ import { DynShapeNode } from "../kinds/dyn-shape";
9
+ import { ChartLineNode } from "../kinds/chart-line";
10
+ import { ChartPieNode } from "../kinds/chart-pie";
11
+ import { ChartBarNode } from "../kinds/chart-bar";
12
+ import { GanttNode } from "../kinds/gantt";
13
+ import { MindMapNode } from "../kinds/mind-map";
14
+ import { MindRadialNode } from "../kinds/mind-radial";
15
+ import { FunnelNode } from "../kinds/funnel";
16
+ import { QuadrantNode } from "../kinds/quadrant";
17
+ import { TreeNode as TreeHierarchyNode } from "../kinds/tree";
18
+ import { UserJourneyNode } from "../kinds/user-journey";
19
+ import {
20
+ ShapeFileNode,
21
+ ShapeFolderNode,
22
+ ShapeCloudNode,
23
+ ShapeCylinderNode,
24
+ ShapeHexagonNode,
25
+ ShapeDiamondNode,
26
+ ShapeStackNode,
27
+ ShapePersonNode,
28
+ } from "../kinds/shape-basement";
29
+ import {
30
+ ShapeWindowNode,
31
+ ShapeTerminalNode,
32
+ ShapeCodeBlockNode,
33
+ ShapeKanbanCardNode,
34
+ ShapeMessageBubbleNode,
35
+ ShapeGearNode,
36
+ } from "../kinds/shape-software";
37
+ import {
38
+ ShapeServerRackNode,
39
+ ShapeNetworkNodeNode,
40
+ ShapeMobileDeviceNode,
41
+ ShapeIotSensorNode,
42
+ ShapeRobotArmNode,
43
+ ShapeSatelliteNode,
44
+ } from "../kinds/shape-hardware";
45
+ import {
46
+ ShapeSmartContractNode,
47
+ ShapeBlockchainBlockNode,
48
+ ShapeRpcNodeNode,
49
+ ShapeWalletNode,
50
+ ShapeNftNode,
51
+ ShapeTokenNode,
52
+ ShapeBlockchainNode,
53
+ ShapeBitcoinChainNode,
54
+ ShapeEthereumChainNode,
55
+ ShapeBlockchainNodeNode,
56
+ } from "../kinds/shape-blockchain";
57
+ import {
58
+ ShapeBankNode,
59
+ ShapeTrustBankNode,
60
+ ShapePaymentProviderNode,
61
+ ShapeCreditCardNode,
62
+ ShapeBrokerageNode,
63
+ ShapeExchangeNode,
64
+ ShapeAtmNode,
65
+ } from "../kinds/shape-finance";
66
+ import {
67
+ ShapeWebsiteNode,
68
+ ShapeStorefrontNode,
69
+ ShapeWarehouseNode,
70
+ ShapeOnlineShopNode,
71
+ ShapeCdnEdgeNode,
72
+ ShapeApiGatewayNode,
73
+ } from "../kinds/shape-commerce";
74
+ import {
75
+ ShapeAuditorNode,
76
+ ShapeRegulatorNode,
77
+ ShapeNotaryNode,
78
+ ShapeLawyerNode,
79
+ ShapeTraderNode,
80
+ ShapeCustomerServiceNode,
81
+ } from "../kinds/shape-people";
82
+ import type { LaidNode } from "../types";
83
+ import { interpolate, resolveNumericAttr } from "./utils";
84
+
85
+ export function CdlNodeView({
86
+ node,
87
+ active,
88
+ progress,
89
+ stateValues,
90
+ currentPhaseId,
91
+ }: {
92
+ node: LaidNode;
93
+ active: boolean;
94
+ progress: number;
95
+ stateValues: Record<string, string>;
96
+ currentPhaseId: string | undefined;
97
+ }): JSX.Element {
98
+ const value = node.value ? interpolate(node.value, stateValues) : undefined;
99
+ const rows = (node.rows ?? []).map((r) => interpolate(r, stateValues));
100
+ // visual binding = wBind / hBind の template を stateValues で resolve、 layout の
101
+ // static w/h を fallback として保持。 signal 値変化で node の描画寸法がリアルタイム変化する
102
+ // (arc-intro 相当の 「slider で bar が伸びる」 UX の foundation)。
103
+ const boundW = node.wBind ? resolveNumericAttr(node.wBind, stateValues, node.w) : node.w;
104
+ const boundH = node.hBind ? resolveNumericAttr(node.hBind, stateValues, node.h) : node.h;
105
+ const boundOpacity =
106
+ node.opacity !== undefined
107
+ ? Math.min(1, Math.max(0, resolveNumericAttr(node.opacity, stateValues, 1)))
108
+ : undefined;
109
+ // conditional visibility: visibleIf template を評価、 falsy or unresolved なら非表示
110
+ // (unresolved = `{missingSig}` そのままなら typo と判断、 fail-safe に hidden 側倒す)
111
+ if (node.visibleIf) {
112
+ const resolved = interpolate(node.visibleIf, stateValues).trim().toLowerCase();
113
+ const unresolved = /^\{\w+(?:[.\[][^}]*)?\}$/.test(resolved) || /\{\w+(?:[.\[][^}]*)?\}/.test(resolved);
114
+ const falsy = resolved === "" || resolved === "0" || resolved === "false" || resolved === "null" || resolved === "undefined" || resolved === "nan";
115
+ if (falsy || unresolved) {
116
+ return <g data-cdl-node={node.id} data-cdl-hidden="true" style={{ display: "none" }} />;
117
+ }
118
+ }
119
+ const resolvedNode: LaidNode = {
120
+ ...node,
121
+ title: interpolate(node.title, stateValues),
122
+ subtitle: node.subtitle ? interpolate(node.subtitle, stateValues) : node.subtitle,
123
+ eyebrow: node.eyebrow ? interpolate(node.eyebrow, stateValues) : node.eyebrow,
124
+ w: boundW,
125
+ h: boundH,
126
+ };
127
+ // storage の rows 数値ハイライト ... 「現在 phase に tween がある」 ときだけ
128
+ const highlightRows = active && currentPhaseId !== undefined;
129
+
130
+ // wrapper <g> に data-cdl-* attribute を付与 (dom-verify.ts の DOM scrape の足場)。
131
+ // data-cdl-node = node id、 data-cdl-kind = kind、 data-cdl-active = "true"/"false"、
132
+ // data-cdl-cx / data-cdl-cy / data-cdl-w / data-cdl-h = layout 計算値 (実 boundingBox と照合)
133
+ const inner = (() => {
134
+ switch (node.kind) {
135
+ case "dyn-rect":
136
+ case "dyn-circle":
137
+ case "dyn-arc":
138
+ case "dyn-wave":
139
+ case "dyn-polygon":
140
+ return <DynShapeNode node={resolvedNode} active={active} stateValues={stateValues} />;
141
+ case "actor":
142
+ return <ActorNode node={resolvedNode} active={active} value={value} />;
143
+ case "function":
144
+ return <FunctionNode node={resolvedNode} active={active} />;
145
+ case "storage":
146
+ return <StorageNode node={resolvedNode} active={active} rows={rows} highlightRows={highlightRows} />;
147
+ case "event":
148
+ return <EventNode node={resolvedNode} active={active} progress={progress} />;
149
+ case "card":
150
+ return <CardNode node={resolvedNode} active={active} />;
151
+ case "chart-line":
152
+ return <ChartLineNode node={resolvedNode} active={active} />;
153
+ case "chart-pie":
154
+ return <ChartPieNode node={resolvedNode} active={active} />;
155
+ case "chart-bar":
156
+ return <ChartBarNode node={resolvedNode} active={active} />;
157
+ case "gantt-timeline":
158
+ return <GanttNode node={resolvedNode} active={active} />;
159
+ case "mind-map":
160
+ return <MindMapNode node={resolvedNode} active={active} />;
161
+ case "mind-radial":
162
+ return <MindRadialNode node={resolvedNode} active={active} />;
163
+ case "funnel-stages":
164
+ return <FunnelNode node={resolvedNode} active={active} />;
165
+ case "quadrant-matrix":
166
+ return <QuadrantNode node={resolvedNode} active={active} />;
167
+ case "tree-hierarchy":
168
+ return <TreeHierarchyNode node={resolvedNode} active={active} />;
169
+ case "journey-map":
170
+ return <UserJourneyNode node={resolvedNode} active={active} />;
171
+ case "shape-file":
172
+ return <ShapeFileNode node={resolvedNode} active={active} />;
173
+ case "shape-folder":
174
+ return <ShapeFolderNode node={resolvedNode} active={active} />;
175
+ case "shape-cloud":
176
+ return <ShapeCloudNode node={resolvedNode} active={active} />;
177
+ case "shape-cylinder":
178
+ return <ShapeCylinderNode node={resolvedNode} active={active} />;
179
+ case "shape-hexagon":
180
+ return <ShapeHexagonNode node={resolvedNode} active={active} />;
181
+ case "shape-diamond":
182
+ return <ShapeDiamondNode node={resolvedNode} active={active} />;
183
+ case "shape-stack":
184
+ return <ShapeStackNode node={resolvedNode} active={active} />;
185
+ case "shape-person":
186
+ return <ShapePersonNode node={resolvedNode} active={active} />;
187
+ case "shape-window":
188
+ return <ShapeWindowNode node={resolvedNode} active={active} />;
189
+ case "shape-terminal":
190
+ return <ShapeTerminalNode node={resolvedNode} active={active} />;
191
+ case "shape-code-block":
192
+ return <ShapeCodeBlockNode node={resolvedNode} active={active} />;
193
+ case "shape-kanban-card":
194
+ return <ShapeKanbanCardNode node={resolvedNode} active={active} />;
195
+ case "shape-message-bubble":
196
+ return <ShapeMessageBubbleNode node={resolvedNode} active={active} />;
197
+ case "shape-gear":
198
+ return <ShapeGearNode node={resolvedNode} active={active} />;
199
+ case "shape-server-rack":
200
+ return <ShapeServerRackNode node={resolvedNode} active={active} />;
201
+ case "shape-network-node":
202
+ return <ShapeNetworkNodeNode node={resolvedNode} active={active} />;
203
+ case "shape-mobile-device":
204
+ return <ShapeMobileDeviceNode node={resolvedNode} active={active} />;
205
+ case "shape-iot-sensor":
206
+ return <ShapeIotSensorNode node={resolvedNode} active={active} />;
207
+ case "shape-robot-arm":
208
+ return <ShapeRobotArmNode node={resolvedNode} active={active} />;
209
+ case "shape-satellite":
210
+ return <ShapeSatelliteNode node={resolvedNode} active={active} />;
211
+ case "shape-smart-contract":
212
+ return <ShapeSmartContractNode node={resolvedNode} active={active} />;
213
+ case "shape-blockchain-block":
214
+ return <ShapeBlockchainBlockNode node={resolvedNode} active={active} />;
215
+ case "shape-rpc-node":
216
+ return <ShapeRpcNodeNode node={resolvedNode} active={active} />;
217
+ case "shape-wallet":
218
+ return <ShapeWalletNode node={resolvedNode} active={active} />;
219
+ case "shape-nft":
220
+ return <ShapeNftNode node={resolvedNode} active={active} />;
221
+ case "shape-token":
222
+ return <ShapeTokenNode node={resolvedNode} active={active} />;
223
+ case "shape-blockchain":
224
+ return <ShapeBlockchainNode node={resolvedNode} active={active} />;
225
+ case "shape-bitcoin-chain":
226
+ return <ShapeBitcoinChainNode node={resolvedNode} active={active} />;
227
+ case "shape-ethereum-chain":
228
+ return <ShapeEthereumChainNode node={resolvedNode} active={active} />;
229
+ case "shape-blockchain-node":
230
+ return <ShapeBlockchainNodeNode node={resolvedNode} active={active} />;
231
+ case "shape-bank":
232
+ return <ShapeBankNode node={resolvedNode} active={active} />;
233
+ case "shape-trust-bank":
234
+ return <ShapeTrustBankNode node={resolvedNode} active={active} />;
235
+ case "shape-payment-provider":
236
+ return <ShapePaymentProviderNode node={resolvedNode} active={active} />;
237
+ case "shape-credit-card":
238
+ return <ShapeCreditCardNode node={resolvedNode} active={active} />;
239
+ case "shape-brokerage":
240
+ return <ShapeBrokerageNode node={resolvedNode} active={active} />;
241
+ case "shape-exchange":
242
+ return <ShapeExchangeNode node={resolvedNode} active={active} />;
243
+ case "shape-atm":
244
+ return <ShapeAtmNode node={resolvedNode} active={active} />;
245
+ case "shape-website":
246
+ return <ShapeWebsiteNode node={resolvedNode} active={active} />;
247
+ case "shape-storefront":
248
+ return <ShapeStorefrontNode node={resolvedNode} active={active} />;
249
+ case "shape-warehouse":
250
+ return <ShapeWarehouseNode node={resolvedNode} active={active} />;
251
+ case "shape-online-shop":
252
+ return <ShapeOnlineShopNode node={resolvedNode} active={active} />;
253
+ case "shape-cdn-edge":
254
+ return <ShapeCdnEdgeNode node={resolvedNode} active={active} />;
255
+ case "shape-api-gateway":
256
+ return <ShapeApiGatewayNode node={resolvedNode} active={active} />;
257
+ case "shape-auditor":
258
+ return <ShapeAuditorNode node={resolvedNode} active={active} />;
259
+ case "shape-regulator":
260
+ return <ShapeRegulatorNode node={resolvedNode} active={active} />;
261
+ case "shape-notary":
262
+ return <ShapeNotaryNode node={resolvedNode} active={active} />;
263
+ case "shape-lawyer":
264
+ return <ShapeLawyerNode node={resolvedNode} active={active} />;
265
+ case "shape-trader":
266
+ return <ShapeTraderNode node={resolvedNode} active={active} />;
267
+ case "shape-customer-service":
268
+ return <ShapeCustomerServiceNode node={resolvedNode} active={active} />;
269
+ default:
270
+ // 新 NodeKind 25 種は GenericNode で汎用描画 (kind 別 icon / color / shape)
271
+ return <GenericNode node={resolvedNode} active={active} value={node.value} stateValues={stateValues} />;
272
+ }
273
+ })();
274
+ // node bounding box を node.w/h に固定するための invisible rect。
275
+ // cloud kind の 5 circle 重ねや diamond / cylinder のような特殊 shape では、
276
+ // <g> の getBoundingClientRect() が shape の実 outline に追従して node.w/h と乖離する。
277
+ // 透明 rect を node bbox 範囲ぴったりに置くことで <g> の bbox を node.w/h に anchor する。
278
+ // render-time offset: layout 計算後の position を X/Y shift、 edges は base position 参照
279
+ // (radial 配置 / free-form 移動用、 signal template で reactive 変化も可能)
280
+ const offsetX = node.renderOffsetX !== undefined ? resolveNumericAttr(node.renderOffsetX, stateValues, 0) : 0;
281
+ const offsetY = node.renderOffsetY !== undefined ? resolveNumericAttr(node.renderOffsetY, stateValues, 0) : 0;
282
+ const hasOffset = offsetX !== 0 || offsetY !== 0;
283
+ return (
284
+ <g
285
+ data-cdl-node={node.id}
286
+ data-cdl-kind={node.kind}
287
+ data-cdl-lane={node.lane}
288
+ data-cdl-active={active ? "true" : "false"}
289
+ data-cdl-cx={node.cx}
290
+ data-cdl-cy={node.cy}
291
+ data-cdl-w={node.w}
292
+ data-cdl-h={node.h}
293
+ data-cdl-title={resolvedNode.title}
294
+ data-cdl-subtitle={resolvedNode.subtitle ?? ""}
295
+ data-cdl-eyebrow={resolvedNode.eyebrow ?? ""}
296
+ data-cdl-offset-x={offsetX || undefined}
297
+ data-cdl-offset-y={offsetY || undefined}
298
+ transform={hasOffset ? `translate(${offsetX}, ${offsetY})` : undefined}
299
+ opacity={boundOpacity}
300
+ data-cdl-tone={node.tone}
301
+ style={{ transition: "opacity 120ms ease-out, transform 200ms ease-out" }}
302
+ >
303
+ <rect
304
+ // 実寸の枠 (#390)。 `data-cdl-w/h` は layout の静的値で、 `wBind` / `hBind` の縮小や
305
+ // `renderOffsetX/Y` の移動を含まない。 実 DOM で「行が枠に収まっているか」 を測る側は
306
+ // この要素を見る。
307
+ data-cdl-frame=""
308
+ x={resolvedNode.cx - resolvedNode.w / 2}
309
+ y={resolvedNode.cy - resolvedNode.h / 2}
310
+ width={resolvedNode.w}
311
+ height={resolvedNode.h}
312
+ fill="none"
313
+ stroke="none"
314
+ pointerEvents="none"
315
+ />
316
+ {inner}
317
+ </g>
318
+ );
319
+ }