@e280/sly 0.0.0-4 → 0.0.0-6

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 (78) hide show
  1. package/README.md +99 -88
  2. package/package.json +2 -2
  3. package/s/demo/demo.bundle.ts +3 -47
  4. package/s/demo/demo.css +16 -6
  5. package/s/demo/views/counter.ts +42 -0
  6. package/s/demo/views/demo.ts +25 -0
  7. package/s/demo/views/loaders.ts +71 -0
  8. package/s/features/op/loaders/make-loader.ts +18 -0
  9. package/s/features/op/loaders/parts/anims.ts +413 -0
  10. package/s/features/op/loaders/parts/ascii-anim.ts +38 -0
  11. package/s/features/{loady → op/loaders}/parts/error-display.ts +10 -10
  12. package/s/features/op/op.ts +42 -20
  13. package/s/features/op/podium.ts +67 -0
  14. package/s/features/views/use.ts +6 -5
  15. package/s/features/views/view.ts +12 -5
  16. package/s/index.html.ts +2 -2
  17. package/s/index.ts +4 -3
  18. package/x/demo/demo.bundle.js +2 -36
  19. package/x/demo/demo.bundle.js.map +1 -1
  20. package/x/demo/demo.bundle.min.js +72 -10
  21. package/x/demo/demo.bundle.min.js.map +4 -4
  22. package/x/demo/demo.css +16 -6
  23. package/x/demo/views/counter.d.ts +1 -0
  24. package/x/demo/views/counter.js +34 -0
  25. package/x/demo/views/counter.js.map +1 -0
  26. package/x/demo/views/demo.d.ts +1 -0
  27. package/x/demo/views/demo.js +21 -0
  28. package/x/demo/views/demo.js.map +1 -0
  29. package/x/demo/views/loaders.d.ts +1 -0
  30. package/x/demo/views/loaders.js +63 -0
  31. package/x/demo/views/loaders.js.map +1 -0
  32. package/x/features/op/loaders/make-loader.d.ts +5 -0
  33. package/x/features/op/loaders/make-loader.js +7 -0
  34. package/x/features/op/loaders/make-loader.js.map +1 -0
  35. package/x/features/op/loaders/parts/anims.d.ts +34 -0
  36. package/x/features/op/loaders/parts/anims.js +377 -0
  37. package/x/features/op/loaders/parts/anims.js.map +1 -0
  38. package/x/features/op/loaders/parts/ascii-anim.d.ts +6 -0
  39. package/x/features/op/loaders/parts/ascii-anim.js +26 -0
  40. package/x/features/op/loaders/parts/ascii-anim.js.map +1 -0
  41. package/x/features/op/loaders/parts/error-display.d.ts +1 -0
  42. package/x/features/{loady → op/loaders}/parts/error-display.js +9 -9
  43. package/x/features/op/loaders/parts/error-display.js.map +1 -0
  44. package/x/features/op/op.d.ts +12 -3
  45. package/x/features/op/op.js +33 -17
  46. package/x/features/op/op.js.map +1 -1
  47. package/x/features/op/podium.d.ts +9 -0
  48. package/x/features/op/podium.js +53 -0
  49. package/x/features/op/podium.js.map +1 -0
  50. package/x/features/views/use.d.ts +4 -3
  51. package/x/features/views/use.js +7 -5
  52. package/x/features/views/use.js.map +1 -1
  53. package/x/features/views/view.js +11 -5
  54. package/x/features/views/view.js.map +1 -1
  55. package/x/index.d.ts +4 -3
  56. package/x/index.html +20 -10
  57. package/x/index.html.js +2 -2
  58. package/x/index.html.js.map +1 -1
  59. package/x/index.js +4 -3
  60. package/x/index.js.map +1 -1
  61. package/s/features/loady/ascii-loader.ts +0 -38
  62. package/s/features/loady/parts/ascii-anim.ts +0 -27
  63. package/s/features/loady/parts/ascii-loader.ts +0 -14
  64. package/s/features/op/pod.ts +0 -19
  65. package/x/features/loady/ascii-loader.d.ts +0 -5
  66. package/x/features/loady/ascii-loader.js +0 -33
  67. package/x/features/loady/ascii-loader.js.map +0 -1
  68. package/x/features/loady/parts/ascii-anim.d.ts +0 -1
  69. package/x/features/loady/parts/ascii-anim.js +0 -21
  70. package/x/features/loady/parts/ascii-anim.js.map +0 -1
  71. package/x/features/loady/parts/ascii-loader.d.ts +0 -3
  72. package/x/features/loady/parts/ascii-loader.js +0 -10
  73. package/x/features/loady/parts/ascii-loader.js.map +0 -1
  74. package/x/features/loady/parts/error-display.d.ts +0 -1
  75. package/x/features/loady/parts/error-display.js.map +0 -1
  76. package/x/features/op/pod.d.ts +0 -5
  77. package/x/features/op/pod.js +0 -16
  78. package/x/features/op/pod.js.map +0 -1
package/README.md CHANGED
@@ -2,7 +2,9 @@
2
2
  <div align="center"><img alt="" width="256" src="./assets/favicon.png"/></div>
3
3
 
4
4
  # 🦝 sly — mischievous shadow views
5
- - 🪒 lean [lit](https://lit.dev/) view framework for web devs
5
+ > testing page at https://sly.e280.org/
6
+
7
+ - 🪒 lean view framework for [lit](https://lit.dev/) web devs
6
8
  - 🌅 sly is the successor to [@benev/slate](https://github.com/benevolent-games/slate)
7
9
  - 🏂 commonly used with stz standard library [@e280/stz](https://github.com/e280/stz)
8
10
  - ⛏️ integrates signals and state trees from [@e280/strata](https://github.com/e280/strata)
@@ -11,8 +13,7 @@
11
13
 
12
14
  <br/>
13
15
 
14
- ## 🦝 INSTALL SLY AND PEERS
15
- they all super work together.
16
+ ## 🦝 INSTALL SLY AND PALS
16
17
 
17
18
  ```sh
18
19
  npm install @e280/sly @e280/stz @e280/strata lit
@@ -20,50 +21,90 @@ npm install @e280/sly @e280/stz @e280/strata lit
20
21
 
21
22
  <br/>
22
23
 
23
- ## 🦝 VIEWS ARE LEAN
24
+ ## 🦝 SLY VIEWS
24
25
  views are the crown jewel of sly. shadow-dom'd. hooks-based. fancy ergonomics. not components.
25
26
 
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
+ views are leaner than web components.. no dom registration, no 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
 
28
29
  sly views are wired to automatically rerender whenever they're using any state stuff from [@e280/strata](https://github.com/e280/strata).
29
30
 
30
31
  ### 🍋 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">`
32
+ - views are hooks-based functional components with a [shadow root](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM)
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
+ - **injecting a view into the dom**
51
+ ```ts
52
+ import {render, html} from "lit"
53
+ import {CounterView} from "./my-counter.js"
50
54
 
51
- #### injecting a view into the dom
52
- ```ts
53
- import {render, html} from "lit"
54
- import {CounterView} from "./my-counter.js"
55
+ const content = html`
56
+ <h1>my demo page</h1>
57
+ ${CounterView(1)}
58
+ `
55
59
 
56
- const content = html`
57
- <h1>my demo page</h1>
58
- ${CounterView(1)}
59
- `
60
+ render(content, document.querySelector(".app")!)
61
+ ```
60
62
 
61
- render(content, document.querySelector(".app")!)
62
- ```
63
+ ### 🍋 view declaration settings
64
+ - special settings for views at declaration-time
65
+ ```ts
66
+ import {view} from "@e280/sly"
67
+ import {html} from "lit"
63
68
 
64
- ### 🍋 view `use`
65
- > super special view helper, with hooks and other goodies
69
+ export const CoolView = view
70
+ .settings({mode: "open", delegatesFocus: true})
71
+ .view(use => (greeting: string) => {
72
+
73
+ return html`😎 ${greeting} <slot></slot>`
74
+ })
75
+ ```
76
+ - these `settings` like `mode` and `delegatesFocus` are [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters)
77
+ - note the `<slot></slot>` we'll use in the next example lol
66
78
 
79
+ ### 🍋 view injection options
80
+ - options for views at the template injection site
81
+ ```ts
82
+ import {render, html} from "lit"
83
+ import {CoolView} from "./cool-view.js"
84
+
85
+ const content = html`
86
+ <h2>super cool example</h2>
87
+ ${CoolView
88
+ .attr("class", "hero")
89
+ .children(html`<em>spongebob</em>`)
90
+ .props("hello")}
91
+ `
92
+
93
+ render(content, document.querySelector(".app")!)
94
+ ```
95
+ - `attr` — set html attributes on the `<sly-view>` host element
96
+ - `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)
97
+ - `props` — finally inject the view by providing its props
98
+
99
+ ### 🍋 view `use` reference
100
+ - **use.name** — set the "view" attr value, eg `<sly-view view="squarepants">`
101
+ ```ts
102
+ use.name("squarepants")
103
+ ```
104
+ - **use.styles** — attach stylesheets into the view's shadow dom
105
+ ```ts
106
+ use.styles(css1, css2, css3)
107
+ ```
67
108
  - **use.signal** — create a [strata signal](https://github.com/e280/strata)
68
109
  ```ts
69
110
  const count = use.signal(1)
@@ -103,25 +144,30 @@ render(content, document.querySelector(".app")!)
103
144
 
104
145
  v //-> 123
105
146
  ```
106
- - **use.name** — set the "view" attr value, eg `<sly-view view="squarepants">`
147
+ - **use.render** — force a hard render (not debounced)
107
148
  ```ts
108
- use.name("squarepants")
149
+ use.render()
109
150
  ```
110
- - **use.styles** — attach stylesheets into the view's shadow dom
111
- ```ts
112
- use.styles(css1, css2, css3)
113
- ```
114
- - **use.rendered** — promise that resolves *after* view has rendered
151
+ - **use.rendered** — promise that resolves *after* the next render
115
152
  ```ts
116
153
  use.rendered.then(() => {
117
154
  const slot = use.shadow.querySelector("slot")!
118
155
  console.log(slot)
119
156
  })
120
157
  ```
158
+ - **use.op.fn** — start with an op based on an async fn
159
+ ```ts
160
+ const op = use.op.fn(async() => {
161
+ await nap(5000)
162
+ return 123
163
+ })
164
+ ```
165
+ - **use.op.promise** — start with an op based on a promise
166
+ ```ts
167
+ const op = use.op.promise(doAsyncWork())
168
+ ```
121
169
 
122
170
  ### 🍋 neat tricks to impress the ladies
123
- > common patterns and snippets
124
-
125
171
  - make a ticker — mount, repeat, and nap
126
172
  ```ts
127
173
  import {repeat, nap} from "@e280/stz"
@@ -141,55 +187,20 @@ render(content, document.querySelector(".app")!)
141
187
  }))
142
188
  ```
143
189
 
144
- ### 🍋 view declaration settings
145
- > special settings for views at declaration-time
146
-
147
- ```ts
148
- import {view} from "@e280/sly"
149
- import {html} from "lit"
150
-
151
- export const CoolView = view
152
- .settings({mode: "open", delegatesFocus: true})
153
- .view(use => (greeting: string) => {
154
-
155
- return html`😎 ${greeting} <slot></slot>`
156
- })
157
- ```
158
- - these `settings` like `mode` and `delegatesFocus` are [attachShadow params](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#parameters)
159
- - note the `<slot></slot>` we'll use in the next example lol
160
-
161
- ### 🍋 view injection options
162
- > options for views at the template injection site
163
-
164
- ```ts
165
- import {render, html} from "lit"
166
- import {CoolView} from "./cool-view.js"
167
-
168
- const content = html`
169
- <h2>super cool example</h2>
170
- ${CoolView
171
- .attr("class", "hero")
172
- .children(html`<em>spongebob</em>`)
173
- .props("hello")}
174
- `
175
-
176
- render(content, document.querySelector(".app")!)
177
- ```
178
- - `attr` — set html attributes on the `<sly-view>` host element
179
- - `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)
180
- - `props` — finally inject the view by providing its props
181
-
182
190
  <br/>
183
191
 
184
- ## 🦝 OPS LOADING INDICATORS
185
- > ***TODO*** *implemented but not yet documented, lol*
186
- - `Pod` is a type for (loading/ready/error states)
192
+ ## 🦝 SLY OPS, PODS, AND LOADERS
193
+ > ***TODO*** *we need to write real docs for this, lol*
194
+ - `Pod` is a type for loading/ready/error states
195
+ - `podium` is a tool with fns for working with pods
187
196
  - `Op` class wraps a pod signal and has some ergonomic fns
188
- - `loady` has various loading indicators for dealing with ops
197
+ - `makeLoader(anims.bar2)` makes it easy to create a loader
198
+ - see the available `anims` on the testing page: https://sly.e280.org/
199
+ - a loader's job is to render an op, with a nice loading anim and error display view
189
200
 
190
201
  <br/>
191
202
 
192
- ## 🧑‍💻 PROJECT BY e280
203
+ ## 🧑‍💻 SLY BY E280
193
204
  reward us with github stars
194
205
  build with us at https://e280.org/ but only if you're cool
195
206
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e280/sly",
3
- "version": "0.0.0-4",
3
+ "version": "0.0.0-6",
4
4
  "description": "web shadow views",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "scripts": {
28
28
  "build": "run-s _clean _ln _tsc _scute",
29
- "watch": "octo 'scute -vw' 'tsc -w' 'node --watch x/tests.test.js' 'http-server x'",
29
+ "start": "octo 'scute -vw' 'tsc -w' 'node --watch x/tests.test.js' 'http-server x'",
30
30
  "count": "find s -path '*/_archive' -prune -o -name '*.ts' -exec wc -l {} +",
31
31
  "test": "node x/tests.test.js",
32
32
  "test-inspect": "node inspect x/tests.test.js",
@@ -1,52 +1,8 @@
1
1
 
2
- import {nap, repeat} from "@e280/stz"
3
- import {css, html, render} from "lit"
4
-
2
+ import {DemoView} from "./views/demo.js"
5
3
  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
-
10
- console.log("🦝 sly")
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
4
 
26
- use.mount(() => repeat(async() => {
27
- await nap(1000)
28
- count.value++
29
- }))
5
+ $.render($(".demo"), DemoView())
30
6
 
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
- )
7
+ console.log("🦝 sly")
52
8
 
package/s/demo/demo.css CHANGED
@@ -5,6 +5,7 @@
5
5
  :root {
6
6
  --prime: #1eff00;
7
7
  --accent: #387d42;
8
+ --pill: #1276391a;
8
9
  --bg: #0e2316;
9
10
  --link: cyan;
10
11
  }
@@ -51,15 +52,13 @@
51
52
 
52
53
  @layer page {
53
54
  :root {
54
- color-scheme: dark;
55
-
56
- padding: 5vw 0.5em;
57
- min-height: 100%;
58
- scrollbar-gutter: stable;
59
-
55
+ height: 100%;
60
56
  font-size: 21px;
61
57
  font-family: sans-serif;
62
58
 
59
+ color-scheme: dark;
60
+ scrollbar-gutter: stable;
61
+
63
62
  color: color-mix(in lch, var(--prime), #fff8 50%);
64
63
  background: radial-gradient(
65
64
  circle,
@@ -69,6 +68,13 @@
69
68
  }
70
69
 
71
70
  body {
71
+ width: 100%;
72
+ min-height: 100%;
73
+ max-width: 32em;
74
+ margin: auto;
75
+ padding: 1em;
76
+ padding-bottom: 6em;
77
+
72
78
  display: flex;
73
79
  flex-direction: column;
74
80
  align-items: center;
@@ -88,6 +94,10 @@
88
94
  font-size: 0.8em;
89
95
  }
90
96
 
97
+ .demo {
98
+ width: 100%;
99
+ }
100
+
91
101
  :not(:defined) {
92
102
  display: none;
93
103
  }
@@ -0,0 +1,42 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {repeat} from "@e280/stz"
4
+
5
+ import {view} from "../../features/views/view.js"
6
+ import {cssReset} from "../../features/views/css-reset.js"
7
+
8
+ export const CounterView = view(use => () => {
9
+ use.name("counter")
10
+ use.styles(cssReset, styles)
11
+
12
+ const start = use.once(() => Date.now())
13
+ const seconds = use.signal(0)
14
+
15
+ use.mount(() => repeat(async() => {
16
+ const since = Date.now() - start
17
+ seconds(Math.floor(since / 1000))
18
+ }))
19
+
20
+ const count = use.signal(0)
21
+ const increment = () => count(count() + 1)
22
+
23
+ return html`
24
+ <div>
25
+ <span>${seconds()}</span>
26
+ </div>
27
+ <div>
28
+ <span>${count()}</span>
29
+ <button @click="${increment}">+</button>
30
+ </div>
31
+ `
32
+ })
33
+
34
+ const styles = css`
35
+ :host {
36
+ display: flex;
37
+ flex-direction: column;
38
+ justify-content: center;
39
+ text-align: center;
40
+ }
41
+ `
42
+
@@ -0,0 +1,25 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {CounterView} from "./counter.js"
4
+ import {LoadersView} from "./loaders.js"
5
+ import {view} from "../../features/views/view.js"
6
+ import {cssReset} from "../../features/views/css-reset.js"
7
+
8
+ export const DemoView = view(use => () => {
9
+ use.name("demo")
10
+ use.styles(cssReset, styles)
11
+
12
+ return html`
13
+ ${CounterView()}
14
+ ${LoadersView()}
15
+ `
16
+ })
17
+
18
+ const styles = css`
19
+ :host {
20
+ display: flex;
21
+ flex-direction: column;
22
+ gap: 1em;
23
+ }
24
+ `
25
+
@@ -0,0 +1,71 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {Op} from "../../features/op/op.js"
4
+ import {view} from "../../features/views/view.js"
5
+ import {cssReset} from "../../features/views/css-reset.js"
6
+ import {anims, makeLoader} from "../../features/op/loaders/make-loader.js"
7
+
8
+ export const LoadersView = view(use => () => {
9
+ use.name("loaders")
10
+ use.styles(cssReset, styles)
11
+
12
+ const op = use.once(() => Op.loading())
13
+
14
+ const loaders = use.once(() =>
15
+ Object.entries(anims).map(([key, anim]) => ({
16
+ key,
17
+ loader: makeLoader(anim)
18
+ }))
19
+ )
20
+
21
+ return loaders.map(({key, loader}) => html`
22
+ <div data-anim="${key}">
23
+ <span>${key}</span>
24
+ <span>${loader(op, () => null)}</span>
25
+ </div>
26
+ `)
27
+ })
28
+
29
+ const styles = css`
30
+ :host {
31
+ display: flex;
32
+ flex-direction: row;
33
+ justify-content: center;
34
+ flex-wrap: wrap;
35
+
36
+ gap: 0.2em;
37
+ padding: 1em;
38
+
39
+ width: 100%;
40
+ }
41
+
42
+ div {
43
+ font-family: monospace;
44
+
45
+ display: flex;
46
+ flex-direction: column;
47
+ justify-content: center;
48
+ align-items: center;
49
+ text-align: center;
50
+
51
+ gap: 0.4em;
52
+ padding: 0.2em 0.5em;
53
+ background: var(--pill);
54
+ border-radius: 0.5em;
55
+
56
+ span:nth-child(1) {
57
+ font-size: 0.6em;
58
+ }
59
+
60
+ span:nth-child(2) {
61
+ display: flex;
62
+ justify-content: center;
63
+ align-items: center;
64
+
65
+ font-size: 1.2em;
66
+ min-width: 7em;
67
+ min-height: 2.5em;
68
+ }
69
+ }
70
+ `
71
+
@@ -0,0 +1,18 @@
1
+
2
+ import {Op} from "../op.js"
3
+ import {braille} from "./parts/anims.js"
4
+ import {Content} from "../../views/types.js"
5
+ import {ErrorDisplay} from "./parts/error-display.js"
6
+
7
+ export * as anims from "./parts/anims.js"
8
+
9
+ export type Loader = <V>(op: Op<V>, ready: (value: V) => Content) => Content
10
+
11
+ export function makeLoader(
12
+ loading: () => Content = braille,
13
+ error: (error: any) => Content = (error: any) => ErrorDisplay(error),
14
+ ): Loader {
15
+
16
+ return (op, ready) => op.select({loading, ready, error})
17
+ }
18
+