@e280/sly 0.0.0-1 → 0.0.0-3

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 (90) hide show
  1. package/README.md +181 -3
  2. package/package.json +3 -5
  3. package/s/demo/demo.bundle.ts +49 -0
  4. package/s/demo/demo.css +6 -0
  5. package/s/features/dom/dashify.ts +11 -0
  6. package/s/features/dom/dollar.ts +21 -0
  7. package/s/features/dom/register.ts +48 -0
  8. package/s/features/dom/types.ts +5 -0
  9. package/s/features/loady/ascii-loader.ts +38 -0
  10. package/s/features/loady/parts/ascii-anim.ts +27 -0
  11. package/s/features/loady/parts/ascii-loader.ts +14 -0
  12. package/s/features/loady/parts/error-display.ts +26 -0
  13. package/s/features/op/op.ts +98 -0
  14. package/s/features/op/pod.ts +19 -0
  15. package/s/features/op/types.ts +12 -0
  16. package/s/features/views/css-reset.ts +21 -0
  17. package/s/features/views/types.ts +23 -0
  18. package/s/features/views/use.ts +75 -0
  19. package/s/features/views/utils/apply-attrs.ts +33 -0
  20. package/s/features/views/utils/apply-styles.ts +21 -0
  21. package/s/features/views/utils/mounts.ts +22 -0
  22. package/s/features/views/view.ts +98 -0
  23. package/s/index.html.ts +5 -4
  24. package/s/index.ts +18 -0
  25. package/x/demo/demo.bundle.d.ts +1 -0
  26. package/x/demo/demo.bundle.js +37 -1
  27. package/x/demo/demo.bundle.js.map +1 -1
  28. package/x/demo/demo.bundle.min.js +72 -1
  29. package/x/demo/demo.bundle.min.js.map +4 -4
  30. package/x/demo/demo.css +6 -0
  31. package/x/features/dom/dashify.d.ts +7 -0
  32. package/x/features/dom/dashify.js +10 -0
  33. package/x/features/dom/dashify.js.map +1 -0
  34. package/x/features/dom/dollar.d.ts +8 -0
  35. package/x/features/dom/dollar.js +15 -0
  36. package/x/features/dom/dollar.js.map +1 -0
  37. package/x/features/dom/register.d.ts +18 -0
  38. package/x/features/dom/register.js +29 -0
  39. package/x/features/dom/register.js.map +1 -0
  40. package/x/features/dom/types.d.ts +5 -0
  41. package/x/features/dom/types.js +2 -0
  42. package/x/features/dom/types.js.map +1 -0
  43. package/x/features/loady/ascii-loader.d.ts +5 -0
  44. package/x/features/loady/ascii-loader.js +33 -0
  45. package/x/features/loady/ascii-loader.js.map +1 -0
  46. package/x/features/loady/parts/ascii-anim.d.ts +8 -0
  47. package/x/features/loady/parts/ascii-anim.js +21 -0
  48. package/x/features/loady/parts/ascii-anim.js.map +1 -0
  49. package/x/features/loady/parts/ascii-loader.d.ts +3 -0
  50. package/x/features/loady/parts/ascii-loader.js +10 -0
  51. package/x/features/loady/parts/ascii-loader.js.map +1 -0
  52. package/x/features/loady/parts/error-display.d.ts +8 -0
  53. package/x/features/loady/parts/error-display.js +20 -0
  54. package/x/features/loady/parts/error-display.js.map +1 -0
  55. package/x/features/op/op.d.ts +21 -0
  56. package/x/features/op/op.js +79 -0
  57. package/x/features/op/op.js.map +1 -0
  58. package/x/features/op/pod.d.ts +5 -0
  59. package/x/features/op/pod.js +16 -0
  60. package/x/features/op/pod.js.map +1 -0
  61. package/x/features/op/types.d.ts +9 -0
  62. package/x/features/op/types.js +2 -0
  63. package/x/features/op/types.js.map +1 -0
  64. package/x/features/views/css-reset.d.ts +2 -0
  65. package/x/features/views/css-reset.js +19 -0
  66. package/x/features/views/css-reset.js.map +1 -0
  67. package/x/features/views/types.d.ts +16 -0
  68. package/x/features/views/types.js +2 -0
  69. package/x/features/views/types.js.map +1 -0
  70. package/x/features/views/use.d.ts +25 -0
  71. package/x/features/views/use.js +62 -0
  72. package/x/features/views/use.js.map +1 -0
  73. package/x/features/views/utils/apply-attrs.d.ts +2 -0
  74. package/x/features/views/utils/apply-attrs.js +21 -0
  75. package/x/features/views/utils/apply-attrs.js.map +1 -0
  76. package/x/features/views/utils/apply-styles.d.ts +2 -0
  77. package/x/features/views/utils/apply-styles.js +16 -0
  78. package/x/features/views/utils/apply-styles.js.map +1 -0
  79. package/x/features/views/utils/mounts.d.ts +6 -0
  80. package/x/features/views/utils/mounts.js +18 -0
  81. package/x/features/views/utils/mounts.js.map +1 -0
  82. package/x/features/views/view.d.ts +16 -0
  83. package/x/features/views/view.js +81 -0
  84. package/x/features/views/view.js.map +1 -0
  85. package/x/index.d.ts +13 -0
  86. package/x/index.html +13 -6
  87. package/x/index.html.js +5 -4
  88. package/x/index.html.js.map +1 -1
  89. package/x/index.js +13 -1
  90. package/x/index.js.map +1 -1
package/README.md CHANGED
@@ -1,7 +1,185 @@
1
1
 
2
- <div align="center"><img alt="" width="512" src="./assets/favicon.png"/></div>
2
+ <div align="center"><img alt="" width="256" src="./assets/favicon.png"/></div>
3
3
 
4
- # 🦝 sly
4
+ # 🦝 sly — mischievious frontend web framework
5
+ - 🪒 lean view framework for [lit](https://lit.dev/)
6
+ - 🌅 sly is the successor to [@benev/slate](https://github.com/benevolent-games/slate)
7
+ - 🏂 commonly used with stz standard library [@e280/stz](https://github.com/e280/stz)
8
+ - ⛏️ integrates signals and state trees from [@e280/strata](https://github.com/e280/strata)
9
+ - 🐢 if you need a buildy-bundler-buddy, try [scute](https://github.com/e280/scute)
10
+ - 🧑‍💻 project by [@e280](https://e280.org/)
5
11
 
6
- > *wip — lit html shadow view library — will replace [`@benev/slate`](https://github.com/benevolent-games/slate)*
12
+ <br/>
13
+
14
+ ## 🦝 INSTALL SLY AND PEERS
15
+ they all super work together.
16
+
17
+ ```sh
18
+ npm install @e280/sly @e280/stz @e280/strata lit
19
+ ```
20
+
21
+ <br/>
22
+
23
+ ## 🦝 VIEWS ARE LEAN
24
+ views are the crown jewel of sly. shadow-dom'd. hooks-based. fancy ergonomics. not components.
25
+
26
+ views are leaner than web components.. no dom registration, string tag names.. just import 'em, and the types work.. web components are fine, but they're for providing html authors with entrypoints to your cool widgets.. whereas views are the building blocks for frontend app devs.
27
+
28
+ sly views are wired to automatically rerender whenever they're using any state stuff from [@e280/strata](https://github.com/e280/strata).
29
+
30
+ ### 🍋 basic view example
31
+ > views are hooks-based functional components. they are *not* web components nor *custom elements*, yet they are encapsulated within a [shadow root](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM).
32
+
33
+ #### declaring a view
34
+ ```ts
35
+ import {view} from "@e280/sly"
36
+ import {html, css} from "lit"
37
+
38
+ export const CounterView = view(use => (start: number) => {
39
+ use.name("counter")
40
+ use.styles(css`p {color: green}`)
41
+ const count = use.signal(start)
42
+
43
+ return html`
44
+ <p>count ${count()}</p>
45
+ <button @click="${() => { count.value++ }}"></button>
46
+ `
47
+ })
48
+ ```
49
+ - each view renders into a `<sly-view>` host, with the provided `name` set as its view attribute, eg `<sly-view view="counter">`
50
+
51
+ #### injecting a view into the dom
52
+ ```ts
53
+ import {render, html} from "lit"
54
+ import {CounterView} from "./my-counter.js"
55
+
56
+ const content = html`
57
+ <h1>my demo page</h1>
58
+ ${CounterView(1)}
59
+ `
60
+
61
+ render(content, document.body)
62
+ ```
63
+
64
+ ### 🍋 view `use`
65
+ > super special view helper, with hooks and other goodies
66
+
67
+ - **use.signal** — create a [strata signal](https://github.com/e280/strata)
68
+ ```ts
69
+ const count = use.signal(1)
70
+
71
+ // read the signal
72
+ count() //-> 1
73
+
74
+ // write the signal
75
+ count(2)
76
+ ```
77
+ - **use.once** — run fn at initialization
78
+ ```ts
79
+ const whatever = use.once(() => {
80
+ console.log("happens only once")
81
+ return 123
82
+ })
83
+
84
+ whatever //-> 123
85
+ ```
86
+ - **use.mount** — setup mount/unmount lifecycle
87
+ ```ts
88
+ use.mount(() => {
89
+ console.log("view mounted")
90
+
91
+ return () => {
92
+ console.log("view unmounted")
93
+ }
94
+ })
95
+ ```
96
+ - **use.name** — set the "view" attr value, eg `<sly-view view="squarepants">`
97
+ ```ts
98
+ use.name("squarepants")
99
+ ```
100
+ - **use.styles** — attach stylesheets into the view's shadow dom
101
+ ```ts
102
+ use.styles(css1, css2, css3)
103
+ ```
104
+ - **use.rendered** — promise that resolves *after* view has rendered
105
+ ```ts
106
+ use.rendered.then(() => {
107
+ const slot = use.shadow.querySelector("slot")!
108
+ console.log(slot)
109
+ })
110
+ ```
111
+
112
+ ### 🍋 neat tricks to impress the ladies
113
+ > common patterns and snippets
114
+
115
+ - make a ticker — mount, repeat, and nap
116
+ ```ts
117
+ import {repeat, nap} from "@e280/stz"
118
+ ```
119
+ ```ts
120
+ const seconds = use.signal(0)
121
+
122
+ use.mount(() => repeat(async() => {
123
+ await nap(1000)
124
+ seconds.value++
125
+ }))
126
+ ```
127
+ - once+rendered to do an action after the first render
128
+ ```ts
129
+ use.once(() => use.rendered.then(() => {
130
+ console.log("after first render")
131
+ }))
132
+ ```
133
+
134
+ ### 🍋 view declaration settings
135
+ > special settings for views at declaration-time
136
+
137
+ ```ts
138
+ import {view} from "@e280/sly"
139
+ import {html} from "lit"
140
+
141
+ export const CoolView = view
142
+ .settings({mode: "open", delegatesFocus: true})
143
+ .view(use => (greeting: string) => {
144
+
145
+ return html`😎 ${greeting} <slot></slot>`
146
+ })
147
+ ```
148
+ - these `settings` like `mode` and `delegatesFocus` are [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters)
149
+ - note the `<slot></slot>` we'll use in the next example lol
150
+
151
+ ### 🍋 view injection options
152
+ > options for views at the template injection site
153
+
154
+ ```ts
155
+ import {render, html} from "lit"
156
+ import {CoolView} from "./cool-view.js"
157
+
158
+ const content = html`
159
+ <h2>super cool example</h2>
160
+ ${CoolView
161
+ .attr("class", "hero")
162
+ .children(html`<em>spongebob</em>`)
163
+ .props("hello")}
164
+ `
165
+
166
+ render(content, document.body)
167
+ ```
168
+ - `attr` — set html attributes on the `<sly-view>` host element
169
+ - `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)
170
+ - `props` — finally inject the view by providing its props
171
+
172
+ <br/>
173
+
174
+ ## 🦝 OPS LOADING INDICATORS
175
+ > ***TODO*** *implemented but not yet documented, lol*
176
+ - `Pod` is a type for (loading/ready/error states)
177
+ - `Op` class wraps a pod signal and has some ergonomic fns
178
+ - `loady` has various loading indicators for dealing with ops
179
+
180
+ <br/>
181
+
182
+ ## 🧑‍💻 PROJECT BY e280
183
+ reward us with github stars
184
+ build with us at https://e280.org/ but only if you're cool
7
185
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e280/sly",
3
- "version": "0.0.0-1",
3
+ "version": "0.0.0-3",
4
4
  "description": "web shadow views",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -13,10 +13,8 @@
13
13
  "s"
14
14
  ],
15
15
  "peerDependencies": {
16
- "@e280/strata": "^0.0.0-9"
17
- },
18
- "dependencies": {
19
- "@e280/stz": "^0.0.0-34",
16
+ "@e280/stz": "^0.0.0-35",
17
+ "@e280/strata": "^0.0.0-10",
20
18
  "lit": "^3.3.1"
21
19
  },
22
20
  "devDependencies": {
@@ -1,3 +1,52 @@
1
1
 
2
+ import {nap, repeat} from "@e280/stz"
3
+ import {css, html, render} from "lit"
4
+
5
+ import {$} from "../features/dom/dollar.js"
6
+ import {view} from "../features/views/view.js"
7
+ import {cssReset} from "../features/views/css-reset.js"
8
+ import {loady} from "../features/loady/ascii-loader.js"
9
+
2
10
  console.log("🦝 sly")
3
11
 
12
+ const styles = css`
13
+ :host {
14
+ display: flex;
15
+ flex-direction: column;
16
+ justify-content: center;
17
+ text-align: center;
18
+ }
19
+ `
20
+
21
+ const MyView = view(use => (greeting: string) => {
22
+ use.name("my-view")
23
+ use.styles(cssReset, styles)
24
+ const count = use.signal(0)
25
+
26
+ use.mount(() => repeat(async() => {
27
+ await nap(1000)
28
+ count.value++
29
+ }))
30
+
31
+ use.once(() => use.rendered.then(() => {
32
+ console.log("slot", $("slot", use.shadow))
33
+ }))
34
+
35
+ const op = use.op.fn(async() => {
36
+ await nap(5000)
37
+ })
38
+
39
+ return html`
40
+ <p>${greeting} <slot></slot> ${count()}</p>
41
+ <p>${loady.dots(op, () => "op loaded")}</p>
42
+ `
43
+ })
44
+
45
+ render(
46
+ MyView
47
+ .attr("class", "incredi")
48
+ .children("world")
49
+ .props("hello"),
50
+ $(".demo"),
51
+ )
52
+
package/s/demo/demo.css CHANGED
@@ -79,11 +79,17 @@
79
79
  display: block;
80
80
  width: 100%;
81
81
  max-width: 24em;
82
+ max-height: 30vh;
83
+ object-fit: contain;
82
84
  }
83
85
 
84
86
  .lil {
85
87
  opacity: 0.6;
86
88
  font-size: 0.8em;
87
89
  }
90
+
91
+ :not(:defined) {
92
+ display: none;
93
+ }
88
94
  }
89
95
 
@@ -0,0 +1,11 @@
1
+
2
+ /**
3
+ * Convert a camel-case name into a dashed name
4
+ * - for example
5
+ * dashify("BigManStyle")
6
+ * // "big-man-style"
7
+ */
8
+ export function dashify(camel: string) {
9
+ return camel.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase()
10
+ }
11
+
@@ -0,0 +1,21 @@
1
+
2
+ export const $ = one
3
+
4
+ export type Queryable = HTMLElement | Document | ShadowRoot | Element
5
+
6
+ function all<E extends HTMLElement = HTMLElement>(selector: string, context: Queryable = document) {
7
+ return Array.from(context.querySelectorAll<E>(selector))
8
+ }
9
+
10
+ function one<E extends HTMLElement = HTMLElement>(selector: string, context: Queryable = document) {
11
+ const e = context.querySelector<E>(selector)
12
+ if (!e) throw new Error(`$1 ${selector} not found`)
13
+ return e
14
+ }
15
+
16
+ one.maybe = <E extends HTMLElement = HTMLElement>(selector: string, context: Queryable = document) => {
17
+ return context.querySelector<E>(selector)
18
+ }
19
+
20
+ one.all = all
21
+
@@ -0,0 +1,48 @@
1
+
2
+ import {dashify} from "./dashify.js"
3
+ import {HTMLElementClasses} from "./types.js"
4
+
5
+ export type RegistrationOptions = {
6
+ soft: boolean
7
+ upgrade: boolean
8
+ }
9
+
10
+ /**
11
+ * register custom elements (web components) to the dom
12
+ * - takes an object full of custom html elements, and automatically dashes the names
13
+ * - eg, `MyCoolElement` is registered as `<my-cool-element></my-cool-element>`
14
+ * - calls `customElements.define`
15
+ * - option `soft`
16
+ * - `false` (default) will throw errors if elements are already defined
17
+ * - `true` will do nothing if an element is already defined
18
+ * - option `upgrade`
19
+ * - `true` (default) will run `customElements.upgrade` where appropriate
20
+ * - `false` will NOT upgrade any existing elements on the page
21
+ */
22
+ export function register<E extends HTMLElementClasses>(
23
+ elements: E,
24
+ options: Partial<RegistrationOptions> = {},
25
+ ) {
26
+
27
+ const {
28
+ soft = false,
29
+ upgrade = true,
30
+ } = options
31
+
32
+ for (const [name, Element] of Object.entries(elements)) {
33
+ const tag = dashify(name)
34
+ const already = customElements.get(tag)
35
+
36
+ if (soft && already)
37
+ continue
38
+
39
+ customElements.define(tag, Element)
40
+
41
+ if (upgrade)
42
+ document.querySelectorAll(tag).forEach(element => {
43
+ if (element.constructor === HTMLElement)
44
+ customElements.upgrade(element)
45
+ })
46
+ }
47
+ }
48
+
@@ -0,0 +1,5 @@
1
+
2
+ export type HTMLElementClasses = {
3
+ [key: string]: {new(...args: any[]): HTMLElement}
4
+ }
5
+
@@ -0,0 +1,38 @@
1
+
2
+ import {makeAsciiLoader} from "./parts/ascii-loader.js";
3
+
4
+ const hz = 15
5
+
6
+ export const loady = {
7
+ cylon: makeAsciiLoader(hz, [
8
+ "=----",
9
+ "-=---",
10
+ "--=--",
11
+ "---=-",
12
+ "----=",
13
+ "-----",
14
+ "-----",
15
+ ]),
16
+
17
+ dots: makeAsciiLoader(hz, [
18
+ ":....",
19
+ "::...",
20
+ ".::..",
21
+ "..::.",
22
+ "...::",
23
+ "....:",
24
+ ".....",
25
+ ".....",
26
+ ]),
27
+
28
+ binary: makeAsciiLoader(hz, [
29
+ "01111",
30
+ "10111",
31
+ "11011",
32
+ "11101",
33
+ "11110",
34
+ "11111",
35
+ "11111",
36
+ ]),
37
+ }
38
+
@@ -0,0 +1,27 @@
1
+
2
+ import {css} from "lit"
3
+ import {nap, repeat} from "@e280/stz"
4
+
5
+ import {view} from "../../views/view.js"
6
+ import {cssReset} from "../../views/css-reset.js"
7
+
8
+ const style = css`
9
+ :host {
10
+ font-family: monospace;
11
+ }
12
+ `
13
+
14
+ export const AsciiAnim = view(use => (hz: number, anim: string[]) => {
15
+ use.name("loading")
16
+ use.styles(cssReset, style)
17
+ const frame = use.signal(0)
18
+
19
+ use.mount(() => repeat(async() => {
20
+ await nap(1000 / hz)
21
+ const next = frame() + 1
22
+ frame(next >= anim.length ? 0 : next)
23
+ }))
24
+
25
+ return anim.at(frame())
26
+ })
27
+
@@ -0,0 +1,14 @@
1
+
2
+ import {Op} from "../../op/op.js"
3
+ import {AsciiAnim} from "./ascii-anim.js"
4
+ import {Content} from "../../views/types.js"
5
+ import {ErrorDisplay} from "./error-display.js"
6
+
7
+ export function makeAsciiLoader(hz: number, anim: string[]) {
8
+ return <V>(op: Op<V>, fn: (value: V) => Content) => op.select({
9
+ loading: () => AsciiAnim(hz, anim),
10
+ error: error => ErrorDisplay(error),
11
+ ready: fn,
12
+ })
13
+ }
14
+
@@ -0,0 +1,26 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {view} from "../../views/view.js"
4
+ import {cssReset} from "../../views/css-reset.js"
5
+
6
+ const style = css`
7
+ :host {
8
+ font-family: monospace;
9
+ color: red;
10
+ }
11
+ `
12
+
13
+ export const ErrorDisplay = view(use => (error: any) => {
14
+ use.name("loading")
15
+ use.styles(cssReset, style)
16
+
17
+ if (typeof error === "string")
18
+ return error
19
+
20
+ else if (error instanceof Error)
21
+ return html`<strong>${error.name}:</strong> <span>${error.message}</span>`
22
+
23
+ else
24
+ return `error`
25
+ })
26
+
@@ -0,0 +1,98 @@
1
+
2
+ import {pub} from "@e280/stz"
3
+ import {signal} from "@e280/strata/signals"
4
+
5
+ import {pod} from "./pod.js"
6
+ import {Pod, PodSelect} from "./types.js"
7
+
8
+ export class Op<V> {
9
+ static loading() {
10
+ return new this()
11
+ }
12
+
13
+ static ready<V>(value: V) {
14
+ const op = new this<V>()
15
+ op.signal(["ready", value])
16
+ return op
17
+ }
18
+
19
+ static error(error: any) {
20
+ const op = new this()
21
+ op.signal(["error", error])
22
+ return op
23
+ }
24
+
25
+ static promise<V>(promise: Promise<V>) {
26
+ const op = new this<V>()
27
+ op.promise(promise)
28
+ return op
29
+ }
30
+
31
+ static fn<V>(fn: () => Promise<V>) {
32
+ return this.promise(fn())
33
+ }
34
+
35
+ readonly signal = signal<Pod<V>>(["loading"])
36
+ #resolve = pub<[V]>()
37
+ #reject = pub<[any]>()
38
+
39
+ get wait() {
40
+ return new Promise((resolve, reject) => {
41
+ this.#resolve.next().then(resolve)
42
+ this.#reject.next().then(reject)
43
+ })
44
+ }
45
+
46
+ async setLoading() {
47
+ await this.signal(["loading"])
48
+ }
49
+
50
+ async setReady(value: V) {
51
+ await this.signal(["ready", value])
52
+ await this.#resolve(value)
53
+ }
54
+
55
+ async setError(error: any) {
56
+ await this.signal(["error", error])
57
+ await this.#reject(error)
58
+ }
59
+
60
+ async promise(promise: Promise<V>) {
61
+ await this.setLoading()
62
+ try {
63
+ const value = await promise
64
+ await this.setReady(value)
65
+ return value
66
+ }
67
+ catch (error) {
68
+ await this.setError(error)
69
+ }
70
+ }
71
+
72
+ async fn(fn: () => Promise<V>) {
73
+ return this.promise(fn())
74
+ }
75
+
76
+ get pod() {
77
+ return this.signal()
78
+ }
79
+
80
+ get status() {
81
+ return this.signal()[0]
82
+ }
83
+
84
+ get value() {
85
+ return pod.value(this.signal())
86
+ }
87
+
88
+ require() {
89
+ const pod = this.signal()
90
+ if (pod[0] !== "ready") throw new Error("required value not ready")
91
+ return pod[1]
92
+ }
93
+
94
+ select<R>(select: PodSelect<V, R>) {
95
+ return pod.select(this.signal(), select)
96
+ }
97
+ }
98
+
@@ -0,0 +1,19 @@
1
+
2
+ import {Pod, PodSelect} from "./types.js"
3
+
4
+ export const pod = {
5
+ value: <V>(pod: Pod<V>) => {
6
+ return pod[0] === "ready"
7
+ ? pod[1]
8
+ : undefined
9
+ },
10
+ select: <V, R>(pod: Pod<V>, select: PodSelect<V, R>) => {
11
+ switch (pod[0]) {
12
+ case "loading": return select.loading()
13
+ case "error": return select.error(pod[1])
14
+ case "ready": return select.ready(pod[1])
15
+ default: throw new Error("unknown op status")
16
+ }
17
+ },
18
+ }
19
+
@@ -0,0 +1,12 @@
1
+
2
+ export type PodLoading = [status: "loading"]
3
+ export type PodReady<V> = [status: "ready", value: V]
4
+ export type PodError = [status: "error", error: any]
5
+ export type Pod<V> = PodLoading | PodReady<V> | PodError
6
+
7
+ export type PodSelect<V, R> = {
8
+ loading: () => R
9
+ ready: (value: V) => R
10
+ error: (error: any) => R
11
+ }
12
+
@@ -0,0 +1,21 @@
1
+
2
+ import {css, CSSResultGroup} from "lit"
3
+
4
+ export const cssReset: CSSResultGroup = css`
5
+ @layer reset {
6
+ * {
7
+ margin: 0;
8
+ padding: 0;
9
+ box-sizing: border-box;
10
+
11
+ scrollbar-width: thin;
12
+ scrollbar-color: #888 transparent;
13
+ }
14
+
15
+ ::-webkit-scrollbar { width: 8px; }
16
+ ::-webkit-scrollbar-track { background: transparent; }
17
+ ::-webkit-scrollbar-thumb { background: #333; border-radius: 1em; }
18
+ ::-webkit-scrollbar-thumb:hover { background: #444; }
19
+ }
20
+ `
21
+
@@ -0,0 +1,23 @@
1
+
2
+ import {DirectiveResult} from "lit/directive.js"
3
+ import {CSSResultGroup, TemplateResult} from "lit"
4
+
5
+ import {Use} from "./use.js"
6
+
7
+ export type Content = TemplateResult | DirectiveResult | HTMLElement | string | null | undefined | void
8
+ export type AttrValue = string | boolean | number | undefined | null | void
9
+
10
+ export type ViewFn<Props extends any[]> = (use: Use) => (...props: Props) => Content
11
+ export type View<Props extends any[]> = (...props: Props) => DirectiveResult<any>
12
+
13
+ export type ViewSettings = ShadowRootInit & {
14
+ tag?: string
15
+ name?: string
16
+ styles?: CSSResultGroup
17
+ }
18
+
19
+ export type ViewWith = {
20
+ children: Content
21
+ attrs: Record<string, AttrValue>
22
+ }
23
+