tutuca 0.9.97 → 0.9.98
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/tutuca-cli.js +190 -59
- package/dist/tutuca-dev.ext.js +76 -29
- package/dist/tutuca-dev.js +76 -29
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.ext.js +56 -28
- package/dist/tutuca-extra.js +56 -28
- package/dist/tutuca-extra.min.js +2 -2
- package/dist/tutuca-storybook.js +11 -4
- package/dist/tutuca.ext.js +56 -28
- package/dist/tutuca.js +56 -28
- package/dist/tutuca.min.js +2 -2
- package/package.json +3 -3
- package/skill/tutuca/advanced.md +14 -5
- package/skill/tutuca/core.md +78 -15
- package/skill/tutuca/margaui.md +25 -13
- package/skill/tutuca/patterns/README.md +1 -0
- package/skill/tutuca/patterns/filter-a-list.md +3 -1
- package/skill/tutuca/patterns/filter-and-paginate.md +116 -0
- package/skill/tutuca/patterns/paginate-a-list.md +3 -1
- package/skill/tutuca/storybook.md +7 -2
- package/skill/tutuca/testing.md +11 -0
- package/skill/tutuca-source/tutuca.ext.js +56 -28
package/dist/tutuca-storybook.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/storybook.js
|
|
2
|
-
import { component, dispatchPhase, html, injectCss, tutuca } from "tutuca";
|
|
2
|
+
import { component, dispatchPhase, html, injectCss, phaseHasBubble, tutuca } from "tutuca";
|
|
3
3
|
var Storybook = component({
|
|
4
4
|
name: "Storybook",
|
|
5
5
|
fields: {
|
|
@@ -274,18 +274,25 @@ var Example = component({
|
|
|
274
274
|
},
|
|
275
275
|
receive: {
|
|
276
276
|
init(ctx) {
|
|
277
|
-
|
|
277
|
+
this.runPhase(ctx, "init", this.on?.init);
|
|
278
278
|
return this;
|
|
279
279
|
},
|
|
280
280
|
resume(ctx) {
|
|
281
|
-
|
|
281
|
+
this.runPhase(ctx, "resume", this.on?.resume);
|
|
282
282
|
return this;
|
|
283
283
|
},
|
|
284
284
|
suspend(ctx) {
|
|
285
|
-
|
|
285
|
+
this.runPhase(ctx, "suspend", this.on?.suspend);
|
|
286
286
|
return this;
|
|
287
287
|
}
|
|
288
288
|
},
|
|
289
|
+
methods: {
|
|
290
|
+
runPhase(ctx, name, phase) {
|
|
291
|
+
if (phaseHasBubble(phase))
|
|
292
|
+
console.warn(`storybook on.${name}: a \`bubble\` action leaves this example and is received by the storybook engine, so your component's bubble handler won't run. Use send/request/input to drive a preset state.`);
|
|
293
|
+
dispatchPhase(ctx, ctx.at.field("value").buildPath(), phase, this.value);
|
|
294
|
+
}
|
|
295
|
+
},
|
|
289
296
|
input: {
|
|
290
297
|
onLogSelected() {
|
|
291
298
|
console.log(this.value);
|
package/dist/tutuca.ext.js
CHANGED
|
@@ -1744,37 +1744,47 @@ class Renderer {
|
|
|
1744
1744
|
renderEach(stack, iterInfo, node, viewName) {
|
|
1745
1745
|
const { seq, filter, loopWith } = iterInfo.eval(stack);
|
|
1746
1746
|
const r = [];
|
|
1747
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1747
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
1748
|
+
const renderOne = (key, value, attrName) => {
|
|
1749
|
+
const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
|
|
1750
|
+
this.pushEachEntry(r, node.nodeId, attrName, key, dom);
|
|
1751
|
+
};
|
|
1752
|
+
if (keys)
|
|
1753
|
+
imKeysIter(seq, renderOne, keys);
|
|
1754
|
+
else
|
|
1755
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
1756
|
+
if (filter.call(stack.it, key, value, iterData))
|
|
1757
|
+
renderOne(key, value, attrName);
|
|
1758
|
+
}, start, end);
|
|
1754
1759
|
return r;
|
|
1755
1760
|
}
|
|
1756
1761
|
renderEachWhen(stack, iterInfo, view, nid) {
|
|
1757
1762
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
1758
1763
|
const r = [];
|
|
1759
1764
|
const it = stack.it;
|
|
1760
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
1775
|
-
}
|
|
1765
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
|
|
1766
|
+
const renderOne = (key, value, attrName) => {
|
|
1767
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
1768
|
+
const binds = { key, value };
|
|
1769
|
+
const cacheKey = `${nid}-${key}`;
|
|
1770
|
+
if (enricher)
|
|
1771
|
+
enricher.call(it, binds, key, value, iterData);
|
|
1772
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
1773
|
+
if (cachedNode)
|
|
1774
|
+
this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
1775
|
+
else {
|
|
1776
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
1777
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
1778
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
1776
1779
|
}
|
|
1777
|
-
}
|
|
1780
|
+
};
|
|
1781
|
+
if (keys)
|
|
1782
|
+
imKeysIter(seq, renderOne, keys);
|
|
1783
|
+
else
|
|
1784
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
1785
|
+
if (filter.call(it, key, value, iterData))
|
|
1786
|
+
renderOne(key, value, attrName);
|
|
1787
|
+
}, start, end);
|
|
1778
1788
|
return r;
|
|
1779
1789
|
}
|
|
1780
1790
|
renderView(view, stack) {
|
|
@@ -1810,8 +1820,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
|
1810
1820
|
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
1811
1821
|
var unpackLoopResult = (result, seq) => {
|
|
1812
1822
|
const r = result ?? {};
|
|
1813
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
|
|
1823
|
+
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
1824
|
+
};
|
|
1825
|
+
var imKeysIter = (seq, visit, keys) => {
|
|
1826
|
+
const attrName = isIndexed(seq) ? "si" : "sk";
|
|
1827
|
+
for (const key of keys)
|
|
1828
|
+
visit(key, seq.get(key), attrName);
|
|
1814
1829
|
};
|
|
1830
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
1831
|
+
lookup: (name) => stack.lookupBind(name),
|
|
1832
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
1833
|
+
});
|
|
1815
1834
|
var imIndexedIter = (seq, visit, start, end) => {
|
|
1816
1835
|
const [s, e] = normalizeRange(start, end, seq.size);
|
|
1817
1836
|
for (let i = s;i < e; i++)
|
|
@@ -2359,11 +2378,11 @@ class IterInfo {
|
|
|
2359
2378
|
return { seq, filter, loopWith, enricher };
|
|
2360
2379
|
}
|
|
2361
2380
|
enrichBinds(stack, key) {
|
|
2362
|
-
const { seq, loopWith, enricher } = this.eval(stack);
|
|
2381
|
+
const { seq, filter, loopWith, enricher } = this.eval(stack);
|
|
2363
2382
|
const value = seq?.get ? seq.get(key, null) : null;
|
|
2364
2383
|
const binds = { key, value };
|
|
2365
2384
|
if (enricher) {
|
|
2366
|
-
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
2385
|
+
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
2367
2386
|
enricher.call(stack.it, binds, key, value, iterData);
|
|
2368
2387
|
}
|
|
2369
2388
|
return binds;
|
|
@@ -3714,6 +3733,13 @@ function phaseOps(phase) {
|
|
|
3714
3733
|
function resolveArgs(args, self) {
|
|
3715
3734
|
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
3716
3735
|
}
|
|
3736
|
+
function phaseHasBubble(phase) {
|
|
3737
|
+
if (!phase)
|
|
3738
|
+
return false;
|
|
3739
|
+
if (phase.bubble?.length)
|
|
3740
|
+
return true;
|
|
3741
|
+
return (phase.do ?? []).some((op) => op.type === "bubble");
|
|
3742
|
+
}
|
|
3717
3743
|
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
3718
3744
|
if (!phase)
|
|
3719
3745
|
return;
|
|
@@ -4007,7 +4033,8 @@ class FieldSet extends Field {
|
|
|
4007
4033
|
}
|
|
4008
4034
|
function mkCompField(field, scope, args) {
|
|
4009
4035
|
const Comp = scope?.lookupComponent(field.type) ?? null;
|
|
4010
|
-
|
|
4036
|
+
if (Comp === null)
|
|
4037
|
+
console.warn(scope ? `component field "${field.name}": component "${field.type}" not found in scope` : `component field "${field.name}": cannot resolve component "${field.type}" — built without a registered scope (use ${field.type}.make({}) as the default, or build via a registered component)`);
|
|
4011
4038
|
return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
|
|
4012
4039
|
}
|
|
4013
4040
|
|
|
@@ -4156,6 +4183,7 @@ export {
|
|
|
4156
4183
|
removeIn,
|
|
4157
4184
|
remove,
|
|
4158
4185
|
phaseOps,
|
|
4186
|
+
phaseHasBubble,
|
|
4159
4187
|
mergeWith,
|
|
4160
4188
|
mergeDeepWith,
|
|
4161
4189
|
mergeDeep,
|
package/dist/tutuca.js
CHANGED
|
@@ -6114,37 +6114,47 @@ class Renderer {
|
|
|
6114
6114
|
renderEach(stack, iterInfo, node, viewName) {
|
|
6115
6115
|
const { seq, filter, loopWith } = iterInfo.eval(stack);
|
|
6116
6116
|
const r = [];
|
|
6117
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6117
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6118
|
+
const renderOne = (key, value, attrName) => {
|
|
6119
|
+
const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
|
|
6120
|
+
this.pushEachEntry(r, node.nodeId, attrName, key, dom);
|
|
6121
|
+
};
|
|
6122
|
+
if (keys)
|
|
6123
|
+
imKeysIter(seq, renderOne, keys);
|
|
6124
|
+
else
|
|
6125
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
6126
|
+
if (filter.call(stack.it, key, value, iterData))
|
|
6127
|
+
renderOne(key, value, attrName);
|
|
6128
|
+
}, start, end);
|
|
6124
6129
|
return r;
|
|
6125
6130
|
}
|
|
6126
6131
|
renderEachWhen(stack, iterInfo, view, nid) {
|
|
6127
6132
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
6128
6133
|
const r = [];
|
|
6129
6134
|
const it = stack.it;
|
|
6130
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
6145
|
-
}
|
|
6135
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6136
|
+
const renderOne = (key, value, attrName) => {
|
|
6137
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
6138
|
+
const binds = { key, value };
|
|
6139
|
+
const cacheKey = `${nid}-${key}`;
|
|
6140
|
+
if (enricher)
|
|
6141
|
+
enricher.call(it, binds, key, value, iterData);
|
|
6142
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
6143
|
+
if (cachedNode)
|
|
6144
|
+
this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
6145
|
+
else {
|
|
6146
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
6147
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
6148
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
6146
6149
|
}
|
|
6147
|
-
}
|
|
6150
|
+
};
|
|
6151
|
+
if (keys)
|
|
6152
|
+
imKeysIter(seq, renderOne, keys);
|
|
6153
|
+
else
|
|
6154
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
6155
|
+
if (filter.call(it, key, value, iterData))
|
|
6156
|
+
renderOne(key, value, attrName);
|
|
6157
|
+
}, start, end);
|
|
6148
6158
|
return r;
|
|
6149
6159
|
}
|
|
6150
6160
|
renderView(view, stack) {
|
|
@@ -6180,8 +6190,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
|
6180
6190
|
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
6181
6191
|
var unpackLoopResult = (result, seq) => {
|
|
6182
6192
|
const r = result ?? {};
|
|
6183
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
|
|
6193
|
+
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
6184
6194
|
};
|
|
6195
|
+
var imKeysIter = (seq, visit, keys) => {
|
|
6196
|
+
const attrName = isIndexed(seq) ? "si" : "sk";
|
|
6197
|
+
for (const key of keys)
|
|
6198
|
+
visit(key, seq.get(key), attrName);
|
|
6199
|
+
};
|
|
6200
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
6201
|
+
lookup: (name) => stack.lookupBind(name),
|
|
6202
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
6203
|
+
});
|
|
6185
6204
|
var imIndexedIter = (seq, visit, start, end) => {
|
|
6186
6205
|
const [s, e] = normalizeRange(start, end, seq.size);
|
|
6187
6206
|
for (let i = s;i < e; i++)
|
|
@@ -6729,11 +6748,11 @@ class IterInfo {
|
|
|
6729
6748
|
return { seq, filter, loopWith, enricher };
|
|
6730
6749
|
}
|
|
6731
6750
|
enrichBinds(stack, key) {
|
|
6732
|
-
const { seq, loopWith, enricher } = this.eval(stack);
|
|
6751
|
+
const { seq, filter, loopWith, enricher } = this.eval(stack);
|
|
6733
6752
|
const value = seq?.get ? seq.get(key, null) : null;
|
|
6734
6753
|
const binds = { key, value };
|
|
6735
6754
|
if (enricher) {
|
|
6736
|
-
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
6755
|
+
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6737
6756
|
enricher.call(stack.it, binds, key, value, iterData);
|
|
6738
6757
|
}
|
|
6739
6758
|
return binds;
|
|
@@ -8028,6 +8047,13 @@ function phaseOps(phase) {
|
|
|
8028
8047
|
function resolveArgs(args, self) {
|
|
8029
8048
|
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
8030
8049
|
}
|
|
8050
|
+
function phaseHasBubble(phase) {
|
|
8051
|
+
if (!phase)
|
|
8052
|
+
return false;
|
|
8053
|
+
if (phase.bubble?.length)
|
|
8054
|
+
return true;
|
|
8055
|
+
return (phase.do ?? []).some((op) => op.type === "bubble");
|
|
8056
|
+
}
|
|
8031
8057
|
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
8032
8058
|
if (!phase)
|
|
8033
8059
|
return;
|
|
@@ -8320,7 +8346,8 @@ class FieldSet extends Field {
|
|
|
8320
8346
|
}
|
|
8321
8347
|
function mkCompField(field, scope, args) {
|
|
8322
8348
|
const Comp = scope?.lookupComponent(field.type) ?? null;
|
|
8323
|
-
|
|
8349
|
+
if (Comp === null)
|
|
8350
|
+
console.warn(scope ? `component field "${field.name}": component "${field.type}" not found in scope` : `component field "${field.name}": cannot resolve component "${field.type}" — built without a registered scope (use ${field.type}.make({}) as the default, or build via a registered component)`);
|
|
8324
8351
|
return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
|
|
8325
8352
|
}
|
|
8326
8353
|
|
|
@@ -8469,6 +8496,7 @@ export {
|
|
|
8469
8496
|
removeIn,
|
|
8470
8497
|
remove,
|
|
8471
8498
|
phaseOps,
|
|
8499
|
+
phaseHasBubble,
|
|
8472
8500
|
mergeWith$1 as mergeWith,
|
|
8473
8501
|
mergeDeepWith$1 as mergeDeepWith,
|
|
8474
8502
|
mergeDeep$1 as mergeDeep,
|