@e280/shiny 0.1.0-10 → 0.1.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 +13 -8
- package/package.json +3 -3
- package/s/components/button/component.ts +30 -0
- package/s/components/button/showcase.ts +119 -0
- package/s/components/button/style.css.ts +63 -0
- package/s/components/copy/component.ts +3 -1
- package/s/components/copy/showcase.ts +51 -0
- package/s/components/drawer/component.ts +30 -32
- package/s/components/drawer/showcase.ts +93 -0
- package/s/components/drawer/style.css.ts +9 -4
- package/s/components/raw-components.ts +2 -0
- package/s/components/tabs/component.ts +13 -2
- package/s/components/tabs/control.ts +3 -3
- package/s/components/tabs/showcase.ts +73 -0
- package/s/components/tabs/style.css.ts +38 -1
- package/s/demo/demo.bundle.ts +14 -199
- package/s/demo/demo.css +1 -0
- package/s/demo/lipsum.ts +6 -0
- package/s/demo/utils/lipsum.ts +1 -1
- package/s/demo/views/demonstration/style.css.ts +8 -0
- package/s/demo/views/demonstration/view.ts +10 -6
- package/s/demo/views/exhibit/style.css.ts +82 -0
- package/s/demo/views/exhibit/view.ts +59 -0
- package/s/demo/views/showcase/style.css.ts +50 -0
- package/s/demo/views/showcase/view.ts +54 -0
- package/s/demo/viewsets.ts +12 -0
- package/s/index.html.ts +4 -7
- package/s/themes/aura.css.ts +52 -14
- package/s/themes/infra/css-vars.ts +19 -6
- package/s/themes/plain.css.ts +0 -1
- package/x/components/button/component.d.ts +6 -0
- package/x/components/button/component.js +25 -0
- package/x/components/button/component.js.map +1 -0
- package/x/components/button/showcase.d.ts +1 -0
- package/x/components/button/showcase.js +116 -0
- package/x/components/button/showcase.js.map +1 -0
- package/x/components/button/style.css.d.ts +2 -0
- package/x/components/button/style.css.js +62 -0
- package/x/components/button/style.css.js.map +1 -0
- package/x/components/copy/component.d.ts +2 -2
- package/x/components/copy/component.js +3 -1
- package/x/components/copy/component.js.map +1 -1
- package/x/components/copy/showcase.d.ts +1 -0
- package/x/components/copy/showcase.js +48 -0
- package/x/components/copy/showcase.js.map +1 -0
- package/x/components/drawer/component.d.ts +3 -3
- package/x/components/drawer/component.js +28 -31
- package/x/components/drawer/component.js.map +1 -1
- package/x/components/drawer/showcase.d.ts +1 -0
- package/x/components/drawer/showcase.js +87 -0
- package/x/components/drawer/showcase.js.map +1 -0
- package/x/components/drawer/style.css.js +9 -4
- package/x/components/drawer/style.css.js.map +1 -1
- package/x/components/example/component.d.ts +1 -1
- package/x/components/raw-components.d.ts +2 -0
- package/x/components/raw-components.js +2 -0
- package/x/components/raw-components.js.map +1 -1
- package/x/components/tabs/component.d.ts +1 -1
- package/x/components/tabs/component.js +13 -2
- package/x/components/tabs/component.js.map +1 -1
- package/x/components/tabs/control.d.ts +1 -1
- package/x/components/tabs/control.js +3 -3
- package/x/components/tabs/control.js.map +1 -1
- package/x/components/tabs/showcase.d.ts +1 -0
- package/x/components/tabs/showcase.js +69 -0
- package/x/components/tabs/showcase.js.map +1 -0
- package/x/components/tabs/style.css.js +38 -1
- package/x/components/tabs/style.css.js.map +1 -1
- package/x/demo/demo.bundle.js +14 -193
- package/x/demo/demo.bundle.js.map +1 -1
- package/x/demo/demo.bundle.min.js +497 -311
- package/x/demo/demo.bundle.min.js.map +4 -4
- package/x/demo/demo.css +1 -0
- package/x/demo/lipsum.d.ts +2 -0
- package/x/demo/lipsum.js +4 -0
- package/x/demo/lipsum.js.map +1 -0
- package/x/demo/utils/lipsum.js +1 -1
- package/x/demo/views/demonstration/style.css.js +8 -0
- package/x/demo/views/demonstration/style.css.js.map +1 -1
- package/x/demo/views/demonstration/view.js +8 -6
- package/x/demo/views/demonstration/view.js.map +1 -1
- package/x/demo/views/exhibit/style.css.d.ts +2 -0
- package/x/demo/views/exhibit/style.css.js +81 -0
- package/x/demo/views/exhibit/style.css.js.map +1 -0
- package/x/demo/views/exhibit/view.d.ts +29 -0
- package/x/demo/views/exhibit/view.js +38 -0
- package/x/demo/views/exhibit/view.js.map +1 -0
- package/x/demo/views/showcase/style.css.d.ts +2 -0
- package/x/demo/views/showcase/style.css.js +49 -0
- package/x/demo/views/showcase/style.css.js.map +1 -0
- package/x/demo/views/showcase/view.d.ts +7 -0
- package/x/demo/views/showcase/view.js +40 -0
- package/x/demo/views/showcase/view.js.map +1 -0
- package/x/demo/{aura-views.d.ts → viewsets.d.ts} +5 -2
- package/x/demo/viewsets.js +9 -0
- package/x/demo/viewsets.js.map +1 -0
- package/x/index.html +5 -4
- package/x/index.html.js +4 -7
- package/x/index.html.js.map +1 -1
- package/x/install/aura.bundle.min.js +210 -65
- package/x/install/aura.bundle.min.js.map +4 -4
- package/x/install/plain.bundle.min.js +159 -53
- package/x/install/plain.bundle.min.js.map +4 -4
- package/x/shiny.d.ts +8 -3
- package/x/themes/aura.css.js +52 -14
- package/x/themes/aura.css.js.map +1 -1
- package/x/themes/infra/css-vars.d.ts +6 -2
- package/x/themes/infra/css-vars.js +7 -3
- package/x/themes/infra/css-vars.js.map +1 -1
- package/x/themes/plain.css.js +0 -1
- package/x/themes/plain.css.js.map +1 -1
- package/s/demo/aura-views.ts +0 -6
- package/x/demo/aura-views.js +0 -4
- package/x/demo/aura-views.js.map +0 -1
package/README.md
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
> *web ui components*
|
|
6
6
|
|
|
7
7
|
- 💁 ***see all the components at https://shiny.e280.org/*** 👈
|
|
8
|
-
- 👷 built with [🦝sly](https://github.com/e280/sly) and [🔥lit](https://lit.dev/)
|
|
9
8
|
- 🎭 duality: all components are available as ***web components*** or ***sly views***
|
|
9
|
+
- 👷 built with [🦝sly](https://github.com/e280/sly) and [🔥lit](https://lit.dev/)
|
|
10
|
+
- 🎨 totally customizable, via theme presets, custom themes, css vars and parts
|
|
11
|
+
- 🧩 using [tabler icons](https://github.com/tabler/tabler-icons)
|
|
10
12
|
- 🧑💻 a project by https://e280.org/
|
|
11
13
|
|
|
12
14
|
|
|
@@ -92,13 +94,16 @@
|
|
|
92
94
|
```html
|
|
93
95
|
<style>
|
|
94
96
|
html {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
--shiny-bg: #111;
|
|
98
|
+
--shiny-alpha: #def;
|
|
99
|
+
--shiny-lame: #8888;
|
|
100
|
+
--shiny-inactive-opacity: 0.5;
|
|
101
|
+
--shiny-angry: #f50;
|
|
102
|
+
--shiny-zesty: #cf0;
|
|
103
|
+
--shiny-happy: #0fa;
|
|
104
|
+
--shiny-calm: #0af;
|
|
105
|
+
--shiny-sad: #74f;
|
|
106
|
+
--shiny-quirky: #f49;
|
|
102
107
|
}
|
|
103
108
|
</style>
|
|
104
109
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e280/shiny",
|
|
3
|
-
"version": "0.1.0-
|
|
3
|
+
"version": "0.1.0-12",
|
|
4
4
|
"description": "✨ web ui components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"s"
|
|
15
15
|
],
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@e280/sly": "^0.2.0-
|
|
17
|
+
"@e280/sly": "^0.2.0-26",
|
|
18
18
|
"lit": "^3.3.1"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@e280/scute": "^0.1.0",
|
|
27
27
|
"http-server": "^14.1.1",
|
|
28
28
|
"npm-run-all": "^4.1.5",
|
|
29
|
-
"typescript": "^5.9.
|
|
29
|
+
"typescript": "^5.9.3"
|
|
30
30
|
},
|
|
31
31
|
"scripts": {
|
|
32
32
|
"build": "run-s _clean _ln _tsc _scute",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
import {html} from "lit"
|
|
3
|
+
import {Content, view} from "@e280/sly"
|
|
4
|
+
import styleCss from "./style.css.js"
|
|
5
|
+
import {foundationCss} from "../foundation.css.js"
|
|
6
|
+
import {ShinyContext, ShinyElement} from "../framework.js"
|
|
7
|
+
|
|
8
|
+
export class ShinyButton extends (
|
|
9
|
+
view(use => (context: ShinyContext, content?: Content) => {
|
|
10
|
+
use.name("shiny-button")
|
|
11
|
+
use.styles(foundationCss, context.theme, styleCss)
|
|
12
|
+
|
|
13
|
+
const attrs = use.attrs.spec({
|
|
14
|
+
disabled: Boolean,
|
|
15
|
+
hidden: Boolean,
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
return html`
|
|
19
|
+
<button
|
|
20
|
+
part=button
|
|
21
|
+
?disabled="${attrs.disabled}"
|
|
22
|
+
?hidden="${attrs.hidden}">
|
|
23
|
+
<slot>${content}</slot>
|
|
24
|
+
</button>
|
|
25
|
+
`
|
|
26
|
+
})
|
|
27
|
+
.component(ShinyElement)
|
|
28
|
+
.props(el => [el.context] as const)
|
|
29
|
+
) {}
|
|
30
|
+
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
|
|
2
|
+
import {css, html} from "lit"
|
|
3
|
+
import {Showcase} from "../../demo/views/showcase/view.js"
|
|
4
|
+
|
|
5
|
+
const cssSnippet = `
|
|
6
|
+
shiny-button {
|
|
7
|
+
--padding: 0.3em;
|
|
8
|
+
font-size: 1em;
|
|
9
|
+
color: currentColor;
|
|
10
|
+
background: transparent;
|
|
11
|
+
}
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
export const buttonShowcase = () => Showcase({
|
|
15
|
+
name: "button",
|
|
16
|
+
style: css`
|
|
17
|
+
.box {
|
|
18
|
+
> * { font-size: 1.5em; }
|
|
19
|
+
}
|
|
20
|
+
`,
|
|
21
|
+
exhibits: [
|
|
22
|
+
{
|
|
23
|
+
label: "basic",
|
|
24
|
+
explain: html`<p>clicky-clacky pressy button.</p>`,
|
|
25
|
+
snippets: [
|
|
26
|
+
{label: "html", code: `<shiny-button>button</shiny-button>`},
|
|
27
|
+
{label: "view", code: `ShinyButton("button")`},
|
|
28
|
+
{label: "css", code: cssSnippet},
|
|
29
|
+
],
|
|
30
|
+
style: css``,
|
|
31
|
+
presentation: views => html`
|
|
32
|
+
${views.ShinyButton.props().children("button").render()}
|
|
33
|
+
`,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: "gradient",
|
|
37
|
+
explain: html`<p>added <code>gradient</code> attribute.</p>`,
|
|
38
|
+
snippets: [
|
|
39
|
+
{label: "html", code: `<shiny-button gradient>button</shiny-button>`},
|
|
40
|
+
{label: "view", code: `
|
|
41
|
+
ShinyButton
|
|
42
|
+
.props("button")
|
|
43
|
+
.attr("gradient")
|
|
44
|
+
.render()
|
|
45
|
+
`},
|
|
46
|
+
{label: "css", code: cssSnippet},
|
|
47
|
+
],
|
|
48
|
+
style: css``,
|
|
49
|
+
presentation: views => html`
|
|
50
|
+
${views.ShinyButton.props().attr("gradient").children("button").render()}
|
|
51
|
+
`,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
label: "catalog",
|
|
55
|
+
explain: html`<p>clicky-clacky pressy buttons.</p>`,
|
|
56
|
+
snippets: [
|
|
57
|
+
{label: "html", code: `
|
|
58
|
+
<shiny-button calm gradient>calm</shiny-button>
|
|
59
|
+
<shiny-button angry gradient>angry</shiny-button>
|
|
60
|
+
<shiny-button happy gradient>happy</shiny-button>
|
|
61
|
+
<shiny-button zesty gradient>zesty</shiny-button>
|
|
62
|
+
<shiny-button sad gradient>sad</shiny-button>
|
|
63
|
+
<shiny-button quirky gradient>quirky</shiny-button>
|
|
64
|
+
<shiny-button plain gradient>plain</shiny-button>
|
|
65
|
+
`},
|
|
66
|
+
{label: "view", code: `
|
|
67
|
+
[
|
|
68
|
+
ShinyButton.props().attr("calm").attr("gradient").children("calm").render(),
|
|
69
|
+
ShinyButton.props().attr("angry").attr("gradient").children("angry").render(),
|
|
70
|
+
ShinyButton.props().attr("happy").attr("gradient").children("happy").render(),
|
|
71
|
+
ShinyButton.props().attr("zesty").attr("gradient").children("zesty").render(),
|
|
72
|
+
ShinyButton.props().attr("sad").attr("gradient").children("sad").render(),
|
|
73
|
+
ShinyButton.props().attr("quirky").attr("gradient").children("quirky").render(),
|
|
74
|
+
ShinyButton.props().attr("plain").children("plain").render(),
|
|
75
|
+
]
|
|
76
|
+
`},
|
|
77
|
+
{label: "css", code: cssSnippet},
|
|
78
|
+
],
|
|
79
|
+
style: css``,
|
|
80
|
+
presentation: views => [
|
|
81
|
+
views.ShinyButton.props()
|
|
82
|
+
.attr("calm")
|
|
83
|
+
.attr("gradient")
|
|
84
|
+
.children("calm")
|
|
85
|
+
.render(),
|
|
86
|
+
views.ShinyButton.props()
|
|
87
|
+
.attr("angry")
|
|
88
|
+
.attr("gradient")
|
|
89
|
+
.children("angry")
|
|
90
|
+
.render(),
|
|
91
|
+
views.ShinyButton.props()
|
|
92
|
+
.attr("happy")
|
|
93
|
+
.attr("gradient")
|
|
94
|
+
.children("happy")
|
|
95
|
+
.render(),
|
|
96
|
+
views.ShinyButton.props()
|
|
97
|
+
.attr("zesty")
|
|
98
|
+
.attr("gradient")
|
|
99
|
+
.children("zesty")
|
|
100
|
+
.render(),
|
|
101
|
+
views.ShinyButton.props()
|
|
102
|
+
.attr("sad")
|
|
103
|
+
.attr("gradient")
|
|
104
|
+
.children("sad")
|
|
105
|
+
.render(),
|
|
106
|
+
views.ShinyButton.props()
|
|
107
|
+
.attr("quirky")
|
|
108
|
+
.attr("gradient")
|
|
109
|
+
.children("quirky")
|
|
110
|
+
.render(),
|
|
111
|
+
views.ShinyButton.props()
|
|
112
|
+
.attr("plain")
|
|
113
|
+
.children("plain")
|
|
114
|
+
.render(),
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
})
|
|
119
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
|
|
2
|
+
import {css} from "lit"
|
|
3
|
+
export default css`@layer view {
|
|
4
|
+
|
|
5
|
+
:host {
|
|
6
|
+
opacity: 0.8;
|
|
7
|
+
display: inline-flex;
|
|
8
|
+
width: max-content;
|
|
9
|
+
height: max-content;
|
|
10
|
+
|
|
11
|
+
--padding: 0.3em;
|
|
12
|
+
border-radius: 0.2em;
|
|
13
|
+
border: 0.1em solid currentColor;
|
|
14
|
+
|
|
15
|
+
cursor: pointer;
|
|
16
|
+
background: transparent;
|
|
17
|
+
user-select: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:host(:not([disabled]):is(:hover, :focus-visible)) { opacity: 1; }
|
|
21
|
+
:host(:not([disabled]):active) { opacity: 0.6; }
|
|
22
|
+
|
|
23
|
+
:host([disabled]) {
|
|
24
|
+
cursor: default;
|
|
25
|
+
color: var(--lame);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
:host([hidden]) {
|
|
29
|
+
display: none !important;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
:host([lame]) { color: var(--lame); }
|
|
33
|
+
:host([angry]) { color: var(--angry); }
|
|
34
|
+
:host([zesty]) { color: var(--zesty); }
|
|
35
|
+
:host([happy]) { color: var(--happy); }
|
|
36
|
+
:host([calm]) { color: var(--calm); }
|
|
37
|
+
:host([sad]) { color: var(--sad); }
|
|
38
|
+
:host([quirky]) { color: var(--quirky); }
|
|
39
|
+
|
|
40
|
+
button {
|
|
41
|
+
background: transparent;
|
|
42
|
+
border: none;
|
|
43
|
+
|
|
44
|
+
font: inherit;
|
|
45
|
+
color: inherit;
|
|
46
|
+
cursor: inherit;
|
|
47
|
+
text-shadow: inherit;
|
|
48
|
+
|
|
49
|
+
display: inline-flex;
|
|
50
|
+
justify-content: center;
|
|
51
|
+
align-items: center;
|
|
52
|
+
|
|
53
|
+
width: 100%;
|
|
54
|
+
height: 100%;
|
|
55
|
+
padding: var(--padding);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
slot {
|
|
59
|
+
display: contents;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
}`
|
|
63
|
+
|
|
@@ -33,6 +33,8 @@ export class ShinyCopy extends (
|
|
|
33
33
|
async function click() {
|
|
34
34
|
if (text === undefined) return
|
|
35
35
|
try {
|
|
36
|
+
if (use.attrs.booleans.fail)
|
|
37
|
+
throw new Error("copy failed on purpose for testing purposes")
|
|
36
38
|
await navigator.clipboard.writeText(text)
|
|
37
39
|
await statusFlash("good")
|
|
38
40
|
}
|
|
@@ -47,7 +49,7 @@ export class ShinyCopy extends (
|
|
|
47
49
|
case "invalid": return clipboardSvg
|
|
48
50
|
case "good": return clipboardCheckFilledSvg
|
|
49
51
|
case "bad": return clipboardXFilledSvg
|
|
50
|
-
default: throw new Error(`
|
|
52
|
+
default: throw new Error(`unknown copy status`)
|
|
51
53
|
}})()
|
|
52
54
|
|
|
53
55
|
return html`
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
|
|
2
|
+
import {css, html} from "lit"
|
|
3
|
+
import {Showcase} from "../../demo/views/showcase/view.js"
|
|
4
|
+
|
|
5
|
+
const cssSnippet = `
|
|
6
|
+
shiny-copy {
|
|
7
|
+
font-size: 1em;
|
|
8
|
+
--happy: #0fa;
|
|
9
|
+
--angry: #f50;
|
|
10
|
+
--lame: #8888;
|
|
11
|
+
--inactive-opacity: 0.5;
|
|
12
|
+
}
|
|
13
|
+
`
|
|
14
|
+
|
|
15
|
+
export const copyShowcase = () => Showcase({
|
|
16
|
+
name: "copy",
|
|
17
|
+
style: css`
|
|
18
|
+
.box {
|
|
19
|
+
> * { font-size: 4em; }
|
|
20
|
+
}
|
|
21
|
+
`,
|
|
22
|
+
exhibits: [
|
|
23
|
+
{
|
|
24
|
+
label: "succeed",
|
|
25
|
+
explain: html`<p>click-to-copy text button.</p>`,
|
|
26
|
+
snippets: [
|
|
27
|
+
{label: "html", code: `<shiny-copy text="hello world"></shiny-button>`},
|
|
28
|
+
{label: "view", code: `ShinyCopy("hello world")`},
|
|
29
|
+
{label: "css", code: cssSnippet},
|
|
30
|
+
],
|
|
31
|
+
style: css``,
|
|
32
|
+
presentation: views => html`
|
|
33
|
+
${views.ShinyCopy("hello world")}
|
|
34
|
+
`,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: "fail",
|
|
38
|
+
explain: html`<p>copy text button, deliberately fails so you can see.</p>`,
|
|
39
|
+
snippets: [
|
|
40
|
+
{label: "html", code: `<shiny-copy fail></shiny-button>`},
|
|
41
|
+
{label: "view", code: `ShinyCopy.props("").attr("fail").render()`},
|
|
42
|
+
{label: "css", code: cssSnippet},
|
|
43
|
+
],
|
|
44
|
+
style: css``,
|
|
45
|
+
presentation: views => html`
|
|
46
|
+
${views.ShinyCopy.props("").attr("fail").render()}
|
|
47
|
+
`,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
})
|
|
51
|
+
|
|
@@ -12,7 +12,7 @@ import {ShinyContext, ShinyElement} from "../framework.js"
|
|
|
12
12
|
|
|
13
13
|
export class ShinyDrawer extends (
|
|
14
14
|
view(use => (context: ShinyContext, options: {
|
|
15
|
-
button
|
|
15
|
+
button?: boolean
|
|
16
16
|
side?: "left" | "right"
|
|
17
17
|
control?: DrawerControl
|
|
18
18
|
}) => {
|
|
@@ -21,44 +21,46 @@ export class ShinyDrawer extends (
|
|
|
21
21
|
use.styles(foundationCss, context.theme, styleCss)
|
|
22
22
|
const states = use.once(() => new States(use.element))
|
|
23
23
|
|
|
24
|
-
const
|
|
25
|
-
const
|
|
24
|
+
const button = options.button ?? use.attrs.booleans.button
|
|
25
|
+
const side = options.side ?? (use.attrs.strings.side === "right" ? "right" : "left")
|
|
26
|
+
const control = use.once(() => (options.control ?? new DrawerControl()))
|
|
26
27
|
states.assign(side)
|
|
27
28
|
|
|
28
29
|
use.mount(() => dom.events(window, {keydown: (event: KeyboardEvent) => {
|
|
29
30
|
if (event.code === "Escape")
|
|
30
|
-
|
|
31
|
+
control.close()
|
|
31
32
|
}}))
|
|
32
33
|
|
|
33
|
-
dom.attrs(use.element).booleans.open =
|
|
34
|
+
dom.attrs(use.element).booleans.open = control.isOpen
|
|
35
|
+
|
|
36
|
+
function renderButton() {
|
|
37
|
+
return html`
|
|
38
|
+
<button @click="${control.toggle}">
|
|
39
|
+
${control.isOpen
|
|
40
|
+
? html`
|
|
41
|
+
<slot name=button-x>
|
|
42
|
+
${xSvg}
|
|
43
|
+
</slot>
|
|
44
|
+
`
|
|
45
|
+
: html`
|
|
46
|
+
<slot name=button>
|
|
47
|
+
${menu2Svg}
|
|
48
|
+
</slot>
|
|
49
|
+
`}
|
|
50
|
+
</button>
|
|
51
|
+
`
|
|
52
|
+
}
|
|
34
53
|
|
|
35
54
|
return html`
|
|
36
|
-
<div class=shell ?data-open="${
|
|
37
|
-
<slot name=plate ?inert="${
|
|
55
|
+
<div class=shell ?data-open="${control.isOpen}" data-side="${side}">
|
|
56
|
+
<slot name=plate ?inert="${control.isOpen}"></slot>
|
|
38
57
|
|
|
39
58
|
<div class=clipper>
|
|
40
|
-
<div part=blanket @click="${
|
|
59
|
+
<div part=blanket @click="${control.close}" ?inert="${!control.isOpen}"></div>
|
|
41
60
|
|
|
42
61
|
<div part=tray>
|
|
43
|
-
<slot ?inert="${!
|
|
44
|
-
|
|
45
|
-
${options.button
|
|
46
|
-
? html`
|
|
47
|
-
<button @click="${drawer.toggle}">
|
|
48
|
-
${drawer.isOpen
|
|
49
|
-
? html`
|
|
50
|
-
<slot name=button-x>
|
|
51
|
-
${xSvg}
|
|
52
|
-
</slot>
|
|
53
|
-
`
|
|
54
|
-
: html`
|
|
55
|
-
<slot name=button>
|
|
56
|
-
${menu2Svg}
|
|
57
|
-
</slot>
|
|
58
|
-
`}
|
|
59
|
-
</button>
|
|
60
|
-
`
|
|
61
|
-
: null}
|
|
62
|
+
<slot part=slate ?inert="${!control.isOpen}"></slot>
|
|
63
|
+
${button ?renderButton() :null}
|
|
62
64
|
</div>
|
|
63
65
|
</div>
|
|
64
66
|
</div>
|
|
@@ -83,10 +85,6 @@ export class ShinyDrawer extends (
|
|
|
83
85
|
get open() { return this.control.open }
|
|
84
86
|
get close() { return this.control.close }
|
|
85
87
|
})
|
|
86
|
-
.props(el => [el.context, {
|
|
87
|
-
control: el.control,
|
|
88
|
-
button: el.button,
|
|
89
|
-
side: el.side,
|
|
90
|
-
}] as const)
|
|
88
|
+
.props(el => [el.context, {control: el.control}] as const)
|
|
91
89
|
) {}
|
|
92
90
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
|
|
2
|
+
import {css, html} from "lit"
|
|
3
|
+
import {lipsum} from "../../demo/lipsum.js"
|
|
4
|
+
import {Showcase} from "../../demo/views/showcase/view.js"
|
|
5
|
+
import {ExhibitParams} from "../../demo/views/exhibit/view.js"
|
|
6
|
+
|
|
7
|
+
const lip1 = lipsum()
|
|
8
|
+
const lip2 = lipsum()
|
|
9
|
+
const lip3 = lipsum()
|
|
10
|
+
|
|
11
|
+
const cssSnippet = `
|
|
12
|
+
shiny-drawer {
|
|
13
|
+
--button-size: 2em;
|
|
14
|
+
--anim-duration: 200ms;
|
|
15
|
+
--slate-hidden-opacity: 1;
|
|
16
|
+
--blanket-backdrop-filter: blur(0.5em);
|
|
17
|
+
--blanket-bg: color-mix(
|
|
18
|
+
in oklab,
|
|
19
|
+
transparent,
|
|
20
|
+
var(--bg)
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const makeExhibit = (side: "left" | "right"): ExhibitParams => ({
|
|
26
|
+
label: side,
|
|
27
|
+
explain: html`<p>slide-out panel. button optional.</p>`,
|
|
28
|
+
snippets: [
|
|
29
|
+
{label: "html", code: `
|
|
30
|
+
<shiny-drawer button side=${side}>
|
|
31
|
+
<header>example</header>
|
|
32
|
+
<section slot=plate>lorem kettlebell..</section>
|
|
33
|
+
</shiny-drawer>
|
|
34
|
+
`},
|
|
35
|
+
{label: "view", code: `
|
|
36
|
+
ShinyDrawer
|
|
37
|
+
.props({button: true, side: "${side}"})
|
|
38
|
+
.children(html\`
|
|
39
|
+
<header>example</header>
|
|
40
|
+
<section slot=plate>lorem kettlebell..</section>
|
|
41
|
+
\`)
|
|
42
|
+
.render()
|
|
43
|
+
`},
|
|
44
|
+
{label: "css", code: cssSnippet},
|
|
45
|
+
],
|
|
46
|
+
style: css``,
|
|
47
|
+
presentation: views => html`
|
|
48
|
+
${views.ShinyDrawer
|
|
49
|
+
.props({button: true, side})
|
|
50
|
+
.children(html`
|
|
51
|
+
<header>
|
|
52
|
+
<h2>example drawer</h2>
|
|
53
|
+
<p>you can put any content in here.</p>
|
|
54
|
+
<p class=lipsum>${lip1}</p>
|
|
55
|
+
</header>
|
|
56
|
+
<section slot=plate>
|
|
57
|
+
<p class=lipsum>${lip2}</p>
|
|
58
|
+
<p class=lipsum>${lip3}</p>
|
|
59
|
+
</section>
|
|
60
|
+
`)
|
|
61
|
+
.render()}
|
|
62
|
+
`,
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
export const drawerShowcase = () => Showcase({
|
|
66
|
+
name: "drawer",
|
|
67
|
+
style: css`
|
|
68
|
+
.box sly-view {
|
|
69
|
+
border-radius: 0.5em;
|
|
70
|
+
overflow: hidden;
|
|
71
|
+
--button-size: 3em;
|
|
72
|
+
|
|
73
|
+
header {
|
|
74
|
+
> * + * { margin-top: 0.5em; }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
section {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
justify-content: center;
|
|
81
|
+
min-height: 100%;
|
|
82
|
+
padding: 1em;
|
|
83
|
+
padding-top: 3em;
|
|
84
|
+
> * + * { margin-top: 0.5em; }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
`,
|
|
88
|
+
exhibits: [
|
|
89
|
+
makeExhibit("left"),
|
|
90
|
+
makeExhibit("right"),
|
|
91
|
+
],
|
|
92
|
+
})
|
|
93
|
+
|
|
@@ -7,8 +7,8 @@ export default css`@layer view {
|
|
|
7
7
|
width: 100%;
|
|
8
8
|
height: 100%;
|
|
9
9
|
--button-size: 2em;
|
|
10
|
-
--anim-duration: 200ms;
|
|
11
10
|
--blanket-backdrop-filter: blur(0.5em);
|
|
11
|
+
--slate-hidden-opacity: 1;
|
|
12
12
|
--blanket-bg: color-mix(in oklab, transparent, var(--bg));
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -52,12 +52,15 @@ export default css`@layer view {
|
|
|
52
52
|
height: auto;
|
|
53
53
|
max-height: 100%;
|
|
54
54
|
|
|
55
|
-
opacity: 1;
|
|
56
55
|
transform: translateX(-100%);
|
|
57
56
|
will-change: opacity, transform;
|
|
58
57
|
transition: all var(--anim-duration) ease;
|
|
59
58
|
|
|
60
|
-
>
|
|
59
|
+
> [part="slate"] {
|
|
60
|
+
opacity: var(--slate-hidden-opacity);
|
|
61
|
+
will-change: opacity;
|
|
62
|
+
transition: opacity var(--anim-duration) ease;
|
|
63
|
+
|
|
61
64
|
display: block;
|
|
62
65
|
height: 100%;
|
|
63
66
|
overflow-y: auto;
|
|
@@ -110,8 +113,10 @@ export default css`@layer view {
|
|
|
110
113
|
opacity: 1;
|
|
111
114
|
}
|
|
112
115
|
[part="tray"] {
|
|
113
|
-
opacity: 1;
|
|
114
116
|
transform: translateX(0%);
|
|
117
|
+
> [part="slate"] {
|
|
118
|
+
opacity: 1;
|
|
119
|
+
}
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
|
|
2
|
+
import {ShinyButton} from "./button/component.js"
|
|
2
3
|
import {ShinyCopy} from "./copy/component.js"
|
|
3
4
|
import {ShinyDrawer} from "./drawer/component.js"
|
|
4
5
|
import {ShinyExample} from "./example/component.js"
|
|
5
6
|
import {ShinyTabs} from "./tabs/component.js"
|
|
6
7
|
|
|
7
8
|
export const rawComponents = {
|
|
9
|
+
ShinyButton,
|
|
8
10
|
ShinyCopy,
|
|
9
11
|
ShinyDrawer,
|
|
10
12
|
ShinyExample,
|
|
@@ -29,10 +29,21 @@ export class ShinyTabs extends (
|
|
|
29
29
|
attrs.index = control.$index()
|
|
30
30
|
control.length = $tabs().length
|
|
31
31
|
|
|
32
|
+
function isNeighborActive(index: number, delta: number) {
|
|
33
|
+
const nextIndex = control.clamp(index + delta)
|
|
34
|
+
if (nextIndex === index) return false
|
|
35
|
+
return (nextIndex === control.index)
|
|
36
|
+
}
|
|
37
|
+
|
|
32
38
|
for (const [index, tab] of $tabs().entries()) {
|
|
33
39
|
const active = (index === control.index)
|
|
34
|
-
dom.attrs(tab)
|
|
35
|
-
|
|
40
|
+
const tabAttrs = dom.attrs(tab)
|
|
41
|
+
tabAttrs.booleans.disabled = active
|
|
42
|
+
tabAttrs.booleans["data-active"] = active
|
|
43
|
+
tabAttrs.booleans["data-first"] = (index === 0)
|
|
44
|
+
tabAttrs.booleans["data-last"] = (index === (control.length - 1))
|
|
45
|
+
tabAttrs.booleans["data-next-is-active"] = isNeighborActive(index, 1)
|
|
46
|
+
tabAttrs.booleans["data-previous-is-active"] = isNeighborActive(index, -1)
|
|
36
47
|
tab.onclick = () => control.setIndex(index)
|
|
37
48
|
}
|
|
38
49
|
|
|
@@ -9,14 +9,14 @@ export class TabControl {
|
|
|
9
9
|
this.$index.value = start
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
clamp(index: number) {
|
|
13
13
|
index = Math.min(index, this.length - 1)
|
|
14
14
|
index = Math.max(index, 0)
|
|
15
15
|
return index
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
get index() {
|
|
19
|
-
return this
|
|
19
|
+
return this.clamp(this.$index.get())
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
async setIndex(index: number) {
|
|
@@ -24,7 +24,7 @@ export class TabControl {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async shimmy(delta: number) {
|
|
27
|
-
const index = this
|
|
27
|
+
const index = this.clamp(this.index + delta)
|
|
28
28
|
return this.setIndex(index)
|
|
29
29
|
}
|
|
30
30
|
}
|