@e280/sly 0.2.5 → 0.3.0-10

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 (350) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +356 -626
  3. package/package.json +22 -30
  4. package/s/_archive/README.md +1221 -0
  5. package/s/_archive/view/index.ts +7 -0
  6. package/s/_archive/view/types.ts +45 -0
  7. package/s/demo/demo.bundle.ts +5 -8
  8. package/s/demo/views/counter-light.ts +13 -0
  9. package/s/demo/views/counter-shadow.ts +16 -0
  10. package/s/demo/views/demo.ts +24 -20
  11. package/s/demo/views/loaders.ts +9 -9
  12. package/s/demo/views/time-light.ts +19 -0
  13. package/s/demo/views/time-shadow.ts +22 -0
  14. package/s/dom/attrs/attrs.ts +3 -3
  15. package/s/dom/attrs/parts/attr-spec.ts +17 -5
  16. package/s/dom/attrs/parts/on-attrs.ts +1 -1
  17. package/s/dom/dom.ts +1 -1
  18. package/s/index.html.ts +30 -33
  19. package/s/index.ts +2 -4
  20. package/s/{loaders → loader}/index.barrel.ts +0 -1
  21. package/s/{loaders → loader}/index.ts +0 -1
  22. package/s/{loaders → loader}/make.ts +1 -1
  23. package/s/{loaders → loader}/parts/ascii-anim.ts +6 -8
  24. package/s/loader/parts/error-display.ts +26 -0
  25. package/s/{loaders → loader}/types.ts +1 -1
  26. package/s/test.ts +5 -0
  27. package/s/view/common/css-reset.ts +19 -0
  28. package/s/view/common/sly-shadow.ts +14 -0
  29. package/s/view/elements/light.ts +14 -0
  30. package/s/view/elements/shadow.ts +52 -0
  31. package/s/view/hooks/plumbing/hooks.ts +28 -0
  32. package/s/view/hooks/plumbing/hookscope.ts +12 -0
  33. package/s/view/hooks/use-attrs.ts +28 -0
  34. package/s/view/hooks/use-css.ts +14 -0
  35. package/s/view/hooks/use-cx.ts +41 -0
  36. package/s/view/hooks/use-life.ts +17 -0
  37. package/s/view/hooks/use-mount.ts +30 -0
  38. package/s/view/hooks/use-name.ts +10 -0
  39. package/s/view/hooks/use-once.ts +9 -0
  40. package/s/view/hooks/use-op.ts +12 -0
  41. package/s/view/hooks/use-ref.ts +11 -0
  42. package/s/view/hooks/use-signal.ts +16 -0
  43. package/s/view/hooks/use-state.ts +20 -0
  44. package/s/view/hooks/use-wake.ts +8 -0
  45. package/s/view/index.ts +22 -4
  46. package/s/view/light.ts +50 -0
  47. package/s/view/parts/apply-attrs.ts +22 -0
  48. package/s/view/parts/apply-styles.ts +21 -0
  49. package/s/view/parts/cx.ts +26 -0
  50. package/s/view/parts/reactivity.ts +22 -0
  51. package/s/view/shadow.ts +93 -0
  52. package/s/view/types.ts +15 -34
  53. package/x/demo/demo.bundle.js +5 -8
  54. package/x/demo/demo.bundle.js.map +1 -1
  55. package/x/demo/demo.bundle.min.js +52 -63
  56. package/x/demo/demo.bundle.min.js.map +4 -4
  57. package/x/demo/views/counter-light.d.ts +1 -0
  58. package/x/demo/views/counter-light.js +10 -0
  59. package/x/demo/views/counter-light.js.map +1 -0
  60. package/x/demo/views/counter-shadow.d.ts +1 -0
  61. package/x/demo/views/counter-shadow.js +12 -0
  62. package/x/demo/views/counter-shadow.js.map +1 -0
  63. package/x/demo/views/demo.d.ts +1 -4
  64. package/x/demo/views/demo.js +24 -20
  65. package/x/demo/views/demo.js.map +1 -1
  66. package/x/demo/views/loaders.d.ts +1 -1
  67. package/x/demo/views/loaders.js +9 -9
  68. package/x/demo/views/loaders.js.map +1 -1
  69. package/x/demo/views/{counter.d.ts → time-light.d.ts} +3 -19
  70. package/x/demo/views/time-light.js +16 -0
  71. package/x/demo/views/time-light.js.map +1 -0
  72. package/x/demo/views/time-shadow.d.ts +365 -0
  73. package/x/demo/views/time-shadow.js +18 -0
  74. package/x/demo/views/time-shadow.js.map +1 -0
  75. package/x/dom/attrs/attrs.d.ts +3 -2
  76. package/x/dom/attrs/attrs.js +2 -2
  77. package/x/dom/attrs/attrs.js.map +1 -1
  78. package/x/dom/attrs/parts/attr-spec.d.ts +5 -1
  79. package/x/dom/attrs/parts/attr-spec.js +12 -6
  80. package/x/dom/attrs/parts/attr-spec.js.map +1 -1
  81. package/x/dom/attrs/parts/on-attrs.d.ts +1 -1
  82. package/x/dom/attrs/parts/on-attrs.js.map +1 -1
  83. package/x/dom/dom.d.ts +1 -1
  84. package/x/dom/dom.js.map +1 -1
  85. package/x/index.d.ts +2 -4
  86. package/x/index.html +30 -140
  87. package/x/index.html.js +31 -31
  88. package/x/index.html.js.map +1 -1
  89. package/x/index.js +2 -4
  90. package/x/index.js.map +1 -1
  91. package/x/{loaders → loader}/index.barrel.d.ts +0 -1
  92. package/x/loader/index.barrel.js.map +1 -0
  93. package/x/{loaders → loader}/index.d.ts +0 -1
  94. package/x/loader/index.js.map +1 -0
  95. package/x/{loaders → loader}/make.d.ts +1 -1
  96. package/x/loader/make.js.map +1 -0
  97. package/x/loader/mock.js.map +1 -0
  98. package/x/loader/parts/anims.js.map +1 -0
  99. package/x/{loaders → loader}/parts/ascii-anim.d.ts +1 -1
  100. package/x/{loaders → loader}/parts/ascii-anim.js +6 -7
  101. package/x/loader/parts/ascii-anim.js.map +1 -0
  102. package/x/loader/parts/error-display.d.ts +1 -0
  103. package/x/loader/parts/error-display.js +20 -0
  104. package/x/loader/parts/error-display.js.map +1 -0
  105. package/x/{loaders → loader}/types.d.ts +1 -1
  106. package/x/{loaders → loader}/types.js.map +1 -1
  107. package/x/loot/drag-and-drops.d.ts +2 -2
  108. package/x/loot/drops.d.ts +1 -1
  109. package/x/op/index.js.map +1 -0
  110. package/x/op/op.js.map +1 -0
  111. package/x/op/podium.js.map +1 -0
  112. package/x/{ops → op}/types.js.map +1 -1
  113. package/x/test.js +3 -0
  114. package/x/test.js.map +1 -0
  115. package/x/view/common/css-reset.js +17 -0
  116. package/x/view/common/css-reset.js.map +1 -0
  117. package/x/view/common/sly-shadow.d.ts +4 -0
  118. package/x/view/common/sly-shadow.js +11 -0
  119. package/x/view/common/sly-shadow.js.map +1 -0
  120. package/x/view/elements/light.d.ts +357 -0
  121. package/x/view/elements/light.js +10 -0
  122. package/x/view/elements/light.js.map +1 -0
  123. package/x/view/elements/shadow.d.ts +366 -0
  124. package/x/view/elements/shadow.js +42 -0
  125. package/x/view/elements/shadow.js.map +1 -0
  126. package/x/view/hooks/plumbing/hooks.d.ts +11 -0
  127. package/x/view/hooks/plumbing/hooks.js +26 -0
  128. package/x/view/hooks/plumbing/hooks.js.map +1 -0
  129. package/x/view/hooks/plumbing/hookscope.d.ts +10 -0
  130. package/x/view/hooks/plumbing/hookscope.js +12 -0
  131. package/x/view/hooks/plumbing/hookscope.js.map +1 -0
  132. package/x/view/hooks/use-attrs.d.ts +2 -0
  133. package/x/view/hooks/use-attrs.js +23 -0
  134. package/x/view/hooks/use-attrs.js.map +1 -0
  135. package/x/view/hooks/use-css.d.ts +4 -0
  136. package/x/view/hooks/use-css.js +10 -0
  137. package/x/view/hooks/use-css.js.map +1 -0
  138. package/x/view/hooks/use-cx.d.ts +10 -0
  139. package/x/view/hooks/use-cx.js +33 -0
  140. package/x/view/hooks/use-cx.js.map +1 -0
  141. package/x/view/hooks/use-life.d.ts +2 -0
  142. package/x/view/hooks/use-life.js +13 -0
  143. package/x/view/hooks/use-life.js.map +1 -0
  144. package/x/{base/utils/mounts.d.ts → view/hooks/use-mount.d.ts} +1 -0
  145. package/x/{base/utils/mounts.js → view/hooks/use-mount.js} +7 -1
  146. package/x/view/hooks/use-mount.js.map +1 -0
  147. package/x/view/hooks/use-name.d.ts +2 -0
  148. package/x/view/hooks/use-name.js +8 -0
  149. package/x/view/hooks/use-name.js.map +1 -0
  150. package/x/view/hooks/use-once.d.ts +2 -0
  151. package/x/view/hooks/use-once.js +7 -0
  152. package/x/view/hooks/use-once.js.map +1 -0
  153. package/x/view/hooks/use-op.d.ts +3 -0
  154. package/x/view/hooks/use-op.js +9 -0
  155. package/x/view/hooks/use-op.js.map +1 -0
  156. package/x/view/hooks/use-ref.d.ts +5 -0
  157. package/x/view/hooks/use-ref.js +11 -0
  158. package/x/view/hooks/use-ref.js.map +1 -0
  159. package/x/view/hooks/use-signal.d.ts +3 -0
  160. package/x/view/hooks/use-signal.js +12 -0
  161. package/x/view/hooks/use-signal.js.map +1 -0
  162. package/x/view/hooks/use-state.d.ts +1 -0
  163. package/x/view/hooks/use-state.js +17 -0
  164. package/x/view/hooks/use-state.js.map +1 -0
  165. package/x/view/hooks/use-wake.d.ts +2 -0
  166. package/x/view/hooks/use-wake.js +6 -0
  167. package/x/view/hooks/use-wake.js.map +1 -0
  168. package/x/view/index.d.ts +19 -4
  169. package/x/view/index.js +19 -4
  170. package/x/view/index.js.map +1 -1
  171. package/x/view/light.d.ts +2 -0
  172. package/x/view/light.js +41 -0
  173. package/x/view/light.js.map +1 -0
  174. package/x/view/parts/apply-attrs.d.ts +2 -0
  175. package/x/view/parts/apply-attrs.js +22 -0
  176. package/x/view/parts/apply-attrs.js.map +1 -0
  177. package/x/{base/utils → view/parts}/apply-styles.js.map +1 -1
  178. package/x/view/parts/cx.d.ts +12 -0
  179. package/x/view/parts/cx.js +24 -0
  180. package/x/view/parts/cx.js.map +1 -0
  181. package/x/view/parts/reactivity.d.ts +5 -0
  182. package/x/view/parts/reactivity.js +18 -0
  183. package/x/view/parts/reactivity.js.map +1 -0
  184. package/x/view/shadow.d.ts +6 -0
  185. package/x/view/shadow.js +71 -0
  186. package/x/view/shadow.js.map +1 -0
  187. package/x/view/types.d.ts +13 -21
  188. package/s/demo/views/counter.ts +0 -50
  189. package/s/demo/views/fastcount.ts +0 -29
  190. package/s/demo/views/mounting.ts +0 -36
  191. package/s/loaders/parts/error-display.ts +0 -26
  192. package/s/tests.test.ts +0 -8
  193. package/x/base/css-reset.js +0 -19
  194. package/x/base/css-reset.js.map +0 -1
  195. package/x/base/element.d.ts +0 -19
  196. package/x/base/element.js +0 -55
  197. package/x/base/element.js.map +0 -1
  198. package/x/base/index.d.ts +0 -5
  199. package/x/base/index.js +0 -6
  200. package/x/base/index.js.map +0 -1
  201. package/x/base/types.d.ts +0 -3
  202. package/x/base/types.js +0 -3
  203. package/x/base/types.js.map +0 -1
  204. package/x/base/use.d.ts +0 -59
  205. package/x/base/use.js +0 -129
  206. package/x/base/use.js.map +0 -1
  207. package/x/base/utils/attr-watcher.d.ts +0 -8
  208. package/x/base/utils/attr-watcher.js +0 -20
  209. package/x/base/utils/attr-watcher.js.map +0 -1
  210. package/x/base/utils/mounts.js.map +0 -1
  211. package/x/base/utils/reactor.d.ts +0 -5
  212. package/x/base/utils/reactor.js +0 -25
  213. package/x/base/utils/reactor.js.map +0 -1
  214. package/x/base/utils/states.d.ts +0 -13
  215. package/x/base/utils/states.js +0 -41
  216. package/x/base/utils/states.js.map +0 -1
  217. package/x/base/utils/use-attrs.d.ts +0 -11
  218. package/x/base/utils/use-attrs.js +0 -18
  219. package/x/base/utils/use-attrs.js.map +0 -1
  220. package/x/demo/views/counter.js +0 -42
  221. package/x/demo/views/counter.js.map +0 -1
  222. package/x/demo/views/fastcount.d.ts +0 -12
  223. package/x/demo/views/fastcount.js +0 -21
  224. package/x/demo/views/fastcount.js.map +0 -1
  225. package/x/demo/views/mounting.d.ts +0 -3
  226. package/x/demo/views/mounting.js +0 -28
  227. package/x/demo/views/mounting.js.map +0 -1
  228. package/x/loaders/index.barrel.js.map +0 -1
  229. package/x/loaders/index.js.map +0 -1
  230. package/x/loaders/make.js.map +0 -1
  231. package/x/loaders/mock.js.map +0 -1
  232. package/x/loaders/parts/anims.js.map +0 -1
  233. package/x/loaders/parts/ascii-anim.js.map +0 -1
  234. package/x/loaders/parts/error-display.d.ts +0 -1
  235. package/x/loaders/parts/error-display.js +0 -20
  236. package/x/loaders/parts/error-display.js.map +0 -1
  237. package/x/ops/index.js.map +0 -1
  238. package/x/ops/op.js.map +0 -1
  239. package/x/ops/podium.js.map +0 -1
  240. package/x/spa/index.barrel.d.ts +0 -4
  241. package/x/spa/index.barrel.js +0 -3
  242. package/x/spa/index.barrel.js.map +0 -1
  243. package/x/spa/index.d.ts +0 -2
  244. package/x/spa/index.js +0 -2
  245. package/x/spa/index.js.map +0 -1
  246. package/x/spa/plumbing/braces.d.ts +0 -12
  247. package/x/spa/plumbing/braces.js +0 -55
  248. package/x/spa/plumbing/braces.js.map +0 -1
  249. package/x/spa/plumbing/primitives.d.ts +0 -22
  250. package/x/spa/plumbing/primitives.js +0 -65
  251. package/x/spa/plumbing/primitives.js.map +0 -1
  252. package/x/spa/plumbing/router-core.d.ts +0 -13
  253. package/x/spa/plumbing/router-core.js +0 -38
  254. package/x/spa/plumbing/router-core.js.map +0 -1
  255. package/x/spa/plumbing/types.d.ts +0 -35
  256. package/x/spa/plumbing/types.js +0 -2
  257. package/x/spa/plumbing/types.js.map +0 -1
  258. package/x/spa/router.d.ts +0 -13
  259. package/x/spa/router.js +0 -39
  260. package/x/spa/router.js.map +0 -1
  261. package/x/spa/spa.test.d.ts +0 -15
  262. package/x/spa/spa.test.js +0 -78
  263. package/x/spa/spa.test.js.map +0 -1
  264. package/x/tests.test.js +0 -6
  265. package/x/tests.test.js.map +0 -1
  266. package/x/view/utils/contextualize.d.ts +0 -13
  267. package/x/view/utils/contextualize.js +0 -18
  268. package/x/view/utils/contextualize.js.map +0 -1
  269. package/x/view/utils/make-component.d.ts +0 -5
  270. package/x/view/utils/make-component.js +0 -17
  271. package/x/view/utils/make-component.js.map +0 -1
  272. package/x/view/utils/make-view.d.ts +0 -2
  273. package/x/view/utils/make-view.js +0 -32
  274. package/x/view/utils/make-view.js.map +0 -1
  275. package/x/view/utils/parts/capsule.d.ts +0 -12
  276. package/x/view/utils/parts/capsule.js +0 -56
  277. package/x/view/utils/parts/capsule.js.map +0 -1
  278. package/x/view/utils/parts/chain.d.ts +0 -13
  279. package/x/view/utils/parts/chain.js +0 -26
  280. package/x/view/utils/parts/chain.js.map +0 -1
  281. package/x/view/utils/parts/context.d.ts +0 -9
  282. package/x/view/utils/parts/context.js +0 -10
  283. package/x/view/utils/parts/context.js.map +0 -1
  284. package/x/view/utils/parts/directive.d.ts +0 -5
  285. package/x/view/utils/parts/directive.js +0 -20
  286. package/x/view/utils/parts/directive.js.map +0 -1
  287. package/x/view/utils/parts/naked.d.ts +0 -18
  288. package/x/view/utils/parts/naked.js +0 -57
  289. package/x/view/utils/parts/naked.js.map +0 -1
  290. package/x/view/utils/parts/sly-view.d.ts +0 -6
  291. package/x/view/utils/parts/sly-view.js +0 -16
  292. package/x/view/utils/parts/sly-view.js.map +0 -1
  293. package/x/view/view.d.ts +0 -11
  294. package/x/view/view.js +0 -15
  295. package/x/view/view.js.map +0 -1
  296. /package/s/{base → _archive/base}/css-reset.ts +0 -0
  297. /package/s/{base → _archive/base}/element.ts +0 -0
  298. /package/s/{base → _archive/base}/index.ts +0 -0
  299. /package/s/{base → _archive/base}/types.ts +0 -0
  300. /package/s/{base → _archive/base}/use.ts +0 -0
  301. /package/s/{base → _archive/base}/utils/apply-styles.ts +0 -0
  302. /package/s/{base → _archive/base}/utils/attr-watcher.ts +0 -0
  303. /package/s/{base → _archive/base}/utils/mounts.ts +0 -0
  304. /package/s/{base → _archive/base}/utils/reactor.ts +0 -0
  305. /package/s/{base → _archive/base}/utils/states.ts +0 -0
  306. /package/s/{base → _archive/base}/utils/use-attrs.ts +0 -0
  307. /package/s/{spa → _archive/spa}/index.barrel.ts +0 -0
  308. /package/s/{spa → _archive/spa}/index.ts +0 -0
  309. /package/s/{spa → _archive/spa}/plumbing/braces.ts +0 -0
  310. /package/s/{spa → _archive/spa}/plumbing/primitives.ts +0 -0
  311. /package/s/{spa → _archive/spa}/plumbing/router-core.ts +0 -0
  312. /package/s/{spa → _archive/spa}/plumbing/types.ts +0 -0
  313. /package/s/{spa → _archive/spa}/router.ts +0 -0
  314. /package/s/{spa → _archive/spa}/spa.test.ts +0 -0
  315. /package/s/{view → _archive/view}/utils/contextualize.ts +0 -0
  316. /package/s/{view → _archive/view}/utils/make-component.ts +0 -0
  317. /package/s/{view → _archive/view}/utils/make-view.ts +0 -0
  318. /package/s/{view → _archive/view}/utils/parts/capsule.ts +0 -0
  319. /package/s/{view → _archive/view}/utils/parts/chain.ts +0 -0
  320. /package/s/{view → _archive/view}/utils/parts/context.ts +0 -0
  321. /package/s/{view → _archive/view}/utils/parts/directive.ts +0 -0
  322. /package/s/{view → _archive/view}/utils/parts/naked.ts +0 -0
  323. /package/s/{view → _archive/view}/utils/parts/sly-view.ts +0 -0
  324. /package/s/{view → _archive/view}/view.ts +0 -0
  325. /package/s/{loaders → loader}/mock.ts +0 -0
  326. /package/s/{loaders → loader}/parts/anims.ts +0 -0
  327. /package/s/{ops → op}/index.ts +0 -0
  328. /package/s/{ops → op}/op.ts +0 -0
  329. /package/s/{ops → op}/podium.ts +0 -0
  330. /package/s/{ops → op}/types.ts +0 -0
  331. /package/x/{loaders → loader}/index.barrel.js +0 -0
  332. /package/x/{loaders → loader}/index.js +0 -0
  333. /package/x/{loaders → loader}/make.js +0 -0
  334. /package/x/{loaders → loader}/mock.d.ts +0 -0
  335. /package/x/{loaders → loader}/mock.js +0 -0
  336. /package/x/{loaders → loader}/parts/anims.d.ts +0 -0
  337. /package/x/{loaders → loader}/parts/anims.js +0 -0
  338. /package/x/{loaders → loader}/types.js +0 -0
  339. /package/x/{ops → op}/index.d.ts +0 -0
  340. /package/x/{ops → op}/index.js +0 -0
  341. /package/x/{ops → op}/op.d.ts +0 -0
  342. /package/x/{ops → op}/op.js +0 -0
  343. /package/x/{ops → op}/podium.d.ts +0 -0
  344. /package/x/{ops → op}/podium.js +0 -0
  345. /package/x/{ops → op}/types.d.ts +0 -0
  346. /package/x/{ops → op}/types.js +0 -0
  347. /package/x/{tests.test.d.ts → test.d.ts} +0 -0
  348. /package/x/{base → view/common}/css-reset.d.ts +0 -0
  349. /package/x/{base/utils → view/parts}/apply-styles.d.ts +0 -0
  350. /package/x/{base/utils → view/parts}/apply-styles.js +0 -0
package/README.md CHANGED
@@ -2,236 +2,212 @@
2
2
  <div align="center"><img alt="" width="256" src="./assets/favicon.png"/></div>
3
3
 
4
4
  # 🦝 sly
5
- > *mischievous shadow views*
6
-
7
- [@e280](https://e280.org/)'s new [lit](https://lit.dev/)-based frontend webdev library.
8
-
9
- - 🍋 [**#views**](#views) — shadow-dom'd, hooks-based, componentizable
10
- - 🪵 [**#base-element**](#base-element) — for a more classical experience
11
- - 🪄 [**#dom**](#dom) — the "it's not jquery" multitool
12
- - 🫛 [**#ops**](#ops) — reactive tooling for async operations
13
- - ⏳ [**#loaders**](#loaders) — animated loading spinners for rendering ops
14
- - 💅 [**#spa**](#spa) — hash routing for your spa-day
15
- - 🪙 [**#loot**](#loot) — drag-and-drop facilities
16
- - 🧪 https://sly.e280.org/ — our testing page
17
- - **✨[shiny](https://shiny.e280.org/)✨** — our wip component library
18
-
19
-
20
-
21
- <br/><br/>
22
-
23
- ## 🦝 sly and friends
24
- > `@e280/sly`
25
5
 
26
6
  ```sh
27
- npm install @e280/sly lit @e280/strata @e280/stz
7
+ npm install lit @e280/sly @e280/strata @e280/stz
28
8
  ```
29
9
 
30
- > [!NOTE]
31
- > - 🔥 [lit](https://lit.dev/), for html rendering
32
- > - ⛏️ [@e280/strata](https://github.com/e280/strata), for state management (signals, state trees)
33
- > - 🏂 [@e280/stz](https://github.com/e280/stz), our ts standard library
34
- > - 🐢 [@e280/scute](https://github.com/e280/scute), our buildy-bundly-buddy
10
+ #### [@e280](https://e280.org/)'s [lit-based](https://lit.dev/) web library for reactive light or shadow views
35
11
 
36
- > [!TIP]
37
- > you can import everything in sly from `@e280/sly`,
38
- > or from specific subpackages like `@e280/sly/view`, `@e280/sly/dom`, etc...
12
+ - 🎭 [**#views,**](#views) reactive lit views, light-dom or shadow-dom
13
+ - 🪝 [**#hooks,**](#hooks) react-like composable hooks
14
+ - 🫛 [**#ops,**](#ops) tooling for async operations ui
15
+ - ⏳ [**#loaders,**](#loaders) render ops with animated loading spinners
16
+ - 🪙 [**#loot,**](#loot) drag-and-drop facilities
17
+ - 🪄 [**#dom,**](#dom) the "it's not jquery" multitool
18
+ - 🧪 **https://sly.e280.org/** sly's testing page
39
19
 
40
20
 
41
21
 
42
22
  <br/><br/>
43
23
  <a id="views"></a>
44
24
 
45
- ## 🍋🦝 sly views
46
- > `@e280/sly/view`
47
- > *the crown jewel of sly*
25
+ ## 🎭 views
26
+ > *reactive lit-html views*
27
+
28
+ - 🔮 [**see codepen demo,**](https://codepen.io/editor/ChaseMoskal/pen/019cd681-722b-7f51-a961-bc16e3d524a9) plain html (no build!)
29
+ - 🌗 **light or shadow,** render nakedly on the page, or within a cozy shadow bubble
30
+ - 🪝 **hooks-based,** familiar react-style [hooks](#hooks)
31
+ - ⚡ **auto-reactive,** views magically rerender on [strata](https://github.com/e280/strata)-compatible state changes
32
+ - 🪶 **no compile step,** just god's honest javascript via [lit](https://lit.dev/)-html tagged-templates
33
+ - 🧩 **not web components,** no dom registration needed, just vibes and good typings
48
34
 
49
35
  ```ts
50
- view(use => () => html`<p>hello world</p>`)
51
- ```
36
+ import {html} from "lit"
37
+ import {light, shadow, dom} from "@e280/sly"
52
38
 
53
- - 🪶 **no compile step** just god's honest javascript, via [lit](https://lit.dev/)-html tagged-template-literals
54
- - 🥷 **shadow dom'd** — each view gets its own cozy [shadow](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) bubble, and supports [slots](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots)
55
- - 🪝 **hooks-based** — declarative rendering with the [`use`](#use) family of ergonomic hooks
56
- - ⚡ **reactive** — they auto-rerender whenever any [strata](https://github.com/e280/strata)-compatible state changes
57
- - 🧐 **not components, per se** — they're comfy typescript-native ui building blocks [(technically, lit directives)](https://lit.dev/docs/templates/custom-directives/)
58
- - 🧩 **componentizable** — any view can be magically converted into a proper [web component](https://developer.mozilla.org/en-US/docs/Web/API/Web_components)
39
+ export const MyLightView = light(() => html`<p>blinded by the light</p>`)
59
40
 
60
- ### 🍋 view example
61
- ```ts
62
- import {view, dom, BaseElement} from "@e280/sly"
63
- import {html, css} from "lit"
41
+ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
64
42
  ```
65
- - **declare view**
43
+
44
+ ### 🌞 light views
45
+ > *just pretend it's like react!*
46
+
47
+ - **define a light view**
66
48
  ```ts
67
- export const CounterView = view(use => (start: number) => {
68
- use.styles(css`p {color: green}`)
49
+ import {html} from "lit"
50
+ import {light, useSignal} from "@e280/sly"
69
51
 
70
- const $count = use.signal(start)
52
+ export const MyCounter = light((start: number) => {
53
+ const $count = useSignal(start)
71
54
  const increment = () => $count.value++
72
55
 
73
56
  return html`
74
- <button @click="${increment}">
75
- ${$count.value}
76
- </button>
57
+ <button @click="${increment}">${$count.value}</button>
77
58
  `
78
59
  })
79
60
  ```
80
- - `$count` is a [strata signal](https://github.com/e280/strata#readme) *(we like those)*
81
- - **inject view into dom**
61
+ - **render it into the dom**
82
62
  ```ts
83
- dom.in(".app").render(html`
84
- <h1>cool counter demo</h1>
85
- ${CounterView(1)}
63
+ dom.render(dom(".demo"), html`
64
+ <h1>my cool counter demo</h1>
65
+ ${MyCounter(123)}
86
66
  `)
87
67
  ```
88
- - 🤯 **register view as web component**
68
+ - **remember, light views are naked.**
69
+ so they don't have a containing host element,
70
+ and they can't have their own styles.
71
+
72
+ ### 🌚 shadow views
73
+ > *each shadow view gets its own cozy [shadow-dom](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) bubble and supports [slotting](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots)*
74
+
75
+ - **define a shadow view**
89
76
  ```ts
90
- dom.register({
91
- MyCounter: CounterView
92
- .component()
93
- .props(() => [1]),
77
+ import {css, html} from "lit"
78
+ import {shadow, useName, useCss, useSignal} from "@e280/sly"
79
+
80
+ export const MyShadowCounter = shadow((start: number) => {
81
+ useName("counter")
82
+ useCss(css`button { color: cyan }`)
83
+
84
+ const $count = useSignal(start)
85
+ const increment = () => $count.value++
86
+
87
+ return html`
88
+ <button @click="${increment}">${$count.value}</button>
89
+ <slot></slot>
90
+ `
94
91
  })
95
92
  ```
96
- ```html
97
- <my-counter></my-counter>
93
+ - **render it into the dom**
94
+ ```ts
95
+ dom.render(dom(".demo"), html`
96
+ <h1>my cool counter demo</h1>
97
+ ${MyShadowCounter(234)}
98
+ `)
98
99
  ```
99
-
100
- ### 🍋 view settings
101
- - optional settings for views you should know about
100
+ - shadow views have a host element, rendered output looks like:
101
+ ```html
102
+ <h1>my cool counter demo</h1>
103
+ <sly-shadow view="counter"></sly-shadow>
104
+ ```
105
+ - **.with to nest children or set attrs**
106
+ ```ts
107
+ dom.render(dom(".demo"), html`
108
+ <h1>my cool counter demo</h1>
109
+
110
+ ${MyShadowCounter.with({
111
+ props: [234],
112
+ attrs: {"data-whatever": 555},
113
+ children: html`
114
+ <p>woah, slotting support!</p>
115
+ `,
116
+ })}
117
+ `)
118
+ ```
119
+ - **you can do custom shadow setup if needed** (default shown)
102
120
  ```ts
103
- export const CoolView = view
104
- .settings({mode: "open", delegatesFocus: true})
105
- .render(use => (greeting: string) => html`😎 ${greeting} <slot></slot>`)
121
+ import {SlyShadow} from "@e280/sly"
122
+
123
+ const customShadow = shadow.setup(() => {
124
+ SlyShadow.register()
125
+ const host = document.createElement("sly-shadow")
126
+ const shadow = host.attachShadow({mode: "open"})
127
+ return {host, shadow}
128
+ })
129
+
130
+ const MyShadowView = customShadow(() => html`<p>shrouded in darkness</p>`)
106
131
  ```
107
- - all [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters) (like `mode` and `delegatesFocus`) are valid `settings`
108
- - note the `<slot></slot>` we'll use in the next example lol
109
132
 
110
- ### 🍋 view chains
111
- - views have this sick chaining syntax for supplying more stuff at the template injection site
133
+ ### 🍨 web components
134
+ > *web-native custom elements*
135
+
136
+ - **they use hooks like the views, but they don't take props**
112
137
  ```ts
113
- dom.in(".app").render(html`
114
- <h2>cool example</h2>
115
- ${CoolView
116
- .props("hello")
117
- .attr("class", "hero")
118
- .children(html`<em>spongebob</em>`)
119
- .render()}
120
- `)
138
+ import {html} from "lit"
139
+ import {lightElement, shadowElement} from "@e280/sly"
140
+
141
+ const MyLight = lightElement(() => html`hello`)
142
+ const MyShadow = shadowElement(() => html`hello`)
143
+
144
+ dom.register({MyLight, MyShadow})
121
145
  ```
122
- - `props` — provide props and start a view chain
123
- - `attr` — set html attributes on the `<sly-view>` host element
124
- - `children` — add nested [slottable](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots) content
125
- - `render` — end the view chain and render the lit directive
146
+ ```html
147
+ <my-light></my-light>
148
+ <my-shadow></my-shadow>
149
+ ```
150
+
151
+
152
+
153
+ <br/><br/>
154
+ <a id="hooks"></a>
155
+
156
+ ## 🪝 hooks
157
+ > *composable view state and utilities*
126
158
 
127
- ### 🍋 view/component universality
128
- - **you can start with a view,**
159
+ ### 👮 follow the hooks rules
160
+
161
+ just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of hooks seriously matters.
162
+
163
+ you must not call these hooks under if-conditionals, or for-loops, or inside callback functions, or after a conditional return statement, or anything like that.. *otherwise, heed my warning: weird bad stuff will happen..*
164
+
165
+ ### 🌚 shadow-only hooks
166
+ - **useName,** set the "view" attribute value
129
167
  ```ts
130
- export const GreeterView = view(use => (name: string) => {
131
- return html`<p>hello ${name}</p>`
132
- })
168
+ useName("squarepants")
169
+ // <sly-shadow view="squarepants">
133
170
  ```
134
- - view usage
135
- ```ts
136
- GreeterView("pimsley")
137
- ```
138
- **then you can convert it to a component.**
171
+ - **useCss,** attach stylesheets (use lit's `css`!) to the shadow root
139
172
  ```ts
140
- export class GreeterComponent extends (
141
- GreeterView
142
- .component()
143
- .props(component => [component.getAttribute("name") ?? "unknown"])
144
- ) {}
173
+ useCss(css1, css2, css3)
145
174
  ```
146
- - html usage
147
- ```html
148
- <greeter-component name="pimsley"></greeter-component>
149
- ```
150
- - **you can start with a component,**
175
+ - **useHost,** get the host element
151
176
  ```ts
152
- export class GreeterComponent extends (
153
- view(use => (name: string) => {
154
- return html`<p>hello ${name}</p>`
155
- })
156
- .component()
157
- .props(component => [component.getAttribute("name") ?? "unknown"])
158
- ) {}
177
+ const host = useHost()
159
178
  ```
160
- - html usage
161
- ```html
162
- <greeter-component name="pimsley"></greeter-component>
163
- ```
164
- **and it already has `.view` ready for you.**
165
- - view usage
166
- ```ts
167
- GreeterComponent.view("pimsley")
168
- ```
169
- - **understanding `.component(BaseElement)` and `.props(fn)`**
170
- - `.props` takes a fn that is called every render, which returns the props given to the view
171
- ```ts
172
- .props(() => ["pimsley"])
173
- ```
174
- the props fn receives the component instance, so you can query html attributes or instance properties
175
- ```ts
176
- .props(component => [component.getAttribute("name") ?? "unknown"])
177
- ```
178
- - `.component` accepts a subclass of `BaseElement`, so you can define your own properties and methods for your component class
179
- ```ts
180
- const GreeterComponent = GreeterView
181
-
182
- // declare your own custom class
183
- .component(class extends BaseElement {
184
- $name = signal("jim raynor")
185
- updateName(name: string) {
186
- this.$name.value = name
187
- }
188
- })
189
-
190
- // props gets the right types on 'component'
191
- .props(component => [component.$name.value])
192
- ```
193
- - `.component` provides the devs interacting with your component, with noice typings
194
- ```ts
195
- dom<GreeterComponent>("greeter-component").updateName("mortimer")
196
- ```
197
- - typescript class wizardry
198
- - ❌ smol-brain approach exports class value, but NOT the typings
199
- ```ts
200
- export const GreeterComponent = (...)
201
- ```
202
- - ✅ giga-brain approach exports class value AND the typings
203
- ```ts
204
- export class GreeterComponent extends (...) {}
205
- ```
206
- - **register web components to the dom**
207
- ```ts
208
- dom.register({GreeterComponent})
209
- ```
210
- - **oh and don't miss out on the insta-component shorthand**
211
- ```ts
212
- dom.register({
213
- QuickComponent: view.component(use => html`⚡ incredi`),
214
- })
179
+ - **useShadow,** get the shadow root
180
+ ```ts
181
+ const shadow = useShadow()
215
182
  ```
183
+ - **useAttrs,** access host element attributes (and rerender on attr changes)
184
+ ```ts
185
+ const attrs = useAttrs({
186
+ name: String,
187
+ count: Number,
188
+ active: Boolean,
189
+ })
216
190
 
217
- <a id="use"></a>
191
+ attrs.count = 123 // set the attr
192
+ ```
218
193
 
219
- ### 🍋 "use" hooks reference
220
- - 👮 **follow the hooks rules**
221
- > just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of sly's `use` hooks actually matters..
222
- > you must not call these hooks under `if` conditionals, or `for` loops, or in callbacks, or after a conditional `return` statement, or anything like that.. *otherwise, heed my warning: weird bad stuff will happen..*
223
- - **use.name** — set the "view" attr value, eg `<sly-view view="squarepants">`
194
+ ### 🌞 universal hooks
195
+ - **useState,** react-like hook to create some reactive state (we prefer signals)
224
196
  ```ts
225
- use.name("squarepants")
197
+ const [count, setCount] = useState(0)
198
+
199
+ const increment = () => setCount(n => n + 1)
226
200
  ```
227
- - **use.styles** attach stylesheets into the view's shadow dom
201
+ - **useRef,** react-like hook to make a non-reactive box for a value
228
202
  ```ts
229
- use.styles(css1, css2, css3)
203
+ const ref = useRef(0)
204
+
205
+ ref.current // 0
206
+ ref.current = 1 // does not trigger rerender
230
207
  ```
231
- *(alias `use.css`)*
232
- - **use.signal** — create a [strata signal](https://github.com/e280/strata)
208
+ - **useSignal,** create a [strata](https://github.com/e280/strata) signal
233
209
  ```ts
234
- const $count = use.signal(1)
210
+ const $count = useSignal(1)
235
211
 
236
212
  // read the signal
237
213
  $count()
@@ -239,392 +215,96 @@ import {html, css} from "lit"
239
215
  // write the signal
240
216
  $count(2)
241
217
  ```
242
- - `derived` signals
243
- ```ts
244
- const $product = use.derived(() => $count() * $whatever())
245
- ```
246
- - `lazy` signals
247
- ```ts
248
- const $product = use.lazy(() => $count() * $whatever())
249
- ```
250
- - go read the [strata readme](https://github.com/e280/strata) about this stuff
251
- - **use.once** — run fn at initialization, and return a value
218
+ - **useDerived,** create a [strata](https://github.com/e280/strata) derived signal
252
219
  ```ts
253
- const whatever = use.once(() => {
254
- console.log("happens only once")
220
+ const $product = useDerived(() => $count() * $whatever())
221
+ ```
222
+ - **useOnce,** run fn at initialization, and return a value
223
+ ```ts
224
+ const whatever = useOnce(() => {
225
+ console.log("happens one time")
255
226
  return 123
256
227
  })
257
228
 
258
229
  whatever // 123
259
230
  ```
260
- - **use.mount** setup mount/unmount lifecycle
231
+ - **useMount,** setup mount/unmount lifecycle
261
232
  ```ts
262
- use.mount(() => {
263
- console.log("view mounted")
264
-
265
- return () => {
266
- console.log("view unmounted")
267
- }
233
+ useMount(() => {
234
+ console.log("mounted")
235
+ return () => console.log("unmounted")
268
236
  })
269
237
  ```
270
- - **use.wake** run fn each time mounted, and return value
238
+ - **useWake,** run fn each time mounted, and return value
271
239
  ```ts
272
- const whatever = use.wake(() => {
273
- console.log("view mounted")
240
+ const whatever = useWake(() => {
241
+ console.log("mounted")
274
242
  return 123
275
243
  })
276
244
 
277
245
  whatever // 123
278
246
  ```
279
- - **use.life** mount/unmount lifecycle, but also return a value
247
+ - **useLife,** mount/unmount lifecycle, but also return a value
280
248
  ```ts
281
- const v = use.life(() => {
249
+ const whatever = useLife(() => {
282
250
  console.log("mounted")
283
251
  const value = 123
284
252
  return [value, () => console.log("unmounted")]
285
253
  })
286
254
 
287
- v // 123
288
- ```
289
- - **use.events** — attach event listeners to the element (auto-cleaned up)
290
- ```ts
291
- use.events({
292
- keydown: (e: KeyboardEvent) => console.log("keydown", e.code),
293
- keyup: (e: KeyboardEvent) => console.log("keyup", e.code),
294
- })
295
- ```
296
- - **use.states** — [internal states](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/states) helper
297
- ```ts
298
- const states = use.states()
299
- states.assign("active", "cool")
300
- ```
301
- ```css
302
- [view="my-view"]::state(active) { color: yellow; }
303
- [view="my-view"]::state(cool) { outline: 1px solid cyan; }
304
- ```
305
- - **use.attrs** — ergonomic typed html attribute access
306
- - `use.attrs` is similar to [#dom.attrs](#dom.attrs)
307
- ```ts
308
- const attrs = use.attrs({
309
- name: String,
310
- count: Number,
311
- active: Boolean,
312
- })
313
- ```
314
- ```ts
315
- attrs.name // "chase"
316
- attrs.count // 123
317
- attrs.active // true
318
- ```
319
- - use.attrs.{strings/numbers/booleans}
320
- ```ts
321
- use.attrs.strings.name // "chase"
322
- use.attrs.numbers.count // 123
323
- use.attrs.booleans.active // true
324
- ```
325
- - use.attrs.on
326
- ```ts
327
- use.attrs.on(() => console.log("an attribute changed"))
328
- ```
329
- - **use.render** — rerender the view (debounced)
330
- ```ts
331
- use.render()
255
+ whatever // 123
332
256
  ```
333
- - **use.renderNow** rerender the view instantly (not debounced)
257
+ - **useRender,** returns a fn to rerender the view (debounced)
334
258
  ```ts
335
- use.renderNow()
259
+ const render = useRender()
260
+
261
+ render().then(() => console.log("render done"))
336
262
  ```
337
- - **use.rendered** promise that resolves *after* the next render
263
+ - **useRendered,** get a promise that resolves *after* the next render
338
264
  ```ts
339
- use.rendered.then(() => {
340
- const slot = use.shadow.querySelector("slot")
341
- console.log(slot)
342
- })
265
+ useRendered().then(() => console.log("rendered"))
343
266
  ```
344
- - **use.op** start with an op based on an async fn
267
+ - **useOp,** start loading an op based on an async fn
345
268
  ```ts
346
- const op = use.op(async() => {
269
+ const op = useOp(async() => {
347
270
  await nap(5000)
348
271
  return 123
349
272
  })
350
273
  ```
351
- - **use.op.promise** start with an op based on a promise
274
+ - **useOpPromise,** start loading an op based on a promise
352
275
  ```ts
353
- const op = use.op.promise(doAsyncWork())
276
+ const op = useOpPromise(doAsyncWork())
354
277
  ```
355
278
 
356
- ### 🍋 "use" recipes
357
- - make a ticker mount, cycle, and nap
279
+ ### 🧑‍🍳 happy hooks recipes
280
+ - make a ticker, mount, cycle, and nap
358
281
  ```ts
359
282
  import {cycle, nap} from "@e280/stz"
360
283
  ```
361
284
  ```ts
362
- const $seconds = use.signal(0)
285
+ const $seconds = useSignal(0)
363
286
 
364
- use.mount(() => cycle(async() => {
287
+ useMount(() => cycle(async() => {
365
288
  await nap(1000)
366
289
  $seconds.value++
367
290
  }))
368
291
  ```
369
292
  - wake + rendered, to do something after each mount's first render
370
293
  ```ts
371
- use.wake(() => use.rendered.then(() => {
294
+ const rendered = useRendered()
295
+
296
+ useWake(() => rendered.then(() => {
372
297
  console.log("after first render")
373
298
  }))
374
299
  ```
375
300
 
376
301
 
377
302
 
378
- <br/><br/>
379
- <a id="base-element"></a>
380
-
381
- ## 🪵🦝 sly base element
382
- > `@e280/sly/base`
383
- > *the classic experience*
384
-
385
- ```ts
386
- import {BaseElement, Use, dom} from "@e280/sly"
387
- import {html, css} from "lit"
388
- ```
389
-
390
- `BaseElement` is more of an old-timey class-based "boomer" approach to making web components, but with a millennial twist — its `render` method gives you the same `use` hooks that views enjoy.
391
-
392
- 👮 a *BaseElement* is not a *View*, and cannot be converted into a *View*.
393
-
394
- ### 🪵 let's clarify some sly terminology
395
- - "Element"
396
- - an html element; any subclass of the browser's HTMLElement
397
- - all genuine ["web components"](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) are elements
398
- - "BaseElement"
399
- - sly's own subclass of the browser-native HTMLElement
400
- - is a true element and web component (can be registered to the dom)
401
- - "View"
402
- - sly's own magic concept that uses a lit-directive to render stuff
403
- - NOT an element or web component (can NOT be registered to the dom)
404
- - NOT related to BaseElement
405
- - can be converted into a Component via `view.component().props(() => [])`
406
- - "Component"
407
- - a sly view that has been converted into an element
408
- - is a true element and web component (can be registered to the dom)
409
- - actually a subclass of BaseElement
410
- - actually contains the view on `Component.view`
411
-
412
- ### 🪵 base element setup
413
- - **declare your element class**
414
- ```ts
415
- export class MyElement extends BaseElement {
416
- static styles = css`span{color:orange}`
417
-
418
- // custom property
419
- $start = signal(10)
420
-
421
- // custom attributes
422
- attrs = dom.attrs(this).spec({
423
- multiply: Number,
424
- })
425
-
426
- // custom methods
427
- hello() {
428
- return "world"
429
- }
430
-
431
- render(use: Use) {
432
- const $count = use.signal(1)
433
- const increment = () => $count.value++
434
-
435
- const {$start} = this
436
- const {multiply = 1} = this.attrs
437
- const result = $start() + (multiply * $count())
438
-
439
- return html`
440
- <span>${result}</span>
441
- <button @click="${increment}">+</button>
442
- `
443
- }
444
- }
445
- ```
446
- - **register your element to the dom**
447
- ```ts
448
- dom.register({MyElement})
449
- ```
450
-
451
- ### 🪵 base element usage
452
- - **place the element in your html body**
453
- ```html
454
- <body>
455
- <my-element></my-element>
456
- </body>
457
- ```
458
- - **now you can interact with it**
459
- ```ts
460
- const myElement = dom<MyElement>("my-element")
461
-
462
- // js property
463
- myElement.$start(100)
464
-
465
- // html attributes
466
- myElement.attrs.multiply = 2
467
-
468
- // methods
469
- myElement.hello()
470
- // "world"
471
- ```
472
-
473
-
474
-
475
- <br/><br/>
476
- <a id="dom"></a>
477
-
478
- ## 🪄🦝 sly dom
479
- > `@e280/sly/dom`
480
- > *the "it's not jquery!" multitool*
481
-
482
- ```ts
483
- import {dom} from "@e280/sly"
484
- ```
485
-
486
- ### 🪄 dom queries
487
- - `require` an element
488
- ```ts
489
- dom(".demo")
490
- // HTMLElement (or throws)
491
- ```
492
- ```ts
493
- // alias
494
- dom.require(".demo")
495
- // HTMLElement (or throws)
496
- ```
497
- - `maybe` get an element
498
- ```ts
499
- dom.maybe(".demo")
500
- // HTMLElement | undefined
501
- ```
502
- - `all` matching elements in an array
503
- ```ts
504
- dom.all(".demo ul li")
505
- // HTMLElement[]
506
- ```
507
-
508
- ### 🪄 dom.in scope
509
- - make a scope
510
- ```ts
511
- dom.in(".demo") // selector
512
- // Dom instance
513
- ```
514
- ```ts
515
- dom.in(demoElement) // element
516
- // Dom instance
517
- ```
518
- - run queries in that scope
519
- ```ts
520
- dom.in(demoElement).require(".button")
521
- ```
522
- ```ts
523
- dom.in(demoElement).maybe(".button")
524
- ```
525
- ```ts
526
- dom.in(demoElement).all("ol li")
527
- ```
528
-
529
- ### 🪄 dom utilities
530
- - `dom.register` web components
531
- ```ts
532
- dom.register({MyComponent, AnotherCoolComponent})
533
- // <my-component>
534
- // <another-cool-component>
535
- ```
536
- - `dom.register` automatically dashes the tag names (`MyComponent` becomes `<my-component>`)
537
- - `dom.render` content into an element
538
- ```ts
539
- dom.render(element, html`<p>hello world</p>`)
540
- ```
541
- ```ts
542
- dom.in(".demo").render(html`<p>hello world</p>`)
543
- ```
544
- - `dom.el` little element builder
545
- ```ts
546
- const div = dom.el("div", {"data-whatever": 123, "data-active": true})
547
- // <div data-whatever="123" data-active></div>
548
- ```
549
- - `dom.elmer` make an element with a fluent chain
550
- ```ts
551
- const div = dom.elmer("div")
552
- .attr("data-whatever", 123)
553
- .attr("data-active")
554
- .children("hello world")
555
- .done()
556
- // HTMLElement
557
- ```
558
- - `dom.mk` make an element with a lit template (returns the first)
559
- ```ts
560
- const div = dom.mk(html`
561
- <div data-whatever="123" data-active>
562
- hello world
563
- </div>
564
- `) // HTMLElement
565
- ```
566
- - `dom.events` <a id="dom.events"></a> to attach event listeners
567
- ```ts
568
- const detach = dom.events(element, {
569
- keydown: (e: KeyboardEvent) => console.log("keydown", e.code),
570
- keyup: (e: KeyboardEvent) => console.log("keyup", e.code),
571
- })
572
- ```
573
- ```ts
574
- const detach = dom.in(".demo").events({
575
- keydown: (e: KeyboardEvent) => console.log("keydown", e.code),
576
- keyup: (e: KeyboardEvent) => console.log("keyup", e.code),
577
- })
578
- ```
579
- ```ts
580
- // unattach those event listeners when you're done
581
- detach()
582
- ```
583
- - `dom.attrs` <a id="dom.attrs"></a> to setup a type-happy html attribute helper
584
- ```ts
585
- const attrs = dom.attrs(element).spec({
586
- name: String,
587
- count: Number,
588
- active: Boolean,
589
- })
590
- ```
591
- ```ts
592
- const attrs = dom.in(".demo").attrs.spec({
593
- name: String,
594
- count: Number,
595
- active: Boolean,
596
- })
597
- ```
598
- ```ts
599
- attrs.name // "chase"
600
- attrs.count // 123
601
- attrs.active // true
602
- ```
603
- ```ts
604
- attrs.name = "zenky"
605
- attrs.count = 124
606
- attrs.active = false // removes html attr
607
- ```
608
- ```ts
609
- attrs.name = undefined // removes the attr
610
- attrs.count = undefined // removes the attr
611
- ```
612
- or if you wanna be more loosey-goosey, skip the spec
613
- ```ts
614
- const a = dom.in(".demo").attrs
615
- a.strings.name = "pimsley"
616
- a.numbers.count = 125
617
- a.booleans.active = true
618
- ```
619
-
620
-
621
-
622
303
  <br/><br/>
623
304
  <a id="ops"></a>
624
305
 
625
- ## 🫛🦝 sly ops
626
- > `@e280/sly/ops`
627
- > *tools for async operations and loading spinners*
306
+ ## 🫛 ops
307
+ > *helpers for async operations*
628
308
 
629
309
  ```ts
630
310
  import {nap} from "@e280/stz"
@@ -659,22 +339,22 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
659
339
  podium.value(["ready", 123])
660
340
  // 123
661
341
  ```
662
- - see more at [podium.ts](./s/ops/podium.ts)
342
+ - see more at [podium.ts](./s/op/podium.ts)
663
343
 
664
344
  ### 🫛 ops: nice pod ergonomics
665
- - an `Op<V>` wraps a pod with a signal for reactivity
345
+ - an `Op<V>` wraps a pod with a strata signal for reactivity
666
346
  - create an op
667
347
  ```ts
668
- const op = new Op<number>() // loading status by default
348
+ new Op<number>() // loading status by default
669
349
  ```
670
350
  ```ts
671
- const op = Op.loading<number>()
351
+ Op.loading<number>()
672
352
  ```
673
353
  ```ts
674
- const op = Op.ready<number>(123)
354
+ Op.ready<number>(123)
675
355
  ```
676
356
  ```ts
677
- const op = Op.error<number>(new Error())
357
+ Op.error<number>(new Error())
678
358
  ```
679
359
  - 🔥 create an op that calls and tracks an async fn
680
360
  ```ts
@@ -701,13 +381,12 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
701
381
  - select executes a fn based on the status
702
382
  ```ts
703
383
  const result = op.select({
704
- loading: () => "it's loading...",
384
+ loading: () => "still loading...",
705
385
  ready: value => `dude, it's ready! ${value}`,
706
- error: err => `dude, there's an error!`,
386
+ error: err => `ack! an error!`,
707
387
  })
708
388
 
709
- result
710
- // "dude, it's ready! 123"
389
+ result // "dude, it's ready! 123"
711
390
  ```
712
391
  - morph returns a new pod, transforming the value if ready
713
392
  ```ts
@@ -732,9 +411,8 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
732
411
  <br/><br/>
733
412
  <a id="loaders"></a>
734
413
 
735
- ## ⏳🦝 sly loaders
736
- > `@e280/sly/loaders`
737
- > *animated loading spinners for ops*
414
+ ## loaders
415
+ > *animated loading spinners for ops*
738
416
 
739
417
  ```ts
740
418
  import {loaders} from "@e280/sly"
@@ -765,100 +443,10 @@ import {loaders} from "@e280/sly"
765
443
 
766
444
 
767
445
 
768
- <br/><br/>
769
- <a id="spa"></a>
770
-
771
- ## 💅🦝 sly spa
772
- > `@e280/sly/spa`
773
- > *hash router for single-page-apps*
774
-
775
- ```ts
776
- import {spa, html} from "@e280/sly"
777
- ```
778
-
779
- ### 💅 spa.Router basics
780
- - **make a spa router**
781
- ```ts
782
- const router = new spa.Router({
783
- routes: {
784
- home: spa.route("#/", async() => html`home`),
785
- settings: spa.route("#/settings", async() => html`settings`),
786
- user: spa.route("#/user/{userId}", async({userId}) => html`user ${userId}`),
787
- },
788
- })
789
- ```
790
- - all route strings must start with `#/`
791
- - use braces like `{userId}` to accept string params
792
- - home-equivalent hashes like `""` and `"#"` are normalized to `"#/"`
793
- - the router has an effect on the appearance of the url in the browser address bar -- the home `#/` is removed, aesthetically, eg, `e280.org/#/` is rewritten to `e280.org` using *history.replaceState*
794
- - you can provide `loader` option if you want to specify the loading spinner (defaults to `loaders.make()`)
795
- - you can provide `notFound` option, if you want to specify what is shown on invalid routes (defaults to `() => null`)
796
- - when `auto` is true (default), the router calls `.refresh()` and `.listen()` in the constructor.. set it to `false` if you want manual control
797
- - you can set `auto` option false if you want to omit the default initial refresh and listen calls
798
- - **render your current page**
799
- ```ts
800
- return html`
801
- <div class="my-page">
802
- ${router.render()}
803
- </div>
804
- `
805
- ```
806
- - returns lit content
807
- - shows a loading spinner when pages are loading
808
- - will display the notFound content for invalid routes (defaults to null)
809
- - **perform navigations**
810
- - go to settings page
811
- ```ts
812
- await router.nav.settings.go()
813
- // goes to "#/settings"
814
- ```
815
- - go to user page
816
- ```ts
817
- await router.nav.user.go("123")
818
- // goes to "#/user/123"
819
- ```
820
-
821
- ### 💅 spa.Router advanced
822
- - **generate a route's hash string**
823
- ```ts
824
- const hash = router.nav.user.hash("123")
825
- // "#/user/123"
826
-
827
- html`<a href="${hash}">user 123</a>`
828
- ```
829
- - **check if a route is the currently-active one**
830
- ```ts
831
- const hash = router.nav.user.active
832
- // true
833
- ```
834
- - **force-refresh the router**
835
- ```ts
836
- await router.refresh()
837
- ```
838
- - **force-navigate the router by hash**
839
- ```ts
840
- await router.refresh("#/user/123")
841
- ```
842
- - **get the current hash string (normalized)**
843
- ```ts
844
- router.hash
845
- // "#/user/123"
846
- ```
847
- - **the `route(...)` helper fn enables the braces-params syntax**
848
- - but, if you wanna do it differently, you *can* implement your own hash parser to do your own funky syntax
849
- - **dispose the router when you're done with it**
850
- ```ts
851
- router.dispose()
852
- // stop listening to hashchange events
853
- ```
854
-
855
-
856
-
857
446
  <br/><br/>
858
447
  <a id="loot"></a>
859
448
 
860
- ## 🪙🦝 loot
861
- > `@e280/sly/loot`
449
+ ## 🪙 loot
862
450
  > *drag-and-drop facilities*
863
451
 
864
452
  ```ts
@@ -881,7 +469,7 @@ import {ev} from "@e280/stz"
881
469
  - **attach event listeners to your dropzone,** one of these ways:
882
470
  - **view example**
883
471
  ```ts
884
- view(() => () => html`
472
+ light(() => html`
885
473
  <div
886
474
  ?data-indicator="${drops.$indicator()}"
887
475
  @dragover="${drops.dragover}"
@@ -937,9 +525,9 @@ import {ev} from "@e280/stz"
937
525
  ```
938
526
  - **attach dragzone listeners** (there can be many dragzones...)
939
527
  ```ts
940
- view(use => () => {
941
- const money = use.once((): Money => ({value: 280}))
942
- const dragzone = use.once(() => dnd.dragzone(() => money))
528
+ light(() => {
529
+ const money = useOnce((): Money => ({value: 280}))
530
+ const dragzone = useOnce(() => dnd.dragzone(() => money))
943
531
 
944
532
  return html`
945
533
  <div
@@ -953,9 +541,9 @@ import {ev} from "@e280/stz"
953
541
  ```
954
542
  - **attach dropzone listeners** (there can be many dropzones...)
955
543
  ```ts
956
- view(use => () => {
957
- const bag = use.once((): Bag => ({id: 1}))
958
- const dropzone = use.once(() => dnd.dropzone(() => bag))
544
+ light(() => {
545
+ const bag = useOnce((): Bag => ({id: 1}))
546
+ const dropzone = useOnce(() => dnd.dropzone(() => bag))
959
547
  const indicator = !!(dnd.dragging && dnd.hovering === bag)
960
548
 
961
549
  return html`
@@ -978,13 +566,155 @@ import {ev} from "@e280/stz"
978
566
 
979
567
 
980
568
  <br/><br/>
981
- <a id="e280"></a>
569
+ <a id="dom"></a>
982
570
 
983
- ## 🧑‍💻🦝 sly is by e280
984
- reward us with github stars
985
- build with us at https://e280.org/ but only if you're cool
571
+ ## 🪄 dom
572
+ > *the "it's not jquery!" multitool*
573
+
574
+ ```ts
575
+ import {dom} from "@e280/sly"
576
+ ```
577
+
578
+ ### 🪄 dom queries
579
+ - `require` an element
580
+ ```ts
581
+ dom(".demo")
582
+ // HTMLElement (or throws)
583
+ ```
584
+ ```ts
585
+ // alias
586
+ dom.require(".demo")
587
+ // HTMLElement (or throws)
588
+ ```
589
+ - `maybe` get an element
590
+ ```ts
591
+ dom.maybe(".demo")
592
+ // HTMLElement | undefined
593
+ ```
594
+ - `all` matching elements in an array
595
+ ```ts
596
+ dom.all(".demo ul li")
597
+ // HTMLElement[]
598
+ ```
599
+
600
+ ### 🪄 dom.in scope
601
+ - make a scope
602
+ ```ts
603
+ dom.in(".demo") // selector
604
+ // Dom instance
605
+ ```
606
+ ```ts
607
+ dom.in(demoElement) // element
608
+ // Dom instance
609
+ ```
610
+ - run queries in that scope
611
+ ```ts
612
+ dom.in(demoElement).require(".button")
613
+ ```
614
+ ```ts
615
+ dom.in(demoElement).maybe(".button")
616
+ ```
617
+ ```ts
618
+ dom.in(demoElement).all("ol li")
619
+ ```
620
+
621
+ ### 🪄 dom utilities
622
+ - `dom.register` web components
623
+ ```ts
624
+ dom.register({MyComponent, AnotherCoolComponent})
625
+ // <my-component>
626
+ // <another-cool-component>
627
+ ```
628
+ - `dom.register` automatically dashes the tag names (`MyComponent` becomes `<my-component>`)
629
+ - `dom.render` content into an element
630
+ ```ts
631
+ dom.render(element, html`<p>hello world</p>`)
632
+ ```
633
+ ```ts
634
+ dom.in(".demo").render(html`<p>hello world</p>`)
635
+ ```
636
+ - `dom.el` little element builder
637
+ ```ts
638
+ const div = dom.el("div", {"data-whatever": 123, "data-active": true})
639
+ // <div data-whatever="123" data-active></div>
640
+ ```
641
+ - `dom.elmer` make an element with a fluent chain
642
+ ```ts
643
+ const div = dom.elmer("div")
644
+ .attr("data-whatever", 123)
645
+ .attr("data-active")
646
+ .children("hello world")
647
+ .done()
648
+ // HTMLElement
649
+ ```
650
+ - `dom.mk` make an element with a lit template (returns the first)
651
+ ```ts
652
+ const div = dom.mk(html`
653
+ <div data-whatever="123" data-active>
654
+ hello world
655
+ </div>
656
+ `) // HTMLElement
657
+ ```
658
+ - `dom.events` <a id="dom.events"></a> to attach event listeners
659
+ ```ts
660
+ const detach = dom.events(element, {
661
+ keydown: (e: KeyboardEvent) => console.log("keydown", e.code),
662
+ keyup: (e: KeyboardEvent) => console.log("keyup", e.code),
663
+ })
664
+ ```
665
+ ```ts
666
+ const detach = dom.in(".demo").events({
667
+ keydown: (e: KeyboardEvent) => console.log("keydown", e.code),
668
+ keyup: (e: KeyboardEvent) => console.log("keyup", e.code),
669
+ })
670
+ ```
671
+ ```ts
672
+ // unattach those event listeners when you're done
673
+ detach()
674
+ ```
675
+ - `dom.attrs` <a id="dom.attrs"></a> to setup a type-happy html attribute helper
676
+ ```ts
677
+ const attrs = dom.attrs(element).spec({
678
+ name: String,
679
+ count: Number,
680
+ active: Boolean,
681
+ })
682
+ ```
683
+ ```ts
684
+ const attrs = dom.in(".demo").attrs.spec({
685
+ name: String,
686
+ count: Number,
687
+ active: Boolean,
688
+ })
689
+ ```
690
+ ```ts
691
+ attrs.name // "chase"
692
+ attrs.count // 123
693
+ attrs.active // true
694
+ ```
695
+ ```ts
696
+ attrs.name = "zenky"
697
+ attrs.count = 124
698
+ attrs.active = false // removes html attr
699
+ ```
700
+ ```ts
701
+ attrs.name = undefined // removes the attr
702
+ attrs.count = undefined // removes the attr
703
+ ```
704
+ or if you wanna be more loosey-goosey, skip the spec
705
+ ```ts
706
+ const {attrs} = dom.in(".demo")
707
+ attrs.strings.name = "pimsley"
708
+ attrs.numbers.count = 125
709
+ attrs.booleans.active = true
710
+ ```
986
711
 
987
712
 
988
713
 
989
714
  <br/><br/>
715
+ <a id="e280"></a>
716
+
717
+ ## 🧑‍💻 sly is by e280
718
+ reward us with github stars
719
+ build with us at https://e280.org/ but only if you're cool
990
720