@e280/sly 0.1.1 → 0.2.0-0
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 +17 -17
- package/package.json +3 -3
- package/s/demo/views/counter.ts +4 -4
- package/s/demo/views/demo.ts +1 -1
- package/s/ops/loaders/parts/ascii-anim.ts +3 -3
- package/s/ops/op.ts +10 -10
- package/s/views/types.ts +10 -7
- package/s/views/view.ts +49 -34
- package/x/demo/demo.bundle.min.js +17 -17
- package/x/demo/demo.bundle.min.js.map +4 -4
- package/x/demo/views/counter.js +4 -4
- package/x/demo/views/counter.js.map +1 -1
- package/x/demo/views/demo.js +1 -1
- package/x/demo/views/demo.js.map +1 -1
- package/x/index.html +2 -2
- package/x/ops/loaders/parts/ascii-anim.js +3 -3
- package/x/ops/loaders/parts/ascii-anim.js.map +1 -1
- package/x/ops/op.js +10 -10
- package/x/ops/op.js.map +1 -1
- package/x/views/types.d.ts +9 -7
- package/x/views/view.d.ts +1 -1
- package/x/views/view.js +44 -34
- package/x/views/view.js.map +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,6 @@ npm install @e280/sly lit
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
> [!NOTE]
|
|
25
|
-
> ecosystem buddies:
|
|
26
25
|
> - 🔥 [lit](https://lit.dev/) for html rendering
|
|
27
26
|
> - ⛏️ [@e280/strata](https://github.com/e280/strata) for state management (signals, state trees)
|
|
28
27
|
> - 🏂 [@e280/stz](https://github.com/e280/stz) ***(optional)*** stz is our ts standard library
|
|
@@ -78,33 +77,34 @@ view(use => () => html`<p>hello world</p>`)
|
|
|
78
77
|
// <my-counter></my-counter>
|
|
79
78
|
```
|
|
80
79
|
|
|
80
|
+
### 🍋 view declaration settings
|
|
81
|
+
- special settings for views at declaration-time
|
|
82
|
+
```ts
|
|
83
|
+
export const CoolView = view
|
|
84
|
+
.settings({mode: "open", delegatesFocus: true})
|
|
85
|
+
.declare(use => (greeting: string) => {
|
|
86
|
+
return html`😎 ${greeting} <slot></slot>`
|
|
87
|
+
})
|
|
88
|
+
```
|
|
89
|
+
- all [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters) (like `mode` and `delegatesFocus`) are valid `settings`
|
|
90
|
+
- note the `<slot></slot>` we'll use in the next example lol
|
|
91
|
+
|
|
81
92
|
### 🍋 view injection options
|
|
82
93
|
- options for views at the template injection site
|
|
83
94
|
```ts
|
|
84
95
|
$.render($(".app"), html`
|
|
85
96
|
<h2>super cool example</h2>
|
|
86
|
-
|
|
97
|
+
|
|
98
|
+
${CoolView.props("hello")
|
|
87
99
|
.attr("class", "hero")
|
|
88
100
|
.children(html`<em>spongebob</em>`)
|
|
89
|
-
.
|
|
101
|
+
.render()}
|
|
90
102
|
`)
|
|
91
103
|
```
|
|
104
|
+
- `props` — provide props and start a view chain
|
|
92
105
|
- `attr` — set html attributes on the `<sly-view>` host element
|
|
93
106
|
- `children` — nested content in the host element, can be [slotted](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots)
|
|
94
|
-
- `
|
|
95
|
-
|
|
96
|
-
### 🍋 view declaration settings
|
|
97
|
-
- special settings for views at declaration-time
|
|
98
|
-
```ts
|
|
99
|
-
export const CoolView = view
|
|
100
|
-
.settings({mode: "open", delegatesFocus: true})
|
|
101
|
-
.view(use => (greeting: string) => {
|
|
102
|
-
|
|
103
|
-
return html`😎 ${greeting} <slot></slot>`
|
|
104
|
-
})
|
|
105
|
-
```
|
|
106
|
-
- all [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters) (like `mode` and `delegatesFocus`) are valid `settings`
|
|
107
|
-
- note the `<slot></slot>` we'll use in the next example lol
|
|
107
|
+
- `render` — end the view chain and render the lit directive
|
|
108
108
|
|
|
109
109
|
### 🍋 web components
|
|
110
110
|
- **build a component directly**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/sly",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0-0",
|
|
4
4
|
"description": "web shadow views",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"lit": "^3.3.1"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@e280/strata": "^0.
|
|
20
|
-
"@e280/stz": "^0.2.0
|
|
19
|
+
"@e280/strata": "^0.2.0-0",
|
|
20
|
+
"@e280/stz": "^0.2.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@e280/science": "^0.1.1",
|
package/s/demo/views/counter.ts
CHANGED
|
@@ -14,19 +14,19 @@ export const CounterView = view(use => (initial: number) => {
|
|
|
14
14
|
|
|
15
15
|
use.mount(() => repeat(async() => {
|
|
16
16
|
const since = Date.now() - start
|
|
17
|
-
seconds(Math.floor(since / 1000))
|
|
17
|
+
seconds.set(Math.floor(since / 1000))
|
|
18
18
|
}))
|
|
19
19
|
|
|
20
20
|
const count = use.signal(initial)
|
|
21
|
-
const increment = () => count
|
|
21
|
+
const increment = () => count.value++
|
|
22
22
|
|
|
23
23
|
return html`
|
|
24
24
|
<slot></slot>
|
|
25
25
|
<div>
|
|
26
|
-
<span>${seconds()}</span>
|
|
26
|
+
<span>${seconds.get()}</span>
|
|
27
27
|
</div>
|
|
28
28
|
<div>
|
|
29
|
-
<span>${count()}</span>
|
|
29
|
+
<span>${count.get()}</span>
|
|
30
30
|
<button @click="${increment}">+</button>
|
|
31
31
|
</div>
|
|
32
32
|
`
|
package/s/demo/views/demo.ts
CHANGED
|
@@ -21,11 +21,11 @@ export const AsciiAnim = view(use => ({hz, frames}: {
|
|
|
21
21
|
|
|
22
22
|
use.mount(() => repeat(async() => {
|
|
23
23
|
await nap(1000 / hz)
|
|
24
|
-
const next = frame() + 1
|
|
25
|
-
frame(next >= frames.length ? 0 : next)
|
|
24
|
+
const next = frame.get() + 1
|
|
25
|
+
frame.set(next >= frames.length ? 0 : next)
|
|
26
26
|
}))
|
|
27
27
|
|
|
28
|
-
return frames.at(frame())
|
|
28
|
+
return frames.at(frame.get())
|
|
29
29
|
})
|
|
30
30
|
|
|
31
31
|
const style = css`
|
package/s/ops/op.ts
CHANGED
|
@@ -46,16 +46,16 @@ export class Op<V> {
|
|
|
46
46
|
get finally() { return this.wait.finally.bind(this.wait) }
|
|
47
47
|
|
|
48
48
|
async setLoading() {
|
|
49
|
-
await this.signal(["loading"])
|
|
49
|
+
await this.signal.set(["loading"])
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
async setReady(value: V) {
|
|
53
|
-
await this.signal(["ready", value])
|
|
53
|
+
await this.signal.set(["ready", value])
|
|
54
54
|
await this.#resolve(value)
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
async setError(error: any) {
|
|
58
|
-
await this.signal(["error", error])
|
|
58
|
+
await this.signal.set(["error", error])
|
|
59
59
|
await this.#reject(error)
|
|
60
60
|
}
|
|
61
61
|
|
|
@@ -79,23 +79,23 @@ export class Op<V> {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
get pod() {
|
|
82
|
-
return this.signal()
|
|
82
|
+
return this.signal.get()
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
set pod(p: Pod<V>) {
|
|
86
|
-
this.signal(p)
|
|
86
|
+
this.signal.set(p)
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
get status() {
|
|
90
|
-
return this.signal()[0]
|
|
90
|
+
return this.signal.get()[0]
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
get value() {
|
|
94
|
-
return podium.value(this.signal())
|
|
94
|
+
return podium.value(this.signal.get())
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
get error() {
|
|
98
|
-
return podium.error(this.signal())
|
|
98
|
+
return podium.error(this.signal.get())
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
get isLoading() {
|
|
@@ -111,13 +111,13 @@ export class Op<V> {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
require() {
|
|
114
|
-
const pod = this.signal()
|
|
114
|
+
const pod = this.signal.get()
|
|
115
115
|
if (pod[0] !== "ready") throw new Error("required value not ready")
|
|
116
116
|
return pod[1]
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
select<R>(select: PodSelect<V, R>) {
|
|
120
|
-
return podium.select(this.signal(), select)
|
|
120
|
+
return podium.select(this.signal.get(), select)
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
morph<V2>(fn: (value: V) => V2) {
|
package/s/views/types.ts
CHANGED
|
@@ -16,11 +16,7 @@ export type ComponentFn = (use: Use) => Content
|
|
|
16
16
|
export type ViewFn<Props extends any[]> = (use: Use) => (...props: Props) => Content
|
|
17
17
|
export type BasicView<Props extends any[]> = (...props: Props) => DirectiveResult<any>
|
|
18
18
|
export type View<Props extends any[]> = BasicView<Props> & {
|
|
19
|
-
props:
|
|
20
|
-
with: (w: Partial<ViewWith>) => View<Props>
|
|
21
|
-
children: (...children: Content[]) => View<Props>
|
|
22
|
-
attrs: (attrs: Record<string, AttrValue>) => View<Props>
|
|
23
|
-
attr: (name: string, value: AttrValue) => View<Props>
|
|
19
|
+
props: (...props: Props) => ViewChain
|
|
24
20
|
component: (...props: Props) => Constructor<Component>
|
|
25
21
|
}
|
|
26
22
|
|
|
@@ -30,8 +26,15 @@ export type ViewSettings = ShadowRootInit & {
|
|
|
30
26
|
styles?: CSSResultGroup
|
|
31
27
|
}
|
|
32
28
|
|
|
33
|
-
export type
|
|
34
|
-
children: Content
|
|
29
|
+
export type ViewChain = {
|
|
30
|
+
children(...c: Content[]): ViewChain
|
|
31
|
+
attrs(a: Record<string, AttrValue>): ViewChain
|
|
32
|
+
attr(n: string, v: AttrValue): ViewChain
|
|
33
|
+
render(): DirectiveResult<any>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type ViewContext = {
|
|
37
|
+
children: Content[]
|
|
35
38
|
attrs: Record<string, AttrValue>
|
|
36
39
|
}
|
|
37
40
|
|
package/s/views/view.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
|
|
2
2
|
import {render} from "lit"
|
|
3
3
|
import {debounce, MapG} from "@e280/stz"
|
|
4
|
+
import {directive} from "lit/directive.js"
|
|
4
5
|
import {tracker} from "@e280/strata/tracker"
|
|
5
6
|
import {AsyncDirective} from "lit/async-directive.js"
|
|
6
|
-
import {directive, DirectiveResult} from "lit/directive.js"
|
|
7
7
|
|
|
8
8
|
import {register} from "../dom/register.js"
|
|
9
9
|
import {applyAttrs} from "./utils/apply-attrs.js"
|
|
10
10
|
import {applyStyles} from "./utils/apply-styles.js"
|
|
11
11
|
import {Use, _wrap, _disconnect, _reconnect} from "./use.js"
|
|
12
|
-
import {AttrValue, ComponentFn, Content, View, ViewFn, ViewSettings,
|
|
12
|
+
import {AttrValue, ComponentFn, Content, View, ViewFn, ViewSettings, ViewContext} from "./types.js"
|
|
13
13
|
|
|
14
14
|
export const view = setupView({mode: "open"})
|
|
15
15
|
export class SlyView extends HTMLElement {}
|
|
16
16
|
register({SlyView}, {soft: true, upgrade: true})
|
|
17
17
|
|
|
18
18
|
function setupView(settings: ViewSettings) {
|
|
19
|
-
function view<Props extends any[]>(fn: ViewFn<Props>) {
|
|
19
|
+
function view<Props extends any[]>(fn: ViewFn<Props>): View<Props> {
|
|
20
20
|
type Situation = {
|
|
21
21
|
getElement: () => HTMLElement
|
|
22
22
|
isComponent: boolean
|
|
@@ -27,7 +27,7 @@ function setupView(settings: ViewSettings) {
|
|
|
27
27
|
#shadow = this.#element.attachShadow(settings)
|
|
28
28
|
#renderDebounced = debounce(0, () => this.#renderNow())
|
|
29
29
|
#tracking = new MapG<any, () => void>
|
|
30
|
-
#params!: {
|
|
30
|
+
#params!: {context: ViewContext, props: Props}
|
|
31
31
|
|
|
32
32
|
#use = new Use(
|
|
33
33
|
this.#element,
|
|
@@ -46,7 +46,7 @@ function setupView(settings: ViewSettings) {
|
|
|
46
46
|
#renderNow() {
|
|
47
47
|
if (!this.#params) return
|
|
48
48
|
if (!this.isConnected) return
|
|
49
|
-
const {
|
|
49
|
+
const {context: w, props} = this.#params
|
|
50
50
|
|
|
51
51
|
this.#use[_wrap](() => {
|
|
52
52
|
// apply html attributes
|
|
@@ -71,8 +71,8 @@ function setupView(settings: ViewSettings) {
|
|
|
71
71
|
})
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
render(
|
|
75
|
-
this.#params = {
|
|
74
|
+
render(context: ViewContext, props: Props) {
|
|
75
|
+
this.#params = {context: context, props}
|
|
76
76
|
this.#renderNow()
|
|
77
77
|
return situation.isComponent ? null : this.#element
|
|
78
78
|
}
|
|
@@ -94,40 +94,55 @@ function setupView(settings: ViewSettings) {
|
|
|
94
94
|
isComponent: false,
|
|
95
95
|
}))
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
97
|
+
const freshViewContext = (): ViewContext => ({attrs: {}, children: []})
|
|
98
|
+
|
|
99
|
+
function rendy(...props: Props) {
|
|
100
|
+
return d(freshViewContext(), props)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
rendy.props = (...props: Props) => {
|
|
104
|
+
let ctx = freshViewContext()
|
|
105
|
+
const chain = {
|
|
106
|
+
children(...children: Content[]) {
|
|
107
|
+
ctx = {...ctx, children: [...ctx.children, ...children]}
|
|
108
|
+
return chain
|
|
109
|
+
},
|
|
110
|
+
attrs(attrs: Record<string, AttrValue>) {
|
|
111
|
+
ctx = {...ctx, attrs: {...ctx.attrs, ...attrs}}
|
|
112
|
+
return chain
|
|
113
|
+
},
|
|
114
|
+
attr(name: string, value: AttrValue) {
|
|
115
|
+
ctx = {...ctx, attrs: {...ctx.attrs, [name]: value}}
|
|
116
|
+
return chain
|
|
117
|
+
},
|
|
118
|
+
render() {
|
|
119
|
+
return d(ctx, props)
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
return chain
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
rendy.component = (...props: Props) => class extends HTMLElement {
|
|
126
|
+
#directive = directive(
|
|
127
|
+
make({
|
|
109
128
|
getElement: () => this,
|
|
110
129
|
isComponent: true,
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
130
|
+
})
|
|
131
|
+
)
|
|
132
|
+
constructor() {
|
|
133
|
+
super()
|
|
134
|
+
this.render(...props)
|
|
135
|
+
}
|
|
136
|
+
render(...props: Props) {
|
|
137
|
+
if (this.isConnected)
|
|
138
|
+
render(this.#directive(freshViewContext(), props), this)
|
|
120
139
|
}
|
|
121
|
-
return rend
|
|
122
140
|
}
|
|
123
141
|
|
|
124
|
-
return
|
|
125
|
-
attrs: {},
|
|
126
|
-
children: null,
|
|
127
|
-
})
|
|
142
|
+
return rendy
|
|
128
143
|
}
|
|
129
144
|
|
|
130
|
-
view.
|
|
145
|
+
view.declare = view
|
|
131
146
|
view.settings = (settings2: Partial<ViewSettings>) => setupView({...settings, ...settings2})
|
|
132
147
|
view.component = (fn: ComponentFn) => view(use => () => fn(use)).component()
|
|
133
148
|
return view
|