rizzo-css 0.0.12 → 0.0.13

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 (230) hide show
  1. package/.env.example +12 -0
  2. package/LICENSE +21 -0
  3. package/README.md +17 -3
  4. package/bin/rizzo-css.js +93 -43
  5. package/package.json +5 -3
  6. package/scaffold/astro-app/README.md +13 -2
  7. package/scaffold/astro-app/src/components/Accordion.astro +178 -0
  8. package/scaffold/astro-app/src/components/Alert.astro +131 -0
  9. package/scaffold/astro-app/src/components/Avatar.astro +59 -0
  10. package/scaffold/astro-app/src/components/Badge.astro +24 -0
  11. package/scaffold/astro-app/src/components/Breadcrumb.astro +61 -0
  12. package/scaffold/astro-app/src/components/Button.astro +3 -0
  13. package/scaffold/astro-app/src/components/Card.astro +18 -0
  14. package/scaffold/astro-app/src/components/Checkbox.astro +38 -0
  15. package/scaffold/astro-app/src/components/CodeBlock.astro +393 -0
  16. package/scaffold/astro-app/src/components/CopyToClipboard.astro +219 -0
  17. package/scaffold/astro-app/src/components/Divider.astro +37 -0
  18. package/scaffold/astro-app/src/components/Dropdown.astro +807 -0
  19. package/scaffold/astro-app/src/components/FormGroup.astro +59 -0
  20. package/scaffold/astro-app/src/components/FrameworkSwitcher.astro +72 -0
  21. package/scaffold/astro-app/src/components/Input.astro +59 -0
  22. package/scaffold/astro-app/src/components/Modal.astro +212 -0
  23. package/scaffold/astro-app/src/components/Navbar.astro +701 -0
  24. package/scaffold/astro-app/src/components/Pagination.astro +240 -0
  25. package/scaffold/astro-app/src/components/ProgressBar.astro +65 -0
  26. package/scaffold/astro-app/src/components/Radio.astro +38 -0
  27. package/scaffold/astro-app/src/components/Search.astro +1259 -0
  28. package/scaffold/astro-app/src/components/Select.astro +49 -0
  29. package/scaffold/astro-app/src/components/Settings.astro +382 -0
  30. package/scaffold/astro-app/src/components/Spinner.astro +30 -0
  31. package/scaffold/astro-app/src/components/Table.astro +181 -0
  32. package/scaffold/astro-app/src/components/Tabs.astro +223 -0
  33. package/scaffold/astro-app/src/components/Textarea.astro +58 -0
  34. package/scaffold/astro-app/src/components/ThemeSwitcher.astro +504 -0
  35. package/scaffold/astro-app/src/components/Toast.astro +30 -0
  36. package/scaffold/astro-app/src/components/Tooltip.astro +32 -0
  37. package/scaffold/astro-app/src/components/icons/Brush.astro +10 -0
  38. package/scaffold/astro-app/src/components/icons/Cake.astro +11 -0
  39. package/scaffold/astro-app/src/components/icons/Check.astro +29 -0
  40. package/scaffold/astro-app/src/components/icons/Cherry.astro +11 -0
  41. package/scaffold/astro-app/src/components/icons/ChevronDown.astro +29 -0
  42. package/scaffold/astro-app/src/components/icons/Circle.astro +29 -0
  43. package/scaffold/astro-app/src/components/icons/Close.astro +30 -0
  44. package/scaffold/astro-app/src/components/icons/Cmd.astro +26 -0
  45. package/scaffold/astro-app/src/components/icons/Copy.astro +30 -0
  46. package/scaffold/astro-app/src/components/icons/Eye.astro +30 -0
  47. package/scaffold/astro-app/src/components/icons/Filter.astro +29 -0
  48. package/scaffold/astro-app/src/components/icons/Flame.astro +28 -0
  49. package/scaffold/astro-app/src/components/icons/Flower.astro +11 -0
  50. package/scaffold/astro-app/src/components/icons/Gear.astro +30 -0
  51. package/scaffold/astro-app/src/components/icons/Heart.astro +28 -0
  52. package/scaffold/astro-app/src/components/icons/IceCream.astro +31 -0
  53. package/scaffold/astro-app/src/components/icons/Leaf.astro +29 -0
  54. package/scaffold/astro-app/src/components/icons/Lemon.astro +11 -0
  55. package/scaffold/astro-app/src/components/icons/Moon.astro +29 -0
  56. package/scaffold/astro-app/src/components/icons/Owl.astro +34 -0
  57. package/scaffold/astro-app/src/components/icons/Palette.astro +33 -0
  58. package/scaffold/astro-app/src/components/icons/Rainbow.astro +31 -0
  59. package/scaffold/astro-app/src/components/icons/Search.astro +30 -0
  60. package/scaffold/astro-app/src/components/icons/Shield.astro +28 -0
  61. package/scaffold/astro-app/src/components/icons/Snowflake.astro +34 -0
  62. package/scaffold/astro-app/src/components/icons/Sort.astro +30 -0
  63. package/scaffold/astro-app/src/components/icons/Sun.astro +29 -0
  64. package/scaffold/astro-app/src/components/icons/Sunset.astro +10 -0
  65. package/scaffold/astro-app/src/components/icons/Zap.astro +9 -0
  66. package/scaffold/astro-app/src/components/icons/devicons/Astro.astro +53 -0
  67. package/scaffold/astro-app/src/components/icons/devicons/Bash.astro +34 -0
  68. package/scaffold/astro-app/src/components/icons/devicons/Css3.astro +29 -0
  69. package/scaffold/astro-app/src/components/icons/devicons/Git.astro +24 -0
  70. package/scaffold/astro-app/src/components/icons/devicons/Html5.astro +27 -0
  71. package/scaffold/astro-app/src/components/icons/devicons/Javascript.astro +25 -0
  72. package/scaffold/astro-app/src/components/icons/devicons/Nodejs.astro +47 -0
  73. package/scaffold/astro-app/src/components/icons/devicons/Plaintext.astro +33 -0
  74. package/scaffold/astro-app/src/components/icons/devicons/React.astro +27 -0
  75. package/scaffold/astro-app/src/components/icons/devicons/Svelte.astro +25 -0
  76. package/scaffold/astro-app/src/components/icons/devicons/Vue.astro +26 -0
  77. package/scaffold/astro-app/src/config/frameworks.ts +26 -0
  78. package/scaffold/astro-app/src/config/themes.ts +54 -0
  79. package/scaffold/astro-app/src/layouts/DocsLayout.astro +204 -0
  80. package/scaffold/astro-app/src/layouts/Layout.astro +11 -2
  81. package/scaffold/astro-app/src/pages/components/accordion.astro +172 -0
  82. package/scaffold/astro-app/src/pages/components/alert.astro +250 -0
  83. package/scaffold/astro-app/src/pages/components/avatar.astro +102 -0
  84. package/scaffold/astro-app/src/pages/components/badge.astro +119 -0
  85. package/scaffold/astro-app/src/pages/components/breadcrumb.astro +124 -0
  86. package/scaffold/astro-app/src/pages/components/button.astro +74 -0
  87. package/scaffold/astro-app/src/pages/components/cards.astro +247 -0
  88. package/scaffold/astro-app/src/pages/components/copy-to-clipboard.astro +49 -0
  89. package/scaffold/astro-app/src/pages/components/divider.astro +74 -0
  90. package/scaffold/astro-app/src/pages/components/dropdown.astro +394 -0
  91. package/scaffold/astro-app/src/pages/components/forms.astro +367 -0
  92. package/scaffold/astro-app/src/pages/components/icons.astro +246 -0
  93. package/scaffold/astro-app/src/pages/components/modal.astro +152 -0
  94. package/scaffold/astro-app/src/pages/components/navbar.astro +80 -0
  95. package/scaffold/astro-app/src/pages/components/pagination.astro +126 -0
  96. package/scaffold/astro-app/src/pages/components/progress-bar.astro +94 -0
  97. package/scaffold/astro-app/src/pages/components/search.astro +155 -0
  98. package/scaffold/astro-app/src/pages/components/settings.astro +78 -0
  99. package/scaffold/astro-app/src/pages/components/spinner.astro +81 -0
  100. package/scaffold/astro-app/src/pages/components/table.astro +144 -0
  101. package/scaffold/astro-app/src/pages/components/tabs.astro +220 -0
  102. package/scaffold/astro-app/src/pages/components/theme-switcher.astro +67 -0
  103. package/scaffold/astro-app/src/pages/components/toast.astro +157 -0
  104. package/scaffold/astro-app/src/pages/components/tooltip.astro +209 -0
  105. package/scaffold/astro-app/src/pages/components.astro +290 -0
  106. package/scaffold/astro-app/src/pages/docs/accessibility.astro +9 -0
  107. package/scaffold/astro-app/src/pages/docs/colors.astro +9 -0
  108. package/scaffold/astro-app/src/pages/docs/design-system.astro +9 -0
  109. package/scaffold/astro-app/src/pages/docs/getting-started.astro +9 -0
  110. package/scaffold/astro-app/src/pages/docs/index.astro +15 -0
  111. package/scaffold/astro-app/src/pages/docs/themes/[theme].astro +14 -0
  112. package/scaffold/astro-app/src/pages/docs/theming.astro +10 -0
  113. package/scaffold/astro-app/src/pages/index.astro +5 -11
  114. package/scaffold/svelte-app/README.md +9 -2
  115. package/scaffold/svelte-app/src/app.html +1 -1
  116. package/scaffold/svelte-app/src/lib/rizzo/Accordion.svelte +128 -0
  117. package/scaffold/svelte-app/src/lib/rizzo/Alert.svelte +85 -0
  118. package/scaffold/svelte-app/src/lib/rizzo/Avatar.svelte +39 -0
  119. package/scaffold/svelte-app/src/lib/rizzo/Badge.svelte +31 -0
  120. package/scaffold/svelte-app/src/lib/rizzo/Breadcrumb.svelte +49 -0
  121. package/scaffold/svelte-app/src/lib/rizzo/Button.svelte +27 -0
  122. package/scaffold/svelte-app/src/lib/rizzo/Card.svelte +17 -0
  123. package/scaffold/svelte-app/src/lib/rizzo/Checkbox.svelte +37 -0
  124. package/scaffold/svelte-app/src/lib/rizzo/CopyToClipboard.svelte +79 -0
  125. package/scaffold/svelte-app/src/lib/rizzo/Divider.svelte +28 -0
  126. package/scaffold/svelte-app/src/lib/rizzo/Dropdown.svelte +254 -0
  127. package/scaffold/svelte-app/src/lib/rizzo/FormGroup.svelte +51 -0
  128. package/scaffold/svelte-app/src/lib/rizzo/Input.svelte +59 -0
  129. package/scaffold/svelte-app/src/lib/rizzo/Modal.svelte +157 -0
  130. package/scaffold/svelte-app/src/lib/rizzo/Pagination.svelte +93 -0
  131. package/scaffold/svelte-app/src/lib/rizzo/ProgressBar.svelte +58 -0
  132. package/scaffold/svelte-app/src/lib/rizzo/Radio.svelte +38 -0
  133. package/scaffold/svelte-app/src/lib/rizzo/Select.svelte +51 -0
  134. package/scaffold/svelte-app/src/lib/rizzo/Spinner.svelte +14 -0
  135. package/scaffold/svelte-app/src/lib/rizzo/Table.svelte +158 -0
  136. package/scaffold/svelte-app/src/lib/rizzo/Tabs.svelte +117 -0
  137. package/scaffold/svelte-app/src/lib/rizzo/Textarea.svelte +59 -0
  138. package/scaffold/svelte-app/src/lib/rizzo/ThemeSwitcher.svelte +315 -0
  139. package/scaffold/svelte-app/src/lib/rizzo/Toast.svelte +33 -0
  140. package/scaffold/svelte-app/src/lib/rizzo/Tooltip.svelte +19 -0
  141. package/scaffold/svelte-app/src/lib/rizzo/icons/Check.svelte +29 -0
  142. package/scaffold/svelte-app/src/lib/rizzo/icons/ChevronDown.svelte +29 -0
  143. package/scaffold/svelte-app/src/lib/rizzo/icons/Circle.svelte +29 -0
  144. package/scaffold/svelte-app/src/lib/rizzo/icons/Close.svelte +30 -0
  145. package/scaffold/svelte-app/src/lib/rizzo/icons/Cmd.svelte +27 -0
  146. package/scaffold/svelte-app/src/lib/rizzo/icons/Copy.svelte +30 -0
  147. package/scaffold/svelte-app/src/lib/rizzo/icons/Eye.svelte +30 -0
  148. package/scaffold/svelte-app/src/lib/rizzo/icons/Filter.svelte +29 -0
  149. package/scaffold/svelte-app/src/lib/rizzo/icons/Gear.svelte +30 -0
  150. package/scaffold/svelte-app/src/lib/rizzo/icons/IceCream.svelte +31 -0
  151. package/scaffold/svelte-app/src/lib/rizzo/icons/Moon.svelte +29 -0
  152. package/scaffold/svelte-app/src/lib/rizzo/icons/Owl.svelte +34 -0
  153. package/scaffold/svelte-app/src/lib/rizzo/icons/Palette.svelte +33 -0
  154. package/scaffold/svelte-app/src/lib/rizzo/icons/Rainbow.svelte +31 -0
  155. package/scaffold/svelte-app/src/lib/rizzo/icons/Search.svelte +30 -0
  156. package/scaffold/svelte-app/src/lib/rizzo/icons/Snowflake.svelte +34 -0
  157. package/scaffold/svelte-app/src/lib/rizzo/icons/Sort.svelte +30 -0
  158. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Astro.svelte +45 -0
  159. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Bash.svelte +28 -0
  160. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Css3.svelte +23 -0
  161. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Git.svelte +18 -0
  162. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Html5.svelte +21 -0
  163. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Javascript.svelte +19 -0
  164. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Nodejs.svelte +44 -0
  165. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Plaintext.svelte +24 -0
  166. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/React.svelte +21 -0
  167. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/SvelteIcon.svelte +19 -0
  168. package/scaffold/svelte-app/src/lib/rizzo/icons/devicons/Vue.svelte +20 -0
  169. package/scaffold/svelte-app/src/lib/rizzo/index.ts +33 -0
  170. package/scaffold/svelte-app/src/lib/rizzo-docs/CodeBlock.svelte +239 -0
  171. package/scaffold/svelte-app/src/lib/rizzo-docs/SvelteDocPage.svelte +99 -0
  172. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AccordionDoc.svelte +53 -0
  173. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AlertDoc.svelte +114 -0
  174. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/AvatarDoc.svelte +92 -0
  175. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BadgeDoc.svelte +60 -0
  176. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/BreadcrumbDoc.svelte +55 -0
  177. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ButtonDoc.svelte +55 -0
  178. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CardsDoc.svelte +173 -0
  179. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComingSoon.svelte +12 -0
  180. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ComponentsOverview.svelte +92 -0
  181. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/CopyToClipboardDoc.svelte +26 -0
  182. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DividerDoc.svelte +105 -0
  183. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/DropdownDoc.svelte +161 -0
  184. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/FormsDoc.svelte +375 -0
  185. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/IconsDoc.svelte +246 -0
  186. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Index.svelte +8 -0
  187. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ModalDoc.svelte +50 -0
  188. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/NavbarDoc.svelte +79 -0
  189. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/PaginationDoc.svelte +44 -0
  190. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ProgressBarDoc.svelte +95 -0
  191. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SearchDoc.svelte +147 -0
  192. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SettingsDoc.svelte +158 -0
  193. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/SpinnerDoc.svelte +41 -0
  194. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TableDoc.svelte +116 -0
  195. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TabsDoc.svelte +152 -0
  196. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ThemeSwitcherDoc.svelte +181 -0
  197. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/Theming.svelte +6 -0
  198. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/ToastDoc.svelte +136 -0
  199. package/scaffold/svelte-app/src/lib/rizzo-docs/pages/TooltipDoc.svelte +57 -0
  200. package/scaffold/svelte-app/src/routes/+page.svelte +2 -2
  201. package/scaffold/svelte-app/src/routes/components/+page.svelte +4 -0
  202. package/scaffold/svelte-app/src/routes/components/[slug]/+page.svelte +7 -0
  203. package/scaffold/vanilla/README.md +11 -4
  204. package/scaffold/vanilla/components/accordion.html +187 -0
  205. package/scaffold/vanilla/components/alert.html +187 -0
  206. package/scaffold/vanilla/components/avatar.html +187 -0
  207. package/scaffold/vanilla/components/badge.html +187 -0
  208. package/scaffold/vanilla/components/breadcrumb.html +187 -0
  209. package/scaffold/vanilla/components/button.html +187 -0
  210. package/scaffold/vanilla/components/cards.html +187 -0
  211. package/scaffold/vanilla/components/copy-to-clipboard.html +187 -0
  212. package/scaffold/vanilla/components/divider.html +187 -0
  213. package/scaffold/vanilla/components/dropdown.html +187 -0
  214. package/scaffold/vanilla/components/forms.html +187 -0
  215. package/scaffold/vanilla/components/icons.html +187 -0
  216. package/scaffold/vanilla/components/index.html +212 -0
  217. package/scaffold/vanilla/components/modal.html +187 -0
  218. package/scaffold/vanilla/components/navbar.html +187 -0
  219. package/scaffold/vanilla/components/pagination.html +187 -0
  220. package/scaffold/vanilla/components/progress-bar.html +187 -0
  221. package/scaffold/vanilla/components/search.html +187 -0
  222. package/scaffold/vanilla/components/settings.html +187 -0
  223. package/scaffold/vanilla/components/spinner.html +187 -0
  224. package/scaffold/vanilla/components/table.html +187 -0
  225. package/scaffold/vanilla/components/tabs.html +187 -0
  226. package/scaffold/vanilla/components/theme-switcher.html +187 -0
  227. package/scaffold/vanilla/components/toast.html +187 -0
  228. package/scaffold/vanilla/components/tooltip.html +187 -0
  229. package/scaffold/vanilla/index.html +16 -6
  230. package/scaffold/vanilla/js/main.js +4 -3
@@ -0,0 +1,59 @@
1
+ ---
2
+ interface Props {
3
+ label?: string;
4
+ labelFor?: string;
5
+ required?: boolean;
6
+ help?: string;
7
+ error?: string;
8
+ success?: string;
9
+ class?: string;
10
+ }
11
+
12
+ const {
13
+ label,
14
+ labelFor,
15
+ required = false,
16
+ help,
17
+ error,
18
+ success,
19
+ class: className = '',
20
+ } = Astro.props;
21
+
22
+ const errorId = labelFor && error ? `${labelFor}-error` : undefined;
23
+ const helpId = labelFor && help ? `${labelFor}-help` : undefined;
24
+ ---
25
+
26
+ <div class={`form-group ${className}`}>
27
+ {label && (
28
+ labelFor
29
+ ? (
30
+ <label
31
+ for={labelFor}
32
+ class={`form-group__label ${required ? 'required' : ''}`}
33
+ >
34
+ {label}
35
+ </label>
36
+ )
37
+ : (
38
+ <span class={`form-group__label ${required ? 'required' : ''}`}>
39
+ {label}
40
+ </span>
41
+ )
42
+ )}
43
+ <slot />
44
+ {help && (
45
+ <span id={helpId} class="form-group__help">
46
+ {help}
47
+ </span>
48
+ )}
49
+ {error && (
50
+ <span id={errorId} class="form-error" role="alert">
51
+ {error}
52
+ </span>
53
+ )}
54
+ {success && (
55
+ <span class="form-success" role="status">
56
+ {success}
57
+ </span>
58
+ )}
59
+ </div>
@@ -0,0 +1,72 @@
1
+ ---
2
+ import { FRAMEWORKS, FRAMEWORK_STORAGE_KEY, getFrameworkFromPath, shouldShowFrameworkSwitcher } from '../config/frameworks.js';
3
+ import AstroIcon from './icons/devicons/Astro.astro';
4
+ import Svelte from './icons/devicons/Svelte.astro';
5
+ import Javascript from './icons/devicons/Javascript.astro';
6
+ import React from './icons/devicons/React.astro';
7
+ import Vue from './icons/devicons/Vue.astro';
8
+
9
+ interface Props {
10
+ currentPath: string;
11
+ }
12
+
13
+ const { currentPath } = Astro.props;
14
+
15
+ if (!shouldShowFrameworkSwitcher(currentPath)) {
16
+ return null;
17
+ }
18
+
19
+ const { framework: currentFramework, canonicalPath } = getFrameworkFromPath(currentPath);
20
+
21
+ const FRAMEWORK_ICONS: Record<string, typeof AstroIcon> = {
22
+ astro: AstroIcon,
23
+ svelte: Svelte,
24
+ vanilla: Javascript,
25
+ react: React,
26
+ vue: Vue,
27
+ };
28
+ ---
29
+
30
+ <nav class="framework-switcher" aria-label="Switch documentation framework">
31
+ <span class="framework-switcher__label">View as</span>
32
+ <div class="framework-switcher__segmented" role="group">
33
+ {FRAMEWORKS.map((fw, i) => {
34
+ const href = fw.pathPrefix + (canonicalPath || '') || '/';
35
+ const isCurrent = fw.id === currentFramework.id;
36
+ const isFirst = i === 0;
37
+ const isLast = i === FRAMEWORKS.length - 1;
38
+ const IconComponent = FRAMEWORK_ICONS[fw.id];
39
+ return (
40
+ <a
41
+ class={`framework-switcher__segment ${isCurrent ? 'framework-switcher__segment--current' : ''} ${isFirst ? 'framework-switcher__segment--first' : ''} ${isLast ? 'framework-switcher__segment--last' : ''}`}
42
+ href={href}
43
+ data-framework={fw.id}
44
+ aria-current={isCurrent ? 'page' : undefined}
45
+ >
46
+ {IconComponent && <IconComponent width={18} height={18} class="framework-switcher__icon" aria-hidden="true" />}
47
+ <span class="framework-switcher__segment-label">{fw.label}</span>
48
+ </a>
49
+ );
50
+ })}
51
+ </div>
52
+ </nav>
53
+ <script define:vars={{ FRAMEWORK_STORAGE_KEY }}>
54
+ function initFrameworkSwitcher() {
55
+ document.querySelectorAll('.framework-switcher__segment').forEach((link) => {
56
+ link.addEventListener('click', (e) => {
57
+ const id = link.getAttribute('data-framework');
58
+ const href = link.getAttribute('href');
59
+ if (id && href) {
60
+ e.preventDefault();
61
+ try { localStorage.setItem(FRAMEWORK_STORAGE_KEY, id); } catch (_) {}
62
+ window.location.href = href;
63
+ }
64
+ });
65
+ });
66
+ }
67
+ if (document.readyState === 'loading') {
68
+ document.addEventListener('DOMContentLoaded', initFrameworkSwitcher);
69
+ } else {
70
+ initFrameworkSwitcher();
71
+ }
72
+ </script>
@@ -0,0 +1,59 @@
1
+ ---
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
+
20
+ const {
21
+ type = 'text',
22
+ id,
23
+ name,
24
+ value,
25
+ placeholder,
26
+ required = false,
27
+ disabled = false,
28
+ readonly = false,
29
+ autocomplete,
30
+ size = 'md',
31
+ error = false,
32
+ success = false,
33
+ class: className = '',
34
+ ariaDescribedby,
35
+ ariaInvalid,
36
+ } = Astro.props;
37
+
38
+ const sizeClass = size !== 'md' ? `form-input--${size}` : '';
39
+ const errorClass = error ? 'form-input--error' : '';
40
+ const successClass = success ? 'form-input--success' : '';
41
+ const classes = `form-input ${sizeClass} ${errorClass} ${successClass} ${className}`.trim();
42
+
43
+ const invalid = error || ariaInvalid === true || ariaInvalid === 'true';
44
+ ---
45
+
46
+ <input
47
+ type={type}
48
+ id={id}
49
+ name={name}
50
+ value={value}
51
+ placeholder={placeholder}
52
+ required={required}
53
+ disabled={disabled}
54
+ readonly={readonly}
55
+ autocomplete={autocomplete}
56
+ class={classes}
57
+ aria-invalid={invalid ? 'true' : 'false'}
58
+ aria-describedby={ariaDescribedby}
59
+ />
@@ -0,0 +1,212 @@
1
+ ---
2
+ import Close from './icons/Close.astro';
3
+
4
+ interface Props {
5
+ id?: string;
6
+ title?: string;
7
+ size?: 'sm' | 'md' | 'lg';
8
+ open?: boolean;
9
+ closeOnOverlayClick?: boolean;
10
+ closeOnEscape?: boolean;
11
+ class?: string;
12
+ }
13
+
14
+ const {
15
+ id,
16
+ title = 'Modal',
17
+ size = 'md',
18
+ open = false,
19
+ closeOnOverlayClick = true,
20
+ closeOnEscape = true,
21
+ class: className = '',
22
+ } = Astro.props;
23
+
24
+ const modalId = id || `modal-${Math.random().toString(36).substr(2, 9)}`;
25
+ const sizeClass = size !== 'md' ? `modal--${size}` : '';
26
+ const classes = `modal ${sizeClass} ${className}`.trim();
27
+ ---
28
+
29
+ <div
30
+ class="modal__overlay"
31
+ data-modal-overlay
32
+ aria-hidden={open ? 'false' : 'true'}
33
+ id={`${modalId}-overlay`}
34
+ ></div>
35
+
36
+ <div
37
+ class={classes}
38
+ role="dialog"
39
+ aria-modal="true"
40
+ aria-labelledby={`${modalId}-title`}
41
+ aria-hidden={open ? 'false' : 'true'}
42
+ id={modalId}
43
+ data-modal
44
+ >
45
+ <div class="modal__header">
46
+ <h2 id={`${modalId}-title`} class="modal__title">
47
+ {title}
48
+ </h2>
49
+ <button
50
+ type="button"
51
+ class="modal__close"
52
+ aria-label="Close modal"
53
+ data-modal-close
54
+ >
55
+ <Close width={20} height={20} />
56
+ </button>
57
+ </div>
58
+
59
+ <div class="modal__body">
60
+ <slot />
61
+ </div>
62
+
63
+ <div class="modal__footer">
64
+ <slot name="footer" />
65
+ </div>
66
+ </div>
67
+
68
+ <script define:vars={{ modalId, closeOnEscape, closeOnOverlayClick, open }}>
69
+ (function initModal() {
70
+ // Wait for DOM to be ready
71
+ const init = () => {
72
+ const modal = document.querySelector(`#${modalId}`);
73
+ if (!modal) {
74
+ // Retry if modal not found yet
75
+ if (document.readyState === 'loading') {
76
+ document.addEventListener('DOMContentLoaded', init);
77
+ return;
78
+ }
79
+ return;
80
+ }
81
+
82
+ const overlay = document.querySelector(`#${modalId}-overlay`);
83
+ const closeBtn = modal.querySelector('[data-modal-close]');
84
+ const title = modal.querySelector(`#${modalId}-title`);
85
+
86
+ if (!overlay || !closeBtn) return;
87
+
88
+ // Ensure modal starts closed unless explicitly opened
89
+ if (!open) {
90
+ modal.setAttribute('aria-hidden', 'true');
91
+ overlay.setAttribute('aria-hidden', 'true');
92
+ modal.removeAttribute('data-open');
93
+ }
94
+
95
+ // Get focusable elements within modal
96
+ const getFocusableElements = (container) => {
97
+ const focusableSelectors = [
98
+ 'button:not([disabled])',
99
+ 'a[href]',
100
+ 'input:not([disabled])',
101
+ 'select:not([disabled])',
102
+ 'textarea:not([disabled])',
103
+ '[tabindex]:not([tabindex="-1"])',
104
+ ].join(', ');
105
+ return Array.from(container.querySelectorAll(focusableSelectors));
106
+ };
107
+
108
+ let previousActiveElement = null;
109
+ let focusTrapHandler = null;
110
+
111
+ // Open modal
112
+ const openModal = () => {
113
+ previousActiveElement = document.activeElement;
114
+ modal.setAttribute('aria-hidden', 'false');
115
+ overlay.setAttribute('aria-hidden', 'false');
116
+ modal.setAttribute('data-open', 'true');
117
+
118
+ // Focus first focusable element or close button
119
+ const focusableElements = getFocusableElements(modal);
120
+ const firstFocusable = focusableElements.length > 0 ? focusableElements[0] : closeBtn;
121
+ if (firstFocusable) {
122
+ setTimeout(() => firstFocusable.focus(), 0);
123
+ }
124
+
125
+ // Add focus trap
126
+ focusTrapHandler = (e) => {
127
+ if (modal.getAttribute('data-open') !== 'true') return;
128
+
129
+ if (e.key === 'Escape' && closeOnEscape) {
130
+ e.preventDefault();
131
+ closeModal();
132
+ return;
133
+ }
134
+
135
+ // Focus trap: Tab key
136
+ if (e.key === 'Tab') {
137
+ const focusableElements = getFocusableElements(modal);
138
+ if (focusableElements.length === 0) return;
139
+
140
+ const firstElement = focusableElements[0];
141
+ const lastElement = focusableElements[focusableElements.length - 1];
142
+ const activeElement = document.activeElement;
143
+
144
+ if (e.shiftKey) {
145
+ // Shift + Tab: move backwards
146
+ if (activeElement === firstElement || !modal.contains(activeElement)) {
147
+ e.preventDefault();
148
+ lastElement.focus();
149
+ }
150
+ } else {
151
+ // Tab: move forwards
152
+ if (activeElement === lastElement || !modal.contains(activeElement)) {
153
+ e.preventDefault();
154
+ firstElement.focus();
155
+ }
156
+ }
157
+ }
158
+ };
159
+
160
+ document.addEventListener('keydown', focusTrapHandler);
161
+ };
162
+
163
+ // Close modal
164
+ const closeModal = () => {
165
+ modal.setAttribute('aria-hidden', 'true');
166
+ overlay.setAttribute('aria-hidden', 'true');
167
+ modal.removeAttribute('data-open');
168
+
169
+ // Remove focus trap
170
+ if (focusTrapHandler) {
171
+ document.removeEventListener('keydown', focusTrapHandler);
172
+ focusTrapHandler = null;
173
+ }
174
+
175
+ // Return focus to previous element
176
+ if (previousActiveElement) {
177
+ previousActiveElement.focus();
178
+ previousActiveElement = null;
179
+ }
180
+ };
181
+
182
+ // Event listeners
183
+ closeBtn.addEventListener('click', closeModal);
184
+
185
+ if (closeOnOverlayClick) {
186
+ overlay.addEventListener('click', (e) => {
187
+ if (e.target === overlay) {
188
+ closeModal();
189
+ }
190
+ });
191
+ }
192
+
193
+ // Initialize if open prop is true
194
+ if (open) {
195
+ setTimeout(() => openModal(), 0);
196
+ }
197
+
198
+ // Expose methods globally
199
+ // Convert hyphens to underscores for valid JavaScript identifiers
200
+ const modalIdAttr = modal.id.replace(/-/g, '_');
201
+ window[`openModal_${modalIdAttr}`] = openModal;
202
+ window[`closeModal_${modalIdAttr}`] = closeModal;
203
+ };
204
+
205
+ // Start initialization
206
+ if (document.readyState === 'loading') {
207
+ document.addEventListener('DOMContentLoaded', init);
208
+ } else {
209
+ init();
210
+ }
211
+ })();
212
+ </script>