@wrnrlr/prelude 0.2.23 → 0.2.24

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrnrlr/prelude",
3
- "version": "0.2.23",
3
+ "version": "0.2.24",
4
4
  "exports": {
5
5
  ".": "./src/mod.ts",
6
6
  "./style.css": "./src/style.css"
@@ -0,0 +1,132 @@
1
+ <script type="module">
2
+
3
+ import {
4
+ render, h, signal, memo, untrack, batch, effect, uid,
5
+ children, onMount, onCleanup, context, useContext, Show, List
6
+ } from '../src/mod.ts'
7
+
8
+ const component = (Comp, props) => untrack(() => Comp(props || ({})));
9
+ const token = (...args) => {
10
+ const comp = (props) => {
11
+ const tok = component(args[1], props)
12
+ return tok
13
+ }
14
+ return comp
15
+ }
16
+
17
+ // const CanvasCtx = context()
18
+ // const useCanvas = () => useContext(CanvasCtx)
19
+
20
+ function Canvas(props) {
21
+ console.log('canvas init')
22
+ let canvas, ctx
23
+ const ref = (e) => {
24
+ console.log('canvas ref')
25
+ canvas = e
26
+ ctx = canvas.getContext('2d')
27
+ effect(()=>{
28
+ console.log('children effect', props.children)
29
+ })
30
+ // const kids = children(()=>props.children)
31
+ }
32
+ const objects = signal([])
33
+ onMount(()=>{
34
+ console.log('mount canvas')
35
+ effect(()=>{
36
+ console.log('canvas effect', objects())
37
+ // batch(()=>{
38
+ // const kids = children(()=>props.children)
39
+ // console.log(kids)
40
+ // })
41
+ })
42
+ })
43
+ // return h('canvas', {ref}, h(CanvasCtx, {value: ()=>[objects, ctx]}), ()=>props.children)
44
+ return h('canvas', {ref})
45
+ }
46
+
47
+ const Arc = token('', function Arc(props) {
48
+ const id = props.id || uid()
49
+ // const objects = useCanvas()
50
+ console.log('init arc', id)
51
+ const draw = memo(() => {
52
+ const point = props.coord()
53
+ const p = new Path2D()
54
+ p.arc(point.x, point.y, 10, 0, 2*Math.PI)
55
+ return p
56
+ })
57
+ const render = (ctx) => {
58
+
59
+ }
60
+ const hit = (ctx, p) => {
61
+ const drawing = untrack(draw)
62
+ const result = ctx.isPointInPath(drawing, p.x, p.y) || ctx.isPointInStroke(drawing, p.x, p.y)
63
+ if (result) console.log('hit', id)
64
+ }
65
+ onMount(()=>{console.log('mount arc', id)})
66
+ onCleanup(()=>{
67
+ console.log('cleanup arc', id)
68
+ })
69
+ const self = {draw, hit, render}
70
+ return self
71
+ })
72
+
73
+ function Group(props) {
74
+ const id = props.id || uid()
75
+ const objects = useCanvas()
76
+ console.log('init group', id, objects)
77
+ const draw = memo(() => {
78
+
79
+ })
80
+ const render = (ctx) => {
81
+
82
+ }
83
+ const hit = (ctx, p) => {
84
+ const drawing = untrack(draw)
85
+ const result = ctx.isPointInPath(drawing, p.x, p.y) || ctx.isPointInStroke(drawing, p.x, p.y)
86
+ if (result) console.log('hit', id)
87
+ }
88
+ onMount(()=>{
89
+ console.log('mount arc', id)
90
+ })
91
+ onCleanup(()=>{
92
+ console.log('cleanup arc', id)
93
+ })
94
+ const self = {draw, hit, render}
95
+ return self
96
+ }
97
+
98
+ function Demo1() {
99
+ const a = signal(new DOMPoint(10, 10))
100
+ const b = signal(new DOMPoint(20, 20))
101
+ return h(Canvas, [
102
+ h(Arc, {coord:()=>a}),
103
+ h(Arc, {coord:()=>a})
104
+ ])
105
+ }
106
+
107
+ function Demo2() {
108
+ return h(Canvas, [
109
+ h(Arc, {coord: ()=>new DOMPoint(10, 10)}),
110
+ h(Arc, {coord: ()=>new DOMPoint(20, 20)}),
111
+ ])
112
+ }
113
+
114
+ render(()=>[
115
+ h(Demo1),
116
+ // h(Demo2),
117
+ ], document.body)
118
+
119
+ class CanvasElement extends EventTarget {
120
+
121
+ }
122
+
123
+ </script>
124
+
125
+ <style>
126
+ canvas {
127
+ border: 1px solid gray;
128
+ width: 600;
129
+ height: 300;
130
+ }
131
+ canvas + canvas { margin-top: 10px }
132
+ </style>
@@ -10,18 +10,21 @@ const useCounter = () => {
10
10
  }
11
11
 
12
12
  function CounterProvider(props) {
13
+ console.log('init provider')
13
14
  const counter = signal(0)
14
15
  const increment = ()=>(console.log('increment', counter()),counter(v=>++v))
15
- return h(CounterCtx, {value:()=>[counter, increment]}, props.children)
16
+ return h(CounterCtx, {value:[counter, increment]}, props.children)
16
17
  }
17
18
 
18
19
  function Counter() {
20
+ console.log('init counter')
19
21
  const [val, increment] = useCounter()
20
22
  return [val, h('button', {onClick:e=>increment()}, '+')]
21
23
  }
22
24
 
23
25
  function App() {
24
- return h(CounterProvider, ()=>h(Counter))
26
+ console.log('init app')
27
+ return h(CounterProvider, (console.log('render child'), ()=>h(Counter)))
25
28
  }
26
29
 
27
30
  render(App, document.body)
package/example/h.html CHANGED
@@ -1,22 +1,29 @@
1
1
  <script type="module">
2
2
 
3
- // import { createSignal, createEffect } from 'solid'
3
+ import { createSignal, createEffect, createContext, useContext } from 'https://esm.sh/solid-js'
4
4
  import { render } from 'https://esm.sh/solid-js/web'
5
5
  import h from 'https://esm.sh/solid-js/h'
6
6
 
7
- function A(props) {
8
- console.log('A')
9
- return ['A', h(B)]
7
+ const CounterCtx = createContext()
8
+
9
+ const useCounter = () => { return useContext(CounterCtx) }
10
+
11
+ function CounterProvider(props) {
12
+ console.log('init provider')
13
+ const counter = createSignal(0)
14
+ const increment = ()=>(console.log('increment', counter()),counter(v=>++v))
15
+ return h(CounterCtx.Provider, {value:()=>[counter, increment]}, props.children)
10
16
  }
11
17
 
12
- function B() {
13
- console.log('B')
14
- return 'B'
18
+ function Counter() {
19
+ console.log('init counter')
20
+ const [val, increment] = useCounter()
21
+ return [val, h('button', {onClick:e=>increment()}, '+')]
15
22
  }
16
23
 
17
24
  function App() {
18
- console.log('App')
19
- return h(A, h(B))
25
+ console.log('init app')
26
+ return h(CounterProvider, h(Counter))
20
27
  }
21
28
 
22
29
  render(App, document.body)
@@ -14,6 +14,7 @@
14
14
  <li><a href="context.html">Context (Dependency Injection)</a></li>
15
15
  <li><a href="h.html">h</a></li>
16
16
  <li><a href="router.html">Router</a></li>
17
+ <li><a href="canvas.html">Canvas</a></li>
17
18
  </ul>
18
19
  <!-- <a href="router.html">Router</a> -->
19
20
  <!-- <a href="context.html">Context</a> -->
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wrnrlr/prelude",
3
3
  "type": "module",
4
- "version": "0.2.23",
4
+ "version": "0.2.24",
5
5
  "author": "Werner Laurensse",
6
6
  "description": "A signal based frontend library with fine-grained reactivity",
7
7
  "main": "./src/mod.ts",
package/src/form.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { signal, memo, effect, context, useContext, renderEffect } from './reactive.ts'
2
2
  import { Show } from './show.ts'
3
3
  import { List } from './list.ts'
4
- import { h } from './hyperscript.ts'
4
+ import { h } from './web.ts'
5
5
  import { nbsp } from './constants.ts'
6
6
 
7
7
  const Ctx = context()
@@ -1,11 +1,8 @@
1
1
  import type {DOMElements} from './constants.ts'
2
2
  import type {Mountable} from './runtime.ts'
3
- import {r} from './runtime.ts'
4
3
 
5
4
  // const document = globalThis.document
6
5
 
7
- export const h = hyperscript(r)
8
-
9
6
  type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node
10
7
 
11
8
  interface Runtime {
@@ -179,6 +176,11 @@ export function hyperscript(r: Runtime): HyperScript {
179
176
  return h;
180
177
  }
181
178
 
179
+ function dynamicProperty<T>(props: Record<string, unknown>, key: string) {
180
+ const src = props[key] as ()=>unknown
181
+ Object.defineProperty(props, key, {get() {return src()}, enumerable:true})
182
+ // return props
183
+ }
182
184
 
183
185
  // ^([a-zA-Z]\w*)?(#[a-zA-Z][-\w]*)?(.[a-zA-Z][-\w]*)*
184
186
  // export function parseHtmlTag(s:Tag) {
@@ -207,12 +209,6 @@ export function hyperscript(r: Runtime): HyperScript {
207
209
  // return {name:name as string,classes,id:id}
208
210
  // }
209
211
 
210
- function dynamicProperty<T>(props: Record<string, unknown>, key: string) {
211
- const src = props[key] as ()=>unknown
212
- Object.defineProperty(props, key, {get() {return src()}, enumerable:true})
213
- // return props
214
- }
215
-
216
212
  // function tw(rules) {
217
213
  // const classes = (classes) => classes.filter(c=>!rules.some(r=>c.match(r[0]))).join(' ')
218
214
  // const styles = (classes) => classes.reduce((acc,c) => {
@@ -0,0 +1,211 @@
1
+ import type {DOMElements} from './constants.ts'
2
+ import type {Runtime,Mountable} from './runtime.ts'
3
+
4
+ const ELEMENT: unique symbol = Symbol(), {isArray} = Array
5
+
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}
11
+
12
+ export type TagParser = <T extends string>(s:T) => {name:string,id?:string,classes:string[],namespace?:string}
13
+
14
+ export type HyperScript = {
15
+ (first: Tag): View
16
+ <P>(first: Tag, second: P): View
17
+ <C extends Child>(first: Tag, second: C): View
18
+ <C extends Child, P>(first: Tag, second: P, third: C): View
19
+
20
+ (first: Component<Record<string,never>>): View
21
+ <P extends Record<string, unknown>>(first: Component<P>, second: P): View
22
+ <C>(first: Component<{children:C}>, second: C): View
23
+ <P extends Record<string, unknown>, C>(first: Component<P & {children:C}>, second:P, third:C): View
24
+ }
25
+
26
+ /**
27
+ @param r
28
+ @param patch
29
+ @group Hyperscript
30
+ */
31
+ export function hyperscript(r: Runtime, parseTag: TagParser = parseHtmlTag): HyperScript {
32
+
33
+ function item(e: Element, c: Child, m?: null): void {
34
+ if (c===null) return
35
+ const t = typeof c
36
+ if (isArray(c)) {
37
+ for (const child of c)
38
+ item(e, child, m)
39
+ } else if (t === 'object' && r.isChild(c)) {
40
+ r.insert(e, c, m)
41
+ } else if (t === 'string') {
42
+ e.appendChild(r.text((c as string)))
43
+ } else if (t === 'function') {
44
+ console.log('c', c)
45
+ while (((c as any)[ELEMENT])?.call) {
46
+ c = (c as any)()
47
+ console.log('c', c)
48
+ }
49
+ r.insert(e, c, m)
50
+ } else e.appendChild(r.text(c.toString()))
51
+ }
52
+
53
+ return function h<P extends Record<string,unknown>, C = never>(
54
+ first: Tag | Component<P>,
55
+ second?: P | C,
56
+ third?: C
57
+ ): View {
58
+ let props: P
59
+ let children: Child
60
+
61
+ if (typeof second === 'object' && !isArray(second)) {
62
+ children = (third as Child) || [];
63
+ props = ((second ?? {}) as P & {children:C})
64
+ } else {
65
+ children = (second as Child) || []
66
+ props = {} as P & {children:C}
67
+ }
68
+
69
+ let ret:View
70
+
71
+ if (typeof first === 'string') {
72
+ const tag = parseTag(first)
73
+ const multiExpression = detectMultiExpression(children) ? null : undefined
74
+ const e = r.element(tag.name)
75
+ const props2 = props as P & {class?: string|(()=>string)}
76
+ if (tag.id) e.setAttribute('id',tag.id)
77
+ if (tag.classes?.length) {
78
+ const cd = Object.getOwnPropertyDescriptor(props2,'class') ?? ({value:'',writable:true,enumerable:true});
79
+ props2.class = (cd.value?.call) ?
80
+ () => [...tag.classes,...(cd.value()??'').split(' ')].filter(c=>c).join(' ') :
81
+ [...tag.classes,...(cd.value??'').split(' ')].filter(c=>c).join(' ')
82
+ }
83
+ // if (patch) patch(props2)
84
+ let dynamic = false
85
+ const d = Object.getOwnPropertyDescriptors(props2)
86
+ for (const k in d) {
87
+ if (k !== 'ref' && !k.startsWith('on') && typeof d[k].value === 'function') {
88
+ dynamicProperty(props2, k)
89
+ dynamic = true
90
+ } else if (d[k].get) dynamic = true
91
+ }
92
+ (dynamic ? r.spread : r.assign) (e, props2, !!(children as {length?: number})?.length)
93
+ item(e, children, multiExpression)
94
+ ret = () => e
95
+ } else {
96
+ const d = Object.getOwnPropertyDescriptors(props)
97
+ if (children) (props as unknown as {children:unknown}).children = children
98
+ for (const k in d) {
99
+ if (isArray(d[k].value)) {
100
+ const list = d[k].value;
101
+ (props as Record<string, ()=>unknown>)[k] = () => {
102
+ for (let i = 0; i < list.length; i++){
103
+ console.log('i', list[i][ELEMENT], k, d[k])
104
+ while (list[i][ELEMENT]) {
105
+ console.log('i', list[i][ELEMENT])
106
+ list[i] = list[i]()
107
+ }
108
+ }
109
+ return list
110
+ }
111
+ dynamicProperty(props, k)
112
+ } else if (typeof d[k].value==='function' && !d[k].value.length) { // A function with zero arguments
113
+ dynamicProperty(props, k)
114
+ }
115
+ }
116
+ const e = r.component(() => (first as Component<P>)(props))
117
+ ret = () => e
118
+ }
119
+ ret[ELEMENT] = true
120
+ return ret
121
+ }
122
+ }
123
+
124
+ function detectMultiExpression(children: Child): boolean {
125
+ if (typeof children === 'function') return true
126
+ else if (!isArray(children)) return false
127
+ for (const i of children) {
128
+ if (typeof i === 'function') return true
129
+ else if (isArray(i)) return detectMultiExpression(i)
130
+ }
131
+ return false
132
+ }
133
+
134
+ // ^([a-zA-Z]\w*)?(#[a-zA-Z][-\w]*)?(.[a-zA-Z][-\w]*)*
135
+ export function parseHtmlTag(s:Tag) {
136
+ const classes:string[] = [];
137
+ let id:string|undefined = undefined, i:number
138
+
139
+ i = s.indexOf('#')
140
+ if (i===-1) i = s.indexOf('.')
141
+ if (i===-1) i = s.length
142
+ const name = s.slice(0, i) || 'div'
143
+ s = s.slice(i)
144
+
145
+ if (s[0]==='#') {
146
+ i = s.indexOf('.')
147
+ if (i===-1) i = s.length
148
+ id = s.slice(1, i)
149
+ s = s.slice(i)
150
+ }
151
+
152
+ while(s[0]==='.') {
153
+ i = s.indexOf('.',1)
154
+ if (i===-1) i = s.length
155
+ classes.push(s.slice(1, i))
156
+ s = s.slice(i)
157
+ }
158
+ return {id, name:name as string, classes}
159
+ }
160
+
161
+ function dynamicProperty<T>(props: Record<string, unknown>, key: string) {
162
+ const src = props[key] as ()=>unknown
163
+ Object.defineProperty(props, key, {get() {return src()}, enumerable:true})
164
+ // return props
165
+ }
166
+
167
+ // function tw(rules) {
168
+ // const classes = (classes) => classes.filter(c=>!rules.some(r=>c.match(r[0]))).join(' ')
169
+ // const styles = (classes) => classes.reduce((acc,c) => {
170
+ // for (const r of rules) {
171
+ // const m = c.match(r[0])
172
+ // if (m) acc.push(r[1](...m.splice(1)))
173
+ // }
174
+ // return acc
175
+ // },[]).join(';')
176
+ // return props => {
177
+ // if (!props.class) return
178
+ // const cd = Object.getOwnPropertyDescriptor(props,'class'), cf = typeof cd.value === 'function'
179
+ // props.class = cf ? ()=>classes(cd.value().split(' ')) : classes(cd.value.split(' '))
180
+ // if (!props.style) props.style = cf ? ()=>styles(cd.value().split(' ')) : styles(cd.value.split(' '))
181
+ // else {
182
+ // const sd = Object.getOwnPropertyDescriptor(props,'style'), sf = typeof sd.value === 'function'
183
+ // if (cf) props.style = sf ? ()=>styles(cd.value().split(' ')) + ';' + sd.value() : ()=>styles(cd.value().split(' ')) + ';' + sd.value
184
+ // else {
185
+ // const ca = styles(cd.value.split(' '))
186
+ // props.style = sf ? () => ca + ';' + sd.value() : ca + ';' + sd.value
187
+ // }
188
+ // }
189
+ // }
190
+ // }
191
+
192
+ // const spacing = {p:'padding', m:'margin'}
193
+ // const toDirection = {b:'bottom', l:'left', r:'right', t:'top'}
194
+ // const toSurface = {bg:'background',text:'text',border:'border',outline:'outline'}
195
+ // const alignContent = {start:'flex-start',center:'center',end:'flex-end',between:'space-between',around:'space-around',evenly:'space-evenly'}
196
+ // const toColor = (name,weight) => 'red'
197
+
198
+ // const rules = [
199
+ // // padding & margin
200
+ // [/([pm])-(\d+)/, (pm,size)=>`${spacing[pm]}:${size/4}rem`],
201
+ // // border
202
+ // // [/b-%d/, (width)=>({'border-size':width})]
203
+ // // bg & text & border & outline
204
+ // // [/(bg|text|border|outline)-\W+-\d+/, (style,color,weight)=>({[toSurface[style]]:toColor(color,weight)})],
205
+ // // display
206
+ // // [/(block|inline|inline-block|flex|inline-flex|none)/, (display)=>({display})],
207
+ // // [/items-(start|center|end|stretch|baseline)/, (pos)=>({'align-items':pos})],
208
+ // // [/justify-(start|center|end|stretch|baseline)/, (pos)=>({'justify-content':pos})],
209
+ // // [/content-(start|center|end|between|around|evenly)/, (pos)=>({'align-content':alignContent[pos]})],
210
+ // // [/self-(auto|start|center|end|stretch|baseline)/, (pos)=>({'aligh-self':pos})],
211
+ // ]
package/src/mod.ts CHANGED
@@ -5,9 +5,11 @@ export {List} from './list.ts'
5
5
  export {Show} from './show.ts'
6
6
  export {r, type Runtime} from './runtime.ts'
7
7
  export type * from './hyperscript.ts'
8
- export {hyperscript, h} from './hyperscript.ts'
8
+ export {hyperscript} from './hyperscript.ts'
9
+ export {h} from './web.ts'
9
10
  export {Router} from './router.js'
10
11
  export {resource,makeAbortable,abortable} from './resource.js'
11
12
  import {r} from './runtime.ts'
12
13
  export const render = r.render
13
14
  export {Dialog,useDialog,Input,Checkbox,Select} from './form.js'
15
+ export {uid} from './util.ts'
package/src/reactive.ts CHANGED
@@ -304,7 +304,7 @@ export function context<T>(defaultValue?: T) {
304
304
  const s = {id, defaultValue}
305
305
  return Object.assign((props:any) => {
306
306
  OBSERVER?.set(id, props.value)
307
- return () => props.children.call ? props.children() : props.children
307
+ return () => props.children?.call ? props.children() : props.children
308
308
  }, s) as unknown as Context<T>
309
309
  }
310
310
 
package/src/runtime.ts CHANGED
@@ -54,6 +54,12 @@ function isChild(a:unknown): a is Element {
54
54
  }
55
55
 
56
56
  function component(fn:()=>unknown, props: unknown) {
57
+ // if (fn.prototype && fn.prototype.isClassComponent) {
58
+ // return untrack(() => {
59
+ // const comp = new fn(props);
60
+ // return comp.render(props);
61
+ // });
62
+ // }
57
63
  return untrack(()=>fn(props))
58
64
  }
59
65
 
package/src/util.ts ADDED
@@ -0,0 +1,5 @@
1
+ let seq = 0;
2
+
3
+ export function uid():string {
4
+ return '_' + (seq++).toString(36);
5
+ }
package/src/web.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { r } from './runtime.ts'
2
+ import { hyperscript } from './hyperscript.ts'
3
+ // import {hyperscript} from './hyperscript2.ts'
4
+
5
+ export const h = hyperscript(r)
File without changes
package/src/canvas.js DELETED
@@ -1,16 +0,0 @@
1
-
2
- export function Canvas(props) {
3
-
4
- }
5
-
6
- function Arc(props) {
7
-
8
- }
9
-
10
- function Line(props) {
11
-
12
- }
13
-
14
- function Bezier(props) {
15
-
16
- }
package/src/svg.js DELETED
File without changes