@e280/shiny 0.1.0-11 → 0.1.0-13

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 (99) hide show
  1. package/README.md +3 -1
  2. package/package.json +3 -3
  3. package/s/components/button/component.ts +3 -3
  4. package/s/components/button/showcase.ts +119 -0
  5. package/s/components/button/style.css.ts +0 -1
  6. package/s/components/copy/component.ts +3 -1
  7. package/s/components/copy/showcase.ts +51 -0
  8. package/s/components/drawer/component.ts +30 -32
  9. package/s/components/drawer/showcase.ts +93 -0
  10. package/s/components/drawer/style.css.ts +9 -4
  11. package/s/components/tabs/showcase.ts +166 -0
  12. package/s/components/tabs/style.css.ts +7 -4
  13. package/s/demo/demo.bundle.ts +13 -281
  14. package/s/demo/demo.css +1 -0
  15. package/s/demo/lipsum.ts +6 -0
  16. package/s/demo/utils/lipsum.ts +1 -1
  17. package/s/demo/views/exhibit/style.css.ts +82 -0
  18. package/s/demo/views/exhibit/view.ts +61 -0
  19. package/s/demo/views/showcase/style.css.ts +53 -0
  20. package/s/demo/views/showcase/view.ts +54 -0
  21. package/s/demo/viewsets.ts +12 -0
  22. package/s/index.html.ts +4 -7
  23. package/s/themes/aura.css.ts +4 -4
  24. package/s/themes/infra/css-vars.ts +7 -2
  25. package/x/components/button/component.d.ts +2 -1
  26. package/x/components/button/component.js +2 -2
  27. package/x/components/button/component.js.map +1 -1
  28. package/x/components/button/showcase.d.ts +1 -0
  29. package/x/components/button/showcase.js +116 -0
  30. package/x/components/button/showcase.js.map +1 -0
  31. package/x/components/button/style.css.js +0 -1
  32. package/x/components/button/style.css.js.map +1 -1
  33. package/x/components/copy/component.d.ts +2 -2
  34. package/x/components/copy/component.js +3 -1
  35. package/x/components/copy/component.js.map +1 -1
  36. package/x/components/copy/showcase.d.ts +1 -0
  37. package/x/components/copy/showcase.js +48 -0
  38. package/x/components/copy/showcase.js.map +1 -0
  39. package/x/components/drawer/component.d.ts +3 -3
  40. package/x/components/drawer/component.js +28 -31
  41. package/x/components/drawer/component.js.map +1 -1
  42. package/x/components/drawer/showcase.d.ts +1 -0
  43. package/x/components/drawer/showcase.js +87 -0
  44. package/x/components/drawer/showcase.js.map +1 -0
  45. package/x/components/drawer/style.css.js +9 -4
  46. package/x/components/drawer/style.css.js.map +1 -1
  47. package/x/components/example/component.d.ts +1 -1
  48. package/x/components/tabs/component.d.ts +1 -1
  49. package/x/components/tabs/showcase.d.ts +1 -0
  50. package/x/components/tabs/showcase.js +162 -0
  51. package/x/components/tabs/showcase.js.map +1 -0
  52. package/x/components/tabs/style.css.js +7 -4
  53. package/x/components/tabs/style.css.js.map +1 -1
  54. package/x/demo/demo.bundle.js +13 -274
  55. package/x/demo/demo.bundle.js.map +1 -1
  56. package/x/demo/demo.bundle.min.js +473 -401
  57. package/x/demo/demo.bundle.min.js.map +4 -4
  58. package/x/demo/demo.css +1 -0
  59. package/x/demo/lipsum.d.ts +2 -0
  60. package/x/demo/lipsum.js +4 -0
  61. package/x/demo/lipsum.js.map +1 -0
  62. package/x/demo/utils/lipsum.js +1 -1
  63. package/x/demo/views/exhibit/style.css.js +81 -0
  64. package/x/demo/views/exhibit/style.css.js.map +1 -0
  65. package/x/demo/views/exhibit/view.d.ts +29 -0
  66. package/x/demo/views/exhibit/view.js +40 -0
  67. package/x/demo/views/exhibit/view.js.map +1 -0
  68. package/x/demo/views/showcase/style.css.d.ts +2 -0
  69. package/x/demo/views/showcase/style.css.js +52 -0
  70. package/x/demo/views/showcase/style.css.js.map +1 -0
  71. package/x/demo/views/showcase/view.d.ts +7 -0
  72. package/x/demo/views/showcase/view.js +40 -0
  73. package/x/demo/views/showcase/view.js.map +1 -0
  74. package/x/demo/{aura-views.d.ts → viewsets.d.ts} +5 -3
  75. package/x/demo/viewsets.js +9 -0
  76. package/x/demo/viewsets.js.map +1 -0
  77. package/x/index.html +5 -4
  78. package/x/index.html.js +4 -7
  79. package/x/index.html.js.map +1 -1
  80. package/x/install/aura.bundle.min.js +55 -49
  81. package/x/install/aura.bundle.min.js.map +3 -3
  82. package/x/install/plain.bundle.min.js +51 -45
  83. package/x/install/plain.bundle.min.js.map +3 -3
  84. package/x/shiny.d.ts +5 -5
  85. package/x/themes/aura.css.js +4 -4
  86. package/x/themes/infra/css-vars.d.ts +2 -1
  87. package/x/themes/infra/css-vars.js +2 -1
  88. package/x/themes/infra/css-vars.js.map +1 -1
  89. package/s/demo/aura-views.ts +0 -6
  90. package/s/demo/views/demonstration/style.css.ts +0 -124
  91. package/s/demo/views/demonstration/view.ts +0 -57
  92. package/x/demo/aura-views.js +0 -4
  93. package/x/demo/aura-views.js.map +0 -1
  94. package/x/demo/views/demonstration/style.css.js +0 -123
  95. package/x/demo/views/demonstration/style.css.js.map +0 -1
  96. package/x/demo/views/demonstration/view.d.ts +0 -12
  97. package/x/demo/views/demonstration/view.js +0 -44
  98. package/x/demo/views/demonstration/view.js.map +0 -1
  99. /package/x/demo/views/{demonstration → exhibit}/style.css.d.ts +0 -0
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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@e280/shiny",
3
- "version": "0.1.0-11",
3
+ "version": "0.1.0-13",
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-25",
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.2"
29
+ "typescript": "^5.9.3"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "run-s _clean _ln _tsc _scute",
@@ -1,12 +1,12 @@
1
1
 
2
2
  import {html} from "lit"
3
- import {view} from "@e280/sly"
3
+ import {Content, view} from "@e280/sly"
4
4
  import styleCss from "./style.css.js"
5
5
  import {foundationCss} from "../foundation.css.js"
6
6
  import {ShinyContext, ShinyElement} from "../framework.js"
7
7
 
8
8
  export class ShinyButton extends (
9
- view(use => (context: ShinyContext) => {
9
+ view(use => (context: ShinyContext, content?: Content) => {
10
10
  use.name("shiny-button")
11
11
  use.styles(foundationCss, context.theme, styleCss)
12
12
 
@@ -20,7 +20,7 @@ export class ShinyButton extends (
20
20
  part=button
21
21
  ?disabled="${attrs.disabled}"
22
22
  ?hidden="${attrs.hidden}">
23
- <slot></slot>
23
+ <slot>${content}</slot>
24
24
  </button>
25
25
  `
26
26
  })
@@ -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
+
@@ -44,7 +44,6 @@ button {
44
44
  font: inherit;
45
45
  color: inherit;
46
46
  cursor: inherit;
47
- outline: inherit;
48
47
  text-shadow: inherit;
49
48
 
50
49
  display: inline-flex;
@@ -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(`invalid copy status`)
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: boolean
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 side = options.side ?? "left"
25
- const drawer = use.once(() => (options.control ?? new DrawerControl()))
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
- drawer.close()
31
+ control.close()
31
32
  }}))
32
33
 
33
- dom.attrs(use.element).booleans.open = drawer.isOpen
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="${drawer.isOpen}" data-side="${side}">
37
- <slot name=plate ?inert="${drawer.isOpen}"></slot>
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="${drawer.close}" ?inert="${!drawer.isOpen}"></div>
59
+ <div part=blanket @click="${control.close}" ?inert="${!control.isOpen}"></div>
41
60
 
42
61
  <div part=tray>
43
- <slot ?inert="${!drawer.isOpen}"></slot>
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
- > slot {
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
  }
@@ -0,0 +1,166 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {lipsum} from "../../demo/lipsum.js"
4
+ import {Showcase} from "../../demo/views/showcase/view.js"
5
+
6
+ const lip1 = lipsum()
7
+ const lip2 = lipsum()
8
+ const lip3 = lipsum()
9
+
10
+ const cssSnippet = `
11
+ shiny-tabs {
12
+ &::part(tabs) {}
13
+ &::part(panels) {}
14
+ > shiny-button {}
15
+ }
16
+ `
17
+
18
+ export const tabsShowcase = () => Showcase({
19
+ name: "tabs",
20
+ style: css`
21
+ .box {
22
+ place-content: start start;
23
+ p { margin-top: 0.5em; }
24
+ button { padding: 1em; }
25
+ }
26
+ `,
27
+ exhibits: [
28
+ {
29
+ label: "shiny snug",
30
+ explain: html`<p>button bar. panels optional.</p>`,
31
+ snippets: [
32
+ {label: "html", code: `
33
+ <shiny-tabs snug>
34
+ <shiny-button>tab1</shiny-button>
35
+ <shiny-button>tab2</shiny-button>
36
+ <shiny-button>tab3</shiny-button>
37
+ <div slot=panel>panel1</div>
38
+ <div slot=panel>panel2</div>
39
+ <div slot=panel>panel3</div>
40
+ </shiny-tabs>
41
+ `},
42
+ {label: "view", code: `
43
+ ShinyTabs
44
+ .props()
45
+ .attr("snug")
46
+ .children(html\`
47
+ \${ShinyButton.props().children("tab1").render()}
48
+ \${ShinyButton.props().children("tab2").render()}
49
+ \${ShinyButton.props().children("tab3").render()}
50
+ <div slot=panel>panel1</div>
51
+ <div slot=panel>panel2</div>
52
+ <div slot=panel>panel3</div>
53
+ \`)
54
+ .render()
55
+ `},
56
+ {label: "css", code: cssSnippet},
57
+ ],
58
+ style: css``,
59
+ presentation: views => html`
60
+ ${views.ShinyTabs
61
+ .props()
62
+ .attr("snug")
63
+ .children(html`
64
+ ${views.ShinyButton.props().children("tab1").render()}
65
+ ${views.ShinyButton.props().children("tab2").render()}
66
+ ${views.ShinyButton.props().children("tab3").render()}
67
+ <p slot=panel class=lipsum>${lip1}</p>
68
+ <p slot=panel class=lipsum>${lip2}</p>
69
+ <p slot=panel class=lipsum>${lip3}</p>
70
+ `)
71
+ .render()}
72
+ `,
73
+ },
74
+ {
75
+ label: "regular",
76
+ explain: html`<p>button bar. panels optional.</p>`,
77
+ snippets: [
78
+ {label: "html", code: `
79
+ <shiny-tabs>
80
+ <button>tab1</button>
81
+ <button>tab2</button>
82
+ <button>tab3</button>
83
+ <div slot=panel>panel1</div>
84
+ <div slot=panel>panel2</div>
85
+ <div slot=panel>panel3</div>
86
+ </shiny-tabs>
87
+ `},
88
+ {label: "view", code: `
89
+ ShinyTabs
90
+ .props()
91
+ .children(html\`
92
+ <button>tab1</button>
93
+ <button>tab2</button>
94
+ <button>tab3</button>
95
+ <div slot=panel>panel1</div>
96
+ <div slot=panel>panel2</div>
97
+ <div slot=panel>panel3</div>
98
+ \`)
99
+ .render()
100
+ `},
101
+ {label: "css", code: cssSnippet},
102
+ ],
103
+ style: css``,
104
+ presentation: views => html`
105
+ ${views.ShinyTabs
106
+ .props()
107
+ .children(html`
108
+ <button>tab1</button>
109
+ <button>tab2</button>
110
+ <button>tab3</button>
111
+ <p slot=panel class=lipsum>${lip1}</p>
112
+ <p slot=panel class=lipsum>${lip2}</p>
113
+ <p slot=panel class=lipsum>${lip3}</p>
114
+ `)
115
+ .render()}
116
+ `,
117
+ },
118
+ {
119
+ label: "regular snug",
120
+ explain: html`<p>button bar. panels optional.</p>`,
121
+ snippets: [
122
+ {label: "html", code: `
123
+ <shiny-tabs snug>
124
+ <button>tab1</button>
125
+ <button>tab2</button>
126
+ <button>tab3</button>
127
+ <div slot=panel>panel1</div>
128
+ <div slot=panel>panel2</div>
129
+ <div slot=panel>panel3</div>
130
+ </shiny-tabs>
131
+ `},
132
+ {label: "view", code: `
133
+ ShinyTabs
134
+ .props()
135
+ .attr("snug")
136
+ .children(html\`
137
+ <button>tab1</button>
138
+ <button>tab2</button>
139
+ <button>tab3</button>
140
+ <div slot=panel>panel1</div>
141
+ <div slot=panel>panel2</div>
142
+ <div slot=panel>panel3</div>
143
+ \`)
144
+ .render()
145
+ `},
146
+ {label: "css", code: cssSnippet},
147
+ ],
148
+ style: css``,
149
+ presentation: views => html`
150
+ ${views.ShinyTabs
151
+ .props()
152
+ .attr("snug")
153
+ .children(html`
154
+ <button>tab1</button>
155
+ <button>tab2</button>
156
+ <button>tab3</button>
157
+ <p slot=panel class=lipsum>${lip1}</p>
158
+ <p slot=panel class=lipsum>${lip2}</p>
159
+ <p slot=panel class=lipsum>${lip3}</p>
160
+ `)
161
+ .render()}
162
+ `,
163
+ },
164
+ ],
165
+ })
166
+
@@ -9,16 +9,19 @@ export default css`@layer view {
9
9
 
10
10
  slot[part="tabs"] {
11
11
  display: flex;
12
-
13
- &::slotted(*) {
14
- border-radius: 0.3em;
15
- }
12
+ flex-wrap: wrap;
16
13
 
17
14
  &::slotted([data-active]) {
18
15
  opacity: 1;
19
16
  color: currentColor;
20
17
  text-decoration: underline;
21
18
  }
19
+ }
20
+
21
+ :host([snug]) slot[part="tabs"] {
22
+ &::slotted(*) {
23
+ border-radius: 0.3em;
24
+ }
22
25
 
23
26
  &::slotted(:not([data-last], [data-next-is-active])) {
24
27
  border-right: none;