@echojs-ecosystem/hyperdom 0.1.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 +82 -0
- package/dist/index.d.ts +286 -0
- package/dist/index.js +583 -0
- package/dist/index.js.map +1 -0
- package/dist/lifecycle/mount.d.ts +17 -0
- package/dist/lifecycle/mount.js +14 -0
- package/dist/lifecycle/mount.js.map +1 -0
- package/dist/types-DqjK6Jv-.d.ts +47 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# @echojs-ecosystem/hyperdom
|
|
4
|
+
|
|
5
|
+
**Direct DOM rendering — no virtual DOM, no JSX required.**
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@echojs-ecosystem/hyperdom)
|
|
8
|
+
[](https://echojs.dev/docs/packages/hyperdom)
|
|
9
|
+
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
The view layer of EchoJS. Maps **views to real DOM nodes** with a hyperscript API (`h`), reactive children, and control helpers (`Show`, `List`). Designed as the foundation for a future JSX compiler.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **`h()`** — create elements, components, and reactive regions
|
|
19
|
+
- **`createView` / `createModel`** — structured UI with context checks
|
|
20
|
+
- **`Show` / `List`** — conditional and list rendering
|
|
21
|
+
- **Reactive props & children** — `() => value` registers effects; only what changed updates
|
|
22
|
+
- **`render()` + `dispose()`** — mount with full cleanup (listeners, effects, DOM)
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @echojs-ecosystem/hyperdom @echojs-ecosystem/reactivity
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { h, render, Show, button, div, span } from "@echojs-ecosystem/hyperdom";
|
|
34
|
+
import { signal } from "@echojs-ecosystem/reactivity";
|
|
35
|
+
|
|
36
|
+
const $count = signal(0);
|
|
37
|
+
|
|
38
|
+
const view = div({ class: "app" }, [
|
|
39
|
+
button({ onClick: () => $count.update((n) => n + 1) }, "Increment"),
|
|
40
|
+
span(null, () => String($count.value())),
|
|
41
|
+
Show(
|
|
42
|
+
() => $count.value() > 0,
|
|
43
|
+
() => span(null, "Count is positive"),
|
|
44
|
+
),
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
const dispose = render(view, document.getElementById("app")!);
|
|
48
|
+
// dispose() when unmounting
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## API
|
|
52
|
+
|
|
53
|
+
| Export | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `h`, `div`, `button`, … | Hyperscript & HTML DSL |
|
|
56
|
+
| `render(view, container)` | Mount view, return `dispose()` |
|
|
57
|
+
| `createView` / `createModel` | View/model factories |
|
|
58
|
+
| `createComponent` | Model + view composition |
|
|
59
|
+
| `Show` / `List` | Control-flow helpers |
|
|
60
|
+
| `mount` | Lifecycle mount helper |
|
|
61
|
+
|
|
62
|
+
### Reactive patterns
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Reactive child
|
|
66
|
+
h("span", null, () => $count.value());
|
|
67
|
+
|
|
68
|
+
// Reactive prop
|
|
69
|
+
h("input", { value: () => $text.value(), onInput: (e) => $text.set(e.currentTarget.value) });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Related packages
|
|
73
|
+
|
|
74
|
+
| Package | Role |
|
|
75
|
+
|---------|------|
|
|
76
|
+
| [`@echojs-ecosystem/reactivity`](https://www.npmjs.com/package/@echojs-ecosystem/reactivity) | Signals for dynamic regions |
|
|
77
|
+
| [`@echojs-ecosystem/router`](https://www.npmjs.com/package/@echojs-ecosystem/router) | SPA routing bindings |
|
|
78
|
+
| [`@echojs-ecosystem/ui`](https://www.npmjs.com/package/@echojs-ecosystem/ui) | Accessible UI components |
|
|
79
|
+
|
|
80
|
+
## Documentation
|
|
81
|
+
|
|
82
|
+
[echojs.dev/docs/packages/hyperdom](https://echojs.dev/docs/packages/hyperdom)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { P as Props, C as Child, a as Component, b as ClassValue } from './types-DqjK6Jv-.js';
|
|
2
|
+
|
|
3
|
+
type HtmlTagName = keyof HTMLElementTagNameMap;
|
|
4
|
+
type SvgTagName = keyof SVGElementTagNameMap;
|
|
5
|
+
type IntrinsicTagName = HtmlTagName | SvgTagName;
|
|
6
|
+
|
|
7
|
+
type ElementForIntrinsicTag$1<T extends IntrinsicTagName> = T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : T extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[T] : Element;
|
|
8
|
+
/**
|
|
9
|
+
* Typed callable signature for `h()`.
|
|
10
|
+
*
|
|
11
|
+
* This is written as a type (not function overloads) so the runtime implementation can be an
|
|
12
|
+
* arrow function while still preserving overload-like call inference.
|
|
13
|
+
*/
|
|
14
|
+
type H = {
|
|
15
|
+
<T extends IntrinsicTagName>(tag: T, props?: Props<ElementForIntrinsicTag$1<T>> | null, children?: Child, ...rest: Child[]): Child;
|
|
16
|
+
<T extends IntrinsicTagName>(tag: T, children?: Child, ...rest: Child[]): Child;
|
|
17
|
+
<P = any>(tag: Component<P>, props?: (P & Props<Element>) | null, children?: Child, ...rest: Child[]): Child;
|
|
18
|
+
<P = any>(tag: Component<P>, children?: Child, ...rest: Child[]): Child;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Creates a DOM node (or calls a component function) with props and children.
|
|
22
|
+
*
|
|
23
|
+
* Supports a convenience call shape: `h("div", "text")` (treat second arg as children when it
|
|
24
|
+
* doesn't look like a props object).
|
|
25
|
+
*/
|
|
26
|
+
declare const h: H;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Renders a `Child` view into a container element.
|
|
30
|
+
*
|
|
31
|
+
* Establishes a cleanup scope, mounts the initial tree, then activates deferred bindings.
|
|
32
|
+
* Returns a `dispose()` function that tears down reactive resources and clears the container.
|
|
33
|
+
*/
|
|
34
|
+
declare const render: (view: Child, container: Element) => (() => void);
|
|
35
|
+
|
|
36
|
+
interface MountResult {
|
|
37
|
+
node: HTMLElement;
|
|
38
|
+
dispose: () => void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Mounts a view into a container element.
|
|
42
|
+
*
|
|
43
|
+
* Creates a container `<div>` by default and returns `{ node, dispose }`.
|
|
44
|
+
*/
|
|
45
|
+
declare const mount: (view: Child, options?: {
|
|
46
|
+
container?: HTMLElement;
|
|
47
|
+
className?: string;
|
|
48
|
+
}) => MountResult;
|
|
49
|
+
|
|
50
|
+
/** Returns true while a `createModel(...)` factory is executing. */
|
|
51
|
+
declare const isInModelContext: () => boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Wraps a model factory to mark "model construction context".
|
|
54
|
+
*
|
|
55
|
+
* Useful for strict-mode checks and for debugging lifecycle boundaries.
|
|
56
|
+
*/
|
|
57
|
+
declare const createModel: <VM>(factory: () => VM, name: string) => (() => VM);
|
|
58
|
+
|
|
59
|
+
declare const createView: <VM = void>(viewFn: (vm: VM) => Child, name: string) => ((vm: VM) => Child);
|
|
60
|
+
|
|
61
|
+
declare const isInViewContext: () => boolean;
|
|
62
|
+
|
|
63
|
+
type ModelFactory<VM> = () => VM;
|
|
64
|
+
type ViewFn<VM> = (vm: VM) => Child;
|
|
65
|
+
type CreateComponentOptions = {
|
|
66
|
+
/** Debug label (e.g. "Counter" → Counter.displayName). */
|
|
67
|
+
name?: string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Binds a model factory and view into a callable component.
|
|
71
|
+
*
|
|
72
|
+
* @example No props
|
|
73
|
+
* ```ts
|
|
74
|
+
* export const Counter = createComponent(createCounterModel, CounterView);
|
|
75
|
+
* // route: view: () => Counter()
|
|
76
|
+
* ```
|
|
77
|
+
*
|
|
78
|
+
* @example With props — pass the bound model factory
|
|
79
|
+
* ```ts
|
|
80
|
+
* export const CodeBlock = (props: Props) =>
|
|
81
|
+
* createComponent(createCodeBlockModel(props), CodeBlockView)();
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare const createComponent: <VM>(model: ModelFactory<VM>, view: ViewFn<VM>, options?: CreateComponentOptions) => (() => Child);
|
|
85
|
+
|
|
86
|
+
/** Enables/disables strict context checks for UI construction. */
|
|
87
|
+
declare const setStrictContextChecks: (enabled: boolean) => void;
|
|
88
|
+
/** Returns current value of strict context checks. */
|
|
89
|
+
declare const getStrictContextChecks: () => boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Conditional region helper.
|
|
93
|
+
*
|
|
94
|
+
* Returns a dynamic child that re-evaluates `condition()` and renders either `then()` or
|
|
95
|
+
* `fallback()` on each update.
|
|
96
|
+
*/
|
|
97
|
+
declare const Show: (condition: () => boolean, then: () => Child, fallback?: () => Child) => (() => Child);
|
|
98
|
+
|
|
99
|
+
type SignalLike<T> = {
|
|
100
|
+
value(): T;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* List rendering helper.
|
|
104
|
+
*
|
|
105
|
+
* Returns a function so the list can be used as a dynamic child and re-evaluated when reactive
|
|
106
|
+
* dependencies change.
|
|
107
|
+
*/
|
|
108
|
+
declare const List: <T>(source: SignalLike<readonly T[]> | (() => readonly T[]), renderItem: (item: T, index: () => number) => Child) => (() => Child);
|
|
109
|
+
|
|
110
|
+
type IntrinsicTag = keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap;
|
|
111
|
+
type ElementForIntrinsicTag<T extends IntrinsicTag> = T extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[T] : T extends keyof SVGElementTagNameMap ? SVGElementTagNameMap[T] : Element;
|
|
112
|
+
type PropsFor<T extends IntrinsicTag> = Props<ElementForIntrinsicTag<T>> | null | undefined;
|
|
113
|
+
type TagFn<T extends IntrinsicTag> = {
|
|
114
|
+
(): Child;
|
|
115
|
+
(props?: PropsFor<T>): Child;
|
|
116
|
+
(props: PropsFor<T>, children?: Child, ...rest: Child[]): Child;
|
|
117
|
+
(children?: Child, ...rest: Child[]): Child;
|
|
118
|
+
};
|
|
119
|
+
/** Small `class` builder for conditional class names. */
|
|
120
|
+
declare const cx: (...values: ClassValue[]) => string;
|
|
121
|
+
/**
|
|
122
|
+
* Tiny helpers for common DOM event props using `onXxx` form.
|
|
123
|
+
*
|
|
124
|
+
* If you want per-element `currentTarget` typing, prefer using `onClick` / `onInput` on the
|
|
125
|
+
* element props so it can be inferred from the tag.
|
|
126
|
+
*/
|
|
127
|
+
declare const on: {
|
|
128
|
+
readonly click: (fn: (e: MouseEvent & {
|
|
129
|
+
currentTarget: Element;
|
|
130
|
+
}) => void) => {
|
|
131
|
+
onClick: (e: MouseEvent & {
|
|
132
|
+
currentTarget: Element;
|
|
133
|
+
}) => void;
|
|
134
|
+
};
|
|
135
|
+
readonly input: (fn: (e: Event & {
|
|
136
|
+
currentTarget: Element;
|
|
137
|
+
}) => void) => {
|
|
138
|
+
onInput: (e: Event & {
|
|
139
|
+
currentTarget: Element;
|
|
140
|
+
}) => void;
|
|
141
|
+
};
|
|
142
|
+
readonly change: (fn: (e: Event & {
|
|
143
|
+
currentTarget: Element;
|
|
144
|
+
}) => void) => {
|
|
145
|
+
onChange: (e: Event & {
|
|
146
|
+
currentTarget: Element;
|
|
147
|
+
}) => void;
|
|
148
|
+
};
|
|
149
|
+
readonly submit: (fn: (e: SubmitEvent & {
|
|
150
|
+
currentTarget: Element;
|
|
151
|
+
}) => void) => {
|
|
152
|
+
onSubmit: (e: SubmitEvent & {
|
|
153
|
+
currentTarget: Element;
|
|
154
|
+
}) => void;
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
/** Common `aria-*` attribute helpers. */
|
|
158
|
+
declare const aria: {
|
|
159
|
+
readonly label: (value: string) => {
|
|
160
|
+
"aria-label": string;
|
|
161
|
+
};
|
|
162
|
+
readonly expanded: (value: boolean) => {
|
|
163
|
+
"aria-expanded": boolean;
|
|
164
|
+
};
|
|
165
|
+
readonly pressed: (value: boolean) => {
|
|
166
|
+
"aria-pressed": boolean;
|
|
167
|
+
};
|
|
168
|
+
readonly hidden: (value: boolean) => {
|
|
169
|
+
"aria-hidden": boolean;
|
|
170
|
+
};
|
|
171
|
+
};
|
|
172
|
+
/** Common `data-*` attribute helpers. */
|
|
173
|
+
declare const data: {
|
|
174
|
+
readonly testid: (value: string) => {
|
|
175
|
+
"data-testid": string;
|
|
176
|
+
};
|
|
177
|
+
readonly test: (value: string) => {
|
|
178
|
+
"data-test": string;
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
/** `<h1>` element factory. */
|
|
182
|
+
declare const h1: TagFn<"h1">;
|
|
183
|
+
/** `<h2>` element factory. */
|
|
184
|
+
declare const h2: TagFn<"h2">;
|
|
185
|
+
/** `<h3>` element factory. */
|
|
186
|
+
declare const h3: TagFn<"h3">;
|
|
187
|
+
/** `<h4>` element factory. */
|
|
188
|
+
declare const h4: TagFn<"h4">;
|
|
189
|
+
/** `<h5>` element factory. */
|
|
190
|
+
declare const h5: TagFn<"h5">;
|
|
191
|
+
/** `<h6>` element factory. */
|
|
192
|
+
declare const h6: TagFn<"h6">;
|
|
193
|
+
/** `<p>` element factory. */
|
|
194
|
+
declare const p: TagFn<"p">;
|
|
195
|
+
/** `<pre>` element factory. */
|
|
196
|
+
declare const pre: TagFn<"pre">;
|
|
197
|
+
/** `<blockquote>` element factory. */
|
|
198
|
+
declare const blockquote: TagFn<"blockquote">;
|
|
199
|
+
/** `<span>` element factory. */
|
|
200
|
+
declare const span: TagFn<"span">;
|
|
201
|
+
/** `<strong>` element factory. */
|
|
202
|
+
declare const strong: TagFn<"strong">;
|
|
203
|
+
/** `<em>` element factory. */
|
|
204
|
+
declare const em: TagFn<"em">;
|
|
205
|
+
/** `<small>` element factory. */
|
|
206
|
+
declare const small: TagFn<"small">;
|
|
207
|
+
/** `<code>` element factory. */
|
|
208
|
+
declare const code: TagFn<"code">;
|
|
209
|
+
/** `<kbd>` element factory. */
|
|
210
|
+
declare const kbd: TagFn<"kbd">;
|
|
211
|
+
/** `<div>` element factory. */
|
|
212
|
+
declare const div: TagFn<"div">;
|
|
213
|
+
/** `<hr>` element factory. */
|
|
214
|
+
declare const hr: TagFn<"hr">;
|
|
215
|
+
/** `<br>` element factory. */
|
|
216
|
+
declare const br: TagFn<"br">;
|
|
217
|
+
/** `<header>` element factory. */
|
|
218
|
+
declare const header: TagFn<"header">;
|
|
219
|
+
/** `<main>` element factory. */
|
|
220
|
+
declare const main: TagFn<"main">;
|
|
221
|
+
/** `<footer>` element factory. */
|
|
222
|
+
declare const footer: TagFn<"footer">;
|
|
223
|
+
/** `<nav>` element factory. */
|
|
224
|
+
declare const nav: TagFn<"nav">;
|
|
225
|
+
/** `<section>` element factory. */
|
|
226
|
+
declare const section: TagFn<"section">;
|
|
227
|
+
/** `<article>` element factory. */
|
|
228
|
+
declare const article: TagFn<"article">;
|
|
229
|
+
/** `<aside>` element factory. */
|
|
230
|
+
declare const aside: TagFn<"aside">;
|
|
231
|
+
/** `<ul>` element factory. */
|
|
232
|
+
declare const ul: TagFn<"ul">;
|
|
233
|
+
/** `<ol>` element factory. */
|
|
234
|
+
declare const ol: TagFn<"ol">;
|
|
235
|
+
/** `<li>` element factory. */
|
|
236
|
+
declare const li: TagFn<"li">;
|
|
237
|
+
/** `<dl>` element factory. */
|
|
238
|
+
declare const dl: TagFn<"dl">;
|
|
239
|
+
/** `<dt>` element factory. */
|
|
240
|
+
declare const dt: TagFn<"dt">;
|
|
241
|
+
/** `<dd>` element factory. */
|
|
242
|
+
declare const dd: TagFn<"dd">;
|
|
243
|
+
/** `<form>` element factory. */
|
|
244
|
+
declare const form: TagFn<"form">;
|
|
245
|
+
/** `<label>` element factory. */
|
|
246
|
+
declare const label: TagFn<"label">;
|
|
247
|
+
/** `<input>` element factory. */
|
|
248
|
+
declare const input: TagFn<"input">;
|
|
249
|
+
/** `<textarea>` element factory. */
|
|
250
|
+
declare const textarea: TagFn<"textarea">;
|
|
251
|
+
/** `<select>` element factory. */
|
|
252
|
+
declare const select: TagFn<"select">;
|
|
253
|
+
/** `<option>` element factory. */
|
|
254
|
+
declare const option: TagFn<"option">;
|
|
255
|
+
/** `<button>` element factory. */
|
|
256
|
+
declare const button: TagFn<"button">;
|
|
257
|
+
/** `<img>` element factory. */
|
|
258
|
+
declare const img: TagFn<"img">;
|
|
259
|
+
/** `<picture>` element factory. */
|
|
260
|
+
declare const picture: TagFn<"picture">;
|
|
261
|
+
/** `<source>` element factory. */
|
|
262
|
+
declare const source: TagFn<"source">;
|
|
263
|
+
/** `<video>` element factory. */
|
|
264
|
+
declare const video: TagFn<"video">;
|
|
265
|
+
/** `<audio>` element factory. */
|
|
266
|
+
declare const audio: TagFn<"audio">;
|
|
267
|
+
/** `<svg>` element factory. */
|
|
268
|
+
declare const svg: TagFn<"svg">;
|
|
269
|
+
/** `<table>` element factory. */
|
|
270
|
+
declare const table: TagFn<"table">;
|
|
271
|
+
/** `<thead>` element factory. */
|
|
272
|
+
declare const thead: TagFn<"thead">;
|
|
273
|
+
/** `<tbody>` element factory. */
|
|
274
|
+
declare const tbody: TagFn<"tbody">;
|
|
275
|
+
/** `<tfoot>` element factory. */
|
|
276
|
+
declare const tfoot: TagFn<"tfoot">;
|
|
277
|
+
/** `<tr>` element factory. */
|
|
278
|
+
declare const tr: TagFn<"tr">;
|
|
279
|
+
/** `<th>` element factory. */
|
|
280
|
+
declare const th: TagFn<"th">;
|
|
281
|
+
/** `<td>` element factory. */
|
|
282
|
+
declare const td: TagFn<"td">;
|
|
283
|
+
/** `<caption>` element factory. */
|
|
284
|
+
declare const caption: TagFn<"caption">;
|
|
285
|
+
|
|
286
|
+
export { Child, Component, type CreateComponentOptions, type IntrinsicTag, List, type ModelFactory, Props, Show, type ViewFn, aria, article, aside, audio, blockquote, br, button, caption, code, createComponent, createModel, createView, cx, data, dd, div, dl, dt, em, footer, form, getStrictContextChecks, h, h1, h2, h3, h4, h5, h6, header, hr, img, input, isInModelContext, isInViewContext, kbd, label, li, main, mount, nav, ol, on, option, p, picture, pre, render, section, select, setStrictContextChecks, small, source, span, strong, svg, table, tbody, td, textarea, tfoot, th, thead, tr, ul, video };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,583 @@
|
|
|
1
|
+
import { effect } from '@echojs-ecosystem/reactivity';
|
|
2
|
+
|
|
3
|
+
// src/lifecycle/reactive.ts
|
|
4
|
+
|
|
5
|
+
// src/lifecycle/cleanup.ts
|
|
6
|
+
var currentScope = null;
|
|
7
|
+
var createScope = () => ({ cleanups: [], disposed: false });
|
|
8
|
+
var getCurrentScope = () => currentScope;
|
|
9
|
+
var runWithScope = (scope, fn) => {
|
|
10
|
+
const prev = currentScope;
|
|
11
|
+
currentScope = scope;
|
|
12
|
+
try {
|
|
13
|
+
return fn();
|
|
14
|
+
} finally {
|
|
15
|
+
currentScope = prev;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var onCleanup = (fn) => {
|
|
19
|
+
const scope = currentScope;
|
|
20
|
+
if (!scope || scope.disposed) return;
|
|
21
|
+
scope.cleanups.push(fn);
|
|
22
|
+
};
|
|
23
|
+
var disposeScope = (scope) => {
|
|
24
|
+
if (scope.disposed) return;
|
|
25
|
+
scope.disposed = true;
|
|
26
|
+
for (let i = scope.cleanups.length - 1; i >= 0; i--) {
|
|
27
|
+
try {
|
|
28
|
+
scope.cleanups[i]?.();
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
scope.cleanups.length = 0;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/lifecycle/reactive.ts
|
|
36
|
+
var createReactiveEffect = (fn, onDispose) => {
|
|
37
|
+
const dispose = effect(fn);
|
|
38
|
+
const wrapped = () => {
|
|
39
|
+
try {
|
|
40
|
+
dispose();
|
|
41
|
+
} finally {
|
|
42
|
+
onDispose?.();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
onCleanup(wrapped);
|
|
46
|
+
return wrapped;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/dom/add-binding.ts
|
|
50
|
+
var bindings = /* @__PURE__ */ new WeakMap();
|
|
51
|
+
var addBinding = (node, fn) => {
|
|
52
|
+
const list = bindings.get(node);
|
|
53
|
+
if (list) list.push(fn);
|
|
54
|
+
else bindings.set(node, [fn]);
|
|
55
|
+
};
|
|
56
|
+
var takeBindings = (node) => {
|
|
57
|
+
const list = bindings.get(node);
|
|
58
|
+
if (!list) return null;
|
|
59
|
+
bindings.delete(node);
|
|
60
|
+
return list;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// src/dom/parse-event-key.ts
|
|
64
|
+
var parseEventKey = (key) => {
|
|
65
|
+
if (!/^on[A-Z]/.test(key)) return null;
|
|
66
|
+
const eventName = key.slice(2);
|
|
67
|
+
const event = eventName.charAt(0).toLowerCase() + eventName.slice(1);
|
|
68
|
+
return { event };
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/dom/set-event.ts
|
|
72
|
+
var setEvent = (element, key, handler) => {
|
|
73
|
+
const parsed = parseEventKey(key);
|
|
74
|
+
if (!parsed) return null;
|
|
75
|
+
if (typeof handler !== "function") return null;
|
|
76
|
+
const { event } = parsed;
|
|
77
|
+
const user = handler;
|
|
78
|
+
const listener = (event2) => user(event2);
|
|
79
|
+
element.addEventListener(event, listener);
|
|
80
|
+
return { event, listener };
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
// src/dom/props.ts
|
|
84
|
+
var isPlainObject = (v) => typeof v === "object" && v !== null && v.constructor === Object;
|
|
85
|
+
var normalizeClass = (value) => {
|
|
86
|
+
const out = [];
|
|
87
|
+
const push = (v) => {
|
|
88
|
+
if (!v || v === true) return;
|
|
89
|
+
if (typeof v === "string") {
|
|
90
|
+
const s = v.trim();
|
|
91
|
+
if (s) out.push(s);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (Array.isArray(v)) {
|
|
95
|
+
for (const x of v) push(x);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (isPlainObject(v)) {
|
|
99
|
+
for (const [k, ok] of Object.entries(v)) {
|
|
100
|
+
if (ok) out.push(k);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
push(value);
|
|
105
|
+
return out.length ? out.join(" ") : null;
|
|
106
|
+
};
|
|
107
|
+
var setStyle = (el, value) => {
|
|
108
|
+
if (value == null || value === false) {
|
|
109
|
+
el.removeAttribute("style");
|
|
110
|
+
el.style.cssText = "";
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (typeof value === "string") {
|
|
114
|
+
el.setAttribute("style", value);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (Array.isArray(value)) {
|
|
118
|
+
el.removeAttribute("style");
|
|
119
|
+
el.style.cssText = "";
|
|
120
|
+
for (const part of value) {
|
|
121
|
+
if (part == null || part === false) continue;
|
|
122
|
+
if (typeof part === "string") {
|
|
123
|
+
el.style.cssText += part.endsWith(";") ? part : part + ";";
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (isPlainObject(part)) {
|
|
127
|
+
const style = el.style;
|
|
128
|
+
for (const [k, v] of Object.entries(part)) {
|
|
129
|
+
if (v == null || v === false) style.removeProperty(k);
|
|
130
|
+
else style.setProperty(k, String(v));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (isPlainObject(value)) {
|
|
137
|
+
const style = el.style;
|
|
138
|
+
for (const [k, v] of Object.entries(value)) {
|
|
139
|
+
if (v == null || v === false) {
|
|
140
|
+
style.removeProperty(k);
|
|
141
|
+
} else {
|
|
142
|
+
style.setProperty(k, String(v));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
var setRef = (el, value) => {
|
|
148
|
+
if (typeof value !== "function") return;
|
|
149
|
+
const ref = value;
|
|
150
|
+
ref(el);
|
|
151
|
+
onCleanup(() => ref(null));
|
|
152
|
+
};
|
|
153
|
+
var setAttr = (el, key, value) => {
|
|
154
|
+
if (value == null || value === false) {
|
|
155
|
+
el.removeAttribute(key);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
el.setAttribute(key, value === true ? "" : String(value));
|
|
159
|
+
};
|
|
160
|
+
var setDomProp = (el, key, value) => {
|
|
161
|
+
if (value == null || value === false) {
|
|
162
|
+
try {
|
|
163
|
+
el[key] = key === "value" ? "" : false;
|
|
164
|
+
} catch {
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
el[key] = value;
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
var setProp = (el, key, value) => {
|
|
174
|
+
if (key === "children") return;
|
|
175
|
+
if (key.startsWith("on")) return;
|
|
176
|
+
if (key.startsWith(".")) {
|
|
177
|
+
setDomProp(el, key.slice(1), value);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (key.startsWith("^")) {
|
|
181
|
+
setAttr(el, key.slice(1), value);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (key === "ref") {
|
|
185
|
+
addBinding(el, () => setRef(el, value));
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (key === "class" || key === "className") {
|
|
189
|
+
setAttr(el, "class", normalizeClass(value));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (key === "style") {
|
|
193
|
+
setStyle(el, value);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (key.startsWith("data-") || key.startsWith("aria-")) {
|
|
197
|
+
setAttr(el, key, value);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (key in el) {
|
|
201
|
+
setDomProp(el, key, value);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
setAttr(el, key, value);
|
|
205
|
+
};
|
|
206
|
+
var setProps = (el, props) => {
|
|
207
|
+
if (!props) return;
|
|
208
|
+
for (const [key, raw] of Object.entries(props)) {
|
|
209
|
+
if (key.startsWith("on")) {
|
|
210
|
+
addBinding(el, () => {
|
|
211
|
+
const bound = setEvent(el, key, raw);
|
|
212
|
+
if (!bound) return;
|
|
213
|
+
onCleanup(() => el.removeEventListener(bound.event, bound.listener));
|
|
214
|
+
});
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (typeof raw === "function" && key !== "ref") {
|
|
218
|
+
addBinding(el, () => createReactiveEffect(() => setProp(el, key, raw())));
|
|
219
|
+
} else {
|
|
220
|
+
setProp(el, key, raw);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/dom/remove-node.ts
|
|
226
|
+
var removeNode = (node) => {
|
|
227
|
+
node.parentNode?.removeChild(node);
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// src/dom/clear-between.ts
|
|
231
|
+
var clearBetween = (start, end) => {
|
|
232
|
+
let cur = start.nextSibling;
|
|
233
|
+
while (cur && cur !== end) {
|
|
234
|
+
const next = cur.nextSibling;
|
|
235
|
+
removeNode(cur);
|
|
236
|
+
cur = next;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/dom/collect-between.ts
|
|
241
|
+
var collectBetween = (start, end) => {
|
|
242
|
+
const out = [];
|
|
243
|
+
let cur = start.nextSibling;
|
|
244
|
+
while (cur && cur !== end) {
|
|
245
|
+
out.push(cur);
|
|
246
|
+
cur = cur.nextSibling;
|
|
247
|
+
}
|
|
248
|
+
return out;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// src/dom/activate-bindings.ts
|
|
252
|
+
var activateBindings = (node) => {
|
|
253
|
+
const list = takeBindings(node);
|
|
254
|
+
if (!list) return;
|
|
255
|
+
for (const fn of list) fn();
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// src/dom/activate-tree.ts
|
|
259
|
+
var activateTree = (root) => {
|
|
260
|
+
activateBindings(root);
|
|
261
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_ALL);
|
|
262
|
+
let cur = walker.nextNode();
|
|
263
|
+
while (cur) {
|
|
264
|
+
activateBindings(cur);
|
|
265
|
+
cur = walker.nextNode();
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// src/dom/children.ts
|
|
270
|
+
var isNode = (v) => typeof v === "object" && v !== null && typeof v.nodeType === "number";
|
|
271
|
+
var normalizeText = (v) => document.createTextNode(String(v));
|
|
272
|
+
var mountChild = (parent, child, before) => {
|
|
273
|
+
if (child == null || child === false || child === true) return [];
|
|
274
|
+
if (typeof child === "string" || typeof child === "number") {
|
|
275
|
+
const node = normalizeText(child);
|
|
276
|
+
parent.insertBefore(node, before);
|
|
277
|
+
return [node];
|
|
278
|
+
}
|
|
279
|
+
if (typeof child === "function") {
|
|
280
|
+
return mountDynamic(parent, child, before);
|
|
281
|
+
}
|
|
282
|
+
if (Array.isArray(child)) {
|
|
283
|
+
return mountChildren(parent, child, before);
|
|
284
|
+
}
|
|
285
|
+
if (isNode(child)) {
|
|
286
|
+
parent.insertBefore(child, before);
|
|
287
|
+
return [child];
|
|
288
|
+
}
|
|
289
|
+
return [];
|
|
290
|
+
};
|
|
291
|
+
var mountChildren = (parent, children, before) => {
|
|
292
|
+
const out = [];
|
|
293
|
+
for (const child of children) {
|
|
294
|
+
if (Array.isArray(child)) out.push(...mountChildren(parent, child, before));
|
|
295
|
+
else out.push(...mountChild(parent, child, before));
|
|
296
|
+
}
|
|
297
|
+
return out;
|
|
298
|
+
};
|
|
299
|
+
var mountDynamic = (parent, compute, before) => {
|
|
300
|
+
const start = document.createComment("hyperdom:start");
|
|
301
|
+
const end = document.createComment("hyperdom:end");
|
|
302
|
+
parent.insertBefore(end, before);
|
|
303
|
+
parent.insertBefore(start, end);
|
|
304
|
+
let regionScope = null;
|
|
305
|
+
const update = () => {
|
|
306
|
+
if (regionScope) {
|
|
307
|
+
disposeScope(regionScope);
|
|
308
|
+
regionScope = null;
|
|
309
|
+
}
|
|
310
|
+
clearBetween(start, end);
|
|
311
|
+
const next = compute();
|
|
312
|
+
const nextScope = createScope();
|
|
313
|
+
regionScope = nextScope;
|
|
314
|
+
runWithScope(nextScope, () => {
|
|
315
|
+
mountChild(parent, next, end);
|
|
316
|
+
for (const node of collectBetween(start, end)) {
|
|
317
|
+
activateTree(node);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
};
|
|
321
|
+
const activate = () => {
|
|
322
|
+
const ownerScope = getCurrentScope();
|
|
323
|
+
if (!ownerScope) {
|
|
324
|
+
update();
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const updateInOwnerScope = () => runWithScope(ownerScope, update);
|
|
328
|
+
createReactiveEffect(updateInOwnerScope, () => {
|
|
329
|
+
if (regionScope) disposeScope(regionScope);
|
|
330
|
+
clearBetween(start, end);
|
|
331
|
+
start.parentNode?.removeChild(start);
|
|
332
|
+
end.parentNode?.removeChild(end);
|
|
333
|
+
});
|
|
334
|
+
};
|
|
335
|
+
addBinding(end, activate);
|
|
336
|
+
addBinding(end, () => {
|
|
337
|
+
onCleanup(() => {
|
|
338
|
+
if (regionScope) disposeScope(regionScope);
|
|
339
|
+
clearBetween(start, end);
|
|
340
|
+
start.parentNode?.removeChild(start);
|
|
341
|
+
end.parentNode?.removeChild(end);
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
return [start, end];
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
// src/dom/create-node.ts
|
|
348
|
+
var createNode = (tag, props, children) => {
|
|
349
|
+
if (typeof tag === "function") {
|
|
350
|
+
const nextProps = { ...props ?? {}, children };
|
|
351
|
+
return tag(nextProps);
|
|
352
|
+
}
|
|
353
|
+
const element = document.createElement(tag);
|
|
354
|
+
setProps(element, props ?? null);
|
|
355
|
+
if (children !== void 0) {
|
|
356
|
+
if (Array.isArray(children)) mountChildren(element, children, null);
|
|
357
|
+
else mountChild(element, children, null);
|
|
358
|
+
}
|
|
359
|
+
return element;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// src/config.ts
|
|
363
|
+
var strictContextChecks = true;
|
|
364
|
+
var setStrictContextChecks = (enabled) => {
|
|
365
|
+
strictContextChecks = enabled;
|
|
366
|
+
};
|
|
367
|
+
var getStrictContextChecks = () => strictContextChecks;
|
|
368
|
+
|
|
369
|
+
// src/view-context.ts
|
|
370
|
+
var viewDepth = 0;
|
|
371
|
+
var isInViewContext = () => viewDepth > 0;
|
|
372
|
+
var withViewContext = (fn) => {
|
|
373
|
+
viewDepth++;
|
|
374
|
+
try {
|
|
375
|
+
return fn();
|
|
376
|
+
} finally {
|
|
377
|
+
viewDepth--;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/h.ts
|
|
382
|
+
var isProps = (value) => {
|
|
383
|
+
return value === null || typeof value === "object" && value !== null && !Array.isArray(value) && !value.nodeType;
|
|
384
|
+
};
|
|
385
|
+
var normalizeChildren = (list) => {
|
|
386
|
+
if (list.length === 0) return void 0;
|
|
387
|
+
if (list.length === 1) return list[0];
|
|
388
|
+
return list;
|
|
389
|
+
};
|
|
390
|
+
var h = ((tag, props, children, ...rest) => {
|
|
391
|
+
if (getStrictContextChecks() && !isInViewContext() && !getCurrentScope()) {
|
|
392
|
+
throw new Error(
|
|
393
|
+
"hyperdom: h() called outside of view/render context. Wrap UI creation in createView(...), or call it while rendering."
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
if (children === void 0 && rest.length === 0 && props !== void 0 && !isProps(props)) {
|
|
397
|
+
return createNode(tag, null, props);
|
|
398
|
+
}
|
|
399
|
+
const normalized = normalizeChildren(children === void 0 ? [] : [children, ...rest]);
|
|
400
|
+
return createNode(tag, props ?? null, normalized);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// src/render.ts
|
|
404
|
+
var render = (view, container) => {
|
|
405
|
+
container.textContent = "";
|
|
406
|
+
const scope = createScope();
|
|
407
|
+
runWithScope(scope, () => {
|
|
408
|
+
if (Array.isArray(view)) mountChildren(container, view, null);
|
|
409
|
+
else mountChild(container, view, null);
|
|
410
|
+
activateTree(container);
|
|
411
|
+
});
|
|
412
|
+
return () => {
|
|
413
|
+
disposeScope(scope);
|
|
414
|
+
container.textContent = "";
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
// src/mount.ts
|
|
419
|
+
var mount = (view, options) => {
|
|
420
|
+
const node = options?.container ?? document.createElement("div");
|
|
421
|
+
if (options?.className) node.className = options.className;
|
|
422
|
+
const dispose = render(view, node);
|
|
423
|
+
node.__echoDispose = dispose;
|
|
424
|
+
return { node, dispose };
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
// src/create-model.ts
|
|
428
|
+
var modelDepth = 0;
|
|
429
|
+
var isInModelContext = () => modelDepth > 0;
|
|
430
|
+
var createModel = (factory, name) => {
|
|
431
|
+
const make = () => {
|
|
432
|
+
modelDepth++;
|
|
433
|
+
try {
|
|
434
|
+
return factory();
|
|
435
|
+
} finally {
|
|
436
|
+
modelDepth--;
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
return Object.assign(make, { displayName: name });
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// src/create-view.ts
|
|
443
|
+
var createView = (viewFn, name) => {
|
|
444
|
+
const view = (vm) => withViewContext(() => viewFn(vm));
|
|
445
|
+
return Object.assign(view, { displayName: name });
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// src/component.ts
|
|
449
|
+
var labelComponent = (fn, name) => {
|
|
450
|
+
if (!name) return fn;
|
|
451
|
+
return Object.assign(fn, { displayName: name });
|
|
452
|
+
};
|
|
453
|
+
var createComponent = (model, view, options) => labelComponent(() => {
|
|
454
|
+
const vm = model();
|
|
455
|
+
return view(vm);
|
|
456
|
+
}, options?.name);
|
|
457
|
+
|
|
458
|
+
// src/control/show.ts
|
|
459
|
+
var Show = (condition, then, fallback) => {
|
|
460
|
+
return () => condition() ? then() : fallback ? fallback() : null;
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
// src/control/list.ts
|
|
464
|
+
var readSource = (source2) => {
|
|
465
|
+
if (typeof source2 === "function") return source2();
|
|
466
|
+
return source2.value();
|
|
467
|
+
};
|
|
468
|
+
var List = (source2, renderItem) => {
|
|
469
|
+
return () => {
|
|
470
|
+
const arr = readSource(source2);
|
|
471
|
+
return arr.map((item, i) => renderItem(item, () => i));
|
|
472
|
+
};
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
// src/dsl.ts
|
|
476
|
+
var isProps2 = (value) => {
|
|
477
|
+
return value === null || typeof value === "object" && value !== null && !Array.isArray(value) && !value.nodeType;
|
|
478
|
+
};
|
|
479
|
+
var normalizeChildren2 = (list) => {
|
|
480
|
+
if (list.length === 0) return void 0;
|
|
481
|
+
if (list.length === 1) return list[0];
|
|
482
|
+
return list;
|
|
483
|
+
};
|
|
484
|
+
var makeTag = (name) => {
|
|
485
|
+
return ((arg1, arg2, ...rest) => {
|
|
486
|
+
const props = isProps2(arg1) ? arg1 : null;
|
|
487
|
+
const childrenList = isProps2(arg1) ? [arg2, ...rest] : [arg1, arg2, ...rest];
|
|
488
|
+
const children = normalizeChildren2(childrenList.filter((x) => x !== void 0));
|
|
489
|
+
return h(name, props, children);
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
var cx = (...values) => {
|
|
493
|
+
const out = [];
|
|
494
|
+
const push = (value) => {
|
|
495
|
+
if (!value) return;
|
|
496
|
+
if (typeof value === "string") {
|
|
497
|
+
const s = value.trim();
|
|
498
|
+
if (s) out.push(s);
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (Array.isArray(value)) {
|
|
502
|
+
for (const x of value) push(x);
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
for (const [k, ok] of Object.entries(value)) {
|
|
506
|
+
if (ok) out.push(k);
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
for (const value of values) push(value);
|
|
510
|
+
return out.join(" ");
|
|
511
|
+
};
|
|
512
|
+
var on = {
|
|
513
|
+
click: (fn) => ({ onClick: fn }),
|
|
514
|
+
input: (fn) => ({ onInput: fn }),
|
|
515
|
+
change: (fn) => ({ onChange: fn }),
|
|
516
|
+
submit: (fn) => ({ onSubmit: fn })
|
|
517
|
+
};
|
|
518
|
+
var aria = {
|
|
519
|
+
label: (value) => ({ "aria-label": value }),
|
|
520
|
+
expanded: (value) => ({ "aria-expanded": value }),
|
|
521
|
+
pressed: (value) => ({ "aria-pressed": value }),
|
|
522
|
+
hidden: (value) => ({ "aria-hidden": value })
|
|
523
|
+
};
|
|
524
|
+
var data = {
|
|
525
|
+
testid: (value) => ({ "data-testid": value }),
|
|
526
|
+
test: (value) => ({ "data-test": value })
|
|
527
|
+
};
|
|
528
|
+
var h1 = makeTag("h1");
|
|
529
|
+
var h2 = makeTag("h2");
|
|
530
|
+
var h3 = makeTag("h3");
|
|
531
|
+
var h4 = makeTag("h4");
|
|
532
|
+
var h5 = makeTag("h5");
|
|
533
|
+
var h6 = makeTag("h6");
|
|
534
|
+
var p = makeTag("p");
|
|
535
|
+
var pre = makeTag("pre");
|
|
536
|
+
var blockquote = makeTag("blockquote");
|
|
537
|
+
var span = makeTag("span");
|
|
538
|
+
var strong = makeTag("strong");
|
|
539
|
+
var em = makeTag("em");
|
|
540
|
+
var small = makeTag("small");
|
|
541
|
+
var code = makeTag("code");
|
|
542
|
+
var kbd = makeTag("kbd");
|
|
543
|
+
var div = makeTag("div");
|
|
544
|
+
var hr = makeTag("hr");
|
|
545
|
+
var br = makeTag("br");
|
|
546
|
+
var header = makeTag("header");
|
|
547
|
+
var main = makeTag("main");
|
|
548
|
+
var footer = makeTag("footer");
|
|
549
|
+
var nav = makeTag("nav");
|
|
550
|
+
var section = makeTag("section");
|
|
551
|
+
var article = makeTag("article");
|
|
552
|
+
var aside = makeTag("aside");
|
|
553
|
+
var ul = makeTag("ul");
|
|
554
|
+
var ol = makeTag("ol");
|
|
555
|
+
var li = makeTag("li");
|
|
556
|
+
var dl = makeTag("dl");
|
|
557
|
+
var dt = makeTag("dt");
|
|
558
|
+
var dd = makeTag("dd");
|
|
559
|
+
var form = makeTag("form");
|
|
560
|
+
var label = makeTag("label");
|
|
561
|
+
var input = makeTag("input");
|
|
562
|
+
var textarea = makeTag("textarea");
|
|
563
|
+
var select = makeTag("select");
|
|
564
|
+
var option = makeTag("option");
|
|
565
|
+
var button = makeTag("button");
|
|
566
|
+
var img = makeTag("img");
|
|
567
|
+
var picture = makeTag("picture");
|
|
568
|
+
var source = makeTag("source");
|
|
569
|
+
var video = makeTag("video");
|
|
570
|
+
var audio = makeTag("audio");
|
|
571
|
+
var svg = makeTag("svg");
|
|
572
|
+
var table = makeTag("table");
|
|
573
|
+
var thead = makeTag("thead");
|
|
574
|
+
var tbody = makeTag("tbody");
|
|
575
|
+
var tfoot = makeTag("tfoot");
|
|
576
|
+
var tr = makeTag("tr");
|
|
577
|
+
var th = makeTag("th");
|
|
578
|
+
var td = makeTag("td");
|
|
579
|
+
var caption = makeTag("caption");
|
|
580
|
+
|
|
581
|
+
export { List, Show, aria, article, aside, audio, blockquote, br, button, caption, code, createComponent, createModel, createView, cx, data, dd, div, dl, dt, em, footer, form, getStrictContextChecks, h, h1, h2, h3, h4, h5, h6, header, hr, img, input, isInModelContext, isInViewContext, kbd, label, li, main, mount, nav, ol, on, option, p, picture, pre, render, section, select, setStrictContextChecks, small, source, span, strong, svg, table, tbody, td, textarea, tfoot, th, thead, tr, ul, video };
|
|
582
|
+
//# sourceMappingURL=index.js.map
|
|
583
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lifecycle/cleanup.ts","../src/lifecycle/reactive.ts","../src/dom/add-binding.ts","../src/dom/parse-event-key.ts","../src/dom/set-event.ts","../src/dom/props.ts","../src/dom/remove-node.ts","../src/dom/clear-between.ts","../src/dom/collect-between.ts","../src/dom/activate-bindings.ts","../src/dom/activate-tree.ts","../src/dom/children.ts","../src/dom/create-node.ts","../src/config.ts","../src/view-context.ts","../src/h.ts","../src/render.ts","../src/mount.ts","../src/create-model.ts","../src/create-view.ts","../src/component.ts","../src/control/show.ts","../src/control/list.ts","../src/dsl.ts"],"names":["event","source","isProps","normalizeChildren"],"mappings":"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","file":"index.js","sourcesContent":["export type CleanupFn = () => void;\n\nexport interface Scope {\n readonly cleanups: CleanupFn[];\n disposed: boolean;\n}\n\nlet currentScope: Scope | null = null;\n\n/** Creates a fresh cleanup scope (used by render and dynamic regions). */\nexport const createScope = (): Scope => ({ cleanups: [], disposed: false });\n\n/** Returns the scope currently active on this call stack (if any). */\nexport const getCurrentScope = (): Scope | null => currentScope;\n\n/**\n * Runs a function with `scope` set as current, restoring the previous scope afterwards.\n */\nexport const runWithScope = <T>(scope: Scope, fn: () => T): T => {\n const prev = currentScope;\n currentScope = scope;\n try {\n return fn();\n } finally {\n currentScope = prev;\n }\n};\n\n/** Registers a cleanup callback on the current scope (no-op if no active scope). */\nexport const onCleanup = (fn: CleanupFn): void => {\n const scope = currentScope;\n if (!scope || scope.disposed) return;\n scope.cleanups.push(fn);\n};\n\n/** Disposes a scope, running cleanups in reverse order (best-effort). */\nexport const disposeScope = (scope: Scope): void => {\n if (scope.disposed) return;\n scope.disposed = true;\n\n for (let i = scope.cleanups.length - 1; i >= 0; i--) {\n try {\n scope.cleanups[i]?.();\n } catch {\n // best-effort cleanup\n }\n }\n scope.cleanups.length = 0;\n};\n","import { effect } from \"@echojs-ecosystem/reactivity\";\nimport { onCleanup } from \"./cleanup\";\n\n/**\n * Registers a reactive effect in the current cleanup scope.\n *\n * Returns the disposer function (also registered with `onCleanup`).\n */\nexport const createReactiveEffect = (fn: () => void, onDispose?: () => void): (() => void) => {\n const dispose = effect(fn);\n const wrapped = () => {\n try {\n dispose();\n } finally {\n onDispose?.();\n }\n };\n onCleanup(wrapped);\n return wrapped;\n};\n","type Binding = () => void;\n\nconst bindings = new WeakMap<Node, Binding[]>();\n\nexport const addBinding = (node: Node, fn: Binding): void => {\n const list = bindings.get(node);\n if (list) list.push(fn);\n else bindings.set(node, [fn]);\n};\n\nexport const takeBindings = (node: Node): Binding[] | null => {\n const list = bindings.get(node);\n if (!list) return null;\n bindings.delete(node);\n return list;\n};\n\n","/** Parses React-style event props (`onClick` → `click`). */\nexport const parseEventKey = (key: string): { event: string } | null => {\n if (!/^on[A-Z]/.test(key)) return null;\n\n const eventName = key.slice(2);\n const event = eventName.charAt(0).toLowerCase() + eventName.slice(1);\n return { event };\n};\n","import { parseEventKey } from \"./parse-event-key\";\n\nexport type EventHandler = (event: Event) => void;\n\nexport const setEvent = (\n element: Element,\n key: string,\n handler: unknown,\n): { event: string; listener: EventListener } | null => {\n const parsed = parseEventKey(key);\n if (!parsed) return null;\n if (typeof handler !== \"function\") return null;\n\n const { event } = parsed;\n const user = handler as (e: Event) => void;\n const listener: EventListener = (event) => user(event);\n\n element.addEventListener(event, listener);\n return { event, listener };\n};\n","import { createReactiveEffect } from \"../lifecycle/reactive\";\nimport { onCleanup } from \"../lifecycle/cleanup\";\nimport { addBinding } from \"./add-binding\";\nimport { setEvent } from \"./set-event\";\n\ntype StyleObject = Record<string, string | number | null | undefined | false>;\n\nconst isPlainObject = (v: unknown): v is Record<string, unknown> =>\n typeof v === \"object\" && v !== null && (v as any).constructor === Object;\n\ntype ClassObject = Record<string, boolean | null | undefined>;\ntype ClassValue =\n | string\n | null\n | undefined\n | false\n | ClassObject\n | readonly ClassValue[];\n\nconst normalizeClass = (value: unknown): string | null => {\n const out: string[] = [];\n\n const push = (v: unknown): void => {\n if (!v || v === true) return;\n if (typeof v === \"string\") {\n const s = v.trim();\n if (s) out.push(s);\n return;\n }\n if (Array.isArray(v)) {\n for (const x of v) push(x);\n return;\n }\n if (isPlainObject(v)) {\n for (const [k, ok] of Object.entries(v as ClassObject)) {\n if (ok) out.push(k);\n }\n }\n };\n\n push(value as ClassValue);\n return out.length ? out.join(\" \") : null;\n};\n\n/** Applies a `style` value (string or object) onto an element. */\nconst setStyle = (el: HTMLElement, value: unknown): void => {\n if (value == null || value === false) {\n el.removeAttribute(\"style\");\n el.style.cssText = \"\";\n return;\n }\n if (typeof value === \"string\") {\n el.setAttribute(\"style\", value);\n return;\n }\n if (Array.isArray(value)) {\n // Vue-like: allow an array of style objects and/or strings.\n // We reset first so reactive updates don't accumulate old styles.\n el.removeAttribute(\"style\");\n el.style.cssText = \"\";\n for (const part of value) {\n if (part == null || part === false) continue;\n if (typeof part === \"string\") {\n el.style.cssText += part.endsWith(\";\") ? part : part + \";\";\n continue;\n }\n if (isPlainObject(part)) {\n const style = el.style;\n for (const [k, v] of Object.entries(part as StyleObject)) {\n if (v == null || v === false) style.removeProperty(k);\n else style.setProperty(k, String(v));\n }\n }\n }\n return;\n }\n if (isPlainObject(value)) {\n const style = el.style;\n for (const [k, v] of Object.entries(value as StyleObject)) {\n if (v == null || v === false) {\n style.removeProperty(k);\n } else {\n style.setProperty(k, String(v));\n }\n }\n }\n};\n\n/** Applies a `ref` callback and registers cleanup to pass `null` on dispose. */\nconst setRef = (el: Element, value: unknown): void => {\n if (typeof value !== \"function\") return;\n const ref = value as (el: Element | null) => void;\n ref(el);\n onCleanup(() => ref(null));\n};\n\n/** Sets/removes a string attribute, handling boolean-ish values. */\nconst setAttr = (el: Element, key: string, value: unknown): void => {\n if (value == null || value === false) {\n el.removeAttribute(key);\n return;\n }\n el.setAttribute(key, value === true ? \"\" : String(value));\n};\n\n/** Sets a DOM property when it exists on the element (best-effort). */\nconst setDomProp = (el: any, key: string, value: unknown): void => {\n if (value == null || value === false) {\n try {\n el[key] = key === \"value\" ? \"\" : false;\n } catch {\n // ignore\n }\n return;\n }\n try {\n el[key] = value;\n } catch {\n // ignore\n }\n};\n\n/**\n * Applies a single prop to an element.\n *\n * Events are deferred and handled by `setProps()` so they can participate in scope cleanup.\n */\nexport const setProp = (el: Element, key: string, value: unknown): void => {\n if (key === \"children\") return;\n\n // Events (deferred, because cleanup depends on render scope)\n if (key.startsWith(\"on\")) return;\n\n // Vue-like modifiers:\n // - `.prop` forces setting a DOM property\n // - `^attr` forces setting an attribute\n if (key.startsWith(\".\")) {\n setDomProp(el as any, key.slice(1), value);\n return;\n }\n if (key.startsWith(\"^\")) {\n setAttr(el, key.slice(1), value);\n return;\n }\n\n if (key === \"ref\") {\n addBinding(el, () => setRef(el, value));\n return;\n }\n\n if (key === \"class\" || key === \"className\") {\n setAttr(el, \"class\", normalizeClass(value));\n return;\n }\n\n if (key === \"style\") {\n setStyle(el as HTMLElement, value);\n return;\n }\n\n if (key.startsWith(\"data-\") || key.startsWith(\"aria-\")) {\n setAttr(el, key, value);\n return;\n }\n\n // Prefer DOM properties when they exist on the element\n if (key in (el as any)) {\n setDomProp(el as any, key, value);\n return;\n }\n\n setAttr(el, key, value);\n};\n\n/**\n * Applies a props object to an element.\n *\n * - Event props (`onClick`, `onInput`, …) are deferred via bindings so they can be cleaned up.\n * - Function-valued props (except `ref`) are treated as reactive getters and re-evaluated.\n */\nexport const setProps = (el: Element, props: Record<string, unknown> | null | undefined): void => {\n if (!props) return;\n\n for (const [key, raw] of Object.entries(props)) {\n if (key.startsWith(\"on\")) {\n addBinding(el, () => {\n const bound = setEvent(el, key, raw);\n if (!bound) return;\n onCleanup(() => el.removeEventListener(bound.event, bound.listener));\n });\n continue;\n }\n\n if (typeof raw === \"function\" && key !== \"ref\") {\n addBinding(el, () => createReactiveEffect(() => setProp(el, key, (raw as any)())));\n } else {\n setProp(el, key, raw);\n }\n }\n};\n","export const removeNode = (node: Node): void => {\n node.parentNode?.removeChild(node);\n};\n\n","import { removeNode } from \"./remove-node\";\n\nexport const clearBetween = (start: Comment, end: Comment): void => {\n let cur = start.nextSibling;\n while (cur && cur !== end) {\n const next = cur.nextSibling;\n removeNode(cur);\n cur = next;\n }\n};\n\n","export const collectBetween = (start: Comment, end: Comment): Node[] => {\n const out: Node[] = [];\n let cur = start.nextSibling;\n while (cur && cur !== end) {\n out.push(cur);\n cur = cur.nextSibling;\n }\n return out;\n};\n\n","import { takeBindings } from \"./add-binding\";\n\nexport const activateBindings = (node: Node): void => {\n const list = takeBindings(node);\n if (!list) return;\n for (const fn of list) fn();\n};\n\n","import { activateBindings } from \"./activate-bindings\";\n\nexport const activateTree = (root: Node): void => {\n activateBindings(root);\n\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ALL);\n let cur: Node | null = walker.nextNode();\n while (cur) {\n activateBindings(cur);\n cur = walker.nextNode();\n }\n};\n\n","import type { Child } from \"../types\";\nimport {\n createScope,\n disposeScope,\n runWithScope,\n type Scope,\n getCurrentScope,\n onCleanup,\n} from \"../lifecycle/cleanup\";\nimport { createReactiveEffect } from \"../lifecycle/reactive\";\nimport { clearBetween } from \"./clear-between\";\nimport { collectBetween } from \"./collect-between\";\nimport { addBinding } from \"./add-binding\";\nimport { activateTree } from \"./activate-tree\";\n\nconst isNode = (v: unknown): v is Node =>\n typeof v === \"object\" && v !== null && typeof (v as any).nodeType === \"number\";\n\n/** Creates a DOM Text node from a primitive child. */\nconst normalizeText = (v: string | number): Text => document.createTextNode(String(v));\n\n/**\n * Mounts a single `Child` value into the DOM.\n *\n * Returns the list of inserted nodes for bookkeeping by higher-level mounts.\n */\nexport const mountChild = (parent: Node, child: Child, before: Node | null): Node[] => {\n if (child == null || child === false || child === true) return [];\n\n if (typeof child === \"string\" || typeof child === \"number\") {\n const node = normalizeText(child);\n parent.insertBefore(node, before);\n return [node];\n }\n\n if (typeof child === \"function\") {\n return mountDynamic(parent, child as () => Child, before);\n }\n\n if (Array.isArray(child)) {\n return mountChildren(parent, child, before);\n }\n\n if (isNode(child)) {\n parent.insertBefore(child, before);\n return [child];\n }\n\n // Unknown values: ignore\n return [];\n};\n\n/** Mounts an array of children into the DOM. */\nexport const mountChildren = (parent: Node, children: Child[], before: Node | null): Node[] => {\n const out: Node[] = [];\n for (const child of children) {\n if (Array.isArray(child)) out.push(...mountChildren(parent, child, before));\n else out.push(...mountChild(parent, child, before));\n }\n return out;\n};\n\n/**\n * Mounts a dynamic region (`() => Child`) between two comment markers.\n *\n * The region is activated later (via bindings) when `render()` runs inside a scope, so reactive\n * dependencies can be tracked and cleaned up correctly.\n */\nconst mountDynamic = (parent: Node, compute: () => Child, before: Node | null): Node[] => {\n const start = document.createComment(\"hyperdom:start\");\n const end = document.createComment(\"hyperdom:end\");\n parent.insertBefore(end, before);\n parent.insertBefore(start, end);\n\n let regionScope: Scope | null = null;\n\n const update = () => {\n if (regionScope) {\n disposeScope(regionScope);\n regionScope = null;\n }\n clearBetween(start, end);\n\n const next = compute();\n const nextScope = createScope();\n regionScope = nextScope;\n\n runWithScope(nextScope, () => {\n mountChild(parent, next, end);\n // Activate deferred bindings (props/events/dynamic regions) created inside this region scope.\n // Without this, reactive props/events inside dynamic regions would never start updating.\n for (const node of collectBetween(start, end)) {\n activateTree(node);\n }\n });\n };\n\n const activate = () => {\n const ownerScope = getCurrentScope();\n if (!ownerScope) {\n // If somehow activated outside of render scope, do a one-off render without reactivity.\n update();\n return;\n }\n\n const updateInOwnerScope = () => runWithScope(ownerScope, update);\n\n createReactiveEffect(updateInOwnerScope, () => {\n if (regionScope) disposeScope(regionScope);\n clearBetween(start, end);\n start.parentNode?.removeChild(start);\n end.parentNode?.removeChild(end);\n });\n };\n\n // Defer activation until render() runs inside a scope.\n addBinding(end, activate);\n\n // Also ensure markers are removed on scope dispose even if activation never happened.\n addBinding(end, () => {\n onCleanup(() => {\n if (regionScope) disposeScope(regionScope);\n clearBetween(start, end);\n start.parentNode?.removeChild(start);\n end.parentNode?.removeChild(end);\n });\n });\n\n return [start, end];\n};\n","import type { Child, Component, Props } from \"../types\";\nimport { setProps } from \"./props\";\nimport { mountChild, mountChildren } from \"./children\";\n\nexport type HtmlTagName = keyof HTMLElementTagNameMap;\nexport type SvgTagName = keyof SVGElementTagNameMap;\nexport type IntrinsicTagName = HtmlTagName | SvgTagName;\n\nexport type Tag = IntrinsicTagName | Component<any>;\n\n/**\n * Creates an element for an intrinsic tag, or calls a component function.\n *\n * - Intrinsic tags are created via `document.createElement(...)`\n * - Props are applied via `setProps(...)`\n * - Children are mounted immediately\n */\nexport const createNode = (tag: Tag, props?: Props<any> | null, children?: Child): Child => {\n if (typeof tag === \"function\") {\n const nextProps = { ...(props ?? {}), children } as any;\n return tag(nextProps);\n }\n\n // Note: createElement supports both HTML and SVG tag names.\n const element = document.createElement(tag as string);\n setProps(element, props ?? null);\n\n if (children !== undefined) {\n if (Array.isArray(children)) mountChildren(element , children, null);\n else mountChild(element, children, null);\n }\n\n return element;\n};\n","let strictContextChecks = true;\n\n/** Enables/disables strict context checks for UI construction. */\nexport const setStrictContextChecks = (enabled: boolean): void => {\n strictContextChecks = enabled;\n};\n\n/** Returns current value of strict context checks. */\nexport const getStrictContextChecks = (): boolean => strictContextChecks;\n","let viewDepth = 0;\n\nexport const isInViewContext = (): boolean => viewDepth > 0;\n\nexport const withViewContext = <T>(fn: () => T): T => {\n viewDepth++;\n try {\n return fn();\n } finally {\n viewDepth--;\n }\n};\n\n","import type { Child, Component, Props } from \"./types\";\nimport { createNode, type IntrinsicTagName, type Tag } from \"./dom/create-node\";\nimport { getStrictContextChecks } from \"./config\";\nimport { isInViewContext } from \"./view-context\";\nimport { getCurrentScope } from \"./lifecycle/cleanup\";\n\ntype ElementForIntrinsicTag<T extends IntrinsicTagName> = T extends keyof HTMLElementTagNameMap\n ? HTMLElementTagNameMap[T]\n : T extends keyof SVGElementTagNameMap\n ? SVGElementTagNameMap[T]\n : Element;\n\n/** True when a value looks like a props bag (not a child). */\nconst isProps = (value: unknown): value is Props<any> => {\n return (\n value === null ||\n (typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value as any).nodeType)\n );\n};\n\n/** Normalizes `children` arguments into a single `Child` value. */\nconst normalizeChildren = (list: unknown[]): Child | undefined => {\n if (list.length === 0) return undefined;\n if (list.length === 1) return list[0] as Child;\n return list as Child[];\n};\n\n/**\n * Typed callable signature for `h()`.\n *\n * This is written as a type (not function overloads) so the runtime implementation can be an\n * arrow function while still preserving overload-like call inference.\n */\nexport type H = {\n <T extends IntrinsicTagName>(\n tag: T,\n props?: Props<ElementForIntrinsicTag<T>> | null,\n children?: Child,\n ...rest: Child[]\n ): Child;\n <T extends IntrinsicTagName>(tag: T, children?: Child, ...rest: Child[]): Child;\n <P = any>(\n tag: Component<P>,\n props?: (P & Props<Element>) | null,\n children?: Child,\n ...rest: Child[]\n ): Child;\n <P = any>(tag: Component<P>, children?: Child, ...rest: Child[]): Child;\n};\n\n/**\n * Creates a DOM node (or calls a component function) with props and children.\n *\n * Supports a convenience call shape: `h(\"div\", \"text\")` (treat second arg as children when it\n * doesn't look like a props object).\n */\nexport const h: H = ((\n tag: IntrinsicTagName | Component<any>,\n props?: Props<any> | null,\n children?: Child,\n ...rest: Child[]\n): Child => {\n // Strict mode: prevent accidental UI construction at module scope.\n // But allow calls inside:\n // - createView() (initial view creation)\n // - render()/dynamic regions/effects (they run under a lifecycle scope)\n if (getStrictContextChecks() && !isInViewContext() && !getCurrentScope()) {\n throw new Error(\n \"hyperdom: h() called outside of view/render context. Wrap UI creation in createView(...), or call it while rendering.\",\n );\n }\n\n // Support h('div', 'text') and h('div', [..]) as a convenience\n if (children === undefined && rest.length === 0 && props !== undefined && !isProps(props)) {\n return createNode(tag as Tag, null, props as any as Child);\n }\n\n const normalized = normalizeChildren(children === undefined ? [] : [children, ...rest]);\n return createNode(tag as Tag, props ?? null, normalized);\n}) as unknown as H;\n","import type { Child } from \"./types\";\nimport { createScope, disposeScope, runWithScope } from \"./lifecycle/cleanup\";\nimport { mountChild, mountChildren } from \"./dom/children\";\nimport { activateTree } from \"./dom/activate-tree\";\n\n/**\n * Renders a `Child` view into a container element.\n *\n * Establishes a cleanup scope, mounts the initial tree, then activates deferred bindings.\n * Returns a `dispose()` function that tears down reactive resources and clears the container.\n */\nexport const render = (view: Child, container: Element): (() => void) => {\n container.textContent = \"\";\n\n const scope = createScope();\n\n runWithScope(scope, () => {\n if (Array.isArray(view)) mountChildren(container, view, null);\n else mountChild(container, view, null);\n\n // Activate deferred reactive props/events/regions inside the current scope.\n activateTree(container);\n });\n\n return () => {\n disposeScope(scope);\n container.textContent = \"\";\n };\n};\n","import type { Child } from \"./types\";\nimport { render } from \"./render\";\n\nexport interface MountResult {\n node: HTMLElement;\n dispose: () => void;\n}\n\n/**\n * Mounts a view into a container element.\n *\n * Creates a container `<div>` by default and returns `{ node, dispose }`.\n */\nexport const mount = (\n view: Child,\n options?: { container?: HTMLElement; className?: string },\n): MountResult => {\n const node = options?.container ?? document.createElement(\"div\");\n if (options?.className) node.className = options.className;\n\n const dispose = render(view, node);\n\n // Optional interop with @echojs-ecosystem/core unmount() mechanism.\n (node as any).__echoDispose = dispose;\n\n return { node, dispose };\n};\n","let modelDepth = 0;\n\n/** Returns true while a `createModel(...)` factory is executing. */\nexport const isInModelContext = (): boolean => modelDepth > 0;\n\n/**\n * Wraps a model factory to mark \"model construction context\".\n *\n * Useful for strict-mode checks and for debugging lifecycle boundaries.\n */\nexport const createModel = <VM>(factory: () => VM, name: string): (() => VM) => {\n const make = (): VM => {\n modelDepth++;\n try {\n return factory();\n } finally {\n modelDepth--;\n }\n };\n return Object.assign(make, { displayName: name });\n};\n","import type { Child } from \"./types\";\nimport { withViewContext } from \"./view-context\";\n\nexport const createView = <VM = void>(\n viewFn: (vm: VM) => Child,\n name: string,\n): ((vm: VM) => Child) => {\n const view = (vm: VM): Child => withViewContext(() => viewFn(vm));\n return Object.assign(view, { displayName: name });\n};\n","import type { Child } from \"./types\";\n\nexport type ModelFactory<VM> = () => VM;\nexport type ViewFn<VM> = (vm: VM) => Child;\n\nexport type CreateComponentOptions = {\n /** Debug label (e.g. \"Counter\" → Counter.displayName). */\n name?: string;\n};\n\nconst labelComponent = (fn: () => Child, name?: string): (() => Child) => {\n if (!name) return fn;\n return Object.assign(fn, { displayName: name });\n};\n\n/**\n * Binds a model factory and view into a callable component.\n *\n * @example No props\n * ```ts\n * export const Counter = createComponent(createCounterModel, CounterView);\n * // route: view: () => Counter()\n * ```\n *\n * @example With props — pass the bound model factory\n * ```ts\n * export const CodeBlock = (props: Props) =>\n * createComponent(createCodeBlockModel(props), CodeBlockView)();\n * ```\n */\nexport const createComponent = <VM>(\n model: ModelFactory<VM>,\n view: ViewFn<VM>,\n options?: CreateComponentOptions,\n): (() => Child) =>\n labelComponent((): Child => {\n const vm = model();\n return view(vm);\n }, options?.name);\n","import type { Child } from \"../types\";\n\n/**\n * Conditional region helper.\n *\n * Returns a dynamic child that re-evaluates `condition()` and renders either `then()` or\n * `fallback()` on each update.\n */\nexport const Show = (\n condition: () => boolean,\n then: () => Child,\n fallback?: () => Child,\n): (() => Child) => {\n return () => (condition() ? then() : fallback ? fallback() : null);\n};\n","import type { Child } from \"../types\";\n\ntype SignalLike<T> = { value(): T };\n\n/** Reads an array from either a signal-like source or a getter function. */\nconst readSource = <T>(source: SignalLike<readonly T[]> | (() => readonly T[])): readonly T[] => {\n if (typeof source === \"function\") return source();\n return source.value();\n};\n\n/**\n * List rendering helper.\n *\n * Returns a function so the list can be used as a dynamic child and re-evaluated when reactive\n * dependencies change.\n */\nexport const List = <T>(\n source: SignalLike<readonly T[]> | (() => readonly T[]),\n renderItem: (item: T, index: () => number) => Child,\n): (() => Child) => {\n return () => {\n const arr = readSource(source);\n return arr.map((item, i) => renderItem(item, () => i));\n };\n};\n","import type { Child, ClassValue, Props } from \"./types\";\nimport { h } from \"./h\";\n\nexport type IntrinsicTag = keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap;\n\ntype ElementForIntrinsicTag<T extends IntrinsicTag> = T extends keyof HTMLElementTagNameMap\n ? HTMLElementTagNameMap[T]\n : T extends keyof SVGElementTagNameMap\n ? SVGElementTagNameMap[T]\n : Element;\n\ntype PropsFor<T extends IntrinsicTag> = Props<ElementForIntrinsicTag<T>> | null | undefined;\n\ntype TagFn<T extends IntrinsicTag> = {\n (): Child;\n (props?: PropsFor<T>): Child;\n (props: PropsFor<T>, children?: Child, ...rest: Child[]): Child;\n (children?: Child, ...rest: Child[]): Child;\n};\n\n/** True when a value looks like a props bag (not a child). */\nconst isProps = (value: unknown): value is Record<string, unknown> | null | undefined => {\n return (\n value === null ||\n (typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n !(value as any).nodeType)\n );\n};\n\n/** Normalizes `children` arguments into a single `Child` value. */\nconst normalizeChildren = (list: unknown[]): Child | undefined => {\n if (list.length === 0) return undefined;\n if (list.length === 1) return list[0] as Child;\n return list as Child[];\n};\n\nconst makeTag = <T extends IntrinsicTag>(name: T) => {\n return ((arg1?: unknown, arg2?: unknown, ...rest: unknown[]): Child => {\n // Vue-like call shapes:\n // - div()\n // - div(props)\n // - div('text') / div([..]) / div(() => ...)\n // - div(props, children, ...rest)\n const props = isProps(arg1) ? (arg1 as PropsFor<T>) : null;\n const childrenList = isProps(arg1) ? [arg2, ...rest] : [arg1, arg2, ...rest];\n const children = normalizeChildren(childrenList.filter((x) => x !== undefined));\n return h(name as any, props, children as any);\n }) as unknown as TagFn<T>;\n};\n\n/** Small `class` builder for conditional class names. */\nexport const cx = (...values: ClassValue[]): string => {\n const out: string[] = [];\n const push = (value: ClassValue): void => {\n if (!value) return;\n if (typeof value === \"string\") {\n const s = value.trim();\n if (s) out.push(s);\n return;\n }\n if (Array.isArray(value)) {\n for (const x of value) push(x);\n return;\n }\n for (const [k, ok] of Object.entries(value)) {\n if (ok) out.push(k);\n }\n };\n for (const value of values) push(value);\n return out.join(\" \");\n};\n\n/**\n * Tiny helpers for common DOM event props using `onXxx` form.\n *\n * If you want per-element `currentTarget` typing, prefer using `onClick` / `onInput` on the\n * element props so it can be inferred from the tag.\n */\nexport const on = {\n click: (fn: (e: MouseEvent & { currentTarget: Element }) => void) => ({ onClick: fn }),\n input: (fn: (e: Event & { currentTarget: Element }) => void) => ({ onInput: fn }),\n change: (fn: (e: Event & { currentTarget: Element }) => void) => ({ onChange: fn }),\n submit: (fn: (e: SubmitEvent & { currentTarget: Element }) => void) => ({ onSubmit: fn }),\n} as const;\n\n/** Common `aria-*` attribute helpers. */\nexport const aria = {\n label: (value: string) => ({ \"aria-label\": value }),\n expanded: (value: boolean) => ({ \"aria-expanded\": value }),\n pressed: (value: boolean) => ({ \"aria-pressed\": value }),\n hidden: (value: boolean) => ({ \"aria-hidden\": value }),\n} as const;\n\n/** Common `data-*` attribute helpers. */\nexport const data = {\n testid: (value: string) => ({ \"data-testid\": value }),\n test: (value: string) => ({ \"data-test\": value }),\n} as const;\n\n// Convenience exports (flat) — чтобы писать `button(...)`, `section(...)` и т.д.\n/** `<h1>` element factory. */\nexport const h1 = makeTag(\"h1\");\n/** `<h2>` element factory. */\nexport const h2 = makeTag(\"h2\");\n/** `<h3>` element factory. */\nexport const h3 = makeTag(\"h3\");\n/** `<h4>` element factory. */\nexport const h4 = makeTag(\"h4\");\n/** `<h5>` element factory. */\nexport const h5 = makeTag(\"h5\");\n/** `<h6>` element factory. */\nexport const h6 = makeTag(\"h6\");\n\n/** `<p>` element factory. */\nexport const p = makeTag(\"p\");\n/** `<pre>` element factory. */\nexport const pre = makeTag(\"pre\");\n/** `<blockquote>` element factory. */\nexport const blockquote = makeTag(\"blockquote\");\n\n/** `<span>` element factory. */\nexport const span = makeTag(\"span\");\n/** `<strong>` element factory. */\nexport const strong = makeTag(\"strong\");\n/** `<em>` element factory. */\nexport const em = makeTag(\"em\");\n/** `<small>` element factory. */\nexport const small = makeTag(\"small\");\n/** `<code>` element factory. */\nexport const code = makeTag(\"code\");\n/** `<kbd>` element factory. */\nexport const kbd = makeTag(\"kbd\");\n\n/** `<div>` element factory. */\nexport const div = makeTag(\"div\");\n/** `<hr>` element factory. */\nexport const hr = makeTag(\"hr\");\n/** `<br>` element factory. */\nexport const br = makeTag(\"br\");\n\n/** `<header>` element factory. */\nexport const header = makeTag(\"header\");\n/** `<main>` element factory. */\nexport const main = makeTag(\"main\");\n/** `<footer>` element factory. */\nexport const footer = makeTag(\"footer\");\n/** `<nav>` element factory. */\nexport const nav = makeTag(\"nav\");\n/** `<section>` element factory. */\nexport const section = makeTag(\"section\");\n/** `<article>` element factory. */\nexport const article = makeTag(\"article\");\n/** `<aside>` element factory. */\nexport const aside = makeTag(\"aside\");\n\n/** `<ul>` element factory. */\nexport const ul = makeTag(\"ul\");\n/** `<ol>` element factory. */\nexport const ol = makeTag(\"ol\");\n/** `<li>` element factory. */\nexport const li = makeTag(\"li\");\n/** `<dl>` element factory. */\nexport const dl = makeTag(\"dl\");\n/** `<dt>` element factory. */\nexport const dt = makeTag(\"dt\");\n/** `<dd>` element factory. */\nexport const dd = makeTag(\"dd\");\n\n/** `<form>` element factory. */\nexport const form = makeTag(\"form\");\n/** `<label>` element factory. */\nexport const label = makeTag(\"label\");\n/** `<input>` element factory. */\nexport const input = makeTag(\"input\");\n/** `<textarea>` element factory. */\nexport const textarea = makeTag(\"textarea\");\n/** `<select>` element factory. */\nexport const select = makeTag(\"select\");\n/** `<option>` element factory. */\nexport const option = makeTag(\"option\");\n/** `<button>` element factory. */\nexport const button = makeTag(\"button\");\n\n/** `<img>` element factory. */\nexport const img = makeTag(\"img\");\n/** `<picture>` element factory. */\nexport const picture = makeTag(\"picture\");\n/** `<source>` element factory. */\nexport const source = makeTag(\"source\");\n/** `<video>` element factory. */\nexport const video = makeTag(\"video\");\n/** `<audio>` element factory. */\nexport const audio = makeTag(\"audio\");\n/** `<svg>` element factory. */\nexport const svg = makeTag(\"svg\");\n\n/** `<table>` element factory. */\nexport const table = makeTag(\"table\");\n/** `<thead>` element factory. */\nexport const thead = makeTag(\"thead\");\n/** `<tbody>` element factory. */\nexport const tbody = makeTag(\"tbody\");\n/** `<tfoot>` element factory. */\nexport const tfoot = makeTag(\"tfoot\");\n/** `<tr>` element factory. */\nexport const tr = makeTag(\"tr\");\n/** `<th>` element factory. */\nexport const th = makeTag(\"th\");\n/** `<td>` element factory. */\nexport const td = makeTag(\"td\");\n/** `<caption>` element factory. */\nexport const caption = makeTag(\"caption\");\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { C as Child } from '../types-DqjK6Jv-.js';
|
|
2
|
+
|
|
3
|
+
type MountCleanup = void | (() => void);
|
|
4
|
+
/**
|
|
5
|
+
* "onMount" hook implemented as a `Child`.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
*
|
|
9
|
+
* - `div(null, mount(() => { ...; return () => ... }))`
|
|
10
|
+
*
|
|
11
|
+
* The callback runs after the node is inserted into the DOM and bindings are being activated
|
|
12
|
+
* inside an active cleanup scope. If the callback returns a function, it will be registered as
|
|
13
|
+
* cleanup (unmount) handler.
|
|
14
|
+
*/
|
|
15
|
+
declare const mountLifecycleHook: (fn: () => MountCleanup) => Child;
|
|
16
|
+
|
|
17
|
+
export { type MountCleanup, mountLifecycleHook as mount };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/dom/add-binding.ts
|
|
2
|
+
|
|
3
|
+
// src/lifecycle/on-mount.ts
|
|
4
|
+
var mountLifecycleHook = (fn) => {
|
|
5
|
+
{
|
|
6
|
+
throw new Error(
|
|
7
|
+
"hyperdom: mount() called outside of view/render context. Call it while rendering (as a child), or inside createView(...)."
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { mountLifecycleHook as mount };
|
|
13
|
+
//# sourceMappingURL=mount.js.map
|
|
14
|
+
//# sourceMappingURL=mount.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lifecycle/on-mount.ts"],"names":[],"mappings":";;;AAmBO,IAAM,kBAAA,GAAqB,CAAC,EAAA,KAAkC;AACnE,EAA0E;AACxE,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA,EACF;AAaF","file":"mount.js","sourcesContent":["import type { Child } from \"../types\";\nimport { addBinding } from \"../dom/add-binding\";\nimport { onCleanup, getCurrentScope } from \"./cleanup\";\nimport { getStrictContextChecks } from \"../config\";\nimport { isInViewContext } from \"../view-context\";\n\nexport type MountCleanup = void | (() => void);\n\n/**\n * \"onMount\" hook implemented as a `Child`.\n *\n * Usage:\n *\n * - `div(null, mount(() => { ...; return () => ... }))`\n *\n * The callback runs after the node is inserted into the DOM and bindings are being activated\n * inside an active cleanup scope. If the callback returns a function, it will be registered as\n * cleanup (unmount) handler.\n */\nexport const mountLifecycleHook = (fn: () => MountCleanup): Child => {\n if (getStrictContextChecks() && !isInViewContext() && !getCurrentScope()) {\n throw new Error(\n \"hyperdom: mount() called outside of view/render context. Call it while rendering (as a child), or inside createView(...).\",\n );\n }\n\n const marker = document.createComment(\"hyperdom:mount\");\n\n addBinding(marker, () => {\n const cleanup = fn();\n if (typeof cleanup === \"function\") onCleanup(cleanup);\n\n // Remove marker on scope dispose so it doesn't leak into output DOM.\n onCleanup(() => marker.parentNode?.removeChild(marker));\n });\n\n return marker;\n};\n\n/** Public name for the mount lifecycle hook. */\nexport { mountLifecycleHook as mount };\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
type Child = string | number | boolean | null | undefined | Node | Child[] | (() => Child);
|
|
2
|
+
type Primitive = string | number | boolean | null | undefined;
|
|
3
|
+
type MaybeReactive<T> = T | (() => T);
|
|
4
|
+
type StyleObject = Record<string, string | number | null | undefined | false>;
|
|
5
|
+
type ClassObject = Record<string, boolean | null | undefined>;
|
|
6
|
+
type ClassValue = string | null | undefined | false | ClassObject | readonly ClassValue[];
|
|
7
|
+
type StyleValue = string | StyleObject | null | undefined | false | readonly (string | StyleObject | null | undefined | false)[];
|
|
8
|
+
type NonFunctionKeys<T> = {
|
|
9
|
+
[K in keyof T]-?: T[K] extends (...args: any[]) => any ? never : K;
|
|
10
|
+
}[keyof T];
|
|
11
|
+
type ElementLikeProps<E extends Element> = Omit<{
|
|
12
|
+
[K in NonFunctionKeys<E>]?: MaybeReactive<E[K] | null | undefined>;
|
|
13
|
+
}, "style" | "className">;
|
|
14
|
+
type EventName = keyof GlobalEventHandlersEventMap;
|
|
15
|
+
type DomEventHandler<E extends Element, K extends EventName> = (event: GlobalEventHandlersEventMap[K] & {
|
|
16
|
+
currentTarget: E;
|
|
17
|
+
}) => void;
|
|
18
|
+
type OnProps<E extends Element> = {
|
|
19
|
+
[K in EventName as `on${Capitalize<K>}`]?: DomEventHandler<E, K>;
|
|
20
|
+
};
|
|
21
|
+
type DataAriaProps = {
|
|
22
|
+
[K in `data-${string}`]?: MaybeReactive<Primitive>;
|
|
23
|
+
} & {
|
|
24
|
+
[K in `aria-${string}`]?: MaybeReactive<Primitive>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Vue-like prop modifiers:
|
|
28
|
+
* - `.propName` sets an element property directly
|
|
29
|
+
* - `^attrName` forces an attribute (even when a same-named property exists)
|
|
30
|
+
*/
|
|
31
|
+
type ModifierProps = {
|
|
32
|
+
[K in `.${string}`]?: unknown;
|
|
33
|
+
} & {
|
|
34
|
+
[K in `^${string}`]?: Primitive;
|
|
35
|
+
};
|
|
36
|
+
type Props<E extends Element = Element> = ElementLikeProps<E> & OnProps<E> & DataAriaProps & ModifierProps & {
|
|
37
|
+
ref?: (el: E | null) => void;
|
|
38
|
+
class?: MaybeReactive<ClassValue>;
|
|
39
|
+
className?: MaybeReactive<ClassValue>;
|
|
40
|
+
style?: MaybeReactive<StyleValue>;
|
|
41
|
+
children?: Child;
|
|
42
|
+
};
|
|
43
|
+
type Component<P = any> = (props: P & {
|
|
44
|
+
children?: Child;
|
|
45
|
+
}) => Child;
|
|
46
|
+
|
|
47
|
+
export type { Child as C, Props as P, Component as a, ClassValue as b };
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@echojs-ecosystem/hyperdom",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist"
|
|
6
|
+
],
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./lifecycle/mount": {
|
|
15
|
+
"types": "./dist/lifecycle/mount.d.ts",
|
|
16
|
+
"default": "./dist/lifecycle/mount.js"
|
|
17
|
+
},
|
|
18
|
+
"./package.json": "./package.json"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"check-types": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.typing.json --noEmit",
|
|
23
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.typing.json --noEmit",
|
|
24
|
+
"test:types": "tsc -p tsconfig.typing.json --noEmit",
|
|
25
|
+
"lint": "oxlint .",
|
|
26
|
+
"lint:fix": "oxlint . --fix",
|
|
27
|
+
"format": "oxfmt --check .",
|
|
28
|
+
"format:fix": "oxfmt .",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:vitest": "vitest",
|
|
31
|
+
"test:vitest:run": "vitest run",
|
|
32
|
+
"test:coverage": "vitest run --coverage"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@echojs-ecosystem/reactivity": "workspace:*"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@echojs-ecosystem/oxc-config": "workspace:*",
|
|
39
|
+
"jsdom": "^26.1.0",
|
|
40
|
+
"typescript": "5.9.2",
|
|
41
|
+
"vitest": "^4.1.4"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "https://github.com/echojs-ecosystem/echojs-core.git",
|
|
49
|
+
"directory": "packages/hyperdom"
|
|
50
|
+
}
|
|
51
|
+
}
|