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,254 +0,0 @@
1
- <script lang="ts">
2
- import { onMount } from 'svelte';
3
- import ChevronDown from './icons/ChevronDown.svelte';
4
-
5
- export interface MenuItem {
6
- label: string;
7
- value?: string;
8
- href?: string;
9
- onClick?: (value: string) => void;
10
- disabled?: boolean;
11
- separator?: boolean;
12
- submenu?: MenuItem[];
13
- }
14
-
15
- interface Props {
16
- trigger: string;
17
- items: MenuItem[];
18
- id?: string;
19
- class?: string;
20
- position?: 'left' | 'right';
21
- align?: 'start' | 'end';
22
- }
23
-
24
- let {
25
- trigger,
26
- items,
27
- id,
28
- class: className = '',
29
- position = 'left',
30
- align = 'start',
31
- }: Props = $props();
32
-
33
- const fallbackId = `dropdown-${Math.random().toString(36).slice(2, 11)}`;
34
- const dropdownId = $derived(id ?? fallbackId);
35
- const menuId = $derived(`${dropdownId}-menu`);
36
- const triggerId = $derived(`${dropdownId}-trigger`);
37
-
38
- let open = $state(false);
39
- let openSubmenuIndex = $state<number | null>(null);
40
- let menuEl: HTMLDivElement;
41
- let triggerEl: HTMLButtonElement;
42
-
43
- const classes = $derived(['dropdown', className].filter(Boolean).join(' ').trim());
44
- const menuClasses = $derived(`dropdown__menu dropdown__menu--${position} dropdown__menu--${align}`);
45
-
46
- function closeMenu() {
47
- open = false;
48
- openSubmenuIndex = null;
49
- }
50
-
51
- function toggleMenu() {
52
- open = !open;
53
- if (!open) openSubmenuIndex = null;
54
- }
55
-
56
- function toggleSubmenu(index: number) {
57
- openSubmenuIndex = openSubmenuIndex === index ? null : index;
58
- }
59
-
60
- function handleItemClick(item: MenuItem, e: MouseEvent) {
61
- if (item.separator || item.disabled) return;
62
- if (item.submenu?.length) {
63
- e.preventDefault();
64
- return;
65
- }
66
- if (item.href) {
67
- window.location.href = item.href;
68
- }
69
- if (item.onClick) {
70
- item.onClick(item.value ?? item.label);
71
- }
72
- closeMenu();
73
- }
74
-
75
- function handleKeydown(e: KeyboardEvent) {
76
- if (!open) return;
77
- if (e.key === 'Escape') {
78
- e.preventDefault();
79
- closeMenu();
80
- triggerEl?.focus();
81
- }
82
- }
83
-
84
- function handleClickOutside(e: MouseEvent) {
85
- if (menuEl && triggerEl && !menuEl.contains(e.target as Node) && !triggerEl.contains(e.target as Node)) {
86
- closeMenu();
87
- }
88
- }
89
-
90
- onMount(() => {
91
- document.addEventListener('keydown', handleKeydown);
92
- document.addEventListener('click', handleClickOutside);
93
- return () => {
94
- document.removeEventListener('keydown', handleKeydown);
95
- document.removeEventListener('click', handleClickOutside);
96
- };
97
- });
98
- </script>
99
-
100
- <div class={classes} data-dropdown={dropdownId}>
101
- <button
102
- bind:this={triggerEl}
103
- type="button"
104
- class="dropdown__trigger"
105
- id={triggerId}
106
- aria-expanded={open}
107
- aria-haspopup="true"
108
- aria-controls={menuId}
109
- aria-label={trigger}
110
- onclick={toggleMenu}
111
- onkeydown={(e) => {
112
- if (e.key === 'Enter' || e.key === ' ') {
113
- e.preventDefault();
114
- toggleMenu();
115
- }
116
- if (e.key === 'ArrowDown' && !open) {
117
- e.preventDefault();
118
- open = true;
119
- }
120
- }}
121
- >
122
- <span class="dropdown__trigger-text">{trigger}</span>
123
- <ChevronDown class="dropdown__icon" width={16} height={16} />
124
- </button>
125
-
126
- <div
127
- bind:this={menuEl}
128
- class="{menuClasses} {open ? 'dropdown__menu--open' : ''}"
129
- id={menuId}
130
- role="menu"
131
- aria-labelledby={triggerId}
132
- aria-label="{trigger} menu"
133
- aria-orientation="vertical"
134
- aria-hidden={!open}
135
- tabindex="-1"
136
- >
137
- {#each items as item, index}
138
- {#if item.separator}
139
- <div class="dropdown__separator" role="separator"></div>
140
- {:else}
141
- {@const hasSubmenu = item.submenu && item.submenu.length > 0}
142
- {@const isSubmenuOpen = openSubmenuIndex === index}
143
- <div class="dropdown__item-wrapper" class:dropdown__item-wrapper--has-submenu={hasSubmenu}>
144
- {#if item.href && !hasSubmenu}
145
- <a
146
- class="dropdown__item"
147
- class:dropdown__item--disabled={item.disabled}
148
- role="menuitem"
149
- href={item.href}
150
- aria-label={item.label}
151
- aria-disabled={item.disabled ? 'true' : undefined}
152
- tabindex={open ? 0 : -1}
153
- onclick={(e) => {
154
- if (item.disabled) e.preventDefault();
155
- else closeMenu();
156
- }}
157
- >
158
- <span>{item.label}</span>
159
- </a>
160
- {:else}
161
- <div
162
- class="dropdown__item"
163
- class:dropdown__item--disabled={item.disabled}
164
- class:dropdown__item--has-submenu={hasSubmenu}
165
- role="menuitem"
166
- aria-disabled={item.disabled ? 'true' : undefined}
167
- aria-expanded={hasSubmenu ? isSubmenuOpen : undefined}
168
- aria-haspopup={hasSubmenu ? 'true' : undefined}
169
- tabindex={open ? 0 : -1}
170
- onclick={(e) => {
171
- if (item.disabled) return;
172
- if (hasSubmenu) {
173
- e.preventDefault();
174
- toggleSubmenu(index);
175
- } else {
176
- handleItemClick(item, e);
177
- }
178
- }}
179
- onkeydown={(e) => {
180
- if (item.disabled) return;
181
- if (hasSubmenu && (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowRight')) {
182
- e.preventDefault();
183
- toggleSubmenu(index);
184
- } else if (!hasSubmenu && (e.key === 'Enter' || e.key === ' ')) {
185
- e.preventDefault();
186
- handleItemClick(item, e as unknown as MouseEvent);
187
- }
188
- }}
189
- >
190
- <span>{item.label}</span>
191
- {#if hasSubmenu}
192
- <ChevronDown class="dropdown__item-arrow" width={12} height={12} />
193
- {/if}
194
- </div>
195
- {/if}
196
- {#if hasSubmenu && item.submenu}
197
- <div
198
- class="dropdown__submenu"
199
- class:dropdown__submenu--open={isSubmenuOpen}
200
- role="menu"
201
- aria-label="{item.label} submenu"
202
- aria-hidden={!isSubmenuOpen}
203
- >
204
- {#each item.submenu as subItem}
205
- {#if subItem.separator}
206
- <div class="dropdown__separator" role="separator"></div>
207
- {:else if subItem.href}
208
- <a
209
- class="dropdown__item dropdown__submenu-item"
210
- class:dropdown__item--disabled={subItem.disabled}
211
- role="menuitem"
212
- href={subItem.href}
213
- aria-label={subItem.label}
214
- aria-disabled={subItem.disabled ? 'true' : undefined}
215
- onclick={(e) => {
216
- if (subItem.disabled) e.preventDefault();
217
- else closeMenu();
218
- }}
219
- >
220
- <span>{subItem.label}</span>
221
- </a>
222
- {:else}
223
- <div
224
- class="dropdown__item dropdown__submenu-item"
225
- class:dropdown__item--disabled={subItem.disabled}
226
- role="menuitem"
227
- aria-disabled={subItem.disabled ? 'true' : undefined}
228
- tabindex={open ? 0 : -1}
229
- onclick={(e) => {
230
- if (!subItem.disabled) {
231
- subItem.onClick?.(subItem.value ?? subItem.label);
232
- closeMenu();
233
- }
234
- }}
235
- onkeydown={(e) => {
236
- if (subItem.disabled) return;
237
- if (e.key === 'Enter' || e.key === ' ') {
238
- e.preventDefault();
239
- subItem.onClick?.(subItem.value ?? subItem.label);
240
- closeMenu();
241
- }
242
- }}
243
- >
244
- <span>{subItem.label}</span>
245
- </div>
246
- {/if}
247
- {/each}
248
- </div>
249
- {/if}
250
- </div>
251
- {/if}
252
- {/each}
253
- </div>
254
- </div>
@@ -1,51 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte';
3
-
4
- interface Props {
5
- label?: string;
6
- labelFor?: string;
7
- required?: boolean;
8
- help?: string;
9
- error?: string;
10
- success?: string;
11
- class?: string;
12
- children?: Snippet;
13
- }
14
- let {
15
- label,
16
- labelFor,
17
- required = false,
18
- help,
19
- error,
20
- success,
21
- class: className = '',
22
- children,
23
- }: Props = $props();
24
-
25
- const errorId = $derived(labelFor && error ? `${labelFor}-error` : undefined);
26
- const helpId = $derived(labelFor && help ? `${labelFor}-help` : undefined);
27
- </script>
28
-
29
- <div class="form-group {className}">
30
- {#if label}
31
- {#if labelFor}
32
- <label for={labelFor} class="form-group__label {required ? 'required' : ''}">
33
- {label}
34
- </label>
35
- {:else}
36
- <span class="form-group__label {required ? 'required' : ''}">
37
- {label}
38
- </span>
39
- {/if}
40
- {/if}
41
- {@render children?.()}
42
- {#if help}
43
- <span id={helpId} class="form-group__help">{help}</span>
44
- {/if}
45
- {#if error}
46
- <span id={errorId} class="form-error" role="alert">{error}</span>
47
- {/if}
48
- {#if success}
49
- <span class="form-success" role="status">{success}</span>
50
- {/if}
51
- </div>
@@ -1,59 +0,0 @@
1
- <script lang="ts">
2
- interface Props {
3
- type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'time' | 'datetime-local' | 'month' | 'week';
4
- id?: string;
5
- name?: string;
6
- value?: string;
7
- placeholder?: string;
8
- required?: boolean;
9
- disabled?: boolean;
10
- readonly?: boolean;
11
- autocomplete?: string;
12
- size?: 'sm' | 'md' | 'lg';
13
- error?: boolean;
14
- success?: boolean;
15
- class?: string;
16
- ariaDescribedby?: string;
17
- ariaInvalid?: boolean | 'true' | 'false';
18
- }
19
- let {
20
- type = 'text',
21
- id,
22
- name,
23
- value = $bindable(''),
24
- placeholder,
25
- required = false,
26
- disabled = false,
27
- readonly = false,
28
- autocomplete,
29
- size = 'md',
30
- error = false,
31
- success = false,
32
- class: className = '',
33
- ariaDescribedby,
34
- ariaInvalid,
35
- }: Props = $props();
36
-
37
- const sizeClass = $derived(size !== 'md' ? `form-input--${size}` : '');
38
- const errorClass = $derived(error ? 'form-input--error' : '');
39
- const successClass = $derived(success ? 'form-input--success' : '');
40
- const classes = $derived(
41
- ['form-input', sizeClass, errorClass, successClass, className].filter(Boolean).join(' ').trim()
42
- );
43
- const invalid = $derived(error || ariaInvalid === true || ariaInvalid === 'true');
44
- </script>
45
-
46
- <input
47
- {type}
48
- {id}
49
- {name}
50
- bind:value
51
- {placeholder}
52
- {required}
53
- {disabled}
54
- {readonly}
55
- autocomplete={autocomplete}
56
- class={classes}
57
- aria-invalid={invalid ? 'true' : 'false'}
58
- aria-describedby={ariaDescribedby}
59
- />
@@ -1,157 +0,0 @@
1
- <script lang="ts">
2
- import { tick } from 'svelte';
3
- import type { Snippet } from 'svelte';
4
-
5
- interface Props {
6
- id?: string;
7
- title?: string;
8
- size?: 'sm' | 'md' | 'lg';
9
- open?: boolean;
10
- closeOnOverlayClick?: boolean;
11
- closeOnEscape?: boolean;
12
- class?: string;
13
- children?: Snippet;
14
- footer?: Snippet;
15
- }
16
-
17
- let {
18
- id,
19
- title = 'Modal',
20
- size = 'md',
21
- open = $bindable(false),
22
- closeOnOverlayClick = true,
23
- closeOnEscape = true,
24
- class: className = '',
25
- children,
26
- footer,
27
- }: Props = $props();
28
-
29
- const modalId = $derived(id ?? `modal-${Math.random().toString(36).slice(2, 11)}`);
30
- const sizeClass = $derived(size !== 'md' ? `modal--${size}` : '');
31
- const classes = $derived(['modal', sizeClass, className].filter(Boolean).join(' ').trim());
32
-
33
- let overlayEl: HTMLDivElement;
34
- let modalEl: HTMLDivElement;
35
- let previousActiveElement: HTMLElement | null = null;
36
- let keyHandler: ((e: KeyboardEvent) => void) | null = null;
37
-
38
- const focusableSelectors = [
39
- 'button:not([disabled])',
40
- 'a[href]',
41
- 'input:not([disabled])',
42
- 'select:not([disabled])',
43
- 'textarea:not([disabled])',
44
- '[tabindex]:not([tabindex="-1"])',
45
- ].join(', ');
46
-
47
- function getFocusableElements(container: HTMLElement): HTMLElement[] {
48
- return Array.from(container.querySelectorAll<HTMLElement>(focusableSelectors));
49
- }
50
-
51
- function close() {
52
- open = false;
53
- if (keyHandler) {
54
- document.removeEventListener('keydown', keyHandler);
55
- keyHandler = null;
56
- }
57
- if (previousActiveElement) {
58
- previousActiveElement.focus();
59
- previousActiveElement = null;
60
- }
61
- }
62
-
63
- function setupFocusTrap() {
64
- if (!modalEl) return;
65
- keyHandler = (e: KeyboardEvent) => {
66
- if (!open) return;
67
- if (e.key === 'Escape' && closeOnEscape) {
68
- e.preventDefault();
69
- close();
70
- return;
71
- }
72
- if (e.key === 'Tab') {
73
- const focusable = getFocusableElements(modalEl);
74
- if (focusable.length === 0) return;
75
- const first = focusable[0];
76
- const last = focusable[focusable.length - 1];
77
- const active = document.activeElement as HTMLElement | null;
78
- if (e.shiftKey) {
79
- if (active === first || !modalEl.contains(active)) {
80
- e.preventDefault();
81
- last.focus();
82
- }
83
- } else {
84
- if (active === last || !modalEl.contains(active)) {
85
- e.preventDefault();
86
- first.focus();
87
- }
88
- }
89
- }
90
- };
91
- document.addEventListener('keydown', keyHandler);
92
- }
93
-
94
- function openModal() {
95
- previousActiveElement = document.activeElement as HTMLElement | null;
96
- const focusable = modalEl ? getFocusableElements(modalEl) : [];
97
- const closeBtn = modalEl?.querySelector<HTMLElement>('[data-modal-close]');
98
- const first = focusable[0] ?? closeBtn;
99
- tick().then(() => {
100
- first?.focus();
101
- setupFocusTrap();
102
- });
103
- }
104
-
105
- $effect(() => {
106
- if (open && modalEl) {
107
- openModal();
108
- } else {
109
- if (keyHandler) {
110
- document.removeEventListener('keydown', keyHandler);
111
- keyHandler = null;
112
- }
113
- }
114
- });
115
-
116
- function handleOverlayClick(e: MouseEvent) {
117
- if (closeOnOverlayClick && e.target === overlayEl) close();
118
- }
119
- </script>
120
-
121
- <div
122
- bind:this={overlayEl}
123
- class="modal__overlay"
124
- data-modal-overlay
125
- aria-hidden={!open}
126
- id="{modalId}-overlay"
127
- onclick={handleOverlayClick}
128
- role="presentation"
129
- ></div>
130
-
131
- <div
132
- bind:this={modalEl}
133
- class={classes}
134
- role="dialog"
135
- aria-modal="true"
136
- aria-labelledby="{modalId}-title"
137
- aria-hidden={!open}
138
- id={modalId}
139
- data-modal
140
- data-open={open || undefined}
141
- >
142
- <div class="modal__header">
143
- <h2 id="{modalId}-title" class="modal__title">{title}</h2>
144
- <button type="button" class="modal__close" aria-label="Close modal" data-modal-close onclick={close}>
145
- <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
146
- <path d="M18 6L6 18" />
147
- <path d="M6 6l12 12" />
148
- </svg>
149
- </button>
150
- </div>
151
- <div class="modal__body">
152
- {@render children?.()}
153
- </div>
154
- <div class="modal__footer">
155
- {@render footer?.()}
156
- </div>
157
- </div>
@@ -1,93 +0,0 @@
1
- <script lang="ts">
2
- function buildHref(template: string, page: number): string {
3
- return template.replace(/\{page\}/g, String(page));
4
- }
5
-
6
- function getPageItems(total: number, current: number, maxVisible: number): (number | 'ellipsis')[] {
7
- if (total <= 1) return [];
8
- if (total <= maxVisible) {
9
- return Array.from({ length: total }, (_, i) => i + 1);
10
- }
11
- const items: (number | 'ellipsis')[] = [1];
12
- const delta = Math.max(0, Math.floor((maxVisible - 2) / 2));
13
- const start = Math.max(2, current - delta);
14
- const end = Math.min(total - 1, current + delta);
15
- if (start > 2) items.push('ellipsis');
16
- for (let p = start; p <= end; p++) {
17
- if (p !== 1 && p !== total) items.push(p);
18
- }
19
- if (end < total - 1) items.push('ellipsis');
20
- if (total > 1) items.push(total);
21
- return items;
22
- }
23
-
24
- interface Props {
25
- currentPage: number;
26
- totalPages: number;
27
- hrefTemplate?: string;
28
- showFirstLast?: boolean;
29
- maxVisible?: number;
30
- class?: string;
31
- }
32
- let {
33
- currentPage,
34
- totalPages,
35
- hrefTemplate = '?page={page}',
36
- showFirstLast = true,
37
- maxVisible = 5,
38
- class: className = '',
39
- }: Props = $props();
40
-
41
- const classes = $derived(['pagination', className].filter(Boolean).join(' ').trim());
42
- const pageItems = $derived(getPageItems(totalPages, currentPage, maxVisible));
43
- const hasPrev = $derived(currentPage > 1);
44
- const hasNext = $derived(currentPage < totalPages);
45
- </script>
46
-
47
- <nav class={classes} aria-label="Pagination">
48
- <ul class="pagination__list">
49
- {#if showFirstLast && totalPages > 1}
50
- <li class="pagination__item">
51
- {#if hasPrev}
52
- <a class="pagination__link pagination__link--prev" href={buildHref(hrefTemplate, 1)} aria-label="First page">First</a>
53
- {:else}
54
- <span class="pagination__link pagination__link--prev pagination__link--disabled" aria-disabled="true">First</span>
55
- {/if}
56
- </li>
57
- {/if}
58
- <li class="pagination__item">
59
- {#if hasPrev}
60
- <a class="pagination__link pagination__link--prev" href={buildHref(hrefTemplate, currentPage - 1)} aria-label="Previous page">Previous</a>
61
- {:else}
62
- <span class="pagination__link pagination__link--prev pagination__link--disabled" aria-disabled="true">Previous</span>
63
- {/if}
64
- </li>
65
- {#each pageItems as item}
66
- <li class="pagination__item">
67
- {#if item === 'ellipsis'}
68
- <span class="pagination__ellipsis" aria-hidden="true">…</span>
69
- {:else if item === currentPage}
70
- <span class="pagination__link pagination__link--current" aria-current="page">{item}</span>
71
- {:else}
72
- <a class="pagination__link" href={buildHref(hrefTemplate, item)} aria-label="Page {item}">{item}</a>
73
- {/if}
74
- </li>
75
- {/each}
76
- <li class="pagination__item">
77
- {#if hasNext}
78
- <a class="pagination__link pagination__link--next" href={buildHref(hrefTemplate, currentPage + 1)} aria-label="Next page">Next</a>
79
- {:else}
80
- <span class="pagination__link pagination__link--next pagination__link--disabled" aria-disabled="true">Next</span>
81
- {/if}
82
- </li>
83
- {#if showFirstLast && totalPages > 1}
84
- <li class="pagination__item">
85
- {#if hasNext}
86
- <a class="pagination__link pagination__link--next" href={buildHref(hrefTemplate, totalPages)} aria-label="Last page">Last</a>
87
- {:else}
88
- <span class="pagination__link pagination__link--next pagination__link--disabled" aria-disabled="true">Last</span>
89
- {/if}
90
- </li>
91
- {/if}
92
- </ul>
93
- </nav>
@@ -1,58 +0,0 @@
1
- <script lang="ts">
2
- interface Props {
3
- value?: number;
4
- max?: number;
5
- variant?: 'primary' | 'success' | 'warning' | 'error' | 'info';
6
- size?: 'sm' | 'md' | 'lg';
7
- showLabel?: boolean;
8
- indeterminate?: boolean;
9
- label?: string;
10
- class?: string;
11
- }
12
- let {
13
- value = 0,
14
- max = 100,
15
- variant = 'primary',
16
- size = 'md',
17
- showLabel = false,
18
- indeterminate = false,
19
- label,
20
- class: className = '',
21
- }: Props = $props();
22
-
23
- const safeMax = $derived(max <= 0 ? 100 : max);
24
- const clampedValue = $derived(indeterminate ? 0 : Math.max(0, Math.min(value, safeMax)));
25
- const percentage = $derived(indeterminate ? 0 : Math.round((clampedValue / safeMax) * 100));
26
-
27
- const classes = $derived(
28
- [
29
- 'progress',
30
- `progress--${variant}`,
31
- `progress--${size}`,
32
- indeterminate ? 'progress--indeterminate' : '',
33
- className,
34
- ]
35
- .filter(Boolean)
36
- .join(' ')
37
- .trim()
38
- );
39
-
40
- const barStyle = $derived(indeterminate ? {} : { width: `${percentage}%` });
41
- </script>
42
-
43
- <div
44
- class={classes}
45
- role="progressbar"
46
- aria-valuemin={0}
47
- aria-valuemax={safeMax}
48
- aria-label={label ?? (indeterminate ? 'Loading' : undefined)}
49
- aria-valuetext={indeterminate ? 'Loading' : undefined}
50
- aria-valuenow={indeterminate ? undefined : clampedValue}
51
- >
52
- <div class="progress__track">
53
- <div class="progress__bar" style={barStyle}></div>
54
- </div>
55
- {#if showLabel && !indeterminate}
56
- <span class="progress__label" aria-hidden="true">{percentage}%</span>
57
- {/if}
58
- </div>