@e280/sly 0.3.0-1 → 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.
- package/README.md +107 -65
- package/package.json +20 -26
- package/s/demo/demo.bundle.ts +5 -1
- package/s/demo/views/demo.ts +3 -0
- package/s/demo/views/loaders.ts +2 -2
- package/s/demo/views/time-light.ts +19 -0
- package/s/demo/views/time-shadow.ts +22 -0
- package/s/dom/attrs/attrs.ts +3 -3
- package/s/dom/attrs/parts/attr-spec.ts +17 -5
- package/s/dom/attrs/parts/on-attrs.ts +1 -1
- package/s/dom/dom.ts +1 -1
- package/s/index.ts +2 -2
- package/s/{loaders → loader}/index.barrel.ts +0 -1
- package/s/{loaders → loader}/index.ts +0 -1
- package/s/{loaders → loader}/types.ts +1 -1
- package/s/view/{parts → common}/sly-shadow.ts +6 -0
- package/s/view/elements/light.ts +14 -0
- package/s/view/elements/shadow.ts +52 -0
- package/s/view/hooks/use-attrs.ts +28 -0
- package/s/view/hooks/use-life.ts +2 -2
- package/s/view/hooks/use-op.ts +1 -1
- package/s/view/hooks/use-ref.ts +3 -3
- package/s/view/hooks/use-state.ts +4 -4
- package/s/view/index.ts +5 -0
- package/s/view/shadow.ts +12 -12
- package/x/demo/demo.bundle.js +4 -1
- package/x/demo/demo.bundle.js.map +1 -1
- package/x/demo/demo.bundle.min.js +22 -15
- package/x/demo/demo.bundle.min.js.map +4 -4
- package/x/demo/views/demo.js +3 -0
- package/x/demo/views/demo.js.map +1 -1
- package/x/demo/views/loaders.js +2 -2
- package/x/demo/views/loaders.js.map +1 -1
- package/x/demo/views/time-light.d.ts +359 -0
- package/x/demo/views/time-light.js +16 -0
- package/x/demo/views/time-light.js.map +1 -0
- package/x/demo/views/time-shadow.d.ts +365 -0
- package/x/demo/views/time-shadow.js +18 -0
- package/x/demo/views/time-shadow.js.map +1 -0
- package/x/dom/attrs/attrs.d.ts +3 -2
- package/x/dom/attrs/attrs.js +2 -2
- package/x/dom/attrs/attrs.js.map +1 -1
- package/x/dom/attrs/parts/attr-spec.d.ts +5 -1
- package/x/dom/attrs/parts/attr-spec.js +12 -6
- package/x/dom/attrs/parts/attr-spec.js.map +1 -1
- package/x/dom/attrs/parts/on-attrs.d.ts +1 -1
- package/x/dom/attrs/parts/on-attrs.js.map +1 -1
- package/x/dom/dom.d.ts +1 -1
- package/x/dom/dom.js.map +1 -1
- package/x/index.d.ts +2 -2
- package/x/index.html +2 -2
- package/x/index.js +2 -2
- package/x/index.js.map +1 -1
- package/x/{loaders → loader}/index.barrel.d.ts +0 -1
- package/x/loader/index.barrel.js.map +1 -0
- package/x/{loaders → loader}/index.d.ts +0 -1
- package/x/loader/index.js.map +1 -0
- package/x/loader/make.js.map +1 -0
- package/x/loader/mock.js.map +1 -0
- package/x/loader/parts/anims.js.map +1 -0
- package/x/loader/parts/ascii-anim.js.map +1 -0
- package/x/loader/parts/error-display.js.map +1 -0
- package/x/{loaders → loader}/types.d.ts +1 -1
- package/x/{loaders → loader}/types.js.map +1 -1
- package/x/loot/drag-and-drops.d.ts +2 -2
- package/x/loot/drops.d.ts +1 -1
- package/x/op/index.js.map +1 -0
- package/x/op/op.js.map +1 -0
- package/x/op/podium.js.map +1 -0
- package/x/{ops → op}/types.js.map +1 -1
- package/x/{tests.test.js → test.js} +1 -1
- package/x/test.js.map +1 -0
- package/x/view/{parts → common}/sly-shadow.d.ts +1 -0
- package/x/view/{parts → common}/sly-shadow.js +4 -0
- package/x/view/common/sly-shadow.js.map +1 -0
- package/x/view/elements/light.d.ts +357 -0
- package/x/view/elements/light.js +10 -0
- package/x/view/elements/light.js.map +1 -0
- package/x/view/elements/shadow.d.ts +366 -0
- package/x/view/elements/shadow.js +42 -0
- package/x/view/elements/shadow.js.map +1 -0
- package/x/view/hooks/use-attrs.d.ts +2 -0
- package/x/view/hooks/use-attrs.js +23 -0
- package/x/view/hooks/use-attrs.js.map +1 -0
- package/x/view/hooks/use-life.js +2 -2
- package/x/view/hooks/use-life.js.map +1 -1
- package/x/view/hooks/use-op.d.ts +1 -1
- package/x/view/hooks/use-op.js +1 -1
- package/x/view/hooks/use-op.js.map +1 -1
- package/x/view/hooks/use-ref.d.ts +3 -3
- package/x/view/hooks/use-ref.js +5 -5
- package/x/view/hooks/use-ref.js.map +1 -1
- package/x/view/hooks/use-signal.d.ts +3 -3
- package/x/view/hooks/use-state.js +4 -4
- package/x/view/hooks/use-state.js.map +1 -1
- package/x/view/index.d.ts +4 -0
- package/x/view/index.js +4 -0
- package/x/view/index.js.map +1 -1
- package/x/view/shadow.d.ts +2 -2
- package/x/view/shadow.js +10 -11
- package/x/view/shadow.js.map +1 -1
- package/x/loaders/index.barrel.js.map +0 -1
- package/x/loaders/index.js.map +0 -1
- package/x/loaders/make.js.map +0 -1
- package/x/loaders/mock.js.map +0 -1
- package/x/loaders/parts/anims.js.map +0 -1
- package/x/loaders/parts/ascii-anim.js.map +0 -1
- package/x/loaders/parts/error-display.js.map +0 -1
- package/x/ops/index.js.map +0 -1
- package/x/ops/op.js.map +0 -1
- package/x/ops/podium.js.map +0 -1
- package/x/tests.test.js.map +0 -1
- package/x/view/parts/sly-shadow.js.map +0 -1
- /package/s/{loaders → loader}/make.ts +0 -0
- /package/s/{loaders → loader}/mock.ts +0 -0
- /package/s/{loaders → loader}/parts/anims.ts +0 -0
- /package/s/{loaders → loader}/parts/ascii-anim.ts +0 -0
- /package/s/{loaders → loader}/parts/error-display.ts +0 -0
- /package/s/{ops → op}/index.ts +0 -0
- /package/s/{ops → op}/op.ts +0 -0
- /package/s/{ops → op}/podium.ts +0 -0
- /package/s/{ops → op}/types.ts +0 -0
- /package/s/{tests.test.ts → test.ts} +0 -0
- /package/x/{loaders → loader}/index.barrel.js +0 -0
- /package/x/{loaders → loader}/index.js +0 -0
- /package/x/{loaders → loader}/make.d.ts +0 -0
- /package/x/{loaders → loader}/make.js +0 -0
- /package/x/{loaders → loader}/mock.d.ts +0 -0
- /package/x/{loaders → loader}/mock.js +0 -0
- /package/x/{loaders → loader}/parts/anims.d.ts +0 -0
- /package/x/{loaders → loader}/parts/anims.js +0 -0
- /package/x/{loaders → loader}/parts/ascii-anim.d.ts +0 -0
- /package/x/{loaders → loader}/parts/ascii-anim.js +0 -0
- /package/x/{loaders → loader}/parts/error-display.d.ts +0 -0
- /package/x/{loaders → loader}/parts/error-display.js +0 -0
- /package/x/{loaders → loader}/types.js +0 -0
- /package/x/{ops → op}/index.d.ts +0 -0
- /package/x/{ops → op}/index.js +0 -0
- /package/x/{ops → op}/op.d.ts +0 -0
- /package/x/{ops → op}/op.js +0 -0
- /package/x/{ops → op}/podium.d.ts +0 -0
- /package/x/{ops → op}/podium.js +0 -0
- /package/x/{ops → op}/types.d.ts +0 -0
- /package/x/{ops → op}/types.js +0 -0
- /package/x/{tests.test.d.ts → test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -2,33 +2,35 @@
|
|
|
2
2
|
<div align="center"><img alt="" width="256" src="./assets/favicon.png"/></div>
|
|
3
3
|
|
|
4
4
|
# 🦝 sly
|
|
5
|
-
> *mischievous shadow views*
|
|
6
5
|
|
|
7
6
|
```sh
|
|
8
7
|
npm install lit @e280/sly @e280/strata @e280/stz
|
|
9
8
|
```
|
|
10
9
|
|
|
11
|
-
[@e280](https://e280.org/)'s
|
|
10
|
+
#### [@e280](https://e280.org/)'s [lit-based](https://lit.dev/) web library for reactive light or shadow views
|
|
12
11
|
|
|
13
|
-
-
|
|
14
|
-
- 🪝 [**#hooks
|
|
15
|
-
- 🫛 [**#ops
|
|
16
|
-
- ⏳ [**#loaders
|
|
17
|
-
- 🪙 [**#loot
|
|
18
|
-
- 🪄 [**#dom
|
|
19
|
-
- 🧪 https://sly.e280.org
|
|
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
|
|
20
19
|
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
<br/><br/>
|
|
24
23
|
<a id="views"></a>
|
|
25
24
|
|
|
26
|
-
##
|
|
27
|
-
> *
|
|
25
|
+
## 🎭 views
|
|
26
|
+
> *reactive lit-html views*
|
|
28
27
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
- 🪝 **hooks-based
|
|
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
|
|
32
34
|
|
|
33
35
|
```ts
|
|
34
36
|
import {html} from "lit"
|
|
@@ -40,7 +42,7 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
40
42
|
```
|
|
41
43
|
|
|
42
44
|
### 🌞 light views
|
|
43
|
-
> *just pretend it's react
|
|
45
|
+
> *just pretend it's like react!*
|
|
44
46
|
|
|
45
47
|
- **define a light view**
|
|
46
48
|
```ts
|
|
@@ -58,14 +60,17 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
58
60
|
```
|
|
59
61
|
- **render it into the dom**
|
|
60
62
|
```ts
|
|
61
|
-
dom.
|
|
63
|
+
dom.render(dom(".demo"), html`
|
|
62
64
|
<h1>my cool counter demo</h1>
|
|
63
65
|
${MyCounter(123)}
|
|
64
66
|
`)
|
|
65
67
|
```
|
|
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.
|
|
66
71
|
|
|
67
72
|
### 🌚 shadow views
|
|
68
|
-
> *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 [
|
|
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)*
|
|
69
74
|
|
|
70
75
|
- **define a shadow view**
|
|
71
76
|
```ts
|
|
@@ -73,28 +78,33 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
73
78
|
import {shadow, useName, useCss, useSignal} from "@e280/sly"
|
|
74
79
|
|
|
75
80
|
export const MyShadowCounter = shadow((start: number) => {
|
|
76
|
-
useName("
|
|
81
|
+
useName("counter")
|
|
77
82
|
useCss(css`button { color: cyan }`)
|
|
78
83
|
|
|
79
84
|
const $count = useSignal(start)
|
|
80
85
|
const increment = () => $count.value++
|
|
81
86
|
|
|
82
87
|
return html`
|
|
83
|
-
<button @click="${increment}">${$count
|
|
88
|
+
<button @click="${increment}">${$count.value}</button>
|
|
84
89
|
<slot></slot>
|
|
85
90
|
`
|
|
86
91
|
})
|
|
87
92
|
```
|
|
88
93
|
- **render it into the dom**
|
|
89
94
|
```ts
|
|
90
|
-
dom.
|
|
95
|
+
dom.render(dom(".demo"), html`
|
|
91
96
|
<h1>my cool counter demo</h1>
|
|
92
97
|
${MyShadowCounter(234)}
|
|
93
98
|
`)
|
|
94
99
|
```
|
|
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
|
+
```
|
|
95
105
|
- **.with to nest children or set attrs**
|
|
96
106
|
```ts
|
|
97
|
-
dom.
|
|
107
|
+
dom.render(dom(".demo"), html`
|
|
98
108
|
<h1>my cool counter demo</h1>
|
|
99
109
|
|
|
100
110
|
${MyShadowCounter.with({
|
|
@@ -106,13 +116,36 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
106
116
|
})}
|
|
107
117
|
`)
|
|
108
118
|
```
|
|
109
|
-
- **
|
|
119
|
+
- **you can do custom shadow setup if needed** (default shown)
|
|
110
120
|
```ts
|
|
111
|
-
|
|
112
|
-
|
|
121
|
+
import {SlyShadow} from "@e280/sly"
|
|
122
|
+
|
|
123
|
+
const customShadow = shadow.setup(() => {
|
|
124
|
+
SlyShadow.register()
|
|
125
|
+
const host = document.createElement("sly-shadow")
|
|
113
126
|
const shadow = host.attachShadow({mode: "open"})
|
|
114
127
|
return {host, shadow}
|
|
115
|
-
})
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const MyShadowView = customShadow(() => html`<p>shrouded in darkness</p>`)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 🍨 web components
|
|
134
|
+
> *web-native custom elements*
|
|
135
|
+
|
|
136
|
+
- **they use hooks like the views, but they don't take props**
|
|
137
|
+
```ts
|
|
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})
|
|
145
|
+
```
|
|
146
|
+
```html
|
|
147
|
+
<my-light></my-light>
|
|
148
|
+
<my-shadow></my-shadow>
|
|
116
149
|
```
|
|
117
150
|
|
|
118
151
|
|
|
@@ -121,48 +154,58 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
121
154
|
<a id="hooks"></a>
|
|
122
155
|
|
|
123
156
|
## 🪝 hooks
|
|
124
|
-
> *composable view state and utilities*
|
|
157
|
+
> *composable view state and utilities*
|
|
125
158
|
|
|
126
159
|
### 👮 follow the hooks rules
|
|
127
160
|
|
|
128
|
-
just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of
|
|
161
|
+
just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of hooks seriously matters.
|
|
129
162
|
|
|
130
|
-
you must not call these hooks under
|
|
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..*
|
|
131
164
|
|
|
132
165
|
### 🌚 shadow-only hooks
|
|
133
|
-
- **useName
|
|
166
|
+
- **useName,** set the "view" attribute value
|
|
134
167
|
```ts
|
|
135
168
|
useName("squarepants")
|
|
136
169
|
// <sly-shadow view="squarepants">
|
|
137
170
|
```
|
|
138
|
-
- **useCss
|
|
171
|
+
- **useCss,** attach stylesheets (use lit's `css`!) to the shadow root
|
|
139
172
|
```ts
|
|
140
173
|
useCss(css1, css2, css3)
|
|
141
174
|
```
|
|
142
|
-
- **useHost
|
|
175
|
+
- **useHost,** get the host element
|
|
143
176
|
```ts
|
|
144
177
|
const host = useHost()
|
|
145
178
|
```
|
|
146
|
-
- **useShadow
|
|
179
|
+
- **useShadow,** get the shadow root
|
|
147
180
|
```ts
|
|
148
181
|
const shadow = useShadow()
|
|
149
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
|
+
})
|
|
190
|
+
|
|
191
|
+
attrs.count = 123 // set the attr
|
|
192
|
+
```
|
|
150
193
|
|
|
151
194
|
### 🌞 universal hooks
|
|
152
|
-
- **useState
|
|
195
|
+
- **useState,** react-like hook to create some reactive state (we prefer signals)
|
|
153
196
|
```ts
|
|
154
197
|
const [count, setCount] = useState(0)
|
|
155
198
|
|
|
156
199
|
const increment = () => setCount(n => n + 1)
|
|
157
200
|
```
|
|
158
|
-
- **useRef
|
|
201
|
+
- **useRef,** react-like hook to make a non-reactive box for a value
|
|
159
202
|
```ts
|
|
160
203
|
const ref = useRef(0)
|
|
161
204
|
|
|
162
205
|
ref.current // 0
|
|
163
206
|
ref.current = 1 // does not trigger rerender
|
|
164
207
|
```
|
|
165
|
-
- **useSignal
|
|
208
|
+
- **useSignal,** create a [strata](https://github.com/e280/strata) signal
|
|
166
209
|
```ts
|
|
167
210
|
const $count = useSignal(1)
|
|
168
211
|
|
|
@@ -172,13 +215,11 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
172
215
|
// write the signal
|
|
173
216
|
$count(2)
|
|
174
217
|
```
|
|
175
|
-
|
|
176
|
-
- **useDerived** — create a [strata](https://github.com/e280/strata) derived signal
|
|
218
|
+
- **useDerived,** create a [strata](https://github.com/e280/strata) derived signal
|
|
177
219
|
```ts
|
|
178
220
|
const $product = useDerived(() => $count() * $whatever())
|
|
179
221
|
```
|
|
180
|
-
|
|
181
|
-
- **useOnce** — run fn at initialization, and return a value
|
|
222
|
+
- **useOnce,** run fn at initialization, and return a value
|
|
182
223
|
```ts
|
|
183
224
|
const whatever = useOnce(() => {
|
|
184
225
|
console.log("happens one time")
|
|
@@ -187,14 +228,14 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
187
228
|
|
|
188
229
|
whatever // 123
|
|
189
230
|
```
|
|
190
|
-
- **useMount
|
|
231
|
+
- **useMount,** setup mount/unmount lifecycle
|
|
191
232
|
```ts
|
|
192
233
|
useMount(() => {
|
|
193
234
|
console.log("mounted")
|
|
194
235
|
return () => console.log("unmounted")
|
|
195
236
|
})
|
|
196
237
|
```
|
|
197
|
-
- **useWake
|
|
238
|
+
- **useWake,** run fn each time mounted, and return value
|
|
198
239
|
```ts
|
|
199
240
|
const whatever = useWake(() => {
|
|
200
241
|
console.log("mounted")
|
|
@@ -203,7 +244,7 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
203
244
|
|
|
204
245
|
whatever // 123
|
|
205
246
|
```
|
|
206
|
-
- **useLife
|
|
247
|
+
- **useLife,** mount/unmount lifecycle, but also return a value
|
|
207
248
|
```ts
|
|
208
249
|
const whatever = useLife(() => {
|
|
209
250
|
console.log("mounted")
|
|
@@ -213,30 +254,30 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
213
254
|
|
|
214
255
|
whatever // 123
|
|
215
256
|
```
|
|
216
|
-
- **useRender
|
|
257
|
+
- **useRender,** returns a fn to rerender the view (debounced)
|
|
217
258
|
```ts
|
|
218
259
|
const render = useRender()
|
|
219
260
|
|
|
220
261
|
render().then(() => console.log("render done"))
|
|
221
262
|
```
|
|
222
|
-
- **useRendered
|
|
263
|
+
- **useRendered,** get a promise that resolves *after* the next render
|
|
223
264
|
```ts
|
|
224
265
|
useRendered().then(() => console.log("rendered"))
|
|
225
266
|
```
|
|
226
|
-
- **useOp
|
|
267
|
+
- **useOp,** start loading an op based on an async fn
|
|
227
268
|
```ts
|
|
228
269
|
const op = useOp(async() => {
|
|
229
270
|
await nap(5000)
|
|
230
271
|
return 123
|
|
231
272
|
})
|
|
232
273
|
```
|
|
233
|
-
- **useOpPromise
|
|
274
|
+
- **useOpPromise,** start loading an op based on a promise
|
|
234
275
|
```ts
|
|
235
276
|
const op = useOpPromise(doAsyncWork())
|
|
236
277
|
```
|
|
237
278
|
|
|
238
279
|
### 🧑🍳 happy hooks recipes
|
|
239
|
-
- make a ticker
|
|
280
|
+
- make a ticker, mount, cycle, and nap
|
|
240
281
|
```ts
|
|
241
282
|
import {cycle, nap} from "@e280/stz"
|
|
242
283
|
```
|
|
@@ -250,7 +291,9 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
250
291
|
```
|
|
251
292
|
- wake + rendered, to do something after each mount's first render
|
|
252
293
|
```ts
|
|
253
|
-
|
|
294
|
+
const rendered = useRendered()
|
|
295
|
+
|
|
296
|
+
useWake(() => rendered.then(() => {
|
|
254
297
|
console.log("after first render")
|
|
255
298
|
}))
|
|
256
299
|
```
|
|
@@ -261,7 +304,7 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
261
304
|
<a id="ops"></a>
|
|
262
305
|
|
|
263
306
|
## 🫛 ops
|
|
264
|
-
> *
|
|
307
|
+
> *helpers for async operations*
|
|
265
308
|
|
|
266
309
|
```ts
|
|
267
310
|
import {nap} from "@e280/stz"
|
|
@@ -296,22 +339,22 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
|
296
339
|
podium.value(["ready", 123])
|
|
297
340
|
// 123
|
|
298
341
|
```
|
|
299
|
-
- see more at [podium.ts](./s/
|
|
342
|
+
- see more at [podium.ts](./s/op/podium.ts)
|
|
300
343
|
|
|
301
344
|
### 🫛 ops: nice pod ergonomics
|
|
302
|
-
- an `Op<V>` wraps a pod with a signal for reactivity
|
|
345
|
+
- an `Op<V>` wraps a pod with a strata signal for reactivity
|
|
303
346
|
- create an op
|
|
304
347
|
```ts
|
|
305
|
-
|
|
348
|
+
new Op<number>() // loading status by default
|
|
306
349
|
```
|
|
307
350
|
```ts
|
|
308
|
-
|
|
351
|
+
Op.loading<number>()
|
|
309
352
|
```
|
|
310
353
|
```ts
|
|
311
|
-
|
|
354
|
+
Op.ready<number>(123)
|
|
312
355
|
```
|
|
313
356
|
```ts
|
|
314
|
-
|
|
357
|
+
Op.error<number>(new Error())
|
|
315
358
|
```
|
|
316
359
|
- 🔥 create an op that calls and tracks an async fn
|
|
317
360
|
```ts
|
|
@@ -338,13 +381,12 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
|
338
381
|
- select executes a fn based on the status
|
|
339
382
|
```ts
|
|
340
383
|
const result = op.select({
|
|
341
|
-
loading: () => "
|
|
384
|
+
loading: () => "still loading...",
|
|
342
385
|
ready: value => `dude, it's ready! ${value}`,
|
|
343
|
-
error: err => `
|
|
386
|
+
error: err => `ack! an error!`,
|
|
344
387
|
})
|
|
345
388
|
|
|
346
|
-
result
|
|
347
|
-
// "dude, it's ready! 123"
|
|
389
|
+
result // "dude, it's ready! 123"
|
|
348
390
|
```
|
|
349
391
|
- morph returns a new pod, transforming the value if ready
|
|
350
392
|
```ts
|
|
@@ -370,7 +412,7 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
|
370
412
|
<a id="loaders"></a>
|
|
371
413
|
|
|
372
414
|
## ⏳ loaders
|
|
373
|
-
> *animated loading spinners for ops*
|
|
415
|
+
> *animated loading spinners for ops*
|
|
374
416
|
|
|
375
417
|
```ts
|
|
376
418
|
import {loaders} from "@e280/sly"
|
|
@@ -527,7 +569,7 @@ import {ev} from "@e280/stz"
|
|
|
527
569
|
<a id="dom"></a>
|
|
528
570
|
|
|
529
571
|
## 🪄 dom
|
|
530
|
-
> *the "it's not jquery!" multitool*
|
|
572
|
+
> *the "it's not jquery!" multitool*
|
|
531
573
|
|
|
532
574
|
```ts
|
|
533
575
|
import {dom} from "@e280/sly"
|
|
@@ -661,10 +703,10 @@ import {dom} from "@e280/sly"
|
|
|
661
703
|
```
|
|
662
704
|
or if you wanna be more loosey-goosey, skip the spec
|
|
663
705
|
```ts
|
|
664
|
-
const
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
706
|
+
const {attrs} = dom.in(".demo")
|
|
707
|
+
attrs.strings.name = "pimsley"
|
|
708
|
+
attrs.numbers.count = 125
|
|
709
|
+
attrs.booleans.active = true
|
|
668
710
|
```
|
|
669
711
|
|
|
670
712
|
|
package/package.json
CHANGED
|
@@ -1,50 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/sly",
|
|
3
|
-
"version": "0.3.0-
|
|
3
|
+
"version": "0.3.0-10",
|
|
4
4
|
"description": "web shadow views",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"x",
|
|
9
|
+
"s"
|
|
10
|
+
],
|
|
7
11
|
"main": "./x/index.js",
|
|
8
12
|
"exports": {
|
|
9
13
|
".": "./x/index.js",
|
|
10
14
|
"./dom": "./x/dom/index.js",
|
|
11
|
-
"./
|
|
15
|
+
"./loader": "./x/loader/index.js",
|
|
12
16
|
"./loot": "./x/loot/index.js",
|
|
13
|
-
"./
|
|
17
|
+
"./op": "./x/op/index.js",
|
|
14
18
|
"./view": "./x/view/index.js"
|
|
15
19
|
},
|
|
16
|
-
"
|
|
17
|
-
"x",
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "rm -rf x && mkdir x && ln -s '$(realpath s)' x/s && ln -s '$(realpath assets)' x/assets && tsc && scute -v",
|
|
22
|
+
"start": "octo 'tsc -w' 'scute -wv' 'node --watch x/test.js' 'http-server x'",
|
|
23
|
+
"count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
|
|
24
|
+
"test": "node x/test.js"
|
|
25
|
+
},
|
|
20
26
|
"peerDependencies": {
|
|
21
27
|
"lit": "^3.3.2"
|
|
22
28
|
},
|
|
23
29
|
"dependencies": {
|
|
24
|
-
"@e280/strata": "^0.2
|
|
25
|
-
"@e280/stz": "^0.2.
|
|
30
|
+
"@e280/strata": "^0.3.0-2",
|
|
31
|
+
"@e280/stz": "^0.2.24"
|
|
26
32
|
},
|
|
27
33
|
"devDependencies": {
|
|
34
|
+
"@e280/octo": "^0.1.0-12",
|
|
28
35
|
"@e280/science": "^0.1.8",
|
|
29
|
-
"@e280/scute": "^0.
|
|
36
|
+
"@e280/scute": "^0.3.0-1",
|
|
30
37
|
"http-server": "^14.1.1",
|
|
31
38
|
"npm-run-all": "^4.1.5",
|
|
32
39
|
"typescript": "^5.9.3"
|
|
33
40
|
},
|
|
34
|
-
"scripts": {
|
|
35
|
-
"build": "run-s _clean _ln _tsc _scute",
|
|
36
|
-
"start": "octo 'scute -vw' 'tsc -w' 'node --watch x/tests.test.js' 'http-server x'",
|
|
37
|
-
"count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
|
|
38
|
-
"test": "node x/tests.test.js",
|
|
39
|
-
"test-inspect": "node inspect x/tests.test.js",
|
|
40
|
-
"_clean": "rm -rf x && mkdir x",
|
|
41
|
-
"_tsc": "tsc",
|
|
42
|
-
"_scute": "scute -v",
|
|
43
|
-
"_ln": "run-s _ln:s _ln:assets",
|
|
44
|
-
"_ln:s": "ln -s \"$(realpath s)\" x/s",
|
|
45
|
-
"_ln:assets": "ln -s \"$(realpath assets)\" x/assets",
|
|
46
|
-
"_lnx:stz": "rm -rf node_modules/@e280/stz && ln -s \"$(realpath ../stz)\" node_modules/@e280/stz"
|
|
47
|
-
},
|
|
48
41
|
"author": "Chase Moskal <chasemoskal@gmail.com>",
|
|
49
42
|
"homepage": "https://github.com/e280/sly#readme",
|
|
50
43
|
"repository": {
|
|
@@ -55,9 +48,10 @@
|
|
|
55
48
|
"url": "https://github.com/e280/sly/issues"
|
|
56
49
|
},
|
|
57
50
|
"keywords": [
|
|
51
|
+
"lit",
|
|
52
|
+
"views",
|
|
58
53
|
"shadow views",
|
|
59
54
|
"shadow dom",
|
|
60
|
-
"components"
|
|
61
|
-
"lit"
|
|
55
|
+
"components"
|
|
62
56
|
]
|
|
63
57
|
}
|
package/s/demo/demo.bundle.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
import {dom} from "../dom/dom.js"
|
|
3
3
|
import {Demo} from "./views/demo.js"
|
|
4
|
+
import {TimeLight} from "./views/time-light.js"
|
|
5
|
+
import {TimeShadow} from "./views/time-shadow.js"
|
|
4
6
|
|
|
5
|
-
dom.
|
|
7
|
+
dom.register({TimeShadow, TimeLight})
|
|
8
|
+
|
|
9
|
+
dom.render(dom(".demo"), Demo())
|
|
6
10
|
console.log("🦝 sly")
|
|
7
11
|
|
package/s/demo/views/demo.ts
CHANGED
package/s/demo/views/loaders.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import {css, html} from "lit"
|
|
3
|
-
import {Op} from "../../
|
|
3
|
+
import {Op} from "../../op/op.js"
|
|
4
4
|
import {shadow} from "../../view/shadow.js"
|
|
5
|
-
import {loaders} from "../../
|
|
5
|
+
import {loaders} from "../../loader/index.js"
|
|
6
6
|
import {cssReset, useName, useOnce, useStyles} from "../../view/index.js"
|
|
7
7
|
|
|
8
8
|
export const LoadersView = shadow(() => {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
import {html} from "lit"
|
|
3
|
+
import {cycle, nap} from "@e280/stz"
|
|
4
|
+
import {useMount, useSignal} from "../../view/index.js"
|
|
5
|
+
import {lightElement} from "../../view/elements/light.js"
|
|
6
|
+
|
|
7
|
+
export class TimeLight extends lightElement(() => {
|
|
8
|
+
const $time = useSignal(Date.now())
|
|
9
|
+
|
|
10
|
+
useMount(() => cycle(async() => {
|
|
11
|
+
await nap(100)
|
|
12
|
+
$time(Date.now())
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
return html`
|
|
16
|
+
<p>${$time()}</p>
|
|
17
|
+
`
|
|
18
|
+
}) {}
|
|
19
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
import {css, html} from "lit"
|
|
3
|
+
import {cycle, nap} from "@e280/stz"
|
|
4
|
+
import {shadowElement} from "../../view/elements/shadow.js"
|
|
5
|
+
import {useCss, useMount, useName, useSignal} from "../../view/index.js"
|
|
6
|
+
|
|
7
|
+
export class TimeShadow extends shadowElement(() => {
|
|
8
|
+
useName("time-shadow")
|
|
9
|
+
useCss(css`:host{display:inline-block} button{color:cyan}`)
|
|
10
|
+
|
|
11
|
+
const $time = useSignal(Date.now())
|
|
12
|
+
|
|
13
|
+
useMount(() => cycle(async() => {
|
|
14
|
+
await nap(100)
|
|
15
|
+
$time(Date.now())
|
|
16
|
+
}))
|
|
17
|
+
|
|
18
|
+
return html`
|
|
19
|
+
<p>${$time()}</p>
|
|
20
|
+
`
|
|
21
|
+
}) {}
|
|
22
|
+
|
package/s/dom/attrs/attrs.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
import {AttrSpec} from "../types.js"
|
|
3
3
|
import {onAttrs} from "./parts/on-attrs.js"
|
|
4
|
-
import {attrSpec} from "./parts/attr-spec.js"
|
|
5
4
|
import {AttrProxies} from "./parts/attr-proxies.js"
|
|
6
5
|
import {attrGet, attrSet} from "./parts/attr-fns.js"
|
|
6
|
+
import {attrSpec, AttrSpecOptions} from "./parts/attr-spec.js"
|
|
7
7
|
|
|
8
8
|
export function attrs(element: HTMLElement) {
|
|
9
9
|
const proxies = new AttrProxies(element)
|
|
@@ -11,8 +11,8 @@ export function attrs(element: HTMLElement) {
|
|
|
11
11
|
strings: proxies.strings,
|
|
12
12
|
numbers: proxies.numbers,
|
|
13
13
|
booleans: proxies.booleans,
|
|
14
|
-
on: (fn:
|
|
15
|
-
spec: <A extends AttrSpec>(spec: A) => attrSpec(element, spec),
|
|
14
|
+
on: (fn: MutationCallback) => onAttrs(element, fn),
|
|
15
|
+
spec: <A extends AttrSpec>(spec: A, options: AttrSpecOptions = {}) => attrSpec(element, spec, options),
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
import {attrGet, attrSet} from "./attr-fns.js"
|
|
3
3
|
import {AttrSpec, AttrTypes} from "../../types.js"
|
|
4
4
|
|
|
5
|
+
export type AttrSpecOptions = {
|
|
6
|
+
beforeSet?: (attrKey: string) => void
|
|
7
|
+
afterSet?: (attrKey: string) => void
|
|
8
|
+
}
|
|
9
|
+
|
|
5
10
|
/** specify available html attributes and their types and create a proxy accessor */
|
|
6
11
|
export const attrSpec = <A extends AttrSpec>(
|
|
7
12
|
e: HTMLElement,
|
|
8
13
|
spec: A,
|
|
14
|
+
options: AttrSpecOptions = {},
|
|
9
15
|
) => new Proxy(spec, {
|
|
10
16
|
|
|
11
17
|
get: (_target, key: string) => {
|
|
@@ -18,11 +24,17 @@ export const attrSpec = <A extends AttrSpec>(
|
|
|
18
24
|
},
|
|
19
25
|
|
|
20
26
|
set: (_target, key: string, value: any) => {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
try {
|
|
28
|
+
options.beforeSet?.(key)
|
|
29
|
+
switch (spec[key]) {
|
|
30
|
+
case String: return attrSet.string(e, key, value)
|
|
31
|
+
case Number: return attrSet.number(e, key, value)
|
|
32
|
+
case Boolean: return attrSet.boolean(e, key, value)
|
|
33
|
+
default: throw new Error(`invalid attribute type for "${key}"`)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
options.afterSet?.(key)
|
|
26
38
|
}
|
|
27
39
|
},
|
|
28
40
|
}) as any as AttrTypes<A>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
/** respond when any attribute changes on the html element */
|
|
3
|
-
export function onAttrs(element: HTMLElement, fn:
|
|
3
|
+
export function onAttrs(element: HTMLElement, fn: MutationCallback) {
|
|
4
4
|
const observer = new MutationObserver(fn)
|
|
5
5
|
observer.observe(element, {attributes: true})
|
|
6
6
|
return () => observer.disconnect()
|
package/s/dom/dom.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {register} from "./parts/register.js"
|
|
|
11
11
|
import {Queryable, Renderable} from "./types.js"
|
|
12
12
|
import {queryAll, queryMaybe, queryRequire} from "./parts/queries.js"
|
|
13
13
|
|
|
14
|
-
export function dom<E extends
|
|
14
|
+
export function dom<E extends HTMLElement>(selector: string, container: Queryable = document) {
|
|
15
15
|
return queryRequire<E>(selector, container)
|
|
16
16
|
}
|
|
17
17
|
|
package/s/index.ts
CHANGED