@llui/dom 0.0.1
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/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/addressed.d.ts +16 -0
- package/dist/addressed.d.ts.map +1 -0
- package/dist/addressed.js +40 -0
- package/dist/addressed.js.map +1 -0
- package/dist/binding.d.ts +18 -0
- package/dist/binding.d.ts.map +1 -0
- package/dist/binding.js +62 -0
- package/dist/binding.js.map +1 -0
- package/dist/chain-update.d.ts +7 -0
- package/dist/chain-update.d.ts.map +1 -0
- package/dist/chain-update.js +16 -0
- package/dist/chain-update.js.map +1 -0
- package/dist/component.d.ts +3 -0
- package/dist/component.d.ts.map +1 -0
- package/dist/component.js +4 -0
- package/dist/component.js.map +1 -0
- package/dist/devtools.d.ts +113 -0
- package/dist/devtools.d.ts.map +1 -0
- package/dist/devtools.js +390 -0
- package/dist/devtools.js.map +1 -0
- package/dist/el-split.d.ts +3 -0
- package/dist/el-split.d.ts.map +1 -0
- package/dist/el-split.js +54 -0
- package/dist/el-split.js.map +1 -0
- package/dist/el-template.d.ts +17 -0
- package/dist/el-template.d.ts.map +1 -0
- package/dist/el-template.js +64 -0
- package/dist/el-template.js.map +1 -0
- package/dist/elements.d.ts +80 -0
- package/dist/elements.d.ts.map +1 -0
- package/dist/elements.js +234 -0
- package/dist/elements.js.map +1 -0
- package/dist/form.d.ts +30 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +12 -0
- package/dist/form.js.map +1 -0
- package/dist/hmr.d.ts +20 -0
- package/dist/hmr.d.ts.map +1 -0
- package/dist/hmr.js +98 -0
- package/dist/hmr.js.map +1 -0
- package/dist/hydrate.d.ts +29 -0
- package/dist/hydrate.d.ts.map +1 -0
- package/dist/hydrate.js +96 -0
- package/dist/hydrate.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/merge-handlers.d.ts +7 -0
- package/dist/merge-handlers.d.ts.map +1 -0
- package/dist/merge-handlers.js +16 -0
- package/dist/merge-handlers.js.map +1 -0
- package/dist/mount.d.ts +14 -0
- package/dist/mount.d.ts.map +1 -0
- package/dist/mount.js +182 -0
- package/dist/mount.js.map +1 -0
- package/dist/primitives/branch.d.ts +3 -0
- package/dist/primitives/branch.d.ts.map +1 -0
- package/dist/primitives/branch.js +94 -0
- package/dist/primitives/branch.js.map +1 -0
- package/dist/primitives/child.d.ts +3 -0
- package/dist/primitives/child.d.ts.map +1 -0
- package/dist/primitives/child.js +77 -0
- package/dist/primitives/child.js.map +1 -0
- package/dist/primitives/context.d.ts +45 -0
- package/dist/primitives/context.d.ts.map +1 -0
- package/dist/primitives/context.js +87 -0
- package/dist/primitives/context.js.map +1 -0
- package/dist/primitives/each.d.ts +3 -0
- package/dist/primitives/each.d.ts.map +1 -0
- package/dist/primitives/each.js +515 -0
- package/dist/primitives/each.js.map +1 -0
- package/dist/primitives/error-boundary.d.ts +6 -0
- package/dist/primitives/error-boundary.d.ts.map +1 -0
- package/dist/primitives/error-boundary.js +32 -0
- package/dist/primitives/error-boundary.js.map +1 -0
- package/dist/primitives/foreign.d.ts +3 -0
- package/dist/primitives/foreign.d.ts.map +1 -0
- package/dist/primitives/foreign.js +80 -0
- package/dist/primitives/foreign.js.map +1 -0
- package/dist/primitives/memo.d.ts +3 -0
- package/dist/primitives/memo.d.ts.map +1 -0
- package/dist/primitives/memo.js +30 -0
- package/dist/primitives/memo.js.map +1 -0
- package/dist/primitives/on-mount.d.ts +2 -0
- package/dist/primitives/on-mount.d.ts.map +1 -0
- package/dist/primitives/on-mount.js +23 -0
- package/dist/primitives/on-mount.js.map +1 -0
- package/dist/primitives/portal.d.ts +3 -0
- package/dist/primitives/portal.d.ts.map +1 -0
- package/dist/primitives/portal.js +31 -0
- package/dist/primitives/portal.js.map +1 -0
- package/dist/primitives/selector.d.ts +22 -0
- package/dist/primitives/selector.d.ts.map +1 -0
- package/dist/primitives/selector.js +104 -0
- package/dist/primitives/selector.js.map +1 -0
- package/dist/primitives/show.d.ts +3 -0
- package/dist/primitives/show.d.ts.map +1 -0
- package/dist/primitives/show.js +12 -0
- package/dist/primitives/show.js.map +1 -0
- package/dist/primitives/slice.d.ts +23 -0
- package/dist/primitives/slice.d.ts.map +1 -0
- package/dist/primitives/slice.js +57 -0
- package/dist/primitives/slice.js.map +1 -0
- package/dist/primitives/text.d.ts +2 -0
- package/dist/primitives/text.d.ts.map +1 -0
- package/dist/primitives/text.js +35 -0
- package/dist/primitives/text.js.map +1 -0
- package/dist/render-context.d.ts +14 -0
- package/dist/render-context.d.ts.map +1 -0
- package/dist/render-context.js +14 -0
- package/dist/render-context.js.map +1 -0
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +14 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scope.d.ts +24 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +102 -0
- package/dist/scope.js.map +1 -0
- package/dist/slice-handler.d.ts +31 -0
- package/dist/slice-handler.d.ts.map +1 -0
- package/dist/slice-handler.js +34 -0
- package/dist/slice-handler.js.map +1 -0
- package/dist/ssr-dom.d.ts +12 -0
- package/dist/ssr-dom.d.ts.map +1 -0
- package/dist/ssr-dom.js +36 -0
- package/dist/ssr-dom.js.map +1 -0
- package/dist/ssr.d.ts +11 -0
- package/dist/ssr.d.ts.map +1 -0
- package/dist/ssr.js +127 -0
- package/dist/ssr.js.map +1 -0
- package/dist/structural.d.ts +4 -0
- package/dist/structural.d.ts.map +1 -0
- package/dist/structural.js +2 -0
- package/dist/structural.js.map +1 -0
- package/dist/types.d.ts +145 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/update-loop.d.ts +31 -0
- package/dist/update-loop.d.ts.map +1 -0
- package/dist/update-loop.js +236 -0
- package/dist/update-loop.js.map +1 -0
- package/dist/view-helpers.d.ts +44 -0
- package/dist/view-helpers.d.ts.map +1 -0
- package/dist/view-helpers.js +24 -0
- package/dist/view-helpers.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getRenderContext } from '../render-context';
|
|
2
|
+
import { createBinding } from '../binding';
|
|
3
|
+
import { createScope, addDisposer } from '../scope';
|
|
4
|
+
const FULL_MASK = 0xffffffff;
|
|
5
|
+
export function foreign(opts) {
|
|
6
|
+
const ctx = getRenderContext();
|
|
7
|
+
const parentScope = ctx.rootScope;
|
|
8
|
+
const foreignScope = createScope(parentScope);
|
|
9
|
+
// Create container element
|
|
10
|
+
const tag = opts.container?.tag ?? 'div';
|
|
11
|
+
const container = document.createElement(tag);
|
|
12
|
+
if (opts.container?.attrs) {
|
|
13
|
+
for (const [key, value] of Object.entries(opts.container.attrs)) {
|
|
14
|
+
container.setAttribute(key, value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// Mount the foreign instance
|
|
18
|
+
const instance = opts.mount({ container, send: ctx.send });
|
|
19
|
+
// Evaluate initial props and call sync
|
|
20
|
+
let prevProps = undefined;
|
|
21
|
+
const initialProps = opts.props(ctx.state);
|
|
22
|
+
if (typeof opts.sync === 'function') {
|
|
23
|
+
opts.sync({ instance, props: initialProps, prev: undefined });
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
for (const key of Object.keys(initialProps)) {
|
|
27
|
+
const handler = opts.sync[key];
|
|
28
|
+
if (handler) {
|
|
29
|
+
handler({ instance, value: initialProps[key], prev: undefined });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
prevProps = initialProps;
|
|
34
|
+
// Register a binding for the props accessor — fires when state changes
|
|
35
|
+
createBinding(foreignScope, {
|
|
36
|
+
mask: FULL_MASK,
|
|
37
|
+
accessor: ((state) => {
|
|
38
|
+
const newProps = opts.props(state);
|
|
39
|
+
// Shallow-diff props
|
|
40
|
+
let changed = false;
|
|
41
|
+
if (!prevProps) {
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
for (const key of Object.keys(newProps)) {
|
|
46
|
+
if (!Object.is(newProps[key], prevProps[key])) {
|
|
47
|
+
changed = true;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (changed) {
|
|
53
|
+
if (typeof opts.sync === 'function') {
|
|
54
|
+
opts.sync({ instance, props: newProps, prev: prevProps });
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
for (const key of Object.keys(newProps)) {
|
|
58
|
+
if (!prevProps || !Object.is(newProps[key], prevProps[key])) {
|
|
59
|
+
const handler = opts.sync[key];
|
|
60
|
+
if (handler) {
|
|
61
|
+
handler({ instance, value: newProps[key], prev: prevProps?.[key] });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
prevProps = newProps;
|
|
67
|
+
}
|
|
68
|
+
return newProps;
|
|
69
|
+
}),
|
|
70
|
+
kind: 'text', // kind doesn't matter — applyBinding won't be called
|
|
71
|
+
node: container,
|
|
72
|
+
perItem: false,
|
|
73
|
+
});
|
|
74
|
+
// Destroy on scope disposal
|
|
75
|
+
addDisposer(foreignScope, () => {
|
|
76
|
+
opts.destroy(instance);
|
|
77
|
+
});
|
|
78
|
+
return [container];
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=foreign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foreign.js","sourceRoot":"","sources":["../../src/primitives/foreign.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.d.ts","sourceRoot":"","sources":["../../src/primitives/memo.ts"],"names":[],"mappings":"AAGA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEtD;AAID,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CA0B5E"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Current dirty mask — set by the update loop during Phase 2
|
|
2
|
+
let currentDirtyMask = 0;
|
|
3
|
+
export function setCurrentDirtyMask(mask) {
|
|
4
|
+
currentDirtyMask = mask;
|
|
5
|
+
}
|
|
6
|
+
const UNSET = Symbol('unset');
|
|
7
|
+
export function memo(accessor, mask) {
|
|
8
|
+
let lastInput = UNSET;
|
|
9
|
+
let lastOutput;
|
|
10
|
+
return (s) => {
|
|
11
|
+
// Level 1: bitmask fast path — skip if dirty mask doesn't overlap
|
|
12
|
+
if (lastInput !== UNSET && mask !== undefined && (mask & currentDirtyMask) === 0) {
|
|
13
|
+
return lastOutput;
|
|
14
|
+
}
|
|
15
|
+
// Same state reference — skip
|
|
16
|
+
if (lastInput !== UNSET && Object.is(s, lastInput)) {
|
|
17
|
+
return lastOutput;
|
|
18
|
+
}
|
|
19
|
+
// Level 2: output stability — re-evaluate but return cached if same result
|
|
20
|
+
const result = accessor(s);
|
|
21
|
+
if (lastInput !== UNSET && Object.is(result, lastOutput)) {
|
|
22
|
+
lastInput = s;
|
|
23
|
+
return lastOutput;
|
|
24
|
+
}
|
|
25
|
+
lastInput = s;
|
|
26
|
+
lastOutput = result;
|
|
27
|
+
return result;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=memo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memo.js","sourceRoot":"","sources":["../../src/primitives/memo.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,IAAI,gBAAgB,GAAG,CAAC,CAAA;AAExB,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,gBAAgB,GAAG,IAAI,CAAA;AACzB,CAAC;AAED,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;AAE7B,MAAM,UAAU,IAAI,CAAO,QAAqB,EAAE,IAAa;IAC7D,IAAI,SAAS,GAAqB,KAAK,CAAA;IACvC,IAAI,UAAa,CAAA;IAEjB,OAAO,CAAC,CAAI,EAAE,EAAE;QACd,kEAAkE;QAClE,IAAI,SAAS,KAAK,KAAK,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,EAAE,CAAC;YACjF,OAAO,UAAU,CAAA;QACnB,CAAC;QAED,8BAA8B;QAC9B,IAAI,SAAS,KAAK,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC;YACnD,OAAO,UAAU,CAAA;QACnB,CAAC;QAED,2EAA2E;QAC3E,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAA;QAC1B,IAAI,SAAS,KAAK,KAAK,IAAI,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC;YACzD,SAAS,GAAG,CAAC,CAAA;YACb,OAAO,UAAU,CAAA;QACnB,CAAC;QAED,SAAS,GAAG,CAAC,CAAA;QACb,UAAU,GAAG,MAAM,CAAA;QACnB,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-mount.d.ts","sourceRoot":"","sources":["../../src/primitives/on-mount.ts"],"names":[],"mappings":"AAGA,wBAAgB,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAoB5E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { getRenderContext } from '../render-context';
|
|
2
|
+
import { addDisposer } from '../scope';
|
|
3
|
+
export function onMount(callback) {
|
|
4
|
+
// No-op on the server — event listeners and DOM callbacks are client-only
|
|
5
|
+
if (typeof window === 'undefined')
|
|
6
|
+
return;
|
|
7
|
+
const ctx = getRenderContext();
|
|
8
|
+
const scope = ctx.rootScope;
|
|
9
|
+
const container = ctx.container ?? document.body;
|
|
10
|
+
let cancelled = false;
|
|
11
|
+
addDisposer(scope, () => {
|
|
12
|
+
cancelled = true;
|
|
13
|
+
});
|
|
14
|
+
queueMicrotask(() => {
|
|
15
|
+
if (cancelled)
|
|
16
|
+
return;
|
|
17
|
+
const cleanup = callback(container);
|
|
18
|
+
if (typeof cleanup === 'function') {
|
|
19
|
+
addDisposer(scope, cleanup);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=on-mount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"on-mount.js","sourceRoot":"","sources":["../../src/primitives/on-mount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEtC,MAAM,UAAU,OAAO,CAAC,QAA8C;IACpE,0EAA0E;IAC1E,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAM;IAEzC,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAA;IAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,SAAS,CAAA;IAC3B,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,QAAQ,CAAC,IAAI,CAAA;IAChD,IAAI,SAAS,GAAG,KAAK,CAAA;IAErB,WAAW,CAAC,KAAK,EAAE,GAAG,EAAE;QACtB,SAAS,GAAG,IAAI,CAAA;IAClB,CAAC,CAAC,CAAA;IAEF,cAAc,CAAC,GAAG,EAAE;QAClB,IAAI,SAAS;YAAE,OAAM;QACrB,MAAM,OAAO,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAA;QACnC,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;YAClC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../src/primitives/portal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAI7C,wBAAgB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,EAAE,CAiClD"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { getRenderContext, setRenderContext, clearRenderContext } from '../render-context';
|
|
2
|
+
import { createScope, addDisposer } from '../scope';
|
|
3
|
+
export function portal(opts) {
|
|
4
|
+
const ctx = getRenderContext();
|
|
5
|
+
const parentScope = ctx.rootScope;
|
|
6
|
+
const target = typeof opts.target === 'string' ? document.querySelector(opts.target) : opts.target;
|
|
7
|
+
if (!target) {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const portalScope = createScope(parentScope);
|
|
11
|
+
const buildCtx = { ...ctx, rootScope: portalScope, container: target };
|
|
12
|
+
setRenderContext(buildCtx);
|
|
13
|
+
const nodes = opts.render();
|
|
14
|
+
clearRenderContext();
|
|
15
|
+
// Restore parent context
|
|
16
|
+
setRenderContext(ctx);
|
|
17
|
+
for (const node of nodes) {
|
|
18
|
+
target.appendChild(node);
|
|
19
|
+
}
|
|
20
|
+
// On scope disposal, remove portal nodes from target
|
|
21
|
+
addDisposer(portalScope, () => {
|
|
22
|
+
for (const node of nodes) {
|
|
23
|
+
if (node.parentNode === target) {
|
|
24
|
+
target.removeChild(node);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
// Portal returns nothing to the parent DOM — nodes live in the target
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=portal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.js","sourceRoot":"","sources":["../../src/primitives/portal.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC1F,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,UAAU,MAAM,CAAC,IAAmB;IACxC,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAA;IAC9B,MAAM,WAAW,GAAG,GAAG,CAAC,SAAS,CAAA;IAEjC,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAA;IAElG,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC,CAAA;IAC5C,MAAM,QAAQ,GAAG,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,MAAiB,EAAE,CAAA;IACjF,gBAAgB,CAAC,QAAQ,CAAC,CAAA;IAC1B,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAA;IAC3B,kBAAkB,EAAE,CAAA;IACpB,yBAAyB;IACzB,gBAAgB,CAAC,GAAG,CAAC,CAAA;IAErB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAC1B,CAAC;IAED,qDAAqD;IACrD,WAAW,CAAC,WAAW,EAAE,GAAG,EAAE;QAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM,EAAE,CAAC;gBAC/B,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;YAC1B,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,sEAAsE;IACtE,OAAO,EAAE,CAAA;AACX,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { BindingKind } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Optimized "one-of-N" reactive binding — O(1) updates instead of O(n).
|
|
4
|
+
*
|
|
5
|
+
* Watches a state field and compares it against per-item keys. When the
|
|
6
|
+
* field changes, only the old and new matching rows update their DOM.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* // In view, before each():
|
|
10
|
+
* const sel = selector<State, number>(s => s.selected)
|
|
11
|
+
*
|
|
12
|
+
* // Inside each() render:
|
|
13
|
+
* tr({ class: sel.bind(item(r => r.id), 'class', match => match ? 'danger' : '') })
|
|
14
|
+
*
|
|
15
|
+
* sel.bind() creates and manages the DOM binding directly.
|
|
16
|
+
* Returns Node[] to spread into the element's children (empty — no visible output).
|
|
17
|
+
*/
|
|
18
|
+
export declare function selector<S, V>(field: (s: S) => V): SelectorInstance<V>;
|
|
19
|
+
export interface SelectorInstance<V> {
|
|
20
|
+
bind(node: Node, key: V | (() => V), kind: BindingKind, propKey: string | undefined, transform: (match: boolean) => unknown): void;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.d.ts","sourceRoot":"","sources":["../../src/primitives/selector.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAU3C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAgGtE;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC;IACjC,IAAI,CACF,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAClB,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GACrC,IAAI,CAAA;CACR"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { getRenderContext } from '../render-context';
|
|
2
|
+
import { createBinding, applyBinding } from '../binding';
|
|
3
|
+
import { addDisposer } from '../scope';
|
|
4
|
+
import { FULL_MASK } from '../update-loop';
|
|
5
|
+
/**
|
|
6
|
+
* Optimized "one-of-N" reactive binding — O(1) updates instead of O(n).
|
|
7
|
+
*
|
|
8
|
+
* Watches a state field and compares it against per-item keys. When the
|
|
9
|
+
* field changes, only the old and new matching rows update their DOM.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* // In view, before each():
|
|
13
|
+
* const sel = selector<State, number>(s => s.selected)
|
|
14
|
+
*
|
|
15
|
+
* // Inside each() render:
|
|
16
|
+
* tr({ class: sel.bind(item(r => r.id), 'class', match => match ? 'danger' : '') })
|
|
17
|
+
*
|
|
18
|
+
* sel.bind() creates and manages the DOM binding directly.
|
|
19
|
+
* Returns Node[] to spread into the element's children (empty — no visible output).
|
|
20
|
+
*/
|
|
21
|
+
export function selector(field) {
|
|
22
|
+
const ctx = getRenderContext();
|
|
23
|
+
const scope = ctx.rootScope;
|
|
24
|
+
const registry = new Map();
|
|
25
|
+
let lastValue = field(ctx.state);
|
|
26
|
+
// Single watcher binding — evaluates the state field per update cycle.
|
|
27
|
+
// When the value changes, directly updates only affected entries.
|
|
28
|
+
createBinding(scope, {
|
|
29
|
+
mask: FULL_MASK,
|
|
30
|
+
accessor: ((state) => {
|
|
31
|
+
const newValue = field(state);
|
|
32
|
+
if (Object.is(newValue, lastValue))
|
|
33
|
+
return lastValue;
|
|
34
|
+
// Deselect old
|
|
35
|
+
const oldEntries = registry.get(lastValue);
|
|
36
|
+
if (oldEntries) {
|
|
37
|
+
for (const entry of oldEntries) {
|
|
38
|
+
const v = entry.transform(false);
|
|
39
|
+
if (!Object.is(v, entry.lastValue)) {
|
|
40
|
+
entry.lastValue = v;
|
|
41
|
+
applyBinding({ kind: entry.kind, node: entry.node, key: entry.key }, v);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Select new
|
|
46
|
+
const newEntries = registry.get(newValue);
|
|
47
|
+
if (newEntries) {
|
|
48
|
+
for (const entry of newEntries) {
|
|
49
|
+
const v = entry.transform(true);
|
|
50
|
+
if (!Object.is(v, entry.lastValue)) {
|
|
51
|
+
entry.lastValue = v;
|
|
52
|
+
applyBinding({ kind: entry.kind, node: entry.node, key: entry.key }, v);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
lastValue = newValue;
|
|
57
|
+
return newValue;
|
|
58
|
+
}),
|
|
59
|
+
kind: 'text',
|
|
60
|
+
node: document.createComment('selector'),
|
|
61
|
+
perItem: false,
|
|
62
|
+
});
|
|
63
|
+
return {
|
|
64
|
+
/**
|
|
65
|
+
* Bind a DOM node to this selector. Called per row inside each().
|
|
66
|
+
* Applies the initial value and registers for O(1) future updates.
|
|
67
|
+
*
|
|
68
|
+
* @param node - The DOM element to bind
|
|
69
|
+
* @param key - The per-item value to compare against the state field
|
|
70
|
+
* @param kind - Binding kind ('class', 'attr', 'prop', etc.)
|
|
71
|
+
* @param propKey - Property/attribute name (e.g., 'class')
|
|
72
|
+
* @param transform - Maps match boolean to the DOM value
|
|
73
|
+
*/
|
|
74
|
+
bind(node, key, kind, propKey, transform) {
|
|
75
|
+
const currentKey = typeof key === 'function' ? key() : key;
|
|
76
|
+
const initialMatch = Object.is(lastValue, currentKey);
|
|
77
|
+
const initialValue = transform(initialMatch);
|
|
78
|
+
// Apply initial value
|
|
79
|
+
applyBinding({ kind, node, key: propKey }, initialValue);
|
|
80
|
+
// Register in selector registry
|
|
81
|
+
const entry = {
|
|
82
|
+
node,
|
|
83
|
+
kind,
|
|
84
|
+
key: propKey,
|
|
85
|
+
lastValue: initialValue,
|
|
86
|
+
transform,
|
|
87
|
+
};
|
|
88
|
+
let bucket = registry.get(currentKey);
|
|
89
|
+
if (!bucket) {
|
|
90
|
+
bucket = new Set();
|
|
91
|
+
registry.set(currentKey, bucket);
|
|
92
|
+
}
|
|
93
|
+
bucket.add(entry);
|
|
94
|
+
// Cleanup when row scope is disposed
|
|
95
|
+
const itemScope = getRenderContext().rootScope;
|
|
96
|
+
addDisposer(itemScope, () => {
|
|
97
|
+
bucket.delete(entry);
|
|
98
|
+
if (bucket.size === 0)
|
|
99
|
+
registry.delete(currentKey);
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"selector.js","sourceRoot":"","sources":["../../src/primitives/selector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../src/primitives/show.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAK3C,wBAAgB,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,CAQpE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { branch } from './branch';
|
|
2
|
+
const EMPTY = () => [];
|
|
3
|
+
export function show(opts) {
|
|
4
|
+
return branch({
|
|
5
|
+
on: opts.when,
|
|
6
|
+
cases: { true: opts.render, false: opts.fallback ?? EMPTY },
|
|
7
|
+
enter: opts.enter,
|
|
8
|
+
leave: opts.leave,
|
|
9
|
+
onTransition: opts.onTransition,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=show.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show.js","sourceRoot":"","sources":["../../src/primitives/show.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,MAAM,KAAK,GAAG,GAAG,EAAE,CAAC,EAAY,CAAA;AAEhC,MAAM,UAAU,IAAI,CAAiB,IAAuB;IAC1D,OAAO,MAAM,CAAO;QAClB,EAAE,EAAE,IAAI,CAAC,IAAI;QACb,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK,EAAE;QAC3D,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,YAAY,EAAE,IAAI,CAAC,YAAY;KAChC,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Send } from '../types';
|
|
2
|
+
import type { View } from '../view-helpers';
|
|
3
|
+
/**
|
|
4
|
+
* Build a `View<Sub, M>` that composes a selector into every state-bound
|
|
5
|
+
* accessor. Used to write view-functions over a sub-slice of parent state:
|
|
6
|
+
*
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { slice } from '@llui/dom'
|
|
9
|
+
*
|
|
10
|
+
* view: (h) => {
|
|
11
|
+
* const formView = slice(h, (s) => s.form)
|
|
12
|
+
* return [...formView.show({ when: f => f.valid, render: () => [...] })]
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* Kept as a standalone function rather than a method on the View bundle so
|
|
17
|
+
* apps that don't use it don't pay for its bundle cost — tree-shaken when
|
|
18
|
+
* unused.
|
|
19
|
+
*/
|
|
20
|
+
export declare function slice<Root, Sub, M>(h: View<Root, M> | {
|
|
21
|
+
send: Send<M>;
|
|
22
|
+
}, lift: (r: Root) => Sub): View<Sub, M>;
|
|
23
|
+
//# sourceMappingURL=slice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../../src/primitives/slice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAe,MAAM,UAAU,CAAA;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AAS3C;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAChC,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG;IAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;CAAE,EACpC,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,GAAG,GACrB,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAiCd"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { show as _show } from './show';
|
|
2
|
+
import { branch as _branch } from './branch';
|
|
3
|
+
import { each as _each } from './each';
|
|
4
|
+
import { text as _text } from './text';
|
|
5
|
+
import { memo as _memo } from './memo';
|
|
6
|
+
import { selector as _selector } from './selector';
|
|
7
|
+
import { useContext } from './context';
|
|
8
|
+
/**
|
|
9
|
+
* Build a `View<Sub, M>` that composes a selector into every state-bound
|
|
10
|
+
* accessor. Used to write view-functions over a sub-slice of parent state:
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { slice } from '@llui/dom'
|
|
14
|
+
*
|
|
15
|
+
* view: (h) => {
|
|
16
|
+
* const formView = slice(h, (s) => s.form)
|
|
17
|
+
* return [...formView.show({ when: f => f.valid, render: () => [...] })]
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* Kept as a standalone function rather than a method on the View bundle so
|
|
22
|
+
* apps that don't use it don't pay for its bundle cost — tree-shaken when
|
|
23
|
+
* unused.
|
|
24
|
+
*/
|
|
25
|
+
export function slice(h, lift) {
|
|
26
|
+
const send = h.send;
|
|
27
|
+
return {
|
|
28
|
+
send,
|
|
29
|
+
show: (opts) => _show({
|
|
30
|
+
...opts,
|
|
31
|
+
when: (r) => opts.when(lift(r)),
|
|
32
|
+
}),
|
|
33
|
+
branch: (opts) => _branch({
|
|
34
|
+
...opts,
|
|
35
|
+
on: (r) => opts.on(lift(r)),
|
|
36
|
+
}),
|
|
37
|
+
each: (opts) => _each({
|
|
38
|
+
...opts,
|
|
39
|
+
items: (r) => opts.items(lift(r)),
|
|
40
|
+
}),
|
|
41
|
+
text: (accessor, mask) => {
|
|
42
|
+
if (typeof accessor === 'string')
|
|
43
|
+
return _text(accessor);
|
|
44
|
+
return _text((r) => accessor(lift(r)), mask);
|
|
45
|
+
},
|
|
46
|
+
memo: (accessor) => {
|
|
47
|
+
const m = _memo((r) => accessor(lift(r)));
|
|
48
|
+
return (s) => m(s);
|
|
49
|
+
},
|
|
50
|
+
selector: (field) => _selector((r) => field(lift(r))),
|
|
51
|
+
ctx: (c) => {
|
|
52
|
+
const root = useContext(c);
|
|
53
|
+
return (s) => root(s);
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=slice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slice.js","sourceRoot":"","sources":["../../src/primitives/slice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,MAAM,IAAI,OAAO,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,QAAQ,IAAI,SAAS,EAAE,MAAM,YAAY,CAAA;AAClD,OAAO,EAAE,UAAU,EAAgB,MAAM,WAAW,CAAA;AAEpD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,KAAK,CACnB,CAAoC,EACpC,IAAsB;IAEtB,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAA;IACnB,OAAO;QACL,IAAI;QACJ,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CACb,KAAK,CAAU;YACb,GAAG,IAAI;YACP,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAChC,CAAC;QACJ,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CACf,OAAO,CAAU;YACf,GAAG,IAAI;YACP,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAC5B,CAAC;QACJ,IAAI,EAAE,CAAI,IAA4B,EAAE,EAAE,CACxC,KAAK,CAAa;YAChB,GAAG,IAAI;YACP,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAClC,CAAC;QACJ,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE;YACvB,IAAI,OAAO,QAAQ,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC,QAAQ,CAAC,CAAA;YACxD,OAAO,KAAK,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAA;QACpD,CAAC;QACD,IAAI,EAAE,CAAI,QAAuB,EAAE,EAAE;YACnC,MAAM,CAAC,GAAG,KAAK,CAAU,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAClD,OAAO,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAoB,CAAC,CAAA;QAC5C,CAAC;QACD,QAAQ,EAAE,CAAI,KAAoB,EAAE,EAAE,CAAC,SAAS,CAAU,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAChF,GAAG,EAAE,CAAI,CAAa,EAAE,EAAE;YACxB,MAAM,IAAI,GAAG,UAAU,CAAU,CAAC,CAAC,CAAA;YACnC,OAAO,CAAC,CAAM,EAAE,EAAE,CAAC,IAAI,CAAC,CAAoB,CAAC,CAAA;QAC/C,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/primitives/text.ts"],"names":[],"mappings":"AAKA,wBAAgB,IAAI,CAAC,CAAC,EACpB,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,EACtD,IAAI,CAAC,EAAE,MAAM,GACZ,IAAI,CAiCN"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { getRenderContext } from '../render-context';
|
|
2
|
+
import { createBinding } from '../binding';
|
|
3
|
+
import { addItemUpdater } from '../scope';
|
|
4
|
+
import { FULL_MASK } from '../update-loop';
|
|
5
|
+
export function text(accessor, mask) {
|
|
6
|
+
if (typeof accessor === 'string') {
|
|
7
|
+
return document.createTextNode(accessor);
|
|
8
|
+
}
|
|
9
|
+
const ctx = getRenderContext();
|
|
10
|
+
const node = document.createTextNode('');
|
|
11
|
+
// Per-item accessor from each() — zero-arg function (length === 0)
|
|
12
|
+
// Register as direct updater, bypassing Phase 2 binding scan
|
|
13
|
+
if (accessor.length === 0) {
|
|
14
|
+
const get = accessor;
|
|
15
|
+
node.nodeValue = String(get());
|
|
16
|
+
addItemUpdater(ctx.rootScope, () => {
|
|
17
|
+
node.nodeValue = String(get());
|
|
18
|
+
});
|
|
19
|
+
return node;
|
|
20
|
+
}
|
|
21
|
+
// Component-level state accessor
|
|
22
|
+
const bindingMask = mask ?? FULL_MASK;
|
|
23
|
+
const binding = createBinding(ctx.rootScope, {
|
|
24
|
+
mask: bindingMask,
|
|
25
|
+
accessor: accessor,
|
|
26
|
+
kind: 'text',
|
|
27
|
+
node,
|
|
28
|
+
perItem: false,
|
|
29
|
+
});
|
|
30
|
+
const initialValue = accessor(ctx.state);
|
|
31
|
+
node.nodeValue = String(initialValue);
|
|
32
|
+
binding.lastValue = initialValue;
|
|
33
|
+
return node;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/primitives/text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C,MAAM,UAAU,IAAI,CAClB,QAAsD,EACtD,IAAa;IAEb,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAA;IAC1C,CAAC;IAED,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAA;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;IAExC,mEAAmE;IACnE,6DAA6D;IAC7D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,QAAwB,CAAA;QACpC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAA;QAC9B,cAAc,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,EAAE;YACjC,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAA;QAChC,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;IAED,iCAAiC;IACjC,MAAM,WAAW,GAAG,IAAI,IAAI,SAAS,CAAA;IACrC,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE;QAC3C,IAAI,EAAE,WAAW;QACjB,QAAQ,EAAE,QAAqC;QAC/C,IAAI,EAAE,MAAM;QACZ,IAAI;QACJ,OAAO,EAAE,KAAK;KACf,CAAC,CAAA;IACF,MAAM,YAAY,GAAI,QAA6B,CAAC,GAAG,CAAC,KAAU,CAAC,CAAA;IACnE,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;IACrC,OAAO,CAAC,SAAS,GAAG,YAAY,CAAA;IAEhC,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Scope, Binding } from './types';
|
|
2
|
+
import type { StructuralBlock } from './structural';
|
|
3
|
+
export interface RenderContext {
|
|
4
|
+
rootScope: Scope;
|
|
5
|
+
state: unknown;
|
|
6
|
+
allBindings: Binding[];
|
|
7
|
+
structuralBlocks: StructuralBlock[];
|
|
8
|
+
container?: Element;
|
|
9
|
+
send?: (msg: unknown) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare function setRenderContext(ctx: RenderContext): void;
|
|
12
|
+
export declare function clearRenderContext(): void;
|
|
13
|
+
export declare function getRenderContext(): RenderContext;
|
|
14
|
+
//# sourceMappingURL=render-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-context.d.ts","sourceRoot":"","sources":["../src/render-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAC7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEnD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,KAAK,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,WAAW,EAAE,OAAO,EAAE,CAAA;IACtB,gBAAgB,EAAE,eAAe,EAAE,CAAA;IACnC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAA;CAC9B;AAID,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAEzD;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAKhD"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
let currentContext = null;
|
|
2
|
+
export function setRenderContext(ctx) {
|
|
3
|
+
currentContext = ctx;
|
|
4
|
+
}
|
|
5
|
+
export function clearRenderContext() {
|
|
6
|
+
currentContext = null;
|
|
7
|
+
}
|
|
8
|
+
export function getRenderContext() {
|
|
9
|
+
if (!currentContext) {
|
|
10
|
+
throw new Error('LLUI: primitives can only be called inside view()');
|
|
11
|
+
}
|
|
12
|
+
return currentContext;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=render-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-context.js","sourceRoot":"","sources":["../src/render-context.ts"],"names":[],"mappings":"AAYA,IAAI,cAAc,GAAyB,IAAI,CAAA;AAE/C,MAAM,UAAU,gBAAgB,CAAC,GAAkB;IACjD,cAAc,GAAG,GAAG,CAAA;AACtB,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,cAAc,GAAG,IAAI,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,IAAI,CAAC,cAAc,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,OAAO,cAAc,CAAA;AACvB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAKA,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAErD;AAED,wBAAgB,KAAK,IAAI,IAAI,CAI5B"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { flushInstance } from './update-loop';
|
|
2
|
+
const activeInstances = new Set();
|
|
3
|
+
export function registerInstance(inst) {
|
|
4
|
+
activeInstances.add(inst);
|
|
5
|
+
}
|
|
6
|
+
export function unregisterInstance(inst) {
|
|
7
|
+
activeInstances.delete(inst);
|
|
8
|
+
}
|
|
9
|
+
export function flush() {
|
|
10
|
+
for (const inst of activeInstances) {
|
|
11
|
+
flushInstance(inst);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAG7C,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAA;AAEzC,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;AAC9B,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;QACnC,aAAa,CAAC,IAAyB,CAAC,CAAA;IAC1C,CAAC;AACH,CAAC"}
|
package/dist/scope.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Scope, Binding } from './types';
|
|
2
|
+
export declare function createScope(parent: Scope | null): Scope;
|
|
3
|
+
/**
|
|
4
|
+
* Dispose a scope and all its children. By default, detaches the scope
|
|
5
|
+
* from its parent's `children` array via `indexOf + splice` — O(N) per
|
|
6
|
+
* call, which becomes O(N²) when disposing many sibling scopes in bulk
|
|
7
|
+
* (e.g. `each` clearing 1000 rows).
|
|
8
|
+
*
|
|
9
|
+
* Pass `skipParentRemoval = true` when the caller will batch-remove
|
|
10
|
+
* children afterwards (see `removeOrphanedFromParent`). The scope's
|
|
11
|
+
* `parent` pointer is still set to `null` so the caller can identify
|
|
12
|
+
* orphaned entries.
|
|
13
|
+
*/
|
|
14
|
+
export declare function disposeScope(scope: Scope, skipParentRemoval?: boolean): void;
|
|
15
|
+
/**
|
|
16
|
+
* Batch-remove children with `parent === null` from `parent.children`.
|
|
17
|
+
* Called after a bulk `disposeScope(child, true)` pass to collapse the
|
|
18
|
+
* individual O(N) splice operations into one O(N) scan.
|
|
19
|
+
*/
|
|
20
|
+
export declare function removeOrphanedChildren(parent: Scope): void;
|
|
21
|
+
export declare function addBinding(scope: Scope, binding: Binding): void;
|
|
22
|
+
export declare function addItemUpdater(scope: Scope, updater: () => void): void;
|
|
23
|
+
export declare function addDisposer(scope: Scope, disposer: () => void): void;
|
|
24
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAU7C,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI,GAAG,KAAK,CAiBvD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,iBAAiB,UAAQ,GAAG,IAAI,CA+B1E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,KAAK,GAAG,IAAI,CAO1D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAI/D;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAGtE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAGpE"}
|