@e280/shiny 0.1.0-2 → 0.1.0-21

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 (247) hide show
  1. package/README.md +51 -63
  2. package/package.json +19 -26
  3. package/s/_archive/components/button/component.ts +30 -0
  4. package/s/_archive/components/button/showcase.ts +119 -0
  5. package/s/_archive/components/button/style.css.ts +63 -0
  6. package/s/{ui → _archive/components}/copy/component.ts +12 -5
  7. package/s/_archive/components/copy/showcase.ts +51 -0
  8. package/s/{ui → _archive/components}/copy/style.css.ts +6 -6
  9. package/s/_archive/components/drawer/component.ts +90 -0
  10. package/s/_archive/components/drawer/control.ts +31 -0
  11. package/s/_archive/components/drawer/showcase.ts +111 -0
  12. package/s/_archive/components/drawer/style.css.ts +127 -0
  13. package/s/{ui → _archive/components}/example/component.ts +6 -4
  14. package/s/_archive/components/example/showcase.ts +32 -0
  15. package/s/{ui → _archive/components}/example/style.css.ts +2 -2
  16. package/s/_archive/components/foundation.css.ts +15 -0
  17. package/s/{ui → _archive/components}/framework.ts +1 -2
  18. package/s/_archive/components/raw-components.ts +15 -0
  19. package/s/_archive/components/tabs/component.ts +70 -0
  20. package/s/_archive/components/tabs/control.ts +31 -0
  21. package/s/_archive/components/tabs/showcase.ts +171 -0
  22. package/s/_archive/components/tabs/style.css.ts +46 -0
  23. package/s/_archive/demo/demo.bundle.ts +47 -0
  24. package/s/{demo → _archive/demo}/demo.css +1 -0
  25. package/s/_archive/demo/lipsum.ts +6 -0
  26. package/s/_archive/demo/utils/lipsum.ts +19 -0
  27. package/s/_archive/demo/views/exhibit/style.css.ts +85 -0
  28. package/s/_archive/demo/views/exhibit/view.ts +61 -0
  29. package/s/_archive/demo/views/showcase/style.css.ts +53 -0
  30. package/s/_archive/demo/views/showcase/view.ts +54 -0
  31. package/s/_archive/demo/viewsets.ts +12 -0
  32. package/s/_archive/index.html.ts +34 -0
  33. package/s/_archive/index.ts +19 -0
  34. package/s/_archive/install/aura.bundle.ts +9 -0
  35. package/s/_archive/install/plain.bundle.ts +9 -0
  36. package/s/{shiny.ts → _archive/shiny.ts} +2 -2
  37. package/s/_archive/themes/aura.css.ts +86 -0
  38. package/s/_archive/themes/index.barrel.ts +4 -0
  39. package/s/{themes → _archive/themes}/index.ts +1 -0
  40. package/s/_archive/themes/infra/css-vars.ts +46 -0
  41. package/s/_archive/themes/plain.css.ts +11 -0
  42. package/s/_archive/utils/states.ts +15 -0
  43. package/s/demo/globals.d.ts +3 -0
  44. package/s/demo/main.bundle.ts +16 -0
  45. package/s/demo/main.css +71 -0
  46. package/s/demo/parts/exhibit.ts +15 -0
  47. package/s/demo/utils/lipsum.ts +19 -0
  48. package/s/demo/views/codebox/style.css.ts +45 -0
  49. package/s/demo/views/codebox/use-prism-styles.ts +13 -0
  50. package/s/demo/views/codebox/view.ts +39 -0
  51. package/s/demo/views/showcase/style.css.ts +80 -0
  52. package/s/demo/views/showcase/view.ts +50 -0
  53. package/s/demo/views/stylebox/view.ts +21 -0
  54. package/s/icons/tabler/menu-2.svg.ts +4 -0
  55. package/s/icons/tabler/x.svg.ts +4 -0
  56. package/s/index.html.ts +42 -32
  57. package/s/index.ts +6 -7
  58. package/s/test.ts +5 -0
  59. package/s/theme/parts/core.ts +34 -0
  60. package/s/theme/parts/reset.ts +20 -0
  61. package/s/theme/parts/vars.ts +41 -0
  62. package/s/theme/theme-string.ts +15 -0
  63. package/s/theme/theme.css.ts +7 -0
  64. package/s/utils/states.ts +15 -0
  65. package/s/views/button/showcase.ts +43 -0
  66. package/s/views/button/style.css.ts +110 -0
  67. package/s/views/button/view.ts +32 -0
  68. package/s/views/copy/parts/copy-status.ts +3 -0
  69. package/s/views/copy/parts/determine-base-status.ts +7 -0
  70. package/s/views/copy/parts/use-copier.ts +20 -0
  71. package/s/views/copy/showcase.ts +54 -0
  72. package/s/views/copy/style.css.ts +51 -0
  73. package/s/views/copy/view.ts +60 -0
  74. package/s/views/drawer/control.ts +31 -0
  75. package/s/views/drawer/showcase.ts +83 -0
  76. package/s/views/drawer/style.css.ts +128 -0
  77. package/s/views/drawer/view.ts +76 -0
  78. package/s/views/tabs/control.ts +31 -0
  79. package/s/views/tabs/showcase.ts +89 -0
  80. package/s/views/tabs/style.css.ts +46 -0
  81. package/s/views/tabs/view.ts +66 -0
  82. package/x/{demo → _archive/demo}/demo.css +1 -0
  83. package/x/demo/main.bundle.js +13 -0
  84. package/x/demo/main.bundle.js.map +1 -0
  85. package/x/demo/main.bundle.min.js +811 -0
  86. package/x/demo/main.bundle.min.js.map +7 -0
  87. package/x/demo/main.css +71 -0
  88. package/x/demo/parts/exhibit.d.ts +11 -0
  89. package/x/demo/parts/exhibit.js +2 -0
  90. package/x/demo/parts/exhibit.js.map +1 -0
  91. package/x/demo/utils/lipsum.d.ts +2 -0
  92. package/x/demo/utils/lipsum.js +11 -0
  93. package/x/demo/utils/lipsum.js.map +1 -0
  94. package/x/demo/views/codebox/style.css.js +44 -0
  95. package/x/demo/views/codebox/style.css.js.map +1 -0
  96. package/x/demo/views/codebox/use-prism-styles.d.ts +1 -0
  97. package/x/demo/views/codebox/use-prism-styles.js +12 -0
  98. package/x/demo/views/codebox/use-prism-styles.js.map +1 -0
  99. package/x/demo/views/codebox/view.d.ts +2 -0
  100. package/x/demo/views/codebox/view.js +29 -0
  101. package/x/demo/views/codebox/view.js.map +1 -0
  102. package/x/demo/views/showcase/style.css.js +79 -0
  103. package/x/demo/views/showcase/style.css.js.map +1 -0
  104. package/x/demo/views/showcase/view.d.ts +2 -0
  105. package/x/demo/views/showcase/view.js +44 -0
  106. package/x/demo/views/showcase/view.js.map +1 -0
  107. package/x/demo/views/stylebox/view.d.ts +3 -0
  108. package/x/demo/views/stylebox/view.js +13 -0
  109. package/x/demo/views/stylebox/view.js.map +1 -0
  110. package/x/icons/tabler/menu-2.svg.d.ts +2 -0
  111. package/x/icons/tabler/menu-2.svg.js +3 -0
  112. package/x/icons/tabler/menu-2.svg.js.map +1 -0
  113. package/x/icons/tabler/x.svg.d.ts +2 -0
  114. package/x/icons/tabler/x.svg.js +3 -0
  115. package/x/icons/tabler/x.svg.js.map +1 -0
  116. package/x/index.d.ts +6 -5
  117. package/x/index.html +212 -61
  118. package/x/index.html.js +40 -29
  119. package/x/index.html.js.map +1 -1
  120. package/x/index.js +6 -5
  121. package/x/index.js.map +1 -1
  122. package/x/test.js +3 -0
  123. package/x/test.js.map +1 -0
  124. package/x/theme/parts/core.d.ts +1 -0
  125. package/x/theme/parts/core.js +33 -0
  126. package/x/theme/parts/core.js.map +1 -0
  127. package/x/theme/parts/reset.d.ts +1 -0
  128. package/x/theme/parts/reset.js +19 -0
  129. package/x/theme/parts/reset.js.map +1 -0
  130. package/x/theme/parts/vars.d.ts +1 -0
  131. package/x/theme/parts/vars.js +34 -0
  132. package/x/theme/parts/vars.js.map +1 -0
  133. package/x/theme/theme-string.d.ts +1 -0
  134. package/x/theme/theme-string.js +14 -0
  135. package/x/theme/theme-string.js.map +1 -0
  136. package/x/theme/theme.css.d.ts +1 -0
  137. package/x/theme/theme.css.js +4 -0
  138. package/x/theme/theme.css.js.map +1 -0
  139. package/x/utils/states.d.ts +5 -0
  140. package/x/utils/states.js +13 -0
  141. package/x/utils/states.js.map +1 -0
  142. package/x/views/button/showcase.d.ts +1 -0
  143. package/x/views/button/showcase.js +41 -0
  144. package/x/views/button/showcase.js.map +1 -0
  145. package/x/views/button/style.css.js +109 -0
  146. package/x/views/button/style.css.js.map +1 -0
  147. package/x/views/button/view.d.ts +5 -0
  148. package/x/views/button/view.js +23 -0
  149. package/x/views/button/view.js.map +1 -0
  150. package/x/views/copy/parts/copy-status.d.ts +1 -0
  151. package/x/views/copy/parts/copy-status.js +2 -0
  152. package/x/views/copy/parts/copy-status.js.map +1 -0
  153. package/x/views/copy/parts/determine-base-status.d.ts +1 -0
  154. package/x/views/copy/parts/determine-base-status.js +6 -0
  155. package/x/views/copy/parts/determine-base-status.js.map +1 -0
  156. package/x/views/copy/parts/use-copier.d.ts +6 -0
  157. package/x/views/copy/parts/use-copier.js +13 -0
  158. package/x/views/copy/parts/use-copier.js.map +1 -0
  159. package/x/views/copy/showcase.d.ts +1 -0
  160. package/x/views/copy/showcase.js +51 -0
  161. package/x/views/copy/showcase.js.map +1 -0
  162. package/x/views/copy/style.css.d.ts +2 -0
  163. package/x/{ui → views}/copy/style.css.js +14 -9
  164. package/x/views/copy/style.css.js.map +1 -0
  165. package/x/views/copy/view.d.ts +4 -0
  166. package/x/views/copy/view.js +49 -0
  167. package/x/views/copy/view.js.map +1 -0
  168. package/x/views/drawer/control.d.ts +9 -0
  169. package/x/views/drawer/control.js +24 -0
  170. package/x/views/drawer/control.js.map +1 -0
  171. package/x/views/drawer/showcase.d.ts +1 -0
  172. package/x/views/drawer/showcase.js +75 -0
  173. package/x/views/drawer/showcase.js.map +1 -0
  174. package/x/views/drawer/style.css.d.ts +2 -0
  175. package/x/views/drawer/style.css.js +127 -0
  176. package/x/views/drawer/style.css.js.map +1 -0
  177. package/x/views/drawer/view.d.ts +6 -0
  178. package/x/views/drawer/view.js +60 -0
  179. package/x/views/drawer/view.js.map +1 -0
  180. package/x/views/tabs/control.d.ts +9 -0
  181. package/x/views/tabs/control.js +24 -0
  182. package/x/views/tabs/control.js.map +1 -0
  183. package/x/views/tabs/showcase.d.ts +1 -0
  184. package/x/views/tabs/showcase.js +86 -0
  185. package/x/views/tabs/showcase.js.map +1 -0
  186. package/x/views/tabs/style.css.d.ts +2 -0
  187. package/x/views/tabs/style.css.js +45 -0
  188. package/x/views/tabs/style.css.js.map +1 -0
  189. package/x/views/tabs/view.d.ts +5 -0
  190. package/x/views/tabs/view.js +52 -0
  191. package/x/views/tabs/view.js.map +1 -0
  192. package/s/demo/demo.bundle.ts +0 -42
  193. package/s/demo/views/demonstration/style.css.ts +0 -108
  194. package/s/demo/views/demonstration/view.ts +0 -49
  195. package/s/install.bundle.ts +0 -9
  196. package/s/themes/basic.css.ts +0 -18
  197. package/s/themes/index.barrel.ts +0 -3
  198. package/s/ui/raw-components.ts +0 -9
  199. package/x/demo/demo.bundle.js +0 -37
  200. package/x/demo/demo.bundle.js.map +0 -1
  201. package/x/demo/demo.bundle.min.js +0 -277
  202. package/x/demo/demo.bundle.min.js.map +0 -7
  203. package/x/demo/views/demonstration/style.css.js +0 -107
  204. package/x/demo/views/demonstration/style.css.js.map +0 -1
  205. package/x/demo/views/demonstration/view.d.ts +0 -10
  206. package/x/demo/views/demonstration/view.js +0 -36
  207. package/x/demo/views/demonstration/view.js.map +0 -1
  208. package/x/install.bundle.js +0 -5
  209. package/x/install.bundle.js.map +0 -1
  210. package/x/install.bundle.min.js +0 -135
  211. package/x/install.bundle.min.js.map +0 -7
  212. package/x/shiny.d.ts +0 -14
  213. package/x/shiny.js +0 -8
  214. package/x/shiny.js.map +0 -1
  215. package/x/tests.test.d.ts +0 -1
  216. package/x/tests.test.js +0 -3
  217. package/x/tests.test.js.map +0 -1
  218. package/x/themes/basic.css.d.ts +0 -1
  219. package/x/themes/basic.css.js +0 -17
  220. package/x/themes/basic.css.js.map +0 -1
  221. package/x/themes/index.barrel.d.ts +0 -1
  222. package/x/themes/index.barrel.js +0 -2
  223. package/x/themes/index.barrel.js.map +0 -1
  224. package/x/themes/index.d.ts +0 -1
  225. package/x/themes/index.js +0 -2
  226. package/x/themes/index.js.map +0 -1
  227. package/x/ui/copy/component.d.ts +0 -372
  228. package/x/ui/copy/component.js +0 -56
  229. package/x/ui/copy/component.js.map +0 -1
  230. package/x/ui/copy/style.css.js.map +0 -1
  231. package/x/ui/example/component.d.ts +0 -371
  232. package/x/ui/example/component.js +0 -20
  233. package/x/ui/example/component.js.map +0 -1
  234. package/x/ui/example/style.css.js +0 -10
  235. package/x/ui/example/style.css.js.map +0 -1
  236. package/x/ui/framework.d.ts +0 -8
  237. package/x/ui/framework.js +0 -6
  238. package/x/ui/framework.js.map +0 -1
  239. package/x/ui/raw-components.d.ts +0 -6
  240. package/x/ui/raw-components.js +0 -7
  241. package/x/ui/raw-components.js.map +0 -1
  242. /package/s/{tests.test.ts → _archive/tests.test.ts} +0 -0
  243. /package/x/demo/{demo.bundle.d.ts → main.bundle.d.ts} +0 -0
  244. /package/x/demo/views/{demonstration → codebox}/style.css.d.ts +0 -0
  245. /package/x/{ui/copy → demo/views/showcase}/style.css.d.ts +0 -0
  246. /package/x/{install.bundle.d.ts → test.d.ts} +0 -0
  247. /package/x/{ui/example → views/button}/style.css.d.ts +0 -0
@@ -0,0 +1,110 @@
1
+
2
+ import {css} from "lit"
3
+ export default css`@layer view {
4
+
5
+ :host {
6
+ display: inline-flex;
7
+ width: max-content;
8
+ height: max-content;
9
+
10
+ cursor: pointer;
11
+ background: transparent;
12
+ user-select: none;
13
+
14
+ --button-padding: 0.3em 0.7em;
15
+ --button-color: var(--calm);
16
+ }
17
+
18
+ slot {
19
+ z-index: 1;
20
+ position: relative;
21
+ display: block;
22
+ }
23
+
24
+ button {
25
+ opacity: 0.8;
26
+ position: relative;
27
+
28
+ font: inherit;
29
+ cursor: inherit;
30
+ text-shadow: inherit;
31
+ font-weight: medium;
32
+
33
+ display: inline-flex;
34
+ justify-content: center;
35
+ align-items: center;
36
+
37
+ width: 100%;
38
+ height: 100%;
39
+ padding: var(--button-padding);
40
+
41
+ border-radius: 2em;
42
+ background: var(--button-color);
43
+ text-shadow: 0.1em 0.1em 0.1em #0004;
44
+ box-shadow: 0.1em 0.2em 0.3em #0002;
45
+
46
+ color: white;
47
+ border: none;
48
+ background: linear-gradient(
49
+ to bottom right,
50
+ color-mix(in oklab, var(--button-color), white 40%),
51
+ color-mix(in oklab, var(--button-color), black 20%)
52
+ );
53
+
54
+ &::before {
55
+ content: "";
56
+ display: block;
57
+ position: absolute;
58
+ z-index: 0;
59
+ inset: 0.15em;
60
+ border-radius: inherit;
61
+ background: color-mix(in oklab, var(--button-color), #0004 50%);
62
+ }
63
+
64
+ &:not([disabled]):is(:hover, :focus-visible) { opacity: 1; }
65
+ &:not([disabled]):active { opacity: 0.6; }
66
+
67
+ &[data-vibe="lame"] { --button-color: var(--lame); }
68
+ &[data-vibe="angry"] { --button-color: var(--angry); }
69
+ &[data-vibe="zesty"] { --button-color: var(--zesty); }
70
+ &[data-vibe="happy"] { --button-color: var(--happy); }
71
+ &[data-vibe="calm"] { --button-color: var(--calm); }
72
+ &[data-vibe="sad"] { --button-color: var(--sad); }
73
+ &[data-vibe="quirky"] { --button-color: var(--quirky); }
74
+ &[data-vibe="tabbed"] { --button-color: var(--tabbed); }
75
+
76
+ > * {
77
+ position: relative;
78
+ z-index: 1;
79
+ }
80
+
81
+ &[disabled] {
82
+ cursor: default;
83
+ }
84
+
85
+ &[hidden] {
86
+ display: none !important;
87
+ }
88
+ }
89
+
90
+ :host([data-tabbed]) > button {
91
+ opacity: 1;
92
+ filter: brightness(120%);
93
+ }
94
+
95
+ :host(:not([data-tabbed])) > button[disabled] {
96
+ --button-color: var(--lame);
97
+ }
98
+
99
+ :host([data-snug]:not([data-last])) > button {
100
+ border-top-right-radius: 0;
101
+ border-bottom-right-radius: 0;
102
+ }
103
+
104
+ :host([data-snug]:not([data-first])) > button {
105
+ border-top-left-radius: 0;
106
+ border-bottom-left-radius: 0;
107
+ }
108
+
109
+ }`
110
+
@@ -0,0 +1,32 @@
1
+
2
+ import {html} from "lit"
3
+ import {Content, shadow, useCss, useName, useAttrs} from "@e280/sly"
4
+
5
+ import styleCss from "./style.css.js"
6
+ import {themeCss} from "../../theme/theme.css.js"
7
+
8
+ export const ShinyButton = shadow((content?: Content, options: {
9
+ vibe?: "calm" | "lame" | "happy" | "sad" | "angry" | "zesty" | "quirky"
10
+ onClick?: (event: PointerEvent) => void
11
+ } = {}) => {
12
+
13
+ useName("shiny-button")
14
+ useCss(themeCss, styleCss)
15
+
16
+ const attrs = useAttrs({
17
+ hidden: Boolean,
18
+ disabled: Boolean,
19
+ })
20
+
21
+ return html`
22
+ <button
23
+ part=button
24
+ data-vibe="${options.vibe ?? "calm"}"
25
+ ?disabled="${attrs.disabled}"
26
+ ?hidden="${attrs.hidden}"
27
+ @click="${options.onClick}">
28
+ <slot>${content}</slot>
29
+ </button>
30
+ `
31
+ })
32
+
@@ -0,0 +1,3 @@
1
+
2
+ export type CopyStatus = "neutral" | "good" | "bad" | "invalid"
3
+
@@ -0,0 +1,7 @@
1
+
2
+ export function determineBaseStatus(text: string | undefined) {
3
+ return text === undefined
4
+ ? "invalid"
5
+ : "neutral"
6
+ }
7
+
@@ -0,0 +1,20 @@
1
+
2
+ import {debounce} from "@e280/stz"
3
+ import {useOnce, useSignal} from "@e280/sly"
4
+
5
+ import {CopyStatus} from "./copy-status.js"
6
+ import {determineBaseStatus} from "./determine-base-status.js"
7
+
8
+ export function useCopier(text: string | undefined, ms: number) {
9
+ const $status = useSignal<CopyStatus>(determineBaseStatus(text))
10
+
11
+ const reset = useOnce(() => debounce(ms, () => $status.set(determineBaseStatus(text))))
12
+
13
+ const flash = useOnce(() => async(status: CopyStatus) => {
14
+ await $status.set(status)
15
+ await reset()
16
+ })
17
+
18
+ return {reset, flash, status: $status()}
19
+ }
20
+
@@ -0,0 +1,54 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {ShinyCopy} from "./view.js"
4
+ import {exhibit} from "../../demo/parts/exhibit.js"
5
+ import {Showcase} from "../../demo/views/showcase/view.js"
6
+
7
+ export const copyShowcase = () => Showcase("ShinyCopy", [
8
+ exhibit({
9
+ name: "normal",
10
+ explain: "click-to-copy button.",
11
+ render: () => ShinyCopy("hello world"),
12
+ styleboxCss: css`
13
+ :host {
14
+ font-size: 5em;
15
+ }
16
+ `,
17
+ js: `
18
+ ShinyCopy("hello world")
19
+ `,
20
+ css: css`
21
+ [view="shiny-copy"] {
22
+ --shiny-happy: #0fa;
23
+ --shiny-angry: #f50;
24
+ --shiny-lame: #8888;
25
+ --shiny-inactive-opacity: 0.5;
26
+ }
27
+ `,
28
+ }),
29
+
30
+ exhibit({
31
+ name: "fail",
32
+ explain: html`
33
+ <p>click-to-copy button. <em>deliberately fails so you can see.</em></p>
34
+ `,
35
+ render: () => ShinyCopy("hello world", {fail: true}),
36
+ styleboxCss: css`
37
+ :host {
38
+ font-size: 4em;
39
+ }
40
+ `,
41
+ js: `
42
+ ShinyCopy("hello world", {fail: true})
43
+ `,
44
+ css: css`
45
+ [view="shiny-copy"] {
46
+ --shiny-happy: #0fa;
47
+ --shiny-angry: #f50;
48
+ --shiny-lame: #8888;
49
+ --shiny-inactive-opacity: 0.5;
50
+ }
51
+ `,
52
+ }),
53
+ ])
54
+
@@ -0,0 +1,51 @@
1
+
2
+ import {css} from "lit"
3
+ export default css`@layer view {
4
+
5
+ button {
6
+ background: transparent;
7
+ border: none;
8
+ font-size: inherit;
9
+ }
10
+
11
+ button {
12
+ opacity: var(--inactive-opacity);
13
+ display: flex;
14
+ align-items: center;
15
+
16
+ cursor: copy;
17
+ color: inherit;
18
+ transition: all var(--anim-duration) linear;
19
+
20
+ &:is(:hover, :focus-visible) {
21
+ opacity: 1;
22
+ }
23
+
24
+ > span {
25
+ display: flex;
26
+ }
27
+ }
28
+
29
+ [data-status="invalid"] {
30
+ color: var(--lame);
31
+ }
32
+
33
+ [data-status="good"] {
34
+ opacity: 1;
35
+ color: var(--happy);
36
+ filter: drop-shadow(0 0 0.3em color-mix(in oklab, transparent, currentColor 50%));
37
+ }
38
+
39
+ [data-status="bad"] {
40
+ opacity: 1;
41
+ color: var(--angry);
42
+ filter: drop-shadow(0 0 0.3em color-mix(in oklab, transparent, currentColor 50%));
43
+ }
44
+
45
+ svg {
46
+ width: 1em;
47
+ height: 1em;
48
+ }
49
+
50
+ }`
51
+
@@ -0,0 +1,60 @@
1
+
2
+ import {html} from "lit"
3
+ import {shadow, useCss, useName} from "@e280/sly"
4
+
5
+ import styleCss from "./style.css.js"
6
+ import clipboardSvg from "../../icons/tabler/clipboard.svg.js"
7
+ import clipboardXFilledSvg from "../../icons/tabler/clipboard-x-filled.svg.js"
8
+ import clipboardCheckFilledSvg from "../../icons/tabler/clipboard-check-filled.svg.js"
9
+
10
+ import {useCopier} from "./parts/use-copier.js"
11
+ import {themeCss} from "../../theme/theme.css.js"
12
+
13
+ export const ShinyCopy = shadow((
14
+ text: string | undefined,
15
+ options: {ms?: number, fail?: boolean} = {},
16
+ ) => {
17
+
18
+ useName("shiny-copy")
19
+ useCss(themeCss, styleCss)
20
+ const copier = useCopier(text, options.ms ?? 1000)
21
+
22
+ async function click() {
23
+ if (text === undefined) return
24
+ try {
25
+ if (options.fail)
26
+ throw new Error("copy failed on purpose for testing purposes")
27
+ await navigator.clipboard.writeText(text)
28
+ await copier.flash("good")
29
+ }
30
+ catch (error) {
31
+ console.error(error)
32
+ await copier.flash("bad")
33
+ }
34
+ }
35
+
36
+ return html`
37
+ <button data-status="${copier.status}" @click="${click}" part=button>
38
+ <span part=icon>
39
+ ${(() => {switch (copier.status) {
40
+ case "neutral":
41
+ return clipboardSvg
42
+
43
+ case "invalid":
44
+ return clipboardSvg
45
+
46
+ case "good":
47
+ return clipboardCheckFilledSvg
48
+
49
+ case "bad":
50
+ return clipboardXFilledSvg
51
+
52
+ default:
53
+ throw new Error(`unknown copy status`)
54
+ }})()}
55
+ </span>
56
+ <slot></slot>
57
+ </button>
58
+ `
59
+ })
60
+
@@ -0,0 +1,31 @@
1
+
2
+ import {signal} from "@e280/strata"
3
+
4
+ export class DrawerControl {
5
+ $open = signal(false)
6
+
7
+ constructor(startOpen = false) {
8
+ if (startOpen) this.$open.set(true)
9
+ }
10
+
11
+ get isOpen() {
12
+ return this.$open.get()
13
+ }
14
+
15
+ async setOpen(value: boolean) {
16
+ return this.$open.set(value)
17
+ }
18
+
19
+ open = async() => {
20
+ await this.setOpen(true)
21
+ }
22
+
23
+ close = async() => {
24
+ await this.setOpen(false)
25
+ }
26
+
27
+ toggle = async() => {
28
+ return this.setOpen(!this.isOpen)
29
+ }
30
+ }
31
+
@@ -0,0 +1,83 @@
1
+
2
+ import {css, html} from "lit"
3
+ import {ShinyDrawer} from "./view.js"
4
+ import {lipsum} from "../../demo/utils/lipsum.js"
5
+ import {exhibit} from "../../demo/parts/exhibit.js"
6
+ import {Showcase} from "../../demo/views/showcase/view.js"
7
+
8
+ const styleboxCss = css`
9
+ :host {
10
+ font-size: 1em;
11
+ width: 100%;
12
+ min-height: 100%;
13
+ }
14
+ p + p {
15
+ margin-top: var(--padding);
16
+ }
17
+ `
18
+
19
+ const customCss = css`
20
+ [slot=plate] { padding-top: 2em; }
21
+ [view="shiny-drawer"] {
22
+ --slate-bg: color-mix(in oklch, var(--calm), #444);
23
+ &::part(slate) { padding: 1em; }
24
+ &:state(left)::part(slate) { border-bottom-right-radius: 0.5em; }
25
+ &:state(right)::part(slate) { border-bottom-left-radius: 0.5em; }
26
+ }
27
+ `
28
+
29
+ const render = (side: "left" | "right") => (
30
+ ShinyDrawer.with({
31
+ props: [{button: true, side}],
32
+ children: html`
33
+ <header>${lipsum.takeFirst()}</header>
34
+ <section slot=plate>
35
+ <p>${lipsum.takeFirst()}</p>
36
+ <p>${lipsum.takeFirst()}</p>
37
+ </section>
38
+ `,
39
+ })
40
+ )
41
+
42
+ export const drawerShowcase = () => Showcase("ShinyDrawer", [
43
+ exhibit({
44
+ name: "left",
45
+ explain: "slide-out panel. button optional.",
46
+ styleboxCss,
47
+ css: customCss,
48
+ render: () => render("left"),
49
+ js: `
50
+ ShinyDrawer.with({
51
+ props: [{button: true, side: "left"}],
52
+ children: html\`
53
+ <header>lorem kettlebell..</header>
54
+ <section slot=plate>
55
+ <p>lorem protein..</p>
56
+ <p>lorem caffeine..</p>
57
+ </section>
58
+ \`,
59
+ })
60
+ `,
61
+ }),
62
+
63
+ exhibit({
64
+ name: "right",
65
+ explain: "slide-out panel. button optional.",
66
+ styleboxCss,
67
+ css: customCss,
68
+ render: () => render("right"),
69
+ js: `
70
+ ShinyDrawer.with({
71
+ props: [{button: true, side: "right"}],
72
+ children: html\`
73
+ <header>lorem kettlebell..</header>
74
+ <section slot=plate>
75
+ <p>lorem protein..</p>
76
+ <p>lorem caffeine..</p>
77
+ </section>
78
+ \`,
79
+ })
80
+ `,
81
+ }),
82
+ ])
83
+
@@ -0,0 +1,128 @@
1
+
2
+ import {css} from "lit"
3
+ export default css`@layer view {
4
+
5
+ :host {
6
+ display: block;
7
+ width: 100%;
8
+ height: 100%;
9
+
10
+ --slate-bg: transparent;
11
+ --button-size: 2em;
12
+ --blanket-backdrop-filter: blur(0.5em);
13
+ --slate-hidden-opacity: 1;
14
+ --blanket-bg: color-mix(in oklab, transparent, var(--bg));
15
+ }
16
+
17
+ .shell {
18
+ position: relative;
19
+ width: 100%;
20
+ height: 100%;
21
+
22
+ [part="blanket"] {
23
+ opacity: 0;
24
+
25
+ content: "";
26
+ display: block;
27
+ position: absolute;
28
+ inset: 0;
29
+
30
+ background: var(--blanket-bg);
31
+ backdrop-filter: var(--blanket-backdrop-filter);
32
+
33
+ will-change: opacity;
34
+ transition: all var(--anim-duration) ease;
35
+ }
36
+
37
+ .clipper {
38
+ pointer-events: none;
39
+ position: absolute;
40
+ inset: 0;
41
+ width: 100%;
42
+ height: 100%;
43
+ overflow: hidden;
44
+ > * { pointer-events: all; }
45
+ }
46
+
47
+ [part="tray"] {
48
+ position: absolute;
49
+ top: 0;
50
+ width: calc(100% - var(--button-size));
51
+
52
+ display: flex;
53
+ flex-direction: column;
54
+ height: auto;
55
+ max-height: 100%;
56
+
57
+ transform: translateX(-100%);
58
+ will-change: opacity, transform;
59
+ transition: all var(--anim-duration) ease;
60
+
61
+ > [part="slate"] {
62
+ opacity: var(--slate-hidden-opacity);
63
+ will-change: opacity;
64
+ transition: opacity var(--anim-duration) ease;
65
+
66
+ display: block;
67
+ height: 100%;
68
+ overflow-y: auto;
69
+ background: var(--slate-bg);
70
+ }
71
+
72
+ > button {
73
+ position: absolute;
74
+ top: 0;
75
+ left: 100%;
76
+
77
+ opacity: var(--inactive-opacity);
78
+ background: transparent;
79
+ border: none;
80
+ cursor: pointer;
81
+
82
+ &:is(:hover, :focus-visible) {
83
+ opacity: 1;
84
+ }
85
+
86
+ > slot {
87
+ display: contents;
88
+ }
89
+
90
+ svg {
91
+ width: var(--button-size);
92
+ height: var(--button-size);
93
+ }
94
+ }
95
+ }
96
+
97
+ &[data-side="right"] {
98
+ [part="tray"] {
99
+ right: 0;
100
+ transform: translateX(100%);
101
+ > button {
102
+ left: unset;
103
+ right: 100%;
104
+ }
105
+ }
106
+ }
107
+
108
+ slot[name="plate"] {
109
+ display: block;
110
+ width: 100%;
111
+ height: 100%;
112
+ }
113
+
114
+ &[data-open] {
115
+ [part="blanket"] {
116
+ opacity: 1;
117
+ }
118
+ [part="tray"] {
119
+ transform: translateX(0%);
120
+ > [part="slate"] {
121
+ opacity: 1;
122
+ }
123
+ }
124
+ }
125
+ }
126
+
127
+ }`
128
+
@@ -0,0 +1,76 @@
1
+
2
+ import {html} from "lit"
3
+ import {dom, shadow, useAttrs, useCss, useHost, useMount, useName, useOnce} from "@e280/sly"
4
+
5
+ import styleCss from "./style.css.js"
6
+
7
+ import {themeCss} from "../../theme/theme.css.js"
8
+ import {DrawerControl} from "./control.js"
9
+ import {States} from "../../utils/states.js"
10
+ import xSvg from "../../icons/tabler/x.svg.js"
11
+ import menu2Svg from "../../icons/tabler/menu-2.svg.js"
12
+
13
+ export const ShinyDrawer = shadow((options: {
14
+ button?: boolean
15
+ side?: "left" | "right"
16
+ control?: DrawerControl
17
+ } = {}) => {
18
+
19
+ useName("shiny-drawer")
20
+ useCss(themeCss, styleCss)
21
+
22
+ const host = useHost()
23
+ const states = useOnce(() => new States(host))
24
+ const control = useOnce(() => (options.control ?? new DrawerControl()))
25
+
26
+ const attrs = useAttrs({
27
+ side: String,
28
+ button: Boolean,
29
+ open: Boolean,
30
+ })
31
+
32
+ attrs.open = control.isOpen
33
+
34
+ const button = options.button ?? attrs.button
35
+ const side = options.side ?? (attrs.side === "right" ? "right" : "left")
36
+ states.assign(side, control.isOpen ? "opened" : "closed")
37
+
38
+ useMount(() => dom.events(window, {keydown: (event: KeyboardEvent) => {
39
+ if (event.code === "Escape")
40
+ control.close()
41
+ }}))
42
+
43
+ function renderButton() {
44
+ return html`
45
+ <button part=button @click="${control.toggle}">
46
+ ${control.isOpen
47
+ ? html`
48
+ <slot name=button-x>
49
+ ${xSvg}
50
+ </slot>
51
+ `
52
+ : html`
53
+ <slot name=button>
54
+ ${menu2Svg}
55
+ </slot>
56
+ `}
57
+ </button>
58
+ `
59
+ }
60
+
61
+ return html`
62
+ <div class=shell ?data-open="${control.isOpen}" data-side="${side}">
63
+ <slot name=plate ?inert="${control.isOpen}"></slot>
64
+
65
+ <div class=clipper>
66
+ <div part=blanket @click="${control.close}" ?inert="${!control.isOpen}"></div>
67
+
68
+ <div part=tray>
69
+ <slot part=slate ?inert="${!control.isOpen}"></slot>
70
+ ${button ?renderButton() :null}
71
+ </div>
72
+ </div>
73
+ </div>
74
+ `
75
+ })
76
+
@@ -0,0 +1,31 @@
1
+
2
+ import {signal} from "@e280/strata"
3
+
4
+ export class TabsControl {
5
+ length = 1
6
+ $index = signal(0)
7
+
8
+ constructor(start = 0) {
9
+ this.$index.value = start
10
+ }
11
+
12
+ clamp(index: number) {
13
+ index = Math.min(index, this.length - 1)
14
+ index = Math.max(index, 0)
15
+ return index
16
+ }
17
+
18
+ get index() {
19
+ return this.clamp(this.$index())
20
+ }
21
+
22
+ async setIndex(index: number) {
23
+ return this.$index(index)
24
+ }
25
+
26
+ async shimmy(delta: number) {
27
+ const index = this.clamp(this.index + delta)
28
+ return this.setIndex(index)
29
+ }
30
+ }
31
+