@e280/sly 0.3.0-2 → 0.3.0-4
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 +72 -57
- package/package.json +1 -1
- package/s/view/{parts → common}/sly-shadow.ts +6 -0
- package/s/view/index.ts +1 -0
- package/s/view/shadow.ts +11 -11
- package/x/demo/demo.bundle.min.js +11 -11
- package/x/demo/demo.bundle.min.js.map +4 -4
- package/x/index.html +2 -2
- 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/index.d.ts +1 -0
- package/x/view/index.js +1 -0
- package/x/view/index.js.map +1 -1
- package/x/view/shadow.d.ts +2 -1
- package/x/view/shadow.js +9 -10
- package/x/view/shadow.js.map +1 -1
- package/x/view/parts/sly-shadow.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,21 +2,20 @@
|
|
|
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
|
-
- 🎭 [**#views
|
|
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
|
|
|
@@ -24,12 +23,13 @@ npm install lit @e280/sly @e280/strata @e280/stz
|
|
|
24
23
|
<a id="views"></a>
|
|
25
24
|
|
|
26
25
|
## 🎭 views
|
|
27
|
-
> *
|
|
26
|
+
> *"flourish in the light.. or thrive in the darkness"*
|
|
28
27
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
28
|
+
- 🌗 **light or shadow,** render nakedly on the page, or within a cozy shadow bubble
|
|
29
|
+
- 🪝 **hooks-based,** familiar react-style [hooks](#hooks)
|
|
30
|
+
- ⚡ **auto-reactive,** views magically rerender on [strata](https://github.com/e280/strata)-compatible state changes
|
|
31
|
+
- 🪶 **no compile step,** just god's honest javascript via [lit](https://lit.dev/)-html tagged-template-literals
|
|
32
|
+
- 🧩 **not web components,** no dom registration needed, just vibes and good typings
|
|
33
33
|
|
|
34
34
|
```ts
|
|
35
35
|
import {html} from "lit"
|
|
@@ -41,7 +41,7 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
### 🌞 light views
|
|
44
|
-
> *just pretend it's react*
|
|
44
|
+
> *"just pretend it's react, without jsx"*
|
|
45
45
|
|
|
46
46
|
- **define a light view**
|
|
47
47
|
```ts
|
|
@@ -64,9 +64,15 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
64
64
|
${MyCounter(123)}
|
|
65
65
|
`)
|
|
66
66
|
```
|
|
67
|
+
- light views have no host element, rendered output looks like:
|
|
68
|
+
```html
|
|
69
|
+
<h1>my cool counter demo</h1>
|
|
70
|
+
<button>123</button>
|
|
71
|
+
```
|
|
72
|
+
- **light views are naked,** they don't have a containing host element
|
|
67
73
|
|
|
68
74
|
### 🌚 shadow views
|
|
69
|
-
> *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 [
|
|
75
|
+
> *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)*
|
|
70
76
|
|
|
71
77
|
- **define a shadow view**
|
|
72
78
|
```ts
|
|
@@ -74,14 +80,14 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
74
80
|
import {shadow, useName, useCss, useSignal} from "@e280/sly"
|
|
75
81
|
|
|
76
82
|
export const MyShadowCounter = shadow((start: number) => {
|
|
77
|
-
useName("
|
|
83
|
+
useName("counter")
|
|
78
84
|
useCss(css`button { color: cyan }`)
|
|
79
85
|
|
|
80
86
|
const $count = useSignal(start)
|
|
81
87
|
const increment = () => $count.value++
|
|
82
88
|
|
|
83
89
|
return html`
|
|
84
|
-
<button @click="${increment}">${$count
|
|
90
|
+
<button @click="${increment}">${$count.value}</button>
|
|
85
91
|
<slot></slot>
|
|
86
92
|
`
|
|
87
93
|
})
|
|
@@ -93,6 +99,11 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
93
99
|
${MyShadowCounter(234)}
|
|
94
100
|
`)
|
|
95
101
|
```
|
|
102
|
+
- shadow views have a host element, rendered output looks like:
|
|
103
|
+
```html
|
|
104
|
+
<h1>my cool counter demo</h1>
|
|
105
|
+
<sly-shadow view="counter"></sly-shadow>
|
|
106
|
+
```
|
|
96
107
|
- **.with to nest children or set attrs**
|
|
97
108
|
```ts
|
|
98
109
|
dom.render(dom(".demo"), html`
|
|
@@ -107,13 +118,18 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
107
118
|
})}
|
|
108
119
|
`)
|
|
109
120
|
```
|
|
110
|
-
- **you can do custom shadow config if needed**
|
|
121
|
+
- **you can do custom shadow config if needed** (default shown)
|
|
111
122
|
```ts
|
|
112
|
-
|
|
113
|
-
|
|
123
|
+
import {SlyShadow} from "@e280/sly"
|
|
124
|
+
|
|
125
|
+
const customShadow = shadow.config(() => {
|
|
126
|
+
SlyShadow.register()
|
|
127
|
+
const host = document.createElement("sly-shadow")
|
|
114
128
|
const shadow = host.attachShadow({mode: "open"})
|
|
115
129
|
return {host, shadow}
|
|
116
|
-
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
const MyShadowView = customShadow(() => html`<p>shrouded in darkness</p>`)
|
|
117
133
|
```
|
|
118
134
|
|
|
119
135
|
|
|
@@ -122,48 +138,48 @@ export const MyShadowView = shadow(() => html`<p>shrouded in darkness</p>`)
|
|
|
122
138
|
<a id="hooks"></a>
|
|
123
139
|
|
|
124
140
|
## 🪝 hooks
|
|
125
|
-
> *composable view state and utilities*
|
|
141
|
+
> *composable view state and utilities*
|
|
126
142
|
|
|
127
143
|
### 👮 follow the hooks rules
|
|
128
144
|
|
|
129
|
-
just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of
|
|
145
|
+
just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of hooks seriously matters.
|
|
130
146
|
|
|
131
|
-
you must not call these hooks under
|
|
147
|
+
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..*
|
|
132
148
|
|
|
133
149
|
### 🌚 shadow-only hooks
|
|
134
|
-
- **useName
|
|
150
|
+
- **useName,** set the "view" attribute value
|
|
135
151
|
```ts
|
|
136
152
|
useName("squarepants")
|
|
137
153
|
// <sly-shadow view="squarepants">
|
|
138
154
|
```
|
|
139
|
-
- **useCss
|
|
155
|
+
- **useCss,** attach stylesheets (use lit's `css`!) to the shadow root
|
|
140
156
|
```ts
|
|
141
157
|
useCss(css1, css2, css3)
|
|
142
158
|
```
|
|
143
|
-
- **useHost
|
|
159
|
+
- **useHost,** get the host element
|
|
144
160
|
```ts
|
|
145
161
|
const host = useHost()
|
|
146
162
|
```
|
|
147
|
-
- **useShadow
|
|
163
|
+
- **useShadow,** get the shadow root
|
|
148
164
|
```ts
|
|
149
165
|
const shadow = useShadow()
|
|
150
166
|
```
|
|
151
167
|
|
|
152
168
|
### 🌞 universal hooks
|
|
153
|
-
- **useState
|
|
169
|
+
- **useState,** react-like hook to create some reactive state (we prefer signals)
|
|
154
170
|
```ts
|
|
155
171
|
const [count, setCount] = useState(0)
|
|
156
172
|
|
|
157
173
|
const increment = () => setCount(n => n + 1)
|
|
158
174
|
```
|
|
159
|
-
- **useRef
|
|
175
|
+
- **useRef,** react-like hook to make a non-reactive box for a value
|
|
160
176
|
```ts
|
|
161
177
|
const ref = useRef(0)
|
|
162
178
|
|
|
163
179
|
ref.current // 0
|
|
164
180
|
ref.current = 1 // does not trigger rerender
|
|
165
181
|
```
|
|
166
|
-
- **useSignal
|
|
182
|
+
- **useSignal,** create a [strata](https://github.com/e280/strata) signal
|
|
167
183
|
```ts
|
|
168
184
|
const $count = useSignal(1)
|
|
169
185
|
|
|
@@ -173,13 +189,11 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
173
189
|
// write the signal
|
|
174
190
|
$count(2)
|
|
175
191
|
```
|
|
176
|
-
|
|
177
|
-
- **useDerived** — create a [strata](https://github.com/e280/strata) derived signal
|
|
192
|
+
- **useDerived,** create a [strata](https://github.com/e280/strata) derived signal
|
|
178
193
|
```ts
|
|
179
194
|
const $product = useDerived(() => $count() * $whatever())
|
|
180
195
|
```
|
|
181
|
-
|
|
182
|
-
- **useOnce** — run fn at initialization, and return a value
|
|
196
|
+
- **useOnce,** run fn at initialization, and return a value
|
|
183
197
|
```ts
|
|
184
198
|
const whatever = useOnce(() => {
|
|
185
199
|
console.log("happens one time")
|
|
@@ -188,14 +202,14 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
188
202
|
|
|
189
203
|
whatever // 123
|
|
190
204
|
```
|
|
191
|
-
- **useMount
|
|
205
|
+
- **useMount,** setup mount/unmount lifecycle
|
|
192
206
|
```ts
|
|
193
207
|
useMount(() => {
|
|
194
208
|
console.log("mounted")
|
|
195
209
|
return () => console.log("unmounted")
|
|
196
210
|
})
|
|
197
211
|
```
|
|
198
|
-
- **useWake
|
|
212
|
+
- **useWake,** run fn each time mounted, and return value
|
|
199
213
|
```ts
|
|
200
214
|
const whatever = useWake(() => {
|
|
201
215
|
console.log("mounted")
|
|
@@ -204,7 +218,7 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
204
218
|
|
|
205
219
|
whatever // 123
|
|
206
220
|
```
|
|
207
|
-
- **useLife
|
|
221
|
+
- **useLife,** mount/unmount lifecycle, but also return a value
|
|
208
222
|
```ts
|
|
209
223
|
const whatever = useLife(() => {
|
|
210
224
|
console.log("mounted")
|
|
@@ -214,30 +228,30 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
214
228
|
|
|
215
229
|
whatever // 123
|
|
216
230
|
```
|
|
217
|
-
- **useRender
|
|
231
|
+
- **useRender,** returns a fn to rerender the view (debounced)
|
|
218
232
|
```ts
|
|
219
233
|
const render = useRender()
|
|
220
234
|
|
|
221
235
|
render().then(() => console.log("render done"))
|
|
222
236
|
```
|
|
223
|
-
- **useRendered
|
|
237
|
+
- **useRendered,** get a promise that resolves *after* the next render
|
|
224
238
|
```ts
|
|
225
239
|
useRendered().then(() => console.log("rendered"))
|
|
226
240
|
```
|
|
227
|
-
- **useOp
|
|
241
|
+
- **useOp,** start loading an op based on an async fn
|
|
228
242
|
```ts
|
|
229
243
|
const op = useOp(async() => {
|
|
230
244
|
await nap(5000)
|
|
231
245
|
return 123
|
|
232
246
|
})
|
|
233
247
|
```
|
|
234
|
-
- **useOpPromise
|
|
248
|
+
- **useOpPromise,** start loading an op based on a promise
|
|
235
249
|
```ts
|
|
236
250
|
const op = useOpPromise(doAsyncWork())
|
|
237
251
|
```
|
|
238
252
|
|
|
239
253
|
### 🧑🍳 happy hooks recipes
|
|
240
|
-
- make a ticker
|
|
254
|
+
- make a ticker, mount, cycle, and nap
|
|
241
255
|
```ts
|
|
242
256
|
import {cycle, nap} from "@e280/stz"
|
|
243
257
|
```
|
|
@@ -251,7 +265,9 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
251
265
|
```
|
|
252
266
|
- wake + rendered, to do something after each mount's first render
|
|
253
267
|
```ts
|
|
254
|
-
|
|
268
|
+
const rendered = useRendered()
|
|
269
|
+
|
|
270
|
+
useWake(() => rendered.then(() => {
|
|
255
271
|
console.log("after first render")
|
|
256
272
|
}))
|
|
257
273
|
```
|
|
@@ -262,7 +278,7 @@ you must not call these hooks under `if` conditionals, or `for` loops, or in cal
|
|
|
262
278
|
<a id="ops"></a>
|
|
263
279
|
|
|
264
280
|
## 🫛 ops
|
|
265
|
-
> *
|
|
281
|
+
> *helpers for async operations*
|
|
266
282
|
|
|
267
283
|
```ts
|
|
268
284
|
import {nap} from "@e280/stz"
|
|
@@ -300,19 +316,19 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
|
300
316
|
- see more at [podium.ts](./s/ops/podium.ts)
|
|
301
317
|
|
|
302
318
|
### 🫛 ops: nice pod ergonomics
|
|
303
|
-
- an `Op<V>` wraps a pod with a signal for reactivity
|
|
319
|
+
- an `Op<V>` wraps a pod with a strata signal for reactivity
|
|
304
320
|
- create an op
|
|
305
321
|
```ts
|
|
306
|
-
|
|
322
|
+
new Op<number>() // loading status by default
|
|
307
323
|
```
|
|
308
324
|
```ts
|
|
309
|
-
|
|
325
|
+
Op.loading<number>()
|
|
310
326
|
```
|
|
311
327
|
```ts
|
|
312
|
-
|
|
328
|
+
Op.ready<number>(123)
|
|
313
329
|
```
|
|
314
330
|
```ts
|
|
315
|
-
|
|
331
|
+
Op.error<number>(new Error())
|
|
316
332
|
```
|
|
317
333
|
- 🔥 create an op that calls and tracks an async fn
|
|
318
334
|
```ts
|
|
@@ -339,13 +355,12 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
|
339
355
|
- select executes a fn based on the status
|
|
340
356
|
```ts
|
|
341
357
|
const result = op.select({
|
|
342
|
-
loading: () => "
|
|
358
|
+
loading: () => "still loading...",
|
|
343
359
|
ready: value => `dude, it's ready! ${value}`,
|
|
344
|
-
error: err => `
|
|
360
|
+
error: err => `ack! an error!`,
|
|
345
361
|
})
|
|
346
362
|
|
|
347
|
-
result
|
|
348
|
-
// "dude, it's ready! 123"
|
|
363
|
+
result // "dude, it's ready! 123"
|
|
349
364
|
```
|
|
350
365
|
- morph returns a new pod, transforming the value if ready
|
|
351
366
|
```ts
|
|
@@ -371,7 +386,7 @@ import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
|
371
386
|
<a id="loaders"></a>
|
|
372
387
|
|
|
373
388
|
## ⏳ loaders
|
|
374
|
-
> *animated loading spinners for ops*
|
|
389
|
+
> *animated loading spinners for ops*
|
|
375
390
|
|
|
376
391
|
```ts
|
|
377
392
|
import {loaders} from "@e280/sly"
|
|
@@ -528,7 +543,7 @@ import {ev} from "@e280/stz"
|
|
|
528
543
|
<a id="dom"></a>
|
|
529
544
|
|
|
530
545
|
## 🪄 dom
|
|
531
|
-
> *the "it's not jquery!" multitool*
|
|
546
|
+
> *the "it's not jquery!" multitool*
|
|
532
547
|
|
|
533
548
|
```ts
|
|
534
549
|
import {dom} from "@e280/sly"
|
package/package.json
CHANGED
package/s/view/index.ts
CHANGED
package/s/view/shadow.ts
CHANGED
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
import {microbounce} from "@e280/stz"
|
|
3
3
|
import {render as litRender} from "lit"
|
|
4
4
|
|
|
5
|
-
import {dom} from "../dom/dom.js"
|
|
6
5
|
import {ShadowCx} from "./parts/cx.js"
|
|
7
|
-
import {SlyShadow} from "./parts/sly-shadow.js"
|
|
8
6
|
import {hooks} from "./hooks/plumbing/hooks.js"
|
|
7
|
+
import {SlyShadow} from "./common/sly-shadow.js"
|
|
9
8
|
import {Reactivity} from "./parts/reactivity.js"
|
|
10
9
|
import {applyAttrs} from "./parts/apply-attrs.js"
|
|
11
10
|
import {Hookscope} from "./hooks/plumbing/hookscope.js"
|
|
12
11
|
import {View, Placement, ShadowSetup, ShadowView} from "./types.js"
|
|
13
12
|
import {AsyncDirective, directive, PartInfo} from "lit/async-directive.js"
|
|
14
13
|
|
|
14
|
+
export function shadowSetup(): ShadowSetup {
|
|
15
|
+
SlyShadow.register()
|
|
16
|
+
const host = document.createElement("sly-shadow")
|
|
17
|
+
const shadow = host.attachShadow({mode: "open"})
|
|
18
|
+
return {host, shadow}
|
|
19
|
+
}
|
|
20
|
+
|
|
15
21
|
export function shadow<Props extends any[]>(view: View<Props>) {
|
|
16
|
-
|
|
17
|
-
dom.register({SlyShadow}, {soft: true})
|
|
18
|
-
const host = document.createElement("sly-shadow")
|
|
19
|
-
const shadow = host.attachShadow({mode: "open"})
|
|
20
|
-
return {host, shadow}
|
|
21
|
-
}
|
|
22
|
-
return rawShadow(setupFn, view)
|
|
22
|
+
return rawShadow(shadowSetup, view)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
shadow.
|
|
25
|
+
shadow.setup = (setup: () => ShadowSetup) => (
|
|
26
26
|
<Props extends any[]>(view: View<Props>) => (
|
|
27
|
-
rawShadow(
|
|
27
|
+
rawShadow(setup, view)
|
|
28
28
|
)
|
|
29
29
|
)
|
|
30
30
|
|