@expressive/dom 0.3.0 → 0.5.0
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 +9 -6
- package/dist/chunk-adapter-BzKJ4wEj.d.ts +22 -0
- package/dist/{chunk-hot-BAqPvKEQ.js → chunk-hot-Bj-g5ynf.js} +12 -91
- package/dist/chunk-hot-Bj-g5ynf.js.map +1 -0
- package/dist/{chunk-loader-kjuM318E.d.ts → chunk-loader-CZ-53pyV.d.ts} +3 -3
- package/dist/{chunk-vnode-BG1Cv8F9.js → chunk-vnode-wpCWQ_Zg.js} +2 -2
- package/dist/chunk-vnode-wpCWQ_Zg.js.map +1 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +785 -752
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +2 -2
- package/dist/jsx-dev-runtime.js +2 -2
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.d.ts +12 -14
- package/dist/jsx-runtime.js +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/dist/vite.js +4 -4
- package/dist/vite.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-adapter-4jlvwsge.d.ts +0 -37
- package/dist/chunk-hot-BAqPvKEQ.js.map +0 -1
- package/dist/chunk-vnode-BG1Cv8F9.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
`@expressive/dom` renders Expressive MVC without React or Preact. Function components are renderer-stateless: they project props and MVC snapshots into DOM, while `
|
|
9
|
+
`@expressive/dom` renders Expressive MVC without React or Preact. Function components are renderer-stateless: they project props and MVC snapshots into DOM, while `Model.get()` supplies dependency tracking. Owned state lives on classes - a Component field or `<Component for>`.
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
12
|
npm install @expressive/mvc @expressive/dom
|
|
@@ -22,10 +22,10 @@ npm install @expressive/mvc @expressive/dom
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
```tsx
|
|
25
|
-
import {
|
|
25
|
+
import { Model, Component } from '@expressive/mvc';
|
|
26
26
|
import { render } from '@expressive/dom';
|
|
27
27
|
|
|
28
|
-
class Counter extends
|
|
28
|
+
class Counter extends Model {
|
|
29
29
|
count = 0;
|
|
30
30
|
increment() {
|
|
31
31
|
this.count++;
|
|
@@ -33,11 +33,14 @@ class Counter extends State {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
function Count() {
|
|
36
|
-
const { count, increment } = Counter.
|
|
36
|
+
const { count, increment } = Counter.get();
|
|
37
37
|
return <button onClick={increment}>{count}</button>;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const unmount = render(
|
|
40
|
+
const unmount = render(
|
|
41
|
+
<Component for={Counter}><Count /></Component>,
|
|
42
|
+
document.getElementById('app')!
|
|
43
|
+
);
|
|
41
44
|
```
|
|
42
45
|
|
|
43
46
|
`style` recursively composes conditional class tokens and inline declarations. Strings become classes; objects merge left-to-right and render inline. Use `className` for a browser-specific class outside the composition. The `class` attribute spelling and CSS declaration strings are not supported.
|
|
@@ -68,7 +71,7 @@ Global maps use `macro(map)` and can live in side-effect imports. Register macro
|
|
|
68
71
|
|
|
69
72
|
Inline style always beats classes; among classes, a caller's rule beats the callee's, and a rule carried through more component `style` props wins - independent of render order. `false`, `null`, and `undefined` omit an entry; `0` remains a macro argument.
|
|
70
73
|
|
|
71
|
-
`Component` retains the React adapter's
|
|
74
|
+
`Component` retains the React adapter's semantics: fields read by `render()` are dependencies, owned instances mount and clean up with the DOM range, and an externally activated instance can be placed directly without transferring ownership.
|
|
72
75
|
|
|
73
76
|
The first release includes keyed reconciliation, native events, refs, SVG, `<Component for>` providers, direct `has` / `map` collection rendering, portals, lazy components, error and suspense fallbacks, generated component appearance rules, and retention of committed content while `pending()` work suspends. It deliberately excludes standalone hooks, synthetic events, memo wrappers, SSR, hydration, and build-time style extraction.
|
|
74
77
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context, Model } from "@expressive/mvc";
|
|
2
|
+
|
|
3
|
+
//#region src/render/adapter.d.ts
|
|
4
|
+
type NoVoid<T> = T extends undefined | void ? null : T;
|
|
5
|
+
declare module '@expressive/mvc' {
|
|
6
|
+
namespace Model {
|
|
7
|
+
type ForceRefresh = {
|
|
8
|
+
(): void;
|
|
9
|
+
<T = void>(waitFor: Promise<T>): Promise<T>;
|
|
10
|
+
<T = void>(invoke: () => Promise<T>): Promise<T>;
|
|
11
|
+
};
|
|
12
|
+
type GetFactory<T extends Model, R> = (this: T, current: T, refresh: ForceRefresh) => R;
|
|
13
|
+
function get<T extends Model>(this: Model.Extends<T>): T;
|
|
14
|
+
function get<T extends Model>(this: Model.Extends<T>, required: false): T | undefined;
|
|
15
|
+
function get<T extends Model>(this: Model.Extends<T>, required: true): Required<T>;
|
|
16
|
+
function get<T extends Model, R>(this: Model.Extends<T>, factory: GetFactory<T, R>): NoVoid<R>;
|
|
17
|
+
}
|
|
18
|
+
interface Component {
|
|
19
|
+
mount?(): (() => void) | void;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=chunk-adapter-BzKJ4wEj.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model, pending, unbind } from "@expressive/mvc";
|
|
2
2
|
import { watch } from "@expressive/mvc/observable";
|
|
3
3
|
|
|
4
|
-
//#region src/scheduler.ts
|
|
4
|
+
//#region src/render/scheduler.ts
|
|
5
5
|
const urgent = /* @__PURE__ */ new Set();
|
|
6
6
|
const passive = /* @__PURE__ */ new Set();
|
|
7
7
|
const after = [];
|
|
@@ -132,7 +132,7 @@ function unschedule(scope) {
|
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
//#endregion
|
|
135
|
-
//#region src/adapter.ts
|
|
135
|
+
//#region src/render/adapter.ts
|
|
136
136
|
let current;
|
|
137
137
|
let collecting;
|
|
138
138
|
function enter(scope, render) {
|
|
@@ -141,17 +141,9 @@ function enter(scope, render) {
|
|
|
141
141
|
const next = [];
|
|
142
142
|
current = scope;
|
|
143
143
|
collecting = next;
|
|
144
|
-
scope.childContext = scope.context;
|
|
145
|
-
scope.useIndex = 0;
|
|
146
144
|
try {
|
|
147
|
-
|
|
148
|
-
if (scope.kind == "function" && scope.useIndex !== scope.uses.length) {
|
|
149
|
-
if (!scope.hot) throw new Error("State.use() calls must keep the same order on every function-component render.");
|
|
150
|
-
truncate(scope, scope.useIndex);
|
|
151
|
-
}
|
|
152
|
-
return output;
|
|
145
|
+
return render();
|
|
153
146
|
} finally {
|
|
154
|
-
scope.hot = void 0;
|
|
155
147
|
current = parent;
|
|
156
148
|
collecting = releases;
|
|
157
149
|
scope.subscriptions.forEach((release) => release());
|
|
@@ -163,27 +155,9 @@ function dispose(scope) {
|
|
|
163
155
|
unschedule(scope);
|
|
164
156
|
scope.subscriptions.forEach((release) => release());
|
|
165
157
|
scope.subscriptions = [];
|
|
166
|
-
truncate(scope, 0);
|
|
167
|
-
}
|
|
168
|
-
/** Destroy the `State.use()` slots of a scope from `index` on. */
|
|
169
|
-
function truncate(scope, index) {
|
|
170
|
-
for (let i = scope.uses.length - 1; i >= index; i--) {
|
|
171
|
-
const slot = scope.uses[i];
|
|
172
|
-
slot.release();
|
|
173
|
-
if (typeof slot.cleanup == "function") slot.cleanup();
|
|
174
|
-
slot.context.pop();
|
|
175
|
-
slot.instance.set(null);
|
|
176
|
-
}
|
|
177
|
-
scope.uses.length = index;
|
|
178
|
-
}
|
|
179
|
-
function commit(scope) {
|
|
180
|
-
for (const slot of scope.uses) if (!slot.mounted) {
|
|
181
|
-
slot.mounted = true;
|
|
182
|
-
slot.cleanup = slot.instance.mount?.();
|
|
183
|
-
}
|
|
184
158
|
}
|
|
185
159
|
function requireScope() {
|
|
186
|
-
if (!current) throw new Error("
|
|
160
|
+
if (!current) throw new Error("Model.get() may only run while @expressive/dom is rendering.");
|
|
187
161
|
return current;
|
|
188
162
|
}
|
|
189
163
|
function tracked(target, required) {
|
|
@@ -198,9 +172,9 @@ function tracked(target, required) {
|
|
|
198
172
|
collecting.push(release);
|
|
199
173
|
return proxy;
|
|
200
174
|
}
|
|
201
|
-
|
|
175
|
+
Model.get = function get(argument) {
|
|
202
176
|
const scope = requireScope();
|
|
203
|
-
const instance = scope.
|
|
177
|
+
const instance = scope.context.get(this, argument === false ? false : true);
|
|
204
178
|
if (!instance) return void 0;
|
|
205
179
|
const proxy = tracked(instance, argument === true);
|
|
206
180
|
if (typeof argument != "function") return proxy;
|
|
@@ -211,58 +185,8 @@ State.get = function get(argument) {
|
|
|
211
185
|
});
|
|
212
186
|
return argument.call(proxy, proxy, refresh) ?? null;
|
|
213
187
|
};
|
|
214
|
-
State.use = function use(...args) {
|
|
215
|
-
const scope = requireScope();
|
|
216
|
-
if (scope.kind != "function") throw new Error("State.use() is only available at the top level of a function component.");
|
|
217
|
-
const index = scope.useIndex++;
|
|
218
|
-
let slot = scope.uses[index];
|
|
219
|
-
if (slot && slot.Type !== this) {
|
|
220
|
-
if (!scope.hot) throw new Error("State.use() calls must keep the same order on every function-component render.");
|
|
221
|
-
truncate(scope, index);
|
|
222
|
-
slot = void 0;
|
|
223
|
-
}
|
|
224
|
-
if (!slot) {
|
|
225
|
-
let instance;
|
|
226
|
-
const assign = (value) => typeof value == "object" && value && instance.set(value);
|
|
227
|
-
let apply = (...values) => Promise.all(values.flat().map(assign));
|
|
228
|
-
instance = new this((self) => {
|
|
229
|
-
const own = self;
|
|
230
|
-
if (typeof own.use == "function") {
|
|
231
|
-
apply = own.use.bind(own);
|
|
232
|
-
apply(...args);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
return args;
|
|
236
|
-
});
|
|
237
|
-
const context = scope.childContext.push(instance);
|
|
238
|
-
slot = {
|
|
239
|
-
Type: this,
|
|
240
|
-
context,
|
|
241
|
-
instance,
|
|
242
|
-
proxy: instance,
|
|
243
|
-
release: void 0,
|
|
244
|
-
apply
|
|
245
|
-
};
|
|
246
|
-
let first = true;
|
|
247
|
-
slot.release = watch(instance, (proxy) => {
|
|
248
|
-
slot.proxy = proxy;
|
|
249
|
-
if (!first && scope.active) schedule(scope);
|
|
250
|
-
first = false;
|
|
251
|
-
}, void 0, transition);
|
|
252
|
-
slot.apply = apply;
|
|
253
|
-
scope.uses.push(slot);
|
|
254
|
-
} else slot.apply(...args);
|
|
255
|
-
scope.childContext = slot.context;
|
|
256
|
-
return slot.proxy;
|
|
257
|
-
};
|
|
258
|
-
Object.defineProperty(Component, "use", {
|
|
259
|
-
configurable: true,
|
|
260
|
-
value() {
|
|
261
|
-
throw new Error(`${this} is a Component - render it instead of calling use().`);
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
188
|
const OWNERS = /* @__PURE__ */ new WeakMap();
|
|
265
|
-
|
|
189
|
+
Model.on({ method(key, fn, owner) {
|
|
266
190
|
if (/^[A-Z]/.test(key)) OWNERS.set(fn, {
|
|
267
191
|
owner,
|
|
268
192
|
key
|
|
@@ -279,7 +203,7 @@ function owner(type) {
|
|
|
279
203
|
}
|
|
280
204
|
|
|
281
205
|
//#endregion
|
|
282
|
-
//#region src/hot.ts
|
|
206
|
+
//#region src/render/hot.ts
|
|
283
207
|
const FAMILIES = /* @__PURE__ */ new Map();
|
|
284
208
|
const FAMILY = /* @__PURE__ */ new WeakMap();
|
|
285
209
|
/** The latest implementation of a component registered for hot refresh. */
|
|
@@ -319,13 +243,10 @@ function hot(id, components) {
|
|
|
319
243
|
FAMILY.set(type, family);
|
|
320
244
|
if (family.current === type) continue;
|
|
321
245
|
family.current = type;
|
|
322
|
-
for (const scope of family.scopes)
|
|
323
|
-
scope.hot = true;
|
|
324
|
-
schedule(scope);
|
|
325
|
-
}
|
|
246
|
+
for (const scope of family.scopes) schedule(scope);
|
|
326
247
|
}
|
|
327
248
|
}
|
|
328
249
|
|
|
329
250
|
//#endregion
|
|
330
|
-
export { untrack as a,
|
|
331
|
-
//# sourceMappingURL=chunk-hot-
|
|
251
|
+
export { untrack as a, enter as c, release as d, schedule as f, track as i, afterFlush as l, transition as m, latest as n, call as o, settle as p, same as r, dispose as s, hot as t, claim as u };
|
|
252
|
+
//# sourceMappingURL=chunk-hot-Bj-g5ynf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-hot-Bj-g5ynf.js","names":[],"sources":["../src/render/scheduler.ts","../src/render/adapter.ts","../src/render/hot.ts"],"sourcesContent":["import { pending } from '@expressive/mvc';\n\ninterface Schedulable {\n queued?: 'urgent' | 'passive' | 'deferred';\n holds?: (() => void)[];\n probed?: { output: unknown };\n blocking?: (() => void)[];\n update(passive: boolean): PromiseLike<unknown> | void;\n probe?(): PromiseLike<unknown> | void;\n empty?(): boolean;\n}\n\nconst urgent = new Set<Schedulable>();\nconst passive = new Set<Schedulable>();\nconst after: (() => void)[] = [];\n\nlet depth = 0;\nlet urgentQueued = false;\nlet passiveQueued = false;\n\nfunction flush(scopes: Set<Schedulable>) {\n for (const scope of scopes) {\n scopes.delete(scope);\n scope.queued = undefined;\n\n let waiting: PromiseLike<unknown> | void = undefined;\n\n try {\n waiting = scope.update(false);\n } catch (error) {\n console.error(error);\n }\n\n settle(scope);\n if (!waiting) unblock(scope);\n }\n}\n\nfunction flushUrgent() {\n urgentQueued = false;\n flush(urgent);\n\n for (const run of after.splice(0)) run();\n}\n\nfunction afterFlush(run: () => void) {\n after.push(run);\n\n if (!urgentQueued) {\n urgentQueued = true;\n queueMicrotask(flushUrgent);\n }\n}\n\nfunction flushPassive() {\n passiveQueued = false;\n\n const batch = [...passive].filter((scope) => scope.queued === 'passive');\n passive.clear();\n\n for (const scope of batch) {\n const waiting = scope.probe?.();\n if (waiting) return defer(batch, waiting, scope);\n }\n\n batch.sort((a, b) => Number(!!b.empty?.()) - Number(!!a.empty?.()));\n\n for (let index = 0; index < batch.length; index++) {\n const scope = batch[index];\n\n if (scope.queued !== 'passive') continue;\n\n scope.queued = undefined;\n\n let waiting: PromiseLike<unknown> | void = undefined;\n\n try {\n waiting = scope.update(true);\n } catch (error) {\n console.error(error);\n }\n\n settle(scope);\n\n if (waiting) return defer(batch.slice(index + 1), waiting, scope);\n unblock(scope);\n }\n}\n\nfunction defer(scopes: Schedulable[], waiting: PromiseLike<unknown>, source: Schedulable) {\n const held = scopes.filter((scope) => scope.queued === 'passive');\n\n for (const scope of held) {\n scope.queued = 'deferred';\n scope.probed = undefined;\n }\n\n const resume = () => {\n for (const scope of held)\n if (scope.queued === 'deferred') {\n scope.queued = undefined;\n transition(() => schedule(scope));\n }\n };\n\n (source.blocking ||= []).push(resume);\n waiting.then(resume, resume);\n}\n\nfunction unblock(scope: Schedulable) {\n const { blocking } = scope;\n\n scope.blocking = undefined;\n blocking?.forEach((resume) => resume());\n}\n\nfunction release(holds?: (() => void)[]) {\n holds?.forEach((held) => held());\n}\n\nfunction settle(scope: Schedulable) {\n const { holds } = scope;\n\n scope.holds = undefined;\n release(holds);\n}\n\nfunction schedule(scope: Schedulable) {\n const held = pending();\n\n if (held) (scope.holds ||= []).push(held);\n scope.probed = undefined;\n\n if (!depth) {\n passive.delete(scope);\n scope.queued = 'urgent';\n urgent.add(scope);\n\n if (!urgentQueued) {\n urgentQueued = true;\n queueMicrotask(flushUrgent);\n }\n\n return;\n }\n\n if (scope.queued && scope.queued !== 'deferred') return;\n\n scope.queued = 'passive';\n passive.add(scope);\n\n if (!passiveQueued) {\n passiveQueued = true;\n setTimeout(flushPassive);\n }\n}\n\nfunction transition(work: () => void) {\n depth++;\n\n try {\n work();\n } finally {\n depth--;\n }\n}\n\nfunction claim(scope: Schedulable) {\n urgent.delete(scope);\n passive.delete(scope);\n scope.queued = undefined;\n scope.probed = undefined;\n}\n\nfunction unschedule(scope: Schedulable) {\n urgent.delete(scope);\n passive.delete(scope);\n scope.queued = undefined;\n scope.probed = undefined;\n settle(scope);\n unblock(scope);\n}\n\nexport { afterFlush, claim, release, schedule, settle, transition, unschedule };\nexport type { Schedulable };\n","import { Context, Model, unbind } from '@expressive/mvc';\nimport { watch } from '@expressive/mvc/observable';\n\nimport { schedule, transition, unschedule } from './scheduler';\nimport type { Schedulable } from './scheduler';\n\ninterface Scope extends Schedulable {\n active: boolean;\n context: Context;\n subscriptions: (() => void)[];\n}\n\nlet current: Scope | undefined;\nlet collecting: (() => void)[] | undefined;\n\nfunction enter<T>(scope: Scope, render: () => T): T {\n const parent = current;\n const releases = collecting;\n const next: (() => void)[] = [];\n\n current = scope;\n collecting = next;\n\n try {\n return render();\n } finally {\n current = parent;\n collecting = releases;\n scope.subscriptions.forEach((release) => release());\n scope.subscriptions = next;\n }\n}\n\nfunction dispose(scope: Scope) {\n scope.active = false;\n unschedule(scope);\n scope.subscriptions.forEach((release) => release());\n scope.subscriptions = [];\n}\n\nfunction requireScope(): Scope {\n if (!current)\n throw new Error('Model.get() may only run while @expressive/dom is rendering.');\n\n return current;\n}\n\nfunction tracked<T extends object>(target: T, required?: boolean): T {\n const scope = requireScope();\n let proxy = target;\n let first = true;\n\n const release = watch(\n target,\n (next) => {\n proxy = next;\n if (!first && scope.active) schedule(scope);\n first = false;\n },\n required,\n transition\n );\n\n collecting!.push(release);\n return proxy;\n}\n\ntype NoVoid<T> = T extends undefined | void ? null : T;\n\ndeclare module '@expressive/mvc' {\n namespace Model {\n type ForceRefresh = {\n (): void;\n <T = void>(waitFor: Promise<T>): Promise<T>;\n <T = void>(invoke: () => Promise<T>): Promise<T>;\n };\n\n type GetFactory<T extends Model, R> = (\n this: T,\n current: T,\n refresh: ForceRefresh\n ) => R;\n\n function get<T extends Model>(this: Model.Extends<T>): T;\n function get<T extends Model>(this: Model.Extends<T>, required: false): T | undefined;\n function get<T extends Model>(this: Model.Extends<T>, required: true): Required<T>;\n function get<T extends Model, R>(\n this: Model.Extends<T>,\n factory: GetFactory<T, R>\n ): NoVoid<R>;\n }\n\n interface Component {\n mount?(): (() => void) | void;\n }\n}\n\n(Model as any).get = function get<T extends Model>(\n this: Model.Extends<T>,\n argument?: boolean | Model.GetFactory<T, unknown>\n) {\n const scope = requireScope();\n const instance = scope.context.get(this, argument === false ? false : true);\n\n if (!instance) return undefined;\n\n const proxy = tracked(instance, argument === true);\n\n if (typeof argument != 'function') return proxy;\n\n const refresh = ((action?: Promise<unknown> | (() => Promise<unknown>)) => {\n if (typeof action == 'function') action = action();\n schedule(scope);\n return action instanceof Promise ? action.finally(() => schedule(scope)) : undefined;\n }) as Model.ForceRefresh;\n\n return argument.call(proxy, proxy, refresh) ?? null;\n};\n\nconst OWNERS = new WeakMap<Function, { owner: Model; key: string }>();\n\nModel.on({\n method(key, fn, owner) {\n if (/^[A-Z]/.test(key)) OWNERS.set(fn, { owner, key });\n }\n});\n\nfunction call(type: Function, props: unknown) {\n const sub = OWNERS.get(type);\n\n if (!sub) return type(props);\n\n const { owner, key } = sub;\n return unbind((owner as any)[key]).call(tracked(owner), props);\n}\n\nfunction owner(type: unknown) {\n return typeof type == 'function' ? OWNERS.get(type) : undefined;\n}\n\nexport { call, dispose, enter, owner };\nexport type { Scope };\n","import type { Scope } from './adapter';\nimport { owner } from './adapter';\nimport { schedule } from './scheduler';\n\ninterface Family {\n current: Function;\n scopes: Set<Scope>;\n}\n\nconst FAMILIES = new Map<string, Family>();\nconst FAMILY = new WeakMap<Function, Family>();\n\n/** The latest implementation of a component registered for hot refresh. */\nfunction latest(type: Function) {\n return FAMILY.get(type)?.current || type;\n}\n\n/** Whether two element types are one component, across hot edits. */\nfunction same(a: unknown, b: unknown) {\n if (a === b) return true;\n\n const sub = owner(a);\n\n if (sub) {\n const other = owner(b);\n return !!other && other.owner === sub.owner && other.key === sub.key;\n }\n\n const family = typeof a == 'function' && FAMILY.get(a);\n\n return !!family && family === FAMILY.get(b as Function);\n}\n\nfunction track(type: Function, scope: Scope) {\n FAMILY.get(type)?.scopes.add(scope);\n}\n\nfunction untrack(type: Function, scope: Scope) {\n FAMILY.get(type)?.scopes.delete(scope);\n}\n\n/**\n * Register a module's function components under stable ids. A component seen\n * before takes its new implementation and re-renders where it is mounted.\n */\nfunction hot(id: string, components: Record<string, unknown>) {\n for (const [name, type] of Object.entries(components)) {\n if (typeof type != 'function') continue;\n\n const key = `${id}#${name}`;\n let family = FAMILIES.get(key);\n\n if (!family) FAMILIES.set(key, (family = { current: type, scopes: new Set() }));\n\n FAMILY.set(type, family);\n\n if (family.current === type) continue;\n\n family.current = type;\n\n for (const scope of family.scopes) schedule(scope);\n }\n}\n\nexport { hot, latest, same, track, untrack };\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { JSX } from "./jsx-runtime.js";
|
|
2
2
|
import { has, map } from "@expressive/mvc";
|
|
3
3
|
|
|
4
|
-
//#region src/vnode.d.ts
|
|
4
|
+
//#region src/node/vnode.d.ts
|
|
5
5
|
declare const VNODE: unique symbol;
|
|
6
6
|
type Key = string | number | null | undefined;
|
|
7
7
|
type FunctionComponent<P = any> = (props: P) => Node;
|
|
@@ -48,11 +48,11 @@ declare const Portal: (props: {
|
|
|
48
48
|
children?: Node;
|
|
49
49
|
}) => Node;
|
|
50
50
|
//#endregion
|
|
51
|
-
//#region src/loader.d.ts
|
|
51
|
+
//#region src/node/loader.d.ts
|
|
52
52
|
type Module<T extends ComponentType = ComponentType> = T | {
|
|
53
53
|
default: T;
|
|
54
54
|
};
|
|
55
55
|
type Attributes<T> = [T] extends [never] ? {} : T extends (abstract new (...args: any[]) => infer I) ? JSX.LibraryManagedAttributes<T, I> : T extends ((props: infer P) => any) ? P : never;
|
|
56
56
|
//#endregion
|
|
57
57
|
export { Portal as a, vnode as c, Node as i, Module as n, VNode as o, Fragment as r, createElement as s, Attributes as t };
|
|
58
|
-
//# sourceMappingURL=chunk-loader-
|
|
58
|
+
//# sourceMappingURL=chunk-loader-CZ-53pyV.d.ts.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fragment } from "@expressive/mvc/jsx-runtime";
|
|
2
2
|
|
|
3
|
-
//#region src/vnode.ts
|
|
3
|
+
//#region src/node/vnode.ts
|
|
4
4
|
const VNODE = Symbol("@expressive/dom.vnode");
|
|
5
5
|
const PORTAL = Symbol("@expressive/dom.portal");
|
|
6
6
|
function vnode(type, props, key) {
|
|
@@ -33,4 +33,4 @@ const Portal = PORTAL;
|
|
|
33
33
|
|
|
34
34
|
//#endregion
|
|
35
35
|
export { createElement as a, childrenOf as i, PORTAL as n, isVNode as o, Portal as r, vnode as s, Fragment$1 as t };
|
|
36
|
-
//# sourceMappingURL=chunk-vnode-
|
|
36
|
+
//# sourceMappingURL=chunk-vnode-wpCWQ_Zg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-vnode-wpCWQ_Zg.js","names":["Fragment","FRAGMENT"],"sources":["../src/node/vnode.ts"],"sourcesContent":["import { Fragment as FRAGMENT } from '@expressive/mvc/jsx-runtime';\nimport type { has, map } from '@expressive/mvc';\nimport type { JSX as Runtime } from '../jsx-runtime';\n\nconst VNODE = Symbol('@expressive/dom.vnode');\nconst PORTAL = Symbol('@expressive/dom.portal');\n\ntype Key = string | number | null | undefined;\ntype FunctionComponent<P = any> = (props: P) => Node;\ninterface ComponentInstance {\n render(props?: any): Node;\n}\ntype ComponentType<P = any> = FunctionComponent<P> | (abstract new (...args: any[]) => object);\n\ntype Node =\n | VNode\n | ComponentInstance\n | string\n | number\n | bigint\n | boolean\n | null\n | undefined\n | readonly Node[]\n | has.List<Node>\n | has.Pool<Node, any, any>\n | map.Managed<unknown, Node>;\n\ninterface VNode<P = any> {\n readonly [VNODE]: true;\n readonly type: string | symbol | ComponentType<P>;\n readonly props: P & { children?: Node };\n readonly key?: Key;\n}\n\nfunction vnode<P>(type: VNode<P>['type'], props: P, key?: unknown): VNode<P> {\n return {\n [VNODE]: true,\n type,\n props: (props || {}) as VNode<P>['props'],\n key: key as Key\n };\n}\n\nfunction createElement(type: VNode['type'], props?: Record<string, unknown> | null, ...children: unknown[]): VNode {\n const { key, ...rest } = props || {};\n\n if (children.length) rest.children = children.length == 1 ? children[0] : children;\n\n return vnode(type, rest, key);\n}\n\ntype JsxElement = Runtime.Element;\ntype JsxElementType = Runtime.ElementType;\ntype JsxElementClass = Runtime.ElementClass;\ntype JsxAttributesProperty = Runtime.ElementAttributesProperty;\ntype JsxManaged<C, P> = Runtime.LibraryManagedAttributes<C, P>;\ntype JsxChildrenAttribute = Runtime.ElementChildrenAttribute;\ntype JsxIntrinsicAttributes = Runtime.IntrinsicAttributes;\ntype JsxIntrinsicElements = Runtime.IntrinsicElements;\n\ndeclare namespace createElement {\n namespace JSX {\n type Element = JsxElement;\n type ElementType = JsxElementType;\n interface ElementClass extends JsxElementClass {}\n interface ElementAttributesProperty extends JsxAttributesProperty {}\n type LibraryManagedAttributes<C, P> = JsxManaged<C, P>;\n interface ElementChildrenAttribute extends JsxChildrenAttribute {}\n interface IntrinsicAttributes extends JsxIntrinsicAttributes {}\n type IntrinsicElements = JsxIntrinsicElements;\n }\n}\n\nfunction isVNode(value: unknown): value is VNode {\n return !!value && typeof value == 'object' && (value as VNode)[VNODE] === true;\n}\n\nfunction childrenOf(value: unknown): Node[] {\n const output: Node[] = [];\n\n function add(child: unknown) {\n if (Array.isArray(child)) child.forEach(add);\n else if (child !== null && child !== undefined && typeof child != 'boolean')\n output.push(child as Node);\n }\n\n add(value);\n return output;\n}\n\nconst Fragment = FRAGMENT as unknown as (props: { children?: Node }) => Node;\nconst Portal = PORTAL as unknown as (props: { into: Element | DocumentFragment | string; children?: Node }) => Node;\n\nexport {\n VNODE,\n PORTAL,\n childrenOf,\n createElement,\n Fragment,\n Portal,\n isVNode,\n vnode\n};\n\nexport type { ComponentInstance, ComponentType, FunctionComponent, Key, Node, VNode };\n"],"mappings":";;;AAIA,MAAM,QAAQ,OAAO,wBAAwB;AAC7C,MAAM,SAAS,OAAO,yBAAyB;AA8B/C,SAAS,MAAS,MAAwB,OAAU,KAAyB;AAC3E,QAAO;GACJ,QAAQ;EACT;EACA,OAAQ,SAAS,EAAE;EACd;EACN;;AAGH,SAAS,cAAc,MAAqB,OAAwC,GAAG,UAA4B;CACjH,MAAM,EAAE,KAAK,GAAG,SAAS,SAAS,EAAE;AAEpC,KAAI,SAAS,OAAQ,MAAK,WAAW,SAAS,UAAU,IAAI,SAAS,KAAK;AAE1E,QAAO,MAAM,MAAM,MAAM,IAAI;;AAyB/B,SAAS,QAAQ,OAAgC;AAC/C,QAAO,CAAC,CAAC,SAAS,OAAO,SAAS,YAAa,MAAgB,WAAW;;AAG5E,SAAS,WAAW,OAAwB;CAC1C,MAAM,SAAiB,EAAE;CAEzB,SAAS,IAAI,OAAgB;AAC3B,MAAI,MAAM,QAAQ,MAAM,CAAE,OAAM,QAAQ,IAAI;WACnC,UAAU,QAAQ,UAAU,UAAa,OAAO,SAAS,UAChE,QAAO,KAAK,MAAc;;AAG9B,KAAI,MAAM;AACV,QAAO;;AAGT,MAAMA,aAAWC;AACjB,MAAM,SAAS"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { a as Portal, i as Node, r as Fragment, s as createElement } from "./chunk-loader-
|
|
1
|
+
import { a as Portal, i as Node, r as Fragment, s as createElement } from "./chunk-loader-CZ-53pyV.js";
|
|
2
2
|
import { JSX } from "./jsx-runtime.js";
|
|
3
|
+
import { Component, Context } from "@expressive/mvc";
|
|
3
4
|
|
|
4
|
-
//#region src/stylesheet.d.ts
|
|
5
|
+
//#region src/style/stylesheet.d.ts
|
|
5
6
|
type Member = Extract<keyof CSSStyleDeclaration, string>;
|
|
6
7
|
type Settable = { [K in Member]-?: CSSStyleDeclaration[K] extends Function ? never : K }[Member];
|
|
7
8
|
type Key = style.Property | keyof macro.Registry | `--${string}` | `_${string}`;
|
|
@@ -35,7 +36,7 @@ declare namespace style {
|
|
|
35
36
|
declare function style<T extends object>(type: T, rules: style.Map): T;
|
|
36
37
|
declare function macro(rules: macro.Map): macro.Map;
|
|
37
38
|
//#endregion
|
|
38
|
-
//#region src/css.d.ts
|
|
39
|
+
//#region src/style/css.d.ts
|
|
39
40
|
/**
|
|
40
41
|
* Web macro pack. Register with `macro(css)` to opt into pixel units for
|
|
41
42
|
* numbers and the axis shorthands CSS itself does not provide.
|
|
@@ -77,8 +78,10 @@ declare module '@expressive/dom' {
|
|
|
77
78
|
}
|
|
78
79
|
}
|
|
79
80
|
//#endregion
|
|
80
|
-
//#region src/render.d.ts
|
|
81
|
+
//#region src/render/fiber.d.ts
|
|
81
82
|
type Container = Element | DocumentFragment;
|
|
83
|
+
//#endregion
|
|
84
|
+
//#region src/render/render.d.ts
|
|
82
85
|
declare function render(node: Node, container: Container): () => void;
|
|
83
86
|
//#endregion
|
|
84
87
|
export { Fragment, type JSX, Portal, createElement, css, macro, render, style };
|