@wrnrlr/prelude 0.1.9 → 0.2.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/.github/workflows/publish.yml +12 -11
- package/{deno.json → deno.jsonc} +13 -8
- package/example/index.html +43 -0
- package/package.json +6 -2
- package/src/constants.ts +110 -52
- package/src/controlflow.ts +140 -91
- package/src/hyperscript.ts +85 -109
- package/src/mod.ts +3 -5
- package/src/reactive.ts +29 -17
- package/src/runtime.ts +128 -66
- package/test/hyperscript.js +7 -6
- package/test/reactive.js +22 -2
- package/test/types.ts +44 -0
- package/src/components.js +0 -20
- package/src/ui/accordion.ts +0 -8
- package/src/ui/button.ts +0 -9
- package/src/ui/canvas.ts +0 -8
- package/src/ui/date.ts +0 -8
- package/src/ui/dialog.ts +0 -12
- package/src/ui/filter.ts +0 -8
- package/src/ui/form.ts +0 -7
- package/src/ui/h.ts +0 -48
- package/src/ui/image.ts +0 -5
- package/src/ui/input.ts +0 -49
- package/src/ui/mod.ts +0 -12
- package/src/ui/multiselect.ts +0 -42
- package/src/ui/option.ts +0 -1
- package/src/ui/select.ts +0 -28
- package/src/ui/tab.ts +0 -7
- package/src/ui/table.ts +0 -9
- package/src/ui/upload.ts +0 -7
- package/www/assets/css/presets.css +0 -504
- package/www/assets/css/style.css +0 -90
- package/www/demo.html +0 -28
- package/www/index.html +0 -211
- package/www/playground.html +0 -184
- package/www/public/banner.svg +0 -6
- package/www/public/example/admin.html +0 -88
- package/www/public/example/counter.html +0 -24
- package/www/public/example/greeting.html +0 -25
- package/www/public/example/select.html +0 -27
- package/www/public/example/show.html +0 -18
- package/www/public/example/todo.html +0 -70
- package/www/public/fonts/fab.ttf +0 -0
- package/www/public/fonts/fab.woff2 +0 -0
- package/www/public/fonts/far.ttf +0 -0
- package/www/public/fonts/far.woff2 +0 -0
- package/www/public/fonts/fas.ttf +0 -0
- package/www/public/fonts/fas.woff2 +0 -0
- package/www/public/logo.svg +0 -16
- package/www/typedoc.json +0 -13
- package/www/ui.html +0 -49
- package/www/vite.config.js +0 -106
package/src/runtime.ts
CHANGED
@@ -1,10 +1,24 @@
|
|
1
1
|
// @ts-nocheck:
|
2
2
|
import {effect,untrack,root} from './reactive.ts'
|
3
3
|
import {SVGNamespace,SVGElements,ChildProperties,getPropAlias,Properties,Aliases,DelegatedEvents} from './constants.ts'
|
4
|
-
import type {
|
4
|
+
// import type {Mountable} from './constants.ts'
|
5
5
|
|
6
6
|
const {isArray} = Array
|
7
|
-
|
7
|
+
|
8
|
+
export type Mountable = HTMLElement | Document | ShadowRoot | DocumentFragment | Node | string | number | bigint | symbol;
|
9
|
+
|
10
|
+
// declare global {
|
11
|
+
// interface Document {
|
12
|
+
// '_$DX_DELEGATE'?: Record<string, Set<unknown>>
|
13
|
+
// }
|
14
|
+
// // interface SVGElement {}
|
15
|
+
// }
|
16
|
+
|
17
|
+
// interface Element {
|
18
|
+
// style?: string
|
19
|
+
// }
|
20
|
+
|
21
|
+
// declare const globalThis: Document
|
8
22
|
|
9
23
|
/**
|
10
24
|
|
@@ -12,47 +26,63 @@ export const $RUNTIME = Symbol()
|
|
12
26
|
*/
|
13
27
|
export type Runtime = {
|
14
28
|
// window:Window
|
15
|
-
render(code:()=>void, element:
|
29
|
+
render(code:()=>void, element:Element, init:any): any;
|
16
30
|
insert(parent:Mountable, accessor:any, marker?:Node|null, init?:any): any;
|
17
|
-
spread(node:
|
18
|
-
assign(node:
|
31
|
+
spread(node:Element, accessor:any, skipChildren?: boolean): void;
|
32
|
+
assign(node:Element, props:any, skipChildren?:boolean): void;
|
19
33
|
element(name:string): any;
|
34
|
+
component(fn:()=>unknown): any
|
20
35
|
text(s:string): any;
|
21
36
|
isChild(a:any): boolean;
|
22
37
|
clearDelegatedEvents():void
|
23
38
|
}
|
24
39
|
|
40
|
+
type ClassListProps = Record<string, string|boolean>
|
41
|
+
type StyleProps = undefined | string | Record<string, string|undefined>
|
42
|
+
|
25
43
|
/**
|
26
44
|
Create `Runtime` for `window`
|
27
45
|
@param window
|
28
46
|
@group Internal
|
29
47
|
*/
|
30
|
-
export function runtime(
|
31
|
-
const document =
|
32
|
-
|
33
|
-
element = (name:string) => SVGElements.has(name) ?
|
48
|
+
export function runtime(w:Window):Runtime {
|
49
|
+
const document = w.document
|
50
|
+
const isSVG = (e: unknown) => e instanceof (w.SVGElement),
|
51
|
+
element = (name:string) => SVGElements.has(name) ?
|
52
|
+
document.createElementNS("http://www.w3.org/2000/svg",name) : document.createElement(name),
|
34
53
|
text = (s:string) => document.createTextNode(s)
|
35
54
|
|
36
|
-
function isChild(a:unknown):
|
37
|
-
return a instanceof
|
55
|
+
function isChild(a:unknown): a is Element {
|
56
|
+
return a instanceof Element
|
57
|
+
}
|
58
|
+
|
59
|
+
function component(fn:()=>unknown) {
|
60
|
+
return untrack(fn)
|
38
61
|
}
|
39
62
|
|
40
|
-
function render(code:()=>void, element:
|
63
|
+
function render(code: ()=>void, element:Element, init?:any): void
|
64
|
+
function render(code: ()=>void, element:Document, init?:any): void
|
65
|
+
function render(code: ()=>void, element:Element|Document, init?:any): void {
|
41
66
|
if (!element) throw new Error("The `element` passed to `render(..., element)` doesn't exist.");
|
42
67
|
root(() => {
|
43
|
-
if (element
|
44
|
-
else insert(element, code(), element.firstChild ? null : undefined, init)
|
68
|
+
if (element instanceof Document) code()
|
69
|
+
else insert(element as Element, code(), element.firstChild ? null : undefined, init)
|
45
70
|
})
|
46
71
|
}
|
47
72
|
|
48
|
-
|
73
|
+
type Value = string | number | Element | Text
|
74
|
+
type RxValue = (()=>Value) | Value
|
75
|
+
|
76
|
+
function insert(parent: Element, accessor: string, marker?: Node|null, initial?: any): void
|
77
|
+
function insert(parent: Element, accessor: ()=>string, marker?: Node|null, initial?: any): void
|
78
|
+
function insert(parent: Element, accessor: string|(()=>string), marker?: Node|null, initial?: any): void {
|
49
79
|
if (marker !== undefined && !initial) initial = []
|
50
|
-
if (
|
80
|
+
if (typeof accessor !== 'function') return insertExpression(parent, accessor, initial||[], marker)
|
51
81
|
let current = initial||[]
|
52
82
|
effect(() => {current = insertExpression(parent, accessor(), current, marker)})
|
53
83
|
}
|
54
84
|
|
55
|
-
function spread(node:
|
85
|
+
function spread(node:Element, props:any = {}, skipChildren:boolean) {
|
56
86
|
const prevProps:any = {}
|
57
87
|
if (!skipChildren) effect(() => (prevProps.children = insertExpression(node, props.children, prevProps.children)))
|
58
88
|
effect(() => (props.ref?.call ? untrack(() => props.ref(node)) : (props.ref = node)))
|
@@ -60,7 +90,7 @@ export function runtime(window:Window):Runtime {
|
|
60
90
|
return prevProps
|
61
91
|
}
|
62
92
|
|
63
|
-
function assign(node:
|
93
|
+
function assign(node:Element, props:any, skipChildren:boolean, prevProps:any = {}, skipRef:boolean = false) {
|
64
94
|
const svg = isSVG(node)
|
65
95
|
props || (props = {})
|
66
96
|
for (const prop in prevProps) {
|
@@ -79,22 +109,34 @@ export function runtime(window:Window):Runtime {
|
|
79
109
|
}
|
80
110
|
}
|
81
111
|
|
82
|
-
function assignProp(node:
|
112
|
+
function assignProp(node: Element, prop: 'style', value: StyleProps, prev: StyleProps, isSVG: boolean, skipRef: boolean): StyleProps
|
113
|
+
function assignProp(node: Element, prop: 'classList', value: ClassListProps, prev: ClassListProps, isSVG: boolean, skipRef: boolean): ClassListProps
|
114
|
+
function assignProp(node: Element, prop: 'ref', value: ()=>string, prev:string, isSVG: boolean, skipRef: false): string
|
115
|
+
function assignProp(node: Element, prop: string, value: string, prev: string|undefined, isSVG: boolean, skipRef: boolean): string
|
116
|
+
function assignProp(node: Element, prop: string, value: undefined, prev: string|undefined, isSVG: boolean, skipRef: boolean): undefined
|
117
|
+
function assignProp(
|
118
|
+
node: Element,
|
119
|
+
prop: 'style' | 'classList' | 'ref' | string,
|
120
|
+
value: StyleProps | ClassListProps | (()=>string) | string | undefined,
|
121
|
+
prev: StyleProps | ClassListProps | (()=>string) | string | undefined,
|
122
|
+
isSVG: false | boolean,
|
123
|
+
skipRef: boolean
|
124
|
+
) {
|
83
125
|
let isCE, isProp, isChildProp, propAlias, forceProp;
|
84
|
-
if (prop ===
|
85
|
-
if (prop ===
|
126
|
+
if (prop === 'style') return style(node, value, prev);
|
127
|
+
if (prop === 'classList') return classList(node, value, prev);
|
86
128
|
if (value === prev) return prev;
|
87
|
-
if (prop ===
|
129
|
+
if (prop === 'ref') {
|
88
130
|
if (!skipRef) value(node);
|
89
|
-
} else if (prop.slice(0, 3) ===
|
131
|
+
} else if (prop.slice(0, 3) === 'on:') {
|
90
132
|
const e = prop.slice(3);
|
91
133
|
prev && node.removeEventListener(e, prev);
|
92
134
|
value && node.addEventListener(e, value);
|
93
|
-
} else if (prop.slice(0, 10) ===
|
135
|
+
} else if (prop.slice(0, 10) === 'oncapture:') {
|
94
136
|
const e = prop.slice(10);
|
95
137
|
prev && node.removeEventListener(e, prev, true);
|
96
138
|
value && node.addEventListener(e, value, true);
|
97
|
-
} else if (prop.slice(0, 2) ===
|
139
|
+
} else if (prop.slice(0, 2) === 'on') {
|
98
140
|
const name = prop.slice(2).toLowerCase();
|
99
141
|
const delegate = DelegatedEvents.has(name);
|
100
142
|
if (!delegate && prev) {
|
@@ -105,13 +147,13 @@ export function runtime(window:Window):Runtime {
|
|
105
147
|
addEventListener(node, name, value, delegate);
|
106
148
|
delegate && delegateEvents([name],document);
|
107
149
|
}
|
108
|
-
} else if (prop.slice(0, 5) ===
|
150
|
+
} else if (prop.slice(0, 5) === 'attr:') {
|
109
151
|
setAttribute(node, prop.slice(5), value);
|
110
152
|
} else if (
|
111
|
-
(forceProp = prop.slice(0, 5) ===
|
153
|
+
(forceProp = prop.slice(0, 5) === 'prop:') ||
|
112
154
|
(isChildProp = ChildProperties.has(prop)) ||
|
113
155
|
(!isSVG && ((propAlias = getPropAlias(prop, node.tagName)) || (isProp = Properties.has(prop)))) ||
|
114
|
-
(isCE = node.nodeName.includes(
|
156
|
+
(isCE = node.nodeName.includes('-'))
|
115
157
|
) {
|
116
158
|
if (forceProp) {
|
117
159
|
prop = prop.slice(5);
|
@@ -121,15 +163,21 @@ export function runtime(window:Window):Runtime {
|
|
121
163
|
else if (isCE && !isProp && !isChildProp) node[toPropertyName(prop)] = value;
|
122
164
|
else node[propAlias || prop] = value;
|
123
165
|
} else {
|
124
|
-
const ns = isSVG && prop.indexOf(
|
125
|
-
if (ns) setAttributeNS(node, ns, prop, value)
|
126
|
-
else setAttribute(node, Aliases[prop] || prop, value)
|
166
|
+
const ns = isSVG && prop.indexOf(':') > -1 && SVGNamespace[prop.split(':')[0]]
|
167
|
+
if (ns) setAttributeNS(node, ns, prop, value)
|
168
|
+
else setAttribute(node, Aliases[prop] || prop, value)
|
127
169
|
}
|
128
170
|
return value;
|
129
171
|
}
|
130
172
|
|
131
|
-
function insertExpression(
|
132
|
-
|
173
|
+
function insertExpression(
|
174
|
+
parent: Element,
|
175
|
+
value: RxValue,
|
176
|
+
current?: RxValue|Value[],
|
177
|
+
marker?: Node,
|
178
|
+
unwrapArray?: boolean
|
179
|
+
): Value|{():Value} {
|
180
|
+
while (typeof current === 'function') current = current();
|
133
181
|
if (value === current) return current;
|
134
182
|
const t = typeof value,
|
135
183
|
multi = marker !== undefined;
|
@@ -147,21 +195,21 @@ export function runtime(window:Window):Runtime {
|
|
147
195
|
} else node = document.createTextNode(value);
|
148
196
|
current = cleanChildren(parent, current, marker, node);
|
149
197
|
} else {
|
150
|
-
if (current !== "" && typeof current ===
|
151
|
-
current = parent.firstChild.data = value;
|
198
|
+
if (current !== "" && typeof current === 'string') {
|
199
|
+
current = (parent.firstChild as Text).data = value;
|
152
200
|
} else current = parent.textContent = value;
|
153
201
|
}
|
154
|
-
} else if (value == null || t ===
|
202
|
+
} else if (value == null || t === 'boolean') {
|
155
203
|
current = cleanChildren(parent, current, marker);
|
156
|
-
} else if (t ===
|
204
|
+
} else if (t === 'function') {
|
157
205
|
effect(() => {
|
158
206
|
let v = value();
|
159
|
-
while (typeof v ===
|
207
|
+
while (typeof v === 'function') v = v();
|
160
208
|
current = insertExpression(parent, v, current, marker);
|
161
209
|
});
|
162
210
|
return () => current;
|
163
211
|
} else if (isArray(value)) {
|
164
|
-
const array:
|
212
|
+
const array:Node[] = [];
|
165
213
|
const currentArray = current && isArray(current);
|
166
214
|
if (normalizeIncomingArray(array, value, current, unwrapArray)) {
|
167
215
|
effect(() => (current = insertExpression(parent, array, current, marker, true)));
|
@@ -191,20 +239,21 @@ export function runtime(window:Window):Runtime {
|
|
191
239
|
return current;
|
192
240
|
}
|
193
241
|
|
194
|
-
function normalizeIncomingArray(normalized:
|
242
|
+
function normalizeIncomingArray(normalized:Node[], array:Node[], current:Node[], unwrap?:boolean): boolean {
|
195
243
|
let dynamic = false;
|
196
244
|
for (let i = 0, len = array.length; i < len; i++) {
|
197
245
|
let item = array[i]
|
198
246
|
const prev = current && current[normalized.length];
|
199
|
-
if (item == null || item === true || item === false) {
|
200
|
-
|
201
|
-
} else
|
247
|
+
// if (item == null || item === true || item === false) {
|
248
|
+
// // matches null, undefined, true or false skip
|
249
|
+
// } else
|
250
|
+
if (typeof item === 'object' && item.nodeType) {
|
202
251
|
normalized.push(item);
|
203
252
|
} else if (isArray(item)) {
|
204
253
|
dynamic = normalizeIncomingArray(normalized, item, prev) || dynamic;
|
205
254
|
} else if (item.call) {
|
206
255
|
if (unwrap) {
|
207
|
-
while (typeof item ===
|
256
|
+
while (typeof item === 'function') item = item();
|
208
257
|
dynamic = normalizeIncomingArray(
|
209
258
|
normalized,
|
210
259
|
isArray(item) ? item : [item],
|
@@ -223,8 +272,13 @@ export function runtime(window:Window):Runtime {
|
|
223
272
|
return dynamic;
|
224
273
|
}
|
225
274
|
|
226
|
-
function cleanChildren(
|
227
|
-
|
275
|
+
function cleanChildren(
|
276
|
+
parent: Element,
|
277
|
+
current?: Node[],
|
278
|
+
marker?: Node|null,
|
279
|
+
replacement?: boolean
|
280
|
+
): string | Node[] {
|
281
|
+
if (marker === undefined) return (parent.textContent = '');
|
228
282
|
const node = replacement || document.createTextNode('');
|
229
283
|
if (current.length) {
|
230
284
|
let inserted = false;
|
@@ -242,18 +296,18 @@ export function runtime(window:Window):Runtime {
|
|
242
296
|
}
|
243
297
|
|
244
298
|
function clearDelegatedEvents() {
|
245
|
-
if (
|
246
|
-
for (const name of
|
247
|
-
delete
|
299
|
+
if (globalThis[$$EVENTS]) {
|
300
|
+
for (const name of globalThis[$$EVENTS].keys()) document.removeEventListener(name, eventHandler);
|
301
|
+
delete globalThis[$$EVENTS];
|
248
302
|
}
|
249
303
|
}
|
250
304
|
|
251
|
-
return {render,insert,spread,assign,element,text,isChild,clearDelegatedEvents}
|
305
|
+
return {render,component,insert,spread,assign,element,text,isChild,clearDelegatedEvents}
|
252
306
|
}
|
253
307
|
|
254
308
|
const $$EVENTS = "_$DX_DELEGATE"
|
255
309
|
|
256
|
-
function delegateEvents(eventNames:string[], document:
|
310
|
+
function delegateEvents(eventNames:string[], document:Document) {
|
257
311
|
const e = document[$$EVENTS] || (document[$$EVENTS] = new Set());
|
258
312
|
for (let i = 0, l = eventNames.length; i < l; i++) {
|
259
313
|
const name = eventNames[i];
|
@@ -264,13 +318,13 @@ function delegateEvents(eventNames:string[], document:any) {
|
|
264
318
|
}
|
265
319
|
}
|
266
320
|
|
267
|
-
function eventHandler(e:
|
321
|
+
function eventHandler(e: Event) {
|
268
322
|
const key = `$$${e.type}`
|
269
323
|
let node = (e.composedPath && e.composedPath()[0]) || e.target
|
270
324
|
// reverse Shadow DOM retargetting
|
271
|
-
if (e.target !== node) Object.defineProperty(e,
|
325
|
+
if (e.target !== node) Object.defineProperty(e, 'target', {configurable: true, value: node})
|
272
326
|
// simulate currentTarget
|
273
|
-
Object.defineProperty(e,
|
327
|
+
Object.defineProperty(e, 'currentTarget', {configurable: true, get() {return node || document}})
|
274
328
|
while (node) {
|
275
329
|
const handler = node[key];
|
276
330
|
if (handler && !node.disabled) {
|
@@ -282,7 +336,7 @@ function eventHandler(e:any) {
|
|
282
336
|
}
|
283
337
|
}
|
284
338
|
|
285
|
-
function setAttribute(node:
|
339
|
+
function setAttribute(node: Element, name: string, value?: string): undefined {
|
286
340
|
value===undefined || value===null ? node.removeAttribute(name) : node.setAttribute(name, value)
|
287
341
|
}
|
288
342
|
|
@@ -290,7 +344,7 @@ function setAttributeNS(node:Node, ns:string, name:string, value?:string):any {
|
|
290
344
|
value ? node.setAttributeNS(ns, name, value) : node.removeAttributeNS(ns, name)
|
291
345
|
}
|
292
346
|
|
293
|
-
function addEventListener(node:
|
347
|
+
function addEventListener(node: Element, name: string, handler:((e:Event)=>void), delegate:boolean): void {
|
294
348
|
if (delegate) {
|
295
349
|
if (isArray(handler)) {
|
296
350
|
node[`$$${name}`] = handler[0];
|
@@ -298,35 +352,43 @@ function addEventListener(node:Node, name:any, handler:any, delegate:any):any {
|
|
298
352
|
} else node[`$$${name}`] = handler;
|
299
353
|
} else if (isArray(handler)) {
|
300
354
|
const handlerFn = handler[0];
|
301
|
-
node.addEventListener(name, (handler[0] = (e:
|
355
|
+
node.addEventListener(name, (handler[0] = (e:Event) => handlerFn.call(node, handler[1], e)));
|
302
356
|
} else node.addEventListener(name, handler);
|
303
357
|
}
|
304
358
|
|
305
|
-
function classList(
|
359
|
+
function classList(
|
360
|
+
node: Element,
|
361
|
+
value: ClassListProps,
|
362
|
+
prev: ClassListProps = {}
|
363
|
+
): ClassListProps {
|
306
364
|
const classKeys = Object.keys(value || {}),
|
307
365
|
prevKeys = Object.keys(prev);
|
308
366
|
let i, len;
|
309
367
|
for (i = 0, len = prevKeys.length; i < len; i++) {
|
310
368
|
const key = prevKeys[i];
|
311
|
-
if (!key || key ===
|
369
|
+
if (!key || key === 'undefined' || value[key]) continue;
|
312
370
|
toggleClassKey(node, key, false);
|
313
371
|
delete prev[key];
|
314
372
|
}
|
315
373
|
for (i = 0, len = classKeys.length; i < len; i++) {
|
316
374
|
const key = classKeys[i],
|
317
375
|
classValue = !!value[key];
|
318
|
-
if (!key || key ===
|
376
|
+
if (!key || key === 'undefined' || prev[key] === classValue || !classValue) continue;
|
319
377
|
toggleClassKey(node, key, true);
|
320
378
|
prev[key] = classValue;
|
321
379
|
}
|
322
380
|
return prev;
|
323
381
|
}
|
324
382
|
|
325
|
-
function style(
|
326
|
-
|
383
|
+
function style(
|
384
|
+
node: Element,
|
385
|
+
value: StyleProps,
|
386
|
+
prev: StyleProps
|
387
|
+
): StyleProps {
|
388
|
+
if (!value) return prev ? setAttribute(node, 'style', undefined) : value;
|
327
389
|
const nodeStyle = node.style;
|
328
|
-
if (typeof value ===
|
329
|
-
if (typeof prev ===
|
390
|
+
if (typeof value === 'string') return (nodeStyle.cssText = value);
|
391
|
+
if (typeof prev === 'string') nodeStyle.cssText = prev = undefined
|
330
392
|
if (!prev) prev = {}
|
331
393
|
if (!value) value = {}
|
332
394
|
let v, s;
|
@@ -348,7 +410,7 @@ function toPropertyName(name:string):string {
|
|
348
410
|
return name.toLowerCase().replace(/-([a-z])/g, (_:unknown, w:string) => w.toUpperCase());
|
349
411
|
}
|
350
412
|
|
351
|
-
function toggleClassKey(node:
|
413
|
+
function toggleClassKey(node: Element, key:string, value:boolean) {
|
352
414
|
const classNames = key.trim().split(/\s+/)
|
353
415
|
for (let i = 0, nameLen = classNames.length; i < nameLen; i++)
|
354
416
|
node.classList.toggle(classNames[i], value)
|
@@ -360,7 +422,7 @@ function appendNodes(parent:Node, array:Node[], marker:null|Node = null) {
|
|
360
422
|
}
|
361
423
|
|
362
424
|
// Slightly modified version of: https://github.com/WebReflection/udomdiff/blob/master/index.js
|
363
|
-
function reconcileArrays(parentNode:Node, a:
|
425
|
+
function reconcileArrays(parentNode:Node, a:Element[], b:Element[]) {
|
364
426
|
const bLength = b.length
|
365
427
|
let aEnd = a.length,
|
366
428
|
bEnd = bLength,
|
package/test/hyperscript.js
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
import {runtime} from '../src/runtime.ts'
|
2
2
|
import {hyperscript} from '../src/hyperscript.ts'
|
3
3
|
import {signal,root} from '../src/reactive.ts'
|
4
|
-
import {
|
4
|
+
import { Window } from 'happy-dom'
|
5
5
|
import {assertEquals} from '@std/assert'
|
6
6
|
|
7
|
-
const
|
8
|
-
const
|
7
|
+
const window = new Window
|
8
|
+
const document = window.document
|
9
|
+
globalThis = window
|
9
10
|
const r = runtime(window), h = hyperscript(r)
|
10
11
|
|
11
12
|
function testing(name, props, f=props) {
|
@@ -13,7 +14,7 @@ function testing(name, props, f=props) {
|
|
13
14
|
let disposer
|
14
15
|
return root(dispose => {
|
15
16
|
disposer = () => {
|
16
|
-
document.body.textContent = ''
|
17
|
+
window.document.body.textContent = ''
|
17
18
|
r.clearDelegatedEvents()
|
18
19
|
dispose()
|
19
20
|
}
|
@@ -25,7 +26,7 @@ function testing(name, props, f=props) {
|
|
25
26
|
|
26
27
|
function assertHTML(t, e, msg) { assertEquals(t().outerHTML, e, msg) }
|
27
28
|
|
28
|
-
testing('h with basic element',
|
29
|
+
testing('h with basic element', async test => {
|
29
30
|
await test('empty tag', () => assertHTML(h(''), '<div></div>'))
|
30
31
|
await test('tag with id', () => assertHTML(h('#a'), '<div id="a"></div>'))
|
31
32
|
await test('tag with class', () => assertHTML(h('.a'), '<div class="a"></div>'))
|
@@ -63,7 +64,7 @@ function assertText(t, e, msg) { assertEquals(t(), e, msg) }
|
|
63
64
|
// await test('signal fragment', () => assertText(h([()=>1]), '1'))
|
64
65
|
// })
|
65
66
|
|
66
|
-
testing('h with reactive content',
|
67
|
+
testing('h with reactive content', async test => {
|
67
68
|
await test('higher-order component', () => {
|
68
69
|
const Hi = p => h('b',['Hi ',p.name]),
|
69
70
|
name = signal('An'),
|
package/test/reactive.js
CHANGED
@@ -82,7 +82,7 @@ describe('memo',{skip:true},() => {
|
|
82
82
|
describe('memo with initial value',() => {})
|
83
83
|
})
|
84
84
|
|
85
|
-
describe('wrap',()=>{
|
85
|
+
describe('wrap', ()=>{
|
86
86
|
describe('wrap singal of array', () => {
|
87
87
|
const all = signal(['a','b']), first = wrap(all,0)
|
88
88
|
assertEquals(first(),'a')
|
@@ -95,6 +95,7 @@ describe('wrap',()=>{
|
|
95
95
|
assertEquals(name(),'a')
|
96
96
|
assertEquals(name('A'),'A')
|
97
97
|
assertEquals(name(),'A')
|
98
|
+
assertEquals(all(),{name:'A'})
|
98
99
|
})
|
99
100
|
|
100
101
|
describe('wrap singal of array of objects', () => {
|
@@ -104,9 +105,10 @@ describe('wrap',()=>{
|
|
104
105
|
assertEquals(name(),'b')
|
105
106
|
assertEquals(name('A'),'A')
|
106
107
|
assertEquals(name(),'A')
|
108
|
+
assertEquals(all(),[{name:'A'}])
|
107
109
|
})
|
108
110
|
|
109
|
-
describe('wrap singal of object
|
111
|
+
describe('wrap singal of object with arrays', () => {
|
110
112
|
const all = signal({ids:[0,1,2]}), ids = wrap(all,'id'), last = wrap(ids,-1)
|
111
113
|
assertEquals(ids([1,2,3]),[1,2,3])
|
112
114
|
assertEquals(ids(),[1,2,3])
|
@@ -114,4 +116,22 @@ describe('wrap',()=>{
|
|
114
116
|
assertEquals(last(4),4)
|
115
117
|
assertEquals(last(),4)
|
116
118
|
})
|
119
|
+
|
120
|
+
describe('wrap singal of array of objects with array', () => {
|
121
|
+
const all = signal([{ids:[0,1,2]}]), first = wrap(all,0), ids = wrap(first,'ids'), last = wrap(ids,-1)
|
122
|
+
assertEquals(ids([1,2,3]),[1,2,3])
|
123
|
+
assertEquals(last(4),4)
|
124
|
+
assertEquals(all(),[{ids:[1,2,4]}])
|
125
|
+
})
|
126
|
+
|
127
|
+
describe('wrap singal of object with array of objects', () => {
|
128
|
+
const obj = signal({todos:[{done:false,name:'a'}, {done:false,name:'b'}]}), todos = wrap(obj, 'todos'), todo = wrap(todos, 0),
|
129
|
+
name = wrap(todo, 'name'), done = wrap(todo,'done')
|
130
|
+
assertEquals(done(true),true)
|
131
|
+
console.log('OBJ',obj())
|
132
|
+
effect(()=>{
|
133
|
+
name();done()
|
134
|
+
})
|
135
|
+
assertEquals(obj(),{todos:[{done:true,name:'a'},{done:false,name:'b'}]})
|
136
|
+
})
|
117
137
|
})
|
package/test/types.ts
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
import { runtime } from '../src/runtime.ts'
|
2
|
+
import { hyperscript, type Mountable } from '../src/hyperscript.ts'
|
3
|
+
import { signal, root } from '../src/reactive.ts'
|
4
|
+
import { List } from '../src/controlflow.ts'
|
5
|
+
import { Window } from 'happy-dom'
|
6
|
+
|
7
|
+
const window = new Window
|
8
|
+
const r = runtime(window as any), h = hyperscript(r)
|
9
|
+
|
10
|
+
h('hr')
|
11
|
+
h('div', ['hello'])
|
12
|
+
h('', {class:''})
|
13
|
+
|
14
|
+
function CompReturningString() { return 'hi' }
|
15
|
+
function CompReturningNumber() { return 0 }
|
16
|
+
function CompReturningEmptyFragment() { return [] }
|
17
|
+
function CompReturningFragment() { return [h(CompReturningString), h(CompReturningNumber), '', 1] }
|
18
|
+
|
19
|
+
h(CompReturningString)
|
20
|
+
h(CompReturningNumber)
|
21
|
+
h(CompReturningEmptyFragment)
|
22
|
+
h(CompReturningFragment)
|
23
|
+
|
24
|
+
function CompWithProps(props: {a: string}) { return 'hi' }
|
25
|
+
|
26
|
+
h(CompWithProps, {a:''})
|
27
|
+
|
28
|
+
function CompWithChildren(props: {children:Mountable}) { return 'hi' }
|
29
|
+
|
30
|
+
h(CompWithChildren, [])
|
31
|
+
h(CompWithChildren, {}, [])
|
32
|
+
h(CompWithChildren, {children:[]})
|
33
|
+
|
34
|
+
|
35
|
+
function CompWithOptionalChildren(props: {children?:string[]}) { return 'hi' }
|
36
|
+
|
37
|
+
h(CompWithOptionalChildren)
|
38
|
+
h(CompWithOptionalChildren, [])
|
39
|
+
h(CompWithOptionalChildren, {})
|
40
|
+
h(CompWithOptionalChildren, {children:[]})
|
41
|
+
|
42
|
+
const booleans = signal([true, true, false])
|
43
|
+
|
44
|
+
// h(List, {each:()=>booleans}, (b, _i) => b)
|
package/src/components.js
DELETED
package/src/ui/accordion.ts
DELETED
package/src/ui/button.ts
DELETED
package/src/ui/canvas.ts
DELETED
package/src/ui/date.ts
DELETED
package/src/ui/dialog.ts
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
import { effect } from '../reactive.ts'
|
2
|
-
import { h } from './h.ts'
|
3
|
-
|
4
|
-
export function Dialog(props) {
|
5
|
-
return h('dialog', {
|
6
|
-
ref(r) {
|
7
|
-
r.addEventListener('cancel', ()=>props.show(false))
|
8
|
-
const show = props.modal ? ()=>r.showModal() : ()=>r.show()
|
9
|
-
effect(() => props.show() ? show() : r.close())
|
10
|
-
},
|
11
|
-
}, props.children)
|
12
|
-
}
|
package/src/ui/filter.ts
DELETED