@statewalker/fsm-charts 0.0.3 → 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.
@@ -2564,7 +2564,7 @@ function buildCharts({
2564
2564
  finalStateKey = "<final>"
2565
2565
  }) {
2566
2566
  return buildChart(config);
2567
- function buildChart(config2, id = newId("state")) {
2567
+ function buildChart(config2, id = newId("s")) {
2568
2568
  const graph = buildFlatCharts({
2569
2569
  lodash,
2570
2570
  transitions: config2.transitions,
@@ -0,0 +1,529 @@
1
+ import { getPadding } from './chunk-NXWOFQMO.js';
2
+
3
+ // src/utils/toKebabCase.ts
4
+ function toKebabCase2(str) {
5
+ str = str.trim().replace(/\s+/gim, "-");
6
+ str = str.replace(
7
+ /([^A-Z]?)([A-Z])/g,
8
+ (_, a, b) => a.toLowerCase() + "-" + b.toLowerCase()
9
+ );
10
+ return str;
11
+ }
12
+
13
+ // src/utils/serializeCss.ts
14
+ function serializeCss(obj) {
15
+ return visitStyle(obj).join("\n");
16
+ function visitStyle(obj2, lines = [], prefixes = [""]) {
17
+ for (const [key, style] of Object.entries(obj2)) {
18
+ const selectors = [];
19
+ for (const sel of key.split(",").map((_) => _.trim())) {
20
+ for (const prefix of prefixes) {
21
+ const selector = sel.replace(
22
+ /^(.)/,
23
+ (_, ch) => ch === "&" ? prefix : prefix.length > 0 ? prefix + " " + ch : ch
24
+ );
25
+ selectors.push(selector);
26
+ }
27
+ }
28
+ const selectorRules = [];
29
+ const extensions = [];
30
+ for (let [key2, value] of Object.entries(style)) {
31
+ if (typeof value === "object") {
32
+ visitStyle({ [key2]: value }, extensions, selectors);
33
+ } else {
34
+ key2 = toKebabCase2(key2);
35
+ selectorRules.push(` ${key2}: ${value};`);
36
+ }
37
+ }
38
+ if (selectorRules.length) {
39
+ lines.push(`${selectors.join(",\n")} {`);
40
+ lines.push(...selectorRules);
41
+ lines.push(`}`);
42
+ }
43
+ lines.push(...extensions);
44
+ }
45
+ return lines;
46
+ }
47
+ }
48
+
49
+ // src/svg/buildStatechartStyles.ts
50
+ function buildStateDetailsStyle() {
51
+ return {
52
+ ".state-details": {
53
+ backgroundColor: "var(--state-background-color, white)",
54
+ border: "var(--state-border-width, 1px) solid var(--state-border-color, currentColor)",
55
+ borderRadius: "0.5em",
56
+ padding: "0.5em"
57
+ },
58
+ ".state-details__label": {
59
+ cursor: "pointer",
60
+ color: "var(--transition-label-color, currentColor)",
61
+ fontFamily: "var(--state-label-font-family, sans-serif)",
62
+ fontSize: "var(--state-label-font-size, 14px)"
63
+ },
64
+ ".state-details__description": {
65
+ display: "flex",
66
+ flexDirection: "column",
67
+ gap: "0.5em"
68
+ },
69
+ ".state-details__chart": {
70
+ maxWidth: "100%",
71
+ overflow: "auto",
72
+ scrollbarWidth: "thin"
73
+ },
74
+ //
75
+ ".state-details--selected": {
76
+ backgroundColor: "var(--state-selected-background-color, white)",
77
+ border: "var(--state-selected-border-width, 1px) solid var(--state-selected-border-color, currentColor)"
78
+ },
79
+ ".state-details__label--selected": {
80
+ color: "var(--state-selected-label-color)"
81
+ }
82
+ };
83
+ }
84
+ function buildStatechartStyles({
85
+ root = ":root"
86
+ } = {}) {
87
+ return {
88
+ [root]: {
89
+ // --------------------------------------
90
+ // Normal states
91
+ "--state-background-color": "white",
92
+ "--state-border-color": "silver",
93
+ "--state-border-width": "1px",
94
+ "--state-label-color": "gray",
95
+ "--state-label-font-size": "14px",
96
+ "--state-label-font-family": "sans-serif",
97
+ // Selected states
98
+ "--state-selected-background-color": "#eee",
99
+ "--state-selected-border-color": "red",
100
+ "--state-selected-border-width": "2px",
101
+ "--state-selected-label-color": "red",
102
+ // --------------------------------------
103
+ // Normal transitions
104
+ "--transition-background-color": "rgba(255,255,255,0.7)",
105
+ "--transition-border-color": "none",
106
+ "--transition-border-width": "1px",
107
+ "--transition-line-color": "silver",
108
+ "--transition-line-width": "1px",
109
+ "--transition-label-color": "gray",
110
+ "--transition-label-font-size": "12px",
111
+ "--transition-label-font-family": "sans-serif",
112
+ // --------------------------------------
113
+ // Selected transitions
114
+ "--transition-selected-background-color": "#eee",
115
+ "--transition-selected-border-color": "none",
116
+ "--transition-selected-border-width": "0",
117
+ "--transition-selected-line-color": "red",
118
+ "--transition-selected-line-width": "1px",
119
+ "--transition-selected-label-color": "red",
120
+ // --------------------------------------
121
+ // --------------------------------------
122
+ ...buildStateDetailsStyle(),
123
+ ".transition": {},
124
+ ".transition--selected": {
125
+ "--transition-background-color": "var(--transition-selected-background-color)",
126
+ "--transition-border-color": "var(--transition-selected-border-color)",
127
+ "--transition-border-width": "var(--transition-selected-border-width)",
128
+ "--transition-line-color": "var(--transition-selected-line-color)",
129
+ "--transition-line-width": "var(--transition-selected-line-width)",
130
+ "--transition-label-color": "var(--transition-selected-label-color)"
131
+ },
132
+ ".transition__marker": {
133
+ fill: "var(--transition-line-color, currentColor)",
134
+ stroke: "none"
135
+ },
136
+ ".transition__line": {
137
+ stroke: "var(--transition-line-color, currentColor)",
138
+ strokeWidth: "var(--transition-line-width, 1px)"
139
+ },
140
+ ".transition__box": {
141
+ fill: "var(--transition-background-color, rgba(255,255,255,0.7))",
142
+ stroke: "var(--transition-border-color, none)",
143
+ strokeWidth: "var(--transition-border-width, 1px)",
144
+ borderRadius: "0.5em"
145
+ },
146
+ ".transition__label": {
147
+ fill: "var(--transition-label-color, currentColor)",
148
+ fontSize: "var(--transition-label-font-size, 12px)",
149
+ fontFamily: "var(--transition-label-font-family, sans-serif)"
150
+ },
151
+ // ----------------------------------------------
152
+ // States
153
+ ".state": {},
154
+ ".state--selected": {
155
+ "--state-background-color": "var(--state-selected-background-color)",
156
+ "--state-border-color": "var(--state-selected-border-color)",
157
+ "--state-border-width": "var(--state-selected-border-width)",
158
+ "--state-label-color": "var(--state-selected-label-color)"
159
+ },
160
+ // --------------------------
161
+ // Panels
162
+ ".state__details": {
163
+ backgroundColor: "var(--state-background-color, white)",
164
+ border: "var(--state-border-width, 1px) solid var(--state-border-color, currentColor)",
165
+ borderRadius: "0.5em",
166
+ padding: "0.5em"
167
+ },
168
+ ".state__description": {
169
+ display: "flex",
170
+ flexDirection: "column",
171
+ gap: "0.5em"
172
+ },
173
+ ".state__chart-container": {
174
+ maxWidth: "100%",
175
+ overflow: "auto",
176
+ scrollbarWidth: "thin"
177
+ },
178
+ // --------------------------
179
+ // Statecharts
180
+ ".state__box": {
181
+ fill: "var(--state-background-color, white)",
182
+ stroke: "var(--state-border-color, currentColor)",
183
+ strokeWidth: "var(--state-border-width, 1px)",
184
+ borderRadius: "0.5em"
185
+ },
186
+ ".state__label": {
187
+ color: "var(--state-label-color, currentColor)",
188
+ fill: "var(--state-label-color, currentColor)",
189
+ fontSize: "var(--state-label-font-size, 14px)",
190
+ fontFamily: "var(--state-label-font-family, sans-serif)",
191
+ cursor: "pointer"
192
+ },
193
+ ".state__initial": {
194
+ fill: "var(--state-border-color, currentColor)",
195
+ stroke: "var(--state-border-color, currentColor)",
196
+ strokeWidth: "var(--state-border-width, 2px)"
197
+ },
198
+ ".state__final": {
199
+ fill: "white",
200
+ stroke: "var(--state-border-color, currentColor)",
201
+ strokeWidth: "var(--state-border-width, 2px)",
202
+ // ---------------------------
203
+ "&.state__final--inner": {
204
+ fill: "var(--state-border-color, currentColor)",
205
+ stroke: "none",
206
+ strokeWidth: "0"
207
+ }
208
+ }
209
+ }
210
+ };
211
+ }
212
+
213
+ // src/svg/buildStatechartCss.ts
214
+ function buildStatechartCss({ prefix = "" } = {}) {
215
+ const cssObject = buildStatechartStyles({ root: prefix || ":root" });
216
+ return serializeCss(cssObject);
217
+ }
218
+
219
+ // src/utils/serializeAttrs.ts
220
+ function serializeAttrs(attrs = {}, {
221
+ prefix = "",
222
+ transform = false
223
+ } = {}) {
224
+ const result = [];
225
+ for (const [key, value] of Object.entries(attrs || {}).sort(
226
+ ([a], [b]) => a > b ? 1 : -1
227
+ )) {
228
+ if (value === void 0 || value === null || value === "")
229
+ continue;
230
+ result.push(
231
+ `${prefix}${escapeValue(key)}${"=" + JSON.stringify(escapeValue(transform ? toKebabCase(value) : value))}`
232
+ );
233
+ }
234
+ return result.join(" ");
235
+ function escapeValue(value) {
236
+ return String(value).replaceAll(/</gim, "&lt;").replaceAll(/>/gim, "&gt;").replaceAll(/"/gim, "&qout;");
237
+ }
238
+ }
239
+
240
+ // src/utils/BasisCurve.ts
241
+ var BasisCurve = class {
242
+ _context;
243
+ _x0 = 0;
244
+ _y0 = 0;
245
+ _x1 = 0;
246
+ _y1 = 0;
247
+ _point = 0;
248
+ _line = 0;
249
+ constructor(context) {
250
+ this._context = context;
251
+ }
252
+ $point(x, y) {
253
+ this._context.bezierCurveTo(
254
+ (2 * this._x0 + this._x1) / 3,
255
+ (2 * this._y0 + this._y1) / 3,
256
+ (this._x0 + 2 * this._x1) / 3,
257
+ (this._y0 + 2 * this._y1) / 3,
258
+ (this._x0 + 4 * this._x1 + x) / 6,
259
+ (this._y0 + 4 * this._y1 + y) / 6
260
+ );
261
+ }
262
+ areaStart() {
263
+ this._line = 0;
264
+ }
265
+ areaEnd() {
266
+ this._line = NaN;
267
+ }
268
+ lineStart() {
269
+ this._x0 = this._x1 = this._y0 = this._y1 = NaN;
270
+ this._point = 0;
271
+ }
272
+ lineEnd() {
273
+ switch (this._point) {
274
+ case 3:
275
+ this.$point(this._x1, this._y1);
276
+ case 2:
277
+ this._context.lineTo(this._x1, this._y1);
278
+ break;
279
+ }
280
+ if (this._line || this._line !== 0 && this._point === 1)
281
+ this._context.closePath();
282
+ this._line = 1 - this._line;
283
+ }
284
+ point(x, y) {
285
+ x = +x, y = +y;
286
+ switch (this._point) {
287
+ case 0:
288
+ this._point = 1;
289
+ this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y);
290
+ break;
291
+ case 1:
292
+ this._point = 2;
293
+ break;
294
+ case 2:
295
+ this._point = 3;
296
+ this._context.lineTo(
297
+ (5 * this._x0 + this._x1) / 6,
298
+ (5 * this._y0 + this._y1) / 6
299
+ );
300
+ default:
301
+ this.$point(x, y);
302
+ break;
303
+ }
304
+ this._x0 = this._x1, this._x1 = x;
305
+ this._y0 = this._y1, this._y1 = y;
306
+ }
307
+ };
308
+
309
+ // src/svg/buildStatechartSvg.ts
310
+ function getBoxParams({
311
+ x,
312
+ y,
313
+ width,
314
+ height,
315
+ padding = 0
316
+ }) {
317
+ const [top, right, bottom, left] = getPadding(padding);
318
+ const h = Math.ceil(height - top - bottom);
319
+ return {
320
+ x: x + left,
321
+ y: y - bottom - h,
322
+ width: Math.ceil(width - left - right),
323
+ height: h
324
+ };
325
+ }
326
+ function buildStatechartSvg({
327
+ graph: { width, height, nodes, edges },
328
+ newId,
329
+ stateFontSize = 14,
330
+ transitionFontSize = 12,
331
+ println,
332
+ initialStateKey = "<initial>",
333
+ finalStateKey = "<final>"
334
+ }) {
335
+ width = Math.ceil(width);
336
+ height = Math.ceil(height);
337
+ println(
338
+ `<svg ${serializeAttrs({
339
+ class: "statechart",
340
+ width,
341
+ height,
342
+ viewbox: `0 0 ${width} ${height}`,
343
+ xmlns: "http://www.w3.org/2000/svg"
344
+ })}>`
345
+ );
346
+ println(`<g class="statechart__transitions">`);
347
+ const markerAttrs = serializeAttrs({
348
+ refX: 19,
349
+ refY: 7,
350
+ markerWidth: 20,
351
+ markerHeight: 14,
352
+ orient: "auto",
353
+ class: "transition__marker",
354
+ stroke: "none",
355
+ fill: "currentColor"
356
+ });
357
+ for (const edge of edges) {
358
+ const { id, points, event: text } = edge;
359
+ println(` <g class="transition" data-transition-id="${id}">`);
360
+ const markerId = newId("marker");
361
+ println(` <defs>`);
362
+ println(` <marker id="${markerId}" ${markerAttrs}>`);
363
+ println(` <path d="M 19,7 L9,13 L14,7 L9,1 Z"></path>`);
364
+ println(` </marker>`);
365
+ println(` </defs>`);
366
+ const path = [];
367
+ const round = (...n) => n.map(Math.round);
368
+ const base = new BasisCurve({
369
+ bezierCurveTo(x0, y0, x1, y1, x2, y2) {
370
+ path.push("C" + round(x0, y0, x1, y1, x2, y2).join(","));
371
+ },
372
+ moveTo(x, y) {
373
+ path.push("M" + round(x, y).join(","));
374
+ },
375
+ lineTo(x, y) {
376
+ path.push("L" + round(x, y).join(","));
377
+ },
378
+ closePath() {
379
+ path.push("Z");
380
+ }
381
+ });
382
+ base.lineStart();
383
+ for (const point of points) {
384
+ base.point(point.x, point.y);
385
+ }
386
+ base.lineEnd();
387
+ const serializedAttrs = serializeAttrs({
388
+ class: "transition__line",
389
+ fill: "none",
390
+ stroke: "currentColor",
391
+ strokeWidth: "1px",
392
+ d: path.join(""),
393
+ "marker-end": `url(#${markerId})`
394
+ });
395
+ println(` <path ${serializedAttrs} />`);
396
+ if (text) {
397
+ const { x, y, width: width2, height: height2 } = getBoxParams({
398
+ ...edge,
399
+ padding: 0
400
+ });
401
+ const rectAttrs = serializeAttrs({
402
+ x,
403
+ y: y - transitionFontSize,
404
+ width: width2,
405
+ height: height2,
406
+ rx: Math.ceil(transitionFontSize / 2),
407
+ ry: Math.ceil(transitionFontSize / 2),
408
+ fill: "rgba(255,255,255,0.7)",
409
+ stroke: "none",
410
+ strokeWidth: "1",
411
+ class: "transition__box"
412
+ });
413
+ println(` <rect ${rectAttrs} />`);
414
+ const textAttrs = serializeAttrs({
415
+ class: "transition__label",
416
+ "text-anchor": "middle",
417
+ fill: "currentColor",
418
+ x: Math.round(x + width2 / 2),
419
+ y: Math.round(y + height2 / 2 - transitionFontSize / 2)
420
+ });
421
+ println(` <text ${textAttrs}>${text}</text>`);
422
+ }
423
+ println(` </g>`);
424
+ }
425
+ println("</g>");
426
+ const shift = stateFontSize / 4;
427
+ const initialStateRadius = 6;
428
+ const finalStateRadius = initialStateRadius / 2;
429
+ println(`<g class="statechart__states">`);
430
+ for (const node of nodes) {
431
+ const { key, id, state: text } = node;
432
+ const { x, y, width: width2, height: height2 } = getBoxParams({ ...node, padding: shift });
433
+ println(` <g class="state" data-state-id="${id}">`);
434
+ if (key === initialStateKey || key === finalStateKey) {
435
+ const cx = Math.round(x + width2 / 2);
436
+ const cy = Math.round(y + height2 / 2);
437
+ if (key === initialStateKey) {
438
+ const serializedAttrs = serializeAttrs({
439
+ class: "state__initial",
440
+ cx,
441
+ cy,
442
+ r: initialStateRadius,
443
+ fill: "none",
444
+ stroke: "currentColor",
445
+ strokeWidth: "2"
446
+ });
447
+ println(` <circle ${serializedAttrs} />`);
448
+ } else {
449
+ let serializedAttrs = serializeAttrs({
450
+ class: "state__final",
451
+ cx,
452
+ cy,
453
+ r: initialStateRadius,
454
+ fill: "none",
455
+ stroke: "currentColor",
456
+ strokeWidth: 2
457
+ });
458
+ println(` <circle ${serializedAttrs} />`);
459
+ serializedAttrs = serializeAttrs({
460
+ class: "state__final state__final--inner",
461
+ cx,
462
+ cy,
463
+ r: finalStateRadius,
464
+ fill: "currentColor",
465
+ stroke: "none",
466
+ strokeWidth: 0
467
+ });
468
+ println(` <circle ${serializedAttrs} />`);
469
+ }
470
+ } else {
471
+ const rectAttrs = serializeAttrs({
472
+ x,
473
+ y,
474
+ width: width2,
475
+ height: height2,
476
+ rx: Math.ceil(stateFontSize / 2),
477
+ ry: Math.ceil(stateFontSize / 2),
478
+ fill: "none",
479
+ stroke: "currentColor",
480
+ strokeWidth: "2",
481
+ class: "state__box"
482
+ });
483
+ println(` <rect ${rectAttrs} />`);
484
+ const textAttrs = serializeAttrs({
485
+ class: "state__label",
486
+ "text-anchor": "middle",
487
+ fill: "currentColor",
488
+ x: Math.round(x + width2 / 2),
489
+ y: Math.round(y + height2 / 2 + stateFontSize / 4)
490
+ });
491
+ println(` <text ${textAttrs}>${text}</text>`);
492
+ }
493
+ println(" </g>");
494
+ }
495
+ println("</g>");
496
+ println("</svg>");
497
+ }
498
+
499
+ // src/svg/buildStatechartsPanel.ts
500
+ function buildStatechartsPanel({
501
+ statechart,
502
+ newId,
503
+ println,
504
+ initialStateKey = "<initial>",
505
+ finalStateKey = "<final>"
506
+ }) {
507
+ render(statechart, println);
508
+ function render(statechart2, println2) {
509
+ println2(` <details class="state-details" data-state-id="${statechart2.id}">`);
510
+ println2(` <summary class="state-details__label">${statechart2.key}</summary>`);
511
+ println2(` <div class="state-details__description"><div class="state-details__chart">`);
512
+ const printChildren = (str) => println2(` ${str}`);
513
+ buildStatechartSvg({
514
+ graph: statechart2.graph,
515
+ newId,
516
+ println: printChildren,
517
+ initialStateKey,
518
+ finalStateKey
519
+ });
520
+ println2(` </div>`);
521
+ for (const child of statechart2.children || []) {
522
+ render(child, printChildren);
523
+ }
524
+ println2(` </div>`);
525
+ println2(` </details>`);
526
+ }
527
+ }
528
+
529
+ export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel, serializeCss, toKebabCase2 as toKebabCase };
@@ -1,2 +1,2 @@
1
- export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-3GGM3ZWL.js';
1
+ export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-ASIV3YDZ.js';
2
2
  import './chunk-NXWOFQMO.js';
@@ -0,0 +1,33 @@
1
+ import { b as StateChart, T as TransitionsGraph } from './StateChart-DNGQd1XG.js';
2
+
3
+ declare function buildStatechartCss({ prefix }?: {
4
+ prefix?: string | undefined;
5
+ }): string;
6
+
7
+ declare function buildStatechartsPanel({ statechart, newId, println, initialStateKey, finalStateKey, }: {
8
+ statechart: StateChart;
9
+ newId: (prefix: string) => string;
10
+ println: (str: string) => void;
11
+ initialStateKey?: string;
12
+ finalStateKey?: string;
13
+ }): void;
14
+
15
+ interface CssTree extends Record<string, string | number | CssTree> {
16
+ }
17
+ declare function serializeCss(obj: CssTree): string;
18
+
19
+ declare function buildStatechartStyles({ root, }?: {
20
+ root?: string;
21
+ }): CssTree;
22
+
23
+ declare function buildStatechartSvg({ graph: { width, height, nodes, edges }, newId, stateFontSize, transitionFontSize, println, initialStateKey, finalStateKey, }: {
24
+ graph: TransitionsGraph;
25
+ newId: (prefix: string) => string;
26
+ println: (str: string) => void;
27
+ stateFontSize?: number;
28
+ transitionFontSize?: number;
29
+ initialStateKey?: string;
30
+ finalStateKey?: string;
31
+ }): void;
32
+
33
+ export { type CssTree as C, buildStatechartsPanel as a, buildStatechartCss as b, buildStatechartStyles as c, buildStatechartSvg as d, serializeCss as s };
@@ -1,25 +1,2 @@
1
- import { b as StateChart, T as TransitionsGraph } from './StateChart-DNGQd1XG.js';
2
-
3
- declare function buildStatechartCss({ prefix }?: {
4
- prefix?: string | undefined;
5
- }): string;
6
-
7
- declare function buildStatechartsPanel({ statechart, newId, println, initialStateKey, finalStateKey, }: {
8
- statechart: StateChart;
9
- newId: (prefix: string) => string;
10
- println: (str: string) => void;
11
- initialStateKey?: string;
12
- finalStateKey?: string;
13
- }): void;
14
-
15
- declare function buildStatechartSvg({ graph: { width, height, nodes, edges }, newId, stateFontSize, transitionFontSize, println, initialStateKey, finalStateKey, }: {
16
- graph: TransitionsGraph;
17
- newId: (prefix: string) => string;
18
- println: (str: string) => void;
19
- stateFontSize?: number;
20
- transitionFontSize?: number;
21
- initialStateKey?: string;
22
- finalStateKey?: string;
23
- }): void;
24
-
25
- export { buildStatechartCss, buildStatechartSvg, buildStatechartsPanel };
1
+ export { b as buildStatechartCss, c as buildStatechartStyles, d as buildStatechartSvg, a as buildStatechartsPanel } from './index-svg-DW8Cf450.js';
2
+ import './StateChart-DNGQd1XG.js';
package/dist/index-svg.js CHANGED
@@ -1,2 +1,2 @@
1
- export { buildStatechartCss, buildStatechartSvg, buildStatechartsPanel } from './chunk-TPNWHU7Y.js';
1
+ export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel } from './chunk-DX2ZO7QN.js';
2
2
  import './chunk-NXWOFQMO.js';
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
1
  export { GraphParamsProvider, Padding, Transition, buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './index-layout.js';
2
2
  export { D as Dimensions, P as Position, S as StateGraphEdge, a as StateGraphNode, T as TransitionsGraph } from './StateChart-DNGQd1XG.js';
3
- export { buildStatechartCss, buildStatechartSvg, buildStatechartsPanel } from './index-svg.js';
3
+ export { C as CssTree, b as buildStatechartCss, c as buildStatechartStyles, d as buildStatechartSvg, a as buildStatechartsPanel, s as serializeCss } from './index-svg-DW8Cf450.js';
4
+
5
+ declare function toKebabCase(str: string): string;
6
+
7
+ export { toKebabCase };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-3GGM3ZWL.js';
2
- export { buildStatechartCss, buildStatechartSvg, buildStatechartsPanel } from './chunk-TPNWHU7Y.js';
1
+ export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-ASIV3YDZ.js';
2
+ export { buildStatechartCss, buildStatechartStyles, buildStatechartSvg, buildStatechartsPanel, serializeCss, toKebabCase } from './chunk-DX2ZO7QN.js';
3
3
  import './chunk-NXWOFQMO.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statewalker/fsm-charts",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "HFSM Implementation",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/statewalker/statewalker-fsm-charts",
@@ -44,8 +44,8 @@
44
44
  "url": "git@github.com:statewalker/statewalker-fsm-charts.git"
45
45
  },
46
46
  "scripts": {
47
- "build_": "yarn test && tsup",
48
- "build": "tsup",
47
+ "build": "rm -fr ./dist && yarn test && tsup",
48
+ "prepare": "yarn build",
49
49
  "watch": "tsup --watch",
50
50
  "clean": "rm -rf dist",
51
51
  "lint": "eslint",
@@ -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 };