@e280/sly 0.2.0-8 → 0.2.0-9

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.
Files changed (91) hide show
  1. package/README.md +87 -24
  2. package/package.json +1 -1
  3. package/s/demo/demo.bundle.ts +13 -1
  4. package/s/demo/views/counter.ts +13 -5
  5. package/s/demo/views/demo.ts +10 -0
  6. package/s/demo/views/divine.ts +22 -0
  7. package/s/demo/views/incredi.ts +2 -1
  8. package/s/dom/attrs/attrs.ts +21 -0
  9. package/s/dom/attrs/parts/attr-fns.ts +38 -0
  10. package/s/dom/attrs/parts/attr-proxies.ts +35 -0
  11. package/s/dom/attrs/parts/attr-spec.ts +29 -0
  12. package/s/dom/attrs/parts/on-attrs.ts +8 -0
  13. package/s/dom/dom.ts +6 -5
  14. package/s/dom/{register.ts → parts/register.ts} +2 -10
  15. package/s/dom/types.ts +45 -0
  16. package/s/index.html.ts +2 -1
  17. package/s/index.ts +1 -4
  18. package/s/views/base-element.ts +15 -31
  19. package/s/views/types.ts +15 -6
  20. package/s/views/use.ts +10 -11
  21. package/s/views/utils/attr-watcher.ts +22 -0
  22. package/s/views/utils/reactor.ts +23 -0
  23. package/s/views/view.ts +73 -38
  24. package/x/demo/demo.bundle.js +11 -1
  25. package/x/demo/demo.bundle.js.map +1 -1
  26. package/x/demo/demo.bundle.min.js +19 -15
  27. package/x/demo/demo.bundle.min.js.map +4 -4
  28. package/x/demo/views/counter.d.ts +7 -1
  29. package/x/demo/views/counter.js +11 -5
  30. package/x/demo/views/counter.js.map +1 -1
  31. package/x/demo/views/demo.js +8 -0
  32. package/x/demo/views/demo.js.map +1 -1
  33. package/x/demo/views/divine.d.ts +8 -0
  34. package/x/demo/views/divine.js +19 -0
  35. package/x/demo/views/divine.js.map +1 -0
  36. package/x/demo/views/incredi.js +1 -1
  37. package/x/demo/views/incredi.js.map +1 -1
  38. package/x/dom/attrs/attrs.d.ts +20 -0
  39. package/x/dom/attrs/attrs.js +17 -0
  40. package/x/dom/attrs/attrs.js.map +1 -0
  41. package/x/dom/attrs/parts/attr-fns.d.ts +13 -0
  42. package/x/dom/attrs/parts/attr-fns.js +42 -0
  43. package/x/dom/attrs/parts/attr-fns.js.map +1 -0
  44. package/x/dom/attrs/parts/attr-proxies.d.ts +8 -0
  45. package/x/dom/attrs/parts/attr-proxies.js +21 -0
  46. package/x/dom/attrs/parts/attr-proxies.js.map +1 -0
  47. package/x/dom/attrs/parts/attr-spec.d.ts +3 -0
  48. package/x/dom/attrs/parts/attr-spec.js +21 -0
  49. package/x/dom/attrs/parts/attr-spec.js.map +1 -0
  50. package/x/dom/attrs/parts/on-attrs.d.ts +2 -0
  51. package/x/dom/attrs/parts/on-attrs.js +7 -0
  52. package/x/dom/attrs/parts/on-attrs.js.map +1 -0
  53. package/x/dom/dom.d.ts +10 -4
  54. package/x/dom/dom.js +5 -5
  55. package/x/dom/dom.js.map +1 -1
  56. package/x/dom/parts/dashify.js.map +1 -0
  57. package/x/dom/{register.d.ts → parts/register.d.ts} +2 -10
  58. package/x/dom/parts/register.js.map +1 -0
  59. package/x/dom/{attributes.d.ts → types.d.ts} +11 -2
  60. package/x/dom/types.js +2 -0
  61. package/x/dom/types.js.map +1 -0
  62. package/x/index.d.ts +1 -4
  63. package/x/index.html +4 -3
  64. package/x/index.html.js +2 -1
  65. package/x/index.html.js.map +1 -1
  66. package/x/index.js +1 -4
  67. package/x/index.js.map +1 -1
  68. package/x/views/base-element.js +9 -27
  69. package/x/views/base-element.js.map +1 -1
  70. package/x/views/types.d.ts +11 -6
  71. package/x/views/use.d.ts +2 -2
  72. package/x/views/use.js +2 -5
  73. package/x/views/use.js.map +1 -1
  74. package/x/views/utils/attr-watcher.d.ts +8 -0
  75. package/x/views/utils/attr-watcher.js +20 -0
  76. package/x/views/utils/attr-watcher.js.map +1 -0
  77. package/x/views/utils/reactor.d.ts +6 -0
  78. package/x/views/utils/reactor.js +18 -0
  79. package/x/views/utils/reactor.js.map +1 -0
  80. package/x/views/view.d.ts +8 -4
  81. package/x/views/view.js +59 -30
  82. package/x/views/view.js.map +1 -1
  83. package/s/dom/attributes.ts +0 -89
  84. package/x/dom/attributes.js +0 -46
  85. package/x/dom/attributes.js.map +0 -1
  86. package/x/dom/dashify.js.map +0 -1
  87. package/x/dom/register.js.map +0 -1
  88. /package/s/dom/{dashify.ts → parts/dashify.ts} +0 -0
  89. /package/x/dom/{dashify.d.ts → parts/dashify.d.ts} +0 -0
  90. /package/x/dom/{dashify.js → parts/dashify.js} +0 -0
  91. /package/x/dom/{register.js → parts/register.js} +0 -0
package/README.md CHANGED
@@ -20,7 +20,7 @@
20
20
  ## 🦝 sly and friends
21
21
 
22
22
  ```sh
23
- npm install @e280/sly lit
23
+ npm install @e280/sly lit @e280/strata @e280/stz
24
24
  ```
25
25
 
26
26
  > [!NOTE]
@@ -34,15 +34,15 @@ npm install @e280/sly lit
34
34
  <br/><br/>
35
35
  <a id="views"></a>
36
36
 
37
- ## 🦝🍋 sly views
37
+ ## 🦝🍋 sly views and components
38
38
  > *views are the crown jewel of sly.. shadow-dom'd.. hooks-based.. "ergonomics"..*
39
39
 
40
40
  ```ts
41
41
  view(use => () => html`<p>hello world</p>`)
42
42
  ```
43
43
 
44
+ - any view can be converted into a web component
44
45
  - views are not [web components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components), but they do have [shadow roots](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) and support [slots](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots)
45
- - any view can be registered as a web component, perfect for entrypoints or sharing widgets with html authors
46
46
  - views are typescript-native and comfy for webdevs building apps
47
47
  - views automatically rerender whenever any [strata-compatible](https://github.com/e280/strata) state changes
48
48
 
@@ -76,8 +76,14 @@ import {html, css} from "lit"
76
76
  ```
77
77
  - 🤯 **register a view as a web component**
78
78
  ```ts
79
- dom.register({MyCounter: CounterView.component(1)})
80
- // <my-counter></my-counter>
79
+ dom.register({
80
+ MyCounter: CounterView
81
+ .component()
82
+ .props(component => [dom.attrs(component).number.start ?? 0]),
83
+ })
84
+ ```
85
+ ```html
86
+ <my-counter start="1"></my-counter>
81
87
  ```
82
88
 
83
89
  ### 🍋 view declaration settings
@@ -85,7 +91,7 @@ import {html, css} from "lit"
85
91
  ```ts
86
92
  export const CoolView = view
87
93
  .settings({mode: "open", delegatesFocus: true})
88
- .declare(use => (greeting: string) => {
94
+ .render(use => (greeting: string) => {
89
95
  return html`😎 ${greeting} <slot></slot>`
90
96
  })
91
97
  ```
@@ -108,27 +114,77 @@ import {html, css} from "lit"
108
114
  - `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)
109
115
  - `render` — end the view chain and render the lit directive
110
116
 
111
- ### 🍋 view web components
112
- - **build a component directly**
117
+ ### 🍋 view/component universality
118
+ - **start with a view,**
113
119
  ```ts
114
- const MyComponent = view.component(use => html`<p>hello world</p>`)
120
+ export const GreeterView = view(use => (name: string) => {
121
+ return html`<p>hello ${name}</p>`
122
+ })
123
+
124
+ // view usage:
125
+ // GreeterView("pimsley")
115
126
  ```
116
- - notice that direct components don't take props (do `use.attrs` instead)
117
- - **convert any view into a web component**
127
+ then you can convert it to a component
118
128
  ```ts
119
- const MyCounter = CounterView.component(1)
129
+ export class GreeterComponent extends (GreeterView
130
+ .component()
131
+ .props(component => [component.getAttribute("name") ?? "unknown"])
132
+ ) {}
133
+
134
+ // html usage:
135
+ // <greeter-component name="pimsley"></greeter-component>
120
136
  ```
121
- - to convert a view to a component, you provide props
122
- - note that the component instance has a render method like `element.render(2)` which can take new props at runtime
137
+ - **start with a component,**
138
+ ```ts
139
+ export class GreeterComponent extends (view
140
+ .component()
141
+ .props(component => [component.getAttribute("name") ?? "unknown"])
142
+ .render(use => (name: string) => {
143
+ return html`<p>hello ${name}</p>`
144
+ })
145
+ ) {}
146
+
147
+ // html usage:
148
+ // <greeter-component name="pimsley"></greeter-component>
149
+ ```
150
+ then you can already use it as a view
151
+ ```ts
152
+ // view usage:
153
+ // GreeterComponent.view("pimsley")
154
+ ```
155
+ - **understanding `.component(init)` and `.props(fn)`**
156
+ - `.props` takes a fn that is called every render, which returns the props given to the view
157
+ ```ts
158
+ .component()
159
+ .props(() => ["pimsley"])
160
+ ```
161
+ the props fn receives the component instance, so you can query html attributes
162
+ ```ts
163
+ .component()
164
+ .props(component => [component.getAttribute("name") ?? "unknown"])
165
+ ```
166
+ - `.component` takes a mixin type added to the component type, so your `.props` can accept instance properties
167
+ ```ts
168
+ .component<{name?: string}>()
169
+ .props(component => [component.name ?? "unknown"])
170
+ ```
171
+ - `.component` also takes an init fn, so you can do some setup, like use signals for reactivity
172
+ ```ts
173
+ .component<{$name: SignalFn<string>}>(component => {
174
+ component.$name = signal("pimsley")
175
+ })
176
+ .props(component => [component.$name])
177
+ ```
178
+ - `.component` lets you set instance properties, that devs can interact with via the dom
179
+ ```ts
180
+ dom<GreeterComponent>("my-component").$name.value = "mortimer"
181
+ ```
123
182
  - **register web components to the dom**
124
183
  ```ts
125
- dom.register({MyComponent, MyCounter})
126
- // <my-component></my-component>
127
- // <my-counter></my-counter>
184
+ dom.register({GreeterComponent})
128
185
  ```
129
- - `dom.register` automatically dashes the tag names (`MyComponent` becomes `<my-component>`)
130
186
 
131
- ### 🍋 view "use" hooks reference
187
+ ### 🍋 "use" hooks reference
132
188
  - 👮 **follow the hooks rules**
133
189
  > just like [react hooks](https://react.dev/warnings/invalid-hook-call-warning), the execution order of sly's `use` hooks actually matters..
134
190
  > 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..*
@@ -201,7 +257,7 @@ import {html, css} from "lit"
201
257
  - **use.attrs** — ergonomic typed html attribute access
202
258
  *(see [dom.attrs](#dom.attrs) for more details)*
203
259
  ```ts
204
- const attrs = use.attrs({
260
+ const attrs = use.attrs.spec({
205
261
  name: String,
206
262
  count: Number,
207
263
  active: Boolean,
@@ -239,7 +295,7 @@ import {html, css} from "lit"
239
295
  const op = use.op.promise(doAsyncWork())
240
296
  ```
241
297
 
242
- ### 🍋 view "use" recipes
298
+ ### 🍋 "use" recipes
243
299
  - make a ticker — mount, repeat, and nap
244
300
  ```ts
245
301
  import {repeat, nap} from "@e280/stz"
@@ -288,7 +344,7 @@ base element enjoys the same `use` hooks as views.
288
344
  start = 10
289
345
 
290
346
  // custom attributes
291
- attrs = dom.attrs(this, {
347
+ attrs = dom.attrs(this).spec({
292
348
  multiply: Number,
293
349
  })
294
350
 
@@ -388,6 +444,7 @@ import {dom} from "@e280/sly"
388
444
  // <my-component>
389
445
  // <another-cool-component>
390
446
  ```
447
+ - `dom.register` automatically dashes the tag names (`MyComponent` becomes `<my-component>`)
391
448
  - `render` content into an element
392
449
  ```ts
393
450
  dom(element).render(html`<p>hello world</p>`)
@@ -400,7 +457,7 @@ import {dom} from "@e280/sly"
400
457
  ```
401
458
  - `attrs` <a id="dom.attrs"></a> to setup a type-happy html attribute helper
402
459
  ```ts
403
- const attrs = dom.attrs(element, {
460
+ const attrs = dom.attrs(element).spec({
404
461
  name: String,
405
462
  count: Number,
406
463
  active: Boolean,
@@ -420,6 +477,12 @@ import {dom} from "@e280/sly"
420
477
  attrs.name = undefined // removes the attr
421
478
  attrs.count = undefined // removes the attr
422
479
  ```
480
+ or if you wanna be more loosey-goosy, skip the spec
481
+ ```ts
482
+ dom.attrs(element).string.name = "pimsley"
483
+ dom.attrs(element).number.count = 125
484
+ dom.attrs(element).boolean.active = true
485
+ ```
423
486
 
424
487
 
425
488
 
@@ -599,7 +662,7 @@ import {ev} from "@e280/stz"
599
662
  })
600
663
 
601
664
  // sly attribute handler for the body
602
- const attrs = dom.attrs(document.body, {
665
+ const attrs = dom.attrs(document.body).spec({
603
666
  "data-indicator": Boolean,
604
667
  })
605
668
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e280/sly",
3
- "version": "0.2.0-8",
3
+ "version": "0.2.0-9",
4
4
  "description": "web shadow views",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,14 +1,26 @@
1
1
 
2
+ import {nap, repeat} from "@e280/stz"
2
3
  import {dom} from "../dom/dom.js"
3
4
  import {DemoView} from "./views/demo.js"
4
5
  import {CounterView} from "./views/counter.js"
6
+ import {DivineElement} from "./views/divine.js"
5
7
  import {IncrediElement} from "./views/incredi.js"
6
8
 
7
9
  dom.in(".demo").render(DemoView())
8
10
 
9
11
  dom.register({
10
12
  IncrediElement,
11
- DemoCounter: CounterView.component(1),
13
+ DivineElement,
14
+ DemoCounter: CounterView
15
+ .component()
16
+ .props(c => [dom.attrs(c).number.initial ?? 0]),
17
+ })
18
+
19
+ const divine = dom<DivineElement>("divine-element")
20
+
21
+ repeat(async() => {
22
+ await nap(1000)
23
+ divine.$speed.value++
12
24
  })
13
25
 
14
26
  console.log("🦝 sly")
@@ -2,21 +2,22 @@
2
2
  import {css, html} from "lit"
3
3
  import {repeat} from "@e280/stz"
4
4
 
5
+ import {dom} from "../../dom/dom.js"
5
6
  import {view} from "../../views/view.js"
6
7
  import {cssReset} from "../../views/css-reset.js"
7
8
 
8
- export const CounterView = view(use => (initial: number) => {
9
+ export const CounterView = view(use => (start: number) => {
9
10
  use.name("counter")
10
11
  use.styles(cssReset, styles)
11
12
 
12
13
  const $seconds = use.signal(0)
13
- const start = use.once(() => Date.now())
14
+ const since = use.once(() => Date.now())
14
15
  use.mount(() => repeat(async() => {
15
- const since = Date.now() - start
16
- $seconds.set(Math.floor(since / 1000))
16
+ const delta = Date.now() - since
17
+ $seconds.set(Math.floor(delta / 1000))
17
18
  }))
18
19
 
19
- const $count = use.signal(initial)
20
+ const $count = use.signal(start)
20
21
  const increment = () => $count.value++
21
22
 
22
23
  const $product = use.signal
@@ -39,6 +40,13 @@ export const CounterView = view(use => (initial: number) => {
39
40
  `
40
41
  })
41
42
 
43
+ // convert a view into a web component
44
+ export class CounterComponent extends (
45
+ CounterView
46
+ .component<{start?: number}>()
47
+ .props(c => [dom.attrs(c).number.start ?? 0])
48
+ ) {}
49
+
42
50
  const styles = css`
43
51
  :host {
44
52
  display: flex;
@@ -1,16 +1,26 @@
1
1
 
2
2
  import {css, html} from "lit"
3
+ import {DivineView} from "./divine.js"
3
4
  import {view} from "../../views/view.js"
4
5
  import {CounterView} from "./counter.js"
5
6
  import {LoadersView} from "./loaders.js"
6
7
  import {cssReset} from "../../views/css-reset.js"
8
+ import { nap, repeat } from "@e280/stz"
7
9
 
8
10
  export const DemoView = view(use => () => {
9
11
  use.name("demo")
10
12
  use.styles(cssReset, styles)
11
13
 
14
+ const $speed = use.signal(3)
15
+
16
+ use.mount(() => repeat(async() => {
17
+ await nap(1000)
18
+ $speed.value++
19
+ }))
20
+
12
21
  return html`
13
22
  ${CounterView.props(2).children("view").render()}
23
+ ${DivineView($speed())}
14
24
  ${LoadersView()}
15
25
  `
16
26
  })
@@ -0,0 +1,22 @@
1
+
2
+ import {html} from "lit"
3
+ import {view} from "../../views/view.js"
4
+ import {signal, SignalFn} from "@e280/strata"
5
+
6
+ export class DivineElement extends (view
7
+ .component<{$speed: SignalFn<number>}>(component => {
8
+ component.$speed = signal(1)
9
+ })
10
+ .props<[speed: number]>(component => [component.$speed()])
11
+ .render(use => speed => {
12
+ const $count = use.signal(0)
13
+ const increment = () => $count($count() + speed)
14
+ return html`
15
+ <span>${$count()}</span>
16
+ <button @click="${increment}">+${speed}</button>
17
+ `
18
+ })
19
+ ) {}
20
+
21
+ export const DivineView = DivineElement.view
22
+
@@ -8,7 +8,8 @@ import {BaseElement} from "../../views/base-element.js"
8
8
 
9
9
  export class IncrediElement extends BaseElement {
10
10
  static styles = css`span{color:orange}`
11
- attrs = dom.attrs(this, {value: Number})
11
+
12
+ attrs = dom.attrs(this).spec({value: Number})
12
13
  something = {whatever: "rofl"}
13
14
 
14
15
  render(use: Use) {
@@ -0,0 +1,21 @@
1
+
2
+ import {AttrSpec} from "../types.js"
3
+ import {onAttrs} from "./parts/on-attrs.js"
4
+ import {attrFns} from "./parts/attr-fns.js"
5
+ import {attrSpec} from "./parts/attr-spec.js"
6
+ import {AttrProxies} from "./parts/attr-proxies.js"
7
+
8
+ export function attrs(element: HTMLElement) {
9
+ const proxies = new AttrProxies(element)
10
+ return {
11
+ string: proxies.string,
12
+ number: proxies.number,
13
+ boolean: proxies.boolean,
14
+ on: (fn: () => void) => onAttrs(element, fn),
15
+ spec: <A extends AttrSpec>(spec: A) => attrSpec(element, spec),
16
+ }
17
+ }
18
+
19
+ attrs.get = attrFns.get
20
+ attrs.set = attrFns.set
21
+
@@ -0,0 +1,38 @@
1
+
2
+ /** fns for getting and setting html attributes of various types */
3
+ export const attrFns = {
4
+ get: {
5
+ string: (e: HTMLElement, key: string) => {
6
+ return e.getAttribute(key) ?? undefined
7
+ },
8
+ number: (e: HTMLElement, key: string) => {
9
+ const raw = e.getAttribute(key)
10
+ return (raw === null || !raw)
11
+ ? undefined
12
+ : Number(raw)
13
+ },
14
+ boolean: (e: HTMLElement, key: string) => {
15
+ const raw = e.getAttribute(key)
16
+ return raw !== null
17
+ },
18
+ },
19
+
20
+ set: {
21
+ string: (e: HTMLElement, key: string, value: string | undefined) => {
22
+ if (value === undefined) e.removeAttribute(key)
23
+ else e.setAttribute(key, value)
24
+ return true
25
+ },
26
+ number: (e: HTMLElement, key: string, value: number | undefined) => {
27
+ if (value === undefined) e.removeAttribute(key)
28
+ else e.setAttribute(key, value.toString())
29
+ return true
30
+ },
31
+ boolean: (e: HTMLElement, key: string, value: boolean | undefined) => {
32
+ if (value) e.setAttribute(key, "")
33
+ else e.removeAttribute(key)
34
+ return true
35
+ },
36
+ },
37
+ }
38
+
@@ -0,0 +1,35 @@
1
+
2
+ import {attrFns} from "./attr-fns.js"
3
+
4
+ /** a typed proxy accessor for html attributes */
5
+ export class AttrProxies {
6
+ constructor(public element: HTMLElement) {}
7
+
8
+ string = new Proxy({}, {
9
+ get: (_t, key: string) => (
10
+ attrFns.get.string(this.element, key)
11
+ ),
12
+ set: (_t, key: string, value: string | undefined) => (
13
+ attrFns.set.string(this.element, key, value)
14
+ ),
15
+ }) as Record<string, string | undefined>
16
+
17
+ number = new Proxy({}, {
18
+ get: (_t, key: string) => (
19
+ attrFns.get.number(this.element, key)
20
+ ),
21
+ set: (_t, key: string, value: number | undefined) => (
22
+ attrFns.set.number(this.element, key, value)
23
+ ),
24
+ }) as Record<string, number | undefined>
25
+
26
+ boolean = new Proxy({}, {
27
+ get: (_t, key: string) => (
28
+ attrFns.get.boolean(this.element, key)
29
+ ),
30
+ set: (_t, key: string, value: boolean | undefined) => (
31
+ attrFns.set.boolean(this.element, key, value)
32
+ ),
33
+ }) as Record<string, boolean | undefined>
34
+ }
35
+
@@ -0,0 +1,29 @@
1
+
2
+ import {AttrSpec, AttrTypes} from "../../types.js"
3
+ import {attrFns} from "./attr-fns.js"
4
+
5
+ /** specify available html attributes and their types and create a proxy accessor */
6
+ export const attrSpec = <A extends AttrSpec>(
7
+ e: HTMLElement,
8
+ spec: A,
9
+ ) => new Proxy(spec, {
10
+
11
+ get: (_target, key: string) => {
12
+ switch (spec[key]) {
13
+ case String: return attrFns.get.string(e, key)
14
+ case Number: return attrFns.get.number(e, key)
15
+ case Boolean: return attrFns.get.boolean(e, key)
16
+ default: throw new Error(`invalid attribute type for "${key}"`)
17
+ }
18
+ },
19
+
20
+ set: (_target, key: string, value: any) => {
21
+ switch (spec[key]) {
22
+ case String: return attrFns.set.string(e, key, value)
23
+ case Number: return attrFns.set.number(e, key, value)
24
+ case Boolean: return attrFns.set.boolean(e, key, value)
25
+ default: throw new Error(`invalid attribute type for "${key}"`)
26
+ }
27
+ },
28
+ }) as any as AttrTypes<A>
29
+
@@ -0,0 +1,8 @@
1
+
2
+ /** respond when any attribute changes on the html element */
3
+ export function onAttrs(element: HTMLElement, fn: () => void) {
4
+ const observer = new MutationObserver(fn)
5
+ observer.observe(element, {attributes: true})
6
+ return () => observer.disconnect()
7
+ }
8
+
package/s/dom/dom.ts CHANGED
@@ -1,8 +1,9 @@
1
1
 
2
2
  import {render} from "lit"
3
- import {register} from "./register.js"
3
+ import {AttrSpec} from "./types.js"
4
+ import {attrs} from "./attrs/attrs.js"
4
5
  import {Content} from "../views/types.js"
5
- import {attributes, AttrSpec, AttrTypes} from "./attributes.js"
6
+ import {register} from "./parts/register.js"
6
7
 
7
8
  export type Renderable = HTMLElement | ShadowRoot | DocumentFragment
8
9
  export type Queryable = HTMLElement | ShadowRoot | Element | Document | DocumentFragment
@@ -45,8 +46,8 @@ export class Dom<C extends Queryable> {
45
46
  return render(content, this.element as Renderable)
46
47
  }
47
48
 
48
- attrs<A extends AttrSpec>(spec: A) {
49
- return attributes(this.element as HTMLElement, spec)
49
+ attrs() {
50
+ return attrs(this.element as HTMLElement)
50
51
  }
51
52
  }
52
53
 
@@ -64,7 +65,7 @@ dom.require = doc.require.bind(doc)
64
65
  dom.maybe = doc.maybe.bind(doc)
65
66
  dom.all = doc.all.bind(doc)
66
67
 
67
- dom.attrs = attributes
68
+ dom.attrs = attrs
68
69
  dom.register = register
69
70
  dom.render = (container: Renderable, ...content: Content[]) => {
70
71
  return render(content, container)
@@ -1,14 +1,6 @@
1
1
 
2
2
  import {dashify} from "./dashify.js"
3
-
4
- export type HTMLElementClasses = {
5
- [key: string]: {new(...args: any[]): HTMLElement}
6
- }
7
-
8
- export type RegistrationOptions = {
9
- soft: boolean
10
- upgrade: boolean
11
- }
3
+ import {HTMLElementClasses, RegisterOptions} from "../types.js"
12
4
 
13
5
  /**
14
6
  * register custom elements (web components) to the dom
@@ -24,7 +16,7 @@ export type RegistrationOptions = {
24
16
  */
25
17
  export function register<E extends HTMLElementClasses>(
26
18
  elements: E,
27
- options: Partial<RegistrationOptions> = {},
19
+ options: Partial<RegisterOptions> = {},
28
20
  ) {
29
21
 
30
22
  const {
package/s/dom/types.ts ADDED
@@ -0,0 +1,45 @@
1
+
2
+ import {attrs} from "./attrs/attrs.js"
3
+
4
+ // attrs
5
+
6
+ export type AttrKind = (
7
+ | typeof String
8
+ | typeof Number
9
+ | typeof Boolean
10
+ )
11
+
12
+ export type AttrType<H extends AttrKind> = (
13
+ H extends typeof String
14
+ ? string | undefined
15
+
16
+ : H extends typeof Number
17
+ ? number | undefined
18
+
19
+ : H extends typeof Boolean
20
+ ? boolean
21
+
22
+ : never
23
+ )
24
+
25
+ export type AttrSpec = {
26
+ [key: string]: AttrKind
27
+ }
28
+
29
+ export type AttrTypes<A extends AttrSpec> = {
30
+ [P in keyof A]: AttrType<A[P]>
31
+ }
32
+
33
+ export type Attrs = ReturnType<typeof attrs>
34
+
35
+ // register
36
+
37
+ export type HTMLElementClasses = {
38
+ [key: string]: {new(...args: any[]): HTMLElement}
39
+ }
40
+
41
+ export type RegisterOptions = {
42
+ soft: boolean
43
+ upgrade: boolean
44
+ }
45
+
package/s/index.html.ts CHANGED
@@ -30,7 +30,8 @@ export default ssg.page(import.meta.url, async orb => ({
30
30
  <p><a href="https://github.com/e280/sly">github.com/e280/sly</a></p>
31
31
  <p class=lil>v${orb.packageVersion()}</p>
32
32
  <incredi-element></incredi-element>
33
- <demo-counter>component</demo-counter>
33
+ <divine-element></divine-element>
34
+ <demo-counter initial="-1">component</demo-counter>
34
35
  <div class=demo></div>
35
36
  `,
36
37
  }))
package/s/index.ts CHANGED
@@ -1,8 +1,6 @@
1
1
 
2
- export * from "./dom/attributes.js"
3
- export * from "./dom/dashify.js"
2
+ export * from "./dom/types.js"
4
3
  export * from "./dom/dom.js"
5
- export * from "./dom/register.js"
6
4
 
7
5
  export * from "./ops/loaders/make-loader.js"
8
6
  export * from "./ops/loaders/parts/ascii-anim.js"
@@ -13,7 +11,6 @@ export * from "./ops/types.js"
13
11
 
14
12
  export * as loot from "./loot/index.js"
15
13
 
16
- export * from "./dom/attributes.js"
17
14
  export * from "./views/base-element.js"
18
15
  export * from "./views/css-reset.js"
19
16
  export * from "./views/types.js"