@e280/sly 0.2.0-11 โ 0.2.0-12
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 +86 -63
- package/package.json +1 -1
- package/x/index.html +1 -1
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
# ๐ฆ sly
|
|
5
5
|
> *mischievous shadow views*
|
|
6
6
|
|
|
7
|
-
[@e280](https://e280.org/)'s shiny new [lit](https://lit.dev/)-based frontend
|
|
7
|
+
[@e280](https://e280.org/)'s shiny new [lit](https://lit.dev/)-based frontend webdev library. *(sly replaces its predecessor, [slate](https://github.com/benevolent-games/slate))*
|
|
8
8
|
|
|
9
|
-
- ๐ [
|
|
10
|
-
- ๐ชต [
|
|
11
|
-
- ๐ช [
|
|
12
|
-
- ๐ซ [
|
|
13
|
-
- ๐ช [
|
|
9
|
+
- ๐ [**#views**](#views) โ shadow-dom'd, hooks-based, componentizable
|
|
10
|
+
- ๐ชต [**#base-element**](#base-element) โ for a more classical experience
|
|
11
|
+
- ๐ช [**#dom**](#dom) โ the "it's not jquery" multitool
|
|
12
|
+
- ๐ซ [**#ops**](#ops) โ tools for async operations and loading spinners
|
|
13
|
+
- ๐ช [**#loot**](#loot) โ drag-and-drop facilities
|
|
14
14
|
- ๐งช testing page โ https://sly.e280.org/
|
|
15
15
|
|
|
16
16
|
|
|
@@ -34,76 +34,77 @@ npm install @e280/sly lit @e280/strata @e280/stz
|
|
|
34
34
|
<br/><br/>
|
|
35
35
|
<a id="views"></a>
|
|
36
36
|
|
|
37
|
-
## ๐ฆ๐ sly views
|
|
38
|
-
> *
|
|
37
|
+
## ๐ฆ๐ sly views
|
|
38
|
+
> *the crown jewel of sly*
|
|
39
39
|
|
|
40
40
|
```ts
|
|
41
41
|
view(use => () => html`<p>hello world</p>`)
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
44
|
+
- ๐ชถ **no compile step** โ just god's honest javascript, via [lit](https://lit.dev/)-html tagged-template-literals
|
|
45
|
+
- ๐ฅท **shadow dom'd** โ each 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)
|
|
46
|
+
- ๐ช **hooks-based** โ declarative rendering with the [`use.*`](#use) family of ergonomic hooks
|
|
47
|
+
- โก **reactive** โ they auto-rerender whenever any [strata](https://github.com/e280/strata)-compatible state changes
|
|
48
|
+
- ๐ง **not components, per se** โ they're comfy typescript-native ui building blocks [(technically, lit directives)](https://lit.dev/docs/templates/custom-directives/)
|
|
49
|
+
- ๐งฉ **componentizable** โ any view can be magically converted into a proper [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components)
|
|
48
50
|
|
|
49
51
|
### ๐ view example
|
|
50
52
|
```ts
|
|
51
53
|
import {view, dom, BaseElement} from "@e280/sly"
|
|
52
54
|
import {html, css} from "lit"
|
|
53
55
|
```
|
|
54
|
-
- **declare
|
|
56
|
+
- **declare view**
|
|
55
57
|
```ts
|
|
56
58
|
export const CounterView = view(use => (start: number) => {
|
|
57
|
-
use.name("counter")
|
|
58
59
|
use.styles(css`p {color: green}`)
|
|
59
60
|
|
|
60
61
|
const $count = use.signal(start)
|
|
61
62
|
const increment = () => $count.value++
|
|
62
63
|
|
|
63
64
|
return html`
|
|
64
|
-
<
|
|
65
|
-
|
|
65
|
+
<button @click="${increment}">
|
|
66
|
+
${$count.value}
|
|
67
|
+
</button>
|
|
66
68
|
`
|
|
67
69
|
})
|
|
68
70
|
```
|
|
69
|
-
-
|
|
70
|
-
- **inject
|
|
71
|
+
- `$count` is a [strata signal](https://github.com/e280/strata#readme) *(we like those)*
|
|
72
|
+
- **inject view into dom**
|
|
71
73
|
```ts
|
|
72
74
|
dom.in(".app").render(html`
|
|
73
75
|
<h1>cool counter demo</h1>
|
|
74
76
|
${CounterView(1)}
|
|
75
77
|
`)
|
|
76
78
|
```
|
|
77
|
-
- ๐คฏ **register
|
|
79
|
+
- ๐คฏ **register view as web component**
|
|
78
80
|
```ts
|
|
79
81
|
dom.register({
|
|
80
82
|
MyCounter: CounterView
|
|
81
83
|
.component(BaseElement)
|
|
82
|
-
.props(
|
|
84
|
+
.props(() => [1]),
|
|
83
85
|
})
|
|
84
86
|
```
|
|
85
87
|
```html
|
|
86
|
-
<my-counter
|
|
88
|
+
<my-counter></my-counter>
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
### ๐ view
|
|
90
|
-
-
|
|
91
|
+
### ๐ view settings
|
|
92
|
+
- lame settings for views you should know about
|
|
91
93
|
```ts
|
|
92
94
|
export const CoolView = view
|
|
93
95
|
.settings({mode: "open", delegatesFocus: true})
|
|
94
|
-
.render(use => (greeting: string) => {
|
|
95
|
-
return html`๐ ${greeting} <slot></slot>`
|
|
96
|
-
})
|
|
96
|
+
.render(use => (greeting: string) => html`๐ ${greeting} <slot></slot>`)
|
|
97
97
|
```
|
|
98
98
|
- all [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters) (like `mode` and `delegatesFocus`) are valid `settings`
|
|
99
99
|
- note the `<slot></slot>` we'll use in the next example lol
|
|
100
100
|
|
|
101
|
-
### ๐ view
|
|
102
|
-
-
|
|
101
|
+
### ๐ view chain
|
|
102
|
+
- views have this sick chaining syntax for supplying more stuff at the template injection site
|
|
103
103
|
```ts
|
|
104
104
|
dom.in(".app").render(html`
|
|
105
105
|
<h2>cool example</h2>
|
|
106
|
-
${CoolView
|
|
106
|
+
${CoolView
|
|
107
|
+
.props("hello")
|
|
107
108
|
.attr("class", "hero")
|
|
108
109
|
.children(html`<em>spongebob</em>`)
|
|
109
110
|
.render()}
|
|
@@ -111,7 +112,7 @@ import {html, css} from "lit"
|
|
|
111
112
|
```
|
|
112
113
|
- `props` โ provide props and start a view chain
|
|
113
114
|
- `attr` โ set html attributes on the `<sly-view>` host element
|
|
114
|
-
- `children` โ nested
|
|
115
|
+
- `children` โ add nested [slottable](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots) content
|
|
115
116
|
- `render` โ end the view chain and render the lit directive
|
|
116
117
|
|
|
117
118
|
### ๐ view/component universality
|
|
@@ -120,22 +121,23 @@ import {html, css} from "lit"
|
|
|
120
121
|
export const GreeterView = view(use => (name: string) => {
|
|
121
122
|
return html`<p>hello ${name}</p>`
|
|
122
123
|
})
|
|
123
|
-
|
|
124
|
-
// view usage:
|
|
125
|
-
// GreeterView("pimsley")
|
|
126
124
|
```
|
|
127
|
-
|
|
125
|
+
- view usage
|
|
126
|
+
```ts
|
|
127
|
+
GreeterView("pimsley")
|
|
128
|
+
```
|
|
129
|
+
**then you can convert it to a component.**
|
|
128
130
|
```ts
|
|
129
131
|
export class GreeterComponent extends (
|
|
130
132
|
GreeterView
|
|
131
133
|
.component(BaseElement)
|
|
132
134
|
.props(component => [component.getAttribute("name") ?? "unknown"])
|
|
133
135
|
) {}
|
|
134
|
-
|
|
135
|
-
// html usage:
|
|
136
|
-
// <greeter-component name="pimsley"></greeter-component>
|
|
137
136
|
```
|
|
138
|
-
-
|
|
137
|
+
- html usage
|
|
138
|
+
```html
|
|
139
|
+
<greeter-component name="pimsley"></greeter-component>
|
|
140
|
+
```
|
|
139
141
|
- **you can start with a component,**
|
|
140
142
|
```ts
|
|
141
143
|
export class GreeterComponent extends (
|
|
@@ -145,44 +147,65 @@ import {html, css} from "lit"
|
|
|
145
147
|
.component(BaseElement)
|
|
146
148
|
.props(component => [component.getAttribute("name") ?? "unknown"])
|
|
147
149
|
) {}
|
|
148
|
-
|
|
149
|
-
// html usage:
|
|
150
|
-
// <greeter-component name="pimsley"></greeter-component>
|
|
151
|
-
```
|
|
152
|
-
then it already has a `.view` ready for you.
|
|
153
|
-
```ts
|
|
154
|
-
// view usage:
|
|
155
|
-
// GreeterComponent.view("pimsley")
|
|
156
150
|
```
|
|
151
|
+
- html usage
|
|
152
|
+
```html
|
|
153
|
+
<greeter-component name="pimsley"></greeter-component>
|
|
154
|
+
```
|
|
155
|
+
**and it already has `.view` ready for you.**
|
|
156
|
+
- view usage
|
|
157
|
+
```ts
|
|
158
|
+
GreeterComponent.view("pimsley")
|
|
159
|
+
```
|
|
157
160
|
- **understanding `.component(C)` and `.props(fn)`**
|
|
158
161
|
- `.props` takes a fn that is called every render, which returns the props given to the view
|
|
159
162
|
```ts
|
|
160
|
-
.component(BaseElement)
|
|
161
163
|
.props(() => ["pimsley"])
|
|
162
164
|
```
|
|
163
165
|
the props fn receives the component instance, so you can query html attributes or instance properties
|
|
164
166
|
```ts
|
|
165
|
-
.component(BaseElement)
|
|
166
167
|
.props(component => [component.getAttribute("name") ?? "unknown"])
|
|
167
168
|
```
|
|
168
|
-
- `.component` accepts a subclass of `BaseElement`,
|
|
169
|
+
- `.component` accepts a subclass of `BaseElement`, so you can define your own properties and methods for your component class
|
|
169
170
|
```ts
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
171
|
+
const GreeterComponent = GreeterView
|
|
172
|
+
|
|
173
|
+
// declare your own custom class
|
|
174
|
+
.component(class extends BaseElement {
|
|
175
|
+
$name = signal("jim raynor")
|
|
176
|
+
updateName(name: string) {
|
|
177
|
+
this.$name.value = name
|
|
178
|
+
}
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
// props gets the right types on 'component'
|
|
182
|
+
.props(component => [component.$name.value])
|
|
177
183
|
```
|
|
178
|
-
- `.component`
|
|
184
|
+
- `.component` provides the devs interacting with your component, with noice typings
|
|
179
185
|
```ts
|
|
180
|
-
dom<GreeterComponent>("
|
|
186
|
+
dom<GreeterComponent>("greeter-component").updateName("mortimer")
|
|
181
187
|
```
|
|
188
|
+
- typescript class wizardry
|
|
189
|
+
- โ smol-brain approach exports class value, but not the typings
|
|
190
|
+
```ts
|
|
191
|
+
export const GreeterComponent = (...)
|
|
192
|
+
```
|
|
193
|
+
- โ
giga-brain approach exports class value AND the typings
|
|
194
|
+
```ts
|
|
195
|
+
export class GreeterComponent extends (...) {}
|
|
196
|
+
```
|
|
182
197
|
- **register web components to the dom**
|
|
183
198
|
```ts
|
|
184
199
|
dom.register({GreeterComponent})
|
|
185
200
|
```
|
|
201
|
+
- **oh and don't miss out on the insta-component shorthand**
|
|
202
|
+
```ts
|
|
203
|
+
dom.register({
|
|
204
|
+
QuickComponent: view.component(use => html`โก incredi`),
|
|
205
|
+
})
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
<a id="use"></a>
|
|
186
209
|
|
|
187
210
|
### ๐ "use" hooks reference
|
|
188
211
|
- ๐ฎ **follow the hooks rules**
|
|
@@ -328,7 +351,7 @@ import {BaseElement, Use, dom} from "@e280/sly"
|
|
|
328
351
|
import {html, css} from "lit"
|
|
329
352
|
```
|
|
330
353
|
|
|
331
|
-
`BaseElement` is an old-timey class-based "
|
|
354
|
+
`BaseElement` is an old-timey class-based "boomer" approach to making web components, but with a zoomer twist โ its `render` method gives you the same `use` hooks that views enjoy.
|
|
332
355
|
|
|
333
356
|
### ๐ชต base element setup
|
|
334
357
|
- **declare your element class**
|
|
@@ -337,7 +360,7 @@ import {html, css} from "lit"
|
|
|
337
360
|
static styles = css`span{color:orange}`
|
|
338
361
|
|
|
339
362
|
// custom property
|
|
340
|
-
start = 10
|
|
363
|
+
$start = signal(10)
|
|
341
364
|
|
|
342
365
|
// custom attributes
|
|
343
366
|
attrs = dom.attrs(this).spec({
|
|
@@ -353,9 +376,9 @@ import {html, css} from "lit"
|
|
|
353
376
|
const $count = use.signal(1)
|
|
354
377
|
const increment = () => $count.value++
|
|
355
378
|
|
|
356
|
-
const {start} = this
|
|
379
|
+
const {$start} = this
|
|
357
380
|
const {multiply = 1} = this.attrs
|
|
358
|
-
const result = start + (multiply * $count())
|
|
381
|
+
const result = $start() + (multiply * $count())
|
|
359
382
|
|
|
360
383
|
return html`
|
|
361
384
|
<span>${result}</span>
|
|
@@ -381,7 +404,7 @@ import {html, css} from "lit"
|
|
|
381
404
|
const myElement = dom<MyElement>("my-element")
|
|
382
405
|
|
|
383
406
|
// js property
|
|
384
|
-
myElement
|
|
407
|
+
myElement.$start(100)
|
|
385
408
|
|
|
386
409
|
// html attributes
|
|
387
410
|
myElement.attrs.multiply = 2
|
package/package.json
CHANGED
package/x/index.html
CHANGED
|
@@ -131,7 +131,7 @@ body {
|
|
|
131
131
|
<img class=icon alt="" src="/assets/favicon.png"/>
|
|
132
132
|
<h1>sly testing page</h1>
|
|
133
133
|
<p><a href="https://github.com/e280/sly">github.com/e280/sly</a></p>
|
|
134
|
-
<p class=lil>v0.2.0-
|
|
134
|
+
<p class=lil>v0.2.0-12</p>
|
|
135
135
|
|
|
136
136
|
<fastcount-element></fastcount-element>
|
|
137
137
|
<counter-component start=280 step=2>component</counter-component>
|