@statewalker/fsm-charts 0.0.2 → 0.0.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.
@@ -1,437 +0,0 @@
1
- import { getPadding } from './chunk-NXWOFQMO.js';
2
-
3
- // src/svg/buildStatechartCss.ts
4
- function buildStatechartCss({ prefix = "" } = {}) {
5
- return `
6
- --state--fill: white;
7
- --state--stroke-color: silver;
8
- --state--stroke-width: 1px;
9
-
10
- --state-initial--fill: var(--state--stroke-color, silver);
11
- --state-initial--stroke-color: var(--state--stroke-color, none);
12
- --state-initial--stroke-width: var(--state--stroke-width, 0);
13
-
14
- --state-final--fill: var(--state--fill, white);
15
- --state-final--stroke-color: var(--state--stroke-color, silver);
16
- --state-final--stroke-width: var(--state--stroke-width, 1px);
17
-
18
- --state-label--color: gray;
19
- --state-label--font-size: 14px;
20
- --state-label--font-family: sans-serif;
21
-
22
- --transition--fill: rgba(255,255,255,0.7);
23
- --transition--stroke-color: none;
24
- --transition--stroke-width: 1;
25
-
26
- --transition-line--stroke-color: silver;
27
- --transition-line--stroke-width: 1px;
28
-
29
- --transition-label--color: gray;
30
- --transition-label--font-size: 12px;
31
- --transition-label--font-family: sans-serif;
32
-
33
- --transition-marker--fill: var(--transition-line--stroke-color, gray);
34
-
35
- .state-details {
36
-
37
- }
38
-
39
- .state-details {
40
- background-color: var(--state--fill, white);
41
- border: var(--state--stroke-width, 1px) solid var(--state--stroke-color, silver);
42
- border-radius: 0.5em;
43
- padding: 0.5em;
44
- }
45
-
46
- .state-details .state-label {
47
- cursor: pointer;
48
- color: var(--transition-label--color, gray);
49
- font-family: var(--state-label--font-family, sans-serif);
50
- font-size: var(--state-label--font-size, 14px);
51
- }
52
- .state-details .state-description {
53
- display: flex;
54
- flex-direction: column;
55
- gap: 0.5em;
56
- }
57
- .state-details .state-chart-container {
58
- max-width: 100%;
59
- overflow: auto;
60
- scrollbar-width: thin;
61
- }
62
-
63
- .state-details .statechart {
64
-
65
- }
66
-
67
- .state-details .statechart .transition-marker {
68
- fill : var(--transition-marker--fill, silver);
69
- }
70
-
71
- .state-details .statechart .transitions {
72
- }
73
-
74
- .state-details .statechart .transitions .transition .transition-line {
75
- stroke: var(--transition-line--stroke-color, silver);
76
- stroke-width: var(--transition-line--stroke-width, 1px);
77
- }
78
-
79
- .state-details .statechart .transitions .transition .transition-box {
80
- fill: var(--transition--fill, rgba(255,255,255,0.7));
81
- stroke: var(--transition--stroke-color, none);
82
- stroke-width: var(--transition--stroke-width, 1);
83
- border-radius: 0.5em;
84
- }
85
-
86
- .state-details .statechart .transitions .transition .transition-label {
87
- fill: var(--transition-label--color, gray);
88
- font-size: var(--transition-label--font-size, 12px);
89
- font-family: var(--transition-label--font-family, sans-serif);
90
- }
91
-
92
- /* ------------------------------------------ */
93
- .state-details .statechart .states .state {
94
- }
95
- .state-details .statechart .states .state .state-box {
96
- fill: var(--state--fill, white);
97
- stroke: var(--state--stroke-color, silver);
98
- stroke-width: var(--state--stroke-width, 1px);
99
- border-radius: 0.5em;
100
- }
101
- .state-details .statechart .states .state .state-initial {
102
- fill: var(--state-initial--fill, gray);
103
- stroke: var(--state-initial--stroke-color, none);
104
- stroke-width: var(--state-initial--stroke-width, 0);
105
- }
106
- .state-details .statechart .states .state .state-final {
107
- fill: var(--state-final--fill, white);
108
- stroke: var(--state-final--stroke-color, silver);
109
- stroke-width: var(--state-final--stroke-width, 2);
110
- }
111
- .state-details .statechart .states .state .state-final.inner {
112
- fill: var(--state-final--stroke-color, silver);
113
- stroke: none;
114
- stroke-width: 0;
115
- }
116
- .state-details .statechart .states .state .state-label {
117
- fill: var(--state-label--color, gray);
118
- font-size: var(--state-label--font-size, 14px);
119
- font-family: var(--state-label--font-family, sans-serif);
120
- }
121
-
122
- `;
123
- }
124
-
125
- // src/utils/serializeAttrs.ts
126
- function serializeAttrs(attrs = {}, {
127
- prefix = "",
128
- transform = false
129
- } = {}) {
130
- const result = [];
131
- for (const [key, value] of Object.entries(attrs || {}).sort(
132
- ([a], [b]) => a > b ? 1 : -1
133
- )) {
134
- if (value === void 0 || value === null || value === "")
135
- continue;
136
- result.push(
137
- `${prefix}${escapeValue(key)}${"=" + JSON.stringify(escapeValue(transform ? toKebabCase(value) : value))}`
138
- );
139
- }
140
- return result.join(" ");
141
- function escapeValue(value) {
142
- return String(value).replaceAll(/</gim, "&lt;").replaceAll(/>/gim, "&gt;").replaceAll(/"/gim, "&qout;");
143
- }
144
- }
145
-
146
- // src/utils/BasisCurve.ts
147
- var BasisCurve = class {
148
- _context;
149
- _x0 = 0;
150
- _y0 = 0;
151
- _x1 = 0;
152
- _y1 = 0;
153
- _point = 0;
154
- _line = 0;
155
- constructor(context) {
156
- this._context = context;
157
- }
158
- $point(x, y) {
159
- this._context.bezierCurveTo(
160
- (2 * this._x0 + this._x1) / 3,
161
- (2 * this._y0 + this._y1) / 3,
162
- (this._x0 + 2 * this._x1) / 3,
163
- (this._y0 + 2 * this._y1) / 3,
164
- (this._x0 + 4 * this._x1 + x) / 6,
165
- (this._y0 + 4 * this._y1 + y) / 6
166
- );
167
- }
168
- areaStart() {
169
- this._line = 0;
170
- }
171
- areaEnd() {
172
- this._line = NaN;
173
- }
174
- lineStart() {
175
- this._x0 = this._x1 = this._y0 = this._y1 = NaN;
176
- this._point = 0;
177
- }
178
- lineEnd() {
179
- switch (this._point) {
180
- case 3:
181
- this.$point(this._x1, this._y1);
182
- case 2:
183
- this._context.lineTo(this._x1, this._y1);
184
- break;
185
- }
186
- if (this._line || this._line !== 0 && this._point === 1)
187
- this._context.closePath();
188
- this._line = 1 - this._line;
189
- }
190
- point(x, y) {
191
- x = +x, y = +y;
192
- switch (this._point) {
193
- case 0:
194
- this._point = 1;
195
- this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y);
196
- break;
197
- case 1:
198
- this._point = 2;
199
- break;
200
- case 2:
201
- this._point = 3;
202
- this._context.lineTo(
203
- (5 * this._x0 + this._x1) / 6,
204
- (5 * this._y0 + this._y1) / 6
205
- );
206
- default:
207
- this.$point(x, y);
208
- break;
209
- }
210
- this._x0 = this._x1, this._x1 = x;
211
- this._y0 = this._y1, this._y1 = y;
212
- }
213
- };
214
-
215
- // src/svg/buildStatechartSvg.ts
216
- function getBoxParams({
217
- x,
218
- y,
219
- width,
220
- height,
221
- padding = 0
222
- }) {
223
- const [top, right, bottom, left] = getPadding(padding);
224
- const h = Math.ceil(height - top - bottom);
225
- return {
226
- x: x + left,
227
- y: y - bottom - h,
228
- width: Math.ceil(width - left - right),
229
- height: h
230
- };
231
- }
232
- function buildStatechartSvg({
233
- graph: { width, height, nodes, edges },
234
- newId,
235
- stateFontSize = 14,
236
- transitionFontSize = 12,
237
- println,
238
- initialStateKey = "<initial>",
239
- finalStateKey = "<final>"
240
- }) {
241
- width = Math.ceil(width);
242
- height = Math.ceil(height);
243
- println(
244
- `<svg ${serializeAttrs({
245
- class: "statechart",
246
- width,
247
- height,
248
- viewbox: `0 0 ${width} ${height}`,
249
- xmlns: "http://www.w3.org/2000/svg"
250
- })}>`
251
- );
252
- println(`<g class="transitions">`);
253
- const markerAttrs = serializeAttrs({
254
- refX: 19,
255
- refY: 7,
256
- markerWidth: 20,
257
- markerHeight: 14,
258
- orient: "auto",
259
- class: "transition-marker",
260
- stroke: "none",
261
- fill: "currentColor"
262
- });
263
- for (const edge of edges) {
264
- const { id, points, event: text } = edge;
265
- println(` <g class="transition" data-transition-id="${id}">`);
266
- const markerId = newId("marker");
267
- println(` <defs>`);
268
- println(` <marker id="${markerId}" ${markerAttrs}>`);
269
- println(` <path d="M 19,7 L9,13 L14,7 L9,1 Z"></path>`);
270
- println(` </marker>`);
271
- println(` </defs>`);
272
- const path = [];
273
- const round = (...n) => n.map(Math.round);
274
- const base = new BasisCurve({
275
- bezierCurveTo(x0, y0, x1, y1, x2, y2) {
276
- path.push("C" + round(x0, y0, x1, y1, x2, y2).join(","));
277
- },
278
- moveTo(x, y) {
279
- path.push("M" + round(x, y).join(","));
280
- },
281
- lineTo(x, y) {
282
- path.push("L" + round(x, y).join(","));
283
- },
284
- closePath() {
285
- path.push("Z");
286
- }
287
- });
288
- base.lineStart();
289
- for (const point of points) {
290
- base.point(point.x, point.y);
291
- }
292
- base.lineEnd();
293
- const serializedAttrs = serializeAttrs({
294
- class: "transition-line",
295
- "transition-id": id,
296
- fill: "none",
297
- stroke: "currentColor",
298
- strokeWidth: "1px",
299
- d: path.join(""),
300
- "marker-end": `url(#${markerId})`
301
- });
302
- println(` <path ${serializedAttrs} />`);
303
- if (text) {
304
- const { x, y, width: width2, height: height2 } = getBoxParams({
305
- ...edge,
306
- padding: 0
307
- });
308
- const rectAttrs = serializeAttrs({
309
- x,
310
- y: y - transitionFontSize,
311
- width: width2,
312
- height: height2,
313
- rx: Math.ceil(transitionFontSize / 2),
314
- ry: Math.ceil(transitionFontSize / 2),
315
- fill: "rgba(255,255,255,0.7)",
316
- stroke: "none",
317
- strokeWidth: "1",
318
- class: "transition-box"
319
- });
320
- println(` <rect ${rectAttrs} />`);
321
- const textAttrs = serializeAttrs({
322
- class: "transition-label",
323
- "text-anchor": "middle",
324
- fill: "currentColor",
325
- x: Math.round(x + width2 / 2),
326
- y: Math.round(y + height2 / 2 - transitionFontSize / 2)
327
- });
328
- println(` <text ${textAttrs}>${text}</text>`);
329
- }
330
- println(` </g>`);
331
- }
332
- println("</g>");
333
- const shift = stateFontSize / 4;
334
- const initialStateRadius = 6;
335
- const finalStateRadius = initialStateRadius / 2;
336
- println(`<g class="states">`);
337
- for (const node of nodes) {
338
- const { key, id, state: text } = node;
339
- const { x, y, width: width2, height: height2 } = getBoxParams({ ...node, padding: shift });
340
- println(` <g class="state" data-state-id="${id}">`);
341
- if (key === initialStateKey || key === finalStateKey) {
342
- const cx = Math.round(x + width2 / 2);
343
- const cy = Math.round(y + height2 / 2);
344
- if (key === initialStateKey) {
345
- const serializedAttrs = serializeAttrs({
346
- class: "state-initial",
347
- cx,
348
- cy,
349
- r: initialStateRadius,
350
- fill: "none",
351
- stroke: "currentColor",
352
- strokeWidth: "2"
353
- });
354
- println(` <circle ${serializedAttrs} />`);
355
- } else {
356
- let serializedAttrs = serializeAttrs({
357
- class: "state-final",
358
- cx,
359
- cy,
360
- r: initialStateRadius,
361
- fill: "none",
362
- stroke: "currentColor",
363
- strokeWidth: 2
364
- });
365
- println(` <circle ${serializedAttrs} />`);
366
- serializedAttrs = serializeAttrs({
367
- class: "state-final inner",
368
- cx,
369
- cy,
370
- r: finalStateRadius,
371
- fill: "currentColor",
372
- stroke: "none",
373
- strokeWidth: 0
374
- });
375
- println(` <circle ${serializedAttrs} />`);
376
- }
377
- } else {
378
- const rectAttrs = serializeAttrs({
379
- x,
380
- y,
381
- width: width2,
382
- height: height2,
383
- rx: Math.ceil(stateFontSize / 2),
384
- ry: Math.ceil(stateFontSize / 2),
385
- fill: "none",
386
- stroke: "currentColor",
387
- strokeWidth: "2",
388
- class: "state-box"
389
- });
390
- println(` <rect ${rectAttrs} />`);
391
- const textAttrs = serializeAttrs({
392
- class: "state-label",
393
- "text-anchor": "middle",
394
- fill: "currentColor",
395
- x: Math.round(x + width2 / 2),
396
- y: Math.round(y + height2 / 2 + stateFontSize / 4),
397
- "data-state-id": id
398
- });
399
- println(` <text ${textAttrs}>${text}</text>`);
400
- }
401
- println(" </g>");
402
- }
403
- println("</g>");
404
- println("</svg>");
405
- }
406
-
407
- // src/svg/buildStatechartsPanel.ts
408
- function buildStatechartsPanel({
409
- statechart,
410
- newId,
411
- println,
412
- initialStateKey = "<initial>",
413
- finalStateKey = "<final>"
414
- }) {
415
- render(statechart, println);
416
- function render(statechart2, println2) {
417
- println2(`<details class="state-details" data-state-id="${statechart2.id}">`);
418
- println2(` <summary class="state-label">${statechart2.key}</summary>`);
419
- println2(` <div class="state-description"><div class="state-chart-container">`);
420
- const printChildren = (str) => println2(` ${str}`);
421
- buildStatechartSvg({
422
- graph: statechart2.graph,
423
- newId,
424
- println: printChildren,
425
- initialStateKey,
426
- finalStateKey
427
- });
428
- println2(` </div>`);
429
- for (const child of statechart2.children || []) {
430
- render(child, printChildren);
431
- }
432
- println2(` </div>`);
433
- println2(`</details>`);
434
- }
435
- }
436
-
437
- export { buildStatechartCss, buildStatechartSvg, buildStatechartsPanel };