@vielzeug/refine 26.10.7 → 26.10.9

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 (326) hide show
  1. package/README.md +6 -0
  2. package/dist/accordion-item.cjs +2 -2
  3. package/dist/accordion-item.cjs.map +1 -1
  4. package/dist/accordion-item.js +6 -6
  5. package/dist/accordion-item.js.map +1 -1
  6. package/dist/accordion.cjs +2 -2
  7. package/dist/accordion.cjs.map +1 -1
  8. package/dist/accordion.js +2 -2
  9. package/dist/accordion.js.map +1 -1
  10. package/dist/alert.cjs +2 -2
  11. package/dist/alert.cjs.map +1 -1
  12. package/dist/alert.js +2 -2
  13. package/dist/alert.js.map +1 -1
  14. package/dist/avatar.cjs +3 -3
  15. package/dist/avatar.cjs.map +1 -1
  16. package/dist/avatar.js +2 -2
  17. package/dist/avatar.js.map +1 -1
  18. package/dist/badge.cjs +2 -2
  19. package/dist/badge.cjs.map +1 -1
  20. package/dist/badge.js +2 -2
  21. package/dist/badge.js.map +1 -1
  22. package/dist/box.cjs +2 -2
  23. package/dist/box.cjs.map +1 -1
  24. package/dist/box.js +2 -2
  25. package/dist/box.js.map +1 -1
  26. package/dist/button-group.cjs +2 -2
  27. package/dist/button-group.cjs.map +1 -1
  28. package/dist/button-group.js +2 -2
  29. package/dist/button-group.js.map +1 -1
  30. package/dist/button.cjs +9 -9
  31. package/dist/button.cjs.map +1 -1
  32. package/dist/button.js +8 -8
  33. package/dist/button.js.map +1 -1
  34. package/dist/card.cjs +2 -2
  35. package/dist/card.cjs.map +1 -1
  36. package/dist/card.js +2 -2
  37. package/dist/card.js.map +1 -1
  38. package/dist/carousel.cjs +6 -6
  39. package/dist/carousel.cjs.map +1 -1
  40. package/dist/carousel.js +6 -6
  41. package/dist/carousel.js.map +1 -1
  42. package/dist/chat-message.cjs +4 -4
  43. package/dist/chat-message.cjs.map +1 -1
  44. package/dist/chat-message.js +4 -4
  45. package/dist/chat-message.js.map +1 -1
  46. package/dist/checkbox-group.cjs +1 -1
  47. package/dist/checkbox-group.cjs.map +1 -1
  48. package/dist/checkbox-group.js +1 -1
  49. package/dist/checkbox-group.js.map +1 -1
  50. package/dist/checkbox.cjs +1 -1
  51. package/dist/checkbox.cjs.map +1 -1
  52. package/dist/checkbox.js +1 -1
  53. package/dist/checkbox.js.map +1 -1
  54. package/dist/chip.cjs +8 -8
  55. package/dist/chip.cjs.map +1 -1
  56. package/dist/chip.js +8 -8
  57. package/dist/chip.js.map +1 -1
  58. package/dist/combobox.cjs +8 -8
  59. package/dist/combobox.cjs.map +1 -1
  60. package/dist/combobox.js +11 -11
  61. package/dist/combobox.js.map +1 -1
  62. package/dist/content/avatar/avatar.d.ts +2 -1
  63. package/dist/content/avatar/avatar.d.ts.map +1 -1
  64. package/dist/content/card/card.d.ts +6 -3
  65. package/dist/content/card/card.d.ts.map +1 -1
  66. package/dist/content/carousel/carousel.d.ts +5 -3
  67. package/dist/content/carousel/carousel.d.ts.map +1 -1
  68. package/dist/content/chat-message/chat-message.d.ts +2 -1
  69. package/dist/content/chat-message/chat-message.d.ts.map +1 -1
  70. package/dist/content/copy-command/copy-command.d.ts +1 -1
  71. package/dist/content/copy-command/copy-command.d.ts.map +1 -1
  72. package/dist/content/keyboard-key/keyboard-key.d.ts +2 -1
  73. package/dist/content/keyboard-key/keyboard-key.d.ts.map +1 -1
  74. package/dist/content/list/list.d.ts +2 -1
  75. package/dist/content/list/list.d.ts.map +1 -1
  76. package/dist/content/marquee/marquee.d.ts +3 -2
  77. package/dist/content/marquee/marquee.d.ts.map +1 -1
  78. package/dist/content/pagination/pagination.d.ts +1 -1
  79. package/dist/content/pagination/pagination.d.ts.map +1 -1
  80. package/dist/content/qr-code/qr-code.d.ts +0 -41
  81. package/dist/content/qr-code/qr-code.d.ts.map +1 -1
  82. package/dist/content/separator/separator.d.ts +1 -1
  83. package/dist/content/separator/separator.d.ts.map +1 -1
  84. package/dist/content/stepper/step.d.ts +1 -1
  85. package/dist/content/stepper/step.d.ts.map +1 -1
  86. package/dist/content/table/table.d.ts +2 -1
  87. package/dist/content/table/table.d.ts.map +1 -1
  88. package/dist/content/text/text.d.ts +13 -6
  89. package/dist/content/text/text.d.ts.map +1 -1
  90. package/dist/cookie-banner.cjs +1 -1
  91. package/dist/cookie-banner.cjs.map +1 -1
  92. package/dist/cookie-banner.js +1 -1
  93. package/dist/cookie-banner.js.map +1 -1
  94. package/dist/copy-command.cjs +6 -6
  95. package/dist/copy-command.cjs.map +1 -1
  96. package/dist/copy-command.js +7 -7
  97. package/dist/copy-command.js.map +1 -1
  98. package/dist/core/checkable.cjs +1 -1
  99. package/dist/core/checkable.cjs.map +1 -1
  100. package/dist/core/checkable.d.ts +6 -7
  101. package/dist/core/checkable.d.ts.map +1 -1
  102. package/dist/core/checkable.js +1 -1
  103. package/dist/core/checkable.js.map +1 -1
  104. package/dist/core/choice-field.cjs +1 -1
  105. package/dist/core/choice-field.cjs.map +1 -1
  106. package/dist/core/choice-field.d.ts +6 -6
  107. package/dist/core/choice-field.d.ts.map +1 -1
  108. package/dist/core/choice-field.js +1 -1
  109. package/dist/core/choice-field.js.map +1 -1
  110. package/dist/core/text-field.cjs +1 -1
  111. package/dist/core/text-field.cjs.map +1 -1
  112. package/dist/core/text-field.d.ts +8 -8
  113. package/dist/core/text-field.d.ts.map +1 -1
  114. package/dist/core/text-field.js +1 -1
  115. package/dist/core/text-field.js.map +1 -1
  116. package/dist/counter.cjs +2 -2
  117. package/dist/counter.cjs.map +1 -1
  118. package/dist/counter.js +2 -2
  119. package/dist/counter.js.map +1 -1
  120. package/dist/custom-elements.json +378 -241
  121. package/dist/datagrid.cjs +47 -47
  122. package/dist/datagrid.cjs.map +1 -1
  123. package/dist/datagrid.js +51 -51
  124. package/dist/datagrid.js.map +1 -1
  125. package/dist/date-picker.cjs +9 -9
  126. package/dist/date-picker.cjs.map +1 -1
  127. package/dist/date-picker.js +11 -11
  128. package/dist/date-picker.js.map +1 -1
  129. package/dist/dialog.cjs +3 -3
  130. package/dist/dialog.cjs.map +1 -1
  131. package/dist/dialog.js +3 -3
  132. package/dist/dialog.js.map +1 -1
  133. package/dist/disclosure/accordion/accordion.d.ts +4 -2
  134. package/dist/disclosure/accordion/accordion.d.ts.map +1 -1
  135. package/dist/disclosure/accordion-item/accordion-item.d.ts +1 -1
  136. package/dist/disclosure/accordion-item/accordion-item.d.ts.map +1 -1
  137. package/dist/disclosure/tab-item/tab-item.d.ts +1 -1
  138. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  139. package/dist/disclosure/tabs/tabs.d.ts +1 -1
  140. package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
  141. package/dist/drawer.cjs +4 -4
  142. package/dist/drawer.cjs.map +1 -1
  143. package/dist/drawer.js +2 -2
  144. package/dist/drawer.js.map +1 -1
  145. package/dist/feedback/alert/alert.d.ts +2 -1
  146. package/dist/feedback/alert/alert.d.ts.map +1 -1
  147. package/dist/feedback/badge/badge.d.ts +7 -4
  148. package/dist/feedback/badge/badge.d.ts.map +1 -1
  149. package/dist/feedback/chip/chip.d.ts +7 -5
  150. package/dist/feedback/chip/chip.d.ts.map +1 -1
  151. package/dist/grid-item.cjs +2 -2
  152. package/dist/grid-item.cjs.map +1 -1
  153. package/dist/grid-item.js +2 -2
  154. package/dist/grid-item.js.map +1 -1
  155. package/dist/grid.cjs +2 -2
  156. package/dist/grid.cjs.map +1 -1
  157. package/dist/grid.js +2 -2
  158. package/dist/grid.js.map +1 -1
  159. package/dist/input.cjs +7 -7
  160. package/dist/input.cjs.map +1 -1
  161. package/dist/input.js +8 -8
  162. package/dist/input.js.map +1 -1
  163. package/dist/inputs/button/button.d.ts +3 -2
  164. package/dist/inputs/button/button.d.ts.map +1 -1
  165. package/dist/inputs/button-group/button-group.d.ts +1 -37
  166. package/dist/inputs/button-group/button-group.d.ts.map +1 -1
  167. package/dist/inputs/combobox/combobox.types.d.ts +2 -2
  168. package/dist/inputs/combobox/combobox.types.d.ts.map +1 -1
  169. package/dist/inputs/counter/counter.d.ts +3 -2
  170. package/dist/inputs/counter/counter.d.ts.map +1 -1
  171. package/dist/inputs/datagrid/datagrid-model.cjs +1 -1
  172. package/dist/inputs/datagrid/datagrid-model.cjs.map +1 -1
  173. package/dist/inputs/datagrid/datagrid-model.d.ts +2 -1
  174. package/dist/inputs/datagrid/datagrid-model.d.ts.map +1 -1
  175. package/dist/inputs/datagrid/datagrid-model.js +1 -1
  176. package/dist/inputs/datagrid/datagrid-model.js.map +1 -1
  177. package/dist/inputs/datagrid/datagrid.d.ts +4 -2
  178. package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
  179. package/dist/inputs/date-picker/date-picker.d.ts +3 -2
  180. package/dist/inputs/date-picker/date-picker.d.ts.map +1 -1
  181. package/dist/inputs/input/input.d.ts +5 -3
  182. package/dist/inputs/input/input.d.ts.map +1 -1
  183. package/dist/inputs/message-composer/message-composer.d.ts +3 -2
  184. package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
  185. package/dist/inputs/number-input/number-input.d.ts +1 -1
  186. package/dist/inputs/number-input/number-input.d.ts.map +1 -1
  187. package/dist/inputs/otp-input/otp-input.d.ts +3 -2
  188. package/dist/inputs/otp-input/otp-input.d.ts.map +1 -1
  189. package/dist/inputs/query-bar/query-bar.d.ts.map +1 -1
  190. package/dist/inputs/select/select.d.ts +2 -2
  191. package/dist/inputs/select/select.d.ts.map +1 -1
  192. package/dist/inputs/textarea/textarea.d.ts +4 -3
  193. package/dist/inputs/textarea/textarea.d.ts.map +1 -1
  194. package/dist/inputs/time-picker/time-picker.d.ts +2 -2
  195. package/dist/inputs/time-picker/time-picker.d.ts.map +1 -1
  196. package/dist/keyboard-key.cjs +3 -3
  197. package/dist/keyboard-key.cjs.map +1 -1
  198. package/dist/keyboard-key.js +3 -3
  199. package/dist/keyboard-key.js.map +1 -1
  200. package/dist/layout/box/box.d.ts +6 -3
  201. package/dist/layout/box/box.d.ts.map +1 -1
  202. package/dist/layout/grid/grid.d.ts +11 -6
  203. package/dist/layout/grid/grid.d.ts.map +1 -1
  204. package/dist/layout/grid-item/grid-item.d.ts +8 -4
  205. package/dist/layout/grid-item/grid-item.d.ts.map +1 -1
  206. package/dist/layout/navbar/navbar.d.ts +4 -2
  207. package/dist/layout/navbar/navbar.d.ts.map +1 -1
  208. package/dist/layout/sidebar/sidebar.d.ts +2 -1
  209. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  210. package/dist/list-item.cjs +1 -1
  211. package/dist/list-item.cjs.map +1 -1
  212. package/dist/list-item.js +1 -1
  213. package/dist/list-item.js.map +1 -1
  214. package/dist/list.cjs +2 -2
  215. package/dist/list.cjs.map +1 -1
  216. package/dist/list.js +2 -2
  217. package/dist/list.js.map +1 -1
  218. package/dist/marquee.cjs +3 -3
  219. package/dist/marquee.cjs.map +1 -1
  220. package/dist/marquee.js +3 -3
  221. package/dist/marquee.js.map +1 -1
  222. package/dist/menu.cjs +3 -3
  223. package/dist/menu.cjs.map +1 -1
  224. package/dist/menu.js +3 -3
  225. package/dist/menu.js.map +1 -1
  226. package/dist/message-composer.cjs +10 -10
  227. package/dist/message-composer.cjs.map +1 -1
  228. package/dist/message-composer.js +7 -7
  229. package/dist/message-composer.js.map +1 -1
  230. package/dist/navbar.cjs +10 -10
  231. package/dist/navbar.cjs.map +1 -1
  232. package/dist/navbar.js +13 -13
  233. package/dist/navbar.js.map +1 -1
  234. package/dist/number-input.cjs +3 -3
  235. package/dist/number-input.cjs.map +1 -1
  236. package/dist/number-input.js +4 -4
  237. package/dist/number-input.js.map +1 -1
  238. package/dist/otp-input.cjs +4 -4
  239. package/dist/otp-input.cjs.map +1 -1
  240. package/dist/otp-input.js +4 -4
  241. package/dist/otp-input.js.map +1 -1
  242. package/dist/overlay/dialog/dialog.d.ts +7 -4
  243. package/dist/overlay/dialog/dialog.d.ts.map +1 -1
  244. package/dist/overlay/drawer/drawer.d.ts +4 -2
  245. package/dist/overlay/drawer/drawer.d.ts.map +1 -1
  246. package/dist/overlay/menu/menu.d.ts +2 -1
  247. package/dist/overlay/menu/menu.d.ts.map +1 -1
  248. package/dist/pagination.cjs +9 -9
  249. package/dist/pagination.cjs.map +1 -1
  250. package/dist/pagination.js +9 -9
  251. package/dist/pagination.js.map +1 -1
  252. package/dist/qr-code.cjs +2 -2
  253. package/dist/qr-code.cjs.map +1 -1
  254. package/dist/qr-code.js +2 -2
  255. package/dist/qr-code.js.map +1 -1
  256. package/dist/query-bar.cjs +7 -7
  257. package/dist/query-bar.cjs.map +1 -1
  258. package/dist/query-bar.js +8 -8
  259. package/dist/query-bar.js.map +1 -1
  260. package/dist/radio-group.cjs +1 -1
  261. package/dist/radio-group.cjs.map +1 -1
  262. package/dist/radio-group.js +1 -1
  263. package/dist/radio-group.js.map +1 -1
  264. package/dist/refine.cjs +123 -123
  265. package/dist/refine.cjs.map +1 -1
  266. package/dist/refine.iife.js +123 -123
  267. package/dist/refine.iife.js.map +1 -1
  268. package/dist/refine.js +124 -124
  269. package/dist/refine.js.map +1 -1
  270. package/dist/select.cjs +13 -13
  271. package/dist/select.cjs.map +1 -1
  272. package/dist/select.js +15 -15
  273. package/dist/select.js.map +1 -1
  274. package/dist/separator.cjs +4 -4
  275. package/dist/separator.cjs.map +1 -1
  276. package/dist/separator.js +4 -4
  277. package/dist/separator.js.map +1 -1
  278. package/dist/shared/prop-bundles.cjs +1 -1
  279. package/dist/shared/prop-bundles.cjs.map +1 -1
  280. package/dist/shared/prop-bundles.d.ts +7 -8
  281. package/dist/shared/prop-bundles.d.ts.map +1 -1
  282. package/dist/shared/prop-bundles.js +1 -1
  283. package/dist/shared/prop-bundles.js.map +1 -1
  284. package/dist/shared/types.cjs +2 -0
  285. package/dist/shared/types.cjs.map +1 -0
  286. package/dist/shared/types.d.ts +27 -9
  287. package/dist/shared/types.d.ts.map +1 -1
  288. package/dist/shared/types.js +2 -0
  289. package/dist/shared/types.js.map +1 -0
  290. package/dist/sidebar.cjs +7 -7
  291. package/dist/sidebar.cjs.map +1 -1
  292. package/dist/sidebar.js +4 -4
  293. package/dist/sidebar.js.map +1 -1
  294. package/dist/step.cjs +10 -10
  295. package/dist/step.cjs.map +1 -1
  296. package/dist/step.js +10 -10
  297. package/dist/step.js.map +1 -1
  298. package/dist/tab-item.cjs +4 -4
  299. package/dist/tab-item.cjs.map +1 -1
  300. package/dist/tab-item.js +5 -5
  301. package/dist/tab-item.js.map +1 -1
  302. package/dist/table.cjs +2 -2
  303. package/dist/table.cjs.map +1 -1
  304. package/dist/table.js +2 -2
  305. package/dist/table.js.map +1 -1
  306. package/dist/tabs.cjs +2 -2
  307. package/dist/tabs.cjs.map +1 -1
  308. package/dist/tabs.js +4 -4
  309. package/dist/tabs.js.map +1 -1
  310. package/dist/text.cjs +2 -2
  311. package/dist/text.cjs.map +1 -1
  312. package/dist/text.js +2 -2
  313. package/dist/text.js.map +1 -1
  314. package/dist/textarea.cjs +7 -7
  315. package/dist/textarea.cjs.map +1 -1
  316. package/dist/textarea.js +7 -7
  317. package/dist/textarea.js.map +1 -1
  318. package/dist/time-picker.cjs +7 -7
  319. package/dist/time-picker.cjs.map +1 -1
  320. package/dist/time-picker.js +7 -7
  321. package/dist/time-picker.js.map +1 -1
  322. package/dist/tooltip.cjs +1 -1
  323. package/dist/tooltip.cjs.map +1 -1
  324. package/dist/tooltip.js +1 -1
  325. package/dist/tooltip.js.map +1 -1
  326. package/package.json +13 -13
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../src/inputs/button/button.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, prop, useField } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { commonProps } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n frostVariantMixin,\n rainbowEffectMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n shineEffectMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { ButtonType, ComponentSize, LinkTarget, RoundedSize, ThemeColor } from '../../types';\nimport { useLinkProps } from '../../utils';\nimport { BUTTON_GROUP_CTX } from '../button-group/button-group';\nimport { useFormAction } from '../shared';\nimport componentStyles from './button.css?inline';\n\nexport const BUTTON_VARIANTS = ['solid', 'flat', 'bordered', 'outline', 'ghost', 'text', 'frost'] as const;\n\n/** Visual variant for ore-button: derived from BUTTON_VARIANTS for a single source of truth. */\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Animated border effect for ore-button. */\nexport type ButtonEffect = 'shine' | 'rainbow';\n\n/** Button component properties */\nexport type OreButtonProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Animated border effect: 'shine' (color-aware neon sweep) or 'rainbow' */\n effect?: ButtonEffect;\n /**\n * Full height button (100% of container): the inner `[part=\"button\"]` fills its host's\n * height instead of the size preset's fixed height. Useful when the button itself is the\n * whole tappable surface of a container it doesn't otherwise control the size of (e.g. a\n * swipe-revealed row action in `ore-list-item`'s `actions-left`/`actions-right` slots).\n */\n fullheight?: boolean;\n /** Full width button (100% of container) */\n fullwidth?: boolean;\n /** When set, renders an `<a>` instead of `<button>` */\n href?: string;\n /** Icon-only mode (square aspect ratio, no padding) */\n iconOnly?: boolean;\n /** Accessible label for the inner button: required for icon-only buttons */\n label?: string;\n /** Show loading state with spinner */\n loading?: boolean;\n /** Link rel attribute (requires href) */\n rel?: string;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** Link target (requires href) */\n target?: LinkTarget;\n /** HTML button type attribute */\n type?: ButtonType;\n /** Visual style variant */\n variant?: ButtonVariant;\n};\n\n/**\n * A customizable button component with multiple variants, sizes, and states.\n * Supports icons, loading states, and animated border effects.\n *\n * @element ore-button\n *\n * @attr {string} type - HTML button type: 'button' | 'submit' | 'reset'\n * @attr {boolean} disabled - Disable button interaction\n * @attr {boolean} loading - Show loading state with spinner\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost'\n * @attr {string} size - Button size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} effect - Animated border effect: 'shine' | 'rainbow'\n * @attr {boolean} icon-only - Icon-only mode (square aspect ratio, no padding)\n * @attr {boolean} fullwidth - Full width button (100% of container)\n * @attr {boolean} fullheight - Full height button (100% of container)\n *\n * @fires click - Emitted when button is clicked (unless disabled/loading)\n *\n * @slot - Button content (text, icons, etc.)\n * @slot prefix - Content before the button text (e.g., icons)\n * @slot suffix - Content after the button text (e.g., icons, badges)\n *\n * @part button - The inner button or anchor element\n * @part loader - The loading spinner element\n * @part content - The button content wrapper\n *\n * @cssprop --button-bg - Background color override\n * @cssprop --button-color - Text color override\n * @cssprop --button-border - Border width override\n * @cssprop --button-border-color - Border color override\n * @cssprop --button-radius - Border radius override\n * @cssprop --button-padding - Inner padding override\n * @cssprop --button-gap - Gap between icon and text override\n * @cssprop --button-font-size - Font size override\n * @cssprop --button-frost-active-bg - Background when pressed (frost variant)\n * @cssprop --button-frost-active-border-color - Border color when pressed (frost variant)\n *\n * @example\n * ```html\n * <ore-button variant=\"solid\" color=\"primary\">Click me</ore-button>\n * <ore-button loading color=\"success\">Processing...</ore-button>\n * <ore-button effect=\"shine\" color=\"primary\">Shine</ore-button>\n * <ore-button effect=\"rainbow\" variant=\"frost\">Rainbow</ore-button>\n * ```\n */\nexport const BUTTON_TAG = 'ore-button' as const;\ndefine<OreButtonProps>(BUTTON_TAG, {\n formAssociated: true,\n props: {\n ...commonProps,\n effect: prop.string<ButtonEffect>(),\n fullheight: prop.bool(false),\n fullwidth: prop.bool(false),\n href: prop.string(),\n iconOnly: prop.bool(false),\n label: prop.string(),\n rel: prop.string(),\n target: prop.string<LinkTarget>(),\n type: prop.oneOf(['button', 'submit', 'reset'] as const, 'button'),\n variant: prop.oneOf(BUTTON_VARIANTS, 'solid'),\n },\n setup(props) {\n const el = getHost();\n\n // Prefer group context over own props for color/size/variant.\n const groupCtx = inject(BUTTON_GROUP_CTX);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const effectiveSize = computed(() => groupCtx?.size.value ?? props.size.value);\n const effectiveVariant = computed(() => groupCtx?.variant.value ?? props.variant.value);\n\n const isDisabled = computed(() => !!(props.disabled.value || props.loading.value));\n\n // isLink and effectiveRel are computed from signals: correct even if href changes at runtime.\n const { effectiveRel, isLink } = useLinkProps(props.href, props.rel, props.target);\n\n // Form association: relay submit/reset clicks to the associated form.\n // The inner <button> always has type=\"button\" so shadow DOM never drives native form actions.\n // getForm() returns null for link mode at runtime, so no form actions fire.\n const formField = useField({\n disabled: isDisabled,\n toFormValue: () => null,\n value: computed(() => ''),\n });\n\n const handleClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault();\n\n return;\n }\n\n // Link mode renders a real <a href> below: the browser handles left/middle/ctrl-click\n // navigation, target, and rel natively. No manual window.open/location.href needed.\n useFormAction(() => (isLink.value ? null : formField.internals.form), props.type, isDisabled, el)(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n if (isLink.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (el.shadowRoot?.querySelector('[part=\"button\"]') as HTMLElement)?.click();\n }\n };\n\n // ARIA attributes live on the host.\n bind({\n attr: {\n 'aria-busy': computed(() => (isLink.value ? null : props.loading.value)),\n 'aria-disabled': computed(() => (isLink.value ? null : isDisabled.value)),\n 'aria-label': computed(() => (isLink.value ? null : props.label.value)),\n color: effectiveColor,\n effect: props.effect,\n role: computed(() => (isLink.value ? null : (el.getAttribute('role') ?? 'button'))),\n size: effectiveSize,\n tabindex: computed(() => (isLink.value ? null : isDisabled.value ? '-1' : '0')),\n variant: effectiveVariant,\n },\n on: {\n keydown: handleKeydown,\n },\n });\n\n // A factory, not a shared result: ore's static embed moves a result's\n // fragment children into place, consuming it. The link/button switch below\n // re-renders whenever `href` arrives or is removed at runtime (ore\n // templates set interpolated attributes after upgrade, so the first render\n // is usually the span branch), and a shared instance would render empty on\n // every switch after the first.\n const buttonContent = () => html`\n <span class=\"loader\" part=\"loader\" aria-label=\"Loading\" ?hidden=${() => !props.loading.value}></span>\n <slot name=\"prefix\"></slot>\n <span class=\"content\" part=\"content\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `;\n\n // Link mode delegates semantics and focus to the native anchor. Button mode keeps them on\n // the form-associated host because its visual part is intentionally a non-semantic span.\n return html`\n ${() =>\n isLink.value\n ? html`\n <a\n part=\"button\"\n aria-busy=\"${props.loading}\"\n aria-disabled=\"${isDisabled}\"\n aria-label=\"${computed(() => props.label.value || el.textContent?.trim() || null)}\"\n tabindex=\"${computed(() => (isDisabled.value ? '-1' : null))}\"\n href=\"${computed(() => (isDisabled.value ? null : props.href.value))}\"\n rel=\"${effectiveRel}\"\n target=\"${props.target}\"\n @click=\"${handleClick}\">\n ${buttonContent()}\n </a>\n `\n : html`\n <span part=\"button\" role=\"presentation\" @click=\"${handleClick}\">${buttonContent()}</span>\n `}\n `;\n },\n shadow: { delegatesFocus: false },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n forcedColorsMixin,\n sizeVariantMixin({\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n height: 'var(--size-12)',\n iconSize: 'var(--size-6)',\n lineHeight: 'var(--leading-relaxed)',\n padding: 'var(--size-2-5) var(--size-5)',\n },\n sm: {\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-1-5)',\n height: 'var(--size-8)',\n iconSize: 'var(--size-4)',\n lineHeight: 'var(--leading-tight)',\n padding: 'var(--size-1-5) var(--size-3)',\n },\n }),\n frostVariantMixin('[part=\"button\"]'),\n rainbowEffectMixin('[part=\"button\"]'),\n shineEffectMixin('[part=\"button\"]'),\n disabledLoadingMixin,\n componentStyles,\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../src/inputs/button/button.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, prop, useField } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { commonProps } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n frostVariantMixin,\n rainbowEffectMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n shineEffectMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport {\n type ButtonType,\n type ComponentSize,\n LINK_TARGETS,\n type LinkTarget,\n type RoundedSize,\n type ThemeColor,\n} from '../../types';\nimport { useLinkProps } from '../../utils';\nimport { BUTTON_GROUP_CTX } from '../button-group/button-group';\nimport { useFormAction } from '../shared';\nimport componentStyles from './button.css?inline';\n\nexport const BUTTON_VARIANTS = ['solid', 'flat', 'bordered', 'outline', 'ghost', 'text', 'frost'] as const;\n\n/** Visual variant for ore-button: derived from BUTTON_VARIANTS for a single source of truth. */\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Animated border effect for ore-button. */\nexport const BUTTON_EFFECTS = ['shine', 'rainbow'] as const;\nexport type ButtonEffect = (typeof BUTTON_EFFECTS)[number];\n\n/** Button component properties */\nexport type OreButtonProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Animated border effect: 'shine' (color-aware neon sweep) or 'rainbow' */\n effect?: ButtonEffect;\n /**\n * Full height button (100% of container): the inner `[part=\"button\"]` fills its host's\n * height instead of the size preset's fixed height. Useful when the button itself is the\n * whole tappable surface of a container it doesn't otherwise control the size of (e.g. a\n * swipe-revealed row action in `ore-list-item`'s `actions-left`/`actions-right` slots).\n */\n fullheight?: boolean;\n /** Full width button (100% of container) */\n fullwidth?: boolean;\n /** When set, renders an `<a>` instead of `<button>` */\n href?: string;\n /** Icon-only mode (square aspect ratio, no padding) */\n iconOnly?: boolean;\n /** Accessible label for the inner button: required for icon-only buttons */\n label?: string;\n /** Show loading state with spinner */\n loading?: boolean;\n /** Link rel attribute (requires href) */\n rel?: string;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** Link target (requires href) */\n target?: LinkTarget;\n /** HTML button type attribute */\n type?: ButtonType;\n /** Visual style variant */\n variant?: ButtonVariant;\n};\n\n/**\n * A customizable button component with multiple variants, sizes, and states.\n * Supports icons, loading states, and animated border effects.\n *\n * @element ore-button\n *\n * @attr {string} type - HTML button type: 'button' | 'submit' | 'reset'\n * @attr {boolean} disabled - Disable button interaction\n * @attr {boolean} loading - Show loading state with spinner\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost'\n * @attr {string} size - Button size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} effect - Animated border effect: 'shine' | 'rainbow'\n * @attr {boolean} icon-only - Icon-only mode (square aspect ratio, no padding)\n * @attr {boolean} fullwidth - Full width button (100% of container)\n * @attr {boolean} fullheight - Full height button (100% of container)\n *\n * @fires click - Emitted when button is clicked (unless disabled/loading)\n *\n * @slot - Button content (text, icons, etc.)\n * @slot prefix - Content before the button text (e.g., icons)\n * @slot suffix - Content after the button text (e.g., icons, badges)\n *\n * @part button - The inner button or anchor element\n * @part loader - The loading spinner element\n * @part content - The button content wrapper\n *\n * @cssprop --button-bg - Background color override\n * @cssprop --button-color - Text color override\n * @cssprop --button-border - Border width override\n * @cssprop --button-border-color - Border color override\n * @cssprop --button-radius - Border radius override\n * @cssprop --button-padding - Inner padding override\n * @cssprop --button-gap - Gap between icon and text override\n * @cssprop --button-font-size - Font size override\n * @cssprop --button-frost-active-bg - Background when pressed (frost variant)\n * @cssprop --button-frost-active-border-color - Border color when pressed (frost variant)\n *\n * @example\n * ```html\n * <ore-button variant=\"solid\" color=\"primary\">Click me</ore-button>\n * <ore-button loading color=\"success\">Processing...</ore-button>\n * <ore-button effect=\"shine\" color=\"primary\">Shine</ore-button>\n * <ore-button effect=\"rainbow\" variant=\"frost\">Rainbow</ore-button>\n * ```\n */\nexport const BUTTON_TAG = 'ore-button' as const;\ndefine<OreButtonProps>(BUTTON_TAG, {\n formAssociated: true,\n props: {\n ...commonProps,\n effect: prop.oneOf(BUTTON_EFFECTS),\n fullheight: prop.bool(false),\n fullwidth: prop.bool(false),\n href: prop.string(),\n iconOnly: prop.bool(false),\n label: prop.string(),\n rel: prop.string(),\n target: prop.oneOf(LINK_TARGETS),\n type: prop.oneOf(['button', 'submit', 'reset'] as const, 'button'),\n variant: prop.oneOf(BUTTON_VARIANTS, 'solid'),\n },\n setup(props) {\n const el = getHost();\n\n // Prefer group context over own props for color/size/variant.\n const groupCtx = inject(BUTTON_GROUP_CTX);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const effectiveSize = computed(() => groupCtx?.size.value ?? props.size.value);\n const effectiveVariant = computed(() => groupCtx?.variant.value ?? props.variant.value);\n\n const isDisabled = computed(() => !!(props.disabled.value || props.loading.value));\n\n // isLink and effectiveRel are computed from signals: correct even if href changes at runtime.\n const { effectiveRel, isLink } = useLinkProps(props.href, props.rel, props.target);\n\n // Form association: relay submit/reset clicks to the associated form.\n // The inner <button> always has type=\"button\" so shadow DOM never drives native form actions.\n // getForm() returns null for link mode at runtime, so no form actions fire.\n const formField = useField({\n disabled: isDisabled,\n toFormValue: () => null,\n value: computed(() => ''),\n });\n\n const handleClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault();\n\n return;\n }\n\n // Link mode renders a real <a href> below: the browser handles left/middle/ctrl-click\n // navigation, target, and rel natively. No manual window.open/location.href needed.\n useFormAction(() => (isLink.value ? null : formField.internals.form), props.type, isDisabled, el)(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n if (isLink.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (el.shadowRoot?.querySelector('[part=\"button\"]') as HTMLElement)?.click();\n }\n };\n\n // ARIA attributes live on the host.\n bind({\n attr: {\n 'aria-busy': computed(() => (isLink.value ? null : props.loading.value)),\n 'aria-disabled': computed(() => (isLink.value ? null : isDisabled.value)),\n 'aria-label': computed(() => (isLink.value ? null : props.label.value)),\n color: effectiveColor,\n effect: props.effect,\n role: computed(() => (isLink.value ? null : (el.getAttribute('role') ?? 'button'))),\n size: effectiveSize,\n tabindex: computed(() => (isLink.value ? null : isDisabled.value ? '-1' : '0')),\n variant: effectiveVariant,\n },\n on: {\n keydown: handleKeydown,\n },\n });\n\n // A factory, not a shared result: ore's static embed moves a result's\n // fragment children into place, consuming it. The link/button switch below\n // re-renders whenever `href` arrives or is removed at runtime (ore\n // templates set interpolated attributes after upgrade, so the first render\n // is usually the span branch), and a shared instance would render empty on\n // every switch after the first.\n const buttonContent = () => html`\n <span class=\"loader\" part=\"loader\" aria-label=\"Loading\" ?hidden=${() => !props.loading.value}></span>\n <slot name=\"prefix\"></slot>\n <span class=\"content\" part=\"content\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `;\n\n // Link mode delegates semantics and focus to the native anchor. Button mode keeps them on\n // the form-associated host because its visual part is intentionally a non-semantic span.\n return html`\n ${() =>\n isLink.value\n ? html`\n <a\n part=\"button\"\n aria-busy=\"${props.loading}\"\n aria-disabled=\"${isDisabled}\"\n aria-label=\"${computed(() => props.label.value || el.textContent?.trim() || null)}\"\n tabindex=\"${computed(() => (isDisabled.value ? '-1' : null))}\"\n href=\"${computed(() => (isDisabled.value ? null : props.href.value))}\"\n rel=\"${effectiveRel}\"\n target=\"${props.target}\"\n @click=\"${handleClick}\">\n ${buttonContent()}\n </a>\n `\n : html`\n <span part=\"button\" role=\"presentation\" @click=\"${handleClick}\">${buttonContent()}</span>\n `}\n `;\n },\n shadow: { delegatesFocus: false },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n forcedColorsMixin,\n sizeVariantMixin({\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n height: 'var(--size-12)',\n iconSize: 'var(--size-6)',\n lineHeight: 'var(--leading-relaxed)',\n padding: 'var(--size-2-5) var(--size-5)',\n },\n sm: {\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-1-5)',\n height: 'var(--size-8)',\n iconSize: 'var(--size-4)',\n lineHeight: 'var(--leading-tight)',\n padding: 'var(--size-1-5) var(--size-3)',\n },\n }),\n frostVariantMixin('[part=\"button\"]'),\n rainbowEffectMixin('[part=\"button\"]'),\n shineEffectMixin('[part=\"button\"]'),\n disabledLoadingMixin,\n componentStyles,\n ],\n});\n"],"mappings":"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"}
package/dist/card.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./styles/mixins/variants.css.cjs"),i=require("./core/keyboard.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./content/card/card.css.cjs");let s=require("@vielzeug/ripple"),c=require("@vielzeug/ore");var l=`button, a[href], input, select, textarea, summary, [role="button"], [role="link"], [contenteditable=""], [contenteditable="true"]`;function isNestedInteractiveTarget(e,t){for(let n of t.composedPath()){if(!(n instanceof HTMLElement))continue;if(n===e)return!1;let t=n.closest(l);if(t&&t!==e)return!0}return!1}var u=`ore-card`;(0,c.define)(u,{props:{...a.themableBundle,...a.disablableBundle,...a.loadableBundle,elevation:c.prop.number(),interactive:c.prop.bool(!1),orientation:c.prop.string(),padding:c.prop.string(),variant:c.prop.string()},setup(e){let t=(0,c.getHost)(),n=(0,c.useEmit)(),r=(0,c.useSlots)(),a=c.watchEffect;(0,c.bind)({attr:{"aria-busy":()=>e.loading.value?`true`:`false`,"aria-disabled":()=>e.interactive.value?String(e.disabled.value):null,role:()=>e.interactive.value?`button`:null}}),a(()=>{e.interactive.value?t.setAttribute(`tabindex`,e.disabled.value?`-1`:`0`):t.removeAttribute(`tabindex`)});let o=i.createInteraction({disabled:(0,s.computed)(()=>!e.interactive.value||!!e.disabled.value),onPress:(e,t)=>{n(`activate`,{originalEvent:e,trigger:t})}}),handleClick=n=>{e.interactive.value&&!e.disabled.value&&(isNestedInteractiveTarget(t,n)||o.handleClick(n))},handleKeydown=e=>{o.handleKeydown(e)};return(0,c.bind)({on:{click:e=>handleClick(e),keydown:e=>handleKeydown(e)}}),c.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./styles/mixins/variants.css.cjs"),i=require("./core/keyboard.cjs"),a=require("./shared/types.cjs"),o=require("./shared/prop-bundles.cjs"),s=require("./content/card/card.css.cjs");let c=require("@vielzeug/ripple"),l=require("@vielzeug/ore");var u=[`horizontal`],d=[`solid`,`flat`,`frost`],f=`button, a[href], input, select, textarea, summary, [role="button"], [role="link"], [contenteditable=""], [contenteditable="true"]`;function isNestedInteractiveTarget(e,t){for(let n of t.composedPath()){if(!(n instanceof HTMLElement))continue;if(n===e)return!1;let t=n.closest(f);if(t&&t!==e)return!0}return!1}var p=`ore-card`;(0,l.define)(p,{props:{...o.themableBundle,...o.disablableBundle,...o.loadableBundle,elevation:l.prop.oneOf(a.ELEVATION_LEVELS),interactive:l.prop.bool(!1),orientation:l.prop.oneOf(u),padding:l.prop.oneOf(a.PADDING_SIZES),variant:l.prop.oneOf(d)},setup(e){let t=(0,l.getHost)(),n=(0,l.useEmit)(),r=(0,l.useSlots)(),a=l.watchEffect;(0,l.bind)({attr:{"aria-busy":()=>e.loading.value?`true`:`false`,"aria-disabled":()=>e.interactive.value?String(e.disabled.value):null,role:()=>e.interactive.value?`button`:null}}),a(()=>{e.interactive.value?t.setAttribute(`tabindex`,e.disabled.value?`-1`:`0`):t.removeAttribute(`tabindex`)});let o=i.createInteraction({disabled:(0,c.computed)(()=>!e.interactive.value||!!e.disabled.value),onPress:(e,t)=>{n(`activate`,{originalEvent:e,trigger:t})}}),handleClick=n=>{e.interactive.value&&!e.disabled.value&&(isNestedInteractiveTarget(t,n)||o.handleClick(n))},handleKeydown=e=>{o.handleKeydown(e)};return(0,l.bind)({on:{click:e=>handleClick(e),keydown:e=>handleKeydown(e)}}),l.html`
2
2
  <div class="card" part="card">
3
3
  <div class="loading-bar" part="loading-bar"></div>
4
4
  <div class="card-media" part="media" ?hidden="${()=>!r.has(`media`).value}">
@@ -19,5 +19,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
19
19
  </div>
20
20
  </div>
21
21
  </div>
22
- `},styles:[n.colorThemeMixin,n.elevationMixin,t.paddingMixin,t.roundedVariantMixin,r.frostVariantMixin(`.card`),e.reducedMotionMixin,o.default]}),exports.CARD_TAG=u;
22
+ `},styles:[n.colorThemeMixin,n.elevationMixin,t.paddingMixin,t.roundedVariantMixin,r.frostVariantMixin(`.card`),e.reducedMotionMixin,s.default]}),exports.CARD_TAG=p;
23
23
  //# sourceMappingURL=card.cjs.map
package/dist/card.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"card.cjs","names":[],"sources":["../src/content/card/card.ts"],"sourcesContent":["import { bind, define, getHost, html, prop, useEmit, useSlots, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { createInteraction } from '../../core';\nimport { disablableBundle, loadableBundle, themableBundle } from '../../shared';\nimport {\n colorThemeMixin,\n elevationMixin,\n frostVariantMixin,\n paddingMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n} from '../../styles';\nimport type { ElevationLevel, PaddingSize, ThemeColor } from '../../types';\nimport componentStyles from './card.css?inline';\n\nconst INTERACTIVE_DESCENDANT_SELECTOR =\n 'button, a[href], input, select, textarea, summary, [role=\"button\"], [role=\"link\"], [contenteditable=\"\"], [contenteditable=\"true\"]';\n\nfunction isNestedInteractiveTarget(host: HTMLElement, event: Event): boolean {\n for (const node of event.composedPath()) {\n if (!(node instanceof HTMLElement)) continue;\n\n if (node === host) return false;\n\n const interactiveTarget = node.closest(INTERACTIVE_DESCENDANT_SELECTOR);\n\n if (interactiveTarget && interactiveTarget !== host) return true;\n }\n\n return false;\n}\n\n/** Card component properties */\n\nexport type OreCardEvents = {\n activate: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' };\n};\n\nexport type OreCardProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Shadow elevation level (0-5) */\n elevation?: ElevationLevel;\n /** Make the card interactive (role=button, keyboard nav, emits activate) */\n interactive?: boolean;\n /** Show a loading progress bar */\n loading?: boolean;\n /** Card orientation */\n orientation?: 'horizontal';\n /** Internal padding size */\n padding?: PaddingSize;\n /** Visual style variant */\n variant?: 'solid' | 'flat' | 'frost';\n};\n\n/**\n * A versatile card container with semantic slots for media, header, body, footer, and actions.\n *\n * @element ore-card\n *\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'frost'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} padding - Internal padding: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n * @attr {string} orientation - Card layout: 'horizontal'\n * @attr {boolean} interactive - Enable pointer/keyboard activation\n * @attr {boolean} disabled - Disable card interaction\n * @attr {boolean} loading - Show loading progress bar\n *\n * @fires activate - Emitted when an interactive card is activated. detail: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' }\n *\n * @slot media - Media content displayed at top/left\n * @slot header - Card header (title, subtitle)\n * @slot - Main card content\n * @slot footer - Card footer content\n * @slot actions - Action buttons or links\n *\n * @cssprop --card-bg - Background color\n * @cssprop --card-color - Text color\n * @cssprop --card-border - Border width\n * @cssprop --card-border-color - Border color\n * @cssprop --card-radius - Border radius\n * @cssprop --card-padding - Internal padding\n * @cssprop --card-shadow - Box shadow\n * @cssprop --card-hover-shadow - Shadow on hover\n *\n * @part card - Card root container.\n * @part loading-bar - Loading progress bar.\n * @part media - Media slot container.\n * @part body - Body content container.\n * @part header - Header container.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part actions - Actions slot container.\n * @example\n * ```html\n * <ore-card elevation=\"2\"><h3 slot=\"header\">Title</h3><p>Content</p></ore-card>\n * <ore-card interactive color=\"primary\"><h3 slot=\"header\">Click me</h3></ore-card>\n * <ore-card variant=\"frost\" color=\"secondary\">Frosted card</ore-card>\n * ```\n */\nexport const CARD_TAG = 'ore-card' as const;\ndefine<OreCardProps>(CARD_TAG, {\n props: {\n ...themableBundle,\n ...disablableBundle,\n ...loadableBundle,\n elevation: prop.number<ElevationLevel>(),\n interactive: prop.bool(false),\n orientation: prop.string<'horizontal'>(),\n padding: prop.string<PaddingSize>(),\n variant: prop.string<'solid' | 'flat' | 'frost'>(),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCardEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': () => (props.loading.value ? 'true' : 'false'),\n 'aria-disabled': () => (props.interactive.value ? String(props.disabled.value) : null),\n role: () => (props.interactive.value ? 'button' : null),\n },\n });\n\n watch(() => {\n if (props.interactive.value) {\n el.setAttribute('tabindex', props.disabled.value ? '-1' : '0');\n } else {\n el.removeAttribute('tabindex');\n }\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const pressControl = createInteraction({\n disabled: computed(() => !props.interactive.value || Boolean(props.disabled.value)),\n onPress: (originalEvent, trigger) => {\n emit('activate', { originalEvent, trigger });\n },\n });\n\n const handleClick = (e: MouseEvent) => {\n if (!props.interactive.value || props.disabled.value) return;\n\n if (isNestedInteractiveTarget(el, e)) return;\n\n pressControl.handleClick(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n pressControl.handleKeydown(e);\n };\n\n bind({\n on: {\n click: (e: MouseEvent) => handleClick(e),\n keydown: (e: KeyboardEvent) => handleKeydown(e),\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Template\n // ────────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"card\" part=\"card\">\n <div class=\"loading-bar\" part=\"loading-bar\"></div>\n <div class=\"card-media\" part=\"media\" ?hidden=\"${() => !slots.has('media').value}\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <div class=\"card-header\" part=\"header\" ?hidden=\"${() => !slots.has('header').value}\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-content\" part=\"content\" ?hidden=\"${() => !slots.has().value}\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\" ?hidden=\"${() => !slots.has('footer').value}\">\n <slot name=\"footer\"></slot>\n </div>\n <div class=\"card-actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n\n styles: [\n colorThemeMixin,\n elevationMixin,\n paddingMixin,\n roundedVariantMixin,\n frostVariantMixin('.card'),\n reducedMotionMixin,\n componentStyles,\n ],\n});\n"],"mappings":"8aAeA,IAAM,EACJ,oIAEF,SAAS,0BAA0B,EAAmB,EAAuB,CAC3E,IAAK,IAAM,KAAQ,EAAM,aAAa,EAAG,CACvC,GAAI,EAAE,aAAgB,aAAc,SAEpC,GAAI,IAAS,EAAM,MAAO,GAE1B,IAAM,EAAoB,EAAK,QAAQ,CAA+B,EAEtE,GAAI,GAAqB,IAAsB,EAAM,MAAO,EAC9D,CAEA,MAAO,EACT,CAyEA,IAAa,EAAW,YACxB,EAAA,EAAA,OAAA,CAAqB,EAAU,CAC7B,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,iBACH,GAAG,EAAA,eACH,UAAW,EAAA,KAAK,OAAuB,EACvC,YAAa,EAAA,KAAK,KAAK,EAAK,EAC5B,YAAa,EAAA,KAAK,OAAqB,EACvC,QAAS,EAAA,KAAK,OAAoB,EAClC,QAAS,EAAA,KAAK,OAAmC,CACnD,EAEA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAAuB,EAC9B,GAAA,EAAQ,EAAA,SAAA,CAAS,EACjB,EAAQ,EAAA,aAEd,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,gBAAoB,EAAM,QAAQ,MAAQ,OAAS,QACnD,oBAAwB,EAAM,YAAY,MAAQ,OAAO,EAAM,SAAS,KAAK,EAAI,KACjF,SAAa,EAAM,YAAY,MAAQ,SAAW,IACpD,CACF,CAAC,EAED,MAAY,CACN,EAAM,YAAY,MACpB,EAAG,aAAa,WAAY,EAAM,SAAS,MAAQ,KAAO,GAAG,EAE7D,EAAG,gBAAgB,UAAU,CAEjC,CAAC,EAMD,IAAM,EAAe,EAAA,kBAAkB,CACrC,UAAA,EAAU,EAAA,SAAA,KAAe,CAAC,EAAM,YAAY,OAAS,EAAQ,EAAM,SAAS,KAAM,EAClF,SAAU,EAAe,IAAY,CACnC,EAAK,WAAY,CAAE,gBAAe,SAAQ,CAAC,CAC7C,CACF,CAAC,EAEK,YAAe,GAAkB,CAChC,EAAM,YAAY,OAAS,GAAM,SAAS,QAE3C,0BAA0B,EAAI,CAAC,GAEnC,EAAa,YAAY,CAAC,EAC5B,EAEM,cAAiB,GAAqB,CAC1C,EAAa,cAAc,CAAC,CAC9B,EAaA,OAXA,EAAA,EAAA,KAAA,CAAK,CACH,GAAI,CACF,MAAQ,GAAkB,YAAY,CAAC,EACvC,QAAU,GAAqB,cAAc,CAAC,CAChD,CACF,CAAC,EAMM,EAAA,IAAI;;;4DAG+C,CAAC,EAAM,IAAI,OAAO,CAAC,CAAC,MAAM;;;;gEAItB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,CAAC,CAAC,MAAM;;;gEAGrB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,SAAS,CAAC,CAAC,MAAM;;;;;KAM9F,EAEA,OAAQ,CACN,EAAA,gBACA,EAAA,eACA,EAAA,aACA,EAAA,oBACA,EAAA,kBAAkB,OAAO,EACzB,EAAA,mBACA,EAAA,OACF,CACF,CAAC"}
1
+ {"version":3,"file":"card.cjs","names":[],"sources":["../src/content/card/card.ts"],"sourcesContent":["import { bind, define, getHost, html, prop, useEmit, useSlots, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { createInteraction } from '../../core';\nimport { disablableBundle, loadableBundle, themableBundle } from '../../shared';\nimport {\n colorThemeMixin,\n elevationMixin,\n frostVariantMixin,\n paddingMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n} from '../../styles';\nimport { ELEVATION_LEVELS, type ElevationLevel, PADDING_SIZES, type PaddingSize, type ThemeColor } from '../../types';\n\nconst CARD_ORIENTATIONS = ['horizontal'] as const;\nconst CARD_VARIANTS = ['solid', 'flat', 'frost'] as const;\n\nimport componentStyles from './card.css?inline';\n\nconst INTERACTIVE_DESCENDANT_SELECTOR =\n 'button, a[href], input, select, textarea, summary, [role=\"button\"], [role=\"link\"], [contenteditable=\"\"], [contenteditable=\"true\"]';\n\nfunction isNestedInteractiveTarget(host: HTMLElement, event: Event): boolean {\n for (const node of event.composedPath()) {\n if (!(node instanceof HTMLElement)) continue;\n\n if (node === host) return false;\n\n const interactiveTarget = node.closest(INTERACTIVE_DESCENDANT_SELECTOR);\n\n if (interactiveTarget && interactiveTarget !== host) return true;\n }\n\n return false;\n}\n\n/** Card component properties */\n\nexport type OreCardEvents = {\n activate: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' };\n};\n\nexport type OreCardProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Shadow elevation level (0-5) */\n elevation?: ElevationLevel;\n /** Make the card interactive (role=button, keyboard nav, emits activate) */\n interactive?: boolean;\n /** Show a loading progress bar */\n loading?: boolean;\n /** Card orientation */\n orientation?: (typeof CARD_ORIENTATIONS)[number];\n /** Internal padding size */\n padding?: PaddingSize;\n /** Visual style variant */\n variant?: (typeof CARD_VARIANTS)[number];\n};\n\n/**\n * A versatile card container with semantic slots for media, header, body, footer, and actions.\n *\n * @element ore-card\n *\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'frost'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} padding - Internal padding: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n * @attr {string} orientation - Card layout: 'horizontal'\n * @attr {boolean} interactive - Enable pointer/keyboard activation\n * @attr {boolean} disabled - Disable card interaction\n * @attr {boolean} loading - Show loading progress bar\n *\n * @fires activate - Emitted when an interactive card is activated. detail: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' }\n *\n * @slot media - Media content displayed at top/left\n * @slot header - Card header (title, subtitle)\n * @slot - Main card content\n * @slot footer - Card footer content\n * @slot actions - Action buttons or links\n *\n * @cssprop --card-bg - Background color\n * @cssprop --card-color - Text color\n * @cssprop --card-border - Border width\n * @cssprop --card-border-color - Border color\n * @cssprop --card-radius - Border radius\n * @cssprop --card-padding - Internal padding\n * @cssprop --card-shadow - Box shadow\n * @cssprop --card-hover-shadow - Shadow on hover\n *\n * @part card - Card root container.\n * @part loading-bar - Loading progress bar.\n * @part media - Media slot container.\n * @part body - Body content container.\n * @part header - Header container.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part actions - Actions slot container.\n * @example\n * ```html\n * <ore-card elevation=\"2\"><h3 slot=\"header\">Title</h3><p>Content</p></ore-card>\n * <ore-card interactive color=\"primary\"><h3 slot=\"header\">Click me</h3></ore-card>\n * <ore-card variant=\"frost\" color=\"secondary\">Frosted card</ore-card>\n * ```\n */\nexport const CARD_TAG = 'ore-card' as const;\ndefine<OreCardProps>(CARD_TAG, {\n props: {\n ...themableBundle,\n ...disablableBundle,\n ...loadableBundle,\n elevation: prop.oneOf(ELEVATION_LEVELS),\n interactive: prop.bool(false),\n orientation: prop.oneOf(CARD_ORIENTATIONS),\n padding: prop.oneOf(PADDING_SIZES),\n variant: prop.oneOf(CARD_VARIANTS),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCardEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': () => (props.loading.value ? 'true' : 'false'),\n 'aria-disabled': () => (props.interactive.value ? String(props.disabled.value) : null),\n role: () => (props.interactive.value ? 'button' : null),\n },\n });\n\n watch(() => {\n if (props.interactive.value) {\n el.setAttribute('tabindex', props.disabled.value ? '-1' : '0');\n } else {\n el.removeAttribute('tabindex');\n }\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const pressControl = createInteraction({\n disabled: computed(() => !props.interactive.value || Boolean(props.disabled.value)),\n onPress: (originalEvent, trigger) => {\n emit('activate', { originalEvent, trigger });\n },\n });\n\n const handleClick = (e: MouseEvent) => {\n if (!props.interactive.value || props.disabled.value) return;\n\n if (isNestedInteractiveTarget(el, e)) return;\n\n pressControl.handleClick(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n pressControl.handleKeydown(e);\n };\n\n bind({\n on: {\n click: (e: MouseEvent) => handleClick(e),\n keydown: (e: KeyboardEvent) => handleKeydown(e),\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Template\n // ────────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"card\" part=\"card\">\n <div class=\"loading-bar\" part=\"loading-bar\"></div>\n <div class=\"card-media\" part=\"media\" ?hidden=\"${() => !slots.has('media').value}\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <div class=\"card-header\" part=\"header\" ?hidden=\"${() => !slots.has('header').value}\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-content\" part=\"content\" ?hidden=\"${() => !slots.has().value}\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\" ?hidden=\"${() => !slots.has('footer').value}\">\n <slot name=\"footer\"></slot>\n </div>\n <div class=\"card-actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n\n styles: [\n colorThemeMixin,\n elevationMixin,\n paddingMixin,\n roundedVariantMixin,\n frostVariantMixin('.card'),\n reducedMotionMixin,\n componentStyles,\n ],\n});\n"],"mappings":"8cAcA,IAAM,EAAoB,CAAC,YAAY,EACjC,EAAgB,CAAC,QAAS,OAAQ,OAAO,EAIzC,EACJ,oIAEF,SAAS,0BAA0B,EAAmB,EAAuB,CAC3E,IAAK,IAAM,KAAQ,EAAM,aAAa,EAAG,CACvC,GAAI,EAAE,aAAgB,aAAc,SAEpC,GAAI,IAAS,EAAM,MAAO,GAE1B,IAAM,EAAoB,EAAK,QAAQ,CAA+B,EAEtE,GAAI,GAAqB,IAAsB,EAAM,MAAO,EAC9D,CAEA,MAAO,EACT,CAyEA,IAAa,EAAW,YACxB,EAAA,EAAA,OAAA,CAAqB,EAAU,CAC7B,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,iBACH,GAAG,EAAA,eACH,UAAW,EAAA,KAAK,MAAM,EAAA,gBAAgB,EACtC,YAAa,EAAA,KAAK,KAAK,EAAK,EAC5B,YAAa,EAAA,KAAK,MAAM,CAAiB,EACzC,QAAS,EAAA,KAAK,MAAM,EAAA,aAAa,EACjC,QAAS,EAAA,KAAK,MAAM,CAAa,CACnC,EAEA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAAuB,EAC9B,GAAA,EAAQ,EAAA,SAAA,CAAS,EACjB,EAAQ,EAAA,aAEd,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,gBAAoB,EAAM,QAAQ,MAAQ,OAAS,QACnD,oBAAwB,EAAM,YAAY,MAAQ,OAAO,EAAM,SAAS,KAAK,EAAI,KACjF,SAAa,EAAM,YAAY,MAAQ,SAAW,IACpD,CACF,CAAC,EAED,MAAY,CACN,EAAM,YAAY,MACpB,EAAG,aAAa,WAAY,EAAM,SAAS,MAAQ,KAAO,GAAG,EAE7D,EAAG,gBAAgB,UAAU,CAEjC,CAAC,EAMD,IAAM,EAAe,EAAA,kBAAkB,CACrC,UAAA,EAAU,EAAA,SAAA,KAAe,CAAC,EAAM,YAAY,OAAS,EAAQ,EAAM,SAAS,KAAM,EAClF,SAAU,EAAe,IAAY,CACnC,EAAK,WAAY,CAAE,gBAAe,SAAQ,CAAC,CAC7C,CACF,CAAC,EAEK,YAAe,GAAkB,CAChC,EAAM,YAAY,OAAS,GAAM,SAAS,QAE3C,0BAA0B,EAAI,CAAC,GAEnC,EAAa,YAAY,CAAC,EAC5B,EAEM,cAAiB,GAAqB,CAC1C,EAAa,cAAc,CAAC,CAC9B,EAaA,OAXA,EAAA,EAAA,KAAA,CAAK,CACH,GAAI,CACF,MAAQ,GAAkB,YAAY,CAAC,EACvC,QAAU,GAAqB,cAAc,CAAC,CAChD,CACF,CAAC,EAMM,EAAA,IAAI;;;4DAG+C,CAAC,EAAM,IAAI,OAAO,CAAC,CAAC,MAAM;;;;gEAItB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,CAAC,CAAC,MAAM;;;gEAGrB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,SAAS,CAAC,CAAC,MAAM;;;;;KAM9F,EAEA,OAAQ,CACN,EAAA,gBACA,EAAA,eACA,EAAA,aACA,EAAA,oBACA,EAAA,kBAAkB,OAAO,EACzB,EAAA,mBACA,EAAA,OACF,CACF,CAAC"}
package/dist/card.js CHANGED
@@ -1,4 +1,4 @@
1
- import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import{paddingMixin as t,roundedVariantMixin as n}from"./styles/mixins/shape.css.js";import{colorThemeMixin as r,elevationMixin as i}from"./styles/mixins/theme.css.js";import{frostVariantMixin as a}from"./styles/mixins/variants.css.js";import{createInteraction as o}from"./core/keyboard.js";import{disablableBundle as s,loadableBundle as c,themableBundle as l}from"./shared/prop-bundles.js";import u from"./content/card/card.css.js";import{computed as d}from"@vielzeug/ripple";import{bind as f,define as p,getHost as m,html as h,prop as g,useEmit as _,useSlots as v,watchEffect as y}from"@vielzeug/ore";var b=`button, a[href], input, select, textarea, summary, [role="button"], [role="link"], [contenteditable=""], [contenteditable="true"]`;function isNestedInteractiveTarget(e,t){for(let n of t.composedPath()){if(!(n instanceof HTMLElement))continue;if(n===e)return!1;let t=n.closest(b);if(t&&t!==e)return!0}return!1}var x=`ore-card`;p(x,{props:{...l,...s,...c,elevation:g.number(),interactive:g.bool(!1),orientation:g.string(),padding:g.string(),variant:g.string()},setup(e){let t=m(),n=_(),r=v(),i=y;f({attr:{"aria-busy":()=>e.loading.value?`true`:`false`,"aria-disabled":()=>e.interactive.value?String(e.disabled.value):null,role:()=>e.interactive.value?`button`:null}}),i(()=>{e.interactive.value?t.setAttribute(`tabindex`,e.disabled.value?`-1`:`0`):t.removeAttribute(`tabindex`)});let a=o({disabled:d(()=>!e.interactive.value||!!e.disabled.value),onPress:(e,t)=>{n(`activate`,{originalEvent:e,trigger:t})}}),handleClick=n=>{e.interactive.value&&!e.disabled.value&&(isNestedInteractiveTarget(t,n)||a.handleClick(n))},handleKeydown=e=>{a.handleKeydown(e)};return f({on:{click:e=>handleClick(e),keydown:e=>handleKeydown(e)}}),h`
1
+ import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import{paddingMixin as t,roundedVariantMixin as n}from"./styles/mixins/shape.css.js";import{colorThemeMixin as r,elevationMixin as i}from"./styles/mixins/theme.css.js";import{frostVariantMixin as a}from"./styles/mixins/variants.css.js";import{createInteraction as o}from"./core/keyboard.js";import{ELEVATION_LEVELS as s,PADDING_SIZES as c}from"./shared/types.js";import{disablableBundle as l,loadableBundle as u,themableBundle as d}from"./shared/prop-bundles.js";import f from"./content/card/card.css.js";import{computed as p}from"@vielzeug/ripple";import{bind as m,define as h,getHost as g,html as _,prop as v,useEmit as y,useSlots as b,watchEffect as x}from"@vielzeug/ore";var S=[`horizontal`],C=[`solid`,`flat`,`frost`],w=`button, a[href], input, select, textarea, summary, [role="button"], [role="link"], [contenteditable=""], [contenteditable="true"]`;function isNestedInteractiveTarget(e,t){for(let n of t.composedPath()){if(!(n instanceof HTMLElement))continue;if(n===e)return!1;let t=n.closest(w);if(t&&t!==e)return!0}return!1}var T=`ore-card`;h(T,{props:{...d,...l,...u,elevation:v.oneOf(s),interactive:v.bool(!1),orientation:v.oneOf(S),padding:v.oneOf(c),variant:v.oneOf(C)},setup(e){let t=g(),n=y(),r=b(),i=x;m({attr:{"aria-busy":()=>e.loading.value?`true`:`false`,"aria-disabled":()=>e.interactive.value?String(e.disabled.value):null,role:()=>e.interactive.value?`button`:null}}),i(()=>{e.interactive.value?t.setAttribute(`tabindex`,e.disabled.value?`-1`:`0`):t.removeAttribute(`tabindex`)});let a=o({disabled:p(()=>!e.interactive.value||!!e.disabled.value),onPress:(e,t)=>{n(`activate`,{originalEvent:e,trigger:t})}}),handleClick=n=>{e.interactive.value&&!e.disabled.value&&(isNestedInteractiveTarget(t,n)||a.handleClick(n))},handleKeydown=e=>{a.handleKeydown(e)};return m({on:{click:e=>handleClick(e),keydown:e=>handleKeydown(e)}}),_`
2
2
  <div class="card" part="card">
3
3
  <div class="loading-bar" part="loading-bar"></div>
4
4
  <div class="card-media" part="media" ?hidden="${()=>!r.has(`media`).value}">
@@ -19,5 +19,5 @@ import{reducedMotionMixin as e}from"./styles/mixins/accessibility.css.js";import
19
19
  </div>
20
20
  </div>
21
21
  </div>
22
- `},styles:[r,i,t,n,a(`.card`),e,u]});export{x as CARD_TAG};
22
+ `},styles:[r,i,t,n,a(`.card`),e,f]});export{T as CARD_TAG};
23
23
  //# sourceMappingURL=card.js.map
package/dist/card.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","names":[],"sources":["../src/content/card/card.ts"],"sourcesContent":["import { bind, define, getHost, html, prop, useEmit, useSlots, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { createInteraction } from '../../core';\nimport { disablableBundle, loadableBundle, themableBundle } from '../../shared';\nimport {\n colorThemeMixin,\n elevationMixin,\n frostVariantMixin,\n paddingMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n} from '../../styles';\nimport type { ElevationLevel, PaddingSize, ThemeColor } from '../../types';\nimport componentStyles from './card.css?inline';\n\nconst INTERACTIVE_DESCENDANT_SELECTOR =\n 'button, a[href], input, select, textarea, summary, [role=\"button\"], [role=\"link\"], [contenteditable=\"\"], [contenteditable=\"true\"]';\n\nfunction isNestedInteractiveTarget(host: HTMLElement, event: Event): boolean {\n for (const node of event.composedPath()) {\n if (!(node instanceof HTMLElement)) continue;\n\n if (node === host) return false;\n\n const interactiveTarget = node.closest(INTERACTIVE_DESCENDANT_SELECTOR);\n\n if (interactiveTarget && interactiveTarget !== host) return true;\n }\n\n return false;\n}\n\n/** Card component properties */\n\nexport type OreCardEvents = {\n activate: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' };\n};\n\nexport type OreCardProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Shadow elevation level (0-5) */\n elevation?: ElevationLevel;\n /** Make the card interactive (role=button, keyboard nav, emits activate) */\n interactive?: boolean;\n /** Show a loading progress bar */\n loading?: boolean;\n /** Card orientation */\n orientation?: 'horizontal';\n /** Internal padding size */\n padding?: PaddingSize;\n /** Visual style variant */\n variant?: 'solid' | 'flat' | 'frost';\n};\n\n/**\n * A versatile card container with semantic slots for media, header, body, footer, and actions.\n *\n * @element ore-card\n *\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'frost'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} padding - Internal padding: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n * @attr {string} orientation - Card layout: 'horizontal'\n * @attr {boolean} interactive - Enable pointer/keyboard activation\n * @attr {boolean} disabled - Disable card interaction\n * @attr {boolean} loading - Show loading progress bar\n *\n * @fires activate - Emitted when an interactive card is activated. detail: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' }\n *\n * @slot media - Media content displayed at top/left\n * @slot header - Card header (title, subtitle)\n * @slot - Main card content\n * @slot footer - Card footer content\n * @slot actions - Action buttons or links\n *\n * @cssprop --card-bg - Background color\n * @cssprop --card-color - Text color\n * @cssprop --card-border - Border width\n * @cssprop --card-border-color - Border color\n * @cssprop --card-radius - Border radius\n * @cssprop --card-padding - Internal padding\n * @cssprop --card-shadow - Box shadow\n * @cssprop --card-hover-shadow - Shadow on hover\n *\n * @part card - Card root container.\n * @part loading-bar - Loading progress bar.\n * @part media - Media slot container.\n * @part body - Body content container.\n * @part header - Header container.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part actions - Actions slot container.\n * @example\n * ```html\n * <ore-card elevation=\"2\"><h3 slot=\"header\">Title</h3><p>Content</p></ore-card>\n * <ore-card interactive color=\"primary\"><h3 slot=\"header\">Click me</h3></ore-card>\n * <ore-card variant=\"frost\" color=\"secondary\">Frosted card</ore-card>\n * ```\n */\nexport const CARD_TAG = 'ore-card' as const;\ndefine<OreCardProps>(CARD_TAG, {\n props: {\n ...themableBundle,\n ...disablableBundle,\n ...loadableBundle,\n elevation: prop.number<ElevationLevel>(),\n interactive: prop.bool(false),\n orientation: prop.string<'horizontal'>(),\n padding: prop.string<PaddingSize>(),\n variant: prop.string<'solid' | 'flat' | 'frost'>(),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCardEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': () => (props.loading.value ? 'true' : 'false'),\n 'aria-disabled': () => (props.interactive.value ? String(props.disabled.value) : null),\n role: () => (props.interactive.value ? 'button' : null),\n },\n });\n\n watch(() => {\n if (props.interactive.value) {\n el.setAttribute('tabindex', props.disabled.value ? '-1' : '0');\n } else {\n el.removeAttribute('tabindex');\n }\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const pressControl = createInteraction({\n disabled: computed(() => !props.interactive.value || Boolean(props.disabled.value)),\n onPress: (originalEvent, trigger) => {\n emit('activate', { originalEvent, trigger });\n },\n });\n\n const handleClick = (e: MouseEvent) => {\n if (!props.interactive.value || props.disabled.value) return;\n\n if (isNestedInteractiveTarget(el, e)) return;\n\n pressControl.handleClick(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n pressControl.handleKeydown(e);\n };\n\n bind({\n on: {\n click: (e: MouseEvent) => handleClick(e),\n keydown: (e: KeyboardEvent) => handleKeydown(e),\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Template\n // ────────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"card\" part=\"card\">\n <div class=\"loading-bar\" part=\"loading-bar\"></div>\n <div class=\"card-media\" part=\"media\" ?hidden=\"${() => !slots.has('media').value}\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <div class=\"card-header\" part=\"header\" ?hidden=\"${() => !slots.has('header').value}\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-content\" part=\"content\" ?hidden=\"${() => !slots.has().value}\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\" ?hidden=\"${() => !slots.has('footer').value}\">\n <slot name=\"footer\"></slot>\n </div>\n <div class=\"card-actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n\n styles: [\n colorThemeMixin,\n elevationMixin,\n paddingMixin,\n roundedVariantMixin,\n frostVariantMixin('.card'),\n reducedMotionMixin,\n componentStyles,\n ],\n});\n"],"mappings":"qqBAeA,IAAM,EACJ,oIAEF,SAAS,0BAA0B,EAAmB,EAAuB,CAC3E,IAAK,IAAM,KAAQ,EAAM,aAAa,EAAG,CACvC,GAAI,EAAE,aAAgB,aAAc,SAEpC,GAAI,IAAS,EAAM,MAAO,GAE1B,IAAM,EAAoB,EAAK,QAAQ,CAA+B,EAEtE,GAAI,GAAqB,IAAsB,EAAM,MAAO,EAC9D,CAEA,MAAO,EACT,CAyEA,IAAa,EAAW,WACxB,EAAqB,EAAU,CAC7B,MAAO,CACL,GAAG,EACH,GAAG,EACH,GAAG,EACH,UAAW,EAAK,OAAuB,EACvC,YAAa,EAAK,KAAK,EAAK,EAC5B,YAAa,EAAK,OAAqB,EACvC,QAAS,EAAK,OAAoB,EAClC,QAAS,EAAK,OAAmC,CACnD,EAEA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EACb,EAAO,EAAuB,EAC9B,EAAQ,EAAS,EACjB,EAAQ,EAEd,EAAK,CACH,KAAM,CACJ,gBAAoB,EAAM,QAAQ,MAAQ,OAAS,QACnD,oBAAwB,EAAM,YAAY,MAAQ,OAAO,EAAM,SAAS,KAAK,EAAI,KACjF,SAAa,EAAM,YAAY,MAAQ,SAAW,IACpD,CACF,CAAC,EAED,MAAY,CACN,EAAM,YAAY,MACpB,EAAG,aAAa,WAAY,EAAM,SAAS,MAAQ,KAAO,GAAG,EAE7D,EAAG,gBAAgB,UAAU,CAEjC,CAAC,EAMD,IAAM,EAAe,EAAkB,CACrC,SAAU,MAAe,CAAC,EAAM,YAAY,OAAS,EAAQ,EAAM,SAAS,KAAM,EAClF,SAAU,EAAe,IAAY,CACnC,EAAK,WAAY,CAAE,gBAAe,SAAQ,CAAC,CAC7C,CACF,CAAC,EAEK,YAAe,GAAkB,CAChC,EAAM,YAAY,OAAS,GAAM,SAAS,QAE3C,0BAA0B,EAAI,CAAC,GAEnC,EAAa,YAAY,CAAC,EAC5B,EAEM,cAAiB,GAAqB,CAC1C,EAAa,cAAc,CAAC,CAC9B,EAaA,OAXA,EAAK,CACH,GAAI,CACF,MAAQ,GAAkB,YAAY,CAAC,EACvC,QAAU,GAAqB,cAAc,CAAC,CAChD,CACF,CAAC,EAMM,CAAI;;;4DAG+C,CAAC,EAAM,IAAI,OAAO,CAAC,CAAC,MAAM;;;;gEAItB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,CAAC,CAAC,MAAM;;;gEAGrB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,SAAS,CAAC,CAAC,MAAM;;;;;KAM9F,EAEA,OAAQ,CACN,EACA,EACA,EACA,EACA,EAAkB,OAAO,EACzB,EACA,CACF,CACF,CAAC"}
1
+ {"version":3,"file":"card.js","names":[],"sources":["../src/content/card/card.ts"],"sourcesContent":["import { bind, define, getHost, html, prop, useEmit, useSlots, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { createInteraction } from '../../core';\nimport { disablableBundle, loadableBundle, themableBundle } from '../../shared';\nimport {\n colorThemeMixin,\n elevationMixin,\n frostVariantMixin,\n paddingMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n} from '../../styles';\nimport { ELEVATION_LEVELS, type ElevationLevel, PADDING_SIZES, type PaddingSize, type ThemeColor } from '../../types';\n\nconst CARD_ORIENTATIONS = ['horizontal'] as const;\nconst CARD_VARIANTS = ['solid', 'flat', 'frost'] as const;\n\nimport componentStyles from './card.css?inline';\n\nconst INTERACTIVE_DESCENDANT_SELECTOR =\n 'button, a[href], input, select, textarea, summary, [role=\"button\"], [role=\"link\"], [contenteditable=\"\"], [contenteditable=\"true\"]';\n\nfunction isNestedInteractiveTarget(host: HTMLElement, event: Event): boolean {\n for (const node of event.composedPath()) {\n if (!(node instanceof HTMLElement)) continue;\n\n if (node === host) return false;\n\n const interactiveTarget = node.closest(INTERACTIVE_DESCENDANT_SELECTOR);\n\n if (interactiveTarget && interactiveTarget !== host) return true;\n }\n\n return false;\n}\n\n/** Card component properties */\n\nexport type OreCardEvents = {\n activate: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' };\n};\n\nexport type OreCardProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Shadow elevation level (0-5) */\n elevation?: ElevationLevel;\n /** Make the card interactive (role=button, keyboard nav, emits activate) */\n interactive?: boolean;\n /** Show a loading progress bar */\n loading?: boolean;\n /** Card orientation */\n orientation?: (typeof CARD_ORIENTATIONS)[number];\n /** Internal padding size */\n padding?: PaddingSize;\n /** Visual style variant */\n variant?: (typeof CARD_VARIANTS)[number];\n};\n\n/**\n * A versatile card container with semantic slots for media, header, body, footer, and actions.\n *\n * @element ore-card\n *\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'frost'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} padding - Internal padding: 'none' | 'sm' | 'md' | 'lg' | 'xl'\n * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'\n * @attr {string} orientation - Card layout: 'horizontal'\n * @attr {boolean} interactive - Enable pointer/keyboard activation\n * @attr {boolean} disabled - Disable card interaction\n * @attr {boolean} loading - Show loading progress bar\n *\n * @fires activate - Emitted when an interactive card is activated. detail: { originalEvent: MouseEvent | KeyboardEvent; trigger: 'pointer' | 'keyboard' }\n *\n * @slot media - Media content displayed at top/left\n * @slot header - Card header (title, subtitle)\n * @slot - Main card content\n * @slot footer - Card footer content\n * @slot actions - Action buttons or links\n *\n * @cssprop --card-bg - Background color\n * @cssprop --card-color - Text color\n * @cssprop --card-border - Border width\n * @cssprop --card-border-color - Border color\n * @cssprop --card-radius - Border radius\n * @cssprop --card-padding - Internal padding\n * @cssprop --card-shadow - Box shadow\n * @cssprop --card-hover-shadow - Shadow on hover\n *\n * @part card - Card root container.\n * @part loading-bar - Loading progress bar.\n * @part media - Media slot container.\n * @part body - Body content container.\n * @part header - Header container.\n * @part content - Content container.\n * @part footer - Footer container.\n * @part actions - Actions slot container.\n * @example\n * ```html\n * <ore-card elevation=\"2\"><h3 slot=\"header\">Title</h3><p>Content</p></ore-card>\n * <ore-card interactive color=\"primary\"><h3 slot=\"header\">Click me</h3></ore-card>\n * <ore-card variant=\"frost\" color=\"secondary\">Frosted card</ore-card>\n * ```\n */\nexport const CARD_TAG = 'ore-card' as const;\ndefine<OreCardProps>(CARD_TAG, {\n props: {\n ...themableBundle,\n ...disablableBundle,\n ...loadableBundle,\n elevation: prop.oneOf(ELEVATION_LEVELS),\n interactive: prop.bool(false),\n orientation: prop.oneOf(CARD_ORIENTATIONS),\n padding: prop.oneOf(PADDING_SIZES),\n variant: prop.oneOf(CARD_VARIANTS),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCardEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': () => (props.loading.value ? 'true' : 'false'),\n 'aria-disabled': () => (props.interactive.value ? String(props.disabled.value) : null),\n role: () => (props.interactive.value ? 'button' : null),\n },\n });\n\n watch(() => {\n if (props.interactive.value) {\n el.setAttribute('tabindex', props.disabled.value ? '-1' : '0');\n } else {\n el.removeAttribute('tabindex');\n }\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const pressControl = createInteraction({\n disabled: computed(() => !props.interactive.value || Boolean(props.disabled.value)),\n onPress: (originalEvent, trigger) => {\n emit('activate', { originalEvent, trigger });\n },\n });\n\n const handleClick = (e: MouseEvent) => {\n if (!props.interactive.value || props.disabled.value) return;\n\n if (isNestedInteractiveTarget(el, e)) return;\n\n pressControl.handleClick(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n pressControl.handleKeydown(e);\n };\n\n bind({\n on: {\n click: (e: MouseEvent) => handleClick(e),\n keydown: (e: KeyboardEvent) => handleKeydown(e),\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Template\n // ────────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"card\" part=\"card\">\n <div class=\"loading-bar\" part=\"loading-bar\"></div>\n <div class=\"card-media\" part=\"media\" ?hidden=\"${() => !slots.has('media').value}\">\n <slot name=\"media\"></slot>\n </div>\n <div class=\"card-body\" part=\"body\">\n <div class=\"card-header\" part=\"header\" ?hidden=\"${() => !slots.has('header').value}\">\n <slot name=\"header\"></slot>\n </div>\n <div class=\"card-content\" part=\"content\" ?hidden=\"${() => !slots.has().value}\">\n <slot></slot>\n </div>\n <div class=\"card-footer\" part=\"footer\" ?hidden=\"${() => !slots.has('footer').value}\">\n <slot name=\"footer\"></slot>\n </div>\n <div class=\"card-actions\" part=\"actions\" ?hidden=\"${() => !slots.has('actions').value}\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </div>\n `;\n },\n\n styles: [\n colorThemeMixin,\n elevationMixin,\n paddingMixin,\n roundedVariantMixin,\n frostVariantMixin('.card'),\n reducedMotionMixin,\n componentStyles,\n ],\n});\n"],"mappings":"6uBAcA,IAAM,EAAoB,CAAC,YAAY,EACjC,EAAgB,CAAC,QAAS,OAAQ,OAAO,EAIzC,EACJ,oIAEF,SAAS,0BAA0B,EAAmB,EAAuB,CAC3E,IAAK,IAAM,KAAQ,EAAM,aAAa,EAAG,CACvC,GAAI,EAAE,aAAgB,aAAc,SAEpC,GAAI,IAAS,EAAM,MAAO,GAE1B,IAAM,EAAoB,EAAK,QAAQ,CAA+B,EAEtE,GAAI,GAAqB,IAAsB,EAAM,MAAO,EAC9D,CAEA,MAAO,EACT,CAyEA,IAAa,EAAW,WACxB,EAAqB,EAAU,CAC7B,MAAO,CACL,GAAG,EACH,GAAG,EACH,GAAG,EACH,UAAW,EAAK,MAAM,CAAgB,EACtC,YAAa,EAAK,KAAK,EAAK,EAC5B,YAAa,EAAK,MAAM,CAAiB,EACzC,QAAS,EAAK,MAAM,CAAa,EACjC,QAAS,EAAK,MAAM,CAAa,CACnC,EAEA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EACb,EAAO,EAAuB,EAC9B,EAAQ,EAAS,EACjB,EAAQ,EAEd,EAAK,CACH,KAAM,CACJ,gBAAoB,EAAM,QAAQ,MAAQ,OAAS,QACnD,oBAAwB,EAAM,YAAY,MAAQ,OAAO,EAAM,SAAS,KAAK,EAAI,KACjF,SAAa,EAAM,YAAY,MAAQ,SAAW,IACpD,CACF,CAAC,EAED,MAAY,CACN,EAAM,YAAY,MACpB,EAAG,aAAa,WAAY,EAAM,SAAS,MAAQ,KAAO,GAAG,EAE7D,EAAG,gBAAgB,UAAU,CAEjC,CAAC,EAMD,IAAM,EAAe,EAAkB,CACrC,SAAU,MAAe,CAAC,EAAM,YAAY,OAAS,EAAQ,EAAM,SAAS,KAAM,EAClF,SAAU,EAAe,IAAY,CACnC,EAAK,WAAY,CAAE,gBAAe,SAAQ,CAAC,CAC7C,CACF,CAAC,EAEK,YAAe,GAAkB,CAChC,EAAM,YAAY,OAAS,GAAM,SAAS,QAE3C,0BAA0B,EAAI,CAAC,GAEnC,EAAa,YAAY,CAAC,EAC5B,EAEM,cAAiB,GAAqB,CAC1C,EAAa,cAAc,CAAC,CAC9B,EAaA,OAXA,EAAK,CACH,GAAI,CACF,MAAQ,GAAkB,YAAY,CAAC,EACvC,QAAU,GAAqB,cAAc,CAAC,CAChD,CACF,CAAC,EAMM,CAAI;;;4DAG+C,CAAC,EAAM,IAAI,OAAO,CAAC,CAAC,MAAM;;;;gEAItB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,CAAC,CAAC,MAAM;;;gEAGrB,CAAC,EAAM,IAAI,QAAQ,CAAC,CAAC,MAAM;;;kEAGzB,CAAC,EAAM,IAAI,SAAS,CAAC,CAAC,MAAM;;;;;KAM9F,EAEA,OAAQ,CACN,EACA,EACA,EACA,EACA,EAAkB,OAAO,EACzB,EACA,CACF,CACF,CAAC"}
package/dist/carousel.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core/announcer.cjs"),t=require("./core/ore.cjs"),n=require("./core/nav.cjs"),r=require("./icon.cjs"),i=require("./content/carousel/carousel.css.cjs"),a=require("./content/carousel/carousel-slide.cjs"),o=require("./progress.cjs");let s=require("@vielzeug/ripple"),c=require("@vielzeug/ore"),l=require("@vielzeug/gesture");var u=`ore-carousel`,syncDefaultSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.toggleAttribute(`data-before`,r<t),e.toggleAttribute(`data-after`,r>t)})},syncFilmstripSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`)})},syncGallerySlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t,a=t>0&&r===t-1,o=t<n-1&&r===t+1;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`),e.toggleAttribute(`data-gallery-visible`,i||a||o)})};(0,c.define)(u,{props:{autoplay:c.prop.bool(!1),"autoplay-interval":c.prop.number(5e3),color:c.prop.string(),label:c.prop.string(`Carousel`),loop:c.prop.bool(!0),orientation:c.prop.string(`horizontal`),"show-controls":c.prop.bool(!0),"show-indicators":c.prop.bool(!0),"slide-index":c.prop.number(0),variant:c.prop.string(`default`)},setup(r){let i=(0,c.getHost)(),a=(0,c.useEmit)(),o=(0,s.signal)(r[`slide-index`].value??0),u=null,d=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),f=(0,s.signal)(d.length),refreshSlides=()=>{d=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),f.value=d.length},p=(0,s.computed)(()=>r.orientation.value!==`vertical`),m=(0,s.computed)(()=>r.loop.value!==!1),h=(0,s.computed)(()=>r[`show-controls`].value!==!1),g=(0,s.computed)(()=>r[`show-indicators`].value!==!1),_=(0,s.computed)(()=>m.value||o.value>0),v=(0,s.computed)(()=>m.value||o.value<f.value-1),goTo=(t,n=!0)=>{let r=f.value;if(r===0)return;let s=m.value?(t%r+r)%r:Math.max(0,Math.min(t,r-1));s!==o.value&&(o.value=s,i.setAttribute(`slide-index`,String(s)),a(`change`,{index:s}),n&&e.announce(d[s]?.getAttribute(`aria-label`)??`Slide ${s+1} of ${r}`,{document:i.ownerDocument}))},prev=()=>goTo(o.value-1),next=()=>goTo(o.value+1);(0,s.watch)(r[`slide-index`],e=>{typeof e==`number`&&e!==o.value&&goTo(e,!1)});let syncSlideVariants=()=>{let e=r.variant.value??`default`,t=r.orientation.value??`horizontal`;d.forEach(n=>{n.setAttribute(`data-variant`,e),n.setAttribute(`data-orientation`,t)})};(0,s.watch)((0,s.computed)(()=>({orientation:r.orientation.value,variant:r.variant.value})),syncSlideVariants,{immediate:!0});let y={default:syncDefaultSlides,fade:syncDefaultSlides,filmstrip:syncFilmstripSlides,gallery:syncGallerySlides},syncActiveState=()=>{let e=r.variant.value??`default`;y[e](d,o.value)};(0,s.watch)(o,syncActiveState,{immediate:!0});let startAutoplay=()=>{u===null&&(u=setInterval(next,r[`autoplay-interval`].value??5e3))},stopAutoplay=()=>{u!==null&&(clearInterval(u),u=null)};(0,s.watch)((0,s.computed)(()=>({enabled:r.autoplay.value,interval:r[`autoplay-interval`].value})),({enabled:e})=>{stopAutoplay(),e&&startAutoplay()});let handleKeydown=e=>{let t=p.value,n=t?`ArrowLeft`:`ArrowUp`,r=t?`ArrowRight`:`ArrowDown`;e.key===n?(e.preventDefault(),prev()):e.key===r?(e.preventDefault(),next()):e.key===`Home`?(e.preventDefault(),goTo(0)):e.key===`End`&&(e.preventDefault(),goTo(f.value-1))},b=n.createListControl({getItems:()=>Array.from({length:f.value},(e,t)=>t),loop:!0,onNavigate:({index:e})=>{goTo(e),(i.shadowRoot?.querySelector(`.indicator[data-index="${e}"]`))?.focus()},orientation:()=>p.value?`horizontal`:`vertical`,signal:t.lifecycleSignal(c.onCleanup)});(0,c.bind)({attr:{"aria-label":()=>r.label.value??`Carousel`,"aria-roledescription":()=>`carousel`,orientation:()=>r.orientation.value??`horizontal`,role:()=>`region`,style:()=>`touch-action:${p.value?`pan-y`:`pan-x`}`,variant:()=>r.variant.value??`default`},on:{focusin:()=>{stopAutoplay()},focusout:()=>{r.autoplay.value&&startAutoplay()},keydown:handleKeydown,pointerenter:()=>{stopAutoplay()},pointerleave:()=>{r.autoplay.value&&startAutoplay()}}}),(0,c.onMounted)(()=>{let e=(0,l.createPanGesture)(i,{axis:()=>p.value?`x`:`y`,onEnd:({distance:e,reason:t})=>{t!==`release`||Math.abs(e)<48||(e<0?next():prev())},shouldStart:e=>!e.composedPath().some(e=>e instanceof HTMLElement&&(e.tagName===`BUTTON`||e.tagName===`ORE-BUTTON`||e.tagName===`ORE-PROGRESS`))}),t=i.shadowRoot.querySelector(`slot`),onSlotChange=()=>{refreshSlides(),syncSlideVariants(),syncActiveState()};return t.addEventListener(`slotchange`,onSlotChange),r.autoplay.value&&startAutoplay(),()=>{e.dispose(),stopAutoplay(),t.removeEventListener(`slotchange`,onSlotChange)}});let renderControls=()=>h.value?c.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core/announcer.cjs"),t=require("./core/ore.cjs"),n=require("./core/nav.cjs"),r=require("./shared/types.cjs"),i=require("./icon.cjs"),a=require("./content/carousel/carousel.css.cjs"),o=require("./content/carousel/carousel-slide.cjs"),s=require("./progress.cjs");let c=require("@vielzeug/ripple"),l=require("@vielzeug/ore"),u=require("@vielzeug/gesture");var d=[`horizontal`,`vertical`],f=[`default`,`fade`,`filmstrip`,`gallery`],p=`ore-carousel`,syncDefaultSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.toggleAttribute(`data-before`,r<t),e.toggleAttribute(`data-after`,r>t)})},syncFilmstripSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`)})},syncGallerySlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t,a=t>0&&r===t-1,o=t<n-1&&r===t+1;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`),e.toggleAttribute(`data-gallery-visible`,i||a||o)})};(0,l.define)(p,{props:{autoplay:l.prop.bool(!1),"autoplay-interval":l.prop.number(5e3),color:l.prop.oneOf(r.THEME_COLORS),label:l.prop.string(`Carousel`),loop:l.prop.bool(!0),orientation:l.prop.oneOf(d,`horizontal`),"show-controls":l.prop.bool(!0),"show-indicators":l.prop.bool(!0),"slide-index":l.prop.number(0),variant:l.prop.oneOf(f,`default`)},setup(r){let i=(0,l.getHost)(),a=(0,l.useEmit)(),o=(0,c.signal)(r[`slide-index`].value??0),s=null,d=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),f=(0,c.signal)(d.length),refreshSlides=()=>{d=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),f.value=d.length},p=(0,c.computed)(()=>r.orientation.value!==`vertical`),m=(0,c.computed)(()=>r.loop.value!==!1),h=(0,c.computed)(()=>r[`show-controls`].value!==!1),g=(0,c.computed)(()=>r[`show-indicators`].value!==!1),_=(0,c.computed)(()=>m.value||o.value>0),v=(0,c.computed)(()=>m.value||o.value<f.value-1),goTo=(t,n=!0)=>{let r=f.value;if(r===0)return;let s=m.value?(t%r+r)%r:Math.max(0,Math.min(t,r-1));s!==o.value&&(o.value=s,i.setAttribute(`slide-index`,String(s)),a(`change`,{index:s}),n&&e.announce(d[s]?.getAttribute(`aria-label`)??`Slide ${s+1} of ${r}`,{document:i.ownerDocument}))},prev=()=>goTo(o.value-1),next=()=>goTo(o.value+1);(0,c.watch)(r[`slide-index`],e=>{typeof e==`number`&&e!==o.value&&goTo(e,!1)});let syncSlideVariants=()=>{let e=r.variant.value??`default`,t=r.orientation.value??`horizontal`;d.forEach(n=>{n.setAttribute(`data-variant`,e),n.setAttribute(`data-orientation`,t)})};(0,c.watch)((0,c.computed)(()=>({orientation:r.orientation.value,variant:r.variant.value})),syncSlideVariants,{immediate:!0});let y={default:syncDefaultSlides,fade:syncDefaultSlides,filmstrip:syncFilmstripSlides,gallery:syncGallerySlides},syncActiveState=()=>{let e=r.variant.value??`default`;y[e](d,o.value)};(0,c.watch)(o,syncActiveState,{immediate:!0});let startAutoplay=()=>{s===null&&(s=setInterval(next,r[`autoplay-interval`].value??5e3))},stopAutoplay=()=>{s!==null&&(clearInterval(s),s=null)};(0,c.watch)((0,c.computed)(()=>({enabled:r.autoplay.value,interval:r[`autoplay-interval`].value})),({enabled:e})=>{stopAutoplay(),e&&startAutoplay()});let handleKeydown=e=>{let t=p.value,n=t?`ArrowLeft`:`ArrowUp`,r=t?`ArrowRight`:`ArrowDown`;e.key===n?(e.preventDefault(),prev()):e.key===r?(e.preventDefault(),next()):e.key===`Home`?(e.preventDefault(),goTo(0)):e.key===`End`&&(e.preventDefault(),goTo(f.value-1))},b=n.createListControl({getItems:()=>Array.from({length:f.value},(e,t)=>t),loop:!0,onNavigate:({index:e})=>{goTo(e),(i.shadowRoot?.querySelector(`.indicator[data-index="${e}"]`))?.focus()},orientation:()=>p.value?`horizontal`:`vertical`,signal:t.lifecycleSignal(l.onCleanup)});(0,l.bind)({attr:{"aria-label":()=>r.label.value??`Carousel`,"aria-roledescription":()=>`carousel`,orientation:()=>r.orientation.value??`horizontal`,role:()=>`region`,style:()=>`touch-action:${p.value?`pan-y`:`pan-x`}`,variant:()=>r.variant.value??`default`},on:{focusin:()=>{stopAutoplay()},focusout:()=>{r.autoplay.value&&startAutoplay()},keydown:handleKeydown,pointerenter:()=>{stopAutoplay()},pointerleave:()=>{r.autoplay.value&&startAutoplay()}}}),(0,l.onMounted)(()=>{let e=(0,u.createPanGesture)(i,{axis:()=>p.value?`x`:`y`,onEnd:({distance:e,reason:t})=>{t!==`release`||Math.abs(e)<48||(e<0?next():prev())},shouldStart:e=>!e.composedPath().some(e=>e instanceof HTMLElement&&(e.tagName===`BUTTON`||e.tagName===`ORE-BUTTON`||e.tagName===`ORE-PROGRESS`))}),t=i.shadowRoot.querySelector(`slot`),onSlotChange=()=>{refreshSlides(),syncSlideVariants(),syncActiveState()};return t.addEventListener(`slotchange`,onSlotChange),r.autoplay.value&&startAutoplay(),()=>{e.dispose(),stopAutoplay(),t.removeEventListener(`slotchange`,onSlotChange)}});let renderControls=()=>h.value?l.html`
2
2
  <div class="controls" part="controls">
3
3
  <ore-button
4
4
  class="nav-btn prev-btn"
@@ -33,14 +33,14 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
33
33
  aria-hidden="true"></ore-icon>
34
34
  </ore-button>
35
35
  </div>
36
- `:c.html``;return c.html`
36
+ `:l.html``;return l.html`
37
37
  <div class="track" part="track" aria-live=${()=>r.autoplay.value?`off`:`polite`}>
38
38
  <slot></slot>
39
39
  </div>
40
40
 
41
- ${()=>g.value&&f.value>1?c.html`
41
+ ${()=>g.value&&f.value>1?l.html`
42
42
  <div class="indicators" part="indicators" role="tablist" aria-label="Slide indicators">
43
- ${()=>Array.from({length:f.value},(e,t)=>c.html`
43
+ ${()=>Array.from({length:f.value},(e,t)=>l.html`
44
44
  <button
45
45
  type="button"
46
46
  role="tab"
@@ -63,8 +63,8 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
63
63
  `)}
64
64
  ${renderControls}
65
65
  </div>
66
- `:c.html`
66
+ `:l.html`
67
67
  ${renderControls}
68
68
  `}
69
- `},styles:[i.default]}),exports.CAROUSEL_SLIDE_TAG=a.CAROUSEL_SLIDE_TAG,exports.CAROUSEL_TAG=u,exports.ICON_TAG=r.ICON_TAG,exports.PROGRESS_TAG=o.PROGRESS_TAG;
69
+ `},styles:[a.default]}),exports.CAROUSEL_ORIENTATIONS=d,exports.CAROUSEL_SLIDE_TAG=o.CAROUSEL_SLIDE_TAG,exports.CAROUSEL_TAG=p,exports.CAROUSEL_VARIANTS=f,exports.ICON_TAG=i.ICON_TAG,exports.PROGRESS_TAG=s.PROGRESS_TAG;
70
70
  //# sourceMappingURL=carousel.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"carousel.cjs","names":[],"sources":["../src/content/carousel/carousel.ts"],"sourcesContent":["import { createPanGesture } from '@vielzeug/gesture';\nimport { bind, define, getHost, html, onCleanup, onMounted, prop, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { announce, createListControl, lifecycleSignal } from '../../core';\nimport type { ThemeColor } from '../../types';\nimport componentStyles from './carousel.css?inline';\nimport './carousel-slide';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { PROGRESS_TAG } from '../../feedback/progress/progress';\nexport { CAROUSEL_SLIDE_TAG } from './carousel-slide';\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type CarouselOrientation = 'horizontal' | 'vertical';\nexport type CarouselVariant = 'default' | 'fade' | 'filmstrip' | 'gallery';\n\nexport type OreCarouselEvents = {\n /** Fired when the active slide changes. */\n change: { index: number };\n};\n\nexport type OreCarouselProps = {\n /**\n * Whether to advance slides automatically. Defaults to `false`.\n * Opt in explicitly: autoplay on by default is a WCAG 2.1 SC 2.2.2 violation for many use cases.\n */\n autoplay?: boolean;\n /** Interval in milliseconds between automatic slide advances. Defaults to `5000`. */\n 'autoplay-interval'?: number;\n /** Theme color passed to the prev/next navigation buttons. */\n color?: ThemeColor;\n /** Accessible label for the carousel region. */\n label?: string;\n /** Whether the carousel loops from the last slide back to the first. Defaults to `true`. */\n loop?: boolean;\n /** Carousel orientation. Defaults to `'horizontal'`. */\n orientation?: CarouselOrientation;\n /** Show next/prev navigation buttons. Defaults to `true`. */\n 'show-controls'?: boolean;\n /** Show dot/indicator navigation. Defaults to `true`. */\n 'show-indicators'?: boolean;\n /** Index of the currently active slide (zero-based). Defaults to `0`. */\n 'slide-index'?: number;\n /**\n * Layout variant.\n * - `'default'`: slides translate in/out (default)\n * - `'fade'`: slides crossfade; no movement\n * - `'filmstrip'`: all slides visible side-by-side; active expands\n * - `'gallery'`: active slide fills the majority; adjacent slides show as thumbnails\n */\n variant?: CarouselVariant;\n};\n\n/**\n * An accessible, keyboard-navigable carousel / slideshow with optional\n * autoplay, swipe support, and indicator dots.\n *\n * Place `<ore-carousel-slide>` elements as direct children.\n *\n * @element ore-carousel\n * @element ore-carousel-slide - Child element for individual slides\n *\n * @attr {string} color - Theme color for navigation buttons: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {boolean} autoplay - Advance slides automatically (default false)\n * @attr {number} autoplay-interval - Milliseconds between automatic advances (default 5000)\n * @attr {string} label - Accessible label for the carousel region\n * @attr {boolean} loop - Loop from last slide to first (default true)\n * @attr {string} orientation - 'horizontal' (default) | 'vertical'\n * @attr {string} variant - 'default' | 'fade' | 'filmstrip' | 'gallery'\n * @attr {boolean} show-controls - Show prev/next buttons (default true)\n * @attr {boolean} show-indicators - Show indicator dots (default true)\n * @attr {number} slide-index - Active slide index (zero-based, default 0)\n *\n * @fires change - Fires when the active slide changes. detail: { index: number }\n *\n * @slot - Place `<ore-carousel-slide>` elements here\n *\n * @cssprop --carousel-bg - Slide area background\n * @cssprop --carousel-radius - Border radius of the carousel\n * @cssprop --carousel-dot-bg - Inactive indicator color (default: var(--color-contrast-300))\n * @cssprop --carousel-dot-active-bg - Active indicator / fill color (default: var(--color-contrast-700))\n * @cssprop --carousel-transition-duration - Slide transition duration (default 0.35s; 0s under prefers-reduced-motion).\n * @cssprop --carousel-min-height - Minimum height when no explicit height is set (default 240px)\n * @cssprop --carousel-filmstrip-inactive - Width (horizontal) or height (vertical) of inactive slides in filmstrip mode\n * @cssprop --carousel-filmstrip-gap - Gap between slides in filmstrip mode\n * @cssprop --carousel-gallery-thumbnail - Width (horizontal) or height (vertical) of thumbnail slides in gallery mode (default var(--size-24))\n * @cssprop --carousel-gallery-gap - Gap between slides in gallery mode (default var(--size-2))\n *\n * @part track - The scrolling slide track element\n * @part controls - The prev/next button container\n * @part indicators - The indicator dots container\n * @part prev-btn - The previous-slide button\n * @part next-btn - The next-slide button\n *\n * @example\n * ```html\n * <ore-carousel label=\"Product highlights\" loop>\n * <ore-carousel-slide>Slide 1</ore-carousel-slide>\n * <ore-carousel-slide>Slide 2</ore-carousel-slide>\n * <ore-carousel-slide>Slide 3</ore-carousel-slide>\n * </ore-carousel>\n * ```\n */\nexport const CAROUSEL_TAG = 'ore-carousel' as const;\n\n// ── Slide-state sync helpers ──────────────────────────────────────────────────\n// Each function handles exactly one variant's attribute bookkeeping.\n// Called from a dispatch table in syncActiveState.\n\nconst syncDefaultSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.toggleAttribute('data-before', i < current);\n slide.toggleAttribute('data-after', i > current);\n });\n};\n\nconst syncFilmstripSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n });\n};\n\nconst syncGallerySlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n const isPrev = current > 0 && i === current - 1;\n const isNext = current < count - 1 && i === current + 1;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n slide.toggleAttribute('data-gallery-visible', active || isPrev || isNext);\n });\n};\n\n// ── ore-carousel ──────────────────────────────────────────────────────────────\n\ndefine<OreCarouselProps>(CAROUSEL_TAG, {\n props: {\n autoplay: prop.bool(false),\n 'autoplay-interval': prop.number(5000),\n color: prop.string<ThemeColor>(),\n label: prop.string('Carousel'),\n loop: prop.bool(true),\n orientation: prop.string<CarouselOrientation>('horizontal'),\n 'show-controls': prop.bool(true),\n 'show-indicators': prop.bool(true),\n 'slide-index': prop.number(0),\n variant: prop.string<CarouselVariant>('default'),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCarouselEvents>();\n\n // ── State ────────────────────────────────────────────────────────────────\n\n const activeIndex = signal<number>(props['slide-index'].value ?? 0);\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n\n // Slide cache: populated immediately, refreshed on slotchange.\n let slides: HTMLElement[] = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n const slideCount = signal(slides.length);\n\n const refreshSlides = (): void => {\n slides = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n slideCount.value = slides.length;\n };\n\n const isHorizontal = computed(() => props.orientation.value !== 'vertical');\n const looping = computed(() => props.loop.value !== false);\n const showControls = computed(() => props['show-controls'].value !== false);\n const showIndicators = computed(() => props['show-indicators'].value !== false);\n\n const canGoPrev = computed(() => looping.value || activeIndex.value > 0);\n const canGoNext = computed(() => looping.value || activeIndex.value < slideCount.value - 1);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n const goTo = (index: number, announce_: boolean = true): void => {\n const count = slideCount.value;\n\n if (count === 0) return;\n\n const next = looping.value ? ((index % count) + count) % count : Math.max(0, Math.min(index, count - 1));\n\n if (next === activeIndex.value) return;\n\n activeIndex.value = next;\n el.setAttribute('slide-index', String(next));\n emit('change', { index: next });\n\n if (announce_) {\n announce(slides[next]?.getAttribute('aria-label') ?? `Slide ${next + 1} of ${count}`, {\n document: el.ownerDocument,\n });\n }\n };\n\n const prev = (): void => goTo(activeIndex.value - 1);\n const next = (): void => goTo(activeIndex.value + 1);\n\n // ── Sync prop → state ────────────────────────────────────────────────────\n\n watch(props['slide-index'], (v) => {\n if (typeof v === 'number' && v !== activeIndex.value) goTo(v, false);\n });\n\n // ── Sync variant + orientation → slides ──────────────────────────────────\n\n const syncSlideVariants = (): void => {\n const variant = props.variant.value ?? 'default';\n const orientation = props.orientation.value ?? 'horizontal';\n\n slides.forEach((slide) => {\n slide.setAttribute('data-variant', variant);\n slide.setAttribute('data-orientation', orientation);\n });\n };\n\n watch(\n computed(() => ({ orientation: props.orientation.value, variant: props.variant.value })),\n syncSlideVariants,\n { immediate: true },\n );\n\n // ── Sync active index → slides: dispatch table ───────────────────────────\n\n const syncTable: Record<CarouselVariant, (slides: HTMLElement[], current: number) => void> = {\n default: syncDefaultSlides,\n fade: syncDefaultSlides,\n filmstrip: syncFilmstripSlides,\n gallery: syncGallerySlides,\n };\n\n const syncActiveState = (): void => {\n const variant = (props.variant.value ?? 'default') as CarouselVariant;\n\n syncTable[variant](slides, activeIndex.value);\n };\n\n watch(activeIndex, syncActiveState, { immediate: true });\n\n // ── Autoplay ─────────────────────────────────────────────────────────────\n\n const startAutoplay = (): void => {\n if (autoplayTimer !== null) return;\n\n autoplayTimer = setInterval(next, props['autoplay-interval'].value ?? 5000);\n };\n\n const stopAutoplay = (): void => {\n if (autoplayTimer !== null) {\n clearInterval(autoplayTimer);\n autoplayTimer = null;\n }\n };\n\n watch(\n computed(() => ({ enabled: props.autoplay.value, interval: props['autoplay-interval'].value })),\n ({ enabled }) => {\n stopAutoplay();\n\n if (enabled) startAutoplay();\n },\n );\n\n // ── Keyboard navigation ──────────────────────────────────────────────────\n\n const handleKeydown = (e: KeyboardEvent): void => {\n const isH = isHorizontal.value;\n const prevKey = isH ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isH ? 'ArrowRight' : 'ArrowDown';\n\n if (e.key === prevKey) {\n e.preventDefault();\n prev();\n } else if (e.key === nextKey) {\n e.preventDefault();\n next();\n } else if (e.key === 'Home') {\n e.preventDefault();\n goTo(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n goTo(slideCount.value - 1);\n }\n };\n\n const indicatorNav = createListControl<number>({\n getItems: () => Array.from({ length: slideCount.value }, (_, index) => index),\n loop: true,\n onNavigate: ({ index }) => {\n goTo(index);\n const dot = el.shadowRoot?.querySelector<HTMLElement>(`.indicator[data-index=\"${index}\"]`);\n\n dot?.focus();\n },\n orientation: () => (isHorizontal.value ? 'horizontal' : 'vertical'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-label': () => props.label.value ?? 'Carousel',\n 'aria-roledescription': () => 'carousel',\n orientation: () => props.orientation.value ?? 'horizontal',\n role: () => 'region',\n style: () => `touch-action:${isHorizontal.value ? 'pan-y' : 'pan-x'}`,\n variant: () => props.variant.value ?? 'default',\n },\n on: {\n focusin: () => {\n stopAutoplay();\n },\n focusout: () => {\n if (props.autoplay.value) startAutoplay();\n },\n keydown: handleKeydown,\n pointerenter: () => {\n stopAutoplay();\n },\n pointerleave: () => {\n if (props.autoplay.value) startAutoplay();\n },\n },\n });\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const pan = createPanGesture(el, {\n axis: () => (isHorizontal.value ? 'x' : 'y'),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) return;\n\n if (distance < 0) next();\n else prev();\n },\n shouldStart: (event) => {\n const path = event.composedPath();\n\n return !path.some(\n (node) =>\n node instanceof HTMLElement &&\n (node.tagName === 'BUTTON' || node.tagName === 'ORE-BUTTON' || node.tagName === 'ORE-PROGRESS'),\n );\n },\n });\n const shadowRoot = el.shadowRoot!;\n const slot = shadowRoot.querySelector<HTMLSlotElement>('slot')!;\n\n // slotchange replaces MutationObserver: fires exactly when assigned\n // nodes change, scoped to this component's slot, no polling overhead.\n const onSlotChange = (): void => {\n refreshSlides();\n syncSlideVariants();\n syncActiveState();\n };\n\n slot.addEventListener('slotchange', onSlotChange);\n\n if (props.autoplay.value) {\n startAutoplay();\n }\n\n return () => {\n pan.dispose();\n stopAutoplay();\n slot.removeEventListener('slotchange', onSlotChange);\n };\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n const renderControls = () =>\n showControls.value\n ? html`\n <div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n aria-label=\"Previous slide\"\n disabled=${() => (!canGoPrev.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n prev();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-left' : 'chevron-up')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n aria-label=\"Next slide\"\n disabled=${() => (!canGoNext.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n next();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-right' : 'chevron-down')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : html``;\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=${() => (props.autoplay.value ? 'off' : 'polite')}>\n <slot></slot>\n </div>\n\n ${() =>\n showIndicators.value && slideCount.value > 1\n ? html`\n <div class=\"indicators\" part=\"indicators\" role=\"tablist\" aria-label=\"Slide indicators\">\n ${() =>\n Array.from(\n { length: slideCount.value },\n (_, i) => html`\n <button\n type=\"button\"\n role=\"tab\"\n data-index=\"${i}\"\n class=${() => `indicator${i === activeIndex.value ? ' indicator-active' : ''}`}\n aria-selected=${() => String(i === activeIndex.value)}\n tabindex=${() => (i === activeIndex.value ? '0' : '-1')}\n aria-label=\"${`Go to slide ${i + 1}`}\"\n @focus=${() => indicatorNav.set(i)}\n @click=${() => goTo(i)}\n @keydown=${(e: KeyboardEvent) => {\n const target = e.currentTarget;\n\n if (target instanceof HTMLElement) {\n const index = Number(target.dataset.index);\n\n if (Number.isInteger(index)) indicatorNav.set(index);\n }\n\n indicatorNav.handleKeydown(e);\n }}>\n <ore-progress\n aria-hidden=\"true\"\n tabindex=\"-1\"\n color=${() => props.color.value}\n type=${() => (isHorizontal.value ? 'linear' : 'vertical')}\n value=${() => (i === activeIndex.value ? 100 : 0)}\n style=${() => {\n const fillAnim = isHorizontal.value ? 'carousel-fill' : 'carousel-fill-v';\n\n return `--carousel-timeout:${props['autoplay-interval'].value ?? 5000};--carousel-animation-name:${i === activeIndex.value && props.autoplay.value ? fillAnim : 'none'}`;\n }}></ore-progress>\n </button>\n `,\n )}\n ${renderControls}\n </div>\n `\n : html`\n ${renderControls}\n `}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"carousel.cjs","names":[],"sources":["../src/content/carousel/carousel.ts"],"sourcesContent":["import { createPanGesture } from '@vielzeug/gesture';\nimport { bind, define, getHost, html, onCleanup, onMounted, prop, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { announce, createListControl, lifecycleSignal } from '../../core';\nimport { THEME_COLORS, type ThemeColor } from '../../types';\nimport componentStyles from './carousel.css?inline';\nimport './carousel-slide';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { PROGRESS_TAG } from '../../feedback/progress/progress';\nexport { CAROUSEL_SLIDE_TAG } from './carousel-slide';\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport const CAROUSEL_ORIENTATIONS = ['horizontal', 'vertical'] as const;\nexport type CarouselOrientation = (typeof CAROUSEL_ORIENTATIONS)[number];\nexport const CAROUSEL_VARIANTS = ['default', 'fade', 'filmstrip', 'gallery'] as const;\nexport type CarouselVariant = (typeof CAROUSEL_VARIANTS)[number];\n\nexport type OreCarouselEvents = {\n /** Fired when the active slide changes. */\n change: { index: number };\n};\n\nexport type OreCarouselProps = {\n /**\n * Whether to advance slides automatically. Defaults to `false`.\n * Opt in explicitly: autoplay on by default is a WCAG 2.1 SC 2.2.2 violation for many use cases.\n */\n autoplay?: boolean;\n /** Interval in milliseconds between automatic slide advances. Defaults to `5000`. */\n 'autoplay-interval'?: number;\n /** Theme color passed to the prev/next navigation buttons. */\n color?: ThemeColor;\n /** Accessible label for the carousel region. */\n label?: string;\n /** Whether the carousel loops from the last slide back to the first. Defaults to `true`. */\n loop?: boolean;\n /** Carousel orientation. Defaults to `'horizontal'`. */\n orientation?: CarouselOrientation;\n /** Show next/prev navigation buttons. Defaults to `true`. */\n 'show-controls'?: boolean;\n /** Show dot/indicator navigation. Defaults to `true`. */\n 'show-indicators'?: boolean;\n /** Index of the currently active slide (zero-based). Defaults to `0`. */\n 'slide-index'?: number;\n /**\n * Layout variant.\n * - `'default'`: slides translate in/out (default)\n * - `'fade'`: slides crossfade; no movement\n * - `'filmstrip'`: all slides visible side-by-side; active expands\n * - `'gallery'`: active slide fills the majority; adjacent slides show as thumbnails\n */\n variant?: CarouselVariant;\n};\n\n/**\n * An accessible, keyboard-navigable carousel / slideshow with optional\n * autoplay, swipe support, and indicator dots.\n *\n * Place `<ore-carousel-slide>` elements as direct children.\n *\n * @element ore-carousel\n * @element ore-carousel-slide - Child element for individual slides\n *\n * @attr {string} color - Theme color for navigation buttons: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {boolean} autoplay - Advance slides automatically (default false)\n * @attr {number} autoplay-interval - Milliseconds between automatic advances (default 5000)\n * @attr {string} label - Accessible label for the carousel region\n * @attr {boolean} loop - Loop from last slide to first (default true)\n * @attr {string} orientation - 'horizontal' (default) | 'vertical'\n * @attr {string} variant - 'default' | 'fade' | 'filmstrip' | 'gallery'\n * @attr {boolean} show-controls - Show prev/next buttons (default true)\n * @attr {boolean} show-indicators - Show indicator dots (default true)\n * @attr {number} slide-index - Active slide index (zero-based, default 0)\n *\n * @fires change - Fires when the active slide changes. detail: { index: number }\n *\n * @slot - Place `<ore-carousel-slide>` elements here\n *\n * @cssprop --carousel-bg - Slide area background\n * @cssprop --carousel-radius - Border radius of the carousel\n * @cssprop --carousel-dot-bg - Inactive indicator color (default: var(--color-contrast-300))\n * @cssprop --carousel-dot-active-bg - Active indicator / fill color (default: var(--color-contrast-700))\n * @cssprop --carousel-transition-duration - Slide transition duration (default 0.35s; 0s under prefers-reduced-motion).\n * @cssprop --carousel-min-height - Minimum height when no explicit height is set (default 240px)\n * @cssprop --carousel-filmstrip-inactive - Width (horizontal) or height (vertical) of inactive slides in filmstrip mode\n * @cssprop --carousel-filmstrip-gap - Gap between slides in filmstrip mode\n * @cssprop --carousel-gallery-thumbnail - Width (horizontal) or height (vertical) of thumbnail slides in gallery mode (default var(--size-24))\n * @cssprop --carousel-gallery-gap - Gap between slides in gallery mode (default var(--size-2))\n *\n * @part track - The scrolling slide track element\n * @part controls - The prev/next button container\n * @part indicators - The indicator dots container\n * @part prev-btn - The previous-slide button\n * @part next-btn - The next-slide button\n *\n * @example\n * ```html\n * <ore-carousel label=\"Product highlights\" loop>\n * <ore-carousel-slide>Slide 1</ore-carousel-slide>\n * <ore-carousel-slide>Slide 2</ore-carousel-slide>\n * <ore-carousel-slide>Slide 3</ore-carousel-slide>\n * </ore-carousel>\n * ```\n */\nexport const CAROUSEL_TAG = 'ore-carousel' as const;\n\n// ── Slide-state sync helpers ──────────────────────────────────────────────────\n// Each function handles exactly one variant's attribute bookkeeping.\n// Called from a dispatch table in syncActiveState.\n\nconst syncDefaultSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.toggleAttribute('data-before', i < current);\n slide.toggleAttribute('data-after', i > current);\n });\n};\n\nconst syncFilmstripSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n });\n};\n\nconst syncGallerySlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n const isPrev = current > 0 && i === current - 1;\n const isNext = current < count - 1 && i === current + 1;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n slide.toggleAttribute('data-gallery-visible', active || isPrev || isNext);\n });\n};\n\n// ── ore-carousel ──────────────────────────────────────────────────────────────\n\ndefine<OreCarouselProps>(CAROUSEL_TAG, {\n props: {\n autoplay: prop.bool(false),\n 'autoplay-interval': prop.number(5000),\n color: prop.oneOf(THEME_COLORS),\n label: prop.string('Carousel'),\n loop: prop.bool(true),\n orientation: prop.oneOf(CAROUSEL_ORIENTATIONS, 'horizontal'),\n 'show-controls': prop.bool(true),\n 'show-indicators': prop.bool(true),\n 'slide-index': prop.number(0),\n variant: prop.oneOf(CAROUSEL_VARIANTS, 'default'),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCarouselEvents>();\n\n // ── State ────────────────────────────────────────────────────────────────\n\n const activeIndex = signal<number>(props['slide-index'].value ?? 0);\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n\n // Slide cache: populated immediately, refreshed on slotchange.\n let slides: HTMLElement[] = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n const slideCount = signal(slides.length);\n\n const refreshSlides = (): void => {\n slides = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n slideCount.value = slides.length;\n };\n\n const isHorizontal = computed(() => props.orientation.value !== 'vertical');\n const looping = computed(() => props.loop.value !== false);\n const showControls = computed(() => props['show-controls'].value !== false);\n const showIndicators = computed(() => props['show-indicators'].value !== false);\n\n const canGoPrev = computed(() => looping.value || activeIndex.value > 0);\n const canGoNext = computed(() => looping.value || activeIndex.value < slideCount.value - 1);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n const goTo = (index: number, announce_: boolean = true): void => {\n const count = slideCount.value;\n\n if (count === 0) return;\n\n const next = looping.value ? ((index % count) + count) % count : Math.max(0, Math.min(index, count - 1));\n\n if (next === activeIndex.value) return;\n\n activeIndex.value = next;\n el.setAttribute('slide-index', String(next));\n emit('change', { index: next });\n\n if (announce_) {\n announce(slides[next]?.getAttribute('aria-label') ?? `Slide ${next + 1} of ${count}`, {\n document: el.ownerDocument,\n });\n }\n };\n\n const prev = (): void => goTo(activeIndex.value - 1);\n const next = (): void => goTo(activeIndex.value + 1);\n\n // ── Sync prop → state ────────────────────────────────────────────────────\n\n watch(props['slide-index'], (v) => {\n if (typeof v === 'number' && v !== activeIndex.value) goTo(v, false);\n });\n\n // ── Sync variant + orientation → slides ──────────────────────────────────\n\n const syncSlideVariants = (): void => {\n const variant = props.variant.value ?? 'default';\n const orientation = props.orientation.value ?? 'horizontal';\n\n slides.forEach((slide) => {\n slide.setAttribute('data-variant', variant);\n slide.setAttribute('data-orientation', orientation);\n });\n };\n\n watch(\n computed(() => ({ orientation: props.orientation.value, variant: props.variant.value })),\n syncSlideVariants,\n { immediate: true },\n );\n\n // ── Sync active index → slides: dispatch table ───────────────────────────\n\n const syncTable: Record<CarouselVariant, (slides: HTMLElement[], current: number) => void> = {\n default: syncDefaultSlides,\n fade: syncDefaultSlides,\n filmstrip: syncFilmstripSlides,\n gallery: syncGallerySlides,\n };\n\n const syncActiveState = (): void => {\n const variant = (props.variant.value ?? 'default') as CarouselVariant;\n\n syncTable[variant](slides, activeIndex.value);\n };\n\n watch(activeIndex, syncActiveState, { immediate: true });\n\n // ── Autoplay ─────────────────────────────────────────────────────────────\n\n const startAutoplay = (): void => {\n if (autoplayTimer !== null) return;\n\n autoplayTimer = setInterval(next, props['autoplay-interval'].value ?? 5000);\n };\n\n const stopAutoplay = (): void => {\n if (autoplayTimer !== null) {\n clearInterval(autoplayTimer);\n autoplayTimer = null;\n }\n };\n\n watch(\n computed(() => ({ enabled: props.autoplay.value, interval: props['autoplay-interval'].value })),\n ({ enabled }) => {\n stopAutoplay();\n\n if (enabled) startAutoplay();\n },\n );\n\n // ── Keyboard navigation ──────────────────────────────────────────────────\n\n const handleKeydown = (e: KeyboardEvent): void => {\n const isH = isHorizontal.value;\n const prevKey = isH ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isH ? 'ArrowRight' : 'ArrowDown';\n\n if (e.key === prevKey) {\n e.preventDefault();\n prev();\n } else if (e.key === nextKey) {\n e.preventDefault();\n next();\n } else if (e.key === 'Home') {\n e.preventDefault();\n goTo(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n goTo(slideCount.value - 1);\n }\n };\n\n const indicatorNav = createListControl<number>({\n getItems: () => Array.from({ length: slideCount.value }, (_, index) => index),\n loop: true,\n onNavigate: ({ index }) => {\n goTo(index);\n const dot = el.shadowRoot?.querySelector<HTMLElement>(`.indicator[data-index=\"${index}\"]`);\n\n dot?.focus();\n },\n orientation: () => (isHorizontal.value ? 'horizontal' : 'vertical'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-label': () => props.label.value ?? 'Carousel',\n 'aria-roledescription': () => 'carousel',\n orientation: () => props.orientation.value ?? 'horizontal',\n role: () => 'region',\n style: () => `touch-action:${isHorizontal.value ? 'pan-y' : 'pan-x'}`,\n variant: () => props.variant.value ?? 'default',\n },\n on: {\n focusin: () => {\n stopAutoplay();\n },\n focusout: () => {\n if (props.autoplay.value) startAutoplay();\n },\n keydown: handleKeydown,\n pointerenter: () => {\n stopAutoplay();\n },\n pointerleave: () => {\n if (props.autoplay.value) startAutoplay();\n },\n },\n });\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const pan = createPanGesture(el, {\n axis: () => (isHorizontal.value ? 'x' : 'y'),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) return;\n\n if (distance < 0) next();\n else prev();\n },\n shouldStart: (event) => {\n const path = event.composedPath();\n\n return !path.some(\n (node) =>\n node instanceof HTMLElement &&\n (node.tagName === 'BUTTON' || node.tagName === 'ORE-BUTTON' || node.tagName === 'ORE-PROGRESS'),\n );\n },\n });\n const shadowRoot = el.shadowRoot!;\n const slot = shadowRoot.querySelector<HTMLSlotElement>('slot')!;\n\n // slotchange replaces MutationObserver: fires exactly when assigned\n // nodes change, scoped to this component's slot, no polling overhead.\n const onSlotChange = (): void => {\n refreshSlides();\n syncSlideVariants();\n syncActiveState();\n };\n\n slot.addEventListener('slotchange', onSlotChange);\n\n if (props.autoplay.value) {\n startAutoplay();\n }\n\n return () => {\n pan.dispose();\n stopAutoplay();\n slot.removeEventListener('slotchange', onSlotChange);\n };\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n const renderControls = () =>\n showControls.value\n ? html`\n <div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n aria-label=\"Previous slide\"\n disabled=${() => (!canGoPrev.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n prev();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-left' : 'chevron-up')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n aria-label=\"Next slide\"\n disabled=${() => (!canGoNext.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n next();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-right' : 'chevron-down')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : html``;\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=${() => (props.autoplay.value ? 'off' : 'polite')}>\n <slot></slot>\n </div>\n\n ${() =>\n showIndicators.value && slideCount.value > 1\n ? html`\n <div class=\"indicators\" part=\"indicators\" role=\"tablist\" aria-label=\"Slide indicators\">\n ${() =>\n Array.from(\n { length: slideCount.value },\n (_, i) => html`\n <button\n type=\"button\"\n role=\"tab\"\n data-index=\"${i}\"\n class=${() => `indicator${i === activeIndex.value ? ' indicator-active' : ''}`}\n aria-selected=${() => String(i === activeIndex.value)}\n tabindex=${() => (i === activeIndex.value ? '0' : '-1')}\n aria-label=\"${`Go to slide ${i + 1}`}\"\n @focus=${() => indicatorNav.set(i)}\n @click=${() => goTo(i)}\n @keydown=${(e: KeyboardEvent) => {\n const target = e.currentTarget;\n\n if (target instanceof HTMLElement) {\n const index = Number(target.dataset.index);\n\n if (Number.isInteger(index)) indicatorNav.set(index);\n }\n\n indicatorNav.handleKeydown(e);\n }}>\n <ore-progress\n aria-hidden=\"true\"\n tabindex=\"-1\"\n color=${() => props.color.value}\n type=${() => (isHorizontal.value ? 'linear' : 'vertical')}\n value=${() => (i === activeIndex.value ? 100 : 0)}\n style=${() => {\n const fillAnim = isHorizontal.value ? 'carousel-fill' : 'carousel-fill-v';\n\n return `--carousel-timeout:${props['autoplay-interval'].value ?? 5000};--carousel-animation-name:${i === activeIndex.value && props.autoplay.value ? fillAnim : 'none'}`;\n }}></ore-progress>\n </button>\n `,\n )}\n ${renderControls}\n </div>\n `\n : html`\n ${renderControls}\n `}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
package/dist/carousel.js CHANGED
@@ -1,4 +1,4 @@
1
- import{announce as e}from"./core/announcer.js";import{lifecycleSignal as t}from"./core/ore.js";import{createListControl as n}from"./core/nav.js";import{ICON_TAG as r}from"./icon.js";import i from"./content/carousel/carousel.css.js";import{CAROUSEL_SLIDE_TAG as a}from"./content/carousel/carousel-slide.js";import{PROGRESS_TAG as o}from"./progress.js";import{computed as s,signal as c,watch as l}from"@vielzeug/ripple";import{bind as u,define as d,getHost as f,html as p,onCleanup as m,onMounted as h,prop as g,useEmit as _}from"@vielzeug/ore";import{createPanGesture as v}from"@vielzeug/gesture";var y=`ore-carousel`,syncDefaultSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.toggleAttribute(`data-before`,r<t),e.toggleAttribute(`data-after`,r>t)})},syncFilmstripSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`)})},syncGallerySlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t,a=t>0&&r===t-1,o=t<n-1&&r===t+1;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`),e.toggleAttribute(`data-gallery-visible`,i||a||o)})};d(y,{props:{autoplay:g.bool(!1),"autoplay-interval":g.number(5e3),color:g.string(),label:g.string(`Carousel`),loop:g.bool(!0),orientation:g.string(`horizontal`),"show-controls":g.bool(!0),"show-indicators":g.bool(!0),"slide-index":g.number(0),variant:g.string(`default`)},setup(r){let i=f(),a=_(),o=c(r[`slide-index`].value??0),d=null,g=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),y=c(g.length),refreshSlides=()=>{g=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),y.value=g.length},b=s(()=>r.orientation.value!==`vertical`),x=s(()=>r.loop.value!==!1),S=s(()=>r[`show-controls`].value!==!1),C=s(()=>r[`show-indicators`].value!==!1),w=s(()=>x.value||o.value>0),T=s(()=>x.value||o.value<y.value-1),goTo=(t,n=!0)=>{let r=y.value;if(r===0)return;let s=x.value?(t%r+r)%r:Math.max(0,Math.min(t,r-1));s!==o.value&&(o.value=s,i.setAttribute(`slide-index`,String(s)),a(`change`,{index:s}),n&&e(g[s]?.getAttribute(`aria-label`)??`Slide ${s+1} of ${r}`,{document:i.ownerDocument}))},prev=()=>goTo(o.value-1),next=()=>goTo(o.value+1);l(r[`slide-index`],e=>{typeof e==`number`&&e!==o.value&&goTo(e,!1)});let syncSlideVariants=()=>{let e=r.variant.value??`default`,t=r.orientation.value??`horizontal`;g.forEach(n=>{n.setAttribute(`data-variant`,e),n.setAttribute(`data-orientation`,t)})};l(s(()=>({orientation:r.orientation.value,variant:r.variant.value})),syncSlideVariants,{immediate:!0});let E={default:syncDefaultSlides,fade:syncDefaultSlides,filmstrip:syncFilmstripSlides,gallery:syncGallerySlides},syncActiveState=()=>{let e=r.variant.value??`default`;E[e](g,o.value)};l(o,syncActiveState,{immediate:!0});let startAutoplay=()=>{d===null&&(d=setInterval(next,r[`autoplay-interval`].value??5e3))},stopAutoplay=()=>{d!==null&&(clearInterval(d),d=null)};l(s(()=>({enabled:r.autoplay.value,interval:r[`autoplay-interval`].value})),({enabled:e})=>{stopAutoplay(),e&&startAutoplay()});let handleKeydown=e=>{let t=b.value,n=t?`ArrowLeft`:`ArrowUp`,r=t?`ArrowRight`:`ArrowDown`;e.key===n?(e.preventDefault(),prev()):e.key===r?(e.preventDefault(),next()):e.key===`Home`?(e.preventDefault(),goTo(0)):e.key===`End`&&(e.preventDefault(),goTo(y.value-1))},D=n({getItems:()=>Array.from({length:y.value},(e,t)=>t),loop:!0,onNavigate:({index:e})=>{goTo(e),(i.shadowRoot?.querySelector(`.indicator[data-index="${e}"]`))?.focus()},orientation:()=>b.value?`horizontal`:`vertical`,signal:t(m)});u({attr:{"aria-label":()=>r.label.value??`Carousel`,"aria-roledescription":()=>`carousel`,orientation:()=>r.orientation.value??`horizontal`,role:()=>`region`,style:()=>`touch-action:${b.value?`pan-y`:`pan-x`}`,variant:()=>r.variant.value??`default`},on:{focusin:()=>{stopAutoplay()},focusout:()=>{r.autoplay.value&&startAutoplay()},keydown:handleKeydown,pointerenter:()=>{stopAutoplay()},pointerleave:()=>{r.autoplay.value&&startAutoplay()}}}),h(()=>{let e=v(i,{axis:()=>b.value?`x`:`y`,onEnd:({distance:e,reason:t})=>{t!==`release`||Math.abs(e)<48||(e<0?next():prev())},shouldStart:e=>!e.composedPath().some(e=>e instanceof HTMLElement&&(e.tagName===`BUTTON`||e.tagName===`ORE-BUTTON`||e.tagName===`ORE-PROGRESS`))}),t=i.shadowRoot.querySelector(`slot`),onSlotChange=()=>{refreshSlides(),syncSlideVariants(),syncActiveState()};return t.addEventListener(`slotchange`,onSlotChange),r.autoplay.value&&startAutoplay(),()=>{e.dispose(),stopAutoplay(),t.removeEventListener(`slotchange`,onSlotChange)}});let renderControls=()=>S.value?p`
1
+ import{announce as e}from"./core/announcer.js";import{lifecycleSignal as t}from"./core/ore.js";import{createListControl as n}from"./core/nav.js";import{THEME_COLORS as r}from"./shared/types.js";import{ICON_TAG as i}from"./icon.js";import a from"./content/carousel/carousel.css.js";import{CAROUSEL_SLIDE_TAG as o}from"./content/carousel/carousel-slide.js";import{PROGRESS_TAG as s}from"./progress.js";import{computed as c,signal as l,watch as u}from"@vielzeug/ripple";import{bind as d,define as f,getHost as p,html as m,onCleanup as h,onMounted as g,prop as _,useEmit as v}from"@vielzeug/ore";import{createPanGesture as y}from"@vielzeug/gesture";var b=[`horizontal`,`vertical`],x=[`default`,`fade`,`filmstrip`,`gallery`],S=`ore-carousel`,syncDefaultSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.toggleAttribute(`data-before`,r<t),e.toggleAttribute(`data-after`,r>t)})},syncFilmstripSlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-gallery-visible`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`)})},syncGallerySlides=(e,t)=>{let n=e.length;e.forEach((e,r)=>{let i=r===t,a=t>0&&r===t-1,o=t<n-1&&r===t+1;e.toggleAttribute(`data-active`,i),e.setAttribute(`aria-hidden`,String(!i)),e.setAttribute(`aria-label`,e.getAttribute(`aria-label`)??`Slide ${r+1} of ${n}`),e.removeAttribute(`data-before`),e.removeAttribute(`data-after`),e.toggleAttribute(`data-gallery-visible`,i||a||o)})};f(S,{props:{autoplay:_.bool(!1),"autoplay-interval":_.number(5e3),color:_.oneOf(r),label:_.string(`Carousel`),loop:_.bool(!0),orientation:_.oneOf(b,`horizontal`),"show-controls":_.bool(!0),"show-indicators":_.bool(!0),"slide-index":_.number(0),variant:_.oneOf(x,`default`)},setup(r){let i=p(),a=v(),o=l(r[`slide-index`].value??0),s=null,f=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),_=l(f.length),refreshSlides=()=>{f=Array.from(i.querySelectorAll(`:scope > ore-carousel-slide`)),_.value=f.length},b=c(()=>r.orientation.value!==`vertical`),x=c(()=>r.loop.value!==!1),S=c(()=>r[`show-controls`].value!==!1),C=c(()=>r[`show-indicators`].value!==!1),w=c(()=>x.value||o.value>0),T=c(()=>x.value||o.value<_.value-1),goTo=(t,n=!0)=>{let r=_.value;if(r===0)return;let s=x.value?(t%r+r)%r:Math.max(0,Math.min(t,r-1));s!==o.value&&(o.value=s,i.setAttribute(`slide-index`,String(s)),a(`change`,{index:s}),n&&e(f[s]?.getAttribute(`aria-label`)??`Slide ${s+1} of ${r}`,{document:i.ownerDocument}))},prev=()=>goTo(o.value-1),next=()=>goTo(o.value+1);u(r[`slide-index`],e=>{typeof e==`number`&&e!==o.value&&goTo(e,!1)});let syncSlideVariants=()=>{let e=r.variant.value??`default`,t=r.orientation.value??`horizontal`;f.forEach(n=>{n.setAttribute(`data-variant`,e),n.setAttribute(`data-orientation`,t)})};u(c(()=>({orientation:r.orientation.value,variant:r.variant.value})),syncSlideVariants,{immediate:!0});let E={default:syncDefaultSlides,fade:syncDefaultSlides,filmstrip:syncFilmstripSlides,gallery:syncGallerySlides},syncActiveState=()=>{let e=r.variant.value??`default`;E[e](f,o.value)};u(o,syncActiveState,{immediate:!0});let startAutoplay=()=>{s===null&&(s=setInterval(next,r[`autoplay-interval`].value??5e3))},stopAutoplay=()=>{s!==null&&(clearInterval(s),s=null)};u(c(()=>({enabled:r.autoplay.value,interval:r[`autoplay-interval`].value})),({enabled:e})=>{stopAutoplay(),e&&startAutoplay()});let handleKeydown=e=>{let t=b.value,n=t?`ArrowLeft`:`ArrowUp`,r=t?`ArrowRight`:`ArrowDown`;e.key===n?(e.preventDefault(),prev()):e.key===r?(e.preventDefault(),next()):e.key===`Home`?(e.preventDefault(),goTo(0)):e.key===`End`&&(e.preventDefault(),goTo(_.value-1))},D=n({getItems:()=>Array.from({length:_.value},(e,t)=>t),loop:!0,onNavigate:({index:e})=>{goTo(e),(i.shadowRoot?.querySelector(`.indicator[data-index="${e}"]`))?.focus()},orientation:()=>b.value?`horizontal`:`vertical`,signal:t(h)});d({attr:{"aria-label":()=>r.label.value??`Carousel`,"aria-roledescription":()=>`carousel`,orientation:()=>r.orientation.value??`horizontal`,role:()=>`region`,style:()=>`touch-action:${b.value?`pan-y`:`pan-x`}`,variant:()=>r.variant.value??`default`},on:{focusin:()=>{stopAutoplay()},focusout:()=>{r.autoplay.value&&startAutoplay()},keydown:handleKeydown,pointerenter:()=>{stopAutoplay()},pointerleave:()=>{r.autoplay.value&&startAutoplay()}}}),g(()=>{let e=y(i,{axis:()=>b.value?`x`:`y`,onEnd:({distance:e,reason:t})=>{t!==`release`||Math.abs(e)<48||(e<0?next():prev())},shouldStart:e=>!e.composedPath().some(e=>e instanceof HTMLElement&&(e.tagName===`BUTTON`||e.tagName===`ORE-BUTTON`||e.tagName===`ORE-PROGRESS`))}),t=i.shadowRoot.querySelector(`slot`),onSlotChange=()=>{refreshSlides(),syncSlideVariants(),syncActiveState()};return t.addEventListener(`slotchange`,onSlotChange),r.autoplay.value&&startAutoplay(),()=>{e.dispose(),stopAutoplay(),t.removeEventListener(`slotchange`,onSlotChange)}});let renderControls=()=>S.value?m`
2
2
  <div class="controls" part="controls">
3
3
  <ore-button
4
4
  class="nav-btn prev-btn"
@@ -33,14 +33,14 @@ import{announce as e}from"./core/announcer.js";import{lifecycleSignal as t}from"
33
33
  aria-hidden="true"></ore-icon>
34
34
  </ore-button>
35
35
  </div>
36
- `:p``;return p`
36
+ `:m``;return m`
37
37
  <div class="track" part="track" aria-live=${()=>r.autoplay.value?`off`:`polite`}>
38
38
  <slot></slot>
39
39
  </div>
40
40
 
41
- ${()=>C.value&&y.value>1?p`
41
+ ${()=>C.value&&_.value>1?m`
42
42
  <div class="indicators" part="indicators" role="tablist" aria-label="Slide indicators">
43
- ${()=>Array.from({length:y.value},(e,t)=>p`
43
+ ${()=>Array.from({length:_.value},(e,t)=>m`
44
44
  <button
45
45
  type="button"
46
46
  role="tab"
@@ -63,8 +63,8 @@ import{announce as e}from"./core/announcer.js";import{lifecycleSignal as t}from"
63
63
  `)}
64
64
  ${renderControls}
65
65
  </div>
66
- `:p`
66
+ `:m`
67
67
  ${renderControls}
68
68
  `}
69
- `},styles:[i]});export{a as CAROUSEL_SLIDE_TAG,y as CAROUSEL_TAG,r as ICON_TAG,o as PROGRESS_TAG};
69
+ `},styles:[a]});export{b as CAROUSEL_ORIENTATIONS,o as CAROUSEL_SLIDE_TAG,S as CAROUSEL_TAG,x as CAROUSEL_VARIANTS,i as ICON_TAG,s as PROGRESS_TAG};
70
70
  //# sourceMappingURL=carousel.js.map