@e280/sly 0.2.4 → 0.3.0-1

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 (256) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +302 -614
  3. package/package.json +6 -8
  4. package/s/_archive/README.md +1221 -0
  5. package/s/{base → _archive/base}/element.ts +5 -2
  6. package/s/_archive/view/index.ts +7 -0
  7. package/s/_archive/view/types.ts +45 -0
  8. package/s/{view → _archive/view}/utils/parts/capsule.ts +9 -2
  9. package/s/demo/demo.bundle.ts +2 -9
  10. package/s/demo/views/counter-light.ts +13 -0
  11. package/s/demo/views/counter-shadow.ts +16 -0
  12. package/s/demo/views/demo.ts +24 -18
  13. package/s/demo/views/loaders.ts +7 -7
  14. package/s/index.html.ts +30 -33
  15. package/s/index.ts +0 -2
  16. package/s/loaders/make.ts +1 -1
  17. package/s/loaders/parts/ascii-anim.ts +6 -8
  18. package/s/loaders/parts/error-display.ts +9 -9
  19. package/s/tests.test.ts +1 -4
  20. package/s/view/common/css-reset.ts +19 -0
  21. package/s/view/hooks/plumbing/hooks.ts +28 -0
  22. package/s/view/hooks/plumbing/hookscope.ts +12 -0
  23. package/s/view/hooks/use-css.ts +14 -0
  24. package/s/view/hooks/use-cx.ts +41 -0
  25. package/s/view/hooks/use-life.ts +17 -0
  26. package/s/view/hooks/use-mount.ts +30 -0
  27. package/s/view/hooks/use-name.ts +10 -0
  28. package/s/view/hooks/use-once.ts +9 -0
  29. package/s/view/hooks/use-op.ts +12 -0
  30. package/s/view/hooks/use-ref.ts +11 -0
  31. package/s/view/hooks/use-signal.ts +16 -0
  32. package/s/view/hooks/use-state.ts +20 -0
  33. package/s/view/hooks/use-wake.ts +8 -0
  34. package/s/view/index.ts +17 -4
  35. package/s/view/light.ts +50 -0
  36. package/s/view/parts/apply-attrs.ts +22 -0
  37. package/s/view/parts/apply-styles.ts +21 -0
  38. package/s/view/parts/cx.ts +26 -0
  39. package/s/view/parts/reactivity.ts +22 -0
  40. package/s/view/parts/sly-shadow.ts +8 -0
  41. package/s/view/shadow.ts +93 -0
  42. package/s/view/types.ts +15 -34
  43. package/x/demo/demo.bundle.js +2 -8
  44. package/x/demo/demo.bundle.js.map +1 -1
  45. package/x/demo/demo.bundle.min.js +45 -58
  46. package/x/demo/demo.bundle.min.js.map +4 -4
  47. package/x/demo/views/counter-light.d.ts +1 -0
  48. package/x/demo/views/counter-light.js +10 -0
  49. package/x/demo/views/counter-light.js.map +1 -0
  50. package/x/demo/views/counter-shadow.d.ts +1 -0
  51. package/x/demo/views/counter-shadow.js +12 -0
  52. package/x/demo/views/counter-shadow.js.map +1 -0
  53. package/x/demo/views/demo.d.ts +1 -4
  54. package/x/demo/views/demo.js +23 -18
  55. package/x/demo/views/demo.js.map +1 -1
  56. package/x/demo/views/loaders.d.ts +1 -1
  57. package/x/demo/views/loaders.js +7 -7
  58. package/x/demo/views/loaders.js.map +1 -1
  59. package/x/index.d.ts +0 -2
  60. package/x/index.html +30 -140
  61. package/x/index.html.js +31 -31
  62. package/x/index.html.js.map +1 -1
  63. package/x/index.js +0 -2
  64. package/x/index.js.map +1 -1
  65. package/x/loaders/make.d.ts +1 -1
  66. package/x/loaders/parts/ascii-anim.d.ts +1 -1
  67. package/x/loaders/parts/ascii-anim.js +6 -7
  68. package/x/loaders/parts/ascii-anim.js.map +1 -1
  69. package/x/loaders/parts/error-display.d.ts +1 -1
  70. package/x/loaders/parts/error-display.js +9 -9
  71. package/x/loaders/parts/error-display.js.map +1 -1
  72. package/x/tests.test.js +1 -4
  73. package/x/tests.test.js.map +1 -1
  74. package/x/view/common/css-reset.js +17 -0
  75. package/x/view/common/css-reset.js.map +1 -0
  76. package/x/view/hooks/plumbing/hooks.d.ts +11 -0
  77. package/x/view/hooks/plumbing/hooks.js +26 -0
  78. package/x/view/hooks/plumbing/hooks.js.map +1 -0
  79. package/x/view/hooks/plumbing/hookscope.d.ts +10 -0
  80. package/x/view/hooks/plumbing/hookscope.js +12 -0
  81. package/x/view/hooks/plumbing/hookscope.js.map +1 -0
  82. package/x/view/hooks/use-css.d.ts +4 -0
  83. package/x/view/hooks/use-css.js +10 -0
  84. package/x/view/hooks/use-css.js.map +1 -0
  85. package/x/view/hooks/use-cx.d.ts +10 -0
  86. package/x/view/hooks/use-cx.js +33 -0
  87. package/x/view/hooks/use-cx.js.map +1 -0
  88. package/x/view/hooks/use-life.d.ts +2 -0
  89. package/x/view/hooks/use-life.js +13 -0
  90. package/x/view/hooks/use-life.js.map +1 -0
  91. package/x/{base/utils/mounts.d.ts → view/hooks/use-mount.d.ts} +1 -0
  92. package/x/{base/utils/mounts.js → view/hooks/use-mount.js} +7 -1
  93. package/x/view/hooks/use-mount.js.map +1 -0
  94. package/x/view/hooks/use-name.d.ts +2 -0
  95. package/x/view/hooks/use-name.js +8 -0
  96. package/x/view/hooks/use-name.js.map +1 -0
  97. package/x/view/hooks/use-once.d.ts +2 -0
  98. package/x/view/hooks/use-once.js +7 -0
  99. package/x/view/hooks/use-once.js.map +1 -0
  100. package/x/view/hooks/use-op.d.ts +3 -0
  101. package/x/view/hooks/use-op.js +9 -0
  102. package/x/view/hooks/use-op.js.map +1 -0
  103. package/x/view/hooks/use-ref.d.ts +5 -0
  104. package/x/view/hooks/use-ref.js +11 -0
  105. package/x/view/hooks/use-ref.js.map +1 -0
  106. package/x/view/hooks/use-signal.d.ts +3 -0
  107. package/x/view/hooks/use-signal.js +12 -0
  108. package/x/view/hooks/use-signal.js.map +1 -0
  109. package/x/view/hooks/use-state.d.ts +1 -0
  110. package/x/view/hooks/use-state.js +17 -0
  111. package/x/view/hooks/use-state.js.map +1 -0
  112. package/x/view/hooks/use-wake.d.ts +2 -0
  113. package/x/view/hooks/use-wake.js +6 -0
  114. package/x/view/hooks/use-wake.js.map +1 -0
  115. package/x/view/index.d.ts +15 -4
  116. package/x/view/index.js +15 -4
  117. package/x/view/index.js.map +1 -1
  118. package/x/view/light.d.ts +2 -0
  119. package/x/view/light.js +41 -0
  120. package/x/view/light.js.map +1 -0
  121. package/x/view/parts/apply-attrs.d.ts +2 -0
  122. package/x/view/parts/apply-attrs.js +22 -0
  123. package/x/view/parts/apply-attrs.js.map +1 -0
  124. package/x/{base/utils → view/parts}/apply-styles.js.map +1 -1
  125. package/x/view/parts/cx.d.ts +12 -0
  126. package/x/view/parts/cx.js +24 -0
  127. package/x/view/parts/cx.js.map +1 -0
  128. package/x/view/parts/reactivity.d.ts +5 -0
  129. package/x/view/parts/reactivity.js +18 -0
  130. package/x/view/parts/reactivity.js.map +1 -0
  131. package/x/view/parts/sly-shadow.d.ts +3 -0
  132. package/x/view/parts/sly-shadow.js +7 -0
  133. package/x/view/parts/sly-shadow.js.map +1 -0
  134. package/x/view/shadow.d.ts +6 -0
  135. package/x/view/shadow.js +72 -0
  136. package/x/view/shadow.js.map +1 -0
  137. package/x/view/types.d.ts +13 -21
  138. package/s/demo/views/counter.ts +0 -50
  139. package/s/demo/views/fastcount.ts +0 -29
  140. package/x/base/css-reset.js +0 -19
  141. package/x/base/css-reset.js.map +0 -1
  142. package/x/base/element.d.ts +0 -19
  143. package/x/base/element.js +0 -52
  144. package/x/base/element.js.map +0 -1
  145. package/x/base/index.d.ts +0 -5
  146. package/x/base/index.js +0 -6
  147. package/x/base/index.js.map +0 -1
  148. package/x/base/types.d.ts +0 -3
  149. package/x/base/types.js +0 -3
  150. package/x/base/types.js.map +0 -1
  151. package/x/base/use.d.ts +0 -59
  152. package/x/base/use.js +0 -129
  153. package/x/base/use.js.map +0 -1
  154. package/x/base/utils/attr-watcher.d.ts +0 -8
  155. package/x/base/utils/attr-watcher.js +0 -20
  156. package/x/base/utils/attr-watcher.js.map +0 -1
  157. package/x/base/utils/mounts.js.map +0 -1
  158. package/x/base/utils/reactor.d.ts +0 -5
  159. package/x/base/utils/reactor.js +0 -25
  160. package/x/base/utils/reactor.js.map +0 -1
  161. package/x/base/utils/states.d.ts +0 -13
  162. package/x/base/utils/states.js +0 -41
  163. package/x/base/utils/states.js.map +0 -1
  164. package/x/base/utils/use-attrs.d.ts +0 -11
  165. package/x/base/utils/use-attrs.js +0 -18
  166. package/x/base/utils/use-attrs.js.map +0 -1
  167. package/x/demo/views/counter.d.ts +0 -374
  168. package/x/demo/views/counter.js +0 -42
  169. package/x/demo/views/counter.js.map +0 -1
  170. package/x/demo/views/fastcount.d.ts +0 -12
  171. package/x/demo/views/fastcount.js +0 -21
  172. package/x/demo/views/fastcount.js.map +0 -1
  173. package/x/spa/index.barrel.d.ts +0 -4
  174. package/x/spa/index.barrel.js +0 -3
  175. package/x/spa/index.barrel.js.map +0 -1
  176. package/x/spa/index.d.ts +0 -2
  177. package/x/spa/index.js +0 -2
  178. package/x/spa/index.js.map +0 -1
  179. package/x/spa/plumbing/braces.d.ts +0 -12
  180. package/x/spa/plumbing/braces.js +0 -55
  181. package/x/spa/plumbing/braces.js.map +0 -1
  182. package/x/spa/plumbing/primitives.d.ts +0 -22
  183. package/x/spa/plumbing/primitives.js +0 -65
  184. package/x/spa/plumbing/primitives.js.map +0 -1
  185. package/x/spa/plumbing/router-core.d.ts +0 -13
  186. package/x/spa/plumbing/router-core.js +0 -38
  187. package/x/spa/plumbing/router-core.js.map +0 -1
  188. package/x/spa/plumbing/types.d.ts +0 -35
  189. package/x/spa/plumbing/types.js +0 -2
  190. package/x/spa/plumbing/types.js.map +0 -1
  191. package/x/spa/router.d.ts +0 -13
  192. package/x/spa/router.js +0 -39
  193. package/x/spa/router.js.map +0 -1
  194. package/x/spa/spa.test.d.ts +0 -15
  195. package/x/spa/spa.test.js +0 -78
  196. package/x/spa/spa.test.js.map +0 -1
  197. package/x/view/utils/contextualize.d.ts +0 -13
  198. package/x/view/utils/contextualize.js +0 -18
  199. package/x/view/utils/contextualize.js.map +0 -1
  200. package/x/view/utils/make-component.d.ts +0 -5
  201. package/x/view/utils/make-component.js +0 -17
  202. package/x/view/utils/make-component.js.map +0 -1
  203. package/x/view/utils/make-view.d.ts +0 -2
  204. package/x/view/utils/make-view.js +0 -32
  205. package/x/view/utils/make-view.js.map +0 -1
  206. package/x/view/utils/parts/capsule.d.ts +0 -12
  207. package/x/view/utils/parts/capsule.js +0 -50
  208. package/x/view/utils/parts/capsule.js.map +0 -1
  209. package/x/view/utils/parts/chain.d.ts +0 -13
  210. package/x/view/utils/parts/chain.js +0 -26
  211. package/x/view/utils/parts/chain.js.map +0 -1
  212. package/x/view/utils/parts/context.d.ts +0 -9
  213. package/x/view/utils/parts/context.js +0 -10
  214. package/x/view/utils/parts/context.js.map +0 -1
  215. package/x/view/utils/parts/directive.d.ts +0 -5
  216. package/x/view/utils/parts/directive.js +0 -20
  217. package/x/view/utils/parts/directive.js.map +0 -1
  218. package/x/view/utils/parts/naked.d.ts +0 -18
  219. package/x/view/utils/parts/naked.js +0 -57
  220. package/x/view/utils/parts/naked.js.map +0 -1
  221. package/x/view/utils/parts/sly-view.d.ts +0 -6
  222. package/x/view/utils/parts/sly-view.js +0 -16
  223. package/x/view/utils/parts/sly-view.js.map +0 -1
  224. package/x/view/view.d.ts +0 -11
  225. package/x/view/view.js +0 -15
  226. package/x/view/view.js.map +0 -1
  227. /package/s/{base → _archive/base}/css-reset.ts +0 -0
  228. /package/s/{base → _archive/base}/index.ts +0 -0
  229. /package/s/{base → _archive/base}/types.ts +0 -0
  230. /package/s/{base → _archive/base}/use.ts +0 -0
  231. /package/s/{base → _archive/base}/utils/apply-styles.ts +0 -0
  232. /package/s/{base → _archive/base}/utils/attr-watcher.ts +0 -0
  233. /package/s/{base → _archive/base}/utils/mounts.ts +0 -0
  234. /package/s/{base → _archive/base}/utils/reactor.ts +0 -0
  235. /package/s/{base → _archive/base}/utils/states.ts +0 -0
  236. /package/s/{base → _archive/base}/utils/use-attrs.ts +0 -0
  237. /package/s/{spa → _archive/spa}/index.barrel.ts +0 -0
  238. /package/s/{spa → _archive/spa}/index.ts +0 -0
  239. /package/s/{spa → _archive/spa}/plumbing/braces.ts +0 -0
  240. /package/s/{spa → _archive/spa}/plumbing/primitives.ts +0 -0
  241. /package/s/{spa → _archive/spa}/plumbing/router-core.ts +0 -0
  242. /package/s/{spa → _archive/spa}/plumbing/types.ts +0 -0
  243. /package/s/{spa → _archive/spa}/router.ts +0 -0
  244. /package/s/{spa → _archive/spa}/spa.test.ts +0 -0
  245. /package/s/{view → _archive/view}/utils/contextualize.ts +0 -0
  246. /package/s/{view → _archive/view}/utils/make-component.ts +0 -0
  247. /package/s/{view → _archive/view}/utils/make-view.ts +0 -0
  248. /package/s/{view → _archive/view}/utils/parts/chain.ts +0 -0
  249. /package/s/{view → _archive/view}/utils/parts/context.ts +0 -0
  250. /package/s/{view → _archive/view}/utils/parts/directive.ts +0 -0
  251. /package/s/{view → _archive/view}/utils/parts/naked.ts +0 -0
  252. /package/s/{view → _archive/view}/utils/parts/sly-view.ts +0 -0
  253. /package/s/{view → _archive/view}/view.ts +0 -0
  254. /package/x/{base → view/common}/css-reset.d.ts +0 -0
  255. /package/x/{base/utils → view/parts}/apply-styles.d.ts +0 -0
  256. /package/x/{base/utils → view/parts}/apply-styles.js +0 -0
@@ -1,5 +1,6 @@
1
1
 
2
2
  import {debounce} from "@e280/stz"
3
+ import type {RootPart} from "lit-html"
3
4
  import {CSSResultGroup} from "lit"
4
5
 
5
6
  import {dom} from "../dom/dom.js"
@@ -18,6 +19,7 @@ export class BaseElement extends HTMLElement {
18
19
  #mountCount = 0
19
20
  #reactor = new Reactor()
20
21
  #attrWatcher = new AttrWatcher(this, () => this.update())
22
+ #part?: RootPart
21
23
 
22
24
  /** create the shadow root. override this if you want to change the shadow root settings. */
23
25
  createShadow() {
@@ -41,7 +43,7 @@ export class BaseElement extends HTMLElement {
41
43
  /** immediately perform a fresh render into the shadow root. */
42
44
  updateNow = () => {
43
45
  this.#use[_wrap](() => {
44
- dom.render(
46
+ this.#part = dom.render(
45
47
  this.shadow,
46
48
  this.#reactor.effect(
47
49
  () => this.render(this.#use),
@@ -62,15 +64,16 @@ export class BaseElement extends HTMLElement {
62
64
  }
63
65
  else {
64
66
  this.#use[_reconnect]()
67
+ this.#part?.setConnected(true)
65
68
  }
66
69
  this.#attrWatcher.start()
67
70
  this.#mountCount++
68
71
  }
69
72
 
70
73
  disconnectedCallback() {
74
+ this.#part?.setConnected(false)
71
75
  this.#use[_disconnect]()
72
76
  this.#reactor.clear()
73
77
  this.#attrWatcher.stop()
74
78
  }
75
79
  }
76
-
@@ -0,0 +1,7 @@
1
+
2
+ export * from "./utils/parts/chain.js"
3
+ export * from "./utils/parts/sly-view.js"
4
+ export * from "./utils/contextualize.js"
5
+ export * from "./types.js"
6
+ export * from "./view.js"
7
+
@@ -0,0 +1,45 @@
1
+
2
+ import {TemplateResult} from "lit"
3
+ import {Constructor} from "@e280/stz"
4
+ import {DirectiveResult} from "lit/directive.js"
5
+
6
+ import {Use} from "../base/use.js"
7
+ import {BaseElement} from "../base/element.js"
8
+ import {ViewChain} from "./utils/parts/chain.js"
9
+
10
+ export type Content = TemplateResult | DirectiveResult | HTMLElement | string | null | undefined | void | Content[]
11
+
12
+ export type ViewFn<Props extends any[]> = (
13
+ (use: Use) =>
14
+ (...props: Props) =>
15
+ Content
16
+ )
17
+
18
+ export type View<Props extends any[]> = {
19
+ (...props: Props): DirectiveResult
20
+ props: (...props: Props) => ViewChain<Props>
21
+ transmute: <PropsB extends any[]>(convert: (...propsB: PropsB) => Props) => View<PropsB>
22
+ component: <B extends Constructor<BaseElement>>(Base?: B) => {
23
+ props: (propFn: (component: InstanceType<B>) => Props) => (
24
+ ComponentClass<B, Props>
25
+ )
26
+ }
27
+ naked: (host: HTMLElement) => NakedView<Props>
28
+ }
29
+
30
+ export type ViewProps<V extends View<any>> = (
31
+ V extends View<infer Props>
32
+ ? Props
33
+ : never
34
+ )
35
+
36
+ export type ComponentClass<B extends Constructor<BaseElement>, Props extends any[]> = {
37
+ view: View<Props>
38
+ new(): InstanceType<B>
39
+ } & B
40
+
41
+ export type NakedView<Props extends any[]> = {
42
+ host: HTMLElement
43
+ render: (...props: Props) => void
44
+ }
45
+
@@ -1,4 +1,5 @@
1
1
 
2
+ import {RootPart} from "lit"
2
3
  import {debounce} from "@e280/stz"
3
4
  import {ViewFn} from "../../types.js"
4
5
  import {dom} from "../../../dom/dom.js"
@@ -17,6 +18,8 @@ export class ViewCapsule<Props extends any[]> {
17
18
  #shadow: ShadowRoot
18
19
  #context!: ViewContext<Props>
19
20
  #attrWatcher: AttrWatcher
21
+ #partShadow?: RootPart
22
+ #partElement?: RootPart
20
23
 
21
24
  constructor(
22
25
  host: HTMLElement,
@@ -47,8 +50,8 @@ export class ViewCapsule<Props extends any[]> {
47
50
  () => this.#renderDebounced(),
48
51
  )
49
52
  attrSet.entries(this.#element, this.#context.attrs)
50
- dom.render(this.#shadow, content)
51
- dom.render(this.#element, this.#context.children)
53
+ this.#partShadow = dom.render(this.#shadow, content)
54
+ this.#partElement = dom.render(this.#element, this.#context.children)
52
55
  this.#attrWatcher.start()
53
56
  })
54
57
  }
@@ -56,6 +59,8 @@ export class ViewCapsule<Props extends any[]> {
56
59
  #renderDebounced = debounce(0, this.#renderNow)
57
60
 
58
61
  disconnected() {
62
+ this.#partShadow?.setConnected(false)
63
+ this.#partElement?.setConnected(false)
59
64
  this.#use[_disconnect]()
60
65
  this.#reactor.clear()
61
66
  this.#attrWatcher.stop()
@@ -64,6 +69,8 @@ export class ViewCapsule<Props extends any[]> {
64
69
  reconnected() {
65
70
  this.#use[_reconnect]()
66
71
  this.#attrWatcher.start()
72
+ this.#partShadow?.setConnected(true)
73
+ this.#partElement?.setConnected(true)
67
74
  }
68
75
  }
69
76
 
@@ -1,14 +1,7 @@
1
1
 
2
2
  import {dom} from "../dom/dom.js"
3
- import {CounterComponent} from "./views/counter.js"
4
- import {DemoComponent} from "./views/demo.js"
5
- import {FastcountElement} from "./views/fastcount.js"
6
-
7
- dom.register({
8
- DemoComponent,
9
- CounterComponent,
10
- FastcountElement,
11
- })
3
+ import {Demo} from "./views/demo.js"
12
4
 
5
+ dom.in(".demo").render(Demo())
13
6
  console.log("🦝 sly")
14
7
 
@@ -0,0 +1,13 @@
1
+
2
+ import {html} from "lit"
3
+ import {light, useSignal} from "../../view/index.js"
4
+
5
+ export const CounterLight = light((start: number) => {
6
+ const $count = useSignal(start)
7
+ const increment = () => $count.value++
8
+
9
+ return html`
10
+ <button @click="${increment}">${$count()}</button>
11
+ `
12
+ })
13
+
@@ -0,0 +1,16 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {shadow, useName, useCss, useSignal} from "../../view/index.js"
4
+
5
+ export const CounterShadow = shadow((start: number) => {
6
+ useName("counter-shadow")
7
+ useCss(css`:host{display:inline-block} button{color:cyan}`)
8
+
9
+ const $count = useSignal(start)
10
+ const increment = () => $count.value++
11
+
12
+ return html`
13
+ <button @click="${increment}">${$count()}</button>
14
+ `
15
+ })
16
+
@@ -1,29 +1,35 @@
1
1
 
2
2
  import {css, html} from "lit"
3
-
4
- import {view} from "../../view/view.js"
5
- import {CounterView} from "./counter.js"
6
3
  import {LoadersView} from "./loaders.js"
7
- import {cssReset} from "../../base/css-reset.js"
4
+ import {CounterLight} from "./counter-light.js"
5
+ import {CounterShadow} from "./counter-shadow.js"
6
+ import {cssReset, shadow, useName, useStyles} from "../../view/index.js"
7
+
8
+ export const Demo = shadow(() => {
9
+ useName("demo")
10
+ useStyles(cssReset, styles)
8
11
 
9
- export class DemoComponent extends (view.component(use => {
10
- use.name("demo")
11
- use.styles(cssReset, styles)
12
12
  return html`
13
- ${CounterView
14
- .props(768, 3)
15
- .children("view")
16
- .render()}
13
+ <p>light ${CounterLight(123)}</p>
14
+
15
+ <p>
16
+ shadow ${CounterShadow.with({
17
+ props: [234],
18
+ attrs: {"data-lol": 555},
19
+ children: html`<p>hello</p>`,
20
+ })}
21
+ </p>
22
+
17
23
  ${LoadersView()}
18
24
  `
19
- })) {}
25
+ })
20
26
 
21
27
  const styles = css`
22
- :host {
23
- display: flex;
24
- flex-direction: column;
25
- align-items: center;
26
- gap: 1em;
27
- }
28
+ :host {
29
+ display: flex;
30
+ flex-direction: column;
31
+ align-items: center;
32
+ gap: 1em;
33
+ }
28
34
  `
29
35
 
@@ -1,17 +1,17 @@
1
1
 
2
2
  import {css, html} from "lit"
3
3
  import {Op} from "../../ops/op.js"
4
- import {view} from "../../view/view.js"
4
+ import {shadow} from "../../view/shadow.js"
5
5
  import {loaders} from "../../loaders/index.js"
6
- import {cssReset} from "../../base/css-reset.js"
6
+ import {cssReset, useName, useOnce, useStyles} from "../../view/index.js"
7
7
 
8
- export const LoadersView = view(use => () => {
9
- use.name("loaders")
10
- use.styles(cssReset, styles)
8
+ export const LoadersView = shadow(() => {
9
+ useName("loaders")
10
+ useStyles(cssReset, styles)
11
11
 
12
- const op = use.once(() => Op.loading())
12
+ const op = useOnce(() => Op.loading())
13
13
 
14
- const library = use.once(() =>
14
+ const library = useOnce(() =>
15
15
  Object.entries(loaders.anims).map(([key, anim]) => ({
16
16
  key,
17
17
  loader: loaders.make(anim)
package/s/index.html.ts CHANGED
@@ -1,38 +1,35 @@
1
1
 
2
- import {ssg, html} from "@e280/scute"
2
+ import {template, html, socialCard} from "@e280/scute"
3
3
 
4
- const title = "sly"
5
- const description = "mischievous shadow views"
6
- const domain = "sly.e280.org"
7
- const favicon = "/assets/favicon.png"
4
+ export default template(import.meta.url, async orb => html`
5
+ <!doctype html>
6
+ <html>
7
+ <head>
8
+ <meta charset="utf-8"/>
9
+ <meta name="viewport" content="width=device-width,initial-scale=1"/>
10
+ <meta name="darkreader-lock"/>
11
+ <style>@layer base{html{background:#000}}</style>
8
12
 
9
- export default ssg.page(import.meta.url, async orb => ({
10
- title,
11
- js: "demo/demo.bundle.min.js",
12
- css: "demo/demo.css",
13
- favicon,
14
- dark: true,
15
- socialCard: {
16
- themeColor: "#95ff7b",
17
- title,
18
- description,
19
- siteName: "@e280/sly",
20
- image: "https://" + domain + favicon,
21
- },
13
+ <title>sly</title>
14
+ <link rel="icon" href="/assets/favicon.png"/>
15
+ <link rel="stylesheet" href="${orb.hashurl("demo/demo.css")}"/>
16
+ <script type="module" src="${orb.hashurl("demo/demo.bundle.min.js")}"></script>
22
17
 
23
- head: html`
24
- <meta name="example" value="whatever"/>
25
- `,
26
-
27
- body: html`
28
- <img class=icon alt="" src="/assets/favicon.png"/>
29
- <h1>sly testing page</h1>
30
- <p><a href="https://github.com/e280/sly">github.com/e280/sly</a></p>
31
- <p class=lil>v${orb.packageVersion()}</p>
32
-
33
- <fastcount-element></fastcount-element>
34
- <counter-component start=280 step=2>component</counter-component>
35
- <demo-component></demo-component>
36
- `,
37
- }))
18
+ ${socialCard({
19
+ themeColor: "#95ff7b",
20
+ title: "sly",
21
+ description: "mischievous shadow views",
22
+ siteName: "@e280/sly",
23
+ image: "https://sly.e280.org/assets/favicon.png",
24
+ })}
25
+ </head>
26
+ <body>
27
+ <img class=icon alt="" src="/assets/favicon.png"/>
28
+ <h1>sly testing page</h1>
29
+ <p><a href="https://github.com/e280/sly">github.com/e280/sly</a></p>
30
+ <p class=lil>v${orb.packageVersion()}</p>
31
+ <div class="demo"></div>
32
+ </body>
33
+ </html>
34
+ `)
38
35
 
package/s/index.ts CHANGED
@@ -1,9 +1,7 @@
1
1
 
2
- export * from "./base/index.js"
3
2
  export * from "./dom/index.js"
4
3
  export * from "./loaders/index.js"
5
4
  export * from "./loot/index.js"
6
5
  export * from "./ops/index.js"
7
- export * from "./spa/index.js"
8
6
  export * from "./view/index.js"
9
7
 
package/s/loaders/make.ts CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  import {Loader} from "./types.js"
3
3
  import {earth} from "./parts/anims.js"
4
- import type {Content} from "../view/types.js"
4
+ import {Content} from "../view/types.js"
5
5
  import {ErrorDisplay} from "./parts/error-display.js"
6
6
 
7
7
  export function make(
@@ -1,26 +1,24 @@
1
1
 
2
2
  import {css} from "lit"
3
3
  import {nap, cycle} from "@e280/stz"
4
-
5
- import {view} from "../../view/view.js"
6
4
  import {Content} from "../../view/types.js"
7
- import {cssReset} from "../../base/css-reset.js"
5
+ import {cssReset, shadow, useMount, useName, useSignal, useStyles} from "../../view/index.js"
8
6
 
9
7
  export function makeAsciiAnim(hz: number, frames: string[]): () => Content {
10
8
  return () => AsciiAnim({hz, frames})
11
9
  }
12
10
 
13
- export const AsciiAnim = view(use => ({hz, frames}: {
11
+ export const AsciiAnim = shadow(({hz, frames}: {
14
12
  hz: number,
15
13
  frames: string[],
16
14
  }) => {
17
15
 
18
- use.name("loading")
19
- use.styles(cssReset, style)
16
+ useName("loading")
17
+ useStyles(cssReset, style)
20
18
 
21
- const frame = use.signal(0)
19
+ const frame = useSignal(0)
22
20
 
23
- use.mount(() => cycle(async() => {
21
+ useMount(() => cycle(async() => {
24
22
  await nap(1000 / hz)
25
23
  const next = frame.get() + 1
26
24
  frame.set(next >= frames.length ? 0 : next)
@@ -1,11 +1,11 @@
1
1
 
2
2
  import {css, html} from "lit"
3
- import {view} from "../../view/view.js"
4
- import {cssReset} from "../../base/css-reset.js"
3
+ import {shadow} from "../../view/shadow.js"
4
+ import {cssReset, useName, useStyles} from "../../view/index.js"
5
5
 
6
- export const ErrorDisplay = view(use => (error: any) => {
7
- use.name("error")
8
- use.styles(cssReset, style)
6
+ export const ErrorDisplay = shadow((error: any) => {
7
+ useName("error")
8
+ useStyles(cssReset, style)
9
9
 
10
10
  if (typeof error === "string")
11
11
  return error
@@ -18,9 +18,9 @@ export const ErrorDisplay = view(use => (error: any) => {
18
18
  })
19
19
 
20
20
  const style = css`
21
- :host {
22
- font-family: monospace;
23
- color: red;
24
- }
21
+ :host {
22
+ font-family: monospace;
23
+ color: red;
24
+ }
25
25
  `
26
26
 
package/s/tests.test.ts CHANGED
@@ -1,8 +1,5 @@
1
1
 
2
2
  import {Science} from "@e280/science"
3
- import spa from "./spa/spa.test.js"
4
3
 
5
- await Science.run({
6
- spa,
7
- })
4
+ await Science.run({})
8
5
 
@@ -0,0 +1,19 @@
1
+
2
+ import {css, CSSResultGroup} from "lit"
3
+
4
+ export const cssReset: CSSResultGroup = css`
5
+ * {
6
+ margin: 0;
7
+ padding: 0;
8
+ box-sizing: border-box;
9
+
10
+ scrollbar-width: thin;
11
+ scrollbar-color: #888 transparent;
12
+ }
13
+
14
+ ::-webkit-scrollbar { width: 8px; }
15
+ ::-webkit-scrollbar-track { background: transparent; }
16
+ ::-webkit-scrollbar-thumb { background: #888; border-radius: 1em; }
17
+ ::-webkit-scrollbar-thumb:hover { background: #999; }
18
+ `
19
+
@@ -0,0 +1,28 @@
1
+
2
+ import {Hookscope} from "./hookscope.js"
3
+
4
+ export class Hooks {
5
+ #scopes: Hookscope[] = []
6
+
7
+ get scope() {
8
+ const scope = this.#scopes.at(-1)
9
+ if (!scope) throw new Error("hooks must be called within a render fn")
10
+ return scope
11
+ }
12
+
13
+ increment() {
14
+ const scope = this.scope
15
+ const position = scope.position++
16
+ return {scope, position}
17
+ }
18
+
19
+ wrap<Ret>(scope: Hookscope, fn: () => Ret) {
20
+ scope.position = 0
21
+ this.#scopes.push(scope)
22
+ try { return fn() }
23
+ finally { this.#scopes.pop() }
24
+ }
25
+ }
26
+
27
+ export const hooks: Hooks = (globalThis as any)[Symbol.for("e280.hooks")] ??= new Hooks()
28
+
@@ -0,0 +1,12 @@
1
+
2
+ import {GMap} from "@e280/stz"
3
+ import {Mounts} from "../use-mount.js"
4
+ import {LightCx, ShadowCx} from "../../parts/cx.js"
5
+
6
+ export class Hookscope {
7
+ position = 0
8
+ values = new GMap<number, any>()
9
+ mounts = new Mounts()
10
+ constructor(public cx: LightCx | ShadowCx) {}
11
+ }
12
+
@@ -0,0 +1,14 @@
1
+
2
+ import {CSSResultGroup} from "lit"
3
+ import {useShadow} from "./use-cx.js"
4
+ import {useOnce} from "./use-once.js"
5
+ import {applyStyles} from "../parts/apply-styles.js"
6
+
7
+ /** attach stylesheets to the shadow root */
8
+ export function useCss(...styles: CSSResultGroup[]) {
9
+ const shadow = useShadow()
10
+ useOnce(() => applyStyles(shadow, styles))
11
+ }
12
+
13
+ export const useStyles = useCss
14
+
@@ -0,0 +1,41 @@
1
+
2
+ import {ShadowCx} from "../parts/cx.js"
3
+ import {hooks} from "./plumbing/hooks.js"
4
+
5
+ function useCx() {
6
+ const {scope} = hooks.increment()
7
+ return scope.cx
8
+ }
9
+
10
+ function useShadowCx() {
11
+ const cx = useCx()
12
+ if (!(cx instanceof ShadowCx))
13
+ throw new Error("this hook only works on shadow views (but was called in a light view)")
14
+ return cx
15
+ }
16
+
17
+ /** return the current count of how many times this view has been rendered (starts at 0) */
18
+ export function useCount() {
19
+ return useCx().count
20
+ }
21
+
22
+ /** return a function that triggers the view to rerender */
23
+ export function useRender() {
24
+ return useCx().render
25
+ }
26
+
27
+ /** return a promise that resolves after the next render is complete */
28
+ export function useRendered() {
29
+ return useCx().rendered.promise
30
+ }
31
+
32
+ /** return the shadow view's host element */
33
+ export function useHost() {
34
+ return useShadowCx().host
35
+ }
36
+
37
+ /** return the shadow root */
38
+ export function useShadow() {
39
+ return useShadowCx().shadow
40
+ }
41
+
@@ -0,0 +1,17 @@
1
+
2
+ import {useRef} from "./use-ref.js"
3
+ import {useMount} from "./use-mount.js"
4
+
5
+ /** mount/unmount lifecycle, but also return a value */
6
+ export function useLife<Value>(fn: () => [value: Value, dispose: () => void]) {
7
+ const ref = useRef<Value>(undefined as Value)
8
+
9
+ useMount(() => {
10
+ const [value, dispose] = fn()
11
+ ref.value = value
12
+ return dispose
13
+ })
14
+
15
+ return ref.value
16
+ }
17
+
@@ -0,0 +1,30 @@
1
+
2
+ import {useOnce} from "./use-once.js"
3
+ import {hooks} from "./plumbing/hooks.js"
4
+
5
+ export function useMount(fn: () => () => void) {
6
+ const {scope} = hooks.increment()
7
+ return useOnce(() => scope.mounts.mount(fn))
8
+ }
9
+
10
+ export class Mounts {
11
+ #mounters: (() => () => void)[] = []
12
+ #unmounters: (() => void)[] = []
13
+
14
+ mount(mount: () => () => void) {
15
+ this.#mounters.push(mount)
16
+ this.#unmounters.push(mount())
17
+ }
18
+
19
+ unmountAll() {
20
+ for (const unmount of this.#unmounters)
21
+ unmount()
22
+ this.#unmounters = []
23
+ }
24
+
25
+ remountAll() {
26
+ for (const mount of this.#mounters)
27
+ this.#unmounters.push(mount())
28
+ }
29
+ }
30
+
@@ -0,0 +1,10 @@
1
+
2
+ import {useHost} from "./use-cx.js"
3
+ import {useOnce} from "./use-once.js"
4
+
5
+ /** sets the host element's "data-view" attribute */
6
+ export function useName(name = "") {
7
+ const host = useHost()
8
+ useOnce(() => host.setAttribute("view", name))
9
+ }
10
+
@@ -0,0 +1,9 @@
1
+
2
+ import {hooks} from "./plumbing/hooks.js"
3
+
4
+ /** run the fn only one time */
5
+ export function useOnce<Value>(fn: () => Value) {
6
+ const {scope, position} = hooks.increment()
7
+ return scope.values.guarantee(position, fn) as Value
8
+ }
9
+
@@ -0,0 +1,12 @@
1
+
2
+ import {Op} from "../../ops/op.js"
3
+ import {useOnce} from "./use-once.js"
4
+
5
+ export function useOp<Value>(fn: () => Promise<Value>) {
6
+ return useOnce(() => Op.load(fn))
7
+ }
8
+
9
+ export function useOpPromise<Value>(promise: Promise<Value>) {
10
+ return useOnce(() => Op.promise(promise))
11
+ }
12
+
@@ -0,0 +1,11 @@
1
+
2
+ import {useOnce} from "./use-once.js"
3
+
4
+ export function useRef<Value>(value: Value) {
5
+ return useOnce(() => new Ref(value))
6
+ }
7
+
8
+ export class Ref<Value> {
9
+ constructor(public value: Value) {}
10
+ }
11
+
@@ -0,0 +1,16 @@
1
+
2
+ import {signal} from "@e280/strata"
3
+ import {useOnce} from "./use-once.js"
4
+
5
+ export function useSignal<Value>(value: Value) {
6
+ return useOnce(() => signal(value))
7
+ }
8
+
9
+ export function useDerived<Value>(fn: () => Value) {
10
+ return useOnce(() => signal.derived(fn))
11
+ }
12
+
13
+ export function useLazy<Value>(fn: () => Value) {
14
+ return useOnce(() => signal.lazy(fn))
15
+ }
16
+