@grantcodes/ui 2.15.7 → 2.16.0

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 (300) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/custom-elements.json +476 -346
  3. package/package.json +23 -23
  4. package/src/components/accordion/accordion-item.component.js +17 -19
  5. package/src/components/accordion/accordion-item.css +40 -44
  6. package/src/components/accordion/accordion.component.js +7 -7
  7. package/src/components/accordion/accordion.css +5 -5
  8. package/src/components/accordion/accordion.js +6 -6
  9. package/src/components/accordion/accordion.react.js +6 -6
  10. package/src/components/accordion/accordion.stories.js +10 -10
  11. package/src/components/accordion/accordion.test.js +100 -100
  12. package/src/components/accordion/index.js +6 -6
  13. package/src/components/app-bar/app-bar.component.js +86 -92
  14. package/src/components/app-bar/app-bar.css +187 -203
  15. package/src/components/app-bar/app-bar.js +3 -3
  16. package/src/components/app-bar/app-bar.react.js +9 -9
  17. package/src/components/app-bar/app-bar.stories.js +20 -20
  18. package/src/components/app-bar/app-bar.test.js +190 -237
  19. package/src/components/app-bar/index.js +1 -1
  20. package/src/components/app-bar/nav-link.component.js +7 -9
  21. package/src/components/app-bar/nav-link.css +23 -28
  22. package/src/components/app-bar/nav-link.js +3 -3
  23. package/src/components/app-bar/nav-link.react.js +6 -6
  24. package/src/components/avatar/avatar.component.js +79 -68
  25. package/src/components/avatar/avatar.css +18 -18
  26. package/src/components/avatar/avatar.js +3 -3
  27. package/src/components/avatar/avatar.react.js +6 -6
  28. package/src/components/avatar/avatar.stories.js +24 -23
  29. package/src/components/avatar/avatar.test.js +128 -84
  30. package/src/components/avatar/index.js +1 -1
  31. package/src/components/badge/badge.component.js +23 -23
  32. package/src/components/badge/badge.css +39 -52
  33. package/src/components/badge/badge.js +3 -3
  34. package/src/components/badge/badge.react.js +6 -6
  35. package/src/components/badge/badge.stories.js +23 -23
  36. package/src/components/badge/badge.test.js +53 -68
  37. package/src/components/badge/index.js +1 -1
  38. package/src/components/breadcrumb/breadcrumb.component.js +95 -96
  39. package/src/components/breadcrumb/breadcrumb.css +42 -44
  40. package/src/components/breadcrumb/breadcrumb.js +6 -9
  41. package/src/components/breadcrumb/breadcrumb.react.js +9 -12
  42. package/src/components/breadcrumb/breadcrumb.stories.js +5 -5
  43. package/src/components/breadcrumb/breadcrumb.test.js +139 -151
  44. package/src/components/breadcrumb/index.js +1 -1
  45. package/src/components/button/button.component.js +101 -103
  46. package/src/components/button/button.css +90 -94
  47. package/src/components/button/button.js +3 -3
  48. package/src/components/button/button.react.js +6 -6
  49. package/src/components/button/button.stories.js +25 -25
  50. package/src/components/button/button.test.js +324 -344
  51. package/src/components/button/index.js +1 -1
  52. package/src/components/button-group/button-group.component.js +18 -18
  53. package/src/components/button-group/button-group.css +16 -16
  54. package/src/components/button-group/button-group.js +3 -3
  55. package/src/components/button-group/button-group.react.js +6 -6
  56. package/src/components/button-group/button-group.stories.js +23 -23
  57. package/src/components/button-group/button-group.test.js +54 -54
  58. package/src/components/button-group/index.js +1 -1
  59. package/src/components/card/card.component.js +31 -33
  60. package/src/components/card/card.css +85 -85
  61. package/src/components/card/card.js +4 -4
  62. package/src/components/card/card.react.js +6 -6
  63. package/src/components/card/card.stories.js +27 -26
  64. package/src/components/card/card.test.js +56 -56
  65. package/src/components/card/index.js +1 -1
  66. package/src/components/code-preview/code-preview.component.js +47 -48
  67. package/src/components/code-preview/code-preview.css +11 -11
  68. package/src/components/code-preview/code-preview.js +3 -3
  69. package/src/components/code-preview/code-preview.react.js +6 -6
  70. package/src/components/code-preview/code-preview.stories.js +29 -29
  71. package/src/components/code-preview/code-preview.test.js +112 -135
  72. package/src/components/code-preview/index.js +1 -1
  73. package/src/components/container/container.component.js +27 -27
  74. package/src/components/container/container.css +22 -22
  75. package/src/components/container/container.js +3 -3
  76. package/src/components/container/container.react.js +6 -6
  77. package/src/components/container/container.stories.js +44 -44
  78. package/src/components/container/container.test.js +54 -66
  79. package/src/components/container/index.js +1 -1
  80. package/src/components/countdown/countdown.component.js +160 -162
  81. package/src/components/countdown/countdown.css +50 -34
  82. package/src/components/countdown/countdown.js +3 -3
  83. package/src/components/countdown/countdown.react.js +6 -6
  84. package/src/components/countdown/countdown.stories.js +34 -34
  85. package/src/components/countdown/index.js +1 -1
  86. package/src/components/cta/cta.component.js +77 -81
  87. package/src/components/cta/cta.css +24 -24
  88. package/src/components/cta/cta.js +3 -3
  89. package/src/components/cta/cta.react.js +6 -6
  90. package/src/components/cta/cta.stories.js +32 -32
  91. package/src/components/cta/index.js +1 -1
  92. package/src/components/dialog/dialog.component.js +95 -58
  93. package/src/components/dialog/dialog.css +45 -50
  94. package/src/components/dialog/dialog.js +3 -3
  95. package/src/components/dialog/dialog.react.js +6 -6
  96. package/src/components/dialog/dialog.stories.js +38 -29
  97. package/src/components/dialog/dialog.test.js +188 -102
  98. package/src/components/dialog/index.js +1 -1
  99. package/src/components/dropdown/dropdown.component.js +220 -201
  100. package/src/components/dropdown/dropdown.css +60 -84
  101. package/src/components/dropdown/dropdown.js +6 -9
  102. package/src/components/dropdown/dropdown.react.js +15 -15
  103. package/src/components/dropdown/dropdown.stories.js +10 -10
  104. package/src/components/dropdown/dropdown.test.js +211 -157
  105. package/src/components/dropdown/index.js +1 -1
  106. package/src/components/dropzone/dropzone.component.js +126 -129
  107. package/src/components/dropzone/dropzone.css +35 -37
  108. package/src/components/dropzone/dropzone.js +3 -3
  109. package/src/components/dropzone/dropzone.react.js +6 -6
  110. package/src/components/dropzone/dropzone.stories.js +28 -28
  111. package/src/components/dropzone/dropzone.test.js +91 -99
  112. package/src/components/dropzone/index.js +1 -1
  113. package/src/components/feature-list/feature-list.component.js +78 -86
  114. package/src/components/feature-list/feature-list.css +37 -37
  115. package/src/components/feature-list/feature-list.js +3 -3
  116. package/src/components/feature-list/feature-list.react.js +6 -6
  117. package/src/components/feature-list/feature-list.stories.js +86 -90
  118. package/src/components/feature-list/index.js +1 -1
  119. package/src/components/footer/footer-column.component.js +7 -7
  120. package/src/components/footer/footer-column.css +22 -22
  121. package/src/components/footer/footer.component.js +19 -19
  122. package/src/components/footer/footer.css +38 -38
  123. package/src/components/footer/footer.js +8 -8
  124. package/src/components/footer/footer.react.js +9 -9
  125. package/src/components/footer/footer.stories.js +9 -9
  126. package/src/components/footer/footer.test.js +101 -111
  127. package/src/components/footer/index.js +2 -2
  128. package/src/components/form-field/form-field.component.js +167 -125
  129. package/src/components/form-field/form-field.css +24 -24
  130. package/src/components/form-field/form-field.js +3 -3
  131. package/src/components/form-field/form-field.react.js +6 -6
  132. package/src/components/form-field/form-field.stories.js +53 -44
  133. package/src/components/form-field/form-field.test.js +280 -134
  134. package/src/components/form-field/index.js +1 -1
  135. package/src/components/gallery/gallery-image.component.js +30 -30
  136. package/src/components/gallery/gallery-image.js +3 -3
  137. package/src/components/gallery/gallery-image.react.js +6 -6
  138. package/src/components/gallery/gallery.component.js +24 -17
  139. package/src/components/gallery/gallery.css +79 -72
  140. package/src/components/gallery/gallery.js +3 -3
  141. package/src/components/gallery/gallery.react.js +6 -6
  142. package/src/components/gallery/gallery.stories.js +69 -68
  143. package/src/components/gallery/gallery.test.js +95 -88
  144. package/src/components/gallery/index.js +2 -2
  145. package/src/components/hero/hero.component.js +53 -57
  146. package/src/components/hero/hero.css +27 -27
  147. package/src/components/hero/hero.js +3 -3
  148. package/src/components/hero/hero.react.js +6 -6
  149. package/src/components/hero/hero.stories.js +39 -39
  150. package/src/components/hero/index.js +1 -1
  151. package/src/components/icon/icon.component.js +10 -10
  152. package/src/components/icon/icon.css +13 -13
  153. package/src/components/icon/icon.js +4 -4
  154. package/src/components/icon/icon.react.js +6 -6
  155. package/src/components/icon/icon.stories.js +8 -9
  156. package/src/components/icon/icon.test.js +54 -55
  157. package/src/components/icon/index.js +1 -1
  158. package/src/components/loading/index.js +1 -1
  159. package/src/components/loading/loading.component.js +41 -14
  160. package/src/components/loading/loading.css +47 -30
  161. package/src/components/loading/loading.js +4 -4
  162. package/src/components/loading/loading.react.js +6 -6
  163. package/src/components/loading/loading.stories.js +19 -18
  164. package/src/components/loading/loading.test.js +77 -54
  165. package/src/components/logo-cloud/index.js +1 -1
  166. package/src/components/logo-cloud/logo-cloud.component.js +39 -43
  167. package/src/components/logo-cloud/logo-cloud.css +31 -31
  168. package/src/components/logo-cloud/logo-cloud.js +3 -3
  169. package/src/components/logo-cloud/logo-cloud.react.js +6 -6
  170. package/src/components/logo-cloud/logo-cloud.stories.js +80 -80
  171. package/src/components/map/index.js +1 -1
  172. package/src/components/map/map.component.js +103 -107
  173. package/src/components/map/map.css +22 -22
  174. package/src/components/map/map.js +3 -3
  175. package/src/components/map/map.react.js +6 -6
  176. package/src/components/map/map.stories.js +38 -38
  177. package/src/components/media-text/index.js +1 -1
  178. package/src/components/media-text/media-text.component.js +76 -70
  179. package/src/components/media-text/media-text.css +32 -32
  180. package/src/components/media-text/media-text.js +3 -3
  181. package/src/components/media-text/media-text.react.js +6 -6
  182. package/src/components/media-text/media-text.stories.js +45 -45
  183. package/src/components/media-text/media-text.test.js +72 -0
  184. package/src/components/newsletter/index.js +1 -1
  185. package/src/components/newsletter/newsletter.component.js +56 -64
  186. package/src/components/newsletter/newsletter.css +48 -48
  187. package/src/components/newsletter/newsletter.js +3 -3
  188. package/src/components/newsletter/newsletter.react.js +6 -6
  189. package/src/components/newsletter/newsletter.stories.js +35 -35
  190. package/src/components/notice/index.js +1 -1
  191. package/src/components/notice/notice.component.js +66 -55
  192. package/src/components/notice/notice.css +37 -38
  193. package/src/components/notice/notice.js +3 -3
  194. package/src/components/notice/notice.react.js +6 -6
  195. package/src/components/notice/notice.stories.js +54 -53
  196. package/src/components/notice/notice.test.js +210 -156
  197. package/src/components/pagination/index.js +1 -1
  198. package/src/components/pagination/pagination.component.js +44 -44
  199. package/src/components/pagination/pagination.css +6 -6
  200. package/src/components/pagination/pagination.js +4 -4
  201. package/src/components/pagination/pagination.react.js +6 -6
  202. package/src/components/pagination/pagination.stories.js +20 -18
  203. package/src/components/pagination/pagination.test.js +95 -102
  204. package/src/components/person/index.js +1 -1
  205. package/src/components/person/person.component.js +29 -29
  206. package/src/components/person/person.css +17 -17
  207. package/src/components/person/person.js +4 -4
  208. package/src/components/person/person.react.js +6 -6
  209. package/src/components/person/person.stories.js +34 -33
  210. package/src/components/person/person.test.js +55 -68
  211. package/src/components/pricing/index.js +1 -1
  212. package/src/components/pricing/pricing.component.js +58 -70
  213. package/src/components/pricing/pricing.css +65 -65
  214. package/src/components/pricing/pricing.js +3 -3
  215. package/src/components/pricing/pricing.react.js +6 -6
  216. package/src/components/pricing/pricing.stories.js +96 -96
  217. package/src/components/sidebar/index.js +1 -1
  218. package/src/components/sidebar/sidebar.component.js +157 -130
  219. package/src/components/sidebar/sidebar.css +118 -115
  220. package/src/components/sidebar/sidebar.js +4 -4
  221. package/src/components/sidebar/sidebar.react.js +10 -10
  222. package/src/components/sidebar/sidebar.stories.js +10 -10
  223. package/src/components/sidebar/sidebar.test.js +250 -230
  224. package/src/components/stats/index.js +1 -1
  225. package/src/components/stats/stats.component.js +42 -50
  226. package/src/components/stats/stats.css +29 -29
  227. package/src/components/stats/stats.js +3 -3
  228. package/src/components/stats/stats.react.js +6 -6
  229. package/src/components/stats/stats.stories.js +40 -40
  230. package/src/components/tabs/index.js +2 -2
  231. package/src/components/tabs/internal/tabs-button.component.js +16 -27
  232. package/src/components/tabs/internal/tabs-button.js +3 -3
  233. package/src/components/tabs/internal/tabs-button.react.js +6 -6
  234. package/src/components/tabs/internal/tabs-item.component.js +30 -30
  235. package/src/components/tabs/tab.component.js +9 -11
  236. package/src/components/tabs/tab.js +3 -3
  237. package/src/components/tabs/tab.react.js +6 -6
  238. package/src/components/tabs/tabs.component.js +107 -109
  239. package/src/components/tabs/tabs.css +50 -59
  240. package/src/components/tabs/tabs.js +4 -4
  241. package/src/components/tabs/tabs.react.js +6 -6
  242. package/src/components/tabs/tabs.stories.js +23 -22
  243. package/src/components/tabs/tabs.test.js +201 -147
  244. package/src/components/testimonials/index.js +1 -1
  245. package/src/components/testimonials/testimonials.component.js +47 -51
  246. package/src/components/testimonials/testimonials.css +31 -31
  247. package/src/components/testimonials/testimonials.js +3 -3
  248. package/src/components/testimonials/testimonials.react.js +6 -6
  249. package/src/components/testimonials/testimonials.stories.js +49 -51
  250. package/src/components/toast/index.js +1 -1
  251. package/src/components/toast/toast.component.js +217 -148
  252. package/src/components/toast/toast.css +101 -99
  253. package/src/components/toast/toast.js +6 -9
  254. package/src/components/toast/toast.react.js +12 -12
  255. package/src/components/toast/toast.stories.js +75 -49
  256. package/src/components/toast/toast.test.js +260 -221
  257. package/src/components/tooltip/index.js +1 -1
  258. package/src/components/tooltip/tooltip.component.js +56 -49
  259. package/src/components/tooltip/tooltip.css +61 -50
  260. package/src/components/tooltip/tooltip.js +4 -4
  261. package/src/components/tooltip/tooltip.react.js +6 -6
  262. package/src/components/tooltip/tooltip.stories.js +24 -23
  263. package/src/components/tooltip/tooltip.test.js +143 -155
  264. package/src/constructor.test.js +31 -0
  265. package/src/css/base.css +1 -0
  266. package/src/css/colors.stories.js +120 -122
  267. package/src/css/elements/a.css +28 -28
  268. package/src/css/elements/forms/button.css +1 -1
  269. package/src/css/elements/forms/input.css +80 -80
  270. package/src/css/elements/forms/label.css +3 -3
  271. package/src/css/elements/media/image.css +2 -2
  272. package/src/css/elements.stories.js +48 -49
  273. package/src/css/helpers.css +8 -8
  274. package/src/css/layers.stories.js +5 -5
  275. package/src/css/reset.css +102 -102
  276. package/src/css/themes/todomap.css +1 -1
  277. package/src/css/tokens.stories.js +50 -53
  278. package/src/css/typography.css +30 -32
  279. package/src/css/typography.stories.js +92 -92
  280. package/src/css/util/focus-ring.css +12 -20
  281. package/src/css/view-transitions.css +16 -0
  282. package/src/exports.test.js +89 -105
  283. package/src/icons.js +1 -1
  284. package/src/lib/generate-id.js +1 -1
  285. package/src/lib/slot-presence-controller.js +48 -0
  286. package/src/lib/styles/all.css +38 -37
  287. package/src/lib/styles/focus-ring.css +12 -20
  288. package/src/lib/view-transition.js +42 -0
  289. package/src/lib/view-transition.test.js +105 -0
  290. package/src/main.js +29 -29
  291. package/src/pages/agency.stories.js +59 -59
  292. package/src/pages/blog-post.stories.js +48 -48
  293. package/src/pages/saas-landing.stories.js +180 -180
  294. package/src/react.js +44 -44
  295. package/src/react.test.js +42 -51
  296. package/src/test-utils/assert-helpers.js +39 -58
  297. package/src/test-utils/events.js +32 -34
  298. package/src/test-utils/fixture.js +31 -31
  299. package/src/test-utils/index.js +3 -3
  300. package/src/types.d.ts +3 -3
@@ -1,78 +1,76 @@
1
- import { getStorybookHelpers } from "@wc-toolkit/storybook-helpers";
2
- import "./testimonials.js";
1
+ import { getStorybookHelpers } from '@wc-toolkit/storybook-helpers';
2
+ import './testimonials.js';
3
3
 
4
- const { events, args, argTypes } = getStorybookHelpers(
5
- "grantcodes-testimonials",
6
- );
4
+ const { events, args, argTypes } = getStorybookHelpers('grantcodes-testimonials');
7
5
 
8
6
  const meta = {
9
- title: "Blocks/Testimonials",
10
- component: "grantcodes-testimonials",
11
- args,
12
- argTypes,
13
- parameters: {
14
- actions: {
15
- handles: events,
16
- },
17
- layout: "fullscreen",
18
- },
7
+ title: 'Blocks/Testimonials',
8
+ component: 'grantcodes-testimonials',
9
+ args,
10
+ argTypes,
11
+ parameters: {
12
+ actions: {
13
+ handles: events,
14
+ },
15
+ layout: 'fullscreen',
16
+ },
19
17
  };
20
18
 
21
19
  export default meta;
22
20
 
23
21
  const sampleItems = JSON.stringify([
24
- {
25
- quote:
26
- "This component library saved us weeks of design work. The theming system is incredibly flexible.",
27
- name: "Sarah Chen",
28
- role: "Lead Engineer",
29
- company: "Acme Corp",
30
- avatar: "https://i.pravatar.cc/64?img=1",
31
- },
32
- {
33
- quote: "Accessibility out of the box. Our audits pass first time now.",
34
- name: "Marcus Webb",
35
- role: "Frontend Developer",
36
- company: "Globex",
37
- avatar: "https://i.pravatar.cc/64?img=2",
38
- },
39
- {
40
- quote: "The design tokens make it trivial to match our brand guidelines.",
41
- name: "Priya Sharma",
42
- role: "Design Systems Lead",
43
- company: "Initech",
44
- avatar: "https://i.pravatar.cc/64?img=3",
45
- },
22
+ {
23
+ quote:
24
+ 'This component library saved us weeks of design work. The theming system is incredibly flexible.',
25
+ name: 'Sarah Chen',
26
+ role: 'Lead Engineer',
27
+ company: 'Acme Corp',
28
+ avatar: 'https://i.pravatar.cc/64?img=1',
29
+ },
30
+ {
31
+ quote: 'Accessibility out of the box. Our audits pass first time now.',
32
+ name: 'Marcus Webb',
33
+ role: 'Frontend Developer',
34
+ company: 'Globex',
35
+ avatar: 'https://i.pravatar.cc/64?img=2',
36
+ },
37
+ {
38
+ quote: 'The design tokens make it trivial to match our brand guidelines.',
39
+ name: 'Priya Sharma',
40
+ role: 'Design Systems Lead',
41
+ company: 'Initech',
42
+ avatar: 'https://i.pravatar.cc/64?img=3',
43
+ },
46
44
  ]);
47
45
 
48
46
  /**
49
47
  * Default card layout testimonials.
50
48
  */
51
49
  export const Cards = {
52
- args: {
53
- title: "What people are saying",
54
- items: sampleItems,
55
- layout: "cards",
56
- },
50
+ args: {
51
+ title: 'What people are saying',
52
+ items: sampleItems,
53
+ layout: 'cards',
54
+ },
57
55
  };
58
56
 
59
57
  /**
60
58
  * List layout — stacked testimonials with more visual prominence.
61
59
  */
62
60
  export const List = {
63
- args: {
64
- title: "Customer stories",
65
- items: sampleItems,
66
- layout: "list",
67
- },
61
+ args: {
62
+ title: 'Customer stories',
63
+ items: sampleItems,
64
+ layout: 'list',
65
+ },
68
66
  };
69
67
 
70
68
  /**
71
69
  * Testimonials without a section heading.
72
70
  */
73
71
  export const NoHeading = {
74
- args: {
75
- items: sampleItems,
76
- layout: "cards",
77
- },
72
+ args: {
73
+ items: sampleItems,
74
+ layout: 'cards',
75
+ },
78
76
  };
@@ -1 +1 @@
1
- export * from "./toast.js";
1
+ export * from './toast.js';
@@ -1,122 +1,183 @@
1
- import { html, LitElement } from "lit";
2
- import { unsafeHTML } from "lit/directives/unsafe-html.js";
3
- import { classMap } from "lit/directives/class-map.js";
4
- import focusRingStyles from "../../lib/styles/focus-ring.css" with {
5
- type: "css",
6
- };
7
- import toastStyles from "./toast.css" with { type: "css" };
8
- import { GrantCodesIcon } from "../icon/icon.component.js";
9
- import { AlertCircle, Info, CheckCircle2, XCircle, X } from "../../icons.js";
1
+ import { html, LitElement } from 'lit';
2
+ import { classMap } from 'lit/directives/class-map.js';
3
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
4
+ import { AlertCircle, CheckCircle2, Info, X, XCircle } from '../../icons.js';
5
+ import { generateId } from '../../lib/generate-id.js';
6
+ import focusRingStyles from '../../lib/styles/focus-ring.css' with { type: 'css' };
7
+ import {
8
+ canViewTransition,
9
+ prefersReducedMotion,
10
+ startViewTransition,
11
+ } from '../../lib/view-transition.js';
12
+ import { GrantCodesIcon } from '../icon/icon.component.js';
13
+ import toastStyles from './toast.css' with { type: 'css' };
10
14
 
11
15
  const ICONS = {
12
- info: Info,
13
- success: CheckCircle2,
14
- warning: AlertCircle,
15
- error: XCircle,
16
+ info: Info,
17
+ success: CheckCircle2,
18
+ warning: AlertCircle,
19
+ error: XCircle,
16
20
  };
17
21
 
18
22
  export class GrantCodesToast extends LitElement {
19
- static dependencies = { "grancodes-icon": GrantCodesIcon };
20
- static styles = [focusRingStyles, toastStyles];
21
-
22
- static properties = {
23
- variant: { type: String },
24
- title: { type: String },
25
- duration: { type: Number },
26
- position: { type: String },
27
- dismissible: { type: Boolean },
28
- _visible: { type: Boolean, state: true },
29
- };
30
-
31
- constructor() {
32
- super();
33
-
34
- /**
35
- * Visual variant
36
- * @type {'info' | 'success' | 'warning' | 'error'}
37
- */
38
- this.variant = "info";
39
-
40
- /**
41
- * Toast title
42
- * @type {string}
43
- */
44
- this.title = "";
45
-
46
- /**
47
- * Auto-dismiss duration in milliseconds (0 = no auto-dismiss)
48
- * @type {number}
49
- */
50
- this.duration = 5000;
51
-
52
- /**
53
- * Toast position
54
- * @type {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'}
55
- */
56
- this.position = "top-right";
57
-
58
- /**
59
- * Whether toast can be manually dismissed
60
- * @type {boolean}
61
- */
62
- this.dismissible = true;
63
-
64
- /**
65
- * Internal visibility state
66
- * @type {boolean}
67
- */
68
- this._visible = false;
69
-
70
- /**
71
- * Timeout ID for auto-dismiss
72
- * @type {number | null}
73
- */
74
- this._dismissTimeout = null;
75
- }
76
-
77
- connectedCallback() {
78
- super.connectedCallback();
79
- // Show toast after a brief delay for animation
80
- requestAnimationFrame(() => {
81
- this._visible = true;
82
- });
83
-
84
- // Set up auto-dismiss
85
- if (this.duration > 0) {
86
- this._dismissTimeout = setTimeout(() => {
87
- this._handleDismiss();
88
- }, this.duration);
89
- }
90
- }
91
-
92
- disconnectedCallback() {
93
- if (this._dismissTimeout) {
94
- clearTimeout(this._dismissTimeout);
95
- }
96
- super.disconnectedCallback();
97
- }
98
-
99
- _handleDismiss() {
100
- this._visible = false;
101
-
102
- // Remove element after animation completes
103
- setTimeout(() => {
104
- this.dispatchEvent(
105
- new CustomEvent("dismiss", {
106
- bubbles: true,
107
- composed: true,
108
- }),
109
- );
110
- this.remove();
111
- }, 300); // Match animation duration
112
- }
113
-
114
- _renderDismissButton() {
115
- if (!this.dismissible) {
116
- return html``;
117
- }
118
-
119
- return html`
23
+ static dependencies = { 'grancodes-icon': GrantCodesIcon };
24
+ static styles = [focusRingStyles, toastStyles];
25
+
26
+ static properties = {
27
+ variant: { type: String },
28
+ title: { type: String },
29
+ duration: { type: Number },
30
+ position: { type: String },
31
+ dismissible: { type: Boolean },
32
+ _visible: { type: Boolean, state: true },
33
+ };
34
+
35
+ constructor() {
36
+ super();
37
+
38
+ /**
39
+ * Visual variant
40
+ * @type {'info' | 'success' | 'warning' | 'error'}
41
+ */
42
+ this.variant = 'info';
43
+
44
+ /**
45
+ * Toast title
46
+ * @type {string}
47
+ */
48
+ this.title = '';
49
+
50
+ /**
51
+ * Auto-dismiss duration in milliseconds (0 = no auto-dismiss)
52
+ * @type {number}
53
+ */
54
+ this.duration = 5000;
55
+
56
+ /**
57
+ * Toast position
58
+ * @type {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'}
59
+ */
60
+ this.position = 'top-right';
61
+
62
+ /**
63
+ * Whether toast can be manually dismissed
64
+ * @type {boolean}
65
+ */
66
+ this.dismissible = true;
67
+
68
+ /**
69
+ * Internal visibility state
70
+ * @type {boolean}
71
+ */
72
+ this._visible = false;
73
+
74
+ /**
75
+ * Timeout ID for auto-dismiss
76
+ * @type {number | null}
77
+ */
78
+ this._dismissTimeout = null;
79
+
80
+ /**
81
+ * Timeout ID for removing the toast after its exit animation
82
+ * @type {number | null}
83
+ */
84
+ this._removeTimeout = null;
85
+
86
+ /**
87
+ * Guards against dismissing twice (close click plus auto-dismiss)
88
+ * @type {boolean}
89
+ */
90
+ this._removing = false;
91
+
92
+ // A view transition drives the enter and exit where it is available.
93
+ this._useViewTransition = canViewTransition();
94
+ // Per-instance, so two toasts cannot abort each other's view transition.
95
+ this._viewTransitionName = generateId('toast-vt');
96
+ }
97
+
98
+ connectedCallback() {
99
+ super.connectedCallback();
100
+ this.style.setProperty('--toast-vt-name', this._viewTransitionName);
101
+ this.toggleAttribute('data-view-transition', this._useViewTransition);
102
+
103
+ if (this._useViewTransition) {
104
+ startViewTransition(() => {
105
+ this._visible = true;
106
+ return this.updateComplete;
107
+ });
108
+ } else {
109
+ // Let the first paint land at opacity 0 so the CSS transition has somewhere to go.
110
+ requestAnimationFrame(() => {
111
+ this._visible = true;
112
+ });
113
+ }
114
+
115
+ this._startDismissTimer();
116
+ }
117
+
118
+ disconnectedCallback() {
119
+ clearTimeout(this._dismissTimeout);
120
+ clearTimeout(this._removeTimeout);
121
+ super.disconnectedCallback();
122
+ }
123
+
124
+ _startDismissTimer() {
125
+ if (this.duration <= 0) return;
126
+ clearTimeout(this._dismissTimeout);
127
+ this._dismissTimeout = setTimeout(() => this._handleDismiss(), this.duration);
128
+ }
129
+
130
+ // Hover or focus holds the toast open; leaving restarts the full duration.
131
+ _pauseDismiss() {
132
+ clearTimeout(this._dismissTimeout);
133
+ this._dismissTimeout = null;
134
+ }
135
+
136
+ _resumeDismiss() {
137
+ if (!this._visible || this._dismissTimeout !== null) return;
138
+ this._startDismissTimer();
139
+ }
140
+
141
+ _handleDismiss() {
142
+ this._pauseDismiss();
143
+ if (this._removing) return;
144
+ this._removing = true;
145
+
146
+ if (this._useViewTransition) {
147
+ const transition = startViewTransition(() => {
148
+ this._visible = false;
149
+ return this.updateComplete;
150
+ });
151
+ if (transition) {
152
+ transition.finished.then(
153
+ () => this._remove(),
154
+ () => this._remove(),
155
+ );
156
+ return;
157
+ }
158
+ }
159
+
160
+ this._visible = false;
161
+ clearTimeout(this._removeTimeout);
162
+ this._removeTimeout = setTimeout(() => this._remove(), prefersReducedMotion() ? 0 : 300);
163
+ }
164
+
165
+ _remove() {
166
+ this.dispatchEvent(
167
+ new CustomEvent('dismiss', {
168
+ bubbles: true,
169
+ composed: true,
170
+ }),
171
+ );
172
+ this.remove();
173
+ }
174
+
175
+ _renderDismissButton() {
176
+ if (!this.dismissible) {
177
+ return html``;
178
+ }
179
+
180
+ return html`
120
181
  <button
121
182
  type="button"
122
183
  class="toast__close focus-ring"
@@ -126,23 +187,31 @@ export class GrantCodesToast extends LitElement {
126
187
  <grantcodes-icon>${unsafeHTML(X)}</grantcodes-icon>
127
188
  </button>
128
189
  `;
129
- }
130
-
131
- render() {
132
- const icon = ICONS[this.variant];
133
- const classes = classMap({
134
- toast: true,
135
- [`toast--${this.variant}`]: true,
136
- [`toast--${this.position}`]: true,
137
- "toast--visible": this._visible,
138
- });
139
-
140
- return html`
141
- <div class=${classes} role="status" aria-live="polite">
190
+ }
191
+
192
+ render() {
193
+ const icon = ICONS[this.variant];
194
+ const classes = classMap({
195
+ toast: true,
196
+ [`toast--${this.variant}`]: true,
197
+ [`toast--${this.position}`]: true,
198
+ 'toast--visible': this._visible,
199
+ });
200
+
201
+ return html`
202
+ <div
203
+ class=${classes}
204
+ role=${this.variant === 'error' ? 'alert' : 'status'}
205
+ aria-live=${this.variant === 'error' ? 'assertive' : 'polite'}
206
+ @mouseenter=${this._pauseDismiss}
207
+ @mouseleave=${this._resumeDismiss}
208
+ @focusin=${this._pauseDismiss}
209
+ @focusout=${this._resumeDismiss}
210
+ >
142
211
  <grantcodes-icon class="toast__icon">${unsafeHTML(icon)}</grantcodes-icon>
143
212
 
144
213
  <div class="toast__content">
145
- ${this.title ? html`<div class="toast__title">${this.title}</div>` : ""}
214
+ ${this.title ? html`<div class="toast__title">${this.title}</div>` : ''}
146
215
  <div class="toast__message">
147
216
  <slot></slot>
148
217
  </div>
@@ -151,39 +220,39 @@ export class GrantCodesToast extends LitElement {
151
220
  ${this._renderDismissButton()}
152
221
  </div>
153
222
  `;
154
- }
223
+ }
155
224
  }
156
225
 
157
226
  /**
158
227
  * Toast container for managing multiple toasts
159
228
  */
160
229
  export class GrantCodesToastContainer extends LitElement {
161
- static styles = [focusRingStyles, toastStyles];
230
+ static styles = [focusRingStyles, toastStyles];
162
231
 
163
- static properties = {
164
- position: { type: String },
165
- };
232
+ static properties = {
233
+ position: { type: String },
234
+ };
166
235
 
167
- constructor() {
168
- super();
236
+ constructor() {
237
+ super();
169
238
 
170
- /**
171
- * Position of the toast container
172
- * @type {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'}
173
- */
174
- this.position = "top-right";
175
- }
239
+ /**
240
+ * Position of the toast container
241
+ * @type {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'}
242
+ */
243
+ this.position = 'top-right';
244
+ }
176
245
 
177
- render() {
178
- const classes = classMap({
179
- "toast-container": true,
180
- [`toast-container--${this.position}`]: true,
181
- });
246
+ render() {
247
+ const classes = classMap({
248
+ 'toast-container': true,
249
+ [`toast-container--${this.position}`]: true,
250
+ });
182
251
 
183
- return html`
252
+ return html`
184
253
  <div class=${classes}>
185
254
  <slot></slot>
186
255
  </div>
187
256
  `;
188
- }
257
+ }
189
258
  }