@grantcodes/ui 2.0.0-beta.9 → 2.0.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 (314) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +6 -8
  3. package/custom-elements.json +4273 -0
  4. package/package.json +80 -90
  5. package/src/components/app-bar/app-bar.component.js +90 -0
  6. package/src/components/app-bar/app-bar.js +8 -0
  7. package/src/components/app-bar/app-bar.stories.js +84 -0
  8. package/src/components/app-bar/app-bar.styles.js +227 -0
  9. package/src/components/app-bar/app-bar.test.js +174 -0
  10. package/src/components/app-bar/index.js +3 -0
  11. package/src/components/avatar/avatar.component.js +78 -0
  12. package/src/components/avatar/avatar.js +18 -0
  13. package/src/components/avatar/avatar.stories.js +45 -0
  14. package/src/components/avatar/avatar.styles.js +42 -0
  15. package/src/components/avatar/avatar.test.js +85 -0
  16. package/src/components/avatar/index.js +13 -0
  17. package/src/components/badge/badge.component.js +36 -0
  18. package/src/components/badge/badge.js +8 -0
  19. package/src/components/badge/badge.stories.js +46 -0
  20. package/src/components/badge/badge.styles.js +94 -0
  21. package/src/components/badge/badge.test.js +70 -0
  22. package/src/components/badge/index.js +3 -0
  23. package/src/components/breadcrumb/breadcrumb.component.js +110 -0
  24. package/src/components/breadcrumb/breadcrumb.js +12 -0
  25. package/src/components/breadcrumb/breadcrumb.stories.js +25 -0
  26. package/src/components/breadcrumb/breadcrumb.styles.js +96 -0
  27. package/src/components/breadcrumb/breadcrumb.test.js +144 -0
  28. package/src/components/breadcrumb/index.js +3 -0
  29. package/src/components/button/button.component.js +64 -0
  30. package/src/components/button/button.js +6 -0
  31. package/src/components/button/button.stories.js +78 -0
  32. package/src/components/button/button.styles.js +97 -0
  33. package/src/components/button/button.test.js +98 -0
  34. package/src/components/button/index.js +1 -0
  35. package/src/components/button-group/button-group.component.js +27 -0
  36. package/src/components/button-group/button-group.js +6 -0
  37. package/src/components/button-group/button-group.stories.js +33 -0
  38. package/src/components/button-group/button-group.styles.js +43 -0
  39. package/src/components/button-group/button-group.test.js +57 -0
  40. package/src/components/button-group/index.js +1 -0
  41. package/src/components/card/card.component.js +17 -0
  42. package/src/components/card/card.js +6 -0
  43. package/src/components/card/card.stories.js +36 -0
  44. package/src/components/card/card.styles.js +128 -0
  45. package/src/components/card/card.test.js +59 -0
  46. package/src/components/card/index.js +1 -0
  47. package/src/components/code-preview/code-preview.component.js +53 -0
  48. package/src/components/code-preview/code-preview.js +7 -0
  49. package/src/components/code-preview/code-preview.stories.js +67 -0
  50. package/src/components/code-preview/code-preview.styles.js +18 -0
  51. package/src/components/code-preview/code-preview.test.js +118 -0
  52. package/src/components/code-preview/index.js +1 -0
  53. package/src/components/container/container.component.js +38 -0
  54. package/src/components/container/container.js +7 -0
  55. package/src/components/container/container.stories.js +59 -0
  56. package/src/components/container/container.styles.js +43 -0
  57. package/src/components/container/container.test.js +84 -0
  58. package/src/components/container/index.js +1 -0
  59. package/src/components/dialog/dialog.component.js +78 -0
  60. package/src/components/dialog/dialog.js +7 -0
  61. package/src/components/dialog/dialog.stories.js +43 -0
  62. package/src/components/dialog/dialog.styles.js +74 -0
  63. package/src/components/dialog/dialog.test.js +97 -0
  64. package/src/components/dialog/index.js +1 -0
  65. package/src/components/dropdown/dropdown.component.js +225 -0
  66. package/src/components/dropdown/dropdown.js +12 -0
  67. package/src/components/dropdown/dropdown.stories.js +107 -0
  68. package/src/components/dropdown/dropdown.styles.js +128 -0
  69. package/src/components/dropdown/dropdown.test.js +144 -0
  70. package/src/components/dropdown/index.js +3 -0
  71. package/src/components/dropzone/dropzone.component.js +141 -0
  72. package/src/components/dropzone/dropzone.js +6 -0
  73. package/src/components/dropzone/dropzone.stories.js +41 -0
  74. package/src/components/dropzone/dropzone.styles.js +64 -0
  75. package/src/components/dropzone/dropzone.test.js +112 -0
  76. package/src/components/dropzone/index.js +1 -0
  77. package/src/components/footer/footer-column.component.js +15 -0
  78. package/src/components/footer/footer-column.styles.js +51 -0
  79. package/src/components/footer/footer.component.js +38 -0
  80. package/src/components/footer/footer.js +9 -0
  81. package/src/components/footer/footer.stories.js +143 -0
  82. package/src/components/footer/footer.styles.js +90 -0
  83. package/src/components/footer/footer.test.js +107 -0
  84. package/src/components/footer/index.js +2 -0
  85. package/src/components/form-field/form-field.component.js +173 -0
  86. package/src/components/form-field/form-field.js +7 -0
  87. package/src/components/form-field/form-field.stories.js +104 -0
  88. package/src/components/form-field/form-field.styles.js +47 -0
  89. package/src/components/form-field/form-field.test.js +118 -0
  90. package/src/components/form-field/index.js +1 -0
  91. package/src/components/gallery/gallery-image.component.js +52 -0
  92. package/src/components/gallery/gallery-image.js +7 -0
  93. package/src/components/gallery/gallery.component.js +25 -0
  94. package/src/components/gallery/gallery.js +7 -0
  95. package/src/components/gallery/gallery.stories.js +60 -0
  96. package/src/components/gallery/gallery.styles.js +56 -0
  97. package/src/components/gallery/gallery.test.js +58 -0
  98. package/src/components/gallery/index.js +2 -0
  99. package/src/components/icon/icon.component.js +14 -0
  100. package/src/components/icon/icon.js +7 -0
  101. package/src/components/icon/icon.stories.js +26 -0
  102. package/src/components/icon/icon.styles.js +28 -0
  103. package/src/components/icon/icon.test.js +57 -0
  104. package/src/components/icon/index.js +1 -0
  105. package/src/components/loading/index.js +1 -0
  106. package/src/components/loading/loading.component.js +21 -0
  107. package/src/components/loading/loading.js +7 -0
  108. package/src/components/loading/loading.stories.js +25 -0
  109. package/src/components/loading/loading.styles.js +43 -0
  110. package/src/components/loading/loading.test.js +57 -0
  111. package/src/components/notice/index.js +1 -0
  112. package/src/components/notice/notice.component.js +77 -0
  113. package/src/components/notice/notice.js +7 -0
  114. package/src/components/notice/notice.stories.js +122 -0
  115. package/src/components/notice/notice.styles.js +72 -0
  116. package/src/components/notice/notice.test.js +146 -0
  117. package/src/components/pagination/index.js +1 -0
  118. package/src/components/pagination/pagination.component.js +62 -0
  119. package/src/components/pagination/pagination.js +7 -0
  120. package/src/components/pagination/pagination.stories.js +34 -0
  121. package/src/components/pagination/pagination.styles.js +19 -0
  122. package/src/components/pagination/pagination.test.js +98 -0
  123. package/src/components/sidebar/index.js +3 -0
  124. package/src/components/sidebar/sidebar.component.js +165 -0
  125. package/src/components/sidebar/sidebar.js +8 -0
  126. package/src/components/sidebar/sidebar.stories.js +155 -0
  127. package/src/components/sidebar/sidebar.styles.js +192 -0
  128. package/src/components/sidebar/sidebar.test.js +196 -0
  129. package/src/components/tabs/index.js +2 -0
  130. package/src/components/tabs/internal/tabs-button.component.js +39 -0
  131. package/src/components/tabs/internal/tabs-button.js +7 -0
  132. package/src/components/tabs/internal/tabs-item.component.js +39 -0
  133. package/src/components/tabs/tab.component.js +20 -0
  134. package/src/components/tabs/tab.js +7 -0
  135. package/src/components/tabs/tabs.component.js +130 -0
  136. package/src/components/tabs/tabs.js +7 -0
  137. package/src/components/tabs/tabs.stories.js +39 -0
  138. package/src/components/tabs/tabs.styles.js +88 -0
  139. package/src/components/tabs/tabs.test.js +148 -0
  140. package/src/components/toast/index.js +3 -0
  141. package/src/components/toast/toast.component.js +187 -0
  142. package/src/components/toast/toast.js +9 -0
  143. package/src/components/toast/toast.stories.js +169 -0
  144. package/src/components/toast/toast.styles.js +207 -0
  145. package/src/components/toast/toast.test.js +196 -0
  146. package/src/components/tooltip/index.js +1 -0
  147. package/src/components/tooltip/tooltip.component.js +70 -0
  148. package/src/components/tooltip/tooltip.js +7 -0
  149. package/src/components/tooltip/tooltip.stories.js +33 -0
  150. package/src/components/tooltip/tooltip.styles.js +78 -0
  151. package/src/components/tooltip/tooltip.test.js +150 -0
  152. package/src/css/all.css +1 -0
  153. package/src/css/base.css +31 -0
  154. package/src/css/colors.stories.js +192 -0
  155. package/src/css/elements/a.css +50 -0
  156. package/src/css/elements/forms/button.css +15 -0
  157. package/src/css/elements/forms/input.css +183 -0
  158. package/src/css/elements/forms/label.css +5 -0
  159. package/src/css/elements/media/image.css +3 -0
  160. package/src/css/elements.css +5 -0
  161. package/src/css/elements.stories.js +108 -0
  162. package/src/css/helpers.css +16 -0
  163. package/src/css/themes/grantcodes.css +3 -0
  164. package/src/css/themes/todomap.css +2 -0
  165. package/src/css/themes/wireframe.css +2 -0
  166. package/src/css/tokens.stories.js +183 -0
  167. package/src/css/typography.css +64 -0
  168. package/src/css/typography.stories.js +179 -0
  169. package/src/css/util/functions.css +16 -0
  170. package/src/css/util/index.css +2 -0
  171. package/src/css/util/mixins.css +63 -0
  172. package/src/icons.js +3 -0
  173. package/src/lib/classnames.js +61 -0
  174. package/src/lib/generate-id.js +10 -0
  175. package/src/main.js +17 -0
  176. package/src/test-utils/assert-helpers.js +150 -0
  177. package/src/test-utils/events.js +88 -0
  178. package/src/test-utils/fixture.js +77 -0
  179. package/src/test-utils/index.js +7 -0
  180. package/dist/_virtual/_commonjsHelpers.js +0 -1
  181. package/dist/_virtual/index.js +0 -1
  182. package/dist/_virtual/react.production.min.js +0 -1
  183. package/dist/_virtual/react.production.min2.js +0 -1
  184. package/dist/components/avatar/avatar.component.js +0 -3
  185. package/dist/components/avatar/avatar.js +0 -1
  186. package/dist/components/avatar/avatar.react.js +0 -1
  187. package/dist/components/avatar/avatar.scss.js +0 -1
  188. package/dist/components/avatar/index.js +0 -1
  189. package/dist/components/button/button.component.js +0 -5
  190. package/dist/components/button/button.js +0 -1
  191. package/dist/components/button/button.react.js +0 -1
  192. package/dist/components/button/button.scss.js +0 -1
  193. package/dist/components/button/index.js +0 -1
  194. package/dist/components/button-group/button-group.component.js +0 -5
  195. package/dist/components/button-group/button-group.js +0 -1
  196. package/dist/components/button-group/button-group.react.js +0 -1
  197. package/dist/components/button-group/button-group.scss.js +0 -1
  198. package/dist/components/button-group/index.js +0 -1
  199. package/dist/components/card/card.component.js +0 -8
  200. package/dist/components/card/card.js +0 -1
  201. package/dist/components/card/card.react.js +0 -1
  202. package/dist/components/card/card.scss.js +0 -1
  203. package/dist/components/card/index.js +0 -1
  204. package/dist/components/code-preview/code-preview.component.js +0 -3
  205. package/dist/components/code-preview/code-preview.js +0 -1
  206. package/dist/components/code-preview/code-preview.react.js +0 -1
  207. package/dist/components/code-preview/code-preview.scss.js +0 -1
  208. package/dist/components/code-preview/index.js +0 -1
  209. package/dist/components/container/container.component.js +0 -5
  210. package/dist/components/container/container.js +0 -1
  211. package/dist/components/container/container.react.js +0 -1
  212. package/dist/components/container/container.scss.js +0 -1
  213. package/dist/components/container/index.js +0 -1
  214. package/dist/components/dialog/dialog.component.js +0 -23
  215. package/dist/components/dialog/dialog.js +0 -1
  216. package/dist/components/dialog/dialog.react.js +0 -1
  217. package/dist/components/dialog/dialog.scss.js +0 -1
  218. package/dist/components/dialog/index.js +0 -1
  219. package/dist/components/dropzone/dropzone.component.js +0 -11
  220. package/dist/components/dropzone/dropzone.js +0 -1
  221. package/dist/components/dropzone/dropzone.react.js +0 -1
  222. package/dist/components/dropzone/dropzone.scss.js +0 -1
  223. package/dist/components/dropzone/index.js +0 -1
  224. package/dist/components/form-field/form-field.component.js +0 -22
  225. package/dist/components/form-field/form-field.js +0 -1
  226. package/dist/components/form-field/form-field.react.js +0 -1
  227. package/dist/components/form-field/form-field.scss.js +0 -1
  228. package/dist/components/form-field/index.js +0 -1
  229. package/dist/components/gallery/gallery-image.component.js +0 -14
  230. package/dist/components/gallery/gallery-image.js +0 -1
  231. package/dist/components/gallery/gallery.component.js +0 -5
  232. package/dist/components/gallery/gallery.js +0 -1
  233. package/dist/components/gallery/gallery.react.js +0 -1
  234. package/dist/components/gallery/gallery.scss.js +0 -1
  235. package/dist/components/gallery/index.js +0 -1
  236. package/dist/components/icon/icon.component.js +0 -1
  237. package/dist/components/icon/icon.js +0 -1
  238. package/dist/components/icon/icon.react.js +0 -1
  239. package/dist/components/icon/icon.scss.js +0 -1
  240. package/dist/components/icon/index.js +0 -1
  241. package/dist/components/loading/index.js +0 -1
  242. package/dist/components/loading/loading.component.js +0 -5
  243. package/dist/components/loading/loading.js +0 -1
  244. package/dist/components/loading/loading.react.js +0 -1
  245. package/dist/components/loading/loading.scss.js +0 -1
  246. package/dist/components/notice/index.js +0 -1
  247. package/dist/components/notice/notice.component.js +0 -16
  248. package/dist/components/notice/notice.js +0 -1
  249. package/dist/components/notice/notice.react.js +0 -1
  250. package/dist/components/notice/notice.scss.js +0 -1
  251. package/dist/components/pagination/index.js +0 -1
  252. package/dist/components/pagination/pagination.component.js +0 -13
  253. package/dist/components/pagination/pagination.js +0 -1
  254. package/dist/components/pagination/pagination.react.js +0 -1
  255. package/dist/components/pagination/pagination.scss.js +0 -1
  256. package/dist/components/tabs/index.js +0 -1
  257. package/dist/components/tabs/internal/tabs-button.component.js +0 -13
  258. package/dist/components/tabs/internal/tabs-button.js +0 -1
  259. package/dist/components/tabs/internal/tabs-item.component.js +0 -1
  260. package/dist/components/tabs/tab.component.js +0 -10
  261. package/dist/components/tabs/tab.js +0 -1
  262. package/dist/components/tabs/tabs.component.js +0 -22
  263. package/dist/components/tabs/tabs.js +0 -1
  264. package/dist/components/tabs/tabs.react.js +0 -1
  265. package/dist/components/tabs/tabs.scss.js +0 -1
  266. package/dist/components/tooltip/index.js +0 -1
  267. package/dist/components/tooltip/tooltip.component.js +0 -10
  268. package/dist/components/tooltip/tooltip.js +0 -1
  269. package/dist/components/tooltip/tooltip.react.js +0 -1
  270. package/dist/components/tooltip/tooltip.scss.js +0 -1
  271. package/dist/css/base.css +0 -1
  272. package/dist/css/themes/grantcodes.css +0 -1
  273. package/dist/fonts/greycliff-bold-oblique.woff +0 -0
  274. package/dist/fonts/greycliff-bold-oblique.woff2 +0 -0
  275. package/dist/fonts/greycliff-bold.woff +0 -0
  276. package/dist/fonts/greycliff-bold.woff2 +0 -0
  277. package/dist/fonts/greycliff-demi-bold-oblique.woff +0 -0
  278. package/dist/fonts/greycliff-demi-bold-oblique.woff2 +0 -0
  279. package/dist/fonts/greycliff-demi-bold.woff +0 -0
  280. package/dist/fonts/greycliff-demi-bold.woff2 +0 -0
  281. package/dist/fonts/greycliff-extra-bold-oblique.woff +0 -0
  282. package/dist/fonts/greycliff-extra-bold-oblique.woff2 +0 -0
  283. package/dist/fonts/greycliff-extra-bold.woff +0 -0
  284. package/dist/fonts/greycliff-extra-bold.woff2 +0 -0
  285. package/dist/fonts/greycliff-extra-light-oblique.woff +0 -0
  286. package/dist/fonts/greycliff-extra-light-oblique.woff2 +0 -0
  287. package/dist/fonts/greycliff-extra-light.woff +0 -0
  288. package/dist/fonts/greycliff-extra-light.woff2 +0 -0
  289. package/dist/fonts/greycliff-heavy-oblique.woff +0 -0
  290. package/dist/fonts/greycliff-heavy-oblique.woff2 +0 -0
  291. package/dist/fonts/greycliff-heavy.woff +0 -0
  292. package/dist/fonts/greycliff-heavy.woff2 +0 -0
  293. package/dist/fonts/greycliff-light-oblique.woff +0 -0
  294. package/dist/fonts/greycliff-light-oblique.woff2 +0 -0
  295. package/dist/fonts/greycliff-light.woff +0 -0
  296. package/dist/fonts/greycliff-light.woff2 +0 -0
  297. package/dist/fonts/greycliff-medium-oblique.woff +0 -0
  298. package/dist/fonts/greycliff-medium-oblique.woff2 +0 -0
  299. package/dist/fonts/greycliff-medium.woff +0 -0
  300. package/dist/fonts/greycliff-medium.woff2 +0 -0
  301. package/dist/fonts/greycliff-regular-oblique.woff +0 -0
  302. package/dist/fonts/greycliff-regular-oblique.woff2 +0 -0
  303. package/dist/fonts/greycliff-regular.woff +0 -0
  304. package/dist/fonts/greycliff-regular.woff2 +0 -0
  305. package/dist/fonts/greycliff-thin-oblique.woff +0 -0
  306. package/dist/fonts/greycliff-thin-oblique.woff2 +0 -0
  307. package/dist/fonts/greycliff-thin.woff +0 -0
  308. package/dist/fonts/greycliff-thin.woff2 +0 -0
  309. package/dist/icons.js +0 -1
  310. package/dist/lib/generate-id.js +0 -1
  311. package/dist/main.js +0 -1
  312. package/dist/node_modules/react/cjs/react.production.min.js +0 -9
  313. package/dist/node_modules/react/index.js +0 -1
  314. package/dist/react.js +0 -1
@@ -0,0 +1,148 @@
1
+ import { describe, it, afterEach } from "node:test";
2
+ import { strict as assert } from "node:assert";
3
+ import { fixture, cleanup } from "../../test-utils/index.js";
4
+ import "./tabs.js";
5
+ import "./tab.js";
6
+
7
+ describe("Tabs Component", () => {
8
+ let element;
9
+
10
+ afterEach(() => {
11
+ cleanup(element);
12
+ });
13
+
14
+ it("should render with default properties", async () => {
15
+ element = await fixture("grantcodes-tabs");
16
+ assert.ok(element, "Element should be created");
17
+ assert.ok(element.shadowRoot, "Element should have shadow root");
18
+ });
19
+
20
+ it("should have label property", async () => {
21
+ element = await fixture("grantcodes-tabs", {
22
+ label: "Navigation tabs",
23
+ });
24
+
25
+ assert.strictEqual(element.label, "Navigation tabs", "Label should be set");
26
+ });
27
+
28
+ it("should render tabs wrapper", async () => {
29
+ element = await fixture("grantcodes-tabs");
30
+ const tabs = element.shadowRoot.querySelector(".tabs");
31
+ assert.ok(tabs, "Tabs wrapper should exist");
32
+ });
33
+
34
+ it("should render tablist with role", async () => {
35
+ element = await fixture("grantcodes-tabs");
36
+ const tablist = element.shadowRoot.querySelector('[role="tablist"]');
37
+ assert.ok(tablist, "Tablist should exist with role");
38
+ assert.ok(
39
+ tablist.classList.contains("tabs__tablist"),
40
+ "Should have tablist class",
41
+ );
42
+ });
43
+
44
+ it("should render panels container", async () => {
45
+ element = await fixture("grantcodes-tabs");
46
+ const panels = element.shadowRoot.querySelector(".tabs__panels");
47
+ assert.ok(panels, "Panels container should exist");
48
+ });
49
+
50
+ it("should have slot for tab panels", async () => {
51
+ element = await fixture("grantcodes-tabs");
52
+ const slot = element.shadowRoot.querySelector(".tabs__panels slot");
53
+ assert.ok(slot, "Slot should exist for tab panels");
54
+ });
55
+
56
+ it("should generate unique ID", async () => {
57
+ const element1 = await fixture("grantcodes-tabs");
58
+ const element2 = await fixture("grantcodes-tabs");
59
+
60
+ assert.notStrictEqual(element1.id, element2.id, "IDs should be unique");
61
+
62
+ cleanup(element1);
63
+ cleanup(element2);
64
+ });
65
+
66
+ it("should initialize tabs array", async () => {
67
+ element = await fixture("grantcodes-tabs");
68
+ assert.ok(Array.isArray(element.tabs), "Tabs should be an array");
69
+ });
70
+
71
+ it("should initialize tabButtons array", async () => {
72
+ element = await fixture("grantcodes-tabs");
73
+ assert.ok(
74
+ Array.isArray(element.tabButtons),
75
+ "Tab buttons should be an array",
76
+ );
77
+ });
78
+
79
+ it("should have focusedTabIndex property", async () => {
80
+ element = await fixture("grantcodes-tabs");
81
+ // After firstUpdated, if there are tabs, _focusedTabIndex will be set to 0
82
+ // If there are no tabs, it should remain -1
83
+ // Since we're not adding tabs, it should remain -1, but firstUpdated may have run
84
+ // Check that the property exists and is a number
85
+ assert.ok(
86
+ typeof element._focusedTabIndex === "number",
87
+ "Should have focusedTabIndex property",
88
+ );
89
+ });
90
+
91
+ it("should support keyboard navigation", async () => {
92
+ element = await fixture("grantcodes-tabs");
93
+ // The handleTabKeyDown method handles ArrowRight and ArrowLeft
94
+ assert.ok(
95
+ element.handleTabKeyDown,
96
+ "Should have keyboard navigation handler",
97
+ );
98
+ });
99
+
100
+ it("should set aria-label on tablist when label is provided", async () => {
101
+ element = await fixture("grantcodes-tabs", {
102
+ label: "Main navigation",
103
+ });
104
+
105
+ const tablist = element.shadowRoot.querySelector('[role="tablist"]');
106
+ assert.strictEqual(
107
+ tablist.getAttribute("aria-label"),
108
+ "Main navigation",
109
+ "Tablist should have aria-label",
110
+ );
111
+ });
112
+
113
+ it("should manage active tab state", async () => {
114
+ element = await fixture("grantcodes-tabs");
115
+
116
+ // Create and add tab elements
117
+ const tab1 = document.createElement("grantcodes-tab");
118
+ tab1.label = "Tab 1";
119
+ const tab2 = document.createElement("grantcodes-tab");
120
+ tab2.label = "Tab 2";
121
+
122
+ element.appendChild(tab1);
123
+ element.appendChild(tab2);
124
+
125
+ await element.updateComplete;
126
+
127
+ // The tabs are initialized in firstUpdated
128
+ // Check that activeTab getter works
129
+ assert.ok(element.activeTab !== undefined, "Should have activeTab getter");
130
+ });
131
+
132
+ it("should render tab buttons for each tab", async () => {
133
+ element = await fixture("grantcodes-tabs");
134
+
135
+ const tab1 = document.createElement("grantcodes-tab");
136
+ tab1.label = "First";
137
+ const tab2 = document.createElement("grantcodes-tab");
138
+ tab2.label = "Second";
139
+
140
+ element.appendChild(tab1);
141
+ element.appendChild(tab2);
142
+
143
+ await element.updateComplete;
144
+
145
+ // Tab buttons are rendered via renderTabButtons method
146
+ // In a real browser, these would be visible in the shadow DOM
147
+ });
148
+ });
@@ -0,0 +1,3 @@
1
+ export * from "./toast.js";
2
+
3
+
@@ -0,0 +1,187 @@
1
+ import { LitElement } from "lit";
2
+ import { html } from "lit/static-html.js";
3
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
4
+ import { cx } from "../../lib/classnames.js";
5
+ import { toastStyles } from "./toast.styles.js";
6
+ import { GrantCodesIcon } from "../icon/icon.component.js";
7
+ import { AlertCircle, Info, CheckCircle2, XCircle, X } from "../../icons.js";
8
+
9
+ const ICONS = {
10
+ info: Info,
11
+ success: CheckCircle2,
12
+ warning: AlertCircle,
13
+ error: XCircle,
14
+ };
15
+
16
+ export class GrantCodesToast extends LitElement {
17
+ static dependencies = { "grancodes-icon": GrantCodesIcon };
18
+ static styles = [toastStyles];
19
+
20
+ static properties = {
21
+ variant: { type: String },
22
+ title: { type: String },
23
+ duration: { type: Number },
24
+ position: { type: String },
25
+ dismissible: { type: Boolean },
26
+ _visible: { type: Boolean, state: true },
27
+ };
28
+
29
+ constructor() {
30
+ super();
31
+
32
+ /**
33
+ * Visual variant
34
+ * @type {'info' | 'success' | 'warning' | 'error'}
35
+ */
36
+ this.variant = "info";
37
+
38
+ /**
39
+ * Toast title
40
+ * @type {string}
41
+ */
42
+ this.title = "";
43
+
44
+ /**
45
+ * Auto-dismiss duration in milliseconds (0 = no auto-dismiss)
46
+ * @type {number}
47
+ */
48
+ this.duration = 5000;
49
+
50
+ /**
51
+ * Toast position
52
+ * @type {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'}
53
+ */
54
+ this.position = "top-right";
55
+
56
+ /**
57
+ * Whether toast can be manually dismissed
58
+ * @type {boolean}
59
+ */
60
+ this.dismissible = true;
61
+
62
+ /**
63
+ * Internal visibility state
64
+ * @type {boolean}
65
+ */
66
+ this._visible = false;
67
+
68
+ /**
69
+ * Timeout ID for auto-dismiss
70
+ * @type {number | null}
71
+ */
72
+ this._dismissTimeout = null;
73
+ }
74
+
75
+ connectedCallback() {
76
+ super.connectedCallback();
77
+ // Show toast after a brief delay for animation
78
+ requestAnimationFrame(() => {
79
+ this._visible = true;
80
+ });
81
+
82
+ // Set up auto-dismiss
83
+ if (this.duration > 0) {
84
+ this._dismissTimeout = setTimeout(() => {
85
+ this._handleDismiss();
86
+ }, this.duration);
87
+ }
88
+ }
89
+
90
+ disconnectedCallback() {
91
+ if (this._dismissTimeout) {
92
+ clearTimeout(this._dismissTimeout);
93
+ }
94
+ super.disconnectedCallback();
95
+ }
96
+
97
+ _handleDismiss() {
98
+ this._visible = false;
99
+
100
+ // Remove element after animation completes
101
+ setTimeout(() => {
102
+ this.dispatchEvent(
103
+ new CustomEvent("dismiss", {
104
+ bubbles: true,
105
+ composed: true,
106
+ }),
107
+ );
108
+ this.remove();
109
+ }, 300); // Match animation duration
110
+ }
111
+
112
+ _renderDismissButton() {
113
+ if (!this.dismissible) {
114
+ return html``;
115
+ }
116
+
117
+ return html`
118
+ <button
119
+ type="button"
120
+ class="toast__close"
121
+ @click=${this._handleDismiss}
122
+ aria-label="Dismiss notification"
123
+ >
124
+ <grantcodes-icon>${unsafeHTML(X)}</grantcodes-icon>
125
+ </button>
126
+ `;
127
+ }
128
+
129
+ render() {
130
+ const icon = ICONS[this.variant];
131
+ const toastClass = cx("toast", {
132
+ [`toast--${this.variant}`]: true,
133
+ [`toast--${this.position}`]: true,
134
+ "toast--visible": this._visible,
135
+ });
136
+
137
+ return html`
138
+ <div class="${toastClass}" role="status" aria-live="polite">
139
+ <grantcodes-icon class="toast__icon">${unsafeHTML(icon)}</grantcodes-icon>
140
+
141
+ <div class="toast__content">
142
+ ${this.title ? html`<div class="toast__title">${this.title}</div>` : ""}
143
+ <div class="toast__message">
144
+ <slot></slot>
145
+ </div>
146
+ </div>
147
+
148
+ ${this._renderDismissButton()}
149
+ </div>
150
+ `;
151
+ }
152
+ }
153
+
154
+ /**
155
+ * Toast container for managing multiple toasts
156
+ */
157
+ export class GrantCodesToastContainer extends LitElement {
158
+ static styles = [toastStyles];
159
+
160
+ static properties = {
161
+ position: { type: String },
162
+ };
163
+
164
+ constructor() {
165
+ super();
166
+
167
+ /**
168
+ * Position of the toast container
169
+ * @type {'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right'}
170
+ */
171
+ this.position = "top-right";
172
+ }
173
+
174
+ render() {
175
+ const containerClass = cx("toast-container", {
176
+ [`toast-container--${this.position}`]: true,
177
+ });
178
+
179
+ return html`
180
+ <div class="${containerClass}">
181
+ <slot></slot>
182
+ </div>
183
+ `;
184
+ }
185
+ }
186
+
187
+
@@ -0,0 +1,9 @@
1
+ import { GrantCodesToast, GrantCodesToastContainer } from "./toast.component.js";
2
+
3
+ export * from "./toast.component.js";
4
+ export default GrantCodesToast;
5
+
6
+ customElements.define("grantcodes-toast", GrantCodesToast);
7
+ customElements.define("grantcodes-toast-container", GrantCodesToastContainer);
8
+
9
+
@@ -0,0 +1,169 @@
1
+ import { html } from "lit";
2
+ import "./toast.js";
3
+
4
+ const meta = {
5
+ title: "Components/Toast",
6
+ component: "grantcodes-toast",
7
+ };
8
+
9
+ export default meta;
10
+
11
+ /**
12
+ * Basic toast notification that auto-dismisses after 5 seconds
13
+ */
14
+ export const Toast = {
15
+ render: () => html`
16
+ <grantcodes-toast-container position="top-right">
17
+ <grantcodes-toast variant="info" title="Information">
18
+ This is an informational toast message.
19
+ </grantcodes-toast>
20
+ </grantcodes-toast-container>
21
+ `,
22
+ };
23
+
24
+ /**
25
+ * All toast variants
26
+ */
27
+ export const AllVariants = {
28
+ render: () => html`
29
+ <grantcodes-toast-container position="top-right">
30
+ <grantcodes-toast variant="info" title="Info" duration="0">
31
+ This is an info toast message.
32
+ </grantcodes-toast>
33
+ <grantcodes-toast variant="success" title="Success" duration="0">
34
+ Operation completed successfully!
35
+ </grantcodes-toast>
36
+ <grantcodes-toast variant="warning" title="Warning" duration="0">
37
+ Please review before continuing.
38
+ </grantcodes-toast>
39
+ <grantcodes-toast variant="error" title="Error" duration="0">
40
+ An error occurred. Please try again.
41
+ </grantcodes-toast>
42
+ </grantcodes-toast-container>
43
+ `,
44
+ };
45
+
46
+ /**
47
+ * Toast without title
48
+ */
49
+ export const WithoutTitle = {
50
+ render: () => html`
51
+ <grantcodes-toast-container position="top-right">
52
+ <grantcodes-toast variant="success" duration="0">
53
+ This toast has no title, just the message content.
54
+ </grantcodes-toast>
55
+ </grantcodes-toast-container>
56
+ `,
57
+ };
58
+
59
+ /**
60
+ * Non-dismissible toast (no close button)
61
+ */
62
+ export const NonDismissible = {
63
+ render: () => html`
64
+ <grantcodes-toast-container position="top-right">
65
+ <grantcodes-toast variant="info" title="Loading" ?dismissible=${false} duration="0">
66
+ Please wait while we process your request...
67
+ </grantcodes-toast>
68
+ </grantcodes-toast-container>
69
+ `,
70
+ };
71
+
72
+ /**
73
+ * Different positions for toast container
74
+ */
75
+ export const Positions = {
76
+ render: () => html`
77
+ <div style="position: relative; height: 400px; border: 1px solid #ccc;">
78
+ <grantcodes-toast-container position="top-left">
79
+ <grantcodes-toast variant="info" title="Top Left" duration="0">
80
+ Toast in top-left corner
81
+ </grantcodes-toast>
82
+ </grantcodes-toast-container>
83
+
84
+ <grantcodes-toast-container position="top-center">
85
+ <grantcodes-toast variant="success" title="Top Center" duration="0">
86
+ Toast in top-center
87
+ </grantcodes-toast>
88
+ </grantcodes-toast-container>
89
+
90
+ <grantcodes-toast-container position="top-right">
91
+ <grantcodes-toast variant="warning" title="Top Right" duration="0">
92
+ Toast in top-right corner
93
+ </grantcodes-toast>
94
+ </grantcodes-toast-container>
95
+
96
+ <grantcodes-toast-container position="bottom-left">
97
+ <grantcodes-toast variant="info" title="Bottom Left" duration="0">
98
+ Toast in bottom-left corner
99
+ </grantcodes-toast>
100
+ </grantcodes-toast-container>
101
+
102
+ <grantcodes-toast-container position="bottom-center">
103
+ <grantcodes-toast variant="success" title="Bottom Center" duration="0">
104
+ Toast in bottom-center
105
+ </grantcodes-toast>
106
+ </grantcodes-toast-container>
107
+
108
+ <grantcodes-toast-container position="bottom-right">
109
+ <grantcodes-toast variant="error" title="Bottom Right" duration="0">
110
+ Toast in bottom-right corner
111
+ </grantcodes-toast>
112
+ </grantcodes-toast-container>
113
+ </div>
114
+ `,
115
+ };
116
+
117
+ /**
118
+ * Stacked toasts showing multiple notifications
119
+ */
120
+ export const Stacked = {
121
+ render: () => html`
122
+ <grantcodes-toast-container position="top-right">
123
+ <grantcodes-toast variant="info" title="First notification" duration="0">
124
+ This is the first toast message.
125
+ </grantcodes-toast>
126
+ <grantcodes-toast variant="success" title="Second notification" duration="0">
127
+ This is the second toast message.
128
+ </grantcodes-toast>
129
+ <grantcodes-toast variant="warning" title="Third notification" duration="0">
130
+ This is the third toast message.
131
+ </grantcodes-toast>
132
+ </grantcodes-toast-container>
133
+ `,
134
+ };
135
+
136
+ /**
137
+ * Interactive demo with button to trigger toasts
138
+ */
139
+ export const Interactive = {
140
+ render: () => html`
141
+ <div>
142
+ <button
143
+ @click=${() => {
144
+ const container = document.querySelector("grantcodes-toast-container");
145
+ if (!container) {
146
+ const newContainer = document.createElement("grantcodes-toast-container");
147
+ newContainer.position = "top-right";
148
+ document.body.appendChild(newContainer);
149
+ }
150
+
151
+ const toast = document.createElement("grantcodes-toast");
152
+ toast.variant = "success";
153
+ toast.title = "Toast Created!";
154
+ toast.textContent = "This toast was created dynamically.";
155
+ toast.duration = 3000;
156
+
157
+ const finalContainer =
158
+ document.querySelector("grantcodes-toast-container") ||
159
+ document.body.appendChild(document.createElement("grantcodes-toast-container"));
160
+ finalContainer.appendChild(toast);
161
+ }}
162
+ >
163
+ Show Toast
164
+ </button>
165
+ </div>
166
+ `,
167
+ };
168
+
169
+