elements-kit 0.0.1 → 0.0.3
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 +325 -15
- package/dist/attributes.d.mts +90 -0
- package/dist/attributes.mjs +81 -0
- package/dist/builder/dom.d.mts +212 -0
- package/dist/builder/dom.mjs +205 -0
- package/dist/builder/index.d.mts +2 -0
- package/dist/builder/index.mjs +113 -0
- package/dist/element-CCHXkEsj.mjs +262 -0
- package/dist/index-C6xwOPCO.d.mts +263 -0
- package/dist/index-DJejH8Ff.d.mts +89 -0
- package/dist/index.d.mts +36 -0
- package/dist/index.mjs +127 -0
- package/dist/jsx-runtime/index.d.mts +70 -0
- package/dist/jsx-runtime/index.mjs +2 -0
- package/dist/lib-B2drrxlV.mjs +15 -0
- package/dist/polyfill-BEL-HWkO.d.mts +14 -0
- package/dist/signals/index.d.mts +2 -0
- package/dist/signals/index.mjs +2 -0
- package/dist/signals/lib/media.d.mts +14 -0
- package/dist/signals/lib/media.mjs +26 -0
- package/dist/signals/lib/react.d.mts +62 -0
- package/dist/signals/lib/react.mjs +82 -0
- package/dist/signals-Cr7xgAJH.mjs +966 -0
- package/dist/slot.d.mts +73 -0
- package/dist/slot.mjs +142 -0
- package/package.json +69 -15
- package/dist/builder.d.mts +0 -11799
- package/dist/builder.mjs +0 -208
- package/dist/chunk-CFhWmker.mjs +0 -36
- package/dist/core.d.mts +0 -14
- package/dist/core.mjs +0 -74
- package/dist/signals-BGUPt0zl.mjs +0 -13
- package/dist/signals-BzhB4Ch2.d.mts +0 -10
- package/dist/signals.d.mts +0 -3
- package/dist/signals.mjs +0 -5
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { a as effect, t as isReactive } from "./signals-Cr7xgAJH.mjs";
|
|
2
|
+
import { $slots, Slot, Slots } from "./slot.mjs";
|
|
3
|
+
import { t as resolveNode } from "./lib-B2drrxlV.mjs";
|
|
4
|
+
//#region \0rolldown/runtime.js
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __exportAll = (all, no_symbols) => {
|
|
10
|
+
let target = {};
|
|
11
|
+
for (var name in all) __defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
+
return target;
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
20
|
+
key = keys[i];
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
22
|
+
get: ((k) => from[k]).bind(null, key),
|
|
23
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/jsx-runtime/constants.ts
|
|
31
|
+
var constants_exports = /* @__PURE__ */ __exportAll({ ReservedNameSpaces: () => ReservedNameSpaces });
|
|
32
|
+
import * as import_dom_expressions_src_constants_js from "dom-expressions/src/constants.js";
|
|
33
|
+
__reExport(constants_exports, import_dom_expressions_src_constants_js);
|
|
34
|
+
const ReservedNameSpaces = new Set([
|
|
35
|
+
"class",
|
|
36
|
+
"on",
|
|
37
|
+
"style",
|
|
38
|
+
"prop"
|
|
39
|
+
]);
|
|
40
|
+
//#endregion
|
|
41
|
+
//#region src/jsx-runtime/children.ts
|
|
42
|
+
function hasSlots(node) {
|
|
43
|
+
return $slots in node;
|
|
44
|
+
}
|
|
45
|
+
function isChildrenProperty(node, key) {
|
|
46
|
+
if (key === "children" && (node instanceof Element || node instanceof DocumentFragment)) return true;
|
|
47
|
+
if (hasSlots(node)) {
|
|
48
|
+
const slotName = key.replace(/^slot:/, "");
|
|
49
|
+
if (Slots.has(node[$slots], slotName)) return true;
|
|
50
|
+
}
|
|
51
|
+
return key in node && node[key] instanceof Slot;
|
|
52
|
+
}
|
|
53
|
+
function applyChildren(node, key, value) {
|
|
54
|
+
if (hasSlots(node)) {
|
|
55
|
+
const slotName = key.replace(/^slot:/, "");
|
|
56
|
+
if (Slots.has(node[$slots], slotName)) return applySlot(node[$slots][slotName], value);
|
|
57
|
+
}
|
|
58
|
+
if (key === "children" && (node instanceof Element || node instanceof DocumentFragment)) return mountChildren(node, value);
|
|
59
|
+
if (key in node) {
|
|
60
|
+
const slot = node[key];
|
|
61
|
+
if (!(slot instanceof Slot)) return;
|
|
62
|
+
return applySlot(slot, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Sets a Slot's content from a Child value.
|
|
67
|
+
*/
|
|
68
|
+
function applySlot(slot, value) {
|
|
69
|
+
if (typeof value === "function") return effect(() => slot.set(resolveChild(value())));
|
|
70
|
+
slot.set(resolveChild(value));
|
|
71
|
+
}
|
|
72
|
+
function mountChildren(el, value) {
|
|
73
|
+
const children = ensureFlatArray(value);
|
|
74
|
+
const disposers = [];
|
|
75
|
+
for (const child of children) {
|
|
76
|
+
if (typeof child === "function") {
|
|
77
|
+
const slot = Slot.new();
|
|
78
|
+
el.appendChild(slot());
|
|
79
|
+
disposers.push(effect(() => slot.set(resolveChild(child()))));
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
el.appendChild(resolveChild(child));
|
|
83
|
+
}
|
|
84
|
+
return disposers.length > 0 ? () => disposers.forEach((d) => d()) : void 0;
|
|
85
|
+
}
|
|
86
|
+
function resolveChild(value) {
|
|
87
|
+
if (Array.isArray(value)) {
|
|
88
|
+
const fragment = document.createDocumentFragment();
|
|
89
|
+
for (const item of value) fragment.appendChild(resolveChild(item));
|
|
90
|
+
return fragment;
|
|
91
|
+
}
|
|
92
|
+
if (typeof value === "function") return resolveChild(value());
|
|
93
|
+
return resolveNode(value);
|
|
94
|
+
}
|
|
95
|
+
/** Normalises the children prop into a flat array. */
|
|
96
|
+
function ensureFlatArray(raw) {
|
|
97
|
+
return (Array.isArray(raw) ? raw : [raw]).flat(Infinity);
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/jsx-runtime/properties.ts
|
|
101
|
+
function applyProps(node, props) {
|
|
102
|
+
const disposables = /* @__PURE__ */ new Set();
|
|
103
|
+
for (const [key, value] of Object.entries(props)) {
|
|
104
|
+
if (isChildrenProperty(node, key)) {
|
|
105
|
+
const disposable = applyChildren(node, key, value);
|
|
106
|
+
if (disposable) disposables.add(disposable);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (isReactive(value)) {
|
|
110
|
+
if (isEventKey(key)) {
|
|
111
|
+
let cleanup;
|
|
112
|
+
const dispose = effect(() => {
|
|
113
|
+
if (cleanup) cleanup();
|
|
114
|
+
cleanup = setEvent(node, key, value());
|
|
115
|
+
});
|
|
116
|
+
disposables.add(() => {
|
|
117
|
+
dispose();
|
|
118
|
+
if (cleanup) cleanup();
|
|
119
|
+
});
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
disposables.add(effect(() => setProp(node, key, value())));
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (isEventKey(key)) {
|
|
126
|
+
disposables.add(setEvent(node, key, value));
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
setProp(node, key, value);
|
|
130
|
+
}
|
|
131
|
+
return disposables;
|
|
132
|
+
}
|
|
133
|
+
function setProp(node, key, value) {
|
|
134
|
+
const colonIdx = key.indexOf(":");
|
|
135
|
+
if (colonIdx > -1) {
|
|
136
|
+
const ns = key.slice(0, colonIdx);
|
|
137
|
+
const name = key.slice(colonIdx + 1);
|
|
138
|
+
if (ReservedNameSpaces.has(ns)) {
|
|
139
|
+
if (ns === "prop") {
|
|
140
|
+
node[name] = value;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (ns === "class") {
|
|
144
|
+
node.classList.toggle(name, Boolean(value));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (ns === "style") {
|
|
148
|
+
if (value == null || value === false) node.style.removeProperty(name);
|
|
149
|
+
else node.style.setProperty(name, String(value));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const svgNs = constants_exports.SVGNamespace[ns];
|
|
155
|
+
if (svgNs) {
|
|
156
|
+
node.setAttributeNS(svgNs, key, String(value ?? ""));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (key === "class") {
|
|
161
|
+
node.className = String(value ?? "");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (key === "style") {
|
|
165
|
+
applyStyle(node, value);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (constants_exports.ChildProperties.has(key)) {
|
|
169
|
+
node[key] = value ?? "";
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (!(node instanceof SVGElement) && constants_exports.Properties.has(key)) {
|
|
173
|
+
node[key] = value;
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (node instanceof Element && node.nodeName.includes("-") && key in node) {
|
|
177
|
+
try {
|
|
178
|
+
node[key] = value;
|
|
179
|
+
} catch {
|
|
180
|
+
setAttribute(node, key, value);
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (!(node instanceof Element)) {
|
|
185
|
+
node[key] = value;
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
setAttribute(node, key, value);
|
|
189
|
+
}
|
|
190
|
+
function applyStyle(el, value) {
|
|
191
|
+
const s = el.style;
|
|
192
|
+
if (!s) return;
|
|
193
|
+
if (typeof value === "string") s.cssText = value;
|
|
194
|
+
else if (value && typeof value === "object") Object.assign(s, value);
|
|
195
|
+
}
|
|
196
|
+
function setAttribute(el, key, value) {
|
|
197
|
+
if (value == null || value === false) el.removeAttribute(key);
|
|
198
|
+
else el.setAttribute(key, value === true ? "" : String(value));
|
|
199
|
+
}
|
|
200
|
+
function isEventKey(key) {
|
|
201
|
+
return key.startsWith("on:") || key.length > 2 && key.startsWith("on") && key[2] >= "A" && key[2] <= "Z";
|
|
202
|
+
}
|
|
203
|
+
function setEvent(el, key, handler) {
|
|
204
|
+
const event = key.startsWith("on:") ? key.slice(3) : key[2].toLowerCase() + key.slice(3);
|
|
205
|
+
el.addEventListener(event, handler);
|
|
206
|
+
return () => el.removeEventListener(event, handler);
|
|
207
|
+
}
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region src/jsx-runtime/ref.ts
|
|
210
|
+
const $ref = Symbol("ref");
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/jsx-runtime/element.ts
|
|
213
|
+
function createElement(type, { [$ref]: ref, ...props } = {}) {
|
|
214
|
+
if (typeof type === "function" && !type.prototype?.render) {
|
|
215
|
+
const el = type(props);
|
|
216
|
+
if (typeof ref === "function" && el instanceof Element) ref(el);
|
|
217
|
+
return el;
|
|
218
|
+
}
|
|
219
|
+
const node = resolveElement(type);
|
|
220
|
+
if (!node) return null;
|
|
221
|
+
const disposables = applyProps(node, props);
|
|
222
|
+
if (disposables.size > 0) attachDisposables(node, disposables);
|
|
223
|
+
const el = _render(node);
|
|
224
|
+
if (typeof ref === "function" && el instanceof Element) ref(el);
|
|
225
|
+
return el;
|
|
226
|
+
}
|
|
227
|
+
function _render(node) {
|
|
228
|
+
if (node instanceof Element || node instanceof DocumentFragment) return node;
|
|
229
|
+
if (!node || typeof node.render !== "function") return null;
|
|
230
|
+
return _render(node.render());
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Resolves the `type` argument of createElement into a concrete DOM node:
|
|
234
|
+
* - string → document.createElement(type)
|
|
235
|
+
* - Element → the element itself (apply props to an existing node)
|
|
236
|
+
* - class component → new type()
|
|
237
|
+
*/
|
|
238
|
+
function resolveElement(type) {
|
|
239
|
+
if (typeof type === "string") return document.createElement(type);
|
|
240
|
+
if (type instanceof Element || type instanceof DocumentFragment) return type;
|
|
241
|
+
return new type();
|
|
242
|
+
}
|
|
243
|
+
function hasOwnDisposable(el) {
|
|
244
|
+
return Object.hasOwn(el, Symbol.dispose);
|
|
245
|
+
}
|
|
246
|
+
function attachDisposables(el, disposables) {
|
|
247
|
+
const existingDispose = hasOwnDisposable(el) ? el[Symbol.dispose].bind(el) : null;
|
|
248
|
+
Object.defineProperty(el, Symbol.dispose, {
|
|
249
|
+
value() {
|
|
250
|
+
existingDispose?.();
|
|
251
|
+
disposables.forEach((fn) => fn());
|
|
252
|
+
disposables.clear();
|
|
253
|
+
},
|
|
254
|
+
configurable: true
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
/** Runs all cleanup functions registered by JSX props/effects on `el`. */
|
|
258
|
+
function disposeElement(el) {
|
|
259
|
+
el[Symbol.dispose]?.();
|
|
260
|
+
}
|
|
261
|
+
//#endregion
|
|
262
|
+
export { disposeElement as n, createElement as t };
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { u as ValueOrReactive } from "./index-DJejH8Ff.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/signals/lib.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Returns `true` if `fn` is a signal handle created by {@link signal}.
|
|
6
|
+
*
|
|
7
|
+
* Relies on `Function.name` matching the internal `signalOper` function name.
|
|
8
|
+
*/
|
|
9
|
+
declare function isSignal(fn: () => void): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Returns `true` if `fn` is a computed handle created by {@link computed}.
|
|
12
|
+
*
|
|
13
|
+
* Relies on `Function.name` matching the internal `computedOper` function name.
|
|
14
|
+
*/
|
|
15
|
+
declare function isComputed(fn: () => void): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Returns `true` if `fn` is an effect cleanup handle created by {@link effect}.
|
|
18
|
+
*
|
|
19
|
+
* Relies on `Function.name` matching the internal `effectOper` function name.
|
|
20
|
+
*/
|
|
21
|
+
declare function isEffect(fn: () => void): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Returns `true` if `fn` is an effectScope cleanup handle created by
|
|
24
|
+
* {@link effectScope}.
|
|
25
|
+
*
|
|
26
|
+
* Relies on `Function.name` matching the internal `effectScopeOper` function name.
|
|
27
|
+
*/
|
|
28
|
+
declare function isEffectScope(fn: () => void): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Creates a mutable reactive signal.
|
|
31
|
+
*
|
|
32
|
+
* - **Read**: call with no arguments → returns the current value and
|
|
33
|
+
* subscribes the active tracking context.
|
|
34
|
+
* - **Write**: call with a value → updates the signal and schedules
|
|
35
|
+
* downstream effects if the value changed.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const count = signal(0);
|
|
40
|
+
* count(); // → 0 (read)
|
|
41
|
+
* count(1); // write – effects depending on count will re-run
|
|
42
|
+
* count(); // → 1
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare function signal<T>(): {
|
|
46
|
+
(): T | undefined;
|
|
47
|
+
(value: T | undefined): void;
|
|
48
|
+
};
|
|
49
|
+
declare function signal<T>(initialValue: T): {
|
|
50
|
+
(): T;
|
|
51
|
+
(value: T): void;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Creates a lazily-evaluated computed value.
|
|
55
|
+
*
|
|
56
|
+
* The `getter` is only called when the computed value is read **and** one of
|
|
57
|
+
* its dependencies has changed since the last evaluation. If nothing has
|
|
58
|
+
* changed the cached `value` is returned without re-running `getter`.
|
|
59
|
+
*
|
|
60
|
+
* Computed values are read-only; they cannot be set directly.
|
|
61
|
+
*
|
|
62
|
+
* @param getter - Pure function deriving a value from other reactive sources.
|
|
63
|
+
* Receives the previous value as an optional optimisation hint.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const a = signal(1);
|
|
68
|
+
* const b = signal(2);
|
|
69
|
+
* const sum = computed(() => a() + b());
|
|
70
|
+
*
|
|
71
|
+
* sum(); // → 3
|
|
72
|
+
* a(10);
|
|
73
|
+
* sum(); // → 12 (re-evaluated lazily)
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
declare function computed<T>(getter: (previousValue?: T) => T): () => T;
|
|
77
|
+
/**
|
|
78
|
+
* Creates a reactive side-effect that runs immediately and re-runs whenever
|
|
79
|
+
* any signal or computed it read during its last execution changes.
|
|
80
|
+
*
|
|
81
|
+
* Use {@link onCleanup} inside `fn` to register teardown logic that runs
|
|
82
|
+
* before each re-execution and on final disposal.
|
|
83
|
+
*
|
|
84
|
+
* If `effect` is called inside an `effectScope` or another `effect`, the
|
|
85
|
+
* new effect is automatically owned by the outer scope and will be disposed
|
|
86
|
+
* when the scope is disposed.
|
|
87
|
+
*
|
|
88
|
+
* @param fn - The side-effect body. Reactive reads inside this function
|
|
89
|
+
* establish dependency links.
|
|
90
|
+
* @returns A disposal function. Call it to stop the effect and run any
|
|
91
|
+
* registered cleanup.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const url = signal('/api/data');
|
|
96
|
+
*
|
|
97
|
+
* const stop = effect(() => {
|
|
98
|
+
* const controller = new AbortController();
|
|
99
|
+
* fetch(url(), { signal: controller.signal });
|
|
100
|
+
* onCleanup(() => controller.abort());
|
|
101
|
+
* });
|
|
102
|
+
*
|
|
103
|
+
* url('/api/other'); // previous fetch is aborted, new one starts
|
|
104
|
+
* stop(); // final cleanup: abort the last fetch
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
107
|
+
declare function effect(fn: () => void): () => void;
|
|
108
|
+
/**
|
|
109
|
+
* Creates an ownership scope that groups reactive effects so they can all be
|
|
110
|
+
* disposed at once.
|
|
111
|
+
*
|
|
112
|
+
* Effects and nested scopes created inside `fn` are linked to this scope.
|
|
113
|
+
* When the returned disposal function is called, all owned effects are stopped
|
|
114
|
+
* in cascade – triggering their registered {@link onCleanup} callbacks – and
|
|
115
|
+
* the scope itself is removed from any parent scope that owns it.
|
|
116
|
+
*
|
|
117
|
+
* @param fn - Synchronous setup function. Create effects and nested scopes
|
|
118
|
+
* here.
|
|
119
|
+
* @returns A disposal function that tears down all owned effects and the scope
|
|
120
|
+
* itself.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* const stopAll = effectScope(() => {
|
|
125
|
+
* effect(() => console.log('a:', a()));
|
|
126
|
+
* effect(() => console.log('b:', b()));
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* stopAll(); // both effects stopped simultaneously
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
declare function effectScope(fn: () => void): () => void;
|
|
133
|
+
/**
|
|
134
|
+
* Registers a cleanup callback for the currently executing effect or scope.
|
|
135
|
+
*
|
|
136
|
+
* The callback will be called:
|
|
137
|
+
* 1. **Before the next re-run** of the enclosing effect (so resources from
|
|
138
|
+
* the previous run are released before the new run sets them up again).
|
|
139
|
+
* 2. **On final disposal** of the effect, whether triggered explicitly by
|
|
140
|
+
* calling the effect's cleanup handle or implicitly by an owning
|
|
141
|
+
* `effectScope` being disposed.
|
|
142
|
+
*
|
|
143
|
+
* Calling `onCleanup` outside of a tracking context (no active effect) is a
|
|
144
|
+
* no-op; it does **not** throw.
|
|
145
|
+
*
|
|
146
|
+
* Only one cleanup function per effect run is supported. Calling `onCleanup`
|
|
147
|
+
* multiple times within the same run overwrites the previous registration.
|
|
148
|
+
*
|
|
149
|
+
* @param fn - The teardown callback.
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* effect(() => {
|
|
154
|
+
* const id = setInterval(() => tick(), 1000);
|
|
155
|
+
* onCleanup(() => clearInterval(id));
|
|
156
|
+
* });
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @example Composable helper – no prop-drilling needed:
|
|
160
|
+
* ```ts
|
|
161
|
+
* function useEventListener(target: EventTarget, type: string, handler: EventListener) {
|
|
162
|
+
* target.addEventListener(type, handler);
|
|
163
|
+
* onCleanup(() => target.removeEventListener(type, handler));
|
|
164
|
+
* }
|
|
165
|
+
*
|
|
166
|
+
* effect(() => {
|
|
167
|
+
* useEventListener(window, 'resize', onResize);
|
|
168
|
+
* });
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
declare function onCleanup(fn: () => void): void;
|
|
172
|
+
/**
|
|
173
|
+
* Runs `fn` as a single atomic update: all signal writes inside `fn` are
|
|
174
|
+
* collected and effects are flushed only once after `fn` returns, rather than
|
|
175
|
+
* after each individual write.
|
|
176
|
+
*
|
|
177
|
+
* Batches can be nested; the flush only occurs when the outermost batch
|
|
178
|
+
* completes.
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* batch(() => {
|
|
183
|
+
* x(1);
|
|
184
|
+
* y(2);
|
|
185
|
+
* z(3);
|
|
186
|
+
* }); // effects that depend on x, y, or z run once here
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
declare function batch(fn: () => void): void;
|
|
190
|
+
/**
|
|
191
|
+
* Executes `fn` in a non-tracking context: any signals read inside `fn` do
|
|
192
|
+
* **not** create dependency links on the currently active subscriber.
|
|
193
|
+
*
|
|
194
|
+
* Useful when you need to read a signal's current value without subscribing to
|
|
195
|
+
* future changes.
|
|
196
|
+
*
|
|
197
|
+
* @returns The value returned by `fn`.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```ts
|
|
201
|
+
* const logCount = effect(() => {
|
|
202
|
+
* console.log('triggered by a:', a());
|
|
203
|
+
* // read b without subscribing – effect won't re-run when b changes
|
|
204
|
+
* console.log('current b:', untracked(() => b()));
|
|
205
|
+
* });
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
declare function untracked<T>(fn: () => T): T;
|
|
209
|
+
/**
|
|
210
|
+
* Manually triggers all subscribers of every signal read inside `fn`.
|
|
211
|
+
*
|
|
212
|
+
* Unlike writing to a signal, `trigger` does not change the signal's value; it
|
|
213
|
+
* only forces downstream effects and computeds to re-evaluate.
|
|
214
|
+
*
|
|
215
|
+
* @param fn - Function whose reactive reads identify the signals to trigger.
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* ```ts
|
|
219
|
+
* const items = signal([1, 2, 3]);
|
|
220
|
+
*
|
|
221
|
+
* // Mutate in place (referential equality won't detect the change):
|
|
222
|
+
* items().push(4);
|
|
223
|
+
* trigger(() => items()); // manually notify subscribers
|
|
224
|
+
* ```
|
|
225
|
+
*/
|
|
226
|
+
declare function trigger(fn: () => void): void;
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/signals/index.d.ts
|
|
229
|
+
declare function isReactive<T>(value: ValueOrReactive<T>): value is () => T;
|
|
230
|
+
type Updater<T> = (value: T) => void;
|
|
231
|
+
type Computed<T> = () => T;
|
|
232
|
+
type Signal<T> = Updater<T> & Computed<T>;
|
|
233
|
+
/**
|
|
234
|
+
* A decorator that makes a class field reactive by automatically wrapping its value in a signal.
|
|
235
|
+
*
|
|
236
|
+
* The field behaves like a normal property (get/set) but reactivity is tracked under the hood.
|
|
237
|
+
* Any reads will subscribe to the signal and any writes will trigger updates.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```ts
|
|
241
|
+
* class Counter {
|
|
242
|
+
* @reactive()
|
|
243
|
+
* count: number = 0;
|
|
244
|
+
* }
|
|
245
|
+
*
|
|
246
|
+
* const counter = new Counter();
|
|
247
|
+
* counter.count++; // Triggers reactivity
|
|
248
|
+
* console.log(counter.count); // Subscribes to changes
|
|
249
|
+
* ```
|
|
250
|
+
*
|
|
251
|
+
* @remarks
|
|
252
|
+
* Equivalent to manually creating a private signal and getter/setter:
|
|
253
|
+
* ```ts
|
|
254
|
+
* class Counter {
|
|
255
|
+
* #count = signal(0);
|
|
256
|
+
* get count() { return this.#count(); }
|
|
257
|
+
* set count(value) { this.#count(value); }
|
|
258
|
+
* }
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
declare function reactive<This extends object, Value>(source?: (self: This) => Signal<Value>): (_target: unknown, context: ClassFieldDecoratorContext<This, Value>) => (this: This, initialValue: Value) => Value;
|
|
262
|
+
//#endregion
|
|
263
|
+
export { untracked as _, reactive as a, effect as c, isEffect as d, isEffectScope as f, trigger as g, signal as h, isReactive as i, effectScope as l, onCleanup as m, Signal as n, batch as o, isSignal as p, Updater as r, computed as s, Computed as t, isComputed as u };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { t as PrimitiveNodeType } from "./polyfill-BEL-HWkO.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/builder/index.d.ts
|
|
4
|
+
declare const DISPOSABLES: unique symbol;
|
|
5
|
+
declare const DISPOSE: symbol;
|
|
6
|
+
declare const VALUE: unique symbol;
|
|
7
|
+
declare const EFFECT: unique symbol;
|
|
8
|
+
declare class ElementBuilder<T extends Element = Element> {
|
|
9
|
+
/** Dispose the reactive element and run all cleanup functions */
|
|
10
|
+
[DISPOSE]: () => void;
|
|
11
|
+
/** The underlying DOM element */
|
|
12
|
+
private [VALUE];
|
|
13
|
+
/** A set of cleanup functions to run when disposing the element */
|
|
14
|
+
private [DISPOSABLES];
|
|
15
|
+
[EFFECT](fn: () => void): this;
|
|
16
|
+
private constructor();
|
|
17
|
+
static create<T extends Element>(el: T): ReactiveElement<T>;
|
|
18
|
+
children(...children: ValueOrReactive<ElementBuilder | Node | string | number>[]): T;
|
|
19
|
+
ref(): T;
|
|
20
|
+
ref(apply: (ref: T) => void | (() => void)): this;
|
|
21
|
+
on<K extends keyof HTMLElementEventMap>(eventType: K, listener: (ev: HTMLElementEventMap[K]) => void, options?: boolean | AddEventListenerOptions): this;
|
|
22
|
+
}
|
|
23
|
+
declare function toNode(c: ElementBuilder | PrimitiveNodeType): Node;
|
|
24
|
+
declare function builder<T extends Element>(el: T): ReactiveElementOf<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Callable overloads matching the Proxy apply trap → ref() behavior.
|
|
27
|
+
* Calling a reactive element as a function delegates to ref():
|
|
28
|
+
* el() → returns the raw DOM element
|
|
29
|
+
* el((ref) => {}) → applies a side-effect, returns the builder for chaining
|
|
30
|
+
*/
|
|
31
|
+
interface RefCallable<T extends Element> {
|
|
32
|
+
(): T;
|
|
33
|
+
(apply: (ref: T) => void | (() => void)): this;
|
|
34
|
+
}
|
|
35
|
+
type ReactiveElement<T extends Element> = ElementBuilder<T> & RefCallable<T>;
|
|
36
|
+
type ValueOrReactive<T> = (() => T) | T;
|
|
37
|
+
type ValueOrReactiveArray<T extends any[]> = { [K in keyof T]: ValueOrReactive<T[K]> | T[K] };
|
|
38
|
+
/**
|
|
39
|
+
* Filter keys that are writable (exclude readonly and getter-only).
|
|
40
|
+
*/
|
|
41
|
+
type WritableKeys<T> = { [K in keyof T]: (<U>() => U extends { [Q in K]: T[K] } ? 1 : 2) extends (<U>() => U extends { readonly [Q in K]: T[K] } ? 1 : 2) ? never : K }[keyof T];
|
|
42
|
+
/**
|
|
43
|
+
* Extracts the object chaining part of ReactiveBuilder.
|
|
44
|
+
* Used for properties like `style` where you can do both:
|
|
45
|
+
* .style("padding: 20px;") // setter
|
|
46
|
+
* .style.padding("20px") // sub-property chaining
|
|
47
|
+
*/
|
|
48
|
+
type Chain<R, T> = T extends object ? { [K in WritableKeys<T>]: Builder<R, T[K]> } : {};
|
|
49
|
+
type Builder<R, T = R> = T extends ((...args: infer U) => unknown) ? (...value: ValueOrReactiveArray<U>) => R : (value?: ValueOrReactive<T>) => R;
|
|
50
|
+
/**
|
|
51
|
+
* Types eligible for sub-property chaining (e.g., `.style.padding("20px")`).
|
|
52
|
+
*/
|
|
53
|
+
type ChainableType = CSSStyleDeclaration | DOMTokenList | DOMStringMap | StylePropertyMap;
|
|
54
|
+
/**
|
|
55
|
+
* Filters keys to only writable data properties.
|
|
56
|
+
* Excludes methods (function-valued properties) and event handlers (`on*`).
|
|
57
|
+
*/
|
|
58
|
+
type DataPropertyKeys<T> = { [K in keyof T]: K extends `on${string}` ? never : T[K] extends ((...args: any[]) => any) ? never : K }[keyof T];
|
|
59
|
+
/**
|
|
60
|
+
* Reactive setter for a single property.
|
|
61
|
+
* Chainable types (CSSStyleDeclaration, DOMTokenList, etc.) get both
|
|
62
|
+
* sub-property chaining and direct setter support.
|
|
63
|
+
*/
|
|
64
|
+
type ReactiveSetter<R, T> = T extends ChainableType ? Chain<R, T> & ((value: ValueOrReactive<T>) => R) : (value: ValueOrReactive<T>) => R;
|
|
65
|
+
/**
|
|
66
|
+
* A fully-typed reactive element builder for any Element type.
|
|
67
|
+
* Automatically maps all writable data properties into reactive setters.
|
|
68
|
+
*
|
|
69
|
+
* Use this for custom elements instead of needing generated builder interfaces.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* import { reactive, type ReactiveElementOf } from "elements-kit";
|
|
74
|
+
*
|
|
75
|
+
* class MyElement extends HTMLElement {
|
|
76
|
+
* greeting = "hello";
|
|
77
|
+
* }
|
|
78
|
+
* customElements.define("my-element", MyElement);
|
|
79
|
+
*
|
|
80
|
+
* const myEl = () =>
|
|
81
|
+
* reactive(document.createElement("my-element") as MyElement);
|
|
82
|
+
*
|
|
83
|
+
* // Full type support for both own and inherited properties:
|
|
84
|
+
* myEl().greeting("world").style.padding("20px").id("main");
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
type ReactiveElementOf<T extends Element> = ElementBuilder<T> & { [K in WritableKeys<T> & DataPropertyKeys<T> & keyof T]: ReactiveSetter<ReactiveElementOf<T>, T[K]> };
|
|
88
|
+
//#endregion
|
|
89
|
+
export { EFFECT as a, ReactiveElementOf as c, builder as d, toNode as f, DISPOSE as i, VALUE as l, Chain as n, ElementBuilder as o, DISPOSABLES as r, ReactiveElement as s, Builder as t, ValueOrReactive as u };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/components/for.d.ts
|
|
2
|
+
type KeyFn<T> = (item: T, index: number) => string | number;
|
|
3
|
+
type RenderFn<T> = (item: T, index: number) => Element | DocumentFragment | null;
|
|
4
|
+
/**
|
|
5
|
+
* Keyed list renderer. Reconciles a reactive array into the DOM using a key
|
|
6
|
+
* function to match existing nodes — minimising create/destroy churn.
|
|
7
|
+
*
|
|
8
|
+
* Reconciliation strategy (inspired by udomdiff / dom-expressions):
|
|
9
|
+
* 1. Remove stale entries (keys absent from the new array).
|
|
10
|
+
* 2. Skip unchanged common prefix and suffix.
|
|
11
|
+
* 3. Pure-append fast path when the surviving old range is empty.
|
|
12
|
+
* 4. Backward scan of the middle region — move or create entries so that
|
|
13
|
+
* each entry's range lands immediately before the already-correct cursor.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* <For each={visibleTodos} by={(todo) => todo.id}>
|
|
18
|
+
* {(todo) => <li>{todo.text}</li>}
|
|
19
|
+
* </For>
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Props:
|
|
23
|
+
* each — reactive getter returning the array (e.g. a `computed`)
|
|
24
|
+
* by — extracts a stable key per item (default: index)
|
|
25
|
+
* children — render function called once per new key
|
|
26
|
+
*/
|
|
27
|
+
declare class For<T = unknown> {
|
|
28
|
+
#private;
|
|
29
|
+
get each(): T[];
|
|
30
|
+
set each(v: T[]);
|
|
31
|
+
by: KeyFn<T>;
|
|
32
|
+
children: RenderFn<T>;
|
|
33
|
+
render(): DocumentFragment;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { For };
|