@wrnrlr/prelude 0.1.8 → 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/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:ShowProps | 
| 15 | 
            +
            export function Show<T>(props:ShowProps) {
         | 
| 16 16 | 
             
              const condition = memo(()=>props.when)
         | 
| 17 17 | 
             
              return memo(()=>{
         | 
| 18 18 | 
             
                const c = condition()
         | 
| @@ -24,149 +24,198 @@ export function Show<T>(props:ShowProps<T>) { | |
| 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 V = newValue
         | 
| 199 | 
            +
                const I = i
         | 
| 200 | 
            +
                const t = {value: newValue, index: I, disposer}
         | 
| 201 | 
            +
                items.push(t)
         | 
| 202 | 
            +
                const sI = () => { t.indexSetter = I; return signal(I) }
         | 
| 203 | 
            +
                let sV = (...a) => {
         | 
| 204 | 
            +
                  const k = I
         | 
| 205 | 
            +
                  sV = (...a) => {
         | 
| 206 | 
            +
                    if (a.length===0) {
         | 
| 207 | 
            +
                      const bk = list()[k]
         | 
| 208 | 
            +
                      return bk
         | 
| 209 | 
            +
                    } else {
         | 
| 210 | 
            +
                      const b = untrack(list)
         | 
| 211 | 
            +
                      return list(b.toSpliced(k, 1, a[0])).at(k)
         | 
| 212 | 
            +
                    }
         | 
| 213 | 
            +
                  }
         | 
| 214 | 
            +
                  t.valueSetter = sV
         | 
| 215 | 
            +
                  return sV(...a)
         | 
| 216 | 
            +
                }
         | 
| 217 | 
            +
                return mapFn(sV, () => sI())
         | 
| 218 | 
            +
              }
         | 
| 170 219 | 
             
            }
         | 
| 171 220 |  | 
| 172 221 | 
             
            function disposeList(list:any[]) {
         | 
    
        package/src/hyperscript.ts
    CHANGED
    
    | @@ -1,165 +1,141 @@ | |
| 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 HandlerProps = typeof DelegatedEvents extends Set<infer K> ? K : never;
         | 
| 11 | 
            -
            export type ChildProps = {children?:any[]}
         | 
| 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 = {}
         | 
| 20 | 
            -
             | 
| 21 | 
            -
            type AllProps = ElementProps | ComponentProps
         | 
| 22 | 
            -
             | 
| 23 | 
            -
            type EmptyProps = Record<string,never>
         | 
| 24 | 
            -
             | 
| 25 | 
            -
            /**
         | 
| 26 | 
            -
            @group Hyperscript
         | 
| 27 | 
            -
            */
         | 
| 28 | 
            -
            export type HyperScript = {
         | 
| 29 | 
            -
              // (children:Child[]): View
         | 
| 30 | 
            -
             | 
| 31 | 
            -
              (element:Tag, props:ElementProps, children:Child): View
         | 
| 32 | 
            -
              (element:Tag, props:ElementProps): View
         | 
| 33 | 
            -
              (element:Tag, children:Child): View
         | 
| 34 | 
            -
              (element:Tag): View
         | 
| 35 | 
            -
             | 
| 36 | 
            -
              <T,K>(element:Component<T & {children:K}>, props:T, children:K): View
         | 
| 37 | 
            -
              <T>(element:Component<T>, props:T): View
         | 
| 38 | 
            -
              <K>(element:Component<{children:K}>, children:K): View
         | 
| 39 | 
            -
              (element:Component<undefined>): View
         | 
| 40 | 
            -
            }
         | 
| 41 | 
            -
             | 
| 42 | 
            -
            /**
         | 
| 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 | 
            -
             */
         | 
| 6 | 
            +
            export type Mountable = View | HTMLElement | string | number | bigint | symbol | boolean | Date | Mountable[];
         | 
| 7 | 
            +
            export type Component<T> = ((props:T) => Mountable) | ((props:T) => Mountable[])
         | 
| 57 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}
         | 
| 58 11 |  | 
| 59 | 
            -
             | 
| 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
         | 
| 60 22 |  | 
| 61 | 
            -
             | 
| 23 | 
            +
            export type TagParser = <T extends string>(s:T) => {name:string,id?:string,classes:string[],namespace?:string}
         | 
| 62 24 |  | 
| 25 | 
            +
            /**
         | 
| 63 26 | 
             
            @param r
         | 
| 64 27 | 
             
            @param patch
         | 
| 65 28 | 
             
            @group Hyperscript
         | 
| 66 29 | 
             
            */
         | 
| 67 | 
            -
            export function hyperscript(r:Runtime,  | 
| 30 | 
            +
            export function hyperscript(r: Runtime, parseTag: TagParser = parseHtmlTag) {
         | 
| 68 31 |  | 
| 69 | 
            -
              function item | 
| 32 | 
            +
              function item(e: Element, c: Child, m?: null): void {
         | 
| 70 33 | 
             
                if (c===null) return
         | 
| 34 | 
            +
                const t = typeof c
         | 
| 71 35 | 
             
                if (isArray(c))
         | 
| 72 36 | 
             
                  for (const child of c)
         | 
| 73 37 | 
             
                    item(e, child, m)
         | 
| 74 | 
            -
                else if ( | 
| 38 | 
            +
                else if (t === 'object' && r.isChild(c))
         | 
| 75 39 | 
             
                  r.insert(e, c, m)
         | 
| 76 | 
            -
                else if ( | 
| 77 | 
            -
                   | 
| 78 | 
            -
                else if ( | 
| 79 | 
            -
                  while ( | 
| 40 | 
            +
                else if (t === 'string')
         | 
| 41 | 
            +
                  e.appendChild(r.text((c as string)))
         | 
| 42 | 
            +
                else if (t === 'function') {
         | 
| 43 | 
            +
                  // while (c[ELEMENT]?.call) c = (c as any)()
         | 
| 80 44 | 
             
                  r.insert(e, c, m)
         | 
| 81 | 
            -
                } else  | 
| 45 | 
            +
                } else e.appendChild(r.text(c.toString()))
         | 
| 82 46 | 
             
              }
         | 
| 83 47 |  | 
| 84 | 
            -
               | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 48 | 
            +
              function h(first: Tag): View
         | 
| 49 | 
            +
              function h<P>(first: Tag, second: P): View
         | 
| 50 | 
            +
              function h<C extends Child>(first: Tag, second: C): View
         | 
| 51 | 
            +
              function h<C extends Child, P>(first: Tag, second: P, third: C): View
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              function h(first: Component<Record<string,never>>): View
         | 
| 54 | 
            +
              function h<P extends Record<string, unknown>>(first: Component<P>, second: P): View
         | 
| 55 | 
            +
              function h<C>(first: Component<{children:C}>, second: C): View
         | 
| 56 | 
            +
              function h<P extends Record<string, unknown>, C>(first: Component<P & {children:C}>, second:P, third:C): View
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              function h<P extends Record<string,unknown>, C = never>(
         | 
| 59 | 
            +
                first: Tag | Component<P>,
         | 
| 60 | 
            +
                second?: P | C,
         | 
| 61 | 
            +
                third?: C
         | 
| 88 62 | 
             
              ): View {
         | 
| 89 | 
            -
                let props:  | 
| 63 | 
            +
                let props: P
         | 
| 90 64 | 
             
                let children: Child
         | 
| 91 65 |  | 
| 92 66 | 
             
                if (typeof second === 'object' && !isArray(second)) {
         | 
| 93 67 | 
             
                  children = (third as Child) || [];
         | 
| 94 | 
            -
                  props = ((second ?? {}) as  | 
| 68 | 
            +
                  props = ((second ?? {}) as P & {children:C})
         | 
| 95 69 | 
             
                } else {
         | 
| 96 70 | 
             
                  children = (second as Child) || []
         | 
| 97 | 
            -
                  props = {} as  | 
| 71 | 
            +
                  props = {} as P & {children:C}
         | 
| 98 72 | 
             
                }
         | 
| 99 73 |  | 
| 100 74 | 
             
                let ret:View
         | 
| 101 75 |  | 
| 102 | 
            -
                 | 
| 103 | 
            -
             | 
| 104 | 
            -
                  const  | 
| 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)
         | 
| 76 | 
            +
                const t1 = typeof first
         | 
| 77 | 
            +
                if (t1 === 'string') {
         | 
| 78 | 
            +
                  const tag = parseTag(first as Tag)
         | 
| 123 79 | 
             
                  const multiExpression = detectMultiExpression(children) ? null : undefined
         | 
| 124 80 | 
             
                  const e = r.element(tag.name)
         | 
| 125 | 
            -
                  const props2 = props as  | 
| 81 | 
            +
                  const props2 = props as P & {class?: string|(()=>string)}
         | 
| 126 82 | 
             
                  if (tag.id) e.setAttribute('id',tag.id)
         | 
| 127 83 | 
             
                  if (tag.classes?.length) {
         | 
| 128 | 
            -
                    const cd = Object.getOwnPropertyDescriptor(props2,'class') ?? ({value:'',writable:true,enumerable:true} | 
| 129 | 
            -
                     | 
| 84 | 
            +
                    const cd = Object.getOwnPropertyDescriptor(props2,'class') ?? ({value:'',writable:true,enumerable:true});
         | 
| 85 | 
            +
                    props2.class = (cd.value?.call) ?
         | 
| 130 86 | 
             
                      () => [...tag.classes,...(cd.value()??'').split(' ')].filter(c=>c).join(' ') :
         | 
| 131 87 | 
             
                      [...tag.classes,...(cd.value??'').split(' ')].filter(c=>c).join(' ')
         | 
| 132 88 | 
             
                  }
         | 
| 133 | 
            -
                  if (patch) patch(props2)
         | 
| 89 | 
            +
                  // if (patch) patch(props2)
         | 
| 134 90 | 
             
                  let dynamic = false
         | 
| 135 91 | 
             
                  const d = Object.getOwnPropertyDescriptors(props2)
         | 
| 136 92 | 
             
                  for (const k in d) {
         | 
| 137 | 
            -
                    if (k !== 'ref' && !k.startsWith('on') && d[k].value | 
| 138 | 
            -
                      dynamicProperty(props2 | 
| 93 | 
            +
                    if (k !== 'ref' && !k.startsWith('on') && typeof d[k].value === 'function') {
         | 
| 94 | 
            +
                      dynamicProperty(props2, k)
         | 
| 139 95 | 
             
                      dynamic = true
         | 
| 140 96 | 
             
                    } else if (d[k].get) dynamic = true
         | 
| 141 97 | 
             
                  }
         | 
| 142 | 
            -
                  (dynamic ? r.spread : r.assign) (e, props2, !!(children as  | 
| 143 | 
            -
                  item(e,children  | 
| 98 | 
            +
                  (dynamic ? r.spread : r.assign) (e, props2, !!(children as any)?.length)
         | 
| 99 | 
            +
                  item(e, children, multiExpression)
         | 
| 100 | 
            +
                  ret = () => e
         | 
| 101 | 
            +
                } else {
         | 
| 102 | 
            +
                  const d = Object.getOwnPropertyDescriptors(props)
         | 
| 103 | 
            +
                  if (children) (props as any).children = children
         | 
| 104 | 
            +
                  for (const k in d) {
         | 
| 105 | 
            +
                    if (isArray(d[k].value)) {
         | 
| 106 | 
            +
                      const list = d[k].value;
         | 
| 107 | 
            +
                      (props as any)[k] = () => {
         | 
| 108 | 
            +
                        for (let i = 0; i < list.length; i++)
         | 
| 109 | 
            +
                          while (list[i][ELEMENT]) list[i] = list[i]()
         | 
| 110 | 
            +
                        return list
         | 
| 111 | 
            +
                      }
         | 
| 112 | 
            +
                      dynamicProperty(props, k)
         | 
| 113 | 
            +
                    } else if (typeof d[k].value==='function' && !d[k].value.length) { // A function with zero arguments
         | 
| 114 | 
            +
                      dynamicProperty(props, k)
         | 
| 115 | 
            +
                    }
         | 
| 116 | 
            +
                  }
         | 
| 117 | 
            +
                  const e = r.component(() => (first as Component<P>)(props))
         | 
| 144 118 | 
             
                  ret = () => e
         | 
| 145 119 | 
             
                }
         | 
| 146 120 | 
             
                ret[ELEMENT] = true
         | 
| 147 121 | 
             
                return ret
         | 
| 148 122 | 
             
              }
         | 
| 123 | 
            +
             | 
| 124 | 
            +
              return h
         | 
| 149 125 | 
             
            }
         | 
| 150 126 |  | 
| 151 | 
            -
            function detectMultiExpression( | 
| 152 | 
            -
              if ( | 
| 153 | 
            -
              else if (!isArray( | 
| 154 | 
            -
              for (const i of  | 
| 155 | 
            -
                if (i | 
| 127 | 
            +
            function detectMultiExpression(children: Child): boolean {
         | 
| 128 | 
            +
              if (typeof children === 'function') return true
         | 
| 129 | 
            +
              else if (!isArray(children)) return false
         | 
| 130 | 
            +
              for (const i of children) {
         | 
| 131 | 
            +
                if (typeof i === 'function') return true
         | 
| 156 132 | 
             
                else if (isArray(i)) return detectMultiExpression(i)
         | 
| 157 133 | 
             
              }
         | 
| 158 134 | 
             
              return false
         | 
| 159 135 | 
             
            }
         | 
| 160 136 |  | 
| 161 137 | 
             
            // ^([a-zA-Z]\w*)?(#[a-zA-Z][-\w]*)?(.[a-zA-Z][-\w]*)*
         | 
| 162 | 
            -
            function  | 
| 138 | 
            +
            export function parseHtmlTag(s:Tag) {
         | 
| 163 139 | 
             
              const classes:string[] = [];
         | 
| 164 140 | 
             
              let id:string|undefined = undefined, i:number
         | 
| 165 141 |  | 
| @@ -185,10 +161,10 @@ function parseTag(s:string):{name:string,id?:string,classes:string[]} { | |
| 185 161 | 
             
              return {name:name as string,classes,id:id}
         | 
| 186 162 | 
             
            }
         | 
| 187 163 |  | 
| 188 | 
            -
            function dynamicProperty(props:Record<string, | 
| 189 | 
            -
              const src = props[key]
         | 
| 190 | 
            -
              Object.defineProperty(props, key, {get() {return src()},enumerable:true})
         | 
| 191 | 
            -
              return props
         | 
| 164 | 
            +
            function dynamicProperty<T>(props: Record<string, unknown>, key: string) {
         | 
| 165 | 
            +
              const src = props[key] as ()=>unknown
         | 
| 166 | 
            +
              Object.defineProperty(props, key, {get() {return src()}, enumerable:true})
         | 
| 167 | 
            +
              // return props
         | 
| 192 168 | 
             
            }
         | 
| 193 169 |  | 
| 194 170 | 
             
            // function tw(rules) {
         | 
    
        package/src/mod.ts
    CHANGED
    
    | @@ -5,12 +5,10 @@ export {nbsp} from './constants.ts' | |
| 5 5 | 
             
            export {Show,List} from './controlflow.ts'
         | 
| 6 6 | 
             
            export {runtime, type Runtime} from './runtime.ts'
         | 
| 7 7 | 
             
            import {runtime, type Runtime} from './runtime.ts'
         | 
| 8 | 
            -
            export {hyperscript,type  | 
| 9 | 
            -
            import { | 
| 8 | 
            +
            export {hyperscript,type Child,type Tag,type View,type Component} from './hyperscript.ts'
         | 
| 9 | 
            +
            import {hyperscript, parseHtmlTag} from './hyperscript.ts'
         | 
| 10 10 | 
             
            export {Router} from './router.js'
         | 
| 11 11 | 
             
            export {resource,makeAbortable,abortable} from './resource.js'
         | 
| 12 | 
            -
            // export {Input,Table} from './components.js'
         | 
| 13 | 
            -
            // export * from './canvas.js'
         | 
| 14 12 |  | 
| 15 13 | 
             
            const r:Runtime = /*#__PURE__*/ (typeof window === 'object') ? runtime(window as any) : undefined as any
         | 
| 16 14 |  | 
| @@ -29,7 +27,7 @@ h(Input,{onInput:e => {}}) | |
| 29 27 | 
             
            ```
         | 
| 30 28 | 
             
            @group Hyperscript
         | 
| 31 29 | 
             
            */
         | 
| 32 | 
            -
            const h | 
| 30 | 
            +
            const h = /*#__PURE__*/ hyperscript(r, parseHtmlTag)
         | 
| 33 31 |  | 
| 34 32 | 
             
            const render = /*#__PURE__*/ r?.render
         | 
| 35 33 |  | 
    
        package/src/reactive.ts
    CHANGED
    
    | @@ -65,7 +65,9 @@ const SYMBOL_ERRORS = Symbol() | |
| 65 65 | 
             
            // // Value node
         | 
| 66 66 | 
             
            // class VNode {}
         | 
| 67 67 |  | 
| 68 | 
            -
            export  | 
| 68 | 
            +
            export type Signal = Getter<T> & Setter<T>
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            class Signal<T = unknown> {
         | 
| 69 71 | 
             
              public parent: Computation<T> | undefined
         | 
| 70 72 | 
             
              public value: T
         | 
| 71 73 | 
             
              private readonly equals: EqualsFn<T>
         | 
| @@ -209,7 +211,7 @@ n(3) | |
| 209 211 | 
             
             */
         | 
| 210 212 | 
             
            export function signal<T>(value:T, options?:Options<T>): Getter<T> & Setter<T> {
         | 
| 211 213 | 
             
              const s = new Signal<T>(value,options)
         | 
| 212 | 
            -
              const f = Object.assign((...args:T[]) => args.length ? s.set(args[0]) as T : s.get() as T, s)
         | 
| 214 | 
            +
              const f = Object.assign((...args:T[]) => args.length ? s.set(args[(0)]) as T : s.get() as T, s)
         | 
| 213 215 | 
             
              return f as unknown as Getter<T> & Setter<T>
         | 
| 214 216 | 
             
            }
         | 
| 215 217 |  | 
| @@ -294,27 +296,37 @@ export type S<T> = Getter<T> | Setter<T> | |
| 294 296 | 
             
            @param s Signal
         | 
| 295 297 | 
             
            @param k
         | 
| 296 298 | 
             
            */
         | 
| 297 | 
            -
            export function wrap<T>(s:S<Array<T>>, k:number | 
| 298 | 
            -
            export function wrap<T>(s:S< | 
| 299 | 
            +
            export function wrap<T>(s:S<Array<T>>, k:number): S<T>
         | 
| 300 | 
            +
            export function wrap<T>(s:S<Array<T>>, k:()=>number): S<T>
         | 
| 301 | 
            +
            export function wrap<T>(s:S<Record<string,T>>, k:string): S<T>
         | 
| 302 | 
            +
            export function wrap<T>(s:S<Record<string,T>>, k:()=>string): S<T>
         | 
| 299 303 | 
             
            export function wrap<T>(s:S<Array<T>>|S<Record<string,T>>, k:number|string|(()=>number)|(()=>string)): S<T> {
         | 
| 300 304 | 
             
              const t = typeof k
         | 
| 301 305 | 
             
              if (t === 'number') {
         | 
| 302 | 
            -
                return ( | 
| 303 | 
            -
                  const b =  | 
| 304 | 
            -
                  return  | 
| 305 | 
            -
                } | 
| 306 | 
            +
                return (...a) => {
         | 
| 307 | 
            +
                  const b = s()
         | 
| 308 | 
            +
                  return a.length ? s(b.toSpliced(k, 1, a[0])).at(k) : b.at(k)
         | 
| 309 | 
            +
                }
         | 
| 306 310 | 
             
              } else if (t === 'string') {
         | 
| 307 | 
            -
                return ( | 
| 308 | 
            -
                   | 
| 309 | 
            -
             | 
| 310 | 
            -
             | 
| 311 | 
            +
                return (...a) => {
         | 
| 312 | 
            +
                  if (a.length) {
         | 
| 313 | 
            +
                    const b = s()
         | 
| 314 | 
            +
                    return s({...b, [k]:a[0]})[k]
         | 
| 315 | 
            +
                  } else {
         | 
| 316 | 
            +
                    return s()[k]
         | 
| 317 | 
            +
                  }
         | 
| 318 | 
            +
                }
         | 
| 311 319 | 
             
              } else if (t === 'function')
         | 
| 312 | 
            -
                return ( | 
| 313 | 
            -
                  const i =  | 
| 314 | 
            -
                  if (c==='number') return a.length ? | 
| 315 | 
            -
                     | 
| 320 | 
            +
                return (...a) => {
         | 
| 321 | 
            +
                  const i = k(), c = typeof i
         | 
| 322 | 
            +
                  if (c==='number') return a.length ?
         | 
| 323 | 
            +
                    s(old => old.toSpliced(i, 1, a[0]))[i] :
         | 
| 324 | 
            +
                    s()[i]
         | 
| 325 | 
            +
                  else if (c === 'string') return a.length ?
         | 
| 326 | 
            +
                    s(b => ({...b, [i]:a[0]}))[i] :
         | 
| 327 | 
            +
                    s()[i]
         | 
| 316 328 | 
             
                  throw new Error('Cannot wrap signal')
         | 
| 317 | 
            -
                } | 
| 329 | 
            +
                }
         | 
| 318 330 | 
             
              throw new Error('Cannot wrap signal')
         | 
| 319 331 | 
             
            }
         | 
| 320 332 |  |