@grantcodes/ui 2.0.0-beta4 → 2.0.2

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 (310) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +6 -8
  3. package/custom-elements.json +4273 -0
  4. package/package.json +79 -88
  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/components/avatar/avatar.component.js +0 -3
  181. package/dist/components/avatar/avatar.js +0 -1
  182. package/dist/components/avatar/avatar.react.js +0 -1
  183. package/dist/components/avatar/avatar.scss.js +0 -1
  184. package/dist/components/avatar/index.js +0 -1
  185. package/dist/components/button/button.component.js +0 -5
  186. package/dist/components/button/button.js +0 -1
  187. package/dist/components/button/button.react.js +0 -1
  188. package/dist/components/button/button.scss.js +0 -1
  189. package/dist/components/button/index.js +0 -1
  190. package/dist/components/button-group/button-group.component.js +0 -5
  191. package/dist/components/button-group/button-group.js +0 -1
  192. package/dist/components/button-group/button-group.react.js +0 -1
  193. package/dist/components/button-group/button-group.scss.js +0 -1
  194. package/dist/components/button-group/index.js +0 -1
  195. package/dist/components/card/card.component.js +0 -8
  196. package/dist/components/card/card.js +0 -1
  197. package/dist/components/card/card.react.js +0 -1
  198. package/dist/components/card/card.scss.js +0 -1
  199. package/dist/components/card/index.js +0 -1
  200. package/dist/components/code-preview/code-preview.component.js +0 -1
  201. package/dist/components/code-preview/code-preview.js +0 -1
  202. package/dist/components/code-preview/code-preview.react.js +0 -1
  203. package/dist/components/code-preview/code-preview.scss.js +0 -1
  204. package/dist/components/code-preview/index.js +0 -1
  205. package/dist/components/container/container.component.js +0 -5
  206. package/dist/components/container/container.js +0 -1
  207. package/dist/components/container/container.react.js +0 -1
  208. package/dist/components/container/container.scss.js +0 -1
  209. package/dist/components/container/index.js +0 -1
  210. package/dist/components/dialog/dialog.component.js +0 -23
  211. package/dist/components/dialog/dialog.js +0 -1
  212. package/dist/components/dialog/dialog.react.js +0 -1
  213. package/dist/components/dialog/dialog.scss.js +0 -1
  214. package/dist/components/dialog/index.js +0 -1
  215. package/dist/components/dropzone/dropzone.component.js +0 -11
  216. package/dist/components/dropzone/dropzone.js +0 -1
  217. package/dist/components/dropzone/dropzone.react.js +0 -1
  218. package/dist/components/dropzone/dropzone.scss.js +0 -1
  219. package/dist/components/dropzone/index.js +0 -1
  220. package/dist/components/form-field/form-field.component.js +0 -22
  221. package/dist/components/form-field/form-field.js +0 -1
  222. package/dist/components/form-field/form-field.react.js +0 -1
  223. package/dist/components/form-field/form-field.scss.js +0 -1
  224. package/dist/components/form-field/index.js +0 -1
  225. package/dist/components/gallery/gallery-image.component.js +0 -14
  226. package/dist/components/gallery/gallery-image.js +0 -1
  227. package/dist/components/gallery/gallery.component.js +0 -5
  228. package/dist/components/gallery/gallery.js +0 -1
  229. package/dist/components/gallery/gallery.react.js +0 -1
  230. package/dist/components/gallery/gallery.scss.js +0 -1
  231. package/dist/components/gallery/index.js +0 -1
  232. package/dist/components/icon/icon.component.js +0 -1
  233. package/dist/components/icon/icon.js +0 -1
  234. package/dist/components/icon/icon.react.js +0 -1
  235. package/dist/components/icon/icon.scss.js +0 -1
  236. package/dist/components/icon/index.js +0 -1
  237. package/dist/components/loading/index.js +0 -1
  238. package/dist/components/loading/loading.component.js +0 -5
  239. package/dist/components/loading/loading.js +0 -1
  240. package/dist/components/loading/loading.react.js +0 -1
  241. package/dist/components/loading/loading.scss.js +0 -1
  242. package/dist/components/notice/index.js +0 -1
  243. package/dist/components/notice/notice.component.js +0 -17
  244. package/dist/components/notice/notice.js +0 -1
  245. package/dist/components/notice/notice.react.js +0 -1
  246. package/dist/components/notice/notice.scss.js +0 -1
  247. package/dist/components/pagination/index.js +0 -1
  248. package/dist/components/pagination/pagination.component.js +0 -13
  249. package/dist/components/pagination/pagination.js +0 -1
  250. package/dist/components/pagination/pagination.react.js +0 -1
  251. package/dist/components/pagination/pagination.scss.js +0 -1
  252. package/dist/components/tabs/index.js +0 -1
  253. package/dist/components/tabs/tab.component.js +0 -1
  254. package/dist/components/tabs/tab.js +0 -1
  255. package/dist/components/tabs/tabs-item.component.js +0 -1
  256. package/dist/components/tabs/tabs-panel.component.js +0 -10
  257. package/dist/components/tabs/tabs-panel.js +0 -1
  258. package/dist/components/tabs/tabs-tab.component.js +0 -12
  259. package/dist/components/tabs/tabs-tab.js +0 -1
  260. package/dist/components/tabs/tabs.component.js +0 -28
  261. package/dist/components/tabs/tabs.js +0 -1
  262. package/dist/components/tabs/tabs.react.js +0 -1
  263. package/dist/components/tabs/tabs.scss.js +0 -1
  264. package/dist/components/tooltip/index.js +0 -1
  265. package/dist/components/tooltip/tooltip.component.js +0 -10
  266. package/dist/components/tooltip/tooltip.js +0 -1
  267. package/dist/components/tooltip/tooltip.react.js +0 -1
  268. package/dist/components/tooltip/tooltip.scss.js +0 -1
  269. package/dist/css/base.css +0 -1
  270. package/dist/css/themes/grantcodes.css +0 -1
  271. package/dist/fonts/greycliff-bold-oblique.woff +0 -0
  272. package/dist/fonts/greycliff-bold-oblique.woff2 +0 -0
  273. package/dist/fonts/greycliff-bold.woff +0 -0
  274. package/dist/fonts/greycliff-bold.woff2 +0 -0
  275. package/dist/fonts/greycliff-demi-bold-oblique.woff +0 -0
  276. package/dist/fonts/greycliff-demi-bold-oblique.woff2 +0 -0
  277. package/dist/fonts/greycliff-demi-bold.woff +0 -0
  278. package/dist/fonts/greycliff-demi-bold.woff2 +0 -0
  279. package/dist/fonts/greycliff-extra-bold-oblique.woff +0 -0
  280. package/dist/fonts/greycliff-extra-bold-oblique.woff2 +0 -0
  281. package/dist/fonts/greycliff-extra-bold.woff +0 -0
  282. package/dist/fonts/greycliff-extra-bold.woff2 +0 -0
  283. package/dist/fonts/greycliff-extra-light-oblique.woff +0 -0
  284. package/dist/fonts/greycliff-extra-light-oblique.woff2 +0 -0
  285. package/dist/fonts/greycliff-extra-light.woff +0 -0
  286. package/dist/fonts/greycliff-extra-light.woff2 +0 -0
  287. package/dist/fonts/greycliff-heavy-oblique.woff +0 -0
  288. package/dist/fonts/greycliff-heavy-oblique.woff2 +0 -0
  289. package/dist/fonts/greycliff-heavy.woff +0 -0
  290. package/dist/fonts/greycliff-heavy.woff2 +0 -0
  291. package/dist/fonts/greycliff-light-oblique.woff +0 -0
  292. package/dist/fonts/greycliff-light-oblique.woff2 +0 -0
  293. package/dist/fonts/greycliff-light.woff +0 -0
  294. package/dist/fonts/greycliff-light.woff2 +0 -0
  295. package/dist/fonts/greycliff-medium-oblique.woff +0 -0
  296. package/dist/fonts/greycliff-medium-oblique.woff2 +0 -0
  297. package/dist/fonts/greycliff-medium.woff +0 -0
  298. package/dist/fonts/greycliff-medium.woff2 +0 -0
  299. package/dist/fonts/greycliff-regular-oblique.woff +0 -0
  300. package/dist/fonts/greycliff-regular-oblique.woff2 +0 -0
  301. package/dist/fonts/greycliff-regular.woff +0 -0
  302. package/dist/fonts/greycliff-regular.woff2 +0 -0
  303. package/dist/fonts/greycliff-thin-oblique.woff +0 -0
  304. package/dist/fonts/greycliff-thin-oblique.woff2 +0 -0
  305. package/dist/fonts/greycliff-thin.woff +0 -0
  306. package/dist/fonts/greycliff-thin.woff2 +0 -0
  307. package/dist/icons.js +0 -1
  308. package/dist/lib/generate-id.js +0 -1
  309. package/dist/main.js +0 -1
  310. package/dist/react.js +0 -1
@@ -0,0 +1,98 @@
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 "./pagination.js";
5
+
6
+ describe("Pagination Component", () => {
7
+ let element;
8
+
9
+ afterEach(() => {
10
+ cleanup(element);
11
+ });
12
+
13
+ it("should render with default properties", async () => {
14
+ element = await fixture("grantcodes-pagination");
15
+ assert.ok(element, "Element should be created");
16
+ assert.ok(element.shadowRoot, "Element should have shadow root");
17
+ });
18
+
19
+ it("should have page property defaulting to 1", async () => {
20
+ element = await fixture("grantcodes-pagination");
21
+ assert.strictEqual(element.page, 1, "Page should default to 1");
22
+ });
23
+
24
+ it("should have pages property defaulting to 1", async () => {
25
+ element = await fixture("grantcodes-pagination");
26
+ assert.strictEqual(element.pages, 1, "Pages should default to 1");
27
+ });
28
+
29
+ it("should render navigation element", async () => {
30
+ element = await fixture("grantcodes-pagination", {
31
+ pages: 5,
32
+ });
33
+
34
+ const nav = element.shadowRoot.querySelector("nav");
35
+ assert.ok(nav, "Navigation element should exist");
36
+ });
37
+
38
+ it("should render pagination list", async () => {
39
+ element = await fixture("grantcodes-pagination", {
40
+ pages: 5,
41
+ });
42
+
43
+ const list = element.shadowRoot.querySelector(".pagination");
44
+ assert.ok(list, "Pagination list should exist");
45
+ });
46
+
47
+ it("should support href property for links", async () => {
48
+ element = await fixture("grantcodes-pagination", {
49
+ page: 2,
50
+ pages: 5,
51
+ href: "/page/{page}",
52
+ });
53
+
54
+ assert.strictEqual(element.href, "/page/{page}", "Href property should be set");
55
+ });
56
+
57
+ it("should indicate current page", async () => {
58
+ element = await fixture("grantcodes-pagination", {
59
+ page: 3,
60
+ pages: 5,
61
+ });
62
+
63
+ assert.strictEqual(element.page, 3, "Current page should be 3");
64
+ });
65
+
66
+ it("should handle single page", async () => {
67
+ element = await fixture("grantcodes-pagination", {
68
+ page: 1,
69
+ pages: 1,
70
+ });
71
+
72
+ const list = element.shadowRoot.querySelector(".pagination");
73
+ assert.ok(list, "Should render even with single page");
74
+ });
75
+
76
+ it("should handle multiple pages", async () => {
77
+ element = await fixture("grantcodes-pagination", {
78
+ page: 1,
79
+ pages: 10,
80
+ });
81
+
82
+ const list = element.shadowRoot.querySelector(".pagination");
83
+ assert.ok(list, "Should render pagination for multiple pages");
84
+ });
85
+
86
+ it("should support navigation to different pages", async () => {
87
+ element = await fixture("grantcodes-pagination", {
88
+ page: 5,
89
+ pages: 10,
90
+ });
91
+
92
+ // The component should allow navigating to previous and next pages
93
+ assert.ok(element.page > 1, "Should be able to go to previous page");
94
+ assert.ok(element.page < element.pages, "Should be able to go to next page");
95
+ });
96
+ });
97
+
98
+
@@ -0,0 +1,3 @@
1
+ export * from "./sidebar.js";
2
+
3
+
@@ -0,0 +1,165 @@
1
+ import { LitElement } from "lit";
2
+ import { html } from "lit/static-html.js";
3
+ import { cx } from "../../lib/classnames.js";
4
+ import { sidebarStyles } from "./sidebar.styles.js";
5
+
6
+ export class GrantCodesSidebar extends LitElement {
7
+ static styles = [sidebarStyles];
8
+
9
+ static properties = {
10
+ position: { type: String },
11
+ collapsed: { type: Boolean, reflect: true },
12
+ collapsible: { type: Boolean },
13
+ width: { type: String },
14
+ _drawerOpen: { type: Boolean, state: true },
15
+ };
16
+
17
+ constructor() {
18
+ super();
19
+
20
+ /**
21
+ * Position of the sidebar
22
+ * @type {'left' | 'right'}
23
+ */
24
+ this.position = "left";
25
+
26
+ /**
27
+ * Whether the sidebar is collapsed on desktop
28
+ * @type {boolean}
29
+ */
30
+ this.collapsed = false;
31
+
32
+ /**
33
+ * Whether the sidebar can be collapsed
34
+ * @type {boolean}
35
+ */
36
+ this.collapsible = true;
37
+
38
+ /**
39
+ * Custom width of the sidebar
40
+ * @type {string}
41
+ */
42
+ this.width = "280px";
43
+
44
+ /**
45
+ * Whether mobile drawer is open
46
+ * @type {boolean}
47
+ */
48
+ this._drawerOpen = false;
49
+
50
+ this._handleDocumentClick = this._handleDocumentClick.bind(this);
51
+ this._handleEscape = this._handleEscape.bind(this);
52
+ }
53
+
54
+ connectedCallback() {
55
+ super.connectedCallback();
56
+ document.addEventListener("click", this._handleDocumentClick);
57
+ document.addEventListener("keydown", this._handleEscape);
58
+ }
59
+
60
+ disconnectedCallback() {
61
+ document.removeEventListener("click", this._handleDocumentClick);
62
+ document.removeEventListener("keydown", this._handleEscape);
63
+ super.disconnectedCallback();
64
+ }
65
+
66
+ _handleDocumentClick(e) {
67
+ // Close mobile drawer if clicking outside
68
+ if (this._drawerOpen) {
69
+ const path = e.composedPath();
70
+ if (!path.includes(this)) {
71
+ this._drawerOpen = false;
72
+ }
73
+ }
74
+ }
75
+
76
+ _handleEscape(e) {
77
+ if (e.key === "Escape" && this._drawerOpen) {
78
+ this._drawerOpen = false;
79
+ }
80
+ }
81
+
82
+ _toggleCollapsed() {
83
+ if (!this.collapsible) return;
84
+
85
+ this.collapsed = !this.collapsed;
86
+ this.dispatchEvent(
87
+ new CustomEvent("toggle", {
88
+ detail: { collapsed: this.collapsed },
89
+ bubbles: true,
90
+ composed: true,
91
+ }),
92
+ );
93
+ }
94
+
95
+ _toggleDrawer() {
96
+ this._drawerOpen = !this._drawerOpen;
97
+ this.dispatchEvent(
98
+ new CustomEvent("drawer-toggle", {
99
+ detail: { open: this._drawerOpen },
100
+ bubbles: true,
101
+ composed: true,
102
+ }),
103
+ );
104
+ }
105
+
106
+ render() {
107
+ const sidebarClass = cx("sidebar", {
108
+ "sidebar--collapsed": this.collapsed,
109
+ [`sidebar--${this.position}`]: true,
110
+ "sidebar--drawer-open": this._drawerOpen,
111
+ });
112
+
113
+ return html`
114
+ <!-- Mobile Toggle Button -->
115
+ <button
116
+ type="button"
117
+ class="sidebar__mobile-toggle"
118
+ @click=${this._toggleDrawer}
119
+ aria-label="${this._drawerOpen ? "Close sidebar" : "Open sidebar"}"
120
+ >
121
+
122
+ </button>
123
+
124
+ <!-- Overlay for mobile -->
125
+ ${this._drawerOpen
126
+ ? html`
127
+ <div
128
+ class="sidebar__overlay"
129
+ @click=${() => {
130
+ this._drawerOpen = false;
131
+ }}
132
+ ></div>
133
+ `
134
+ : ""}
135
+
136
+ <!-- Sidebar -->
137
+ <aside
138
+ class="${sidebarClass}"
139
+ style="--sidebar-width: ${this.width}"
140
+ >
141
+ <!-- Collapse Toggle (Desktop) -->
142
+ ${this.collapsible
143
+ ? html`
144
+ <button
145
+ type="button"
146
+ class="sidebar__toggle"
147
+ @click=${this._toggleCollapsed}
148
+ aria-label="${this.collapsed ? "Expand sidebar" : "Collapse sidebar"}"
149
+ aria-expanded="${!this.collapsed}"
150
+ >
151
+ ${this.position === "left" ? (this.collapsed ? "→" : "←") : this.collapsed ? "←" : "→"}
152
+ </button>
153
+ `
154
+ : ""}
155
+
156
+ <!-- Content -->
157
+ <div class="sidebar__content">
158
+ <slot></slot>
159
+ </div>
160
+ </aside>
161
+ `;
162
+ }
163
+ }
164
+
165
+
@@ -0,0 +1,8 @@
1
+ import { GrantCodesSidebar } from "./sidebar.component.js";
2
+
3
+ export * from "./sidebar.component.js";
4
+ export default GrantCodesSidebar;
5
+
6
+ customElements.define("grantcodes-sidebar", GrantCodesSidebar);
7
+
8
+
@@ -0,0 +1,155 @@
1
+ import { html } from "lit";
2
+ import "./sidebar.js";
3
+
4
+ const meta = {
5
+ title: "Components/Sidebar",
6
+ component: "grantcodes-sidebar",
7
+ };
8
+
9
+ export default meta;
10
+
11
+ /**
12
+ * Basic sidebar with navigation
13
+ */
14
+ export const Sidebar = {
15
+ render: () => html`
16
+ <div style="display: flex; height: 500px; border: 1px solid #ccc;">
17
+ <grantcodes-sidebar>
18
+ <h3 style="margin-top: 0;">Navigation</h3>
19
+ <nav>
20
+ <ul style="list-style: none; padding: 0;">
21
+ <li style="margin-bottom: 0.5rem;"><a href="/">Dashboard</a></li>
22
+ <li style="margin-bottom: 0.5rem;"><a href="/projects">Projects</a></li>
23
+ <li style="margin-bottom: 0.5rem;"><a href="/tasks">Tasks</a></li>
24
+ <li style="margin-bottom: 0.5rem;"><a href="/settings">Settings</a></li>
25
+ </ul>
26
+ </nav>
27
+ </grantcodes-sidebar>
28
+ <div style="flex: 1; padding: 2rem;">
29
+ <h1>Main Content</h1>
30
+ <p>This is the main content area.</p>
31
+ </div>
32
+ </div>
33
+ `,
34
+ };
35
+
36
+ /**
37
+ * Right-positioned sidebar
38
+ */
39
+ export const RightSidebar = {
40
+ render: () => html`
41
+ <div style="display: flex; height: 500px; border: 1px solid #ccc;">
42
+ <div style="flex: 1; padding: 2rem;">
43
+ <h1>Main Content</h1>
44
+ <p>The sidebar is on the right side.</p>
45
+ </div>
46
+ <grantcodes-sidebar position="right">
47
+ <h3 style="margin-top: 0;">Details</h3>
48
+ <p style="font-size: 0.875rem;">
49
+ Additional information and tools appear here.
50
+ </p>
51
+ </grantcodes-sidebar>
52
+ </div>
53
+ `,
54
+ };
55
+
56
+ /**
57
+ * Collapsible sidebar that can be expanded/collapsed
58
+ */
59
+ export const Collapsible = {
60
+ render: () => html`
61
+ <div style="display: flex; height: 500px; border: 1px solid #ccc;">
62
+ <grantcodes-sidebar collapsible>
63
+ <h3 style="margin-top: 0;">Menu</h3>
64
+ <nav>
65
+ <ul style="list-style: none; padding: 0;">
66
+ <li style="margin-bottom: 0.5rem;"><a href="/">🏠 Home</a></li>
67
+ <li style="margin-bottom: 0.5rem;"><a href="/profile">👤 Profile</a></li>
68
+ <li style="margin-bottom: 0.5rem;"><a href="/messages">💬 Messages</a></li>
69
+ <li style="margin-bottom: 0.5rem;"><a href="/settings">⚙️ Settings</a></li>
70
+ </ul>
71
+ </nav>
72
+ </grantcodes-sidebar>
73
+ <div style="flex: 1; padding: 2rem;">
74
+ <h1>Main Content</h1>
75
+ <p>Click the toggle button to collapse/expand the sidebar.</p>
76
+ </div>
77
+ </div>
78
+ `,
79
+ };
80
+
81
+ /**
82
+ * Initially collapsed sidebar
83
+ */
84
+ export const InitiallyCollapsed = {
85
+ render: () => html`
86
+ <div style="display: flex; height: 500px; border: 1px solid #ccc;">
87
+ <grantcodes-sidebar collapsed>
88
+ <nav>
89
+ <ul style="list-style: none; padding: 0;">
90
+ <li style="margin-bottom: 0.5rem;">🏠</li>
91
+ <li style="margin-bottom: 0.5rem;">👤</li>
92
+ <li style="margin-bottom: 0.5rem;">💬</li>
93
+ <li style="margin-bottom: 0.5rem;">⚙️</li>
94
+ </ul>
95
+ </nav>
96
+ </grantcodes-sidebar>
97
+ <div style="flex: 1; padding: 2rem;">
98
+ <h1>Main Content</h1>
99
+ <p>The sidebar starts collapsed. Click the toggle to expand it.</p>
100
+ </div>
101
+ </div>
102
+ `,
103
+ };
104
+
105
+ /**
106
+ * Custom width sidebar
107
+ */
108
+ export const CustomWidth = {
109
+ render: () => html`
110
+ <div style="display: flex; height: 500px; border: 1px solid #ccc;">
111
+ <grantcodes-sidebar width="350px">
112
+ <h3 style="margin-top: 0;">Wide Sidebar</h3>
113
+ <p>This sidebar has a custom width of 350px.</p>
114
+ <p>You can set any width you need for your layout.</p>
115
+ </grantcodes-sidebar>
116
+ <div style="flex: 1; padding: 2rem;">
117
+ <h1>Main Content</h1>
118
+ <p>Main content adjusts to the sidebar width.</p>
119
+ </div>
120
+ </div>
121
+ `,
122
+ };
123
+
124
+ /**
125
+ * Mobile-responsive demo - shows drawer behavior on small screens
126
+ */
127
+ export const MobileResponsive = {
128
+ render: () => html`
129
+ <div style="max-width: 600px; border: 1px solid #ccc;">
130
+ <div style="display: flex; min-height: 400px;">
131
+ <grantcodes-sidebar>
132
+ <h3 style="margin-top: 0;">Navigation</h3>
133
+ <nav>
134
+ <ul style="list-style: none; padding: 0;">
135
+ <li style="margin-bottom: 0.5rem;"><a href="/">Dashboard</a></li>
136
+ <li style="margin-bottom: 0.5rem;"><a href="/projects">Projects</a></li>
137
+ <li style="margin-bottom: 0.5rem;"><a href="/tasks">Tasks</a></li>
138
+ <li style="margin-bottom: 0.5rem;"><a href="/team">Team</a></li>
139
+ <li style="margin-bottom: 0.5rem;"><a href="/settings">Settings</a></li>
140
+ </ul>
141
+ </nav>
142
+ </grantcodes-sidebar>
143
+ <div style="flex: 1; padding: 2rem;">
144
+ <h1>Main Content</h1>
145
+ <p style="font-size: 0.875rem; color: #666;">
146
+ On mobile/narrow screens, the sidebar becomes a drawer.
147
+ Click the hamburger menu to open it.
148
+ </p>
149
+ </div>
150
+ </div>
151
+ </div>
152
+ `,
153
+ };
154
+
155
+
@@ -0,0 +1,192 @@
1
+ import { css } from "lit";
2
+
3
+ export const sidebarStyles = css`
4
+ *,
5
+ *::before,
6
+ *::after {
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ :host {
11
+ display: contents;
12
+ }
13
+
14
+ .sidebar {
15
+ position: relative;
16
+ inline-size: var(--sidebar-width, 280px);
17
+ block-size: 100%;
18
+ background-color: var(--g-theme-color-background-default);
19
+ border-inline-end: 1px solid var(--g-theme-color-border-default);
20
+ overflow-y: auto;
21
+ transition: inline-size 0.3s ease;
22
+ flex-shrink: 0;
23
+ }
24
+
25
+ .sidebar--right {
26
+ border-inline-end: none;
27
+ border-inline-start: 1px solid var(--g-theme-color-border-default);
28
+ }
29
+
30
+ .sidebar--collapsed {
31
+ inline-size: 60px;
32
+ }
33
+
34
+ .sidebar--collapsed .sidebar__content {
35
+ padding-inline: 0.5rem;
36
+ }
37
+
38
+ .sidebar--collapsed .sidebar__content > *:not(.sidebar__toggle):not(.sidebar__mobile-toggle) {
39
+ display: none;
40
+ }
41
+
42
+ .sidebar--collapsed .sidebar__toggle {
43
+ inset-inline-end: 50%;
44
+ transform: translateX(50%);
45
+ }
46
+
47
+ /* Mobile Toggle Button */
48
+ .sidebar__mobile-toggle {
49
+ all: unset;
50
+ display: none;
51
+ position: fixed;
52
+ inset-block-start: 1rem;
53
+ inset-inline-start: 1rem;
54
+ z-index: 1001;
55
+ inline-size: 2.5rem;
56
+ block-size: 2.5rem;
57
+ align-items: center;
58
+ justify-content: center;
59
+ background-color: var(--g-theme-color-background-default);
60
+ border: 1px solid var(--g-theme-color-border-default);
61
+ border-radius: var(--g-theme-border-radius-md);
62
+ cursor: pointer;
63
+ font-size: 1.5rem;
64
+ transition: all 0.2s ease;
65
+ }
66
+
67
+ .sidebar__mobile-toggle:hover {
68
+ background-color: var(--g-theme-color-background-subtle-hover);
69
+ }
70
+
71
+ .sidebar__mobile-toggle:focus-visible {
72
+ outline: 2px solid var(--component-focus-ring-color);
73
+ outline-offset: 2px;
74
+ }
75
+
76
+ /* Show mobile toggle on small screens */
77
+ @media (max-width: 768px) {
78
+ .sidebar__mobile-toggle {
79
+ display: flex;
80
+ }
81
+
82
+ .sidebar {
83
+ position: fixed;
84
+ inset-block-start: 0;
85
+ inset-block-end: 0;
86
+ inset-inline-start: -100%;
87
+ z-index: 1000;
88
+ transition: inset-inline-start 0.3s ease;
89
+ }
90
+
91
+ .sidebar--right {
92
+ inset-inline-start: auto;
93
+ inset-inline-end: -100%;
94
+ transition: inset-inline-end 0.3s ease;
95
+ }
96
+
97
+ .sidebar--drawer-open {
98
+ inset-inline-start: 0;
99
+ }
100
+
101
+ .sidebar--right.sidebar--drawer-open {
102
+ inset-inline-end: 0;
103
+ inset-inline-start: auto;
104
+ }
105
+ }
106
+
107
+ /* Overlay */
108
+ .sidebar__overlay {
109
+ display: none;
110
+ position: fixed;
111
+ inset: 0;
112
+ background-color: rgba(0, 0, 0, 0.5);
113
+ z-index: 999;
114
+ animation: overlay-fade-in 0.2s ease-out;
115
+ }
116
+
117
+ @media (max-width: 768px) {
118
+ .sidebar__overlay {
119
+ display: block;
120
+ }
121
+ }
122
+
123
+ @keyframes overlay-fade-in {
124
+ from {
125
+ opacity: 0;
126
+ }
127
+ to {
128
+ opacity: 1;
129
+ }
130
+ }
131
+
132
+ /* Collapse Toggle */
133
+ .sidebar__toggle {
134
+ all: unset;
135
+ position: absolute;
136
+ inset-block-start: 1rem;
137
+ inset-inline-end: 0.5rem;
138
+ inline-size: 1.5rem;
139
+ block-size: 1.5rem;
140
+ display: flex;
141
+ align-items: center;
142
+ justify-content: center;
143
+ background-color: var(--g-theme-color-background-default);
144
+ border: 1px solid var(--g-theme-color-border-default);
145
+ border-radius: var(--g-theme-border-radius-md);
146
+ cursor: pointer;
147
+ font-size: 0.875rem;
148
+ transition: all 0.2s ease;
149
+ z-index: 10;
150
+ }
151
+
152
+ .sidebar__toggle:hover {
153
+ background-color: var(--g-theme-color-background-subtle-hover);
154
+ }
155
+
156
+ .sidebar__toggle:focus-visible {
157
+ outline: 2px solid var(--component-focus-ring-color);
158
+ outline-offset: 2px;
159
+ }
160
+
161
+ .sidebar--right .sidebar__toggle {
162
+ inset-inline-end: auto;
163
+ inset-inline-start: 0.5rem;
164
+ }
165
+
166
+ .sidebar--right.sidebar--collapsed .sidebar__toggle {
167
+ inset-inline-start: 50%;
168
+ inset-inline-end: auto;
169
+ transform: translateX(-50%);
170
+ }
171
+
172
+ @media (max-width: 768px) {
173
+ .sidebar__toggle {
174
+ display: none;
175
+ }
176
+ }
177
+
178
+ /* Content */
179
+ .sidebar__content {
180
+ padding-block: 1rem;
181
+ padding-inline: 1rem;
182
+ }
183
+
184
+ /* View transitions */
185
+ @media (prefers-reduced-motion: no-preference) {
186
+ @supports (view-transition-name: auto) {
187
+ .sidebar {
188
+ view-transition-name: sidebar;
189
+ }
190
+ }
191
+ }
192
+ `;