@e280/sly 0.2.0-3 → 0.2.0-30
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 +624 -97
- package/package.json +13 -6
- package/s/base/element.ts +76 -0
- package/s/base/index.ts +6 -0
- package/s/{views → base}/use.ts +25 -16
- package/s/base/utils/attr-watcher.ts +22 -0
- package/s/base/utils/reactor.ts +32 -0
- package/s/base/utils/states.ts +49 -0
- package/s/base/utils/use-attrs.ts +36 -0
- package/s/demo/demo.bundle.ts +9 -5
- package/s/demo/views/counter.ts +21 -24
- package/s/demo/views/demo.ts +10 -6
- package/s/demo/views/fastcount.ts +29 -0
- package/s/demo/views/loaders.ts +7 -7
- package/s/dom/attrs/attrs.ts +21 -0
- package/s/dom/attrs/parts/attr-fns.ts +68 -0
- package/s/dom/attrs/parts/attr-proxies.ts +35 -0
- package/s/dom/attrs/parts/attr-spec.ts +29 -0
- package/s/dom/attrs/parts/on-attrs.ts +8 -0
- package/s/dom/dom.ts +22 -38
- package/s/dom/index.ts +4 -0
- package/s/dom/parts/dom-scope.ts +46 -0
- package/s/dom/parts/el.ts +14 -0
- package/s/dom/parts/elmer.ts +38 -0
- package/s/dom/parts/eve.ts +24 -0
- package/s/dom/parts/mk.ts +9 -0
- package/s/dom/parts/queries.ts +26 -0
- package/s/dom/{register.ts → parts/register.ts} +2 -7
- package/s/dom/types.ts +42 -0
- package/s/index.html.ts +4 -2
- package/s/index.ts +7 -19
- package/s/loaders/index.barrel.ts +10 -0
- package/s/loaders/index.ts +4 -0
- package/s/loaders/make.ts +14 -0
- package/s/loaders/mock.ts +11 -0
- package/s/{ops/loaders → loaders}/parts/anims.ts +1 -1
- package/s/{ops/loaders → loaders}/parts/ascii-anim.ts +6 -5
- package/s/{ops/loaders → loaders}/parts/error-display.ts +2 -2
- package/s/loaders/types.ts +6 -0
- package/s/loot/drag-and-drops.ts +82 -0
- package/s/loot/{drop.ts → drops.ts} +8 -17
- package/s/loot/helpers.ts +3 -3
- package/s/loot/index.barrel.ts +5 -0
- package/s/loot/index.ts +2 -3
- package/s/ops/index.ts +5 -0
- package/s/ops/op.ts +1 -0
- package/s/spa/index.barrel.ts +6 -0
- package/s/spa/index.ts +4 -0
- package/s/spa/plumbing/braces.ts +76 -0
- package/s/spa/plumbing/primitives.ts +85 -0
- package/s/spa/plumbing/router-core.ts +49 -0
- package/s/spa/plumbing/types.ts +45 -0
- package/s/spa/router.ts +49 -0
- package/s/spa/spa.test.ts +91 -0
- package/s/tests.test.ts +4 -1
- package/s/view/index.ts +7 -0
- package/s/view/types.ts +39 -0
- package/s/view/utils/contextualize.ts +45 -0
- package/s/view/utils/make-component.ts +34 -0
- package/s/view/utils/make-view.ts +48 -0
- package/s/view/utils/parts/capsule.ts +67 -0
- package/s/view/utils/parts/chain.ts +40 -0
- package/s/view/utils/parts/context.ts +11 -0
- package/s/view/utils/parts/directive.ts +29 -0
- package/s/view/utils/parts/sly-view.ts +15 -0
- package/s/view/view.ts +24 -0
- package/x/base/css-reset.js.map +1 -0
- package/x/base/element.d.ts +19 -0
- package/x/base/element.js +52 -0
- package/x/base/element.js.map +1 -0
- package/x/base/index.d.ts +4 -0
- package/x/base/index.js +5 -0
- package/x/base/index.js.map +1 -0
- package/x/{views → base}/use.d.ts +8 -4
- package/x/{views → base}/use.js +15 -9
- package/x/base/use.js.map +1 -0
- package/x/base/utils/apply-styles.js.map +1 -0
- package/x/base/utils/attr-watcher.d.ts +8 -0
- package/x/base/utils/attr-watcher.js +20 -0
- package/x/base/utils/attr-watcher.js.map +1 -0
- package/x/base/utils/mounts.js.map +1 -0
- package/x/base/utils/reactor.d.ts +5 -0
- package/x/base/utils/reactor.js +25 -0
- package/x/base/utils/reactor.js.map +1 -0
- package/x/base/utils/states.d.ts +13 -0
- package/x/base/utils/states.js +41 -0
- package/x/base/utils/states.js.map +1 -0
- package/x/base/utils/use-attrs.d.ts +11 -0
- package/x/base/utils/use-attrs.js +18 -0
- package/x/base/utils/use-attrs.js.map +1 -0
- package/x/demo/demo.bundle.js +8 -4
- package/x/demo/demo.bundle.js.map +1 -1
- package/x/demo/demo.bundle.min.js +19 -22
- package/x/demo/demo.bundle.min.js.map +4 -4
- package/x/demo/views/counter.d.ts +374 -1
- package/x/demo/views/counter.js +19 -22
- package/x/demo/views/counter.js.map +1 -1
- package/x/demo/views/demo.d.ts +4 -1
- package/x/demo/views/demo.js +10 -5
- package/x/demo/views/demo.js.map +1 -1
- package/x/demo/views/fastcount.d.ts +12 -0
- package/x/demo/views/fastcount.js +21 -0
- package/x/demo/views/fastcount.js.map +1 -0
- package/x/demo/views/loaders.js +6 -6
- package/x/demo/views/loaders.js.map +1 -1
- package/x/dom/attrs/attrs.d.ts +23 -0
- package/x/dom/attrs/attrs.js +17 -0
- package/x/dom/attrs/attrs.js.map +1 -0
- package/x/dom/attrs/parts/attr-fns.d.ts +16 -0
- package/x/dom/attrs/parts/attr-fns.js +64 -0
- package/x/dom/attrs/parts/attr-fns.js.map +1 -0
- package/x/dom/attrs/parts/attr-proxies.d.ts +8 -0
- package/x/dom/attrs/parts/attr-proxies.js +21 -0
- package/x/dom/attrs/parts/attr-proxies.js.map +1 -0
- package/x/dom/attrs/parts/attr-spec.d.ts +3 -0
- package/x/dom/attrs/parts/attr-spec.js +21 -0
- package/x/dom/attrs/parts/attr-spec.js.map +1 -0
- package/x/dom/attrs/parts/on-attrs.d.ts +2 -0
- package/x/dom/attrs/parts/on-attrs.js +7 -0
- package/x/dom/attrs/parts/on-attrs.js.map +1 -0
- package/x/dom/dom.d.ts +15 -16
- package/x/dom/dom.js +21 -34
- package/x/dom/dom.js.map +1 -1
- package/x/dom/index.d.ts +2 -0
- package/x/dom/index.js +3 -0
- package/x/dom/index.js.map +1 -0
- package/x/dom/parts/dashify.js.map +1 -0
- package/x/dom/parts/dom-scope.d.ts +15 -0
- package/x/dom/parts/dom-scope.js +35 -0
- package/x/dom/parts/dom-scope.js.map +1 -0
- package/x/dom/parts/el.d.ts +2 -0
- package/x/dom/parts/el.js +7 -0
- package/x/dom/parts/el.js.map +1 -0
- package/x/dom/parts/elmer.d.ts +11 -0
- package/x/dom/parts/elmer.js +32 -0
- package/x/dom/parts/elmer.js.map +1 -0
- package/x/dom/parts/eve.d.ts +7 -0
- package/x/dom/parts/eve.js +16 -0
- package/x/dom/parts/eve.js.map +1 -0
- package/x/dom/parts/mk.d.ts +2 -0
- package/x/dom/parts/mk.js +7 -0
- package/x/dom/parts/mk.js.map +1 -0
- package/x/dom/parts/queries.d.ts +4 -0
- package/x/dom/parts/queries.js +13 -0
- package/x/dom/parts/queries.js.map +1 -0
- package/x/dom/{register.d.ts → parts/register.d.ts} +2 -6
- package/x/dom/parts/register.js.map +1 -0
- package/x/dom/types.d.ts +15 -0
- package/x/index.d.ts +7 -16
- package/x/index.html +6 -4
- package/x/index.html.js +4 -2
- package/x/index.html.js.map +1 -1
- package/x/index.js +7 -16
- package/x/index.js.map +1 -1
- package/x/loaders/index.barrel.d.ts +7 -0
- package/x/loaders/index.barrel.js +7 -0
- package/x/loaders/index.barrel.js.map +1 -0
- package/x/loaders/index.d.ts +2 -0
- package/x/loaders/index.js +2 -0
- package/x/loaders/index.js.map +1 -0
- package/x/loaders/make.d.ts +3 -0
- package/x/loaders/make.js +6 -0
- package/x/loaders/make.js.map +1 -0
- package/x/loaders/mock.d.ts +2 -0
- package/x/loaders/mock.js +8 -0
- package/x/loaders/mock.js.map +1 -0
- package/x/{ops/loaders → loaders}/parts/anims.d.ts +1 -1
- package/x/loaders/parts/anims.js.map +1 -0
- package/x/{ops/loaders → loaders}/parts/ascii-anim.d.ts +2 -2
- package/x/{ops/loaders → loaders}/parts/ascii-anim.js +4 -4
- package/x/loaders/parts/ascii-anim.js.map +1 -0
- package/x/loaders/parts/error-display.d.ts +1 -0
- package/x/{ops/loaders → loaders}/parts/error-display.js +2 -2
- package/x/loaders/parts/error-display.js.map +1 -0
- package/x/loaders/types.d.ts +3 -0
- package/x/loaders/types.js.map +1 -0
- package/x/loot/drag-and-drops.d.ts +30 -0
- package/x/loot/drag-and-drops.js +63 -0
- package/x/loot/drag-and-drops.js.map +1 -0
- package/x/loot/{drop.d.ts → drops.d.ts} +3 -5
- package/x/loot/drops.js +25 -0
- package/x/loot/drops.js.map +1 -0
- package/x/loot/helpers.d.ts +3 -3
- package/x/loot/helpers.js +3 -3
- package/x/loot/helpers.js.map +1 -1
- package/x/loot/index.barrel.d.ts +3 -0
- package/x/loot/index.barrel.js +4 -0
- package/x/loot/index.barrel.js.map +1 -0
- package/x/loot/index.d.ts +2 -3
- package/x/loot/index.js +1 -3
- package/x/loot/index.js.map +1 -1
- package/x/ops/index.d.ts +3 -0
- package/x/ops/index.js +4 -0
- package/x/ops/index.js.map +1 -0
- package/x/ops/op.js +1 -0
- package/x/ops/op.js.map +1 -1
- package/x/spa/index.barrel.d.ts +4 -0
- package/x/spa/index.barrel.js +3 -0
- package/x/spa/index.barrel.js.map +1 -0
- package/x/spa/index.d.ts +2 -0
- package/x/spa/index.js +2 -0
- package/x/spa/index.js.map +1 -0
- package/x/spa/plumbing/braces.d.ts +12 -0
- package/x/spa/plumbing/braces.js +55 -0
- package/x/spa/plumbing/braces.js.map +1 -0
- package/x/spa/plumbing/primitives.d.ts +22 -0
- package/x/spa/plumbing/primitives.js +65 -0
- package/x/spa/plumbing/primitives.js.map +1 -0
- package/x/spa/plumbing/router-core.d.ts +13 -0
- package/x/spa/plumbing/router-core.js +38 -0
- package/x/spa/plumbing/router-core.js.map +1 -0
- package/x/spa/plumbing/types.d.ts +35 -0
- package/x/spa/plumbing/types.js +2 -0
- package/x/spa/plumbing/types.js.map +1 -0
- package/x/spa/router.d.ts +16 -0
- package/x/spa/router.js +39 -0
- package/x/spa/router.js.map +1 -0
- package/x/spa/spa.test.d.ts +15 -0
- package/x/spa/spa.test.js +78 -0
- package/x/spa/spa.test.js.map +1 -0
- package/x/tests.test.js +4 -1
- package/x/tests.test.js.map +1 -1
- package/x/view/index.d.ts +5 -0
- package/x/view/index.js +6 -0
- package/x/view/index.js.map +1 -0
- package/x/view/types.d.ts +21 -0
- package/x/view/types.js +2 -0
- package/x/{views → view}/types.js.map +1 -1
- package/x/view/utils/contextualize.d.ts +13 -0
- package/x/view/utils/contextualize.js +18 -0
- package/x/view/utils/contextualize.js.map +1 -0
- package/x/view/utils/make-component.d.ts +5 -0
- package/x/view/utils/make-component.js +17 -0
- package/x/view/utils/make-component.js.map +1 -0
- package/x/view/utils/make-view.d.ts +2 -0
- package/x/view/utils/make-view.js +24 -0
- package/x/view/utils/make-view.js.map +1 -0
- package/x/view/utils/parts/capsule.d.ts +13 -0
- package/x/view/utils/parts/capsule.js +49 -0
- package/x/view/utils/parts/capsule.js.map +1 -0
- package/x/view/utils/parts/chain.d.ts +13 -0
- package/x/view/utils/parts/chain.js +26 -0
- package/x/view/utils/parts/chain.js.map +1 -0
- package/x/view/utils/parts/context.d.ts +9 -0
- package/x/view/utils/parts/context.js +10 -0
- package/x/view/utils/parts/context.js.map +1 -0
- package/x/view/utils/parts/directive.d.ts +5 -0
- package/x/view/utils/parts/directive.js +18 -0
- package/x/view/utils/parts/directive.js.map +1 -0
- package/x/view/utils/parts/sly-view.d.ts +5 -0
- package/x/view/utils/parts/sly-view.js +13 -0
- package/x/view/utils/parts/sly-view.js.map +1 -0
- package/x/view/view.d.ts +11 -0
- package/x/view/view.js +15 -0
- package/x/view/view.js.map +1 -0
- package/s/loot/drag-drop.ts +0 -76
- package/s/ops/loaders/make-loader.ts +0 -18
- package/s/views/attributes.ts +0 -89
- package/s/views/types.ts +0 -40
- package/s/views/utils/apply-attrs.ts +0 -33
- package/s/views/view.ts +0 -150
- package/x/dom/dashify.js.map +0 -1
- package/x/dom/register.js.map +0 -1
- package/x/loot/drag-drop.d.ts +0 -29
- package/x/loot/drag-drop.js +0 -54
- package/x/loot/drag-drop.js.map +0 -1
- package/x/loot/drop.js +0 -32
- package/x/loot/drop.js.map +0 -1
- package/x/ops/loaders/make-loader.d.ts +0 -5
- package/x/ops/loaders/make-loader.js +0 -7
- package/x/ops/loaders/make-loader.js.map +0 -1
- package/x/ops/loaders/parts/anims.js.map +0 -1
- package/x/ops/loaders/parts/ascii-anim.js.map +0 -1
- package/x/ops/loaders/parts/error-display.d.ts +0 -1
- package/x/ops/loaders/parts/error-display.js.map +0 -1
- package/x/views/attributes.d.ts +0 -10
- package/x/views/attributes.js +0 -46
- package/x/views/attributes.js.map +0 -1
- package/x/views/css-reset.js.map +0 -1
- package/x/views/types.d.ts +0 -31
- package/x/views/use.js.map +0 -1
- package/x/views/utils/apply-attrs.d.ts +0 -2
- package/x/views/utils/apply-attrs.js +0 -21
- package/x/views/utils/apply-attrs.js.map +0 -1
- package/x/views/utils/apply-styles.js.map +0 -1
- package/x/views/utils/mounts.js.map +0 -1
- package/x/views/view.d.ts +0 -9
- package/x/views/view.js +0 -116
- package/x/views/view.js.map +0 -1
- /package/s/{views → base}/css-reset.ts +0 -0
- /package/s/{views → base}/utils/apply-styles.ts +0 -0
- /package/s/{views → base}/utils/mounts.ts +0 -0
- /package/s/dom/{dashify.ts → parts/dashify.ts} +0 -0
- /package/x/{views → base}/css-reset.d.ts +0 -0
- /package/x/{views → base}/css-reset.js +0 -0
- /package/x/{views → base}/utils/apply-styles.d.ts +0 -0
- /package/x/{views → base}/utils/apply-styles.js +0 -0
- /package/x/{views → base}/utils/mounts.d.ts +0 -0
- /package/x/{views → base}/utils/mounts.js +0 -0
- /package/x/dom/{dashify.d.ts → parts/dashify.d.ts} +0 -0
- /package/x/dom/{dashify.js → parts/dashify.js} +0 -0
- /package/x/dom/{register.js → parts/register.js} +0 -0
- /package/x/{ops/loaders → loaders}/parts/anims.js +0 -0
- /package/x/{views → loaders}/types.js +0 -0
package/README.md
CHANGED
|
@@ -4,99 +4,116 @@
|
|
|
4
4
|
# 🦝 sly
|
|
5
5
|
> *mischievous shadow views*
|
|
6
6
|
|
|
7
|
-
[@e280](https://e280.org/)'s
|
|
8
|
-
sly replaces its predecessor, [slate](https://github.com/benevolent-games/slate).
|
|
7
|
+
[@e280](https://e280.org/)'s new [lit](https://lit.dev/)-based frontend webdev library. *(sly replaces its predecessor, [slate](https://github.com/benevolent-games/slate))*
|
|
9
8
|
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
9
|
+
- **✨[shiny](https://shiny.e280.org/)✨** — our wip component library https://shiny.e280.org/
|
|
10
|
+
- 🍋 [**#views**](#views) — shadow-dom'd, hooks-based, componentizable
|
|
11
|
+
- 🪵 [**#base-element**](#base-element) — for a more classical experience
|
|
12
|
+
- 🪄 [**#dom**](#dom) — the "it's not jquery" multitool
|
|
13
|
+
- 🫛 [**#ops**](#ops) — reactive tooling for async operations
|
|
14
|
+
- ⏳ [**#loaders**](#loaders) — animated loading spinners for rendering ops
|
|
15
|
+
- 💅 [**#spa**](#spa) — hash routing for your spa-day
|
|
16
|
+
- 🪙 [**#loot**](#loot) — drag-and-drop facilities
|
|
17
|
+
- 🧪 testing page — https://sly.e280.org/
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
|
|
17
21
|
<br/><br/>
|
|
18
22
|
|
|
19
23
|
## 🦝 sly and friends
|
|
24
|
+
> `@e280/sly`
|
|
20
25
|
|
|
21
26
|
```sh
|
|
22
|
-
npm install @e280/sly lit
|
|
27
|
+
npm install @e280/sly lit @e280/strata @e280/stz
|
|
23
28
|
```
|
|
24
29
|
|
|
25
30
|
> [!NOTE]
|
|
26
|
-
> - 🔥 [lit](https://lit.dev/) for html rendering
|
|
31
|
+
> - 🔥 [lit](https://lit.dev/), for html rendering
|
|
27
32
|
> - ⛏️ [@e280/strata](https://github.com/e280/strata), for state management (signals, state trees)
|
|
28
|
-
> - 🏂 [@e280/stz](https://github.com/e280/stz)
|
|
29
|
-
> - 🐢 [scute](https://github.com/e280/scute)
|
|
33
|
+
> - 🏂 [@e280/stz](https://github.com/e280/stz), our ts standard library
|
|
34
|
+
> - 🐢 [@e280/scute](https://github.com/e280/scute), our buildy-bundly-buddy
|
|
35
|
+
|
|
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...
|
|
30
39
|
|
|
31
40
|
|
|
32
41
|
|
|
33
42
|
<br/><br/>
|
|
43
|
+
<a id="views"></a>
|
|
34
44
|
|
|
35
|
-
##
|
|
36
|
-
>
|
|
45
|
+
## 🍋🦝 sly views
|
|
46
|
+
> `@e280/sly/view`
|
|
47
|
+
> *the crown jewel of sly*
|
|
37
48
|
|
|
38
49
|
```ts
|
|
39
50
|
view(use => () => html`<p>hello world</p>`)
|
|
40
51
|
```
|
|
41
52
|
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
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)
|
|
46
59
|
|
|
47
60
|
### 🍋 view example
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- **declare a view**
|
|
61
|
+
```ts
|
|
62
|
+
import {view, dom, BaseElement} from "@e280/sly"
|
|
63
|
+
import {html, css} from "lit"
|
|
64
|
+
```
|
|
65
|
+
- **declare view**
|
|
54
66
|
```ts
|
|
55
67
|
export const CounterView = view(use => (start: number) => {
|
|
56
|
-
use.name("counter")
|
|
57
68
|
use.styles(css`p {color: green}`)
|
|
58
69
|
|
|
59
70
|
const $count = use.signal(start)
|
|
60
71
|
const increment = () => $count.value++
|
|
61
72
|
|
|
62
73
|
return html`
|
|
63
|
-
<
|
|
64
|
-
|
|
74
|
+
<button @click="${increment}">
|
|
75
|
+
${$count.value}
|
|
76
|
+
</button>
|
|
65
77
|
`
|
|
66
78
|
})
|
|
67
79
|
```
|
|
68
|
-
-
|
|
69
|
-
- **inject
|
|
80
|
+
- `$count` is a [strata signal](https://github.com/e280/strata#readme) *(we like those)*
|
|
81
|
+
- **inject view into dom**
|
|
70
82
|
```ts
|
|
71
83
|
dom.in(".app").render(html`
|
|
72
84
|
<h1>cool counter demo</h1>
|
|
73
85
|
${CounterView(1)}
|
|
74
86
|
`)
|
|
75
87
|
```
|
|
76
|
-
- 🤯 **register
|
|
88
|
+
- 🤯 **register view as web component**
|
|
77
89
|
```ts
|
|
78
|
-
dom.register({
|
|
79
|
-
|
|
90
|
+
dom.register({
|
|
91
|
+
MyCounter: CounterView
|
|
92
|
+
.component()
|
|
93
|
+
.props(() => [1]),
|
|
94
|
+
})
|
|
95
|
+
```
|
|
96
|
+
```html
|
|
97
|
+
<my-counter></my-counter>
|
|
80
98
|
```
|
|
81
99
|
|
|
82
|
-
### 🍋 view
|
|
83
|
-
-
|
|
100
|
+
### 🍋 view settings
|
|
101
|
+
- optional settings for views you should know about
|
|
84
102
|
```ts
|
|
85
103
|
export const CoolView = view
|
|
86
104
|
.settings({mode: "open", delegatesFocus: true})
|
|
87
|
-
.
|
|
88
|
-
return html`😎 ${greeting} <slot></slot>`
|
|
89
|
-
})
|
|
105
|
+
.render(use => (greeting: string) => html`😎 ${greeting} <slot></slot>`)
|
|
90
106
|
```
|
|
91
107
|
- all [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters) (like `mode` and `delegatesFocus`) are valid `settings`
|
|
92
108
|
- note the `<slot></slot>` we'll use in the next example lol
|
|
93
109
|
|
|
94
|
-
### 🍋 view
|
|
95
|
-
-
|
|
110
|
+
### 🍋 view chains
|
|
111
|
+
- views have this sick chaining syntax for supplying more stuff at the template injection site
|
|
96
112
|
```ts
|
|
97
113
|
dom.in(".app").render(html`
|
|
98
114
|
<h2>cool example</h2>
|
|
99
|
-
${CoolView
|
|
115
|
+
${CoolView
|
|
116
|
+
.props("hello")
|
|
100
117
|
.attr("class", "hero")
|
|
101
118
|
.children(html`<em>spongebob</em>`)
|
|
102
119
|
.render()}
|
|
@@ -104,30 +121,102 @@ view(use => () => html`<p>hello world</p>`)
|
|
|
104
121
|
```
|
|
105
122
|
- `props` — provide props and start a view chain
|
|
106
123
|
- `attr` — set html attributes on the `<sly-view>` host element
|
|
107
|
-
- `children` — nested
|
|
124
|
+
- `children` — add nested [slottable](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots) content
|
|
108
125
|
- `render` — end the view chain and render the lit directive
|
|
109
126
|
|
|
110
|
-
### 🍋 view
|
|
111
|
-
- **
|
|
127
|
+
### 🍋 view/component universality
|
|
128
|
+
- **you can start with a view,**
|
|
112
129
|
```ts
|
|
113
|
-
const
|
|
130
|
+
export const GreeterView = view(use => (name: string) => {
|
|
131
|
+
return html`<p>hello ${name}</p>`
|
|
132
|
+
})
|
|
114
133
|
```
|
|
115
|
-
-
|
|
116
|
-
|
|
134
|
+
- view usage
|
|
135
|
+
```ts
|
|
136
|
+
GreeterView("pimsley")
|
|
137
|
+
```
|
|
138
|
+
**then you can convert it to a component.**
|
|
117
139
|
```ts
|
|
118
|
-
|
|
140
|
+
export class GreeterComponent extends (
|
|
141
|
+
GreeterView
|
|
142
|
+
.component()
|
|
143
|
+
.props(component => [component.getAttribute("name") ?? "unknown"])
|
|
144
|
+
) {}
|
|
119
145
|
```
|
|
120
|
-
-
|
|
121
|
-
|
|
146
|
+
- html usage
|
|
147
|
+
```html
|
|
148
|
+
<greeter-component name="pimsley"></greeter-component>
|
|
149
|
+
```
|
|
150
|
+
- **you can start with a component,**
|
|
151
|
+
```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
|
+
) {}
|
|
159
|
+
```
|
|
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
|
+
```
|
|
122
206
|
- **register web components to the dom**
|
|
123
207
|
```ts
|
|
124
|
-
dom.register({
|
|
125
|
-
// <my-component></my-component>
|
|
126
|
-
// <my-counter></my-counter>
|
|
208
|
+
dom.register({GreeterComponent})
|
|
127
209
|
```
|
|
128
|
-
|
|
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
|
+
})
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
<a id="use"></a>
|
|
129
218
|
|
|
130
|
-
### 🍋
|
|
219
|
+
### 🍋 "use" hooks reference
|
|
131
220
|
- 👮 **follow the hooks rules**
|
|
132
221
|
> just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of sly's `use` hooks actually matters..
|
|
133
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..*
|
|
@@ -150,9 +239,9 @@ view(use => () => html`<p>hello world</p>`)
|
|
|
150
239
|
// write the signal
|
|
151
240
|
$count(2)
|
|
152
241
|
```
|
|
153
|
-
- `
|
|
242
|
+
- `derived` signals
|
|
154
243
|
```ts
|
|
155
|
-
const $product = use.
|
|
244
|
+
const $product = use.derived(() => $count() * $whatever())
|
|
156
245
|
```
|
|
157
246
|
- `lazy` signals
|
|
158
247
|
```ts
|
|
@@ -197,27 +286,46 @@ view(use => () => html`<p>hello world</p>`)
|
|
|
197
286
|
|
|
198
287
|
v // 123
|
|
199
288
|
```
|
|
200
|
-
- **use.
|
|
289
|
+
- **use.events** — attach event listeners to the element (auto-cleaned up)
|
|
201
290
|
```ts
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
active: Boolean,
|
|
291
|
+
use.events({
|
|
292
|
+
keydown: (e: KeyboardEvent) => console.log("keydown", e.code),
|
|
293
|
+
keyup: (e: KeyboardEvent) => console.log("keyup", e.code),
|
|
206
294
|
})
|
|
207
295
|
```
|
|
296
|
+
- **use.states** — [internal states](https://developer.mozilla.org/en-US/docs/Web/API/ElementInternals/states) helper
|
|
208
297
|
```ts
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
attrs.active // true
|
|
298
|
+
const states = use.states()
|
|
299
|
+
states.assign("active", "cool")
|
|
212
300
|
```
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
attrs.active = false // removes html attr
|
|
217
|
-
```
|
|
218
|
-
```ts
|
|
219
|
-
attrs.name = undefined // removes the attr
|
|
301
|
+
```css
|
|
302
|
+
[view="my-view"]::state(active) { color: yellow; }
|
|
303
|
+
[view="my-view"]::state(cool) { outline: 1px solid cyan; }
|
|
220
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
|
+
```
|
|
221
329
|
- **use.render** — rerender the view (debounced)
|
|
222
330
|
```ts
|
|
223
331
|
use.render()
|
|
@@ -245,15 +353,15 @@ view(use => () => html`<p>hello world</p>`)
|
|
|
245
353
|
const op = use.op.promise(doAsyncWork())
|
|
246
354
|
```
|
|
247
355
|
|
|
248
|
-
### 🍋
|
|
249
|
-
- make a ticker — mount,
|
|
356
|
+
### 🍋 "use" recipes
|
|
357
|
+
- make a ticker — mount, cycle, and nap
|
|
250
358
|
```ts
|
|
251
|
-
import {
|
|
359
|
+
import {cycle, nap} from "@e280/stz"
|
|
252
360
|
```
|
|
253
361
|
```ts
|
|
254
362
|
const $seconds = use.signal(0)
|
|
255
363
|
|
|
256
|
-
use.mount(() =>
|
|
364
|
+
use.mount(() => cycle(async() => {
|
|
257
365
|
await nap(1000)
|
|
258
366
|
$seconds.value++
|
|
259
367
|
}))
|
|
@@ -268,72 +376,259 @@ view(use => () => html`<p>hello world</p>`)
|
|
|
268
376
|
|
|
269
377
|
|
|
270
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>
|
|
271
477
|
|
|
272
|
-
##
|
|
273
|
-
>
|
|
478
|
+
## 🪄🦝 sly dom
|
|
479
|
+
> `@e280/sly/dom`
|
|
480
|
+
> *the "it's not jquery!" multitool*
|
|
274
481
|
|
|
275
482
|
```ts
|
|
276
483
|
import {dom} from "@e280/sly"
|
|
277
484
|
```
|
|
278
485
|
|
|
279
486
|
### 🪄 dom queries
|
|
280
|
-
- require an element
|
|
487
|
+
- `require` an element
|
|
281
488
|
```ts
|
|
282
489
|
dom(".demo")
|
|
283
490
|
// HTMLElement (or throws)
|
|
284
491
|
```
|
|
285
|
-
|
|
492
|
+
```ts
|
|
493
|
+
// alias
|
|
494
|
+
dom.require(".demo")
|
|
495
|
+
// HTMLElement (or throws)
|
|
496
|
+
```
|
|
497
|
+
- `maybe` get an element
|
|
286
498
|
```ts
|
|
287
499
|
dom.maybe(".demo")
|
|
288
500
|
// HTMLElement | undefined
|
|
289
501
|
```
|
|
290
|
-
-
|
|
502
|
+
- `all` matching elements in an array
|
|
291
503
|
```ts
|
|
292
504
|
dom.all(".demo ul li")
|
|
293
505
|
// HTMLElement[]
|
|
294
506
|
```
|
|
295
|
-
|
|
507
|
+
|
|
508
|
+
### 🪄 dom.in scope
|
|
509
|
+
- make a scope
|
|
296
510
|
```ts
|
|
297
|
-
dom.in(
|
|
298
|
-
//
|
|
511
|
+
dom.in(".demo") // selector
|
|
512
|
+
// Dom instance
|
|
299
513
|
```
|
|
300
514
|
```ts
|
|
301
|
-
dom.in(element
|
|
302
|
-
//
|
|
515
|
+
dom.in(demoElement) // element
|
|
516
|
+
// Dom instance
|
|
303
517
|
```
|
|
518
|
+
- run queries in that scope
|
|
304
519
|
```ts
|
|
305
|
-
dom.in(
|
|
306
|
-
|
|
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")
|
|
307
527
|
```
|
|
308
528
|
|
|
309
529
|
### 🪄 dom utilities
|
|
310
|
-
- register web components
|
|
530
|
+
- `dom.register` web components
|
|
311
531
|
```ts
|
|
312
532
|
dom.register({MyComponent, AnotherCoolComponent})
|
|
313
533
|
// <my-component>
|
|
314
534
|
// <another-cool-component>
|
|
315
535
|
```
|
|
316
|
-
-
|
|
536
|
+
- `dom.register` automatically dashes the tag names (`MyComponent` becomes `<my-component>`)
|
|
537
|
+
- `dom.render` content into an element
|
|
317
538
|
```ts
|
|
318
539
|
dom.render(element, html`<p>hello world</p>`)
|
|
319
540
|
```
|
|
320
541
|
```ts
|
|
321
|
-
dom.in(
|
|
542
|
+
dom.in(".demo").render(html`<p>hello world</p>`)
|
|
322
543
|
```
|
|
544
|
+
- `dom.el` little element builder
|
|
323
545
|
```ts
|
|
324
|
-
dom.
|
|
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
|
|
325
618
|
```
|
|
326
619
|
|
|
327
620
|
|
|
328
621
|
|
|
329
622
|
<br/><br/>
|
|
623
|
+
<a id="ops"></a>
|
|
330
624
|
|
|
331
|
-
##
|
|
332
|
-
>
|
|
625
|
+
## 🫛🦝 sly ops
|
|
626
|
+
> `@e280/sly/ops`
|
|
627
|
+
> *tools for async operations and loading spinners*
|
|
333
628
|
|
|
334
629
|
```ts
|
|
335
630
|
import {nap} from "@e280/stz"
|
|
336
|
-
import {Pod, podium, Op,
|
|
631
|
+
import {Pod, podium, Op, loaders} from "@e280/sly"
|
|
337
632
|
```
|
|
338
633
|
|
|
339
634
|
### 🫛 pods: loading/ready/error
|
|
@@ -432,14 +727,29 @@ import {Pod, podium, Op, makeLoader, anims} from "@e280/sly"
|
|
|
432
727
|
- loading if any ops are in loading, otherwise
|
|
433
728
|
- ready if all the ops are ready
|
|
434
729
|
|
|
435
|
-
|
|
436
|
-
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
<br/><br/>
|
|
733
|
+
<a id="loaders"></a>
|
|
734
|
+
|
|
735
|
+
## ⏳🦝 sly loaders
|
|
736
|
+
> `@e280/sly/loaders`
|
|
737
|
+
> *animated loading spinners for ops*
|
|
738
|
+
|
|
739
|
+
```ts
|
|
740
|
+
import {loaders} from "@e280/sly"
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
### ⏳ make a loader, choose an anim
|
|
744
|
+
- create a loader fn
|
|
437
745
|
```ts
|
|
438
|
-
const loader =
|
|
746
|
+
const loader = loaders.make(loaders.anims.dots)
|
|
439
747
|
```
|
|
440
748
|
- see all the anims available on the testing page https://sly.e280.org/
|
|
441
749
|
- ngl, i made too many.. *i was having fun, okay?*
|
|
442
|
-
|
|
750
|
+
|
|
751
|
+
### ⏳ render an op with it
|
|
752
|
+
- use your loader to render an op
|
|
443
753
|
```ts
|
|
444
754
|
return html`
|
|
445
755
|
<h2>cool stuff</h2>
|
|
@@ -456,8 +766,225 @@ import {Pod, podium, Op, makeLoader, anims} from "@e280/sly"
|
|
|
456
766
|
|
|
457
767
|
|
|
458
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
|
+
```
|
|
459
778
|
|
|
460
|
-
|
|
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
|
+
<br/><br/>
|
|
858
|
+
<a id="loot"></a>
|
|
859
|
+
|
|
860
|
+
## 🪙🦝 loot
|
|
861
|
+
> `@e280/sly/loot`
|
|
862
|
+
> *drag-and-drop facilities*
|
|
863
|
+
|
|
864
|
+
```ts
|
|
865
|
+
import {loot, view, dom} from "@e280/sly"
|
|
866
|
+
import {ev} from "@e280/stz"
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
### 🪙 `loot.Drops`
|
|
870
|
+
> *accept the user dropping stuff like files onto the page*
|
|
871
|
+
- **setup drops**
|
|
872
|
+
```ts
|
|
873
|
+
const drops = new loot.Drops({
|
|
874
|
+
predicate: loot.hasFiles,
|
|
875
|
+
acceptDrop: event => {
|
|
876
|
+
const files = loot.files(event)
|
|
877
|
+
console.log("files dropped", files)
|
|
878
|
+
},
|
|
879
|
+
})
|
|
880
|
+
```
|
|
881
|
+
- **attach event listeners to your dropzone,** one of these ways:
|
|
882
|
+
- **view example**
|
|
883
|
+
```ts
|
|
884
|
+
view(() => () => html`
|
|
885
|
+
<div
|
|
886
|
+
?data-indicator="${drops.$indicator()}"
|
|
887
|
+
@dragover="${drops.dragover}"
|
|
888
|
+
@dragleave="${drops.dragleave}"
|
|
889
|
+
@drop="${drops.drop}">
|
|
890
|
+
my dropzone
|
|
891
|
+
</div>
|
|
892
|
+
`)
|
|
893
|
+
```
|
|
894
|
+
- **vanilla-js whole-page example**
|
|
895
|
+
```ts
|
|
896
|
+
// attach listeners to the body
|
|
897
|
+
ev(document.body, {
|
|
898
|
+
dragover: drops.dragover,
|
|
899
|
+
dragleave: drops.dragleave,
|
|
900
|
+
drop: drops.drop,
|
|
901
|
+
})
|
|
902
|
+
|
|
903
|
+
// sly attribute handler for the body
|
|
904
|
+
const attrs = dom.attrs(document.body).spec({
|
|
905
|
+
"data-indicator": Boolean,
|
|
906
|
+
})
|
|
907
|
+
|
|
908
|
+
// sync the data-indicator attribute
|
|
909
|
+
drops.$indicator.on(bool => attrs["data-indicator"] = bool)
|
|
910
|
+
```
|
|
911
|
+
- **flashy css indicator for the dropzone,** so the user knows your app is eager to accept the drop
|
|
912
|
+
```css
|
|
913
|
+
[data-indicator] {
|
|
914
|
+
border: 0.5em dashed cyan;
|
|
915
|
+
}
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
### 🪙 `loot.DragAndDrops`
|
|
919
|
+
> *setup drag-and-drops between items within your page*
|
|
920
|
+
- **declare types for your draggy and droppy things**
|
|
921
|
+
```ts
|
|
922
|
+
// money that can be picked up and dragged
|
|
923
|
+
type Money = {value: number}
|
|
924
|
+
// dnd will call this a "draggy"
|
|
925
|
+
|
|
926
|
+
// bag that money can be dropped into
|
|
927
|
+
type Bag = {id: number}
|
|
928
|
+
// dnd will call this a "droppy"
|
|
929
|
+
```
|
|
930
|
+
- **make your dnd**
|
|
931
|
+
```ts
|
|
932
|
+
const dnd = new loot.DragAndDrops<Money, Bag>({
|
|
933
|
+
acceptDrop: (event, money, bag) => {
|
|
934
|
+
console.log("drop!", {money, bag})
|
|
935
|
+
},
|
|
936
|
+
})
|
|
937
|
+
```
|
|
938
|
+
- **attach dragzone listeners** (there can be many dragzones...)
|
|
939
|
+
```ts
|
|
940
|
+
view(use => () => {
|
|
941
|
+
const money = use.once((): Money => ({value: 280}))
|
|
942
|
+
const dragzone = use.once(() => dnd.dragzone(() => money))
|
|
943
|
+
|
|
944
|
+
return html`
|
|
945
|
+
<div
|
|
946
|
+
draggable="${dragzone.draggable}"
|
|
947
|
+
@dragstart="${dragzone.dragstart}"
|
|
948
|
+
@dragend="${dragzone.dragend}">
|
|
949
|
+
money ${money.value}
|
|
950
|
+
</div>
|
|
951
|
+
`
|
|
952
|
+
})
|
|
953
|
+
```
|
|
954
|
+
- **attach dropzone listeners** (there can be many dropzones...)
|
|
955
|
+
```ts
|
|
956
|
+
view(use => () => {
|
|
957
|
+
const bag = use.once((): Bag => ({id: 1}))
|
|
958
|
+
const dropzone = use.once(() => dnd.dropzone(() => bag))
|
|
959
|
+
const indicator = !!(dnd.dragging && dnd.hovering === bag)
|
|
960
|
+
|
|
961
|
+
return html`
|
|
962
|
+
<div
|
|
963
|
+
?data-indicator="${indicator}"
|
|
964
|
+
@dragenter="${dropzone.dragenter}"
|
|
965
|
+
@dragleave="${dropzone.dragleave}"
|
|
966
|
+
@dragover="${dropzone.dragover}"
|
|
967
|
+
@drop="${dropzone.drop}">
|
|
968
|
+
bag ${bag.id}
|
|
969
|
+
</div>
|
|
970
|
+
`
|
|
971
|
+
})
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
### 🪙 loot helpers
|
|
975
|
+
- **`loot.hasFiles(event)`** — return true if `DragEvent` contains any files (useful in `predicate`)
|
|
976
|
+
- **`loot.files(event)`** — returns an array of files in a drop's `DragEvent` (useful in `acceptDrop`)
|
|
977
|
+
|
|
978
|
+
|
|
979
|
+
|
|
980
|
+
<br/><br/>
|
|
981
|
+
<a id="e280"></a>
|
|
982
|
+
|
|
983
|
+
## 🧑💻🦝 sly is by e280
|
|
461
984
|
reward us with github stars
|
|
462
985
|
build with us at https://e280.org/ but only if you're cool
|
|
463
986
|
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
<br/><br/>
|
|
990
|
+
|