@e280/sly 0.2.0-9 → 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.
Files changed (275) hide show
  1. package/README.md +363 -124
  2. package/package.json +14 -7
  3. package/s/{views/base-element.ts → base/element.ts} +18 -10
  4. package/s/base/index.ts +6 -0
  5. package/s/{views → base}/use.ts +15 -6
  6. package/s/{views → base}/utils/reactor.ts +13 -4
  7. package/s/base/utils/states.ts +49 -0
  8. package/s/base/utils/use-attrs.ts +36 -0
  9. package/s/demo/demo.bundle.ts +6 -19
  10. package/s/demo/views/counter.ts +14 -25
  11. package/s/demo/views/demo.ts +9 -16
  12. package/s/demo/views/{incredi.ts → fastcount.ts} +5 -5
  13. package/s/demo/views/loaders.ts +7 -7
  14. package/s/dom/attrs/attrs.ts +6 -6
  15. package/s/dom/attrs/parts/attr-fns.ts +64 -34
  16. package/s/dom/attrs/parts/attr-proxies.ts +10 -10
  17. package/s/dom/attrs/parts/attr-spec.ts +7 -7
  18. package/s/dom/dom.ts +19 -57
  19. package/s/dom/index.ts +4 -0
  20. package/s/dom/parts/dom-scope.ts +46 -0
  21. package/s/dom/parts/el.ts +14 -0
  22. package/s/dom/parts/elmer.ts +38 -0
  23. package/s/dom/parts/eve.ts +24 -0
  24. package/s/dom/parts/mk.ts +9 -0
  25. package/s/dom/parts/queries.ts +26 -0
  26. package/s/dom/types.ts +5 -0
  27. package/s/index.html.ts +4 -4
  28. package/s/index.ts +7 -17
  29. package/s/loaders/index.barrel.ts +10 -0
  30. package/s/loaders/index.ts +4 -0
  31. package/s/loaders/make.ts +14 -0
  32. package/s/loaders/mock.ts +11 -0
  33. package/s/{ops/loaders → loaders}/parts/anims.ts +1 -1
  34. package/s/{ops/loaders → loaders}/parts/ascii-anim.ts +6 -5
  35. package/s/{ops/loaders → loaders}/parts/error-display.ts +2 -2
  36. package/s/loaders/types.ts +6 -0
  37. package/s/loot/index.barrel.ts +5 -0
  38. package/s/loot/index.ts +2 -3
  39. package/s/ops/index.ts +5 -0
  40. package/s/ops/op.ts +1 -0
  41. package/s/spa/index.barrel.ts +6 -0
  42. package/s/spa/index.ts +4 -0
  43. package/s/spa/plumbing/braces.ts +76 -0
  44. package/s/spa/plumbing/primitives.ts +85 -0
  45. package/s/spa/plumbing/router-core.ts +49 -0
  46. package/s/spa/plumbing/types.ts +45 -0
  47. package/s/spa/router.ts +49 -0
  48. package/s/spa/spa.test.ts +91 -0
  49. package/s/tests.test.ts +4 -1
  50. package/s/view/index.ts +7 -0
  51. package/s/view/types.ts +39 -0
  52. package/s/view/utils/contextualize.ts +45 -0
  53. package/s/view/utils/make-component.ts +34 -0
  54. package/s/view/utils/make-view.ts +48 -0
  55. package/s/view/utils/parts/capsule.ts +67 -0
  56. package/s/view/utils/parts/chain.ts +40 -0
  57. package/s/view/utils/parts/context.ts +11 -0
  58. package/s/view/utils/parts/directive.ts +29 -0
  59. package/s/view/utils/parts/sly-view.ts +15 -0
  60. package/s/view/view.ts +24 -0
  61. package/x/base/css-reset.js.map +1 -0
  62. package/x/base/element.d.ts +19 -0
  63. package/x/{views/base-element.js → base/element.js} +14 -6
  64. package/x/base/element.js.map +1 -0
  65. package/x/base/index.d.ts +4 -0
  66. package/x/base/index.js +5 -0
  67. package/x/base/index.js.map +1 -0
  68. package/x/{views → base}/use.d.ts +6 -2
  69. package/x/{views → base}/use.js +12 -4
  70. package/x/base/use.js.map +1 -0
  71. package/x/base/utils/apply-styles.js.map +1 -0
  72. package/x/base/utils/attr-watcher.js.map +1 -0
  73. package/x/base/utils/mounts.js.map +1 -0
  74. package/x/{views → base}/utils/reactor.d.ts +0 -1
  75. package/x/{views → base}/utils/reactor.js +10 -3
  76. package/x/base/utils/reactor.js.map +1 -0
  77. package/x/base/utils/states.d.ts +13 -0
  78. package/x/base/utils/states.js +41 -0
  79. package/x/base/utils/states.js.map +1 -0
  80. package/x/base/utils/use-attrs.d.ts +11 -0
  81. package/x/base/utils/use-attrs.js +18 -0
  82. package/x/base/utils/use-attrs.js.map +1 -0
  83. package/x/demo/demo.bundle.js +6 -16
  84. package/x/demo/demo.bundle.js.map +1 -1
  85. package/x/demo/demo.bundle.min.js +16 -26
  86. package/x/demo/demo.bundle.min.js.map +4 -4
  87. package/x/demo/views/counter.d.ts +370 -3
  88. package/x/demo/views/counter.js +14 -23
  89. package/x/demo/views/counter.js.map +1 -1
  90. package/x/demo/views/demo.d.ts +4 -1
  91. package/x/demo/views/demo.js +9 -13
  92. package/x/demo/views/demo.js.map +1 -1
  93. package/x/demo/views/{incredi.d.ts → fastcount.d.ts} +3 -3
  94. package/x/demo/views/{incredi.js → fastcount.js} +5 -5
  95. package/x/demo/views/fastcount.js.map +1 -0
  96. package/x/demo/views/loaders.js +6 -6
  97. package/x/demo/views/loaders.js.map +1 -1
  98. package/x/dom/attrs/attrs.d.ts +6 -3
  99. package/x/dom/attrs/attrs.js +6 -6
  100. package/x/dom/attrs/attrs.js.map +1 -1
  101. package/x/dom/attrs/parts/attr-fns.d.ts +15 -12
  102. package/x/dom/attrs/parts/attr-fns.js +60 -38
  103. package/x/dom/attrs/parts/attr-fns.js.map +1 -1
  104. package/x/dom/attrs/parts/attr-proxies.d.ts +3 -3
  105. package/x/dom/attrs/parts/attr-proxies.js +10 -10
  106. package/x/dom/attrs/parts/attr-proxies.js.map +1 -1
  107. package/x/dom/attrs/parts/attr-spec.js +7 -7
  108. package/x/dom/attrs/parts/attr-spec.js.map +1 -1
  109. package/x/dom/dom.d.ts +14 -26
  110. package/x/dom/dom.js +18 -44
  111. package/x/dom/dom.js.map +1 -1
  112. package/x/dom/index.d.ts +2 -0
  113. package/x/dom/index.js +3 -0
  114. package/x/dom/index.js.map +1 -0
  115. package/x/dom/parts/dom-scope.d.ts +15 -0
  116. package/x/dom/parts/dom-scope.js +35 -0
  117. package/x/dom/parts/dom-scope.js.map +1 -0
  118. package/x/dom/parts/el.d.ts +2 -0
  119. package/x/dom/parts/el.js +7 -0
  120. package/x/dom/parts/el.js.map +1 -0
  121. package/x/dom/parts/elmer.d.ts +11 -0
  122. package/x/dom/parts/elmer.js +32 -0
  123. package/x/dom/parts/elmer.js.map +1 -0
  124. package/x/dom/parts/eve.d.ts +7 -0
  125. package/x/dom/parts/eve.js +16 -0
  126. package/x/dom/parts/eve.js.map +1 -0
  127. package/x/dom/parts/mk.d.ts +2 -0
  128. package/x/dom/parts/mk.js +7 -0
  129. package/x/dom/parts/mk.js.map +1 -0
  130. package/x/dom/parts/queries.d.ts +4 -0
  131. package/x/dom/parts/queries.js +13 -0
  132. package/x/dom/parts/queries.js.map +1 -0
  133. package/x/dom/types.d.ts +3 -0
  134. package/x/index.d.ts +7 -14
  135. package/x/index.html +6 -6
  136. package/x/index.html.js +4 -4
  137. package/x/index.js +7 -14
  138. package/x/index.js.map +1 -1
  139. package/x/loaders/index.barrel.d.ts +7 -0
  140. package/x/loaders/index.barrel.js +7 -0
  141. package/x/loaders/index.barrel.js.map +1 -0
  142. package/x/loaders/index.d.ts +2 -0
  143. package/x/loaders/index.js +2 -0
  144. package/x/loaders/index.js.map +1 -0
  145. package/x/loaders/make.d.ts +3 -0
  146. package/x/loaders/make.js +6 -0
  147. package/x/loaders/make.js.map +1 -0
  148. package/x/loaders/mock.d.ts +2 -0
  149. package/x/loaders/mock.js +8 -0
  150. package/x/loaders/mock.js.map +1 -0
  151. package/x/{ops/loaders → loaders}/parts/anims.d.ts +1 -1
  152. package/x/loaders/parts/anims.js.map +1 -0
  153. package/x/{ops/loaders → loaders}/parts/ascii-anim.d.ts +2 -2
  154. package/x/{ops/loaders → loaders}/parts/ascii-anim.js +4 -4
  155. package/x/loaders/parts/ascii-anim.js.map +1 -0
  156. package/x/loaders/parts/error-display.d.ts +1 -0
  157. package/x/{ops/loaders → loaders}/parts/error-display.js +2 -2
  158. package/x/loaders/parts/error-display.js.map +1 -0
  159. package/x/loaders/types.d.ts +3 -0
  160. package/x/loaders/types.js.map +1 -0
  161. package/x/loot/index.barrel.d.ts +3 -0
  162. package/x/loot/index.barrel.js +4 -0
  163. package/x/loot/index.barrel.js.map +1 -0
  164. package/x/loot/index.d.ts +2 -3
  165. package/x/loot/index.js +1 -3
  166. package/x/loot/index.js.map +1 -1
  167. package/x/ops/index.d.ts +3 -0
  168. package/x/ops/index.js +4 -0
  169. package/x/ops/index.js.map +1 -0
  170. package/x/ops/op.js +1 -0
  171. package/x/ops/op.js.map +1 -1
  172. package/x/spa/index.barrel.d.ts +4 -0
  173. package/x/spa/index.barrel.js +3 -0
  174. package/x/spa/index.barrel.js.map +1 -0
  175. package/x/spa/index.d.ts +2 -0
  176. package/x/spa/index.js +2 -0
  177. package/x/spa/index.js.map +1 -0
  178. package/x/spa/plumbing/braces.d.ts +12 -0
  179. package/x/spa/plumbing/braces.js +55 -0
  180. package/x/spa/plumbing/braces.js.map +1 -0
  181. package/x/spa/plumbing/primitives.d.ts +22 -0
  182. package/x/spa/plumbing/primitives.js +65 -0
  183. package/x/spa/plumbing/primitives.js.map +1 -0
  184. package/x/spa/plumbing/router-core.d.ts +13 -0
  185. package/x/spa/plumbing/router-core.js +38 -0
  186. package/x/spa/plumbing/router-core.js.map +1 -0
  187. package/x/spa/plumbing/types.d.ts +35 -0
  188. package/x/spa/plumbing/types.js +2 -0
  189. package/x/spa/plumbing/types.js.map +1 -0
  190. package/x/spa/router.d.ts +13 -0
  191. package/x/spa/router.js +39 -0
  192. package/x/spa/router.js.map +1 -0
  193. package/x/spa/spa.test.d.ts +15 -0
  194. package/x/spa/spa.test.js +78 -0
  195. package/x/spa/spa.test.js.map +1 -0
  196. package/x/tests.test.js +4 -1
  197. package/x/tests.test.js.map +1 -1
  198. package/x/view/index.d.ts +5 -0
  199. package/x/view/index.js +6 -0
  200. package/x/view/index.js.map +1 -0
  201. package/x/view/types.d.ts +21 -0
  202. package/x/view/types.js +2 -0
  203. package/x/{views → view}/types.js.map +1 -1
  204. package/x/view/utils/contextualize.d.ts +13 -0
  205. package/x/view/utils/contextualize.js +18 -0
  206. package/x/view/utils/contextualize.js.map +1 -0
  207. package/x/view/utils/make-component.d.ts +5 -0
  208. package/x/view/utils/make-component.js +17 -0
  209. package/x/view/utils/make-component.js.map +1 -0
  210. package/x/view/utils/make-view.d.ts +2 -0
  211. package/x/view/utils/make-view.js +24 -0
  212. package/x/view/utils/make-view.js.map +1 -0
  213. package/x/view/utils/parts/capsule.d.ts +13 -0
  214. package/x/view/utils/parts/capsule.js +49 -0
  215. package/x/view/utils/parts/capsule.js.map +1 -0
  216. package/x/view/utils/parts/chain.d.ts +13 -0
  217. package/x/view/utils/parts/chain.js +26 -0
  218. package/x/view/utils/parts/chain.js.map +1 -0
  219. package/x/view/utils/parts/context.d.ts +9 -0
  220. package/x/view/utils/parts/context.js +10 -0
  221. package/x/view/utils/parts/context.js.map +1 -0
  222. package/x/view/utils/parts/directive.d.ts +5 -0
  223. package/x/view/utils/parts/directive.js +18 -0
  224. package/x/view/utils/parts/directive.js.map +1 -0
  225. package/x/view/utils/parts/sly-view.d.ts +5 -0
  226. package/x/view/utils/parts/sly-view.js +13 -0
  227. package/x/view/utils/parts/sly-view.js.map +1 -0
  228. package/x/view/view.d.ts +11 -0
  229. package/x/view/view.js +15 -0
  230. package/x/view/view.js.map +1 -0
  231. package/s/demo/views/divine.ts +0 -22
  232. package/s/ops/loaders/make-loader.ts +0 -18
  233. package/s/views/types.ts +0 -49
  234. package/s/views/utils/apply-attrs.ts +0 -33
  235. package/s/views/view.ts +0 -185
  236. package/x/demo/views/divine.d.ts +0 -8
  237. package/x/demo/views/divine.js +0 -19
  238. package/x/demo/views/divine.js.map +0 -1
  239. package/x/demo/views/incredi.js.map +0 -1
  240. package/x/ops/loaders/make-loader.d.ts +0 -5
  241. package/x/ops/loaders/make-loader.js +0 -7
  242. package/x/ops/loaders/make-loader.js.map +0 -1
  243. package/x/ops/loaders/parts/anims.js.map +0 -1
  244. package/x/ops/loaders/parts/ascii-anim.js.map +0 -1
  245. package/x/ops/loaders/parts/error-display.d.ts +0 -1
  246. package/x/ops/loaders/parts/error-display.js.map +0 -1
  247. package/x/views/base-element.d.ts +0 -14
  248. package/x/views/base-element.js.map +0 -1
  249. package/x/views/css-reset.js.map +0 -1
  250. package/x/views/types.d.ts +0 -36
  251. package/x/views/use.js.map +0 -1
  252. package/x/views/utils/apply-attrs.d.ts +0 -2
  253. package/x/views/utils/apply-attrs.js +0 -21
  254. package/x/views/utils/apply-attrs.js.map +0 -1
  255. package/x/views/utils/apply-styles.js.map +0 -1
  256. package/x/views/utils/attr-watcher.js.map +0 -1
  257. package/x/views/utils/mounts.js.map +0 -1
  258. package/x/views/utils/reactor.js.map +0 -1
  259. package/x/views/view.d.ts +0 -13
  260. package/x/views/view.js +0 -145
  261. package/x/views/view.js.map +0 -1
  262. /package/s/{views → base}/css-reset.ts +0 -0
  263. /package/s/{views → base}/utils/apply-styles.ts +0 -0
  264. /package/s/{views → base}/utils/attr-watcher.ts +0 -0
  265. /package/s/{views → base}/utils/mounts.ts +0 -0
  266. /package/x/{views → base}/css-reset.d.ts +0 -0
  267. /package/x/{views → base}/css-reset.js +0 -0
  268. /package/x/{views → base}/utils/apply-styles.d.ts +0 -0
  269. /package/x/{views → base}/utils/apply-styles.js +0 -0
  270. /package/x/{views → base}/utils/attr-watcher.d.ts +0 -0
  271. /package/x/{views → base}/utils/attr-watcher.js +0 -0
  272. /package/x/{views → base}/utils/mounts.d.ts +0 -0
  273. /package/x/{views → base}/utils/mounts.js +0 -0
  274. /package/x/{ops/loaders → loaders}/parts/anims.js +0 -0
  275. /package/x/{views → loaders}/types.js +0 -0
package/package.json CHANGED
@@ -1,12 +1,19 @@
1
1
  {
2
2
  "name": "@e280/sly",
3
- "version": "0.2.0-9",
3
+ "version": "0.2.0",
4
4
  "description": "web shadow views",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "./x/index.js",
8
8
  "exports": {
9
- ".": "./x/index.js"
9
+ ".": "./x/index.js",
10
+ "./base": "./x/base/index.js",
11
+ "./dom": "./x/dom/index.js",
12
+ "./loaders": "./x/loaders/index.js",
13
+ "./loot": "./x/loot/index.js",
14
+ "./ops": "./x/ops/index.js",
15
+ "./spa": "./x/spa/index.js",
16
+ "./view": "./x/view/index.js"
10
17
  },
11
18
  "files": [
12
19
  "x",
@@ -16,15 +23,15 @@
16
23
  "lit": "^3.3.1"
17
24
  },
18
25
  "dependencies": {
19
- "@e280/strata": "^0.2.0-6",
20
- "@e280/stz": "^0.2.0"
26
+ "@e280/strata": "^0.2.2",
27
+ "@e280/stz": "^0.2.14"
21
28
  },
22
29
  "devDependencies": {
23
- "@e280/science": "^0.1.2",
24
- "@e280/scute": "^0.0.0",
30
+ "@e280/science": "^0.1.3",
31
+ "@e280/scute": "^0.1.1",
25
32
  "http-server": "^14.1.1",
26
33
  "npm-run-all": "^4.1.5",
27
- "typescript": "^5.9.2"
34
+ "typescript": "^5.9.3"
28
35
  },
29
36
  "scripts": {
30
37
  "build": "run-s _clean _ln _tsc _scute",
@@ -3,24 +3,30 @@ import {debounce} from "@e280/stz"
3
3
  import {CSSResultGroup} from "lit"
4
4
 
5
5
  import {dom} from "../dom/dom.js"
6
- import {Content} from "./types.js"
6
+ import {Content} from "../view/types.js"
7
7
  import {Reactor} from "./utils/reactor.js"
8
- import {applyStyles} from "./utils/apply-styles.js"
9
8
  import {AttrWatcher} from "./utils/attr-watcher.js"
9
+ import {applyStyles} from "./utils/apply-styles.js"
10
10
  import {Use, _disconnect, _reconnect, _wrap} from "./use.js"
11
11
 
12
- export abstract class BaseElement extends HTMLElement {
12
+ export class BaseElement extends HTMLElement {
13
13
  static styles: CSSResultGroup | undefined
14
+
14
15
  readonly shadow: ShadowRoot
15
16
 
16
17
  #use: Use
17
- #mounts = 0
18
+ #mountCount = 0
18
19
  #reactor = new Reactor()
19
20
  #attrWatcher = new AttrWatcher(this, () => this.update())
20
21
 
22
+ /** create the shadow root. override this if you want to change the shadow root settings. */
23
+ createShadow() {
24
+ return this.attachShadow({mode: "open"})
25
+ }
26
+
21
27
  constructor() {
22
28
  super()
23
- this.shadow = this.attachShadow({mode: "open"})
29
+ this.shadow = this.createShadow()
24
30
  this.#use = new Use(
25
31
  this,
26
32
  this.shadow,
@@ -29,8 +35,10 @@ export abstract class BaseElement extends HTMLElement {
29
35
  )
30
36
  }
31
37
 
32
- abstract render(use: Use): Content
38
+ /** return some content to render. */
39
+ render(_use: Use): Content {}
33
40
 
41
+ /** immediately perform a fresh render into the shadow root. */
34
42
  updateNow = () => {
35
43
  this.#use[_wrap](() => {
36
44
  dom.render(
@@ -43,20 +51,20 @@ export abstract class BaseElement extends HTMLElement {
43
51
  })
44
52
  }
45
53
 
54
+ /** request a rerender which will happen soon (debounced). */
46
55
  update = debounce(0, this.updateNow)
47
56
 
48
57
  connectedCallback() {
49
- if (this.#mounts === 0) {
58
+ if (this.#mountCount === 0) {
50
59
  const styles = (this.constructor as any).styles
51
- if (styles)
52
- applyStyles(this.shadow, styles)
60
+ if (styles) applyStyles(this.shadow, styles)
53
61
  this.updateNow()
54
62
  }
55
63
  else {
56
64
  this.#use[_reconnect]()
57
65
  }
58
66
  this.#attrWatcher.start()
59
- this.#mounts++
67
+ this.#mountCount++
60
68
  }
61
69
 
62
70
  disconnectedCallback() {
@@ -0,0 +1,6 @@
1
+
2
+ export * from "./utils/states.js"
3
+ export * from "./css-reset.js"
4
+ export * from "./element.js"
5
+ export * from "./use.js"
6
+
@@ -1,24 +1,25 @@
1
1
 
2
2
  import {CSSResultGroup} from "lit"
3
- import {defer, MapG} from "@e280/stz"
3
+ import {defer, GMap} from "@e280/stz"
4
4
  import {signal, SignalOptions} from "@e280/strata/signals"
5
5
 
6
6
  import {Op} from "../ops/op.js"
7
- import {dom} from "../dom/dom.js"
8
- import {Attrs} from "../dom/types.js"
9
7
  import {Mounts} from "./utils/mounts.js"
8
+ import {States} from "./utils/states.js"
9
+ import {eve, EveSpec} from "../dom/parts/eve.js"
10
10
  import {applyStyles} from "./utils/apply-styles.js"
11
+ import {useAttrs, UseAttrs} from "./utils/use-attrs.js"
11
12
 
12
13
  export const _wrap = Symbol()
13
14
  export const _disconnect = Symbol()
14
15
  export const _reconnect = Symbol()
15
16
 
16
17
  export class Use {
17
- attrs: Attrs
18
+ readonly attrs: UseAttrs
18
19
 
19
20
  #runs = 0
20
21
  #position = 0
21
- #values = new MapG<number, any>()
22
+ #values = new GMap<number, any>()
22
23
  #rendered = defer()
23
24
  #mounts = new Mounts()
24
25
 
@@ -45,7 +46,7 @@ export class Use {
45
46
  public renderNow: () => void,
46
47
  public render: () => Promise<void>,
47
48
  ) {
48
- this.attrs = dom.attrs(this.element)
49
+ this.attrs = useAttrs(this)
49
50
  }
50
51
 
51
52
  get renderCount() {
@@ -91,6 +92,14 @@ export class Use {
91
92
  return this.life(() => [fn(), () => {}])
92
93
  }
93
94
 
95
+ events(spec: EveSpec) {
96
+ return this.mount(() => eve(this.element, spec))
97
+ }
98
+
99
+ states<S extends string = string>() {
100
+ return this.once(() => new States<S>(this.element))
101
+ }
102
+
94
103
  op = (() => {
95
104
  const that = this
96
105
  function op<V>(f: () => Promise<V>) {
@@ -1,16 +1,25 @@
1
1
 
2
- import {MapG} from "@e280/stz"
2
+ import {GMap} from "@e280/stz"
3
3
  import {tracker} from "@e280/strata"
4
4
 
5
5
  export class Reactor {
6
- #map = new MapG<any, () => void>()
7
-
8
- constructor() {}
6
+ #map = new GMap<any, () => void>()
9
7
 
10
8
  effect<R>(collect: () => R, respond: () => Promise<void>) {
11
9
  const {seen, result} = tracker.observe(collect)
10
+
11
+ // add seen items
12
12
  for (const item of seen)
13
13
  this.#map.guarantee(item, () => tracker.subscribe(item, respond))
14
+
15
+ // remove orphaned items
16
+ for (const [item, dispose] of this.#map) {
17
+ if (!seen.has(item)) {
18
+ dispose()
19
+ this.#map.delete(item)
20
+ }
21
+ }
22
+
14
23
  return result
15
24
  }
16
25
 
@@ -0,0 +1,49 @@
1
+
2
+ export class States<S extends string = string> {
3
+ #states: Set<S>
4
+
5
+ constructor(element: HTMLElement) {
6
+ this.#states = element.attachInternals().states as any
7
+ }
8
+
9
+ ;[Symbol.iterator]() {
10
+ return this.#states.values()
11
+ }
12
+
13
+ values() {
14
+ return this.#states.values()
15
+ }
16
+
17
+ forEach(fn: (s: S) => void) {
18
+ this.#states.forEach(fn)
19
+ return this
20
+ }
21
+
22
+ get size() {
23
+ return this.#states.size
24
+ }
25
+
26
+ has(state: S) {
27
+ return this.#states.has(state)
28
+ }
29
+
30
+ add(...states: S[]) {
31
+ for (const s of states) this.#states.add(s)
32
+ return this
33
+ }
34
+
35
+ delete(...states: S[]) {
36
+ for (const s of states) this.#states.delete(s)
37
+ return this
38
+ }
39
+
40
+ clear() {
41
+ this.#states.clear()
42
+ return this
43
+ }
44
+
45
+ assign(...states: S[]) {
46
+ return this.clear().add(...states)
47
+ }
48
+ }
49
+
@@ -0,0 +1,36 @@
1
+
2
+ import {Use} from "../use.js"
3
+ import {dom} from "../../dom/dom.js"
4
+ import {AttrSpec, AttrTypes} from "../../dom/types.js"
5
+
6
+ export type UseAttrs = {
7
+ <A extends AttrSpec>(spec: A): AttrTypes<A>
8
+ strings: Record<string, undefined | string>
9
+ numbers: Record<string, undefined | number>
10
+ booleans: Record<string, undefined | boolean>
11
+ spec<A extends AttrSpec>(spec: A): AttrTypes<A>
12
+ on(fn: () => void): void
13
+ }
14
+
15
+ export function useAttrs(use: Use): UseAttrs {
16
+ const attrs = dom.attrs(use.element)
17
+
18
+ function attrsFn<A extends AttrSpec>(spec: A) {
19
+ return use.once(() => attrs.spec<A>(spec))
20
+ }
21
+
22
+ attrsFn.strings = attrs.strings
23
+ attrsFn.numbers = attrs.numbers
24
+ attrsFn.booleans = attrs.booleans
25
+
26
+ attrsFn.spec = <A extends AttrSpec>(spec: A) => {
27
+ return use.once(() => attrs.spec<A>(spec))
28
+ }
29
+
30
+ attrsFn.on = (fn: () => void) => {
31
+ return use.mount(() => attrs.on(fn))
32
+ }
33
+
34
+ return attrsFn
35
+ }
36
+
@@ -1,26 +1,13 @@
1
1
 
2
- import {nap, repeat} from "@e280/stz"
3
2
  import {dom} from "../dom/dom.js"
4
- import {DemoView} from "./views/demo.js"
5
- import {CounterView} from "./views/counter.js"
6
- import {DivineElement} from "./views/divine.js"
7
- import {IncrediElement} from "./views/incredi.js"
8
-
9
- dom.in(".demo").render(DemoView())
3
+ import {CounterComponent} from "./views/counter.js"
4
+ import {DemoComponent} from "./views/demo.js"
5
+ import {FastcountElement} from "./views/fastcount.js"
10
6
 
11
7
  dom.register({
12
- IncrediElement,
13
- DivineElement,
14
- DemoCounter: CounterView
15
- .component()
16
- .props(c => [dom.attrs(c).number.initial ?? 0]),
17
- })
18
-
19
- const divine = dom<DivineElement>("divine-element")
20
-
21
- repeat(async() => {
22
- await nap(1000)
23
- divine.$speed.value++
8
+ DemoComponent,
9
+ CounterComponent,
10
+ FastcountElement,
24
11
  })
25
12
 
26
13
  console.log("🦝 sly")
@@ -1,41 +1,25 @@
1
1
 
2
2
  import {css, html} from "lit"
3
- import {repeat} from "@e280/stz"
4
3
 
5
4
  import {dom} from "../../dom/dom.js"
6
- import {view} from "../../views/view.js"
7
- import {cssReset} from "../../views/css-reset.js"
5
+ import {view} from "../../view/view.js"
6
+ import {cssReset} from "../../base/css-reset.js"
7
+ import {BaseElement} from "../../base/element.js"
8
8
 
9
- export const CounterView = view(use => (start: number) => {
9
+ export const CounterView = view(use => (start: number, step: number) => {
10
10
  use.name("counter")
11
11
  use.styles(cssReset, styles)
12
12
 
13
- const $seconds = use.signal(0)
14
- const since = use.once(() => Date.now())
15
- use.mount(() => repeat(async() => {
16
- const delta = Date.now() - since
17
- $seconds.set(Math.floor(delta / 1000))
18
- }))
19
-
20
13
  const $count = use.signal(start)
21
- const increment = () => $count.value++
22
-
23
- const $product = use.signal
24
- .derived(() => $count() * $seconds())
14
+ const increment = () => { $count.value += step }
25
15
 
26
16
  return html`
27
17
  <slot></slot>
28
18
  <div>
29
- <span>${$seconds.get()}</span>
30
- </div>
31
- <div>
32
- <span>${$count.get()}</span>
33
- </div>
34
- <div>
35
- <span>${$product.get()}</span>
19
+ <span>${$count()}</span>
36
20
  </div>
37
21
  <div>
38
- <button @click="${increment}">+</button>
22
+ <button @click="${increment}">++</button>
39
23
  </div>
40
24
  `
41
25
  })
@@ -43,8 +27,13 @@ export const CounterView = view(use => (start: number) => {
43
27
  // convert a view into a web component
44
28
  export class CounterComponent extends (
45
29
  CounterView
46
- .component<{start?: number}>()
47
- .props(c => [dom.attrs(c).number.start ?? 0])
30
+ .component(class extends BaseElement {
31
+ attrs = dom.attrs(this).spec({
32
+ start: Number,
33
+ step: Number,
34
+ })
35
+ })
36
+ .props(c => [c.attrs.start ?? 0, c.attrs.step ?? 1])
48
37
  ) {}
49
38
 
50
39
  const styles = css`
@@ -1,29 +1,22 @@
1
1
 
2
2
  import {css, html} from "lit"
3
- import {DivineView} from "./divine.js"
4
- import {view} from "../../views/view.js"
3
+
4
+ import {view} from "../../view/view.js"
5
5
  import {CounterView} from "./counter.js"
6
6
  import {LoadersView} from "./loaders.js"
7
- import {cssReset} from "../../views/css-reset.js"
8
- import { nap, repeat } from "@e280/stz"
7
+ import {cssReset} from "../../base/css-reset.js"
9
8
 
10
- export const DemoView = view(use => () => {
9
+ export class DemoComponent extends (view.component(use => {
11
10
  use.name("demo")
12
11
  use.styles(cssReset, styles)
13
-
14
- const $speed = use.signal(3)
15
-
16
- use.mount(() => repeat(async() => {
17
- await nap(1000)
18
- $speed.value++
19
- }))
20
-
21
12
  return html`
22
- ${CounterView.props(2).children("view").render()}
23
- ${DivineView($speed())}
13
+ ${CounterView
14
+ .props(768, 3)
15
+ .children("view")
16
+ .render()}
24
17
  ${LoadersView()}
25
18
  `
26
- })
19
+ })) {}
27
20
 
28
21
  const styles = css`
29
22
  :host {
@@ -1,12 +1,12 @@
1
1
 
2
2
  import {css, html} from "lit"
3
- import {nap, repeat} from "@e280/stz"
3
+ import {nap, cycle} from "@e280/stz"
4
4
 
5
5
  import {dom} from "../../dom/dom.js"
6
- import {Use} from "../../views/use.js"
7
- import {BaseElement} from "../../views/base-element.js"
6
+ import {Use} from "../../base/use.js"
7
+ import {BaseElement} from "../../base/element.js"
8
8
 
9
- export class IncrediElement extends BaseElement {
9
+ export class FastcountElement extends BaseElement {
10
10
  static styles = css`span{color:orange}`
11
11
 
12
12
  attrs = dom.attrs(this).spec({value: Number})
@@ -16,7 +16,7 @@ export class IncrediElement extends BaseElement {
16
16
  const {value = 1} = this.attrs
17
17
  const $count = use.signal(0)
18
18
 
19
- use.mount(() => repeat(async() => {
19
+ use.mount(() => cycle(async() => {
20
20
  await nap(10)
21
21
  await $count($count() + 1)
22
22
  }))
@@ -1,9 +1,9 @@
1
1
 
2
2
  import {css, html} from "lit"
3
3
  import {Op} from "../../ops/op.js"
4
- import {view} from "../../views/view.js"
5
- import {cssReset} from "../../views/css-reset.js"
6
- import {anims, makeLoader} from "../../ops/loaders/make-loader.js"
4
+ import {view} from "../../view/view.js"
5
+ import {loaders} from "../../loaders/index.js"
6
+ import {cssReset} from "../../base/css-reset.js"
7
7
 
8
8
  export const LoadersView = view(use => () => {
9
9
  use.name("loaders")
@@ -11,14 +11,14 @@ export const LoadersView = view(use => () => {
11
11
 
12
12
  const op = use.once(() => Op.loading())
13
13
 
14
- const loaders = use.once(() =>
15
- Object.entries(anims).map(([key, anim]) => ({
14
+ const library = use.once(() =>
15
+ Object.entries(loaders.anims).map(([key, anim]) => ({
16
16
  key,
17
- loader: makeLoader(anim)
17
+ loader: loaders.make(anim)
18
18
  }))
19
19
  )
20
20
 
21
- return loaders.map(({key, loader}) => html`
21
+ return library.map(({key, loader}) => html`
22
22
  <div data-anim="${key}">
23
23
  <span>${key}</span>
24
24
  <span>${loader(op, () => null)}</span>
@@ -1,21 +1,21 @@
1
1
 
2
2
  import {AttrSpec} from "../types.js"
3
3
  import {onAttrs} from "./parts/on-attrs.js"
4
- import {attrFns} from "./parts/attr-fns.js"
5
4
  import {attrSpec} from "./parts/attr-spec.js"
6
5
  import {AttrProxies} from "./parts/attr-proxies.js"
6
+ import {attrGet, attrSet} from "./parts/attr-fns.js"
7
7
 
8
8
  export function attrs(element: HTMLElement) {
9
9
  const proxies = new AttrProxies(element)
10
10
  return {
11
- string: proxies.string,
12
- number: proxies.number,
13
- boolean: proxies.boolean,
11
+ strings: proxies.strings,
12
+ numbers: proxies.numbers,
13
+ booleans: proxies.booleans,
14
14
  on: (fn: () => void) => onAttrs(element, fn),
15
15
  spec: <A extends AttrSpec>(spec: A) => attrSpec(element, spec),
16
16
  }
17
17
  }
18
18
 
19
- attrs.get = attrFns.get
20
- attrs.set = attrFns.set
19
+ attrs.get = attrGet
20
+ attrs.set = attrSet
21
21
 
@@ -1,38 +1,68 @@
1
1
 
2
- /** fns for getting and setting html attributes of various types */
3
- export const attrFns = {
4
- get: {
5
- string: (e: HTMLElement, key: string) => {
6
- return e.getAttribute(key) ?? undefined
7
- },
8
- number: (e: HTMLElement, key: string) => {
9
- const raw = e.getAttribute(key)
10
- return (raw === null || !raw)
11
- ? undefined
12
- : Number(raw)
13
- },
14
- boolean: (e: HTMLElement, key: string) => {
15
- const raw = e.getAttribute(key)
16
- return raw !== null
17
- },
18
- },
19
-
20
- set: {
21
- string: (e: HTMLElement, key: string, value: string | undefined) => {
22
- if (value === undefined) e.removeAttribute(key)
23
- else e.setAttribute(key, value)
24
- return true
25
- },
26
- number: (e: HTMLElement, key: string, value: number | undefined) => {
27
- if (value === undefined) e.removeAttribute(key)
28
- else e.setAttribute(key, value.toString())
29
- return true
30
- },
31
- boolean: (e: HTMLElement, key: string, value: boolean | undefined) => {
32
- if (value) e.setAttribute(key, "")
33
- else e.removeAttribute(key)
34
- return true
35
- },
2
+ import {AttrValue} from "../../types.js"
3
+
4
+ /** get html attributes */
5
+ export const attrGet = {
6
+ string: (e: HTMLElement, key: string) => {
7
+ return e.getAttribute(key) ?? undefined
8
+ },
9
+ number: (e: HTMLElement, key: string) => {
10
+ const raw = e.getAttribute(key)
11
+ return (raw === null || !raw)
12
+ ? undefined
13
+ : Number(raw)
14
+ },
15
+ boolean: (e: HTMLElement, key: string) => {
16
+ const raw = e.getAttribute(key)
17
+ return raw !== null
18
+ },
19
+ }
20
+
21
+ /** set html attributes */
22
+ export const attrSet = {
23
+ string: (e: HTMLElement, key: string, value: string | undefined) => {
24
+ if (value === undefined) e.removeAttribute(key)
25
+ else e.setAttribute(key, value)
26
+ return true
27
+ },
28
+ number: (e: HTMLElement, key: string, value: number | undefined) => {
29
+ if (value === undefined) e.removeAttribute(key)
30
+ else e.setAttribute(key, value.toString())
31
+ return true
32
+ },
33
+ boolean: (e: HTMLElement, key: string, value: boolean | undefined) => {
34
+ if (value) e.setAttribute(key, "")
35
+ else e.removeAttribute(key)
36
+ return true
37
+ },
38
+
39
+ any: (element: HTMLElement, key: string, value: AttrValue) => {
40
+ if (value === undefined || value === null)
41
+ element.removeAttribute(key)
42
+
43
+ else if (typeof value === "string")
44
+ element.setAttribute(key, value)
45
+
46
+ else if (typeof value === "number")
47
+ element.setAttribute(key, value.toString())
48
+
49
+ else if (typeof value === "boolean") {
50
+ if (value === true)
51
+ element.setAttribute(key, "")
52
+ else
53
+ element.removeAttribute(key)
54
+ }
55
+
56
+ else console.warn(`invalid attribute "${key}" type is "${typeof value}"`)
57
+ },
58
+
59
+ entries: (element: HTMLElement, entries: Iterable<[key: string, value: AttrValue]>) => {
60
+ for (const [key, value] of entries)
61
+ attrSet.any(element, key, value)
62
+ },
63
+
64
+ record: (element: HTMLElement, record: Record<string, AttrValue>) => {
65
+ return attrSet.entries(element, Object.entries(record))
36
66
  },
37
67
  }
38
68
 
@@ -1,34 +1,34 @@
1
1
 
2
- import {attrFns} from "./attr-fns.js"
2
+ import {attrGet, attrSet} from "./attr-fns.js"
3
3
 
4
4
  /** a typed proxy accessor for html attributes */
5
5
  export class AttrProxies {
6
6
  constructor(public element: HTMLElement) {}
7
7
 
8
- string = new Proxy({}, {
8
+ strings = new Proxy({}, {
9
9
  get: (_t, key: string) => (
10
- attrFns.get.string(this.element, key)
10
+ attrGet.string(this.element, key)
11
11
  ),
12
12
  set: (_t, key: string, value: string | undefined) => (
13
- attrFns.set.string(this.element, key, value)
13
+ attrSet.string(this.element, key, value)
14
14
  ),
15
15
  }) as Record<string, string | undefined>
16
16
 
17
- number = new Proxy({}, {
17
+ numbers = new Proxy({}, {
18
18
  get: (_t, key: string) => (
19
- attrFns.get.number(this.element, key)
19
+ attrGet.number(this.element, key)
20
20
  ),
21
21
  set: (_t, key: string, value: number | undefined) => (
22
- attrFns.set.number(this.element, key, value)
22
+ attrSet.number(this.element, key, value)
23
23
  ),
24
24
  }) as Record<string, number | undefined>
25
25
 
26
- boolean = new Proxy({}, {
26
+ booleans = new Proxy({}, {
27
27
  get: (_t, key: string) => (
28
- attrFns.get.boolean(this.element, key)
28
+ attrGet.boolean(this.element, key)
29
29
  ),
30
30
  set: (_t, key: string, value: boolean | undefined) => (
31
- attrFns.set.boolean(this.element, key, value)
31
+ attrSet.boolean(this.element, key, value)
32
32
  ),
33
33
  }) as Record<string, boolean | undefined>
34
34
  }