dalila 1.9.24 → 1.9.25
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 -0
- package/dist/cli/routes-generator.js +1 -1
- package/dist/core/index.js +0 -2
- package/dist/core/observability.d.ts +3 -0
- package/dist/core/observability.js +7 -4
- package/dist/core/signal.js +2 -1
- package/dist/runtime/bind-if-directive.d.ts +18 -0
- package/dist/runtime/bind-if-directive.js +96 -0
- package/dist/runtime/bind-lazy-directive.d.ts +13 -0
- package/dist/runtime/bind-lazy-directive.js +139 -0
- package/dist/runtime/bind-list-directives.d.ts +21 -0
- package/dist/runtime/bind-list-directives.js +533 -0
- package/dist/runtime/bind-portal.d.ts +21 -0
- package/dist/runtime/bind-portal.js +95 -0
- package/dist/runtime/bind.d.ts +1 -1
- package/dist/runtime/bind.js +61 -872
- package/dist/runtime/boundary.d.ts +1 -1
- package/dist/runtime/boundary.js +1 -1
- package/dist/runtime/lazy.d.ts +1 -1
- package/dist/runtime/lazy.js +1 -1
- package/package.json +88 -1
- package/scripts/dev-server.cjs +21 -0
package/README.md
CHANGED
|
@@ -44,6 +44,8 @@ const ctx = {
|
|
|
44
44
|
bind(document.getElementById('app')!, ctx);
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
+
For bundle-sensitive or no-bundler builds, prefer leaf subpaths like `dalila/core/signal` and `dalila/runtime/bind`.
|
|
48
|
+
|
|
47
49
|
## Docs
|
|
48
50
|
|
|
49
51
|
### Start here
|
|
@@ -102,6 +104,8 @@ bind(document.getElementById('app')!, ctx);
|
|
|
102
104
|
```txt
|
|
103
105
|
dalila → signals, scope, persist, forms, resources, query, mutations
|
|
104
106
|
dalila/runtime → bind(), mount(), configure(), components, lazy, transitions
|
|
107
|
+
dalila/core/* → leaf core modules for tighter bundles
|
|
108
|
+
dalila/runtime/* → leaf runtime modules for tighter bundles
|
|
105
109
|
dalila/context → createContext(), provide(), inject()
|
|
106
110
|
dalila/router → createRouter(), file-based routes, preloading
|
|
107
111
|
dalila/http → createHttpClient()
|
|
@@ -1023,7 +1023,7 @@ export async function generateRoutesFile(routesDir, outputPath) {
|
|
|
1023
1023
|
const importLines = [];
|
|
1024
1024
|
importLines.push(`import type { RouteTable } from 'dalila/router';`);
|
|
1025
1025
|
if (hasHtml) {
|
|
1026
|
-
importLines.push(`import { fromHtml } from 'dalila';`);
|
|
1026
|
+
importLines.push(`import { fromHtml } from 'dalila/runtime/from-html';`);
|
|
1027
1027
|
}
|
|
1028
1028
|
if (imports.length > 0) {
|
|
1029
1029
|
importLines.push(...imports);
|
package/dist/core/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { installDefaultSecurityObservability } from "./observability.js";
|
|
2
1
|
export * from "./scope.js";
|
|
3
2
|
export * from "./signal.js";
|
|
4
3
|
export * from "./observability.js";
|
|
@@ -14,4 +13,3 @@ export * from "./query.js";
|
|
|
14
13
|
export * from "./mutation.js";
|
|
15
14
|
export { batch, measure, mutate, timeSlice, configureScheduler, getSchedulerConfig } from "./scheduler.js";
|
|
16
15
|
export { persist, createJSONStorage, clearPersisted, createPreloadScript, createThemeScript } from "./persist.js";
|
|
17
|
-
installDefaultSecurityObservability();
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type EffectErrorHandler } from "./signal.js";
|
|
1
2
|
export interface SecurityRuntimeEvent {
|
|
2
3
|
timestamp: string;
|
|
3
4
|
source: string;
|
|
@@ -6,6 +7,8 @@ export interface SecurityRuntimeEvent {
|
|
|
6
7
|
fatal: boolean;
|
|
7
8
|
}
|
|
8
9
|
export declare const SECURITY_RUNTIME_EVENT_NAME = "dalila:security-error";
|
|
10
|
+
export declare const observabilityEffectErrorHandler: EffectErrorHandler;
|
|
11
|
+
export declare function reportObservedEffectError(error: Error, source: string): void;
|
|
9
12
|
export declare function installDefaultSecurityObservability(): void;
|
|
10
13
|
export declare function getSecurityRuntimeEvents(): readonly SecurityRuntimeEvent[];
|
|
11
14
|
export declare function clearSecurityRuntimeEvents(): void;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { setDefaultEffectErrorHandler } from "./signal.js";
|
|
2
2
|
export const SECURITY_RUNTIME_EVENT_NAME = "dalila:security-error";
|
|
3
3
|
const MAX_SECURITY_RUNTIME_EVENTS = 25;
|
|
4
4
|
const SECURITY_MESSAGE_PATTERN = /\b(sanitizehtml|trusted types?|srcdoc|javascript:|data:text\/html|xss|csp)\b/i;
|
|
5
5
|
const securityRuntimeEvents = [];
|
|
6
6
|
let observabilityInstalled = false;
|
|
7
7
|
function isSecurityRuntimeError(error) {
|
|
8
|
-
return error
|
|
8
|
+
return error.name === "FatalEffectError" || (error.message.startsWith("[Dalila]")
|
|
9
9
|
&& SECURITY_MESSAGE_PATTERN.test(error.message));
|
|
10
10
|
}
|
|
11
11
|
function storeSecurityRuntimeEvent(event) {
|
|
@@ -23,14 +23,14 @@ function dispatchSecurityRuntimeEvent(event) {
|
|
|
23
23
|
detail: event,
|
|
24
24
|
}));
|
|
25
25
|
}
|
|
26
|
-
const observabilityEffectErrorHandler = (error, source) => {
|
|
26
|
+
export const observabilityEffectErrorHandler = (error, source) => {
|
|
27
27
|
if (isSecurityRuntimeError(error)) {
|
|
28
28
|
const event = {
|
|
29
29
|
timestamp: new Date().toISOString(),
|
|
30
30
|
source,
|
|
31
31
|
message: error.message,
|
|
32
32
|
name: error.name,
|
|
33
|
-
fatal: error
|
|
33
|
+
fatal: error.name === "FatalEffectError",
|
|
34
34
|
};
|
|
35
35
|
storeSecurityRuntimeEvent(event);
|
|
36
36
|
dispatchSecurityRuntimeEvent(event);
|
|
@@ -39,6 +39,9 @@ const observabilityEffectErrorHandler = (error, source) => {
|
|
|
39
39
|
}
|
|
40
40
|
console.error(`[Dalila] Error in ${source}:`, error);
|
|
41
41
|
};
|
|
42
|
+
export function reportObservedEffectError(error, source) {
|
|
43
|
+
observabilityEffectErrorHandler(error, source);
|
|
44
|
+
}
|
|
42
45
|
export function installDefaultSecurityObservability() {
|
|
43
46
|
if (observabilityInstalled)
|
|
44
47
|
return;
|
package/dist/core/signal.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getCurrentScope, withScope } from './scope.js';
|
|
2
2
|
import { scheduleMicrotask, isBatching, queueInBatch } from './scheduler.js';
|
|
3
|
+
import { reportObservedEffectError } from './observability.js';
|
|
3
4
|
import { aliasEffectToNode, linkSubscriberSetToSignal, registerEffect, registerSignal, trackDependency, trackEffectDispose, trackComputedRunEnd, trackComputedRunStart, trackEffectRunEnd, trackEffectRunStart, trackSignalRead, trackSignalWrite, untrackDependencyBySet, } from './devtools.js';
|
|
4
5
|
let effectErrorHandler = null;
|
|
5
6
|
let defaultEffectErrorHandler = null;
|
|
@@ -41,7 +42,7 @@ function reportEffectErrorWithHandlers(error, source) {
|
|
|
41
42
|
defaultEffectErrorHandler(error, source);
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
+
reportObservedEffectError(error, source);
|
|
45
46
|
}
|
|
46
47
|
/**
|
|
47
48
|
* Normalize unknown throws into Error and route to the global handler (or console).
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BindContext, DisposeFunction, TransitionConfig } from './bind.js';
|
|
2
|
+
type TransitionRegistry = Map<string, TransitionConfig>;
|
|
3
|
+
interface TransitionController {
|
|
4
|
+
hasTransition: boolean;
|
|
5
|
+
enter: () => void;
|
|
6
|
+
leave: (onDone: () => void) => void;
|
|
7
|
+
}
|
|
8
|
+
interface BindIfDirectiveDeps {
|
|
9
|
+
qsaIncludingRoot: (root: Element, selector: string) => Element[];
|
|
10
|
+
normalizeBinding: (raw: string | null) => string | null;
|
|
11
|
+
warn: (message: string) => void;
|
|
12
|
+
resolve: (value: unknown) => unknown;
|
|
13
|
+
bindEffect: (target: Element | null | undefined, fn: () => void) => void;
|
|
14
|
+
createTransitionController: (el: HTMLElement, registry: TransitionRegistry, cleanups: DisposeFunction[]) => TransitionController;
|
|
15
|
+
syncPortalElement: (el: HTMLElement) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function bindIfDirective(root: Element, ctx: BindContext, cleanups: DisposeFunction[], transitionRegistry: TransitionRegistry, deps: BindIfDirectiveDeps): void;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export function bindIfDirective(root, ctx, cleanups, transitionRegistry, deps) {
|
|
2
|
+
const elements = deps.qsaIncludingRoot(root, '[d-if]');
|
|
3
|
+
for (const el of elements) {
|
|
4
|
+
const bindingName = deps.normalizeBinding(el.getAttribute('d-if'));
|
|
5
|
+
if (!bindingName)
|
|
6
|
+
continue;
|
|
7
|
+
const binding = ctx[bindingName];
|
|
8
|
+
if (binding === undefined) {
|
|
9
|
+
deps.warn(`d-if: "${bindingName}" not found in context`);
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const elseEl = el.nextElementSibling?.hasAttribute('d-else') ? el.nextElementSibling : null;
|
|
13
|
+
const comment = document.createComment('d-if');
|
|
14
|
+
el.parentNode?.replaceChild(comment, el);
|
|
15
|
+
el.removeAttribute('d-if');
|
|
16
|
+
const htmlEl = el;
|
|
17
|
+
const transitions = deps.createTransitionController(htmlEl, transitionRegistry, cleanups);
|
|
18
|
+
let elseHtmlEl = null;
|
|
19
|
+
let elseComment = null;
|
|
20
|
+
let elseTransitions = null;
|
|
21
|
+
if (elseEl) {
|
|
22
|
+
elseComment = document.createComment('d-else');
|
|
23
|
+
elseEl.parentNode?.replaceChild(elseComment, elseEl);
|
|
24
|
+
elseEl.removeAttribute('d-else');
|
|
25
|
+
elseHtmlEl = elseEl;
|
|
26
|
+
elseTransitions = deps.createTransitionController(elseHtmlEl, transitionRegistry, cleanups);
|
|
27
|
+
}
|
|
28
|
+
const initialValue = !!deps.resolve(binding);
|
|
29
|
+
if (initialValue) {
|
|
30
|
+
comment.parentNode?.insertBefore(htmlEl, comment);
|
|
31
|
+
deps.syncPortalElement(htmlEl);
|
|
32
|
+
if (transitions.hasTransition) {
|
|
33
|
+
htmlEl.removeAttribute('data-leave');
|
|
34
|
+
htmlEl.setAttribute('data-enter', '');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
else if (elseHtmlEl && elseComment) {
|
|
38
|
+
elseComment.parentNode?.insertBefore(elseHtmlEl, elseComment);
|
|
39
|
+
deps.syncPortalElement(elseHtmlEl);
|
|
40
|
+
if (elseTransitions?.hasTransition) {
|
|
41
|
+
elseHtmlEl.removeAttribute('data-leave');
|
|
42
|
+
elseHtmlEl.setAttribute('data-enter', '');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (elseHtmlEl && elseComment) {
|
|
46
|
+
const capturedElseEl = elseHtmlEl;
|
|
47
|
+
const capturedElseComment = elseComment;
|
|
48
|
+
deps.bindEffect(htmlEl, () => {
|
|
49
|
+
const value = !!deps.resolve(binding);
|
|
50
|
+
if (value) {
|
|
51
|
+
if (!htmlEl.parentNode) {
|
|
52
|
+
comment.parentNode?.insertBefore(htmlEl, comment);
|
|
53
|
+
deps.syncPortalElement(htmlEl);
|
|
54
|
+
}
|
|
55
|
+
transitions.enter();
|
|
56
|
+
elseTransitions?.leave(() => {
|
|
57
|
+
if (capturedElseEl.parentNode) {
|
|
58
|
+
capturedElseEl.parentNode.removeChild(capturedElseEl);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
transitions.leave(() => {
|
|
64
|
+
if (htmlEl.parentNode) {
|
|
65
|
+
htmlEl.parentNode.removeChild(htmlEl);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
if (!capturedElseEl.parentNode) {
|
|
69
|
+
capturedElseComment.parentNode?.insertBefore(capturedElseEl, capturedElseComment);
|
|
70
|
+
deps.syncPortalElement(capturedElseEl);
|
|
71
|
+
}
|
|
72
|
+
elseTransitions?.enter();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
deps.bindEffect(htmlEl, () => {
|
|
78
|
+
const value = !!deps.resolve(binding);
|
|
79
|
+
if (value) {
|
|
80
|
+
if (!htmlEl.parentNode) {
|
|
81
|
+
comment.parentNode?.insertBefore(htmlEl, comment);
|
|
82
|
+
deps.syncPortalElement(htmlEl);
|
|
83
|
+
}
|
|
84
|
+
transitions.enter();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
transitions.leave(() => {
|
|
88
|
+
if (htmlEl.parentNode) {
|
|
89
|
+
htmlEl.parentNode.removeChild(htmlEl);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BindContext, BindOptions, DisposeFunction } from './bind.js';
|
|
2
|
+
interface BindLazyDirectiveDeps {
|
|
3
|
+
qsaIncludingRoot: (root: Element, selector: string) => Element[];
|
|
4
|
+
normalizeBinding: (raw: string | null) => string | null;
|
|
5
|
+
warn: (message: string) => void;
|
|
6
|
+
warnRawHtmlSinkHeuristic: (sink: string, source: string, html: string) => void;
|
|
7
|
+
resolveSecurityOptions: (options: BindOptions) => unknown;
|
|
8
|
+
bind: (root: Element, ctx: BindContext, options: BindOptions) => (() => void);
|
|
9
|
+
bindEffect: (target: Element | null | undefined, fn: () => void) => void;
|
|
10
|
+
inheritNestedBindOptions: (parent: BindOptions, overrides: BindOptions) => BindOptions;
|
|
11
|
+
}
|
|
12
|
+
export declare function bindLazyDirective(root: Element, ctx: BindContext, cleanups: DisposeFunction[], refs: Map<string, Element>, events: string[], options: BindOptions, deps: BindLazyDirectiveDeps): void;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { getLazyComponent, observeLazyElement } from './lazy.js';
|
|
2
|
+
import { setElementInnerHTML } from './html-sinks.js';
|
|
3
|
+
export function bindLazyDirective(root, ctx, cleanups, refs, events, options, deps) {
|
|
4
|
+
const elements = deps.qsaIncludingRoot(root, '[d-lazy]');
|
|
5
|
+
for (const el of elements) {
|
|
6
|
+
const lazyComponentName = deps.normalizeBinding(el.getAttribute('d-lazy'));
|
|
7
|
+
if (!lazyComponentName)
|
|
8
|
+
continue;
|
|
9
|
+
const lazyResult = getLazyComponent(lazyComponentName);
|
|
10
|
+
if (!lazyResult) {
|
|
11
|
+
deps.warn(`d-lazy: component "${lazyComponentName}" not found. Use createLazyComponent() to create it.`);
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const { state } = lazyResult;
|
|
15
|
+
const htmlEl = el;
|
|
16
|
+
const loadingTemplate = el.getAttribute('d-lazy-loading') ?? state.loadingTemplate ?? '';
|
|
17
|
+
const errorTemplate = el.getAttribute('d-lazy-error') ?? state.errorTemplate ?? '';
|
|
18
|
+
el.removeAttribute('d-lazy');
|
|
19
|
+
el.removeAttribute('d-lazy-loading');
|
|
20
|
+
el.removeAttribute('d-lazy-error');
|
|
21
|
+
let currentNode = htmlEl;
|
|
22
|
+
let componentMounted = false;
|
|
23
|
+
let componentDispose = null;
|
|
24
|
+
let componentEl = null;
|
|
25
|
+
let hasIntersected = false;
|
|
26
|
+
const refName = deps.normalizeBinding(htmlEl.getAttribute('d-ref'));
|
|
27
|
+
const syncRef = (node) => {
|
|
28
|
+
if (!refName)
|
|
29
|
+
return;
|
|
30
|
+
if (node instanceof Element) {
|
|
31
|
+
refs.set(refName, node);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const replaceCurrentNode = (nextNode) => {
|
|
35
|
+
const parent = currentNode.parentNode;
|
|
36
|
+
if (!parent)
|
|
37
|
+
return;
|
|
38
|
+
parent.replaceChild(nextNode, currentNode);
|
|
39
|
+
currentNode = nextNode;
|
|
40
|
+
syncRef(nextNode);
|
|
41
|
+
};
|
|
42
|
+
const unmountComponent = () => {
|
|
43
|
+
if (componentDispose) {
|
|
44
|
+
componentDispose();
|
|
45
|
+
componentDispose = null;
|
|
46
|
+
}
|
|
47
|
+
componentMounted = false;
|
|
48
|
+
componentEl = null;
|
|
49
|
+
};
|
|
50
|
+
const renderComponent = () => {
|
|
51
|
+
const comp = state.component();
|
|
52
|
+
if (!comp)
|
|
53
|
+
return;
|
|
54
|
+
const compDef = comp.definition;
|
|
55
|
+
const compEl = document.createElement(compDef.tag);
|
|
56
|
+
for (const attr of Array.from(htmlEl.attributes)) {
|
|
57
|
+
if (!attr.name.startsWith('d-')) {
|
|
58
|
+
compEl.setAttribute(attr.name, attr.value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (componentMounted && componentEl === compEl)
|
|
62
|
+
return;
|
|
63
|
+
replaceCurrentNode(compEl);
|
|
64
|
+
componentEl = compEl;
|
|
65
|
+
const parentCtx = Object.create(ctx);
|
|
66
|
+
const parent = compEl.parentNode;
|
|
67
|
+
const nextSibling = compEl.nextSibling;
|
|
68
|
+
componentDispose = deps.bind(compEl, parentCtx, {
|
|
69
|
+
components: { [compDef.tag]: comp },
|
|
70
|
+
events,
|
|
71
|
+
_skipLifecycle: true,
|
|
72
|
+
...deps.inheritNestedBindOptions(options, {}),
|
|
73
|
+
});
|
|
74
|
+
if (!compEl.isConnected && parent) {
|
|
75
|
+
const renderedNode = nextSibling ? nextSibling.previousSibling : parent.lastChild;
|
|
76
|
+
if (renderedNode instanceof Node) {
|
|
77
|
+
currentNode = renderedNode;
|
|
78
|
+
syncRef(renderedNode);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
componentMounted = true;
|
|
82
|
+
};
|
|
83
|
+
const showLoading = () => {
|
|
84
|
+
if (loadingTemplate) {
|
|
85
|
+
if (componentMounted) {
|
|
86
|
+
unmountComponent();
|
|
87
|
+
}
|
|
88
|
+
const loadingEl = document.createElement('div');
|
|
89
|
+
deps.warnRawHtmlSinkHeuristic('d-lazy-loading', lazyComponentName, loadingTemplate);
|
|
90
|
+
setElementInnerHTML(loadingEl, loadingTemplate, deps.resolveSecurityOptions(options));
|
|
91
|
+
replaceCurrentNode(loadingEl);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const showError = (err) => {
|
|
95
|
+
if (componentMounted) {
|
|
96
|
+
unmountComponent();
|
|
97
|
+
}
|
|
98
|
+
if (errorTemplate) {
|
|
99
|
+
const errorEl = document.createElement('div');
|
|
100
|
+
deps.warnRawHtmlSinkHeuristic('d-lazy-error', lazyComponentName, errorTemplate);
|
|
101
|
+
setElementInnerHTML(errorEl, errorTemplate, deps.resolveSecurityOptions(options));
|
|
102
|
+
replaceCurrentNode(errorEl);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
deps.warn(`d-lazy: failed to load "${lazyComponentName}": ${err.message}`);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const syncFromState = () => {
|
|
109
|
+
const loading = state.loading();
|
|
110
|
+
const error = state.error();
|
|
111
|
+
const comp = state.component();
|
|
112
|
+
if (!hasIntersected)
|
|
113
|
+
return;
|
|
114
|
+
if (error) {
|
|
115
|
+
showError(error);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (loading && !comp) {
|
|
119
|
+
showLoading();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (comp && !componentMounted) {
|
|
123
|
+
renderComponent();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
deps.bindEffect(htmlEl, () => {
|
|
127
|
+
syncFromState();
|
|
128
|
+
});
|
|
129
|
+
const cleanupObserver = observeLazyElement(htmlEl, () => {
|
|
130
|
+
hasIntersected = true;
|
|
131
|
+
syncFromState();
|
|
132
|
+
state.load();
|
|
133
|
+
}, 0);
|
|
134
|
+
cleanups.push(() => {
|
|
135
|
+
cleanupObserver();
|
|
136
|
+
unmountComponent();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SchedulerPriority } from '../core/scheduler.js';
|
|
2
|
+
import type { BindContext, BindOptions, DisposeFunction, VirtualListController, VirtualScrollToIndexOptions } from './bind.js';
|
|
3
|
+
interface BindListDirectiveDeps {
|
|
4
|
+
qsaIncludingRoot: (root: Element, selector: string) => Element[];
|
|
5
|
+
normalizeBinding: (raw: string | null) => string | null;
|
|
6
|
+
warn: (message: string) => void;
|
|
7
|
+
resolve: (value: unknown) => unknown;
|
|
8
|
+
bind: (root: Element, ctx: BindContext, options: BindOptions) => (() => void);
|
|
9
|
+
bindEffect: (target: Element | null | undefined, fn: () => void) => void;
|
|
10
|
+
inheritNestedBindOptions: (parent: BindOptions, overrides: BindOptions) => BindOptions;
|
|
11
|
+
isSignal: (value: unknown) => value is (() => unknown) & {
|
|
12
|
+
set: unknown;
|
|
13
|
+
update: unknown;
|
|
14
|
+
};
|
|
15
|
+
resolveListRenderPriority: () => SchedulerPriority;
|
|
16
|
+
}
|
|
17
|
+
export declare function getVirtualListController(target: Element | null): VirtualListController | null;
|
|
18
|
+
export declare function scrollToVirtualIndex(target: Element | null, index: number, options?: VirtualScrollToIndexOptions): boolean;
|
|
19
|
+
export declare function bindVirtualEachDirective(root: Element, ctx: BindContext, cleanups: DisposeFunction[], options: BindOptions, deps: BindListDirectiveDeps): void;
|
|
20
|
+
export declare function bindEachDirective(root: Element, ctx: BindContext, cleanups: DisposeFunction[], options: BindOptions, deps: BindListDirectiveDeps): void;
|
|
21
|
+
export {};
|