@statewalker/fsm-charts 0.1.8 → 0.1.11
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/chunk-2OGGKHD6.js +208 -0
- package/dist/{chunk-U5LUJ7JS.js → chunk-HQZXOJPG.js} +9 -0
- package/dist/{chunk-2XPO6T2M.js → chunk-SURKRLPB.js} +2 -0
- package/dist/index-config.js +1 -1
- package/dist/index-dom.d.ts +22 -0
- package/dist/index-dom.js +1 -0
- package/dist/index-html.js +1 -1
- package/dist/index-layout.js +1 -1
- package/dist/index-runtime.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -4
- package/package.json +7 -10
- package/src/dom/index.ts +269 -0
- package/src/index-dom.ts +1 -0
- package/src/index.ts +1 -0
- /package/dist/{chunk-FS3L6FBI.js → chunk-N77KKO5K.js} +0 -0
- /package/dist/{chunk-SLWDNGWK.js → chunk-SVKVQY7B.js} +0 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
// src/dom/index.ts
|
|
2
|
+
function getStateDescriptionRenderer({
|
|
3
|
+
element,
|
|
4
|
+
rootStateKey,
|
|
5
|
+
splitHeader = (header) => {
|
|
6
|
+
if (!header) return [void 0, ""];
|
|
7
|
+
const text = header.innerText.trim();
|
|
8
|
+
let key;
|
|
9
|
+
let label = text;
|
|
10
|
+
text.replace(/^\s*\[(.*)\]\s*(.*)$/, (_, k, l) => {
|
|
11
|
+
key = k.trim();
|
|
12
|
+
label = l.trim() || key;
|
|
13
|
+
return "";
|
|
14
|
+
});
|
|
15
|
+
return [key, label];
|
|
16
|
+
}
|
|
17
|
+
}) {
|
|
18
|
+
const docSections = buildSections(element);
|
|
19
|
+
const rootStateFilter = getStateDescriptionFilter(splitHeader, rootStateKey);
|
|
20
|
+
const rootDescription = findSection(docSections, rootStateFilter);
|
|
21
|
+
if (!rootDescription) {
|
|
22
|
+
return (statesStack) => {
|
|
23
|
+
return void 0;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
for (const node of visitSectionNodes(rootDescription)) {
|
|
27
|
+
if (node.nodeName[0] === "#") continue;
|
|
28
|
+
node.parentElement?.removeChild(node);
|
|
29
|
+
}
|
|
30
|
+
return (statesStack) => {
|
|
31
|
+
const stateKey = [...statesStack].pop();
|
|
32
|
+
const filter = getStateDescriptionFilter(splitHeader, stateKey);
|
|
33
|
+
const description = findSection(rootDescription, filter);
|
|
34
|
+
if (!description) return;
|
|
35
|
+
const elm = renderSections({
|
|
36
|
+
section: description,
|
|
37
|
+
deep: (s) => !rootStateFilter(s),
|
|
38
|
+
header: (header) => {
|
|
39
|
+
const [key, label] = splitHeader(header);
|
|
40
|
+
if (key === stateKey) {
|
|
41
|
+
return label || key;
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
const details = elm?.querySelector("details");
|
|
47
|
+
details && (details.open = true);
|
|
48
|
+
return elm;
|
|
49
|
+
};
|
|
50
|
+
function getStateDescriptionFilter(splitHeader2, stateKey) {
|
|
51
|
+
if (!stateKey) return () => false;
|
|
52
|
+
return (section) => {
|
|
53
|
+
if (!section.header) return false;
|
|
54
|
+
const [key] = splitHeader2(section.header);
|
|
55
|
+
return key === stateKey;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function* visitDom(elm) {
|
|
60
|
+
for (let node = elm.firstChild; node; node = node.nextSibling) {
|
|
61
|
+
if (isDomElement(node)) {
|
|
62
|
+
if (node.tagName === "DIV") {
|
|
63
|
+
yield* visitDom(node);
|
|
64
|
+
} else {
|
|
65
|
+
yield node;
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
yield node;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function* visitSectionNodes(section) {
|
|
73
|
+
if (section.header) yield section.header;
|
|
74
|
+
yield* section.content;
|
|
75
|
+
for (const s of vistSections(section, true)) {
|
|
76
|
+
yield* visitSectionNodes(s);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function* vistSections(root, ignoreRoot = false) {
|
|
80
|
+
!ignoreRoot && (yield root);
|
|
81
|
+
for (const child of root.children) {
|
|
82
|
+
yield* vistSections(child, false);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function findSection(section, accept) {
|
|
86
|
+
for (const s of vistSections(section)) {
|
|
87
|
+
if (accept(s) === true) return s;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function isDomElement(node) {
|
|
91
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
92
|
+
}
|
|
93
|
+
function newAligner(context) {
|
|
94
|
+
let level = -1;
|
|
95
|
+
return (newLevel, ...params) => {
|
|
96
|
+
while (level >= 0 && level >= newLevel) {
|
|
97
|
+
context.exit(level--, ...params);
|
|
98
|
+
}
|
|
99
|
+
while (level < newLevel) {
|
|
100
|
+
context.enter(++level, ...params);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function* toDomNodesIterator(root) {
|
|
105
|
+
yield* root instanceof Node ? visitDom(root) : root;
|
|
106
|
+
}
|
|
107
|
+
function buildSections(root) {
|
|
108
|
+
const nodes = toDomNodesIterator(root);
|
|
109
|
+
let top = null;
|
|
110
|
+
let peek = null;
|
|
111
|
+
const stack = [];
|
|
112
|
+
const aligner = newAligner({
|
|
113
|
+
enter(level, header) {
|
|
114
|
+
const section = {
|
|
115
|
+
header,
|
|
116
|
+
content: [],
|
|
117
|
+
children: []
|
|
118
|
+
};
|
|
119
|
+
top = top || section;
|
|
120
|
+
peek && peek.children.push(section);
|
|
121
|
+
peek = section;
|
|
122
|
+
stack.push(section);
|
|
123
|
+
},
|
|
124
|
+
exit() {
|
|
125
|
+
stack.pop();
|
|
126
|
+
peek = stack[stack.length - 1];
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
aligner(0);
|
|
130
|
+
let currentHeaderLevel = 0;
|
|
131
|
+
let currentLevel = 0;
|
|
132
|
+
for (const node of nodes) {
|
|
133
|
+
if (isDomElement(node)) {
|
|
134
|
+
if (/^H[1-6]$/i.test(node.tagName)) {
|
|
135
|
+
const headerLevel = +node.tagName.replace(/^H/, "");
|
|
136
|
+
currentLevel = headerLevel > currentHeaderLevel ? currentLevel + 1 : headerLevel < currentHeaderLevel ? currentLevel - 1 : currentLevel;
|
|
137
|
+
currentHeaderLevel = headerLevel;
|
|
138
|
+
aligner(currentLevel, node);
|
|
139
|
+
} else {
|
|
140
|
+
peek.content.push(node);
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
peek.content.push(node);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return top.content.length === 0 && top.children.length === 1 && !top.header ? top.children[0] : top;
|
|
147
|
+
}
|
|
148
|
+
function renderSections({
|
|
149
|
+
section,
|
|
150
|
+
deep = (s) => true,
|
|
151
|
+
header = (headerElm) => headerElm
|
|
152
|
+
}) {
|
|
153
|
+
const container = document.createElement("div");
|
|
154
|
+
const id = `id-${String(Math.random()).split(".")[1]}-${Date.now()}`;
|
|
155
|
+
container.setAttribute("id", id);
|
|
156
|
+
if (!section) return container;
|
|
157
|
+
const sectionView = renderSection(section);
|
|
158
|
+
container.append(sectionView);
|
|
159
|
+
const style = renderSectionStyles(id);
|
|
160
|
+
container.append(style);
|
|
161
|
+
return container;
|
|
162
|
+
function renderSectionStyles(id2) {
|
|
163
|
+
const prefix = id2 ? `#${id2}` : "";
|
|
164
|
+
const style2 = document.createElement("style");
|
|
165
|
+
container.appendChild(style2);
|
|
166
|
+
style2.innerHTML = `
|
|
167
|
+
${prefix} details {
|
|
168
|
+
border: 1px solid #aaa;
|
|
169
|
+
border-radius: 4px;
|
|
170
|
+
padding: 0.5em 0.5em 0;
|
|
171
|
+
margin-bottom: 0.5em;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
${prefix} details > summary {
|
|
175
|
+
font-weight: bold;
|
|
176
|
+
margin: -0.5em -0.5em 0;
|
|
177
|
+
padding: 0.5em;
|
|
178
|
+
cursor: pointer;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
${prefix} details[open] {
|
|
182
|
+
padding: 0.5em;
|
|
183
|
+
}
|
|
184
|
+
`;
|
|
185
|
+
return style2;
|
|
186
|
+
}
|
|
187
|
+
function renderSection(section2) {
|
|
188
|
+
const details = document.createElement("details");
|
|
189
|
+
const summary = document.createElement("summary");
|
|
190
|
+
details.appendChild(summary);
|
|
191
|
+
const content = document.createElement("div");
|
|
192
|
+
details.appendChild(content);
|
|
193
|
+
const headerElm = header(section2.header);
|
|
194
|
+
headerElm && summary.append(headerElm);
|
|
195
|
+
for (const node of section2.content) {
|
|
196
|
+
if (node.nodeName[0] === "#") continue;
|
|
197
|
+
content.append(node.cloneNode(true));
|
|
198
|
+
}
|
|
199
|
+
if (deep(section2)) {
|
|
200
|
+
for (const child of section2.children) {
|
|
201
|
+
content.append(renderSection(child));
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return details;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export { buildSections, findSection, getStateDescriptionRenderer, renderSections, visitDom, visitSectionNodes, vistSections };
|
|
@@ -1008,6 +1008,15 @@ function shiftRanks(t, g, delta) {
|
|
|
1008
1008
|
});
|
|
1009
1009
|
}
|
|
1010
1010
|
|
|
1011
|
+
// src/graphlib/alg/dijkstra.js
|
|
1012
|
+
_.constant(1);
|
|
1013
|
+
|
|
1014
|
+
// src/graphlib/alg/floyd-warshall.js
|
|
1015
|
+
_.constant(1);
|
|
1016
|
+
function CycleException() {
|
|
1017
|
+
}
|
|
1018
|
+
CycleException.prototype = new Error();
|
|
1019
|
+
|
|
1011
1020
|
// src/graphlib/alg/dfs.js
|
|
1012
1021
|
function dfs(g, vs, order2) {
|
|
1013
1022
|
if (!_.isArray(vs)) {
|
|
@@ -338,6 +338,7 @@ var BasisCurve = class {
|
|
|
338
338
|
switch (this._point) {
|
|
339
339
|
case 3:
|
|
340
340
|
this.$point(this._x1, this._y1);
|
|
341
|
+
// falls through
|
|
341
342
|
case 2:
|
|
342
343
|
this._context.lineTo(this._x1, this._y1);
|
|
343
344
|
break;
|
|
@@ -362,6 +363,7 @@ var BasisCurve = class {
|
|
|
362
363
|
(5 * this._x0 + this._x1) / 6,
|
|
363
364
|
(5 * this._y0 + this._y1) / 6
|
|
364
365
|
);
|
|
366
|
+
// falls through
|
|
365
367
|
default:
|
|
366
368
|
this.$point(x, y);
|
|
367
369
|
break;
|
package/dist/index-config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { concatTransitionsToString, serializeProcessConfig, splitTransitionString, toFsmStateConfig } from './chunk-
|
|
1
|
+
export { concatTransitionsToString, serializeProcessConfig, splitTransitionString, toFsmStateConfig } from './chunk-SVKVQY7B.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
type DomSection = {
|
|
2
|
+
header?: HTMLElement;
|
|
3
|
+
content: Node[];
|
|
4
|
+
children: DomSection[];
|
|
5
|
+
};
|
|
6
|
+
declare function getStateDescriptionRenderer({ element, rootStateKey, splitHeader, }: {
|
|
7
|
+
element: HTMLElement;
|
|
8
|
+
rootStateKey: string;
|
|
9
|
+
splitHeader?: (header?: HTMLElement) => [stateKey: undefined | string, label: string];
|
|
10
|
+
}): (statesStack: string[]) => HTMLDivElement | undefined;
|
|
11
|
+
declare function visitDom(elm: Node): Iterable<Node>;
|
|
12
|
+
declare function visitSectionNodes(section: DomSection): Iterable<Node>;
|
|
13
|
+
declare function vistSections(root: DomSection, ignoreRoot?: boolean): Generator<DomSection>;
|
|
14
|
+
declare function findSection(section: DomSection, accept: (section: DomSection) => boolean): DomSection | undefined;
|
|
15
|
+
declare function buildSections(root: HTMLElement | Iterable<Node>): DomSection;
|
|
16
|
+
declare function renderSections({ section, deep, header, }: {
|
|
17
|
+
section: DomSection;
|
|
18
|
+
deep?: (s: DomSection) => boolean;
|
|
19
|
+
header?: (header: HTMLElement) => undefined | string | HTMLElement;
|
|
20
|
+
}): HTMLDivElement;
|
|
21
|
+
|
|
22
|
+
export { type DomSection, buildSections, findSection, getStateDescriptionRenderer, renderSections, visitDom, visitSectionNodes, vistSections };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { buildSections, findSection, getStateDescriptionRenderer, renderSections, visitDom, visitSectionNodes, vistSections } from './chunk-2OGGKHD6.js';
|
package/dist/index-html.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { activeStatesStyle, activeTransitionsStyle, buildStateDetailsStyle, buildStateDetailsStyleWithModifier, buildStatechartCss, buildStatechartStyles, buildStatechartStylesWithModifier, buildStatechartSvg, buildStatechartsPanel, selectedStatesStyle, selectedTransitionsStyle } from './chunk-
|
|
1
|
+
export { activeStatesStyle, activeTransitionsStyle, buildStateDetailsStyle, buildStateDetailsStyleWithModifier, buildStatechartCss, buildStatechartStyles, buildStatechartStylesWithModifier, buildStatechartSvg, buildStatechartsPanel, selectedStatesStyle, selectedTransitionsStyle } from './chunk-SURKRLPB.js';
|
|
2
2
|
import './chunk-FIQDLBWD.js';
|
package/dist/index-layout.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-
|
|
1
|
+
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-HQZXOJPG.js';
|
|
2
2
|
import './chunk-FIQDLBWD.js';
|
package/dist/index-runtime.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { RuntimeStatechartApi, StateChartIndex } from './chunk-
|
|
1
|
+
export { RuntimeStatechartApi, StateChartIndex } from './chunk-N77KKO5K.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { D as Dimensions, F as FsmStateConfig, G as GraphParamsProvider, P as Padding, a as Position, S as StateChart, b as StateGraphEdge, c as StateGraphNode, T as Transition, d as TransitionsGraph } from './StateChart-DlcWaRml.js';
|
|
2
|
+
export { DomSection, buildSections, findSection, getStateDescriptionRenderer, renderSections, visitDom, visitSectionNodes, vistSections } from './index-dom.js';
|
|
2
3
|
export { concatTransitionsToString, serializeProcessConfig, splitTransitionString, toFsmStateConfig } from './index-config.js';
|
|
3
4
|
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './index-layout.js';
|
|
4
5
|
export { C as CssTree, c as activeStatesStyle, d as activeTransitionsStyle, f as buildStateDetailsStyle, g as buildStateDetailsStyleWithModifier, b as buildStatechartCss, i as buildStatechartStyles, h as buildStatechartStylesWithModifier, j as buildStatechartSvg, a as buildStatechartsPanel, s as selectedStatesStyle, e as selectedTransitionsStyle, k as serializeCss } from './index-html-De8e33ol.js';
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { concatTransitionsToString, serializeProcessConfig, splitTransitionString, toFsmStateConfig } from './chunk-
|
|
2
|
-
export {
|
|
3
|
-
export { activeStatesStyle, activeTransitionsStyle, buildStateDetailsStyle, buildStateDetailsStyleWithModifier, buildStatechartCss, buildStatechartStyles, buildStatechartStylesWithModifier, buildStatechartSvg, buildStatechartsPanel, selectedStatesStyle, selectedTransitionsStyle, serializeCss, toKebabCase } from './chunk-
|
|
1
|
+
export { concatTransitionsToString, serializeProcessConfig, splitTransitionString, toFsmStateConfig } from './chunk-SVKVQY7B.js';
|
|
2
|
+
export { buildSections, findSection, getStateDescriptionRenderer, renderSections, visitDom, visitSectionNodes, vistSections } from './chunk-2OGGKHD6.js';
|
|
3
|
+
export { activeStatesStyle, activeTransitionsStyle, buildStateDetailsStyle, buildStateDetailsStyleWithModifier, buildStatechartCss, buildStatechartStyles, buildStatechartStylesWithModifier, buildStatechartSvg, buildStatechartsPanel, selectedStatesStyle, selectedTransitionsStyle, serializeCss, toKebabCase } from './chunk-SURKRLPB.js';
|
|
4
|
+
export { buildCharts, buildFlatCharts, getGraphParamsProvider, getLabelDimensions } from './chunk-HQZXOJPG.js';
|
|
4
5
|
import './chunk-FIQDLBWD.js';
|
|
5
|
-
export { RuntimeStatechartApi, StateChartIndex } from './chunk-
|
|
6
|
+
export { RuntimeStatechartApi, StateChartIndex } from './chunk-N77KKO5K.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@statewalker/fsm-charts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "HFSM Implementation",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/statewalker/statewalker-fsm-charts",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"dist",
|
|
15
15
|
"src"
|
|
16
16
|
],
|
|
17
|
+
"source": "./src/index.ts",
|
|
17
18
|
"module": "./dist/index.js",
|
|
18
19
|
"main": "./dist/index.js",
|
|
19
20
|
"jsdelivr": "./dist/index.js",
|
|
@@ -21,14 +22,10 @@
|
|
|
21
22
|
"types": "./dist/index.d.ts",
|
|
22
23
|
"exports": {
|
|
23
24
|
".": {
|
|
25
|
+
"source": "./src/index.ts",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
24
27
|
"import": "./dist/index.js",
|
|
25
|
-
"
|
|
26
|
-
},
|
|
27
|
-
"./src": {
|
|
28
|
-
"import": "./src"
|
|
29
|
-
},
|
|
30
|
-
"./src/index.ts": {
|
|
31
|
-
"import": "./src/index.ts"
|
|
28
|
+
"default": "./dist/index.js"
|
|
32
29
|
}
|
|
33
30
|
},
|
|
34
31
|
"devDependencies": {
|
|
@@ -60,9 +57,9 @@
|
|
|
60
57
|
"lint": "eslint",
|
|
61
58
|
"lint:fix": "yarn lint -- --fix",
|
|
62
59
|
"test": "vitest --run",
|
|
63
|
-
"test:watch": "vitest"
|
|
60
|
+
"test:watch": "vitest",
|
|
61
|
+
"prepublish": "yarn build"
|
|
64
62
|
},
|
|
65
|
-
"sideEffects": false,
|
|
66
63
|
"publishConfig": {
|
|
67
64
|
"access": "public"
|
|
68
65
|
}
|
package/src/dom/index.ts
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
export type DomSection = {
|
|
2
|
+
header?: HTMLElement;
|
|
3
|
+
content: Node[];
|
|
4
|
+
children: DomSection[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export function getStateDescriptionRenderer({
|
|
8
|
+
element,
|
|
9
|
+
rootStateKey,
|
|
10
|
+
splitHeader = (
|
|
11
|
+
header?: HTMLElement,
|
|
12
|
+
): [stateKey: undefined | string, label: string] => {
|
|
13
|
+
if (!header) return [undefined, ""];
|
|
14
|
+
const text = header.innerText.trim();
|
|
15
|
+
let key: string | undefined;
|
|
16
|
+
let label: string = text;
|
|
17
|
+
text.replace(/^\s*\[(.*)\]\s*(.*)$/, (_, k, l) => {
|
|
18
|
+
key = k.trim();
|
|
19
|
+
label = l.trim() || key;
|
|
20
|
+
return "";
|
|
21
|
+
});
|
|
22
|
+
return [key, label];
|
|
23
|
+
},
|
|
24
|
+
}: {
|
|
25
|
+
element: HTMLElement;
|
|
26
|
+
rootStateKey: string;
|
|
27
|
+
splitHeader?: (
|
|
28
|
+
header?: HTMLElement,
|
|
29
|
+
) => [stateKey: undefined | string, label: string];
|
|
30
|
+
}) {
|
|
31
|
+
const docSections = buildSections(element);
|
|
32
|
+
const rootStateFilter = getStateDescriptionFilter(splitHeader, rootStateKey);
|
|
33
|
+
const rootDescription = findSection(docSections, rootStateFilter);
|
|
34
|
+
|
|
35
|
+
if (!rootDescription) {
|
|
36
|
+
return (statesStack: string[]) => {
|
|
37
|
+
return undefined;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Remove description nodes from DOM
|
|
42
|
+
for (const node of visitSectionNodes(rootDescription)) {
|
|
43
|
+
if (node.nodeName[0] === "#") continue;
|
|
44
|
+
node.parentElement?.removeChild(node);
|
|
45
|
+
}
|
|
46
|
+
// for (const section of vistSections(rootDescription)) {
|
|
47
|
+
// const [key, label] = splitHeader(section.header);
|
|
48
|
+
// console.log("??????", section.header?.innerText, key);
|
|
49
|
+
// if (!key) continue;
|
|
50
|
+
|
|
51
|
+
// section.header?.remove();
|
|
52
|
+
// for (const node of section.content) {
|
|
53
|
+
// if (node.nodeName[0] === "#") continue;
|
|
54
|
+
// node.parentElement?.removeChild(node);
|
|
55
|
+
// }
|
|
56
|
+
// }
|
|
57
|
+
|
|
58
|
+
return (statesStack: string[]) => {
|
|
59
|
+
const stateKey = [...statesStack].pop();
|
|
60
|
+
const filter = getStateDescriptionFilter(splitHeader, stateKey);
|
|
61
|
+
const description = findSection(rootDescription, filter);
|
|
62
|
+
if (!description) return;
|
|
63
|
+
const elm = renderSections({
|
|
64
|
+
section: description,
|
|
65
|
+
deep: (s) => !rootStateFilter(s),
|
|
66
|
+
header: (header) => {
|
|
67
|
+
const [key, label] = splitHeader(header);
|
|
68
|
+
if (key === stateKey) {
|
|
69
|
+
return label || key;
|
|
70
|
+
}
|
|
71
|
+
return;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const details = elm?.querySelector("details");
|
|
75
|
+
details && (details.open = true);
|
|
76
|
+
return elm;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
function getStateDescriptionFilter(
|
|
80
|
+
splitHeader: (header: HTMLElement) => [stateKey?: string, label?: string],
|
|
81
|
+
stateKey?: string,
|
|
82
|
+
) {
|
|
83
|
+
if (!stateKey) return () => false;
|
|
84
|
+
return (section: DomSection) => {
|
|
85
|
+
if (!section.header) return false;
|
|
86
|
+
const [key] = splitHeader(section.header);
|
|
87
|
+
return key === stateKey;
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function* visitDom(elm: Node): Iterable<Node> {
|
|
93
|
+
for (let node = elm.firstChild; node; node = node.nextSibling) {
|
|
94
|
+
if (isDomElement(node)) {
|
|
95
|
+
if (node.tagName === "DIV") {
|
|
96
|
+
yield* visitDom(node);
|
|
97
|
+
} else {
|
|
98
|
+
yield node;
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
yield node;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function* visitSectionNodes(section: DomSection): Iterable<Node> {
|
|
107
|
+
if (section.header) yield section.header;
|
|
108
|
+
yield* section.content;
|
|
109
|
+
for (const s of vistSections(section, true)) {
|
|
110
|
+
yield* visitSectionNodes(s);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function* vistSections(
|
|
115
|
+
root: DomSection,
|
|
116
|
+
ignoreRoot: boolean = false,
|
|
117
|
+
): Generator<DomSection> {
|
|
118
|
+
!ignoreRoot && (yield root);
|
|
119
|
+
for (const child of root.children) {
|
|
120
|
+
yield* vistSections(child, false);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function findSection(
|
|
125
|
+
section: DomSection,
|
|
126
|
+
accept: (section: DomSection) => boolean,
|
|
127
|
+
) {
|
|
128
|
+
for (const s of vistSections(section)) {
|
|
129
|
+
if (accept(s) === true) return s;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function isDomElement(node: Node): node is HTMLElement {
|
|
134
|
+
return node.nodeType === Node.ELEMENT_NODE;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function newAligner<T extends unknown[] = []>(context: {
|
|
138
|
+
enter: (level: number, ...params: T) => void;
|
|
139
|
+
exit: (level: number, ...params: T) => void;
|
|
140
|
+
}) {
|
|
141
|
+
let level = -1;
|
|
142
|
+
return (newLevel: number, ...params: T) => {
|
|
143
|
+
while (level >= 0 && level >= newLevel) {
|
|
144
|
+
context.exit(level--, ...params);
|
|
145
|
+
}
|
|
146
|
+
while (level < newLevel) {
|
|
147
|
+
context.enter(++level, ...params);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function* toDomNodesIterator(root: Node | Iterable<Node>): Iterable<Node> {
|
|
153
|
+
yield* root instanceof Node ? visitDom(root) : root;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function buildSections(root: HTMLElement | Iterable<Node>): DomSection {
|
|
157
|
+
const nodes = toDomNodesIterator(root);
|
|
158
|
+
let top: DomSection = null!;
|
|
159
|
+
let peek: DomSection = null!;
|
|
160
|
+
const stack: DomSection[] = [];
|
|
161
|
+
const aligner = newAligner<[HTMLElement?]>({
|
|
162
|
+
enter(level, header) {
|
|
163
|
+
const section: DomSection = {
|
|
164
|
+
header,
|
|
165
|
+
content: [],
|
|
166
|
+
children: [],
|
|
167
|
+
};
|
|
168
|
+
top = top || section;
|
|
169
|
+
peek && peek.children.push(section);
|
|
170
|
+
peek = section;
|
|
171
|
+
stack.push(section);
|
|
172
|
+
},
|
|
173
|
+
exit() {
|
|
174
|
+
stack.pop();
|
|
175
|
+
peek = stack[stack.length - 1];
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
aligner(0);
|
|
179
|
+
let currentHeaderLevel = 0;
|
|
180
|
+
let currentLevel = 0;
|
|
181
|
+
for (const node of nodes) {
|
|
182
|
+
if (isDomElement(node)) {
|
|
183
|
+
if (/^H[1-6]$/i.test(node.tagName)) {
|
|
184
|
+
const headerLevel = +node.tagName.replace(/^H/, "");
|
|
185
|
+
currentLevel =
|
|
186
|
+
headerLevel > currentHeaderLevel
|
|
187
|
+
? currentLevel + 1
|
|
188
|
+
: headerLevel < currentHeaderLevel
|
|
189
|
+
? currentLevel - 1
|
|
190
|
+
: currentLevel;
|
|
191
|
+
currentHeaderLevel = headerLevel;
|
|
192
|
+
aligner(currentLevel, node);
|
|
193
|
+
} else {
|
|
194
|
+
peek.content.push(node);
|
|
195
|
+
}
|
|
196
|
+
} else {
|
|
197
|
+
peek.content.push(node);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return top.content.length === 0 && top.children.length === 1 && !top.header
|
|
201
|
+
? top.children[0]
|
|
202
|
+
: top;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function renderSections({
|
|
206
|
+
section,
|
|
207
|
+
deep = (s) => true,
|
|
208
|
+
header = (headerElm) => headerElm,
|
|
209
|
+
}: {
|
|
210
|
+
section: DomSection;
|
|
211
|
+
deep?: (s: DomSection) => boolean;
|
|
212
|
+
header?: (header: HTMLElement) => undefined | string | HTMLElement;
|
|
213
|
+
}) {
|
|
214
|
+
const container = document.createElement("div");
|
|
215
|
+
const id = `id-${String(Math.random()).split(".")[1]}-${Date.now()}`;
|
|
216
|
+
container.setAttribute("id", id);
|
|
217
|
+
if (!section) return container;
|
|
218
|
+
|
|
219
|
+
const sectionView = renderSection(section);
|
|
220
|
+
container.append(sectionView);
|
|
221
|
+
const style = renderSectionStyles(id);
|
|
222
|
+
container.append(style);
|
|
223
|
+
return container;
|
|
224
|
+
|
|
225
|
+
function renderSectionStyles(id?: string) {
|
|
226
|
+
const prefix = id ? `#${id}` : "";
|
|
227
|
+
const style = document.createElement("style");
|
|
228
|
+
container.appendChild(style);
|
|
229
|
+
style.innerHTML = `
|
|
230
|
+
${prefix} details {
|
|
231
|
+
border: 1px solid #aaa;
|
|
232
|
+
border-radius: 4px;
|
|
233
|
+
padding: 0.5em 0.5em 0;
|
|
234
|
+
margin-bottom: 0.5em;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
${prefix} details > summary {
|
|
238
|
+
font-weight: bold;
|
|
239
|
+
margin: -0.5em -0.5em 0;
|
|
240
|
+
padding: 0.5em;
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
${prefix} details[open] {
|
|
245
|
+
padding: 0.5em;
|
|
246
|
+
}
|
|
247
|
+
`;
|
|
248
|
+
return style;
|
|
249
|
+
}
|
|
250
|
+
function renderSection(section: DomSection) {
|
|
251
|
+
const details = document.createElement("details");
|
|
252
|
+
const summary = document.createElement("summary");
|
|
253
|
+
details.appendChild(summary);
|
|
254
|
+
const content = document.createElement("div");
|
|
255
|
+
details.appendChild(content);
|
|
256
|
+
const headerElm = header(section.header!);
|
|
257
|
+
headerElm && summary.append(headerElm);
|
|
258
|
+
for (const node of section.content) {
|
|
259
|
+
if (node.nodeName[0] === "#") continue;
|
|
260
|
+
content.append(node.cloneNode(true));
|
|
261
|
+
}
|
|
262
|
+
if (deep(section)) {
|
|
263
|
+
for (const child of section.children) {
|
|
264
|
+
content.append(renderSection(child));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
return details;
|
|
268
|
+
}
|
|
269
|
+
}
|
package/src/index-dom.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./dom/index.ts";
|
package/src/index.ts
CHANGED
|
File without changes
|
|
File without changes
|