tutuca 0.9.27 → 0.9.29
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/README.md +4 -4
- package/dist/tutuca-cli.js +59 -60
- package/dist/tutuca-dev.js +59 -54
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.js +55 -50
- package/dist/tutuca-extra.min.js +2 -2
- package/dist/tutuca.js +53 -48
- package/dist/tutuca.min.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Zero-dependency batteries included SPA framework.
|
|
|
7
7
|
- **Fits in your head** (and the context window)
|
|
8
8
|
- **View source friendly** — step through the whole stack
|
|
9
9
|
- **As much HTML as possible, as little JS as needed**
|
|
10
|
-
- ~
|
|
10
|
+
- ~169KB minified, ~37KB brotli compressed
|
|
11
11
|
|
|
12
12
|
## Quick Start
|
|
13
13
|
|
|
@@ -64,17 +64,17 @@ Zero-dependency batteries included SPA framework.
|
|
|
64
64
|
Tutuca ships a single-file CLI (`dist/tutuca-cli.js`) for inspecting, linting,
|
|
65
65
|
documenting, and rendering components defined in an ES module. The module just
|
|
66
66
|
needs to export `getComponents()` and, for render-time commands, `getExamples()`
|
|
67
|
-
in the storybook shape `{ title, description?,
|
|
67
|
+
in the storybook shape `{ title, description?, items: [{ title, description?, value, view? }] }` (a single section, or an array of sections).
|
|
68
68
|
|
|
69
69
|
### Setup
|
|
70
70
|
|
|
71
71
|
```sh
|
|
72
|
-
npm install --save-dev tutuca
|
|
72
|
+
npm install --save-dev tutuca
|
|
73
73
|
# prettier is optional, only needed for --pretty
|
|
74
74
|
npm install --save-dev prettier
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
The package exposes `tutuca` via `bin`, so `npx tutuca` (or a global `npm i -g tutuca
|
|
77
|
+
The package exposes `tutuca` via `bin`, so `npx tutuca` (or a global `npm i -g tutuca`) just works. `jsdom` ships as a regular dependency (it's needed by `render`, `lint`, and `doctor`) and is installed automatically.
|
|
78
78
|
|
|
79
79
|
### Commands
|
|
80
80
|
|
package/dist/tutuca-cli.js
CHANGED
|
@@ -221,15 +221,11 @@ function normalizeModule(mod, { path = null } = {}) {
|
|
|
221
221
|
"getMacros",
|
|
222
222
|
"getRequestHandlers",
|
|
223
223
|
"getExamples",
|
|
224
|
-
"getStoryBookSection",
|
|
225
224
|
"getRoot"
|
|
226
225
|
]) {
|
|
227
226
|
if (typeof mod[key] === "function")
|
|
228
227
|
present.add(key);
|
|
229
228
|
}
|
|
230
|
-
if (present.has("getStoryBookSection") && !present.has("getExamples")) {
|
|
231
|
-
throw shapeError("module exports getStoryBookSection; rename it to getExamples.", "module");
|
|
232
|
-
}
|
|
233
229
|
const components = present.has("getComponents") ? mod.getComponents() : [];
|
|
234
230
|
const macros = present.has("getMacros") ? mod.getMacros() : null;
|
|
235
231
|
const requestHandlers = present.has("getRequestHandlers") ? mod.getRequestHandlers() : null;
|
|
@@ -1376,13 +1372,13 @@ class IterInfo {
|
|
|
1376
1372
|
}
|
|
1377
1373
|
|
|
1378
1374
|
class ParseContext {
|
|
1379
|
-
constructor(
|
|
1375
|
+
constructor(document2, Text, Comment, nodes, events, macroNodes, frame, parent) {
|
|
1380
1376
|
this.nodes = nodes ?? [];
|
|
1381
1377
|
this.events = events ?? [];
|
|
1382
1378
|
this.macroNodes = macroNodes ?? [];
|
|
1383
1379
|
this.parent = parent ?? null;
|
|
1384
1380
|
this.frame = frame ?? {};
|
|
1385
|
-
this.
|
|
1381
|
+
this.document = document2 ?? globalThis.document;
|
|
1386
1382
|
this.Text = Text ?? globalThis.Text;
|
|
1387
1383
|
this.Comment = Comment ?? globalThis.Comment;
|
|
1388
1384
|
this.cacheConstNodes = true;
|
|
@@ -1391,12 +1387,14 @@ class ParseContext {
|
|
|
1391
1387
|
return this.frame.macroName === name || this.parent?.isInsideMacro(name);
|
|
1392
1388
|
}
|
|
1393
1389
|
enterMacro(macroName, macroVars, macroSlots) {
|
|
1394
|
-
const {
|
|
1390
|
+
const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
|
|
1395
1391
|
const frame = { macroName, macroVars, macroSlots };
|
|
1396
|
-
return new ParseContext(
|
|
1392
|
+
return new ParseContext(document2, Text, Comment, nodes, events, macroNodes, frame, this);
|
|
1397
1393
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1394
|
+
parseHTML(html) {
|
|
1395
|
+
const t = this.document.createElement("template");
|
|
1396
|
+
t.innerHTML = html;
|
|
1397
|
+
return Array.from(t.content.childNodes);
|
|
1400
1398
|
}
|
|
1401
1399
|
addNodeIf(Class, val, extra) {
|
|
1402
1400
|
if (val !== null) {
|
|
@@ -1442,26 +1440,28 @@ class ParseContext {
|
|
|
1442
1440
|
onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall) {}
|
|
1443
1441
|
}
|
|
1444
1442
|
function condenseChildsWhites(childs) {
|
|
1445
|
-
|
|
1446
|
-
if (end === 0)
|
|
1443
|
+
if (childs.length === 0)
|
|
1447
1444
|
return childs;
|
|
1448
|
-
let start = 0;
|
|
1449
1445
|
let changed = false;
|
|
1450
|
-
if (
|
|
1451
|
-
|
|
1446
|
+
if (childs[0].isWhiteSpace?.()) {
|
|
1447
|
+
childs[0].condenseWhiteSpace();
|
|
1452
1448
|
changed = true;
|
|
1453
1449
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1450
|
+
const last = childs.length - 1;
|
|
1451
|
+
if (last > 0 && childs[last].isWhiteSpace?.()) {
|
|
1452
|
+
childs[last].condenseWhiteSpace();
|
|
1456
1453
|
changed = true;
|
|
1457
1454
|
}
|
|
1458
|
-
for (let i = 1;i <
|
|
1455
|
+
for (let i = 1;i < last; i++) {
|
|
1459
1456
|
const cur = childs[i];
|
|
1460
|
-
if (
|
|
1461
|
-
|
|
1457
|
+
if (cur.isWhiteSpace?.() && cur.hasNewLine()) {
|
|
1458
|
+
const bothBlock = isBlockDomNode(childs[i - 1]) && isBlockDomNode(childs[i + 1]);
|
|
1459
|
+
cur.condenseWhiteSpace(bothBlock ? "" : " ");
|
|
1460
|
+
if (bothBlock)
|
|
1461
|
+
changed = true;
|
|
1462
1462
|
}
|
|
1463
1463
|
}
|
|
1464
|
-
return changed ? childs.
|
|
1464
|
+
return changed ? childs.filter((c) => !(c instanceof TextNode && c.val === "")) : childs;
|
|
1465
1465
|
}
|
|
1466
1466
|
|
|
1467
1467
|
class NodeEvents {
|
|
@@ -1517,7 +1517,10 @@ function compileModifiers(eventName, names) {
|
|
|
1517
1517
|
return w(this, f, args, ctx);
|
|
1518
1518
|
};
|
|
1519
1519
|
}
|
|
1520
|
-
var TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs), VALID_NODE_RE,
|
|
1520
|
+
var TextNode, CommentNode, ChildsNode, DomNode, FragmentNode, maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs), VALID_NODE_RE, ANode, MacroNode, RenderViewId, RenderNode, RenderItNode, RenderEachNode, RenderTextNode, RenderOnceNode, WrapperNode, ShowNode, HideNode, PushViewNameNode, SlotNode, ScopeNode, EachNode, filterAlwaysTrue = (_v, _k, _seq) => true, nullLoopWith = (seq) => ({ seq }), WRAPPER_NODES, _htmlBlockTags = "ADDRESS,ARTICLE,ASIDE,BLOCKQUOTE,CAPTION,COL,COLGROUP,DETAILS,DIALOG,DIV,DD,DL,DT,FIELDSET,FIGCAPTION,FIGURE,FOOTER,FORM,H1,H2,H3,H4,H5,H6,HEADER,HGROUP,HR,LEGEND,LI,MAIN,MENU,NAV,OL,P,PRE,SECTION,SUMMARY,TABLE,TBODY,TD,TFOOT,TH,THEAD,TR,UL", HTML_BLOCK_TAGS, isBlockDomNode = (n) => {
|
|
1521
|
+
const node = n instanceof FragmentNode ? n.childs[0] : n;
|
|
1522
|
+
return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
|
|
1523
|
+
}, isMac, fwdIfCtxPred = (pred) => (w) => (that, f, args, ctx) => pred(ctx) ? w(that, f, args, ctx) : that, fwdIfKey = (keyName) => fwdIfCtxPred((ctx) => ctx.e.key === keyName), fwdCtrl, fwdMeta, fwdAlt, metaWraps, MOD_WRAPPERS_BY_EVENT, identityModifierWrapper = (f, _ctx) => f;
|
|
1521
1524
|
var init_anode = __esm(() => {
|
|
1522
1525
|
init_attribute();
|
|
1523
1526
|
init_path();
|
|
@@ -1546,8 +1549,8 @@ var init_anode = __esm(() => {
|
|
|
1546
1549
|
}
|
|
1547
1550
|
return false;
|
|
1548
1551
|
}
|
|
1549
|
-
condenseWhiteSpace() {
|
|
1550
|
-
this.val =
|
|
1552
|
+
condenseWhiteSpace(replacement = "") {
|
|
1553
|
+
this.val = replacement;
|
|
1551
1554
|
}
|
|
1552
1555
|
isConstant() {
|
|
1553
1556
|
return true;
|
|
@@ -1611,9 +1614,7 @@ var init_anode = __esm(() => {
|
|
|
1611
1614
|
return this.val.toPathItem();
|
|
1612
1615
|
}
|
|
1613
1616
|
static parse(html, px) {
|
|
1614
|
-
|
|
1615
|
-
const nodes = _parser.parseFromString(html, "text/html").body.childNodes;
|
|
1616
|
-
return ANode.fromDOM(nodes[0] ?? new px.Text(""), px);
|
|
1617
|
+
return ANode.fromDOM(px.parseHTML(html)[0] ?? new px.Text(""), px);
|
|
1617
1618
|
}
|
|
1618
1619
|
static fromDOM(node, px) {
|
|
1619
1620
|
if (node instanceof px.Text)
|
|
@@ -1664,7 +1665,7 @@ var init_anode = __esm(() => {
|
|
|
1664
1665
|
if (textChild)
|
|
1665
1666
|
childs.unshift(new RenderTextNode(null, textChild));
|
|
1666
1667
|
const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
|
|
1667
|
-
return wrap(new DomNode(tag
|
|
1668
|
+
return wrap(new DomNode(tag, nAttrs, domChilds), px, wrappers);
|
|
1668
1669
|
}
|
|
1669
1670
|
return new CommentNode(`Error: InvalidTagName ${tag}`);
|
|
1670
1671
|
}
|
|
@@ -1840,6 +1841,7 @@ var init_anode = __esm(() => {
|
|
|
1840
1841
|
scope: ScopeNode,
|
|
1841
1842
|
"push-view": PushViewNameNode
|
|
1842
1843
|
};
|
|
1844
|
+
HTML_BLOCK_TAGS = new Set(_htmlBlockTags.split(","));
|
|
1843
1845
|
isMac = (globalThis.navigator?.userAgent ?? "").toLowerCase().includes("mac");
|
|
1844
1846
|
fwdCtrl = fwdIfCtxPred(({ e }) => isMac && e.metaKey || e.ctrlKey);
|
|
1845
1847
|
fwdMeta = fwdIfCtxPred(({ e }) => e.metaKey);
|
|
@@ -2369,8 +2371,8 @@ var init_lint_check = __esm(() => {
|
|
|
2369
2371
|
"dragInfo"
|
|
2370
2372
|
]);
|
|
2371
2373
|
LintParseContext = class LintParseContext extends ParseContext {
|
|
2372
|
-
constructor(
|
|
2373
|
-
super(
|
|
2374
|
+
constructor(document2, Text, Comment) {
|
|
2375
|
+
super(document2, Text, Comment);
|
|
2374
2376
|
this.attrs = [];
|
|
2375
2377
|
}
|
|
2376
2378
|
onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
|
|
@@ -2987,23 +2989,20 @@ function morphNode(domNode, source, target, opts) {
|
|
|
2987
2989
|
domNode.data = target.text;
|
|
2988
2990
|
return domNode;
|
|
2989
2991
|
}
|
|
2990
|
-
if (type === 1 && source.
|
|
2992
|
+
if (type === 1 && source.isSameKind(target)) {
|
|
2991
2993
|
const propsDiff = diffProps(source.attrs, target.attrs);
|
|
2992
2994
|
const isSelect = source.tag === "SELECT";
|
|
2993
2995
|
if (propsDiff) {
|
|
2994
2996
|
if (isSelect && "value" in propsDiff) {
|
|
2995
2997
|
const { value: _v, ...rest } = propsDiff;
|
|
2996
2998
|
applyProperties(domNode, rest, source.attrs);
|
|
2997
|
-
} else
|
|
2999
|
+
} else
|
|
2998
3000
|
applyProperties(domNode, propsDiff, source.attrs);
|
|
2999
|
-
}
|
|
3000
3001
|
}
|
|
3001
|
-
if (!target.attrs.dangerouslySetInnerHTML)
|
|
3002
|
+
if (!target.attrs.dangerouslySetInnerHTML)
|
|
3002
3003
|
morphChildren(domNode, source.childs, target.childs, opts);
|
|
3003
|
-
|
|
3004
|
-
if (isSelect && target.attrs.value !== undefined) {
|
|
3004
|
+
if (isSelect && target.attrs.value !== undefined)
|
|
3005
3005
|
applyProperties(domNode, { value: target.attrs.value }, source.attrs);
|
|
3006
|
-
}
|
|
3007
3006
|
return domNode;
|
|
3008
3007
|
}
|
|
3009
3008
|
if (type === 11) {
|
|
@@ -3082,23 +3081,20 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
|
|
|
3082
3081
|
if (!used[i] && domNodes[i].parentNode === parentDom)
|
|
3083
3082
|
parentDom.removeChild(domNodes[i]);
|
|
3084
3083
|
}
|
|
3085
|
-
function render(vnode, container, options) {
|
|
3086
|
-
const cached = renderCache.get(container);
|
|
3084
|
+
function render(vnode, container, options, prev) {
|
|
3087
3085
|
const isFragment = vnode instanceof VFragment;
|
|
3088
|
-
if (
|
|
3089
|
-
const oldDom = isFragment ? container :
|
|
3090
|
-
const newDom = morphNode(oldDom,
|
|
3091
|
-
|
|
3092
|
-
return newDom;
|
|
3086
|
+
if (prev && prev.vnode instanceof VFragment === isFragment) {
|
|
3087
|
+
const oldDom = isFragment ? container : prev.dom;
|
|
3088
|
+
const newDom = morphNode(oldDom, prev.vnode, vnode, options);
|
|
3089
|
+
return { vnode, dom: isFragment ? container : newDom };
|
|
3093
3090
|
}
|
|
3094
|
-
renderCache.delete(container);
|
|
3095
3091
|
const domNode = vnode.toDom(options);
|
|
3096
3092
|
container.replaceChildren(domNode);
|
|
3097
|
-
|
|
3098
|
-
return domNode;
|
|
3093
|
+
return { vnode, dom: isFragment ? container : domNode };
|
|
3099
3094
|
}
|
|
3100
3095
|
function h(tagName, properties, children) {
|
|
3101
|
-
const
|
|
3096
|
+
const c = tagName.charCodeAt(0);
|
|
3097
|
+
const tag = c >= 97 && c <= 122 ? tagName.toUpperCase() : tagName;
|
|
3102
3098
|
const props = {};
|
|
3103
3099
|
let key, namespace;
|
|
3104
3100
|
if (properties) {
|
|
@@ -3126,7 +3122,7 @@ function h(tagName, properties, children) {
|
|
|
3126
3122
|
addChild(normalizedChildren, children);
|
|
3127
3123
|
return new VNode(tag, props, normalizedChildren, key, namespace);
|
|
3128
3124
|
}
|
|
3129
|
-
var isHtmlAttribute = (propName) => propName[4] === "-" && (propName[0] === "d" || propName[0] === "a"), isObject = (v) => v !== null && typeof v === "object", prototypesDiffer = (a, b) => Object.getPrototypeOf(a) !== Object.getPrototypeOf(b), getKey = (child) => child instanceof VNode ? child.key : undefined, isIterable = (obj) => obj != null && typeof obj !== "string" && typeof obj[Symbol.iterator] === "function", VText, VComment, VFragment, VNode
|
|
3125
|
+
var isHtmlAttribute = (propName) => propName[4] === "-" && (propName[0] === "d" || propName[0] === "a"), isObject = (v) => v !== null && typeof v === "object", prototypesDiffer = (a, b) => Object.getPrototypeOf(a) !== Object.getPrototypeOf(b), getKey = (child) => child instanceof VNode ? child.key : undefined, isIterable = (obj) => obj != null && typeof obj !== "string" && typeof obj[Symbol.iterator] === "function", VText, VComment, VFragment, VNode;
|
|
3130
3126
|
var init_vdom = __esm(() => {
|
|
3131
3127
|
VText = class VText extends VBase {
|
|
3132
3128
|
constructor(text) {
|
|
@@ -3190,10 +3186,13 @@ var init_vdom = __esm(() => {
|
|
|
3190
3186
|
get nodeType() {
|
|
3191
3187
|
return 1;
|
|
3192
3188
|
}
|
|
3189
|
+
isSameKind(other) {
|
|
3190
|
+
return this.tag === other.tag && this.namespace === other.namespace && this.key === other.key;
|
|
3191
|
+
}
|
|
3193
3192
|
isEqualTo(other) {
|
|
3194
3193
|
if (this === other)
|
|
3195
3194
|
return true;
|
|
3196
|
-
if (!(other instanceof VNode) || this.
|
|
3195
|
+
if (!(other instanceof VNode) || !this.isSameKind(other) || this.childs.length !== other.childs.length) {
|
|
3197
3196
|
return false;
|
|
3198
3197
|
}
|
|
3199
3198
|
if (this.attrs !== other.attrs) {
|
|
@@ -3221,7 +3220,6 @@ var init_vdom = __esm(() => {
|
|
|
3221
3220
|
return node;
|
|
3222
3221
|
}
|
|
3223
3222
|
};
|
|
3224
|
-
renderCache = new WeakMap;
|
|
3225
3223
|
});
|
|
3226
3224
|
|
|
3227
3225
|
// src/app.js
|
|
@@ -3244,6 +3242,7 @@ class App {
|
|
|
3244
3242
|
};
|
|
3245
3243
|
this._compiled = false;
|
|
3246
3244
|
this._renderOpts = { document: rootNode.ownerDocument };
|
|
3245
|
+
this._renderState = null;
|
|
3247
3246
|
}
|
|
3248
3247
|
get state() {
|
|
3249
3248
|
return this.transactor.state;
|
|
@@ -3350,7 +3349,10 @@ class App {
|
|
|
3350
3349
|
render() {
|
|
3351
3350
|
const root = this.state.val;
|
|
3352
3351
|
const stack = this.makeStack(root);
|
|
3353
|
-
|
|
3352
|
+
const { renderer, rootNode, _renderOpts, _renderState } = this;
|
|
3353
|
+
const newState = render(renderer.renderRoot(stack, root), rootNode, _renderOpts, _renderState);
|
|
3354
|
+
this._renderState = newState;
|
|
3355
|
+
return newState.dom;
|
|
3354
3356
|
}
|
|
3355
3357
|
onChange(callback) {
|
|
3356
3358
|
this.transactor.state.onChange(callback);
|
|
@@ -7721,7 +7723,7 @@ class Renderer {
|
|
|
7721
7723
|
renderToDOM(stack, val) {
|
|
7722
7724
|
const rootNode = document.createElement("div");
|
|
7723
7725
|
const rOpts = { document };
|
|
7724
|
-
render(h("
|
|
7726
|
+
render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
|
|
7725
7727
|
return rootNode.childNodes[0];
|
|
7726
7728
|
}
|
|
7727
7729
|
renderToString(stack, val, cleanAttrs = true) {
|
|
@@ -8069,9 +8071,6 @@ MODULE CONVENTION
|
|
|
8069
8071
|
|
|
8070
8072
|
export function getRoot() // optional; returned by info
|
|
8071
8073
|
|
|
8072
|
-
The legacy \`getStoryBookSection()\` name fails fast with
|
|
8073
|
-
EXAMPLES_SHAPE_MISMATCH — rename it to \`getExamples\`.
|
|
8074
|
-
|
|
8075
8074
|
COMMANDS (require <module-path>)
|
|
8076
8075
|
info
|
|
8077
8076
|
Summarize which getX() exports are present and count components,
|
|
@@ -8184,18 +8183,18 @@ init_lint_check();
|
|
|
8184
8183
|
import { JSDOM } from "jsdom";
|
|
8185
8184
|
async function createNodeEnv() {
|
|
8186
8185
|
const dom = new JSDOM("<!DOCTYPE html><html><head></head><body></body></html>");
|
|
8187
|
-
const {
|
|
8188
|
-
globalThis.document =
|
|
8186
|
+
const { document: document2, Text, Comment } = dom.window;
|
|
8187
|
+
globalThis.document = document2;
|
|
8189
8188
|
|
|
8190
8189
|
class HeadlessParseContext extends ParseContext {
|
|
8191
8190
|
constructor() {
|
|
8192
|
-
super(
|
|
8191
|
+
super(document2, Text, Comment);
|
|
8193
8192
|
}
|
|
8194
8193
|
}
|
|
8195
8194
|
|
|
8196
8195
|
class HeadlessLintParseContext extends LintParseContext {
|
|
8197
8196
|
constructor() {
|
|
8198
|
-
super(
|
|
8197
|
+
super(document2, Text, Comment);
|
|
8199
8198
|
}
|
|
8200
8199
|
}
|
|
8201
8200
|
return {
|
package/dist/tutuca-dev.js
CHANGED
|
@@ -918,8 +918,8 @@ class TextNode extends BaseNode {
|
|
|
918
918
|
}
|
|
919
919
|
return false;
|
|
920
920
|
}
|
|
921
|
-
condenseWhiteSpace() {
|
|
922
|
-
this.val =
|
|
921
|
+
condenseWhiteSpace(replacement = "") {
|
|
922
|
+
this.val = replacement;
|
|
923
923
|
}
|
|
924
924
|
isConstant() {
|
|
925
925
|
return true;
|
|
@@ -993,7 +993,6 @@ class FragmentNode extends ChildsNode {
|
|
|
993
993
|
}
|
|
994
994
|
var maybeFragment = (xs) => xs.length === 1 ? xs[0] : new FragmentNode(xs);
|
|
995
995
|
var VALID_NODE_RE = /^[a-zA-Z][a-zA-Z0-9-]*$/;
|
|
996
|
-
var _parser = null;
|
|
997
996
|
|
|
998
997
|
class ANode extends BaseNode {
|
|
999
998
|
constructor(nodeId, val) {
|
|
@@ -1005,9 +1004,7 @@ class ANode extends BaseNode {
|
|
|
1005
1004
|
return this.val.toPathItem();
|
|
1006
1005
|
}
|
|
1007
1006
|
static parse(html, px) {
|
|
1008
|
-
|
|
1009
|
-
const nodes = _parser.parseFromString(html, "text/html").body.childNodes;
|
|
1010
|
-
return ANode.fromDOM(nodes[0] ?? new px.Text(""), px);
|
|
1007
|
+
return ANode.fromDOM(px.parseHTML(html)[0] ?? new px.Text(""), px);
|
|
1011
1008
|
}
|
|
1012
1009
|
static fromDOM(node, px) {
|
|
1013
1010
|
if (node instanceof px.Text)
|
|
@@ -1058,7 +1055,7 @@ class ANode extends BaseNode {
|
|
|
1058
1055
|
if (textChild)
|
|
1059
1056
|
childs.unshift(new RenderTextNode(null, textChild));
|
|
1060
1057
|
const domChilds = tag !== "PRE" ? condenseChildsWhites(childs) : childs;
|
|
1061
|
-
return wrap(new DomNode(tag
|
|
1058
|
+
return wrap(new DomNode(tag, nAttrs, domChilds), px, wrappers);
|
|
1062
1059
|
}
|
|
1063
1060
|
return new CommentNode(`Error: InvalidTagName ${tag}`);
|
|
1064
1061
|
}
|
|
@@ -1300,13 +1297,13 @@ var WRAPPER_NODES = {
|
|
|
1300
1297
|
};
|
|
1301
1298
|
|
|
1302
1299
|
class ParseContext {
|
|
1303
|
-
constructor(
|
|
1300
|
+
constructor(document2, Text, Comment, nodes, events, macroNodes, frame, parent) {
|
|
1304
1301
|
this.nodes = nodes ?? [];
|
|
1305
1302
|
this.events = events ?? [];
|
|
1306
1303
|
this.macroNodes = macroNodes ?? [];
|
|
1307
1304
|
this.parent = parent ?? null;
|
|
1308
1305
|
this.frame = frame ?? {};
|
|
1309
|
-
this.
|
|
1306
|
+
this.document = document2 ?? globalThis.document;
|
|
1310
1307
|
this.Text = Text ?? globalThis.Text;
|
|
1311
1308
|
this.Comment = Comment ?? globalThis.Comment;
|
|
1312
1309
|
this.cacheConstNodes = true;
|
|
@@ -1315,12 +1312,14 @@ class ParseContext {
|
|
|
1315
1312
|
return this.frame.macroName === name || this.parent?.isInsideMacro(name);
|
|
1316
1313
|
}
|
|
1317
1314
|
enterMacro(macroName, macroVars, macroSlots) {
|
|
1318
|
-
const {
|
|
1315
|
+
const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
|
|
1319
1316
|
const frame = { macroName, macroVars, macroSlots };
|
|
1320
|
-
return new ParseContext(
|
|
1317
|
+
return new ParseContext(document2, Text, Comment, nodes, events, macroNodes, frame, this);
|
|
1321
1318
|
}
|
|
1322
|
-
|
|
1323
|
-
|
|
1319
|
+
parseHTML(html) {
|
|
1320
|
+
const t = this.document.createElement("template");
|
|
1321
|
+
t.innerHTML = html;
|
|
1322
|
+
return Array.from(t.content.childNodes);
|
|
1324
1323
|
}
|
|
1325
1324
|
addNodeIf(Class, val, extra) {
|
|
1326
1325
|
if (val !== null) {
|
|
@@ -1365,29 +1364,35 @@ class ParseContext {
|
|
|
1365
1364
|
}
|
|
1366
1365
|
onAttributes(_attrs, _wrapperAttrs, _textChild, _isMacroCall) {}
|
|
1367
1366
|
}
|
|
1368
|
-
var
|
|
1369
|
-
var
|
|
1367
|
+
var _htmlBlockTags = "ADDRESS,ARTICLE,ASIDE,BLOCKQUOTE,CAPTION,COL,COLGROUP,DETAILS,DIALOG,DIV,DD,DL,DT,FIELDSET,FIGCAPTION,FIGURE,FOOTER,FORM,H1,H2,H3,H4,H5,H6,HEADER,HGROUP,HR,LEGEND,LI,MAIN,MENU,NAV,OL,P,PRE,SECTION,SUMMARY,TABLE,TBODY,TD,TFOOT,TH,THEAD,TR,UL";
|
|
1368
|
+
var HTML_BLOCK_TAGS = new Set(_htmlBlockTags.split(","));
|
|
1369
|
+
var isBlockDomNode = (n) => {
|
|
1370
|
+
const node = n instanceof FragmentNode ? n.childs[0] : n;
|
|
1371
|
+
return node instanceof DomNode && HTML_BLOCK_TAGS.has(node.tagName);
|
|
1372
|
+
};
|
|
1370
1373
|
function condenseChildsWhites(childs) {
|
|
1371
|
-
|
|
1372
|
-
if (end === 0)
|
|
1374
|
+
if (childs.length === 0)
|
|
1373
1375
|
return childs;
|
|
1374
|
-
let start = 0;
|
|
1375
1376
|
let changed = false;
|
|
1376
|
-
if (
|
|
1377
|
-
|
|
1377
|
+
if (childs[0].isWhiteSpace?.()) {
|
|
1378
|
+
childs[0].condenseWhiteSpace();
|
|
1378
1379
|
changed = true;
|
|
1379
1380
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1381
|
+
const last = childs.length - 1;
|
|
1382
|
+
if (last > 0 && childs[last].isWhiteSpace?.()) {
|
|
1383
|
+
childs[last].condenseWhiteSpace();
|
|
1382
1384
|
changed = true;
|
|
1383
1385
|
}
|
|
1384
|
-
for (let i = 1;i <
|
|
1386
|
+
for (let i = 1;i < last; i++) {
|
|
1385
1387
|
const cur = childs[i];
|
|
1386
|
-
if (
|
|
1387
|
-
|
|
1388
|
+
if (cur.isWhiteSpace?.() && cur.hasNewLine()) {
|
|
1389
|
+
const bothBlock = isBlockDomNode(childs[i - 1]) && isBlockDomNode(childs[i + 1]);
|
|
1390
|
+
cur.condenseWhiteSpace(bothBlock ? "" : " ");
|
|
1391
|
+
if (bothBlock)
|
|
1392
|
+
changed = true;
|
|
1388
1393
|
}
|
|
1389
1394
|
}
|
|
1390
|
-
return changed ? childs.
|
|
1395
|
+
return changed ? childs.filter((c) => !(c instanceof TextNode && c.val === "")) : childs;
|
|
1391
1396
|
}
|
|
1392
1397
|
|
|
1393
1398
|
class View {
|
|
@@ -1494,9 +1499,9 @@ class ParseCtxClassSetCollector extends ParseContext {
|
|
|
1494
1499
|
}
|
|
1495
1500
|
}
|
|
1496
1501
|
enterMacro(macroName, macroVars, macroSlots) {
|
|
1497
|
-
const {
|
|
1502
|
+
const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
|
|
1498
1503
|
const frame = { macroName, macroVars, macroSlots };
|
|
1499
|
-
const v = new ParseCtxClassSetCollector(
|
|
1504
|
+
const v = new ParseCtxClassSetCollector(document2, Text, Comment, nodes, events, macroNodes, frame, this);
|
|
1500
1505
|
v.classes = this.classes;
|
|
1501
1506
|
return v;
|
|
1502
1507
|
}
|
|
@@ -1876,8 +1881,8 @@ class LintContext {
|
|
|
1876
1881
|
}
|
|
1877
1882
|
|
|
1878
1883
|
class LintParseContext extends ParseContext {
|
|
1879
|
-
constructor(
|
|
1880
|
-
super(
|
|
1884
|
+
constructor(document2, Text, Comment) {
|
|
1885
|
+
super(document2, Text, Comment);
|
|
1881
1886
|
this.attrs = [];
|
|
1882
1887
|
}
|
|
1883
1888
|
onAttributes(attrs, wrapperAttrs, textChild, isMacroCall = false) {
|
|
@@ -2824,10 +2829,13 @@ class VNode extends VBase {
|
|
|
2824
2829
|
get nodeType() {
|
|
2825
2830
|
return 1;
|
|
2826
2831
|
}
|
|
2832
|
+
isSameKind(other) {
|
|
2833
|
+
return this.tag === other.tag && this.namespace === other.namespace && this.key === other.key;
|
|
2834
|
+
}
|
|
2827
2835
|
isEqualTo(other) {
|
|
2828
2836
|
if (this === other)
|
|
2829
2837
|
return true;
|
|
2830
|
-
if (!(other instanceof VNode) || this.
|
|
2838
|
+
if (!(other instanceof VNode) || !this.isSameKind(other) || this.childs.length !== other.childs.length) {
|
|
2831
2839
|
return false;
|
|
2832
2840
|
}
|
|
2833
2841
|
if (this.attrs !== other.attrs) {
|
|
@@ -2902,23 +2910,20 @@ function morphNode(domNode, source, target, opts) {
|
|
|
2902
2910
|
domNode.data = target.text;
|
|
2903
2911
|
return domNode;
|
|
2904
2912
|
}
|
|
2905
|
-
if (type === 1 && source.
|
|
2913
|
+
if (type === 1 && source.isSameKind(target)) {
|
|
2906
2914
|
const propsDiff = diffProps(source.attrs, target.attrs);
|
|
2907
2915
|
const isSelect = source.tag === "SELECT";
|
|
2908
2916
|
if (propsDiff) {
|
|
2909
2917
|
if (isSelect && "value" in propsDiff) {
|
|
2910
2918
|
const { value: _v, ...rest } = propsDiff;
|
|
2911
2919
|
applyProperties(domNode, rest, source.attrs);
|
|
2912
|
-
} else
|
|
2920
|
+
} else
|
|
2913
2921
|
applyProperties(domNode, propsDiff, source.attrs);
|
|
2914
|
-
}
|
|
2915
2922
|
}
|
|
2916
|
-
if (!target.attrs.dangerouslySetInnerHTML)
|
|
2923
|
+
if (!target.attrs.dangerouslySetInnerHTML)
|
|
2917
2924
|
morphChildren(domNode, source.childs, target.childs, opts);
|
|
2918
|
-
|
|
2919
|
-
if (isSelect && target.attrs.value !== undefined) {
|
|
2925
|
+
if (isSelect && target.attrs.value !== undefined)
|
|
2920
2926
|
applyProperties(domNode, { value: target.attrs.value }, source.attrs);
|
|
2921
|
-
}
|
|
2922
2927
|
return domNode;
|
|
2923
2928
|
}
|
|
2924
2929
|
if (type === 11) {
|
|
@@ -2997,24 +3002,20 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
|
|
|
2997
3002
|
if (!used[i] && domNodes[i].parentNode === parentDom)
|
|
2998
3003
|
parentDom.removeChild(domNodes[i]);
|
|
2999
3004
|
}
|
|
3000
|
-
|
|
3001
|
-
function render(vnode, container, options) {
|
|
3002
|
-
const cached = renderCache.get(container);
|
|
3005
|
+
function render(vnode, container, options, prev) {
|
|
3003
3006
|
const isFragment = vnode instanceof VFragment;
|
|
3004
|
-
if (
|
|
3005
|
-
const oldDom = isFragment ? container :
|
|
3006
|
-
const newDom = morphNode(oldDom,
|
|
3007
|
-
|
|
3008
|
-
return newDom;
|
|
3007
|
+
if (prev && prev.vnode instanceof VFragment === isFragment) {
|
|
3008
|
+
const oldDom = isFragment ? container : prev.dom;
|
|
3009
|
+
const newDom = morphNode(oldDom, prev.vnode, vnode, options);
|
|
3010
|
+
return { vnode, dom: isFragment ? container : newDom };
|
|
3009
3011
|
}
|
|
3010
|
-
renderCache.delete(container);
|
|
3011
3012
|
const domNode = vnode.toDom(options);
|
|
3012
3013
|
container.replaceChildren(domNode);
|
|
3013
|
-
|
|
3014
|
-
return domNode;
|
|
3014
|
+
return { vnode, dom: isFragment ? container : domNode };
|
|
3015
3015
|
}
|
|
3016
3016
|
function h(tagName, properties, children) {
|
|
3017
|
-
const
|
|
3017
|
+
const c = tagName.charCodeAt(0);
|
|
3018
|
+
const tag = c >= 97 && c <= 122 ? tagName.toUpperCase() : tagName;
|
|
3018
3019
|
const props = {};
|
|
3019
3020
|
let key, namespace;
|
|
3020
3021
|
if (properties) {
|
|
@@ -3065,6 +3066,7 @@ class App {
|
|
|
3065
3066
|
};
|
|
3066
3067
|
this._compiled = false;
|
|
3067
3068
|
this._renderOpts = { document: rootNode.ownerDocument };
|
|
3069
|
+
this._renderState = null;
|
|
3068
3070
|
}
|
|
3069
3071
|
get state() {
|
|
3070
3072
|
return this.transactor.state;
|
|
@@ -3171,7 +3173,10 @@ class App {
|
|
|
3171
3173
|
render() {
|
|
3172
3174
|
const root = this.state.val;
|
|
3173
3175
|
const stack = this.makeStack(root);
|
|
3174
|
-
|
|
3176
|
+
const { renderer, rootNode, _renderOpts, _renderState } = this;
|
|
3177
|
+
const newState = render(renderer.renderRoot(stack, root), rootNode, _renderOpts, _renderState);
|
|
3178
|
+
this._renderState = newState;
|
|
3179
|
+
return newState.dom;
|
|
3175
3180
|
}
|
|
3176
3181
|
onChange(callback) {
|
|
3177
3182
|
this.transactor.state.onChange(callback);
|
|
@@ -8093,7 +8098,7 @@ class Renderer {
|
|
|
8093
8098
|
renderToDOM(stack, val) {
|
|
8094
8099
|
const rootNode = document.createElement("div");
|
|
8095
8100
|
const rOpts = { document };
|
|
8096
|
-
render(h("
|
|
8101
|
+
render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
|
|
8097
8102
|
return rootNode.childNodes[0];
|
|
8098
8103
|
}
|
|
8099
8104
|
renderToString(stack, val, cleanAttrs = true) {
|
|
@@ -8558,9 +8563,9 @@ class LintClassCollectorCtx extends ParseCtxClassSetCollector {
|
|
|
8558
8563
|
this.attrs = [];
|
|
8559
8564
|
}
|
|
8560
8565
|
enterMacro(macroName, macroVars, macroSlots) {
|
|
8561
|
-
const {
|
|
8566
|
+
const { document: document2, Text, Comment, nodes, events, macroNodes } = this;
|
|
8562
8567
|
const frame = { macroName, macroVars, macroSlots };
|
|
8563
|
-
const v = new LintClassCollectorCtx(
|
|
8568
|
+
const v = new LintClassCollectorCtx(document2, Text, Comment, nodes, events, macroNodes, frame, this);
|
|
8564
8569
|
v.classes = this.classes;
|
|
8565
8570
|
v.attrs = this.attrs;
|
|
8566
8571
|
return v;
|