@wrnrlr/prelude 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/deno.jsonc +1 -1
- package/example/checkbox.html +53 -0
- package/example/index.html +3 -33
- package/example/todo.html +77 -0
- package/package.json +1 -1
- package/src/controlflow.ts +16 -16
- package/src/mod.ts +1 -1
- package/src/runtime.ts +1 -1
- package/test/list.js +34 -0
package/deno.jsonc
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<title>Todo</title>
|
3
|
+
|
4
|
+
<script type="module">
|
5
|
+
|
6
|
+
import {h,signal,effect,batch,wrap,render,List} from '../src/mod.ts'
|
7
|
+
|
8
|
+
function Checkbox(props) {
|
9
|
+
// effect(()=>console.log('checkbox value ', props.value))
|
10
|
+
return h('input',{
|
11
|
+
type: 'checkbox',
|
12
|
+
checked: props.value,
|
13
|
+
onInput: e => props.value(e.target.checked)
|
14
|
+
})
|
15
|
+
}
|
16
|
+
|
17
|
+
function App() {
|
18
|
+
const todos = signal([true,false])
|
19
|
+
// const obj = signal({todos:[true]})
|
20
|
+
// const todos = wrap(obj,'todos')
|
21
|
+
const first = wrap(todos, 0)
|
22
|
+
const removeItem = i => {
|
23
|
+
// console.log('remove', i)
|
24
|
+
// batch(()=>{
|
25
|
+
const old = todos()
|
26
|
+
todos(old.toSpliced(i(),1))
|
27
|
+
// })
|
28
|
+
}
|
29
|
+
return [
|
30
|
+
h('button', {onClick:(e)=>{const old = todos(); todos([false, ...old])}}, '+'),
|
31
|
+
h('ol', h(List, {each:()=>todos}, (value, i) =>
|
32
|
+
h('li', [
|
33
|
+
h(Checkbox, { value: ()=>value }),
|
34
|
+
h('button', { onClick: e=>removeItem(i) }, '\u2715')
|
35
|
+
])
|
36
|
+
)),
|
37
|
+
h('button', {onClick:(e)=>{const old = todos(); todos([...old, true])}}, '+'),
|
38
|
+
h(Checkbox, { value:()=>first }),
|
39
|
+
h('pre.hello',()=>'todos: '+JSON.stringify(todos(),undefined,2))
|
40
|
+
]
|
41
|
+
}
|
42
|
+
|
43
|
+
render(App, document.body)
|
44
|
+
|
45
|
+
</script>
|
46
|
+
|
47
|
+
<style>
|
48
|
+
html {background-color:lightgray}
|
49
|
+
ul {margin:0;padding:0}
|
50
|
+
/* ul,li {list-style-type: none} */
|
51
|
+
input {border-width: 0 0 1px 0; margin:0.25em}
|
52
|
+
li>button {border:none; background:none}
|
53
|
+
</style>
|
package/example/index.html
CHANGED
@@ -1,38 +1,8 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
|
-
<title>
|
2
|
+
<title>Examples</title>
|
3
3
|
|
4
|
-
<
|
5
|
-
|
6
|
-
import {h,signal,effect,batch,wrap,render,List} from '../src/mod.ts'
|
7
|
-
|
8
|
-
function Checkbox(props) {
|
9
|
-
// effect(()=>console.log('checkbox value ', props.value))
|
10
|
-
return h('input',{
|
11
|
-
type: 'checkbox',
|
12
|
-
checked: props.value,
|
13
|
-
onInput: e => props.value(e.target.checked)
|
14
|
-
})
|
15
|
-
}
|
16
|
-
|
17
|
-
function App() {
|
18
|
-
// const todos = signal([false])
|
19
|
-
const obj = signal({todos:[false]})
|
20
|
-
const todos = wrap(obj,'todos')
|
21
|
-
const first = wrap(todos, 0)
|
22
|
-
return [
|
23
|
-
h('button', {onClick:(e)=>{const old = todos(); todos([...old, false])}}, '+'),
|
24
|
-
h('ol', h(List, {each:()=>todos}, (value, i) =>
|
25
|
-
// (console.log('value',value),h('li', h(Checkbox, { value:()=>value })))
|
26
|
-
h('li', h(Checkbox, { value:()=>value }))
|
27
|
-
)),
|
28
|
-
h(Checkbox, { value:()=>first }),
|
29
|
-
h('pre.hello',()=>'todos: '+JSON.stringify(todos(),undefined,2))
|
30
|
-
]
|
31
|
-
}
|
32
|
-
|
33
|
-
render(App, document.body)
|
34
|
-
|
35
|
-
</script>
|
4
|
+
<a href="checkbox.html">Checkboxes</a>
|
5
|
+
<a href="todo.html">Todo</a>
|
36
6
|
|
37
7
|
<style>
|
38
8
|
html {background-color:lightgray}
|
@@ -0,0 +1,77 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<title>Todo</title>
|
3
|
+
|
4
|
+
<script type="module">
|
5
|
+
|
6
|
+
import {h,signal,effect,batch,wrap,render,List} from '../src/mod.ts'
|
7
|
+
|
8
|
+
const data = [
|
9
|
+
// {description:'Buy groceries',done:false},
|
10
|
+
{description:'Clean car',done:false},
|
11
|
+
{description:'File taxes',done:true},
|
12
|
+
]
|
13
|
+
|
14
|
+
function Input(props) {
|
15
|
+
return h('input',{
|
16
|
+
value:props.value,
|
17
|
+
onInput:e => props.value(e.target.value),
|
18
|
+
tabindex:props.tabindex
|
19
|
+
})
|
20
|
+
}
|
21
|
+
|
22
|
+
function Checkbox(props) {
|
23
|
+
return h('input',{
|
24
|
+
type:'checkbox',
|
25
|
+
checked:props.value,
|
26
|
+
onInput:e => props.value(e.target.checked)
|
27
|
+
})
|
28
|
+
}
|
29
|
+
|
30
|
+
function TodoItem(props) {
|
31
|
+
// const description = wrap(props.value,'description')
|
32
|
+
const done = wrap(props.value,'done')
|
33
|
+
return h('li', [
|
34
|
+
h(Checkbox,{value:()=>done}),
|
35
|
+
// h(Input,{value:()=>description}),
|
36
|
+
h('button',{onClick:props.onDelete},'\u2715')
|
37
|
+
])
|
38
|
+
}
|
39
|
+
|
40
|
+
function App() {
|
41
|
+
const name = signal('')
|
42
|
+
const todos = signal(data)
|
43
|
+
function onSubmit(e) {
|
44
|
+
e.preventDefault()
|
45
|
+
todos(v => v.toSpliced(v.length, 0, {description:name(), done:false}))
|
46
|
+
name('')
|
47
|
+
}
|
48
|
+
const removeItem = i => e => {
|
49
|
+
batch(()=>{
|
50
|
+
const old = todos()
|
51
|
+
console.log('old',old, i)
|
52
|
+
todos(old.toSpliced(i,1))
|
53
|
+
})
|
54
|
+
}
|
55
|
+
return [
|
56
|
+
h('h3','Todo'),
|
57
|
+
h('ul',[h(List, {each:()=>todos}, (value,i) =>
|
58
|
+
h(TodoItem, {
|
59
|
+
value:()=>value,
|
60
|
+
onDelete: removeItem(i())
|
61
|
+
})
|
62
|
+
)]),
|
63
|
+
h('form',{onSubmit},[h(Input,{value:()=>name,tabindex:1})]),
|
64
|
+
h('pre.hello',()=>'todos: '+JSON.stringify(todos(),undefined,2))
|
65
|
+
]
|
66
|
+
}
|
67
|
+
|
68
|
+
render(App, document.body)
|
69
|
+
|
70
|
+
</script>
|
71
|
+
|
72
|
+
<style>
|
73
|
+
ul {margin:0;padding:0}
|
74
|
+
ul,li {list-style-type: none}
|
75
|
+
input {border-width: 0 0 1px 0; margin:0.25em}
|
76
|
+
li>button {border:none; background:none}
|
77
|
+
</style>
|
package/package.json
CHANGED
package/src/controlflow.ts
CHANGED
@@ -49,24 +49,24 @@ type ItemHolder<T> = {
|
|
49
49
|
disposer: ()=>void
|
50
50
|
}
|
51
51
|
|
52
|
-
function listArray<T, U extends Mountable>(
|
52
|
+
export function listArray<T, U extends Mountable>(
|
53
53
|
list: Getter<T[]>,
|
54
54
|
mapFn: (v: Getter<T>, i: Getter<number>) => U,
|
55
55
|
options: { fallback?: Mountable }
|
56
56
|
): () => U[]
|
57
|
-
function listArray<T, U extends Mountable>(
|
57
|
+
export function listArray<T, U extends Mountable>(
|
58
58
|
list: Signal<T[]>,
|
59
59
|
mapFn: (v: Signal<T>, i: Getter<number>) => U,
|
60
60
|
options: { fallback?: Mountable }
|
61
61
|
): () => U[]
|
62
|
-
function listArray<T, U extends Mountable>(
|
62
|
+
export function listArray<T, U extends Mountable>(
|
63
63
|
list: Getter<T[]> | Signal<T[]>,
|
64
64
|
mapFn: (v: Signal<T>, i: Getter<number>) => U,
|
65
65
|
options: { fallback?: Mountable } = {}
|
66
66
|
): () => U[] {
|
67
67
|
const items: ListItem<T>[] = [];
|
68
68
|
let mapped: U[] = [],
|
69
|
-
unusedItems: number,
|
69
|
+
// unusedItems: number,
|
70
70
|
i: number,
|
71
71
|
j: number,
|
72
72
|
item: ListItem<T>,
|
@@ -92,7 +92,7 @@ function listArray<T, U extends Mountable>(
|
|
92
92
|
}
|
93
93
|
|
94
94
|
const temp: U[] = new Array(newItems.length); // new mapped array
|
95
|
-
unusedItems = items.length;
|
95
|
+
let unusedItems = items.length;
|
96
96
|
|
97
97
|
// 1) no change when values & indexes match
|
98
98
|
for (j = unusedItems - 1; j >= 0; --j) {
|
@@ -186,8 +186,7 @@ function listArray<T, U extends Mountable>(
|
|
186
186
|
return (mapped = temp);
|
187
187
|
})
|
188
188
|
}
|
189
|
-
|
190
|
-
function newValueGetter(_:unknown) { return newValue }
|
189
|
+
function newValueGetter(a:unknown) { console.log({a}); return newValue }
|
191
190
|
function changeBoth() {
|
192
191
|
item!.index = i!
|
193
192
|
item!.indexSetter?.(i)
|
@@ -195,25 +194,26 @@ function listArray<T, U extends Mountable>(
|
|
195
194
|
item!.valueSetter?.(newValueGetter)
|
196
195
|
}
|
197
196
|
function mapper(disposer: ()=>void) {
|
198
|
-
const
|
199
|
-
const t = {value: newValue, index: I, disposer}
|
197
|
+
const t = {value: newValue, index: i, disposer}
|
200
198
|
items.push(t)
|
201
|
-
|
199
|
+
let sI = (...a) => {
|
200
|
+
sI = signal(t.index);
|
201
|
+
t.indexSetter = sI;
|
202
|
+
return sI(...a)
|
203
|
+
}
|
202
204
|
let sV = (...a) => {
|
203
|
-
const k = I
|
204
205
|
sV = (...a) => {
|
205
206
|
if (a.length===0) {
|
206
|
-
|
207
|
-
return bk
|
207
|
+
return list()[sI()]
|
208
208
|
} else {
|
209
|
-
const
|
210
|
-
return list(b.toSpliced(k, 1, a[0])).at(k)
|
209
|
+
const k = untrack(sI)
|
210
|
+
return list(b => b.toSpliced(k, 1, typeof a[0] === 'function' ? a[0]() : a[0])).at(k)
|
211
211
|
}
|
212
212
|
}
|
213
213
|
t.valueSetter = sV
|
214
214
|
return sV(...a)
|
215
215
|
}
|
216
|
-
return mapFn(sV,
|
216
|
+
return mapFn(sV, sI)
|
217
217
|
}
|
218
218
|
}
|
219
219
|
|
package/src/mod.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
export type {Getter,Setter,Fn,EqualsFn,ErrorFn,RootFn,UpdateFn} from './reactive.ts'
|
1
|
+
export type {Getter,Setter,Fn,EqualsFn,ErrorFn,RootFn,UpdateFn,Signal} from './reactive.ts'
|
2
2
|
export {signal,effect,untrack,batch,memo,root,wrap,fuse,onMount,onCleanup} from './reactive.ts'
|
3
3
|
export {nbsp} from './constants.ts'
|
4
4
|
export {Show,List} from './controlflow.ts'
|
package/src/runtime.ts
CHANGED
@@ -338,7 +338,7 @@ function setAttribute(node: Element, name: string, value?: string): undefined {
|
|
338
338
|
value===undefined || value===null ? node.removeAttribute(name) : node.setAttribute(name, value)
|
339
339
|
}
|
340
340
|
|
341
|
-
function setAttributeNS(node:Node, ns:string, name:string, value?:string):
|
341
|
+
function setAttributeNS(node:Node, ns:string, name:string, value?:string):void {
|
342
342
|
value ? node.setAttributeNS(ns, name, value) : node.removeAttributeNS(ns, name)
|
343
343
|
}
|
344
344
|
|
package/test/list.js
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
import {assertEquals,assert} from '@std/assert'
|
2
|
+
import {describe,it} from '@std/testing/bdd'
|
3
|
+
|
4
|
+
import { signal } from '../src/reactive.ts'
|
5
|
+
import { listArray } from '../src/controlflow.ts'
|
6
|
+
|
7
|
+
// Deno.test('listArray applies list to mapFn', ()=>{
|
8
|
+
// const l = signal([0,1,2])
|
9
|
+
// const r = listArray(l, (e,i)=>({e:e(), i:i()}))
|
10
|
+
// assertEquals(r(), [{e:0,i:0}, {e:1,i:1}, {e:2,i:2}])
|
11
|
+
// })
|
12
|
+
|
13
|
+
// Deno.test('listArray append element', ()=>{
|
14
|
+
// const l = signal([0,1,2])
|
15
|
+
// const r = listArray(l, (e,i)=>({e:e(), i:i()}))
|
16
|
+
// assert(r(), [{e:0,i:0}, {e:1,i:1}, {e:2,i:2}])
|
17
|
+
// l(l => [...l,3])
|
18
|
+
// assertEquals(r(), [{e:0,i:0}, {e:1,i:1}, {e:2,i:2}, {e:3,i:3}])
|
19
|
+
// })
|
20
|
+
|
21
|
+
// Deno.test('listArray prepend element', ()=>{
|
22
|
+
// const l = signal([0,1,2])
|
23
|
+
// const r = listArray(l, (e,i)=>({e:e(), i:i()}))
|
24
|
+
// r()
|
25
|
+
// l(l => [3, ...l])
|
26
|
+
// assertEquals(r(), [{e:3,i:0}, {e:0,i:1}, {e:1,i:2}, {e:2,i:3}])
|
27
|
+
// })
|
28
|
+
const l1 = signal(['a'])
|
29
|
+
const r1 = listArray(l1, (e,i)=>([i(),e()]))
|
30
|
+
// r1()
|
31
|
+
l1(l => ['x', ...l])
|
32
|
+
// l1(l => [...l, 'x', 'y'])
|
33
|
+
console.log(JSON.stringify(r1()))
|
34
|
+
// assertEquals(r(), )
|