@wrnrlr/prelude 0.1.9 → 0.2.1
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} +10 -9
- package/example/index.html +43 -0
- package/package.json +6 -2
- package/src/constants.ts +110 -52
- package/src/controlflow.ts +140 -92
- package/src/hyperscript.ts +81 -106
- package/src/mod.ts +11 -19
- package/src/reactive.ts +29 -17
- package/src/runtime.ts +126 -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/controlflow.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
// @ts-nocheck:
|
2
2
|
import type { Child } from './hyperscript.ts'
|
3
|
-
import {signal,untrack,batch,memo,root,type Signal} from './reactive.ts'
|
3
|
+
import {signal,untrack,batch,memo,root,onCleanup,type Signal, type Setter, type Mountable} from './reactive.ts'
|
4
4
|
|
5
5
|
export type ShowProps<T> = {
|
6
6
|
when: T,
|
@@ -12,7 +12,7 @@ export type ShowProps<T> = {
|
|
12
12
|
Show children if `when` prop is true, otherwise show `fallback`.
|
13
13
|
@group Components
|
14
14
|
*/
|
15
|
-
export function Show<T>(props:
|
15
|
+
export function Show<T>(props:ShowProps) {
|
16
16
|
const condition = memo(()=>props.when)
|
17
17
|
return memo(()=>{
|
18
18
|
const c = condition()
|
@@ -24,152 +24,200 @@ export function Show<T>(props:any) {
|
|
24
24
|
})
|
25
25
|
}
|
26
26
|
|
27
|
-
type
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
valueSetter:any,
|
32
|
-
disposer: any
|
33
|
-
}
|
34
|
-
|
35
|
-
export type ListProps<T> = {
|
36
|
-
when: T,
|
37
|
-
each: any,
|
38
|
-
children: Child | ((a:()=>T)=>void),
|
39
|
-
fallback: unknown
|
27
|
+
export type ListProps<T, U extends Mountable, F = Getter | Signal> = {
|
28
|
+
each: F<T[]>,
|
29
|
+
children: (item: F<T>, index: F<number>) => U,
|
30
|
+
fallback?: Mountable
|
40
31
|
}
|
41
32
|
|
42
33
|
/**
|
43
34
|
List
|
44
35
|
@group Components
|
45
36
|
*/
|
46
|
-
export function List<T>(
|
47
|
-
|
48
|
-
|
49
|
-
const
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
37
|
+
export function List<T>(
|
38
|
+
props: ListProps<T>
|
39
|
+
) {
|
40
|
+
const fallback = "fallback" in props && { fallback: () => props.fallback };
|
41
|
+
return memo(listArray<T>(props.each, props.children, fallback || undefined))
|
42
|
+
}
|
43
|
+
|
44
|
+
type ItemHolder<T> = {
|
45
|
+
index: number,
|
46
|
+
indexSetter?: Getter<number>,
|
47
|
+
value: T,
|
48
|
+
valueSetter?: Setter<T>,
|
49
|
+
disposer: ()=>void
|
50
|
+
}
|
51
|
+
|
52
|
+
function listArray<T, U extends Mountable>(
|
53
|
+
list: Getter<T[]>,
|
54
|
+
mapFn: (v: Getter<T>, i: Getter<number>) => U,
|
55
|
+
options: { fallback?: Mountable }
|
56
|
+
): () => U[]
|
57
|
+
function listArray<T, U extends Mountable>(
|
58
|
+
list: Signal<T[]>,
|
59
|
+
mapFn: (v: Signal<T>, i: Getter<number>) => U,
|
60
|
+
options: { fallback?: Mountable }
|
61
|
+
): () => U[]
|
62
|
+
function listArray<T, U extends Mountable>(
|
63
|
+
list: Getter<T[]> | Signal<T[]>,
|
64
|
+
mapFn: (v: Signal<T>, i: Getter<number>) => U,
|
65
|
+
options: { fallback?: Mountable } = {}
|
66
|
+
): () => U[] {
|
67
|
+
const items: ListItem<T>[] = [];
|
68
|
+
let mapped: U[] = [],
|
69
|
+
unusedItems: number,
|
70
|
+
i: number,
|
71
|
+
j: number,
|
72
|
+
item: ListItem<T>,
|
73
|
+
oldValue: T,
|
56
74
|
oldIndex: number,
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
}
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
return cb(
|
70
|
-
(...a:any[]) => a.length ?
|
71
|
-
untrack(()=>list((list:any)=>list.toSpliced(I,1,a[0])))
|
72
|
-
: Vs(),
|
73
|
-
()=>Is())
|
74
|
-
}
|
75
|
-
function mapperWithoutIndexes(disposer:any) {
|
76
|
-
const V = newValue, I = i, Vs = signal(V)
|
77
|
-
items.push({value: V, index: i!, disposer, valueSetter: Vs})
|
78
|
-
return cb((...a:unknown[]) => a.length ?
|
79
|
-
untrack(()=>list((list:any)=>list.toSpliced(I,1,a[0])))
|
80
|
-
: Vs())
|
81
|
-
}
|
82
|
-
const mapper = indexes ? mapperWithIndexes : mapperWithoutIndexes
|
83
|
-
return memo(() => {
|
84
|
-
const newItems = list.call ? list() : list
|
85
|
-
// (newItems)[$TRACK]; // top level tracking
|
75
|
+
newValue: T,
|
76
|
+
fallback: U[] | undefined,
|
77
|
+
fallbackDisposer: undefined | (() => void)
|
78
|
+
|
79
|
+
onCleanup(() => {
|
80
|
+
fallbackDisposer?.()
|
81
|
+
fallbackDisposer = undefined
|
82
|
+
disposeList(items)
|
83
|
+
})
|
84
|
+
|
85
|
+
return () => {
|
86
|
+
const newItems = typeof list==='function' ? list() || [] : list;
|
86
87
|
return untrack(() => {
|
87
|
-
|
88
|
-
|
88
|
+
if (newItems.length > 0 && fallbackDisposer) {
|
89
|
+
fallbackDisposer();
|
90
|
+
fallbackDisposer = undefined;
|
91
|
+
fallback = undefined;
|
92
|
+
}
|
93
|
+
|
94
|
+
const temp: U[] = new Array(newItems.length); // new mapped array
|
95
|
+
unusedItems = items.length;
|
89
96
|
|
90
97
|
// 1) no change when values & indexes match
|
91
|
-
for (
|
92
|
-
item = items[j]
|
98
|
+
for (j = unusedItems - 1; j >= 0; --j) {
|
99
|
+
item = items[j]!;
|
93
100
|
oldIndex = item.index
|
94
101
|
if (oldIndex < newItems.length && newItems[oldIndex] === item.value) {
|
95
|
-
temp[oldIndex] = mapped[oldIndex]
|
102
|
+
temp[oldIndex] = mapped[oldIndex]!
|
96
103
|
if (--unusedItems !== j) {
|
97
|
-
items[j] = items[unusedItems]
|
104
|
+
items[j] = items[unusedItems]!
|
98
105
|
items[unusedItems] = item
|
99
106
|
}
|
100
107
|
}
|
101
108
|
}
|
102
109
|
|
103
110
|
// #2 prepare values matcher
|
104
|
-
const matcher = new Map()
|
111
|
+
const matcher = new Map<T, number[]>()
|
105
112
|
const matchedItems = new Uint8Array(unusedItems)
|
106
|
-
for (
|
107
|
-
oldValue = items[j]
|
113
|
+
for (j = unusedItems - 1; j >= 0; --j) {
|
114
|
+
oldValue = items[j]!.value
|
108
115
|
matcher.get(oldValue)?.push(j) ?? matcher.set(oldValue, [j])
|
109
116
|
}
|
110
117
|
|
111
118
|
// 2) change indexes when values match
|
112
119
|
for (i = 0; i < newItems.length; ++i) {
|
113
120
|
if (i in temp) continue
|
114
|
-
newValue = newItems[i]
|
115
|
-
|
121
|
+
newValue = newItems[i]!
|
122
|
+
j = matcher.get(newValue)?.pop() ?? -1;
|
116
123
|
if (j >= 0) {
|
117
|
-
item = items[j
|
118
|
-
oldIndex = item
|
119
|
-
temp[i] = mapped[oldIndex]
|
120
|
-
item
|
121
|
-
item
|
122
|
-
matchedItems[j
|
124
|
+
item = items[j]!
|
125
|
+
oldIndex = item.index
|
126
|
+
temp[i] = mapped[oldIndex]!
|
127
|
+
item.index = i
|
128
|
+
item.indexSetter?.(i)
|
129
|
+
matchedItems[j] = 1
|
123
130
|
}
|
124
131
|
}
|
125
132
|
|
126
|
-
//
|
127
|
-
for (
|
133
|
+
// #2 reduce unusedItems for matched items
|
134
|
+
for (j = matchedItems.length - 1; j >= 0; --j) {
|
128
135
|
if (matchedItems[j] && --unusedItems !== j) {
|
129
|
-
item = items[j]
|
130
|
-
items[j] = items[unusedItems]
|
136
|
+
item = items[j]!
|
137
|
+
items[j] = items[unusedItems]!
|
131
138
|
items[unusedItems] = item
|
132
139
|
}
|
133
140
|
}
|
134
141
|
|
135
|
-
//
|
136
|
-
for (
|
137
|
-
item = items[j]
|
138
|
-
oldIndex = item
|
142
|
+
// 3) change values when indexes match
|
143
|
+
for (j = unusedItems - 1; j >= 0; --j) {
|
144
|
+
item = items[j]!
|
145
|
+
oldIndex = item.index;
|
139
146
|
if (!(oldIndex in temp) && oldIndex < newItems.length) {
|
140
|
-
temp[oldIndex] = mapped[oldIndex]
|
141
|
-
newValue = newItems[oldIndex]
|
147
|
+
temp[oldIndex] = mapped[oldIndex]!
|
148
|
+
newValue = newItems[oldIndex]!
|
142
149
|
item.value = newValue
|
143
|
-
item.valueSetter?.(
|
150
|
+
item.valueSetter?.(newValue)
|
144
151
|
if (--unusedItems !== j) {
|
145
|
-
items[j] = items[unusedItems]
|
152
|
+
items[j] = items[unusedItems]!
|
146
153
|
items[unusedItems] = item
|
147
154
|
}
|
148
155
|
}
|
149
156
|
}
|
150
157
|
|
151
|
-
//
|
158
|
+
// 4) change value & index when none matched
|
159
|
+
// 5) create new if no unused items left
|
152
160
|
for (i = 0; i < newItems.length; ++i) {
|
153
|
-
if (i in temp) continue
|
154
|
-
newValue = newItems[i]
|
161
|
+
if (i in temp) continue;
|
162
|
+
newValue = newItems[i]!;
|
155
163
|
if (unusedItems > 0) {
|
156
|
-
item = items[--unusedItems]
|
157
|
-
temp[i] = mapped[item.index]
|
164
|
+
item = items[--unusedItems]!;
|
165
|
+
temp[i] = mapped[item.index]!;
|
158
166
|
batch(changeBoth);
|
159
167
|
} else {
|
160
|
-
temp[i] = root(mapper)
|
168
|
+
temp[i] = root(mapper);
|
161
169
|
}
|
162
170
|
}
|
163
171
|
|
164
172
|
// 6) delete any old unused items left
|
165
|
-
disposeList(items.splice(0, unusedItems))
|
173
|
+
disposeList(items.splice(0, unusedItems));
|
166
174
|
|
175
|
+
if (newItems.length === 0 && options.fallback) {
|
176
|
+
if (!fallbackDisposer) {
|
177
|
+
fallback = [
|
178
|
+
root(d => {
|
179
|
+
fallbackDisposer = d;
|
180
|
+
return options.fallback!();
|
181
|
+
}),
|
182
|
+
];
|
183
|
+
}
|
184
|
+
return fallback!;
|
185
|
+
}
|
167
186
|
return (mapped = temp);
|
168
187
|
})
|
169
|
-
}
|
188
|
+
}
|
189
|
+
// const indexes = cb.length > 1 ? [] : null;
|
190
|
+
function newValueGetter(_:unknown) { return newValue }
|
191
|
+
function changeBoth() {
|
192
|
+
item!.index = i!
|
193
|
+
item!.indexSetter?.(i)
|
194
|
+
item!.value = newValue!
|
195
|
+
item!.valueSetter?.(newValueGetter)
|
196
|
+
}
|
197
|
+
function mapper(disposer: ()=>void) {
|
198
|
+
const I = i
|
199
|
+
const t = {value: newValue, index: I, disposer}
|
200
|
+
items.push(t)
|
201
|
+
const sI = () => { t.indexSetter = I; return signal(I) }
|
202
|
+
let sV = (...a) => {
|
203
|
+
const k = I
|
204
|
+
sV = (...a) => {
|
205
|
+
if (a.length===0) {
|
206
|
+
const bk = list()[k]
|
207
|
+
return bk
|
208
|
+
} else {
|
209
|
+
const b = untrack(list)
|
210
|
+
return list(b.toSpliced(k, 1, a[0])).at(k)
|
211
|
+
}
|
212
|
+
}
|
213
|
+
t.valueSetter = sV
|
214
|
+
return sV(...a)
|
215
|
+
}
|
216
|
+
return mapFn(sV, () => sI())
|
217
|
+
}
|
170
218
|
}
|
171
219
|
|
172
|
-
function disposeList(list:
|
220
|
+
function disposeList(list:{disposer?:()=>unknown}[]) {
|
173
221
|
for (let i = 0; i < list.length; i++) {
|
174
222
|
list[i]?.disposer()
|
175
223
|
}
|
package/src/hyperscript.ts
CHANGED
@@ -1,146 +1,121 @@
|
|
1
|
-
|
2
|
-
import {
|
3
|
-
import type {Properties,BooleanAttributes,DelegatedEvents,DOMElements, Mountable} from './constants.ts'
|
4
|
-
import type {Runtime,$RUNTIME} from './runtime.ts'
|
1
|
+
import type {DOMElements} from './constants.ts'
|
2
|
+
import type {Runtime} from './runtime.ts'
|
5
3
|
|
6
4
|
const ELEMENT: unique symbol = Symbol(), {isArray} = Array
|
7
5
|
|
8
|
-
export type
|
9
|
-
export type
|
10
|
-
export type
|
11
|
-
export type
|
12
|
-
|
13
|
-
export type ElementProps = BooleanProps & HandlerProps & ChildProps & {class: string}
|
14
|
-
export type ComponentProps = { children?:Child }
|
15
|
-
|
16
|
-
/**
|
17
|
-
* @group Hyperscript
|
18
|
-
*/
|
19
|
-
export type Props = {}
|
6
|
+
export type Mountable = View | HTMLElement | string | number | bigint | symbol | boolean | Date | Mountable[];
|
7
|
+
export type Component<T> = ((props:T) => Mountable) | ((props:T) => Mountable[])
|
8
|
+
export type Tag = typeof DOMElements extends Set<infer K> ? K : never;
|
9
|
+
export type Child = { ():Child } | Element | Child[] | string | number | symbol | bigint | boolean | Date | Record<string,unknown> | {():Child, [ELEMENT]:boolean}
|
10
|
+
export type View = {():void, [ELEMENT]?:boolean}
|
20
11
|
|
21
|
-
type
|
12
|
+
// export type PropsKeys = typeof Properties extends Set<infer K> ? K : never;
|
13
|
+
// export type BooleanProps = typeof BooleanAttributes ext ends Set<infer K> ? K : never;
|
14
|
+
// export type HandlerProps = typeof DelegatedEvents extends Set<infer K> ? K : never;
|
15
|
+
// export type ChildProps = {children?:any[]}
|
16
|
+
// export type ElementProps = BooleanProps & HandlerProps & ChildProps & {class: string}
|
17
|
+
// export type ComponentProps = { children?:Child }
|
18
|
+
// export type Props = Record<string, any>
|
19
|
+
// type AllProps = ElementProps | ComponentProps
|
20
|
+
// type EmptyProps = Record<string,never>
|
21
|
+
// const Fragment:Component<Props> = <T extends Props>(props:T):Mountable => (props as any).children
|
22
22
|
|
23
|
-
type
|
23
|
+
export type TagParser = <T extends string>(s:T) => {name:string,id?:string,classes:string[],namespace?:string}
|
24
24
|
|
25
|
-
/**
|
26
|
-
@group Hyperscript
|
27
|
-
*/
|
28
25
|
export type HyperScript = {
|
29
|
-
|
30
|
-
|
31
|
-
(
|
32
|
-
(
|
33
|
-
|
34
|
-
(
|
35
|
-
|
36
|
-
<
|
37
|
-
<
|
38
|
-
<K>(element:Component<{children:K}>, children:K): View
|
39
|
-
(element:Component<undefined>): View
|
26
|
+
(first: Tag): View
|
27
|
+
<P>(first: Tag, second: P): View
|
28
|
+
<C extends Child>(first: Tag, second: C): View
|
29
|
+
<C extends Child, P>(first: Tag, second: P, third: C): View
|
30
|
+
|
31
|
+
(first: Component<Record<string,never>>): View
|
32
|
+
<P extends Record<string, unknown>>(first: Component<P>, second: P): View
|
33
|
+
<C>(first: Component<{children:C}>, second: C): View
|
34
|
+
<P extends Record<string, unknown>, C>(first: Component<P & {children:C}>, second:P, third:C): View
|
40
35
|
}
|
41
36
|
|
42
37
|
/**
|
43
|
-
* @group Hyperscript
|
44
|
-
*/
|
45
|
-
export type Child = { call:any } | Child[] | string | number | symbol | bigint | boolean | Record<string,unknown> | {():Child, [ELEMENT]:boolean}
|
46
|
-
/**
|
47
|
-
* @group Hyperscript
|
48
|
-
*/
|
49
|
-
export type View = {():void, [ELEMENT]?:boolean}
|
50
|
-
/**
|
51
|
-
* @group Hyperscript
|
52
|
-
*/
|
53
|
-
export type Component<T> = {(props:T): Mountable, [ELEMENT]?: Runtime}
|
54
|
-
/**
|
55
|
-
* @group Hyperscript
|
56
|
-
*/
|
57
|
-
export type Tag = typeof DOMElements extends Set<infer K> ? K : never;
|
58
|
-
|
59
|
-
const Fragment:Component<Props> = <T extends Props>(props:T):Mountable => (props as any).children
|
60
|
-
|
61
|
-
/**
|
62
|
-
|
63
38
|
@param r
|
64
39
|
@param patch
|
65
40
|
@group Hyperscript
|
66
41
|
*/
|
67
|
-
export function hyperscript(r:Runtime,
|
42
|
+
export function hyperscript(r: Runtime, parseTag: TagParser = parseHtmlTag): HyperScript {
|
68
43
|
|
69
|
-
function item
|
44
|
+
function item(e: Element, c: Child, m?: null): void {
|
70
45
|
if (c===null) return
|
46
|
+
const t = typeof c
|
71
47
|
if (isArray(c))
|
72
48
|
for (const child of c)
|
73
49
|
item(e, child, m)
|
74
|
-
else if (
|
50
|
+
else if (t === 'object' && r.isChild(c))
|
75
51
|
r.insert(e, c, m)
|
76
|
-
else if (
|
77
|
-
|
78
|
-
else if (
|
79
|
-
while (
|
52
|
+
else if (t === 'string')
|
53
|
+
e.appendChild(r.text((c as string)))
|
54
|
+
else if (t === 'function') {
|
55
|
+
// while (c[ELEMENT]?.call) c = (c as any)()
|
80
56
|
r.insert(e, c, m)
|
81
|
-
} else
|
57
|
+
} else e.appendChild(r.text(c.toString()))
|
82
58
|
}
|
83
59
|
|
84
|
-
return function h<
|
85
|
-
|
86
|
-
second?:
|
87
|
-
third?:
|
60
|
+
return function h<P extends Record<string,unknown>, C = never>(
|
61
|
+
first: Tag | Component<P>,
|
62
|
+
second?: P | C,
|
63
|
+
third?: C
|
88
64
|
): View {
|
89
|
-
let props:
|
65
|
+
let props: P
|
90
66
|
let children: Child
|
91
67
|
|
92
68
|
if (typeof second === 'object' && !isArray(second)) {
|
93
69
|
children = (third as Child) || [];
|
94
|
-
props = ((second ?? {}) as
|
70
|
+
props = ((second ?? {}) as P & {children:C})
|
95
71
|
} else {
|
96
72
|
children = (second as Child) || []
|
97
|
-
props = {} as
|
73
|
+
props = {} as P & {children:C}
|
98
74
|
}
|
99
75
|
|
100
76
|
let ret:View
|
101
77
|
|
102
|
-
if (
|
103
|
-
|
104
|
-
const d = Object.getOwnPropertyDescriptors(props)
|
105
|
-
if (children) (props as any).children = children
|
106
|
-
for (const k in d) {
|
107
|
-
if (isArray(d[k].value)) {
|
108
|
-
const list:any[] = d[k].value;
|
109
|
-
(props as any)[k] = () => {
|
110
|
-
for (let i = 0; i < list.length; i++)
|
111
|
-
while (list[i][ELEMENT]) list[i] = list[i]()
|
112
|
-
return list
|
113
|
-
}
|
114
|
-
dynamicProperty(props as any, k)
|
115
|
-
} else if (d[k].value?.call && !d[k].value.length) { // A function with zero arguments
|
116
|
-
dynamicProperty(props as any, k)
|
117
|
-
}
|
118
|
-
}
|
119
|
-
e = untrack(()=>(element as Component<T&{children:K}>)(props as T&{children:K}))
|
120
|
-
ret = () => e
|
121
|
-
} else {
|
122
|
-
const tag = parseTag(element as Tag)
|
78
|
+
if (typeof first === 'string') {
|
79
|
+
const tag = parseTag(first)
|
123
80
|
const multiExpression = detectMultiExpression(children) ? null : undefined
|
124
81
|
const e = r.element(tag.name)
|
125
|
-
const props2 = props as
|
82
|
+
const props2 = props as P & {class?: string|(()=>string)}
|
126
83
|
if (tag.id) e.setAttribute('id',tag.id)
|
127
84
|
if (tag.classes?.length) {
|
128
|
-
const cd = Object.getOwnPropertyDescriptor(props2,'class') ?? ({value:'',writable:true,enumerable:true}
|
129
|
-
|
85
|
+
const cd = Object.getOwnPropertyDescriptor(props2,'class') ?? ({value:'',writable:true,enumerable:true});
|
86
|
+
props2.class = (cd.value?.call) ?
|
130
87
|
() => [...tag.classes,...(cd.value()??'').split(' ')].filter(c=>c).join(' ') :
|
131
88
|
[...tag.classes,...(cd.value??'').split(' ')].filter(c=>c).join(' ')
|
132
89
|
}
|
133
|
-
if (patch) patch(props2)
|
90
|
+
// if (patch) patch(props2)
|
134
91
|
let dynamic = false
|
135
92
|
const d = Object.getOwnPropertyDescriptors(props2)
|
136
93
|
for (const k in d) {
|
137
|
-
if (k !== 'ref' && !k.startsWith('on') && d[k].value
|
138
|
-
dynamicProperty(props2
|
94
|
+
if (k !== 'ref' && !k.startsWith('on') && typeof d[k].value === 'function') {
|
95
|
+
dynamicProperty(props2, k)
|
139
96
|
dynamic = true
|
140
97
|
} else if (d[k].get) dynamic = true
|
141
98
|
}
|
142
|
-
(dynamic ? r.spread : r.assign) (e, props2, !!(children as
|
143
|
-
item(e,children
|
99
|
+
(dynamic ? r.spread : r.assign) (e, props2, !!(children as {length?: number})?.length)
|
100
|
+
item(e, children, multiExpression)
|
101
|
+
ret = () => e
|
102
|
+
} else {
|
103
|
+
const d = Object.getOwnPropertyDescriptors(props)
|
104
|
+
if (children) (props as unknown as {children:unknown}).children = children
|
105
|
+
for (const k in d) {
|
106
|
+
if (isArray(d[k].value)) {
|
107
|
+
const list = d[k].value;
|
108
|
+
(props as Record<string, ()=>unknown>)[k] = () => {
|
109
|
+
for (let i = 0; i < list.length; i++)
|
110
|
+
while (list[i][ELEMENT]) list[i] = list[i]()
|
111
|
+
return list
|
112
|
+
}
|
113
|
+
dynamicProperty(props, k)
|
114
|
+
} else if (typeof d[k].value==='function' && !d[k].value.length) { // A function with zero arguments
|
115
|
+
dynamicProperty(props, k)
|
116
|
+
}
|
117
|
+
}
|
118
|
+
const e = r.component(() => (first as Component<P>)(props))
|
144
119
|
ret = () => e
|
145
120
|
}
|
146
121
|
ret[ELEMENT] = true
|
@@ -148,18 +123,18 @@ export function hyperscript(r:Runtime, patch?:any):HyperScript {
|
|
148
123
|
}
|
149
124
|
}
|
150
125
|
|
151
|
-
function detectMultiExpression(
|
152
|
-
if (
|
153
|
-
else if (!isArray(
|
154
|
-
for (const i of
|
155
|
-
if (i
|
126
|
+
function detectMultiExpression(children: Child): boolean {
|
127
|
+
if (typeof children === 'function') return true
|
128
|
+
else if (!isArray(children)) return false
|
129
|
+
for (const i of children) {
|
130
|
+
if (typeof i === 'function') return true
|
156
131
|
else if (isArray(i)) return detectMultiExpression(i)
|
157
132
|
}
|
158
133
|
return false
|
159
134
|
}
|
160
135
|
|
161
136
|
// ^([a-zA-Z]\w*)?(#[a-zA-Z][-\w]*)?(.[a-zA-Z][-\w]*)*
|
162
|
-
function
|
137
|
+
export function parseHtmlTag(s:Tag) {
|
163
138
|
const classes:string[] = [];
|
164
139
|
let id:string|undefined = undefined, i:number
|
165
140
|
|
@@ -185,10 +160,10 @@ function parseTag(s:string):{name:string,id?:string,classes:string[]} {
|
|
185
160
|
return {name:name as string,classes,id:id}
|
186
161
|
}
|
187
162
|
|
188
|
-
function dynamicProperty(props:Record<string,
|
189
|
-
const src = props[key]
|
190
|
-
Object.defineProperty(props, key, {get() {return src()},enumerable:true})
|
191
|
-
return props
|
163
|
+
function dynamicProperty<T>(props: Record<string, unknown>, key: string) {
|
164
|
+
const src = props[key] as ()=>unknown
|
165
|
+
Object.defineProperty(props, key, {get() {return src()}, enumerable:true})
|
166
|
+
// return props
|
192
167
|
}
|
193
168
|
|
194
169
|
// function tw(rules) {
|
package/src/mod.ts
CHANGED
@@ -1,18 +1,15 @@
|
|
1
|
-
// @ts-nocheck:
|
2
1
|
export type {Getter,Setter,Fn,EqualsFn,ErrorFn,RootFn,UpdateFn} from './reactive.ts'
|
3
2
|
export {signal,effect,untrack,batch,memo,root,wrap,fuse,onMount,onCleanup} from './reactive.ts'
|
4
3
|
export {nbsp} from './constants.ts'
|
5
4
|
export {Show,List} from './controlflow.ts'
|
6
5
|
export {runtime, type Runtime} from './runtime.ts'
|
7
6
|
import {runtime, type Runtime} from './runtime.ts'
|
8
|
-
export {hyperscript,type
|
9
|
-
import {type HyperScript
|
7
|
+
export {hyperscript,type Child,type Tag,type View,type Component} from './hyperscript.ts'
|
8
|
+
import {hyperscript, parseHtmlTag, type HyperScript} from './hyperscript.ts'
|
10
9
|
export {Router} from './router.js'
|
11
10
|
export {resource,makeAbortable,abortable} from './resource.js'
|
12
|
-
// export {Input,Table} from './components.js'
|
13
|
-
// export * from './canvas.js'
|
14
11
|
|
15
|
-
const r:Runtime = /*#__PURE__*/ (typeof window === 'object') ? runtime(window
|
12
|
+
const r:Runtime = /*#__PURE__*/ (typeof window === 'object') ? runtime(window) : undefined as unknown as Runtime
|
16
13
|
|
17
14
|
/** h
|
18
15
|
@example Element with a single child
|
@@ -29,19 +26,14 @@ h(Input,{onInput:e => {}})
|
|
29
26
|
```
|
30
27
|
@group Hyperscript
|
31
28
|
*/
|
32
|
-
const h:HyperScript = /*#__PURE__*/
|
29
|
+
export const h: HyperScript = /*#__PURE__*/ hyperscript(r, parseHtmlTag)
|
33
30
|
|
34
|
-
|
31
|
+
/** render
|
35
32
|
|
36
|
-
|
33
|
+
Render component to DOM element.
|
37
34
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
// if (t==='function') return wrap(a,b)
|
44
|
-
// else return signal(a,b)
|
45
|
-
// }
|
46
|
-
|
47
|
-
export {h,render}
|
35
|
+
```js
|
36
|
+
render(()=>'hi', document.body)
|
37
|
+
```
|
38
|
+
*/
|
39
|
+
export const render:(code:()=>void, element:Element, init:unknown) => void = /*#__PURE__*/ r?.render
|