@wrnrlr/prelude 0.1.5 → 0.1.7
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.json +1 -1
- package/package.json +1 -1
- package/src/mod.ts +1 -1
- package/src/reactive.ts +8 -0
- package/src/runtime.ts +1 -1
- package/test/hyperscript.js +10 -5
- package/test/reactive.js +12 -1
- package/www/index.html +4 -4
- package/src/canvas.js +0 -114
package/deno.json
CHANGED
package/package.json
CHANGED
package/src/mod.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
// @ts-nocheck:
|
2
2
|
export type {Getter,Setter,Fn,EqualsFn,ErrorFn,RootFn,UpdateFn} from './reactive.ts'
|
3
|
-
export {signal,effect,untrack,batch,memo,root,wrap,onMount,onCleanup} from './reactive.ts'
|
3
|
+
export {signal,effect,untrack,batch,memo,root,wrap,fuse,onMount,onCleanup} from './reactive.ts'
|
4
4
|
export {nbsp} from './constants.ts'
|
5
5
|
export {Show,List} from './controlflow.ts'
|
6
6
|
export {runtime, type Runtime} from './runtime.ts'
|
package/src/reactive.ts
CHANGED
@@ -213,6 +213,14 @@ export function signal<T>(value:T, options?:Options<T>): Getter<T> & Setter<T> {
|
|
213
213
|
return f as unknown as Getter<T> & Setter<T>
|
214
214
|
}
|
215
215
|
|
216
|
+
export function fuse<T>(getter:Getter<T>, setter:Setter<T>):Getter<T> & Setter<T> {
|
217
|
+
return (...args:T[]) => {
|
218
|
+
if (args.length) return setter(args[0]) as T
|
219
|
+
else return getter()
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
|
216
224
|
/**
|
217
225
|
@group Reactive Primitive
|
218
226
|
*/
|
package/src/runtime.ts
CHANGED
@@ -283,7 +283,7 @@ function eventHandler(e:any) {
|
|
283
283
|
}
|
284
284
|
|
285
285
|
function setAttribute(node:Node, name:string, value?:string):any {
|
286
|
-
value ? node.
|
286
|
+
value===undefined || value===null ? node.removeAttribute(name) : node.setAttribute(name, value)
|
287
287
|
}
|
288
288
|
|
289
289
|
function setAttributeNS(node:Node, ns:string, name:string, value?:string):any {
|
package/test/hyperscript.js
CHANGED
@@ -30,6 +30,10 @@ testing('h with basic element', {skip:true}, async test => {
|
|
30
30
|
await test('tag with id', () => assertHTML(h('#a'), '<div id="a"></div>'))
|
31
31
|
await test('tag with class', () => assertHTML(h('.a'), '<div class="a"></div>'))
|
32
32
|
await test('tag with id & classes', () => assertHTML(h('i#a.b.c'), '<i id="a" class="b c"></i>'))
|
33
|
+
await test('tag with tag class and prop class', () => assertHTML(h('hr.a', {class:'b'}), '<hr class="a b">'))
|
34
|
+
await test('tag with tag class and dynamic prop class', () => assertHTML(h('hr.a', {class:()=>'b'}), '<hr class="a b">'))
|
35
|
+
await test('tag with tag class and undeefined prop class', () => assertHTML(h('hr.a', {class:undefined}), '<hr class="a">'))
|
36
|
+
await test('tag with tag class and dynamic undeefined prop class', () => assertHTML(h('hr.a', {class:()=>undefined}), '<hr class="a">'))
|
33
37
|
await test('no props or children', () => assertHTML(h('hr'), '<hr>'))
|
34
38
|
await test('boolean content', () => assertHTML(h('b',true), '<b>true</b>'))
|
35
39
|
await test('string content', () => assertHTML(h('b','A'), '<b>A</b>'))
|
@@ -39,11 +43,12 @@ testing('h with basic element', {skip:true}, async test => {
|
|
39
43
|
// await test('regex content', () => assertHTML(h('b',/\w/), '<b>/\\w/</b>'))
|
40
44
|
await test("signal content", () => assertHTML(h('i',()=>1), '<i>1</i>'))
|
41
45
|
await test('array content', () => assertHTML(h('i',['A',1,2n]), '<i>A12</i>'))
|
42
|
-
await test('
|
43
|
-
await test('
|
44
|
-
await test('
|
45
|
-
await test('classList attribute', () => assertHTML(h('hr', {classList:()=>({a:true})}), '<hr class="a">'))
|
46
|
-
await test('
|
46
|
+
await test('ref property', () => assertHTML(h('hr',{ref:el=>el.setAttribute('a','1')}), '<hr a="1">'))
|
47
|
+
await test('style property sets style attribute', () => assertHTML(h('hr',{style:'color:red'}), '<hr style="color: red;">'))
|
48
|
+
await test('htmlFor property sets for attribute', () => assertHTML(h('label',{htmlFor:'a'}), '<label for="a"></label>'))
|
49
|
+
await test('classList property sets class attribute', () => assertHTML(h('hr', {classList:()=>({a:true})}), '<hr class="a">'))
|
50
|
+
await test('custom attribute', () => assertHTML(h('hr', {'attr:a':'b'}), '<hr a="b">'))
|
51
|
+
await test('custom empty attribute', () => assertHTML(h('hr', {'attr:data-a':''}), '<hr data-a="">'))
|
47
52
|
})
|
48
53
|
|
49
54
|
function assertText(t, e, msg) { assertEquals(t(), e, msg) }
|
package/test/reactive.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import {assertEquals,assert} from '@std/assert'
|
2
2
|
import {describe,it} from '@std/testing/bdd'
|
3
3
|
|
4
|
-
import {signal,effect,untrack,batch,memo,context,useContext,root,wrap} from '../src/reactive.ts'
|
4
|
+
import {signal,effect,untrack,batch,memo,context,useContext,root,wrap,fuse} from '../src/reactive.ts'
|
5
5
|
|
6
6
|
describe('signal', () => {
|
7
7
|
const a = signal(1)
|
@@ -13,6 +13,17 @@ describe('signal', () => {
|
|
13
13
|
assertEquals(a(null),null)
|
14
14
|
})
|
15
15
|
|
16
|
+
describe('fuse', () => {
|
17
|
+
const n = signal(1)
|
18
|
+
const odd = signal(false)
|
19
|
+
const c = fuse(n, i => (odd(i%2===0), n(i)))
|
20
|
+
assertEquals(c(),1)
|
21
|
+
assertEquals(c(2),2)
|
22
|
+
assertEquals(odd(),true)
|
23
|
+
assertEquals(c(i=>i+1),3)
|
24
|
+
assertEquals(odd(),false)
|
25
|
+
})
|
26
|
+
|
16
27
|
describe('signal with equals option', () => {
|
17
28
|
const n = signal(0,{equals:false})
|
18
29
|
let m = 0
|
package/www/index.html
CHANGED
@@ -14,8 +14,8 @@
|
|
14
14
|
<span class="prelude text-xl">Prelude</span>
|
15
15
|
</div>
|
16
16
|
<div class="flex items-center gap-5">
|
17
|
-
<a href="/prelude/docs/index.html">
|
18
|
-
<a href="/prelude
|
17
|
+
<a href="/prelude/docs/index.html">Documentation</a>
|
18
|
+
<a href="https://github.com/wrnrlr/prelude">Source</a>
|
19
19
|
<a class="px-3 py-2 rounded-md bg-green-600 text-white font-weight-500 text-shadow-green shadow" href="/prelude/playground">Playground</a>
|
20
20
|
</div>
|
21
21
|
</nav>
|
@@ -25,7 +25,7 @@
|
|
25
25
|
<svg class="py-8" viewBox="0 0 709 709" style="width:300px;--color:var(--neutral-700)"><use xlink:href="./logo.svg#loop"></use></svg>
|
26
26
|
<div class="flex column center items-center gap-6">
|
27
27
|
<span class="prelude text-6xl">Prelude</span>
|
28
|
-
<span class="text-3xl">A signal-based
|
28
|
+
<span class="text-3xl">A signal-based UI library that lets you <br> develop in a familiar functional style</span>
|
29
29
|
<div class="flex gap-4">
|
30
30
|
<a class="px-3 py-2 rounded-md bg-neutral-200 text-xl font-weight-500" href="/prelude/docs/index.html">Get Started</a>
|
31
31
|
<a class="px-3 py-2 rounded-md bg-green-600 text-xl text-white font-weight-500 shadow" href="/prelude/playground">Open Playground</a>
|
@@ -46,7 +46,7 @@ function Counter() {
|
|
46
46
|
return h('button', {onClick}, n)
|
47
47
|
}
|
48
48
|
|
49
|
-
render(Counter,
|
49
|
+
render(Counter, document.body)</code></pre>
|
50
50
|
<div class="card">
|
51
51
|
<div class="title center">Counter</div>
|
52
52
|
<div class="flex justify-center content-center flex-wrap content" id="counter"></div>
|
package/src/canvas.js
DELETED
@@ -1,114 +0,0 @@
|
|
1
|
-
import {signal,effect,memo,context,useContext, onMount} from './reactive.ts'
|
2
|
-
import {$RUNTIME} from './runtime.ts'
|
3
|
-
import {h} from './mod.ts'
|
4
|
-
|
5
|
-
function CanvasRuntime() {
|
6
|
-
let render,insert,spread,assign,element,text,isChild
|
7
|
-
return {render,insert,spread,assign,element,text,isChild}
|
8
|
-
}
|
9
|
-
|
10
|
-
const CountCtx = context()
|
11
|
-
|
12
|
-
const useCount = () => useContext(CountCtx)
|
13
|
-
|
14
|
-
function CountProvider(props) {
|
15
|
-
const count = signal(0)
|
16
|
-
return h(CountCtx, {value:[count]}, props.children)
|
17
|
-
}
|
18
|
-
|
19
|
-
const Ctx = context()
|
20
|
-
const useCanvas = () => useContext(Ctx)
|
21
|
-
|
22
|
-
function Canvas(props) {
|
23
|
-
const canvas = signal()
|
24
|
-
const ctx = signal()
|
25
|
-
effect(() => ctx(canvas()?.getContext('2d')))
|
26
|
-
return h(Ctx, {value:[canvas,ctx]},
|
27
|
-
h('canvas', {ref:canvas}, props.children))
|
28
|
-
}
|
29
|
-
|
30
|
-
function toCanvas(fn) {
|
31
|
-
// fn[$RUNTIME] = CanvasRuntime
|
32
|
-
return fn
|
33
|
-
}
|
34
|
-
|
35
|
-
const Path = context()
|
36
|
-
const usePath = () => useContext(Path)
|
37
|
-
|
38
|
-
const Stroke = props => {
|
39
|
-
const ref = signal()
|
40
|
-
const [_,ctx] = useCanvas()
|
41
|
-
const path = signal(null)
|
42
|
-
let children
|
43
|
-
onMount(()=>path(new Path2D()))
|
44
|
-
effect(()=>console.log('Stroke',ref))
|
45
|
-
effect(() => {
|
46
|
-
if (!children) {
|
47
|
-
children = signal()
|
48
|
-
}
|
49
|
-
const kids = children()
|
50
|
-
if (kids) return
|
51
|
-
})
|
52
|
-
return h(Path, {ref, value:[path]}, props?.children)
|
53
|
-
}
|
54
|
-
|
55
|
-
const Fill = toCanvas(() => {
|
56
|
-
const ctx = useCanvas()
|
57
|
-
})
|
58
|
-
|
59
|
-
const Line = props => {
|
60
|
-
let value, path, path2d
|
61
|
-
// if (props.value) value = memo(() => [l.x0, l.y0, l.x1, l.y1])
|
62
|
-
if (props.children) value = props.children.call ? props.children : () => props.children
|
63
|
-
if (props.fill || props.stroke) {
|
64
|
-
path2d = new Path2D()
|
65
|
-
// ctx =
|
66
|
-
}
|
67
|
-
if (!value) value = props.value
|
68
|
-
let ctx = path2d ?? usePath()
|
69
|
-
if (!path2d&&ctx) { path = ctx[0] }
|
70
|
-
let render = path2d ?
|
71
|
-
() => {
|
72
|
-
path2d.moveTo(v[0],v[1])
|
73
|
-
path2d.lineTo(v[2],v[3])
|
74
|
-
} : () => {
|
75
|
-
const p = path()
|
76
|
-
p.moveTo(v[0],v[1])
|
77
|
-
p.lineTo(v[2],v[3])
|
78
|
-
}
|
79
|
-
// effect(()=>console.log('Line',path(), value()))
|
80
|
-
// effect(()=>{path().lineTo(...value())})
|
81
|
-
return ops => {
|
82
|
-
console.log('render line')
|
83
|
-
// ops.push()
|
84
|
-
return {
|
85
|
-
shape() {return path2d},
|
86
|
-
render,
|
87
|
-
hit() {},
|
88
|
-
size() {},
|
89
|
-
}
|
90
|
-
}
|
91
|
-
}
|
92
|
-
|
93
|
-
const Quadratic = toCanvas(q => {
|
94
|
-
const path = usePath()
|
95
|
-
return () => path.quadraticCurveTo(q.x0,q.y0,q.x1,q.y1,q.x2,q.y2)
|
96
|
-
})
|
97
|
-
|
98
|
-
const Bezier = toCanvas(b => {
|
99
|
-
const path = usePath()
|
100
|
-
return () => path.bezierCurveTo(b.x0,b.y0,b.x1,b.y1,b.x2,b.y2,b.x3,b.y3)
|
101
|
-
})
|
102
|
-
|
103
|
-
const Arc = toCanvas(a => {
|
104
|
-
const path = usePath()
|
105
|
-
return () => path.arc(a.x, a.y, a.radius, a.startAngle, a.endAngle, a.counterclockwise)
|
106
|
-
})
|
107
|
-
|
108
|
-
export const Group = {}
|
109
|
-
export const Pattern = {}
|
110
|
-
export const Text = {}
|
111
|
-
export const Rectangle = {}
|
112
|
-
export const Image = {}
|
113
|
-
|
114
|
-
export {CanvasRuntime,Canvas,Stroke,Fill,Line,Quadratic,Bezier,Arc}
|