rizzo-css 0.0.16 → 0.0.18

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 (259) hide show
  1. package/README.md +4 -4
  2. package/bin/rizzo-css.js +473 -164
  3. package/dist/rizzo.min.css +4 -1
  4. package/package.json +9 -4
  5. package/scaffold/astro-minimal/.env.example +3 -0
  6. package/scaffold/astro-minimal/README.md +36 -0
  7. package/scaffold/astro-minimal/package.json +13 -0
  8. package/scaffold/astro-minimal/src/layouts/Layout.astro +28 -0
  9. package/scaffold/astro-minimal/src/pages/index.astro +10 -0
  10. package/scaffold/svelte-minimal/.env.example +3 -0
  11. package/scaffold/svelte-minimal/README.md +37 -0
  12. package/scaffold/svelte-minimal/package.json +20 -0
  13. package/scaffold/svelte-minimal/src/app.d.ts +11 -0
  14. package/scaffold/svelte-minimal/src/app.html +15 -0
  15. package/scaffold/svelte-minimal/src/routes/+layout.svelte +1 -0
  16. package/scaffold/svelte-minimal/src/routes/+page.svelte +5 -0
  17. package/scaffold/svelte-minimal/svelte.config.js +10 -0
  18. package/scaffold/svelte-minimal/tsconfig.json +11 -0
  19. package/scaffold/vanilla/README.md +4 -4
  20. package/scaffold/vanilla/components/accordion.html +18 -0
  21. package/scaffold/vanilla/components/alert.html +18 -0
  22. package/scaffold/vanilla/components/avatar.html +18 -0
  23. package/scaffold/vanilla/components/badge.html +18 -0
  24. package/scaffold/vanilla/components/breadcrumb.html +18 -0
  25. package/scaffold/vanilla/components/button.html +18 -0
  26. package/scaffold/vanilla/components/cards.html +18 -0
  27. package/scaffold/vanilla/components/copy-to-clipboard.html +18 -0
  28. package/scaffold/vanilla/components/divider.html +18 -0
  29. package/scaffold/vanilla/components/dropdown.html +18 -0
  30. package/scaffold/vanilla/components/forms.html +18 -0
  31. package/scaffold/vanilla/components/icons.html +18 -0
  32. package/scaffold/vanilla/components/index.html +18 -0
  33. package/scaffold/vanilla/components/modal.html +18 -0
  34. package/scaffold/vanilla/components/navbar.html +18 -0
  35. package/scaffold/vanilla/components/pagination.html +18 -0
  36. package/scaffold/vanilla/components/progress-bar.html +18 -0
  37. package/scaffold/vanilla/components/search.html +18 -0
  38. package/scaffold/vanilla/components/settings.html +18 -0
  39. package/scaffold/vanilla/components/spinner.html +18 -0
  40. package/scaffold/vanilla/components/table.html +18 -0
  41. package/scaffold/vanilla/components/tabs.html +18 -0
  42. package/scaffold/vanilla/components/theme-switcher.html +18 -0
  43. package/scaffold/vanilla/components/toast.html +18 -0
  44. package/scaffold/vanilla/components/tooltip.html +18 -0
  45. package/scaffold/vanilla/index.html +18 -0
  46. package/scaffold/astro-app/README.md +0 -43
  47. package/scaffold/astro-app/package.json +0 -1
  48. package/scaffold/astro-app/src/components/Accordion.astro +0 -178
  49. package/scaffold/astro-app/src/components/Alert.astro +0 -131
  50. package/scaffold/astro-app/src/components/Avatar.astro +0 -59
  51. package/scaffold/astro-app/src/components/Badge.astro +0 -24
  52. package/scaffold/astro-app/src/components/Breadcrumb.astro +0 -61
  53. package/scaffold/astro-app/src/components/Button.astro +0 -3
  54. package/scaffold/astro-app/src/components/Card.astro +0 -18
  55. package/scaffold/astro-app/src/components/Checkbox.astro +0 -38
  56. package/scaffold/astro-app/src/components/CodeBlock.astro +0 -393
  57. package/scaffold/astro-app/src/components/CopyToClipboard.astro +0 -219
  58. package/scaffold/astro-app/src/components/Divider.astro +0 -37
  59. package/scaffold/astro-app/src/components/DocsSidebar.astro +0 -51
  60. package/scaffold/astro-app/src/components/Dropdown.astro +0 -807
  61. package/scaffold/astro-app/src/components/FormGroup.astro +0 -59
  62. package/scaffold/astro-app/src/components/FrameworkSwitcher.astro +0 -72
  63. package/scaffold/astro-app/src/components/Input.astro +0 -59
  64. package/scaffold/astro-app/src/components/Modal.astro +0 -212
  65. package/scaffold/astro-app/src/components/Navbar.astro +0 -623
  66. package/scaffold/astro-app/src/components/Pagination.astro +0 -240
  67. package/scaffold/astro-app/src/components/ProgressBar.astro +0 -65
  68. package/scaffold/astro-app/src/components/Radio.astro +0 -38
  69. package/scaffold/astro-app/src/components/Search.astro +0 -1259
  70. package/scaffold/astro-app/src/components/Select.astro +0 -49
  71. package/scaffold/astro-app/src/components/Settings.astro +0 -382
  72. package/scaffold/astro-app/src/components/Spinner.astro +0 -30
  73. package/scaffold/astro-app/src/components/Table.astro +0 -181
  74. package/scaffold/astro-app/src/components/Tabs.astro +0 -223
  75. package/scaffold/astro-app/src/components/Textarea.astro +0 -58
  76. package/scaffold/astro-app/src/components/ThemeIcon.astro +0 -50
  77. package/scaffold/astro-app/src/components/ThemeSwitcher.astro +0 -504
  78. package/scaffold/astro-app/src/components/Toast.astro +0 -30
  79. package/scaffold/astro-app/src/components/Tooltip.astro +0 -32
  80. package/scaffold/astro-app/src/components/icons/Brush.astro +0 -10
  81. package/scaffold/astro-app/src/components/icons/Cake.astro +0 -11
  82. package/scaffold/astro-app/src/components/icons/Check.astro +0 -29
  83. package/scaffold/astro-app/src/components/icons/Cherry.astro +0 -11
  84. package/scaffold/astro-app/src/components/icons/ChevronDown.astro +0 -29
  85. package/scaffold/astro-app/src/components/icons/Circle.astro +0 -29
  86. package/scaffold/astro-app/src/components/icons/Close.astro +0 -30
  87. package/scaffold/astro-app/src/components/icons/Cmd.astro +0 -26
  88. package/scaffold/astro-app/src/components/icons/Copy.astro +0 -30
  89. package/scaffold/astro-app/src/components/icons/Eye.astro +0 -30
  90. package/scaffold/astro-app/src/components/icons/Filter.astro +0 -29
  91. package/scaffold/astro-app/src/components/icons/Flame.astro +0 -28
  92. package/scaffold/astro-app/src/components/icons/Flower.astro +0 -11
  93. package/scaffold/astro-app/src/components/icons/Gear.astro +0 -30
  94. package/scaffold/astro-app/src/components/icons/Heart.astro +0 -28
  95. package/scaffold/astro-app/src/components/icons/IceCream.astro +0 -31
  96. package/scaffold/astro-app/src/components/icons/Leaf.astro +0 -29
  97. package/scaffold/astro-app/src/components/icons/Lemon.astro +0 -11
  98. package/scaffold/astro-app/src/components/icons/Moon.astro +0 -29
  99. package/scaffold/astro-app/src/components/icons/Owl.astro +0 -34
  100. package/scaffold/astro-app/src/components/icons/Palette.astro +0 -33
  101. package/scaffold/astro-app/src/components/icons/Rainbow.astro +0 -31
  102. package/scaffold/astro-app/src/components/icons/Search.astro +0 -30
  103. package/scaffold/astro-app/src/components/icons/Shield.astro +0 -28
  104. package/scaffold/astro-app/src/components/icons/Snowflake.astro +0 -34
  105. package/scaffold/astro-app/src/components/icons/Sort.astro +0 -30
  106. package/scaffold/astro-app/src/components/icons/Sun.astro +0 -29
  107. package/scaffold/astro-app/src/components/icons/Sunset.astro +0 -10
  108. package/scaffold/astro-app/src/components/icons/Zap.astro +0 -9
  109. package/scaffold/astro-app/src/components/icons/devicons/Astro.astro +0 -53
  110. package/scaffold/astro-app/src/components/icons/devicons/Bash.astro +0 -34
  111. package/scaffold/astro-app/src/components/icons/devicons/Css3.astro +0 -29
  112. package/scaffold/astro-app/src/components/icons/devicons/Git.astro +0 -24
  113. package/scaffold/astro-app/src/components/icons/devicons/Html5.astro +0 -27
  114. package/scaffold/astro-app/src/components/icons/devicons/Javascript.astro +0 -25
  115. package/scaffold/astro-app/src/components/icons/devicons/Nodejs.astro +0 -47
  116. package/scaffold/astro-app/src/components/icons/devicons/Plaintext.astro +0 -33
  117. package/scaffold/astro-app/src/components/icons/devicons/React.astro +0 -27
  118. package/scaffold/astro-app/src/components/icons/devicons/Svelte.astro +0 -25
  119. package/scaffold/astro-app/src/components/icons/devicons/Vue.astro +0 -26
  120. package/scaffold/astro-app/src/config/frameworks.ts +0 -26
  121. package/scaffold/astro-app/src/config/themes.ts +0 -54
  122. package/scaffold/astro-app/src/layouts/DocsLayout.astro +0 -263
  123. package/scaffold/astro-app/src/layouts/Layout.astro +0 -41
  124. package/scaffold/astro-app/src/pages/components/accordion.astro +0 -172
  125. package/scaffold/astro-app/src/pages/components/alert.astro +0 -250
  126. package/scaffold/astro-app/src/pages/components/avatar.astro +0 -102
  127. package/scaffold/astro-app/src/pages/components/badge.astro +0 -119
  128. package/scaffold/astro-app/src/pages/components/breadcrumb.astro +0 -124
  129. package/scaffold/astro-app/src/pages/components/button.astro +0 -74
  130. package/scaffold/astro-app/src/pages/components/cards.astro +0 -247
  131. package/scaffold/astro-app/src/pages/components/copy-to-clipboard.astro +0 -49
  132. package/scaffold/astro-app/src/pages/components/divider.astro +0 -74
  133. package/scaffold/astro-app/src/pages/components/dropdown.astro +0 -394
  134. package/scaffold/astro-app/src/pages/components/forms.astro +0 -367
  135. package/scaffold/astro-app/src/pages/components/icons.astro +0 -246
  136. package/scaffold/astro-app/src/pages/components/modal.astro +0 -152
  137. package/scaffold/astro-app/src/pages/components/navbar.astro +0 -80
  138. package/scaffold/astro-app/src/pages/components/pagination.astro +0 -126
  139. package/scaffold/astro-app/src/pages/components/progress-bar.astro +0 -94
  140. package/scaffold/astro-app/src/pages/components/search.astro +0 -155
  141. package/scaffold/astro-app/src/pages/components/settings.astro +0 -78
  142. package/scaffold/astro-app/src/pages/components/spinner.astro +0 -81
  143. package/scaffold/astro-app/src/pages/components/table.astro +0 -144
  144. package/scaffold/astro-app/src/pages/components/tabs.astro +0 -220
  145. package/scaffold/astro-app/src/pages/components/theme-switcher.astro +0 -69
  146. package/scaffold/astro-app/src/pages/components/toast.astro +0 -157
  147. package/scaffold/astro-app/src/pages/components/tooltip.astro +0 -209
  148. package/scaffold/astro-app/src/pages/components.astro +0 -290
  149. package/scaffold/astro-app/src/pages/docs/accessibility.astro +0 -9
  150. package/scaffold/astro-app/src/pages/docs/colors.astro +0 -9
  151. package/scaffold/astro-app/src/pages/docs/design-system.astro +0 -9
  152. package/scaffold/astro-app/src/pages/docs/getting-started.astro +0 -9
  153. package/scaffold/astro-app/src/pages/docs/index.astro +0 -15
  154. package/scaffold/astro-app/src/pages/docs/themes/[theme].astro +0 -14
  155. package/scaffold/astro-app/src/pages/docs/theming.astro +0 -10
  156. package/scaffold/astro-app/src/pages/index.astro +0 -24
  157. package/scaffold/svelte-app/README.md +0 -39
  158. package/scaffold/svelte-app/package.json +0 -22
  159. package/scaffold/svelte-app/src/app.d.ts +0 -28
  160. package/scaffold/svelte-app/src/app.html +0 -21
  161. package/scaffold/svelte-app/src/lib/assets/favicon.svg +0 -1
  162. package/scaffold/svelte-app/src/lib/rizzo/Accordion.svelte +0 -128
  163. package/scaffold/svelte-app/src/lib/rizzo/Alert.svelte +0 -85
  164. package/scaffold/svelte-app/src/lib/rizzo/Avatar.svelte +0 -39
  165. package/scaffold/svelte-app/src/lib/rizzo/Badge.svelte +0 -31
  166. package/scaffold/svelte-app/src/lib/rizzo/Breadcrumb.svelte +0 -49
  167. package/scaffold/svelte-app/src/lib/rizzo/Button.svelte +0 -27
  168. package/scaffold/svelte-app/src/lib/rizzo/Card.svelte +0 -17
  169. package/scaffold/svelte-app/src/lib/rizzo/Checkbox.svelte +0 -37
  170. package/scaffold/svelte-app/src/lib/rizzo/CopyToClipboard.svelte +0 -79
  171. package/scaffold/svelte-app/src/lib/rizzo/Divider.svelte +0 -28
  172. package/scaffold/svelte-app/src/lib/rizzo/Dropdown.svelte +0 -254
  173. package/scaffold/svelte-app/src/lib/rizzo/FormGroup.svelte +0 -51
  174. package/scaffold/svelte-app/src/lib/rizzo/Input.svelte +0 -59
  175. package/scaffold/svelte-app/src/lib/rizzo/Modal.svelte +0 -157
  176. package/scaffold/svelte-app/src/lib/rizzo/Pagination.svelte +0 -93
  177. package/scaffold/svelte-app/src/lib/rizzo/ProgressBar.svelte +0 -58
  178. package/scaffold/svelte-app/src/lib/rizzo/Radio.svelte +0 -38
  179. package/scaffold/svelte-app/src/lib/rizzo/Select.svelte +0 -51
  180. package/scaffold/svelte-app/src/lib/rizzo/Spinner.svelte +0 -14
  181. package/scaffold/svelte-app/src/lib/rizzo/Table.svelte +0 -158
  182. package/scaffold/svelte-app/src/lib/rizzo/Tabs.svelte +0 -117
  183. package/scaffold/svelte-app/src/lib/rizzo/Textarea.svelte +0 -59
  184. package/scaffold/svelte-app/src/lib/rizzo/ThemeIcon.svelte +0 -54
  185. package/scaffold/svelte-app/src/lib/rizzo/ThemeSwitcher.svelte +0 -315
  186. package/scaffold/svelte-app/src/lib/rizzo/Toast.svelte +0 -33
  187. package/scaffold/svelte-app/src/lib/rizzo/Tooltip.svelte +0 -19
  188. package/scaffold/svelte-app/src/lib/rizzo/icons/Check.svelte +0 -29
  189. package/scaffold/svelte-app/src/lib/rizzo/icons/ChevronDown.svelte +0 -29
  190. package/scaffold/svelte-app/src/lib/rizzo/icons/Circle.svelte +0 -29
  191. package/scaffold/svelte-app/src/lib/rizzo/icons/Close.svelte +0 -30
  192. package/scaffold/svelte-app/src/lib/rizzo/icons/Cmd.svelte +0 -27
  193. package/scaffold/svelte-app/src/lib/rizzo/icons/Copy.svelte +0 -30
  194. package/scaffold/svelte-app/src/lib/rizzo/icons/Eye.svelte +0 -30
  195. package/scaffold/svelte-app/src/lib/rizzo/icons/Filter.svelte +0 -29
  196. package/scaffold/svelte-app/src/lib/rizzo/icons/Gear.svelte +0 -30
  197. package/scaffold/svelte-app/src/lib/rizzo/icons/IceCream.svelte +0 -31
  198. package/scaffold/svelte-app/src/lib/rizzo/icons/Moon.svelte +0 -29
  199. package/scaffold/svelte-app/src/lib/rizzo/icons/Owl.svelte +0 -34
  200. package/scaffold/svelte-app/src/lib/rizzo/icons/Palette.svelte +0 -33
  201. package/scaffold/svelte-app/src/lib/rizzo/icons/Rainbow.svelte +0 -31
  202. package/scaffold/svelte-app/src/lib/rizzo/icons/Search.svelte +0 -30
  203. package/scaffold/svelte-app/src/lib/rizzo/icons/Snowflake.svelte +0 -34
  204. package/scaffold/svelte-app/src/lib/rizzo/icons/Sort.svelte +0 -30
  205. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Astro.svelte +0 -45
  206. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Bash.svelte +0 -28
  207. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Css3.svelte +0 -23
  208. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Git.svelte +0 -18
  209. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Html5.svelte +0 -21
  210. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Javascript.svelte +0 -19
  211. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Nodejs.svelte +0 -44
  212. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Plaintext.svelte +0 -24
  213. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/React.svelte +0 -21
  214. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/SvelteIcon.svelte +0 -19
  215. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Vue.svelte +0 -20
  216. package/scaffold/svelte-app/src/lib/rizzo/index.ts +0 -35
  217. package/scaffold/svelte-app/src/lib/rizzo-docs/CodeBlock.svelte +0 -239
  218. package/scaffold/svelte-app/src/lib/rizzo-docs/SvelteDocPage.svelte +0 -99
  219. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AccordionDoc.svelte +0 -53
  220. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AlertDoc.svelte +0 -114
  221. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AvatarDoc.svelte +0 -92
  222. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BadgeDoc.svelte +0 -60
  223. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BreadcrumbDoc.svelte +0 -55
  224. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ButtonDoc.svelte +0 -55
  225. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CardsDoc.svelte +0 -173
  226. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComingSoon.svelte +0 -12
  227. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComponentsOverview.svelte +0 -92
  228. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CopyToClipboardDoc.svelte +0 -26
  229. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DividerDoc.svelte +0 -105
  230. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DropdownDoc.svelte +0 -161
  231. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/FormsDoc.svelte +0 -375
  232. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/IconsDoc.svelte +0 -246
  233. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Index.svelte +0 -8
  234. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ModalDoc.svelte +0 -50
  235. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/NavbarDoc.svelte +0 -79
  236. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/PaginationDoc.svelte +0 -44
  237. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ProgressBarDoc.svelte +0 -95
  238. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SearchDoc.svelte +0 -147
  239. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SettingsDoc.svelte +0 -158
  240. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SpinnerDoc.svelte +0 -41
  241. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TableDoc.svelte +0 -116
  242. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TabsDoc.svelte +0 -152
  243. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ThemeSwitcherDoc.svelte +0 -189
  244. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Theming.svelte +0 -6
  245. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ToastDoc.svelte +0 -136
  246. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TooltipDoc.svelte +0 -57
  247. package/scaffold/svelte-app/src/routes/+layout.svelte +0 -10
  248. package/scaffold/svelte-app/src/routes/+page.svelte +0 -31
  249. package/scaffold/svelte-app/src/routes/components/+page.svelte +0 -4
  250. package/scaffold/svelte-app/src/routes/components/[slug]/+page.svelte +0 -7
  251. package/scaffold/svelte-app/static/robots.txt +0 -3
  252. package/scaffold/svelte-app/svelte.config.js +0 -13
  253. package/scaffold/svelte-app/tsconfig.json +0 -21
  254. package/scaffold/svelte-app/vite.config.ts +0 -6
  255. /package/scaffold/{astro-app → astro-minimal}/astro.config.mjs +0 -0
  256. /package/scaffold/{astro-app → astro-minimal}/public/.gitkeep +0 -0
  257. /package/scaffold/{astro-app → astro-minimal}/public/favicon.svg +0 -0
  258. /package/scaffold/{astro-app → astro-minimal}/tsconfig.json +0 -0
  259. /package/scaffold/{svelte-app → svelte-minimal}/static/.gitkeep +0 -0
@@ -1,807 +0,0 @@
1
- ---
2
- import ChevronDown from './icons/ChevronDown.astro';
3
-
4
- interface MenuItem {
5
- label: string;
6
- value?: string;
7
- href?: string;
8
- onClick?: string;
9
- disabled?: boolean;
10
- separator?: boolean;
11
- submenu?: MenuItem[];
12
- }
13
-
14
- interface Props {
15
- trigger: string;
16
- items: MenuItem[];
17
- id?: string;
18
- class?: string;
19
- position?: 'left' | 'right';
20
- align?: 'start' | 'end';
21
- }
22
-
23
- const {
24
- trigger,
25
- items,
26
- id,
27
- class: className = '',
28
- position = 'left',
29
- align = 'start',
30
- } = Astro.props;
31
-
32
- const dropdownId = id || `dropdown-${Math.random().toString(36).substr(2, 9)}`;
33
- const triggerId = `${dropdownId}-trigger`;
34
- const menuId = `${dropdownId}-menu`;
35
- ---
36
-
37
- <div class={`dropdown ${className}`.trim()} data-dropdown={dropdownId}>
38
- <button
39
- type="button"
40
- class="dropdown__trigger"
41
- id={triggerId}
42
- aria-expanded="false"
43
- aria-haspopup="true"
44
- aria-controls={menuId}
45
- aria-label={trigger}
46
- >
47
- <span class="dropdown__trigger-text">{trigger}</span>
48
- <ChevronDown class="dropdown__icon" width={16} height={16} />
49
- </button>
50
-
51
- <div
52
- class={`dropdown__menu dropdown__menu--${position} dropdown__menu--${align}`}
53
- id={menuId}
54
- role="menu"
55
- aria-labelledby={triggerId}
56
- aria-label={`${trigger} menu`}
57
- aria-orientation="vertical"
58
- aria-hidden="true"
59
- tabindex="-1"
60
- >
61
- {items.map((item, index) => {
62
- if (item.separator) {
63
- return <div class="dropdown__separator" role="separator" />;
64
- }
65
-
66
- const itemId = `${dropdownId}-item-${index}`;
67
- const hasSubmenu = item.submenu && item.submenu.length > 0;
68
- const submenuId = hasSubmenu ? `${dropdownId}-submenu-${index}` : undefined;
69
-
70
- if (item.href) {
71
- return (
72
- <div class={`dropdown__item-wrapper ${hasSubmenu ? 'dropdown__item-wrapper--has-submenu' : ''}`}>
73
- {hasSubmenu ? (
74
- <div
75
- class={`dropdown__item ${item.disabled ? 'dropdown__item--disabled' : ''} dropdown__item--has-submenu`}
76
- role="menuitem"
77
- id={itemId}
78
- tabindex="-1"
79
- aria-label={item.label}
80
- aria-disabled={item.disabled ? 'true' : 'false'}
81
- aria-expanded="false"
82
- aria-haspopup="true"
83
- aria-controls={submenuId}
84
- data-dropdown-has-submenu="true"
85
- >
86
- <span>{item.label}</span>
87
- <ChevronDown class="dropdown__item-arrow" width={12} height={12} />
88
- </div>
89
- ) : (
90
- <div
91
- class={`dropdown__item ${item.disabled ? 'dropdown__item--disabled' : ''}`}
92
- role="menuitem"
93
- id={itemId}
94
- tabindex="-1"
95
- aria-label={item.label}
96
- aria-disabled={item.disabled ? 'true' : 'false'}
97
- data-dropdown-href={item.href}
98
- >
99
- <span>{item.label}</span>
100
- </div>
101
- )}
102
- {hasSubmenu && item.submenu && (
103
- <div
104
- class="dropdown__submenu"
105
- id={submenuId}
106
- role="menu"
107
- aria-label={`${item.label} submenu`}
108
- aria-hidden="true"
109
- >
110
- {item.submenu.map((subItem, subIndex) => {
111
- if (subItem.separator) {
112
- return <div class="dropdown__separator" role="separator" />;
113
- }
114
-
115
- const subItemId = `${submenuId}-item-${subIndex}`;
116
- const hasNestedSubmenu = subItem.submenu && subItem.submenu.length > 0;
117
- const nestedSubmenuId = hasNestedSubmenu ? `${subItemId}-submenu` : undefined;
118
-
119
- if (subItem.href) {
120
- return (
121
- <div class={`dropdown__item-wrapper ${hasNestedSubmenu ? 'dropdown__item-wrapper--has-submenu' : ''}`}>
122
- {hasNestedSubmenu ? (
123
- <div
124
- class={`dropdown__item dropdown__submenu-item ${subItem.disabled ? 'dropdown__item--disabled' : ''} dropdown__item--has-submenu`}
125
- role="menuitem"
126
- id={subItemId}
127
- tabindex="-1"
128
- aria-label={subItem.label}
129
- aria-disabled={subItem.disabled ? 'true' : 'false'}
130
- aria-expanded="false"
131
- aria-haspopup="true"
132
- aria-controls={nestedSubmenuId}
133
- data-dropdown-has-submenu="true"
134
- >
135
- <span>{subItem.label}</span>
136
- <ChevronDown class="dropdown__item-arrow" width={12} height={12} />
137
- </div>
138
- ) : (
139
- <div
140
- class={`dropdown__item dropdown__submenu-item ${subItem.disabled ? 'dropdown__item--disabled' : ''}`}
141
- role="menuitem"
142
- id={subItemId}
143
- tabindex="-1"
144
- aria-label={subItem.label}
145
- aria-disabled={subItem.disabled ? 'true' : 'false'}
146
- data-dropdown-href={subItem.href}
147
- >
148
- <span>{subItem.label}</span>
149
- </div>
150
- )}
151
- {hasNestedSubmenu && subItem.submenu && (
152
- <div
153
- class="dropdown__submenu"
154
- id={nestedSubmenuId}
155
- role="menu"
156
- aria-label={`${subItem.label} submenu`}
157
- aria-hidden="true"
158
- >
159
- {subItem.submenu.map((nestedItem, nestedIndex) => {
160
- if (nestedItem.separator) {
161
- return <div class="dropdown__separator" role="separator" />;
162
- }
163
-
164
- const nestedItemId = `${nestedSubmenuId}-item-${nestedIndex}`;
165
-
166
- if (nestedItem.href) {
167
- return (
168
- <div
169
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
170
- role="menuitem"
171
- id={nestedItemId}
172
- tabindex="-1"
173
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
174
- data-dropdown-href={nestedItem.href}
175
- >
176
- <span>{nestedItem.label}</span>
177
- </div>
178
- );
179
- }
180
-
181
- return (
182
- <div
183
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
184
- role="menuitem"
185
- id={nestedItemId}
186
- tabindex="-1"
187
- aria-label={nestedItem.label}
188
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
189
- data-dropdown-value={nestedItem.value || nestedItem.label}
190
- data-dropdown-onclick={nestedItem.onClick || ''}
191
- >
192
- <span>{nestedItem.label}</span>
193
- </div>
194
- );
195
- })}
196
- </div>
197
- )}
198
- </div>
199
- );
200
- }
201
-
202
- return (
203
- <div class={`dropdown__item-wrapper ${hasNestedSubmenu ? 'dropdown__item-wrapper--has-submenu' : ''}`}>
204
- <div
205
- class={`dropdown__item dropdown__submenu-item ${subItem.disabled ? 'dropdown__item--disabled' : ''} ${hasNestedSubmenu ? 'dropdown__item--has-submenu' : ''}`}
206
- role="menuitem"
207
- id={subItemId}
208
- tabindex="-1"
209
- aria-label={subItem.label}
210
- aria-disabled={subItem.disabled ? 'true' : 'false'}
211
- aria-expanded={hasNestedSubmenu ? 'false' : undefined}
212
- aria-haspopup={hasNestedSubmenu ? 'true' : undefined}
213
- aria-controls={nestedSubmenuId}
214
- data-dropdown-value={subItem.value || subItem.label}
215
- data-dropdown-onclick={subItem.onClick || ''}
216
- data-dropdown-has-submenu={hasNestedSubmenu ? 'true' : undefined}
217
- >
218
- <span>{subItem.label}</span>
219
- {hasNestedSubmenu && <ChevronDown class="dropdown__item-arrow" width={12} height={12} />}
220
- </div>
221
- {hasNestedSubmenu && subItem.submenu && (
222
- <div
223
- class="dropdown__submenu"
224
- id={nestedSubmenuId}
225
- role="menu"
226
- aria-label={`${subItem.label} submenu`}
227
- aria-hidden="true"
228
- >
229
- {subItem.submenu.map((nestedItem, nestedIndex) => {
230
- if (nestedItem.separator) {
231
- return <div class="dropdown__separator" role="separator" />;
232
- }
233
-
234
- const nestedItemId = `${nestedSubmenuId}-item-${nestedIndex}`;
235
-
236
- if (nestedItem.href) {
237
- return (
238
- <div
239
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
240
- role="menuitem"
241
- id={nestedItemId}
242
- tabindex="-1"
243
- aria-label={nestedItem.label}
244
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
245
- data-dropdown-href={nestedItem.href}
246
- >
247
- <span>{nestedItem.label}</span>
248
- </div>
249
- );
250
- }
251
-
252
- return (
253
- <div
254
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
255
- role="menuitem"
256
- id={nestedItemId}
257
- tabindex="-1"
258
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
259
- data-dropdown-value={nestedItem.value || nestedItem.label}
260
- data-dropdown-onclick={nestedItem.onClick || ''}
261
- >
262
- <span>{nestedItem.label}</span>
263
- </div>
264
- );
265
- })}
266
- </div>
267
- )}
268
- </div>
269
- );
270
- })}
271
- </div>
272
- )}
273
- </div>
274
- );
275
- }
276
-
277
- return (
278
- <div class={`dropdown__item-wrapper ${hasSubmenu ? 'dropdown__item-wrapper--has-submenu' : ''}`}>
279
- <div
280
- class={`dropdown__item ${item.disabled ? 'dropdown__item--disabled' : ''} ${hasSubmenu ? 'dropdown__item--has-submenu' : ''}`}
281
- role="menuitem"
282
- id={itemId}
283
- tabindex="-1"
284
- aria-disabled={item.disabled ? 'true' : 'false'}
285
- aria-expanded={hasSubmenu ? 'false' : undefined}
286
- aria-haspopup={hasSubmenu ? 'true' : undefined}
287
- aria-controls={submenuId}
288
- data-dropdown-value={item.value || item.label}
289
- data-dropdown-onclick={item.onClick || ''}
290
- data-dropdown-has-submenu={hasSubmenu ? 'true' : undefined}
291
- >
292
- <span>{item.label}</span>
293
- {hasSubmenu && <ChevronDown class="dropdown__item-arrow" width={12} height={12} />}
294
- </div>
295
- {hasSubmenu && item.submenu && (
296
- <div
297
- class="dropdown__submenu"
298
- id={submenuId}
299
- role="menu"
300
- aria-label={`${item.label} submenu`}
301
- aria-hidden="true"
302
- >
303
- {item.submenu.map((subItem, subIndex) => {
304
- if (subItem.separator) {
305
- return <div class="dropdown__separator" role="separator" />;
306
- }
307
-
308
- const subItemId = `${submenuId}-item-${subIndex}`;
309
- const hasNestedSubmenu = subItem.submenu && subItem.submenu.length > 0;
310
- const nestedSubmenuId = hasNestedSubmenu ? `${subItemId}-submenu` : undefined;
311
-
312
- if (subItem.href) {
313
- return (
314
- <div class={`dropdown__item-wrapper ${hasNestedSubmenu ? 'dropdown__item-wrapper--has-submenu' : ''}`}>
315
- {hasNestedSubmenu ? (
316
- <div
317
- class={`dropdown__item dropdown__submenu-item ${subItem.disabled ? 'dropdown__item--disabled' : ''} dropdown__item--has-submenu`}
318
- role="menuitem"
319
- id={subItemId}
320
- tabindex="-1"
321
- aria-disabled={subItem.disabled ? 'true' : 'false'}
322
- aria-expanded="false"
323
- aria-haspopup="true"
324
- aria-controls={nestedSubmenuId}
325
- data-dropdown-has-submenu="true"
326
- >
327
- <span>{subItem.label}</span>
328
- <ChevronDown class="dropdown__item-arrow" width={12} height={12} />
329
- </div>
330
- ) : (
331
- <div
332
- class={`dropdown__item dropdown__submenu-item ${subItem.disabled ? 'dropdown__item--disabled' : ''}`}
333
- role="menuitem"
334
- id={subItemId}
335
- tabindex="-1"
336
- aria-disabled={subItem.disabled ? 'true' : 'false'}
337
- data-dropdown-href={subItem.href}
338
- >
339
- <span>{subItem.label}</span>
340
- </div>
341
- )}
342
- {hasNestedSubmenu && subItem.submenu && (
343
- <div
344
- class="dropdown__submenu"
345
- id={nestedSubmenuId}
346
- role="menu"
347
- aria-label={`${subItem.label} submenu`}
348
- aria-hidden="true"
349
- >
350
- {subItem.submenu.map((nestedItem, nestedIndex) => {
351
- if (nestedItem.separator) {
352
- return <div class="dropdown__separator" role="separator" />;
353
- }
354
-
355
- const nestedItemId = `${nestedSubmenuId}-item-${nestedIndex}`;
356
-
357
- if (nestedItem.href) {
358
- return (
359
- <div
360
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
361
- role="menuitem"
362
- id={nestedItemId}
363
- tabindex="-1"
364
- aria-label={nestedItem.label}
365
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
366
- data-dropdown-href={nestedItem.href}
367
- >
368
- <span>{nestedItem.label}</span>
369
- </div>
370
- );
371
- }
372
-
373
- return (
374
- <div
375
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
376
- role="menuitem"
377
- id={nestedItemId}
378
- tabindex="-1"
379
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
380
- data-dropdown-value={nestedItem.value || nestedItem.label}
381
- data-dropdown-onclick={nestedItem.onClick || ''}
382
- >
383
- <span>{nestedItem.label}</span>
384
- </div>
385
- );
386
- })}
387
- </div>
388
- )}
389
- </div>
390
- );
391
- }
392
-
393
- return (
394
- <div class={`dropdown__item-wrapper ${hasNestedSubmenu ? 'dropdown__item-wrapper--has-submenu' : ''}`}>
395
- <div
396
- class={`dropdown__item dropdown__submenu-item ${subItem.disabled ? 'dropdown__item--disabled' : ''} ${hasNestedSubmenu ? 'dropdown__item--has-submenu' : ''}`}
397
- role="menuitem"
398
- id={subItemId}
399
- tabindex="-1"
400
- aria-label={subItem.label}
401
- aria-disabled={subItem.disabled ? 'true' : 'false'}
402
- aria-expanded={hasNestedSubmenu ? 'false' : undefined}
403
- aria-haspopup={hasNestedSubmenu ? 'true' : undefined}
404
- aria-controls={nestedSubmenuId}
405
- data-dropdown-value={subItem.value || subItem.label}
406
- data-dropdown-onclick={subItem.onClick || ''}
407
- data-dropdown-has-submenu={hasNestedSubmenu ? 'true' : undefined}
408
- >
409
- <span>{subItem.label}</span>
410
- {hasNestedSubmenu && <ChevronDown class="dropdown__item-arrow" width={12} height={12} />}
411
- </div>
412
- {hasNestedSubmenu && subItem.submenu && (
413
- <div
414
- class="dropdown__submenu"
415
- id={nestedSubmenuId}
416
- role="menu"
417
- aria-label={`${subItem.label} submenu`}
418
- aria-hidden="true"
419
- >
420
- {subItem.submenu.map((nestedItem, nestedIndex) => {
421
- if (nestedItem.separator) {
422
- return <div class="dropdown__separator" role="separator" />;
423
- }
424
-
425
- const nestedItemId = `${nestedSubmenuId}-item-${nestedIndex}`;
426
-
427
- if (nestedItem.href) {
428
- return (
429
- <div
430
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
431
- role="menuitem"
432
- id={nestedItemId}
433
- tabindex="-1"
434
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
435
- data-dropdown-href={nestedItem.href}
436
- >
437
- <span>{nestedItem.label}</span>
438
- </div>
439
- );
440
- }
441
-
442
- return (
443
- <div
444
- class={`dropdown__item dropdown__submenu-item ${nestedItem.disabled ? 'dropdown__item--disabled' : ''}`}
445
- role="menuitem"
446
- id={nestedItemId}
447
- tabindex="-1"
448
- aria-disabled={nestedItem.disabled ? 'true' : 'false'}
449
- data-dropdown-value={nestedItem.value || nestedItem.label}
450
- data-dropdown-onclick={nestedItem.onClick || ''}
451
- >
452
- <span>{nestedItem.label}</span>
453
- </div>
454
- );
455
- })}
456
- </div>
457
- )}
458
- </div>
459
- );
460
- })}
461
- </div>
462
- )}
463
- </div>
464
- );
465
- })}
466
- </div>
467
- </div>
468
-
469
- <script is:inline>
470
- (function initDropdown() {
471
- const init = () => {
472
- const dropdowns = document.querySelectorAll('[data-dropdown]');
473
-
474
- dropdowns.forEach((dropdown) => {
475
- const dropdownId = dropdown.getAttribute('data-dropdown');
476
- if (!dropdownId) return;
477
-
478
- if (dropdown.hasAttribute('data-dropdown-initialized')) return;
479
- dropdown.setAttribute('data-dropdown-initialized', 'true');
480
-
481
- const trigger = dropdown.querySelector('.dropdown__trigger');
482
- const menu = dropdown.querySelector('.dropdown__menu');
483
- const items = dropdown.querySelectorAll('.dropdown__item');
484
- const itemWrappers = dropdown.querySelectorAll('.dropdown__item-wrapper');
485
-
486
- if (!trigger || !menu) return;
487
-
488
- let currentIndex = -1;
489
-
490
- const getVisibleItems = () => {
491
- return Array.from(items).filter(item => {
492
- const isDisabled = item.getAttribute('aria-disabled') === 'true';
493
- const wrapper = item.closest('.dropdown__item-wrapper');
494
- const submenu = wrapper ? wrapper.querySelector('.dropdown__submenu') : null;
495
- // Don't include submenu items in main navigation
496
- if (submenu && item.closest('.dropdown__submenu')) {
497
- return false;
498
- }
499
- return !isDisabled && (item.offsetParent !== null || menu.classList.contains('dropdown__menu--open'));
500
- });
501
- };
502
-
503
- // Close all submenus except the one being opened
504
- const closeAllSubmenus = (exceptWrapper = null) => {
505
- itemWrappers.forEach((wrapper) => {
506
- if (wrapper === exceptWrapper) return; // Don't close the one we're opening
507
- const submenu = wrapper.querySelector('.dropdown__submenu');
508
- const item = wrapper.querySelector('.dropdown__item');
509
- if (submenu && item) {
510
- submenu.classList.remove('dropdown__submenu--open');
511
- submenu.setAttribute('aria-hidden', 'true');
512
- item.setAttribute('aria-expanded', 'false');
513
- }
514
- });
515
- };
516
-
517
- // Toggle submenu
518
- const toggleSubmenu = (wrapper, open) => {
519
- const submenu = wrapper.querySelector('.dropdown__submenu');
520
- const item = wrapper.querySelector('.dropdown__item');
521
- if (!submenu || !item) return;
522
-
523
- const isOpen = open !== undefined ? open : submenu.classList.contains('dropdown__submenu--open');
524
- const willBeOpen = !isOpen;
525
-
526
- // Close other submenus at the same level, but keep parent submenus open
527
- if (willBeOpen) {
528
- // Find all submenus at the same level (siblings of the current wrapper's parent)
529
- const parentSubmenu = wrapper.closest('.dropdown__submenu');
530
- if (parentSubmenu) {
531
- // Close siblings within the same parent submenu
532
- const siblingWrappers = parentSubmenu.querySelectorAll('.dropdown__item-wrapper');
533
- siblingWrappers.forEach((siblingWrapper) => {
534
- if (siblingWrapper === wrapper) return; // Don't close the one we're opening
535
- const siblingSubmenu = siblingWrapper.querySelector('.dropdown__submenu');
536
- const siblingItem = siblingWrapper.querySelector('.dropdown__item');
537
- if (siblingSubmenu && siblingItem) {
538
- siblingSubmenu.classList.remove('dropdown__submenu--open');
539
- siblingSubmenu.setAttribute('aria-hidden', 'true');
540
- siblingItem.setAttribute('aria-expanded', 'false');
541
- }
542
- });
543
- } else {
544
- // Main menu level - close all other main menu submenus
545
- closeAllSubmenus(wrapper);
546
- }
547
- }
548
-
549
- // Toggle the open class
550
- if (willBeOpen) {
551
- submenu.classList.add('dropdown__submenu--open');
552
- submenu.setAttribute('aria-hidden', 'false');
553
- item.setAttribute('aria-expanded', 'true');
554
- } else {
555
- submenu.classList.remove('dropdown__submenu--open');
556
- submenu.setAttribute('aria-hidden', 'true');
557
- item.setAttribute('aria-expanded', 'false');
558
- }
559
-
560
- // Position submenu - now positioned directly under the item
561
- if (willBeOpen) {
562
- // Submenu is positioned directly under via CSS (top: 100%, left: 0, right: 0)
563
- // No JavaScript positioning needed
564
- } else {
565
- // Reset any inline styles when closing
566
- submenu.style.left = '';
567
- submenu.style.right = '';
568
- submenu.style.top = '';
569
- submenu.style.marginLeft = '';
570
- submenu.style.marginRight = '';
571
- submenu.style.marginTop = '';
572
- submenu.style.maxWidth = '';
573
- submenu.style.width = '';
574
- }
575
- };
576
-
577
- const toggleMenu = (open) => {
578
- const isOpen = open !== undefined ? open : menu.classList.contains('dropdown__menu--open');
579
- const willBeOpen = !isOpen;
580
-
581
- menu.classList.toggle('dropdown__menu--open', willBeOpen);
582
- trigger.setAttribute('aria-expanded', willBeOpen.toString());
583
- menu.setAttribute('aria-hidden', (!willBeOpen).toString());
584
-
585
- items.forEach((item) => {
586
- item.setAttribute('tabindex', willBeOpen ? '0' : '-1');
587
- });
588
-
589
- if (!willBeOpen) {
590
- trigger.focus();
591
- currentIndex = -1;
592
- closeAllSubmenus();
593
- } else {
594
- const visibleItems = getVisibleItems();
595
- if (visibleItems.length > 0) {
596
- currentIndex = 0;
597
- setTimeout(() => visibleItems[0].focus(), 0);
598
- }
599
- }
600
- };
601
-
602
- const closeMenu = () => {
603
- menu.classList.remove('dropdown__menu--open');
604
- trigger.setAttribute('aria-expanded', 'false');
605
- menu.setAttribute('aria-hidden', 'true');
606
- items.forEach((item) => {
607
- item.setAttribute('tabindex', '-1');
608
- });
609
- closeAllSubmenus();
610
- currentIndex = -1;
611
- };
612
-
613
- // Handle outside click
614
- const handleOutsideClick = (e) => {
615
- if (e && e.target && !dropdown.contains(e.target)) {
616
- closeMenu();
617
- document.removeEventListener('click', handleOutsideClick);
618
- }
619
- };
620
-
621
- const wrappedToggleMenu = (open) => {
622
- const wasOpen = menu.classList.contains('dropdown__menu--open');
623
- toggleMenu(open);
624
- const isNowOpen = menu.classList.contains('dropdown__menu--open');
625
-
626
- if (isNowOpen && !wasOpen) {
627
- setTimeout(() => document.addEventListener('click', handleOutsideClick), 0);
628
- } else if (!isNowOpen && wasOpen) {
629
- document.removeEventListener('click', handleOutsideClick);
630
- }
631
- };
632
-
633
- // Trigger click
634
- trigger.addEventListener('click', () => wrappedToggleMenu(undefined));
635
-
636
- // Menu item click handler - handles all clicks including nested submenus
637
- menu.addEventListener('click', (e) => {
638
- const target = e.target;
639
- // Find the item - could be the button/a itself, or a child element (span, arrow icon, etc.)
640
- const item = target.closest('.dropdown__item');
641
- if (!item) return;
642
-
643
- // Stop propagation to prevent outside click handler from firing
644
- e.stopPropagation();
645
-
646
- const isDisabled = item.getAttribute('aria-disabled') === 'true';
647
- if (isDisabled) {
648
- e.preventDefault();
649
- return;
650
- }
651
-
652
- // FIRST: Check if item has submenu by finding wrapper and checking for submenu
653
- // This must be checked FIRST, regardless of whether item is in a submenu or not
654
- const wrapper = item.closest('.dropdown__item-wrapper');
655
-
656
- if (wrapper) {
657
- const submenu = wrapper.querySelector('.dropdown__submenu');
658
- if (submenu) {
659
- // Item has submenu - toggle it (works for main menu items AND nested submenu items)
660
- e.preventDefault();
661
- e.stopImmediatePropagation();
662
- toggleSubmenu(wrapper, undefined);
663
- return;
664
- }
665
- }
666
-
667
- // Item does NOT have a submenu - handle as regular item
668
- const href = item.getAttribute('data-dropdown-href');
669
- if (href) {
670
- window.location.href = href;
671
- }
672
- const onClick = item.getAttribute('data-dropdown-onclick');
673
- if (onClick && typeof window[onClick] === 'function') {
674
- const value = item.getAttribute('data-dropdown-value') || item.textContent?.trim() || '';
675
- window[onClick](value);
676
- }
677
-
678
- // Close menu for final items (items without submenus)
679
- closeMenu();
680
- });
681
-
682
- // Keyboard navigation on trigger
683
- trigger.addEventListener('keydown', (e) => {
684
- if (e && 'key' in e) {
685
- const keyEvent = e;
686
- if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
687
- keyEvent.preventDefault();
688
- wrappedToggleMenu(undefined);
689
- } else if (keyEvent.key === 'ArrowDown') {
690
- keyEvent.preventDefault();
691
- const visibleItems = getVisibleItems();
692
- if (visibleItems.length > 0) {
693
- currentIndex = 0;
694
- wrappedToggleMenu(true);
695
- setTimeout(() => visibleItems[0].focus(), 0);
696
- }
697
- } else if (keyEvent.key === 'ArrowUp') {
698
- keyEvent.preventDefault();
699
- const visibleItems = getVisibleItems();
700
- if (visibleItems.length > 0) {
701
- currentIndex = visibleItems.length - 1;
702
- wrappedToggleMenu(true);
703
- setTimeout(() => visibleItems[currentIndex].focus(), 0);
704
- }
705
- } else if (keyEvent.key === 'Escape') {
706
- keyEvent.preventDefault();
707
- closeMenu();
708
- }
709
- }
710
- });
711
-
712
- // Keyboard navigation in menu
713
- menu.addEventListener('keydown', (e) => {
714
- if (e && 'key' in e) {
715
- const keyEvent = e;
716
- const visibleItems = getVisibleItems();
717
-
718
- if (keyEvent.key === 'Escape') {
719
- keyEvent.preventDefault();
720
- closeMenu();
721
- trigger.focus();
722
- } else if (keyEvent.key === 'ArrowDown') {
723
- keyEvent.preventDefault();
724
- currentIndex = (currentIndex + 1) % visibleItems.length;
725
- visibleItems[currentIndex].focus();
726
- } else if (keyEvent.key === 'ArrowUp') {
727
- keyEvent.preventDefault();
728
- currentIndex = currentIndex <= 0 ? visibleItems.length - 1 : currentIndex - 1;
729
- visibleItems[currentIndex].focus();
730
- } else if (keyEvent.key === 'Home') {
731
- keyEvent.preventDefault();
732
- currentIndex = 0;
733
- visibleItems[0].focus();
734
- } else if (keyEvent.key === 'End') {
735
- keyEvent.preventDefault();
736
- currentIndex = visibleItems.length - 1;
737
- visibleItems[currentIndex].focus();
738
- } else if (keyEvent.key === 'ArrowRight') {
739
- // Open submenu if available
740
- const target = keyEvent.target;
741
- if (target && target instanceof HTMLElement) {
742
- const wrapper = target.closest('.dropdown__item-wrapper');
743
- if (wrapper) {
744
- const submenu = wrapper.querySelector('.dropdown__submenu');
745
- if (submenu) {
746
- keyEvent.preventDefault();
747
- toggleSubmenu(wrapper, true);
748
- const firstSubItem = submenu.querySelector('.dropdown__item');
749
- if (firstSubItem) {
750
- setTimeout(() => firstSubItem.focus(), 0);
751
- }
752
- }
753
- }
754
- }
755
- } else if (keyEvent.key === 'ArrowLeft') {
756
- // Close submenu if in one
757
- const target = keyEvent.target;
758
- if (target && target instanceof HTMLElement) {
759
- const submenu = target.closest('.dropdown__submenu');
760
- if (submenu) {
761
- keyEvent.preventDefault();
762
- const wrapper = submenu.closest('.dropdown__item-wrapper');
763
- if (wrapper) {
764
- toggleSubmenu(wrapper, false);
765
- const parentItem = wrapper.querySelector('.dropdown__item');
766
- if (parentItem) {
767
- parentItem.focus();
768
- }
769
- }
770
- }
771
- }
772
- } else if (keyEvent.key === 'Enter' || keyEvent.key === ' ') {
773
- keyEvent.preventDefault();
774
- const target = keyEvent.target;
775
- if (target && target instanceof HTMLElement) {
776
- const isDisabled = target.getAttribute('aria-disabled') === 'true';
777
- if (!isDisabled) {
778
- // Check if item has submenu
779
- const wrapper = target.closest('.dropdown__item-wrapper');
780
- const submenu = wrapper ? wrapper.querySelector('.dropdown__submenu') : null;
781
- if (submenu) {
782
- toggleSubmenu(wrapper, undefined);
783
- } else {
784
- if (target.tagName === 'A') {
785
- target.click();
786
- } else if (target.tagName === 'BUTTON') {
787
- target.click();
788
- }
789
- closeMenu();
790
- }
791
- }
792
- }
793
- } else if (keyEvent.key === 'Tab') {
794
- closeMenu();
795
- }
796
- }
797
- });
798
- });
799
- };
800
-
801
- if (document.readyState === 'loading') {
802
- document.addEventListener('DOMContentLoaded', init);
803
- } else {
804
- init();
805
- }
806
- })();
807
- </script>