@birdycom/omniaui-vue 0.0.0-stage → 0.11.0

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 (364) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -2
  3. package/dist/blocks/OcBlockAboutTimeline.vue.d.ts +29 -0
  4. package/dist/blocks/OcBlockAppHeader.vue.d.ts +33 -0
  5. package/dist/blocks/OcBlockAppShell.vue.d.ts +33 -0
  6. package/dist/blocks/OcBlockAuth.vue.d.ts +28 -0
  7. package/dist/blocks/OcBlockAuthSplit.vue.d.ts +45 -0
  8. package/dist/blocks/OcBlockContactGrid.vue.d.ts +32 -0
  9. package/dist/blocks/OcBlockCta.vue.d.ts +17 -0
  10. package/dist/blocks/OcBlockDataTable.vue.d.ts +33 -0
  11. package/dist/blocks/OcBlockFaq.vue.d.ts +32 -0
  12. package/dist/blocks/OcBlockFeatures.vue.d.ts +25 -0
  13. package/dist/blocks/OcBlockFooter.vue.d.ts +27 -0
  14. package/dist/blocks/OcBlockFormPage.vue.d.ts +36 -0
  15. package/dist/blocks/OcBlockHero.vue.d.ts +18 -0
  16. package/dist/blocks/OcBlockHeroCode.vue.d.ts +32 -0
  17. package/dist/blocks/OcBlockHeroOrbit.vue.d.ts +36 -0
  18. package/dist/blocks/OcBlockHeroSplit.vue.d.ts +19 -0
  19. package/dist/blocks/OcBlockModuleHeader.vue.d.ts +24 -0
  20. package/dist/blocks/OcBlockPageHero.vue.d.ts +18 -0
  21. package/dist/blocks/OcBlockPortfolioGrid.vue.d.ts +34 -0
  22. package/dist/blocks/OcBlockPricing.vue.d.ts +38 -0
  23. package/dist/blocks/OcBlockProcess.vue.d.ts +18 -0
  24. package/dist/blocks/OcBlockProductGrid.vue.d.ts +25 -0
  25. package/dist/blocks/OcBlockProfileHeader.vue.d.ts +36 -0
  26. package/dist/blocks/OcBlockShowcase.vue.d.ts +23 -0
  27. package/dist/blocks/OcBlockSiteFooter.vue.d.ts +42 -0
  28. package/dist/blocks/OcBlockSiteHeader.vue.d.ts +32 -0
  29. package/dist/blocks/OcBlockSpotlight.vue.d.ts +32 -0
  30. package/dist/blocks/OcBlockStats.vue.d.ts +10 -0
  31. package/dist/blocks/OcBlockStatsCounter.vue.d.ts +10 -0
  32. package/dist/blocks/OcBlockTeamList.vue.d.ts +42 -0
  33. package/dist/blocks/OcBlockTwoFactor.vue.d.ts +38 -0
  34. package/dist/blocks/OcBlockWizardDialog.vue.d.ts +52 -0
  35. package/dist/components/OcAccordion.vue.d.ts +15 -0
  36. package/dist/components/OcAccordionAccent.vue.d.ts +20 -0
  37. package/dist/components/OcAccordionItem.vue.d.ts +24 -0
  38. package/dist/components/OcAffixInput.vue.d.ts +31 -0
  39. package/dist/components/OcAlert.vue.d.ts +21 -0
  40. package/dist/components/OcAlertDialog.vue.d.ts +48 -0
  41. package/dist/components/OcAlphaTabs.vue.d.ts +23 -0
  42. package/dist/components/OcAspectRatio.vue.d.ts +16 -0
  43. package/dist/components/OcAttachment.vue.d.ts +26 -0
  44. package/dist/components/OcAttachmentImage.vue.d.ts +10 -0
  45. package/dist/components/OcAttachmentList.vue.d.ts +31 -0
  46. package/dist/components/OcAttachmentThumb.vue.d.ts +16 -0
  47. package/dist/components/OcAvatar.vue.d.ts +21 -0
  48. package/dist/components/OcAvatarGroup.vue.d.ts +12 -0
  49. package/dist/components/OcBackLink.vue.d.ts +18 -0
  50. package/dist/components/OcBadge.vue.d.ts +18 -0
  51. package/dist/components/OcBarcodeInput.vue.d.ts +27 -0
  52. package/dist/components/OcBreadcrumb.vue.d.ts +24 -0
  53. package/dist/components/OcBrowserFrame.vue.d.ts +35 -0
  54. package/dist/components/OcBusyOverlay.vue.d.ts +30 -0
  55. package/dist/components/OcButton.vue.d.ts +31 -0
  56. package/dist/components/OcButtonGroup.vue.d.ts +17 -0
  57. package/dist/components/OcButtonGroupText.vue.d.ts +12 -0
  58. package/dist/components/OcCard.vue.d.ts +27 -0
  59. package/dist/components/OcChartLine.vue.d.ts +28 -0
  60. package/dist/components/OcChatComposer.vue.d.ts +33 -0
  61. package/dist/components/OcCheckbox.vue.d.ts +26 -0
  62. package/dist/components/OcChecklist.vue.d.ts +32 -0
  63. package/dist/components/OcChipFilter.vue.d.ts +24 -0
  64. package/dist/components/OcCollapsible.vue.d.ts +28 -0
  65. package/dist/components/OcColorField.vue.d.ts +17 -0
  66. package/dist/components/OcColorSelect.vue.d.ts +24 -0
  67. package/dist/components/OcColumnMenu.vue.d.ts +31 -0
  68. package/dist/components/OcCommand.vue.d.ts +28 -0
  69. package/dist/components/OcConfirmDialog.vue.d.ts +44 -0
  70. package/dist/components/OcCookieConsent.vue.d.ts +52 -0
  71. package/dist/components/OcCopyField.vue.d.ts +14 -0
  72. package/dist/components/OcCounter.vue.d.ts +9 -0
  73. package/dist/components/OcDataTable.vue.d.ts +37 -0
  74. package/dist/components/OcDecimalInput.vue.d.ts +19 -0
  75. package/dist/components/OcDefinitionList.vue.d.ts +34 -0
  76. package/dist/components/OcDocViewer.vue.d.ts +24 -0
  77. package/dist/components/OcDropdown.vue.d.ts +19 -0
  78. package/dist/components/OcDropdownItem.vue.d.ts +18 -0
  79. package/dist/components/OcDropdownLabel.vue.d.ts +12 -0
  80. package/dist/components/OcDropdownSeparator.vue.d.ts +2 -0
  81. package/dist/components/OcDropzone.vue.d.ts +29 -0
  82. package/dist/components/OcEmojiPicker.vue.d.ts +32 -0
  83. package/dist/components/OcEmptyState.vue.d.ts +24 -0
  84. package/dist/components/OcEntityCard.vue.d.ts +37 -0
  85. package/dist/components/OcFactList.vue.d.ts +29 -0
  86. package/dist/components/OcFilterCounts.vue.d.ts +25 -0
  87. package/dist/components/OcFlipCard.vue.d.ts +31 -0
  88. package/dist/components/OcFormField.vue.d.ts +26 -0
  89. package/dist/components/OcGreeting.vue.d.ts +26 -0
  90. package/dist/components/OcHeading.vue.d.ts +24 -0
  91. package/dist/components/OcHoverCard.vue.d.ts +22 -0
  92. package/dist/components/OcImageZoom.vue.d.ts +28 -0
  93. package/dist/components/OcInput.vue.d.ts +13 -0
  94. package/dist/components/OcInputGroup.vue.d.ts +21 -0
  95. package/dist/components/OcItem.vue.d.ts +39 -0
  96. package/dist/components/OcItemGroup.vue.d.ts +12 -0
  97. package/dist/components/OcItemSeparator.vue.d.ts +2 -0
  98. package/dist/components/OcKbd.vue.d.ts +12 -0
  99. package/dist/components/OcKbdGroup.vue.d.ts +17 -0
  100. package/dist/components/OcLabel.vue.d.ts +19 -0
  101. package/dist/components/OcLanguageSelect.vue.d.ts +32 -0
  102. package/dist/components/OcLauncherCard.vue.d.ts +26 -0
  103. package/dist/components/OcLightbox.vue.d.ts +45 -0
  104. package/dist/components/OcLinkArrow.vue.d.ts +23 -0
  105. package/dist/components/OcListToolbar.vue.d.ts +44 -0
  106. package/dist/components/OcMarquee.vue.d.ts +16 -0
  107. package/dist/components/OcMediaCard.vue.d.ts +24 -0
  108. package/dist/components/OcMediaRow.vue.d.ts +21 -0
  109. package/dist/components/OcMediaThumb.vue.d.ts +32 -0
  110. package/dist/components/OcMessage.vue.d.ts +63 -0
  111. package/dist/components/OcMessageList.vue.d.ts +35 -0
  112. package/dist/components/OcMessageThread.vue.d.ts +80 -0
  113. package/dist/components/OcModal.vue.d.ts +36 -0
  114. package/dist/components/OcNavmenu.vue.d.ts +24 -0
  115. package/dist/components/OcNavmenuList.vue.d.ts +29 -0
  116. package/dist/components/OcNextTeaser.vue.d.ts +29 -0
  117. package/dist/components/OcNumberInput.vue.d.ts +25 -0
  118. package/dist/components/OcOtpInput.vue.d.ts +19 -0
  119. package/dist/components/OcPageHeader.vue.d.ts +36 -0
  120. package/dist/components/OcPagination.vue.d.ts +20 -0
  121. package/dist/components/OcPasswordInput.vue.d.ts +18 -0
  122. package/dist/components/OcPasswordRequirements.vue.d.ts +19 -0
  123. package/dist/components/OcPhoneInput.vue.d.ts +25 -0
  124. package/dist/components/OcPopover.vue.d.ts +24 -0
  125. package/dist/components/OcPriceCard.vue.d.ts +41 -0
  126. package/dist/components/OcProductMark.vue.d.ts +25 -0
  127. package/dist/components/OcProgress.vue.d.ts +11 -0
  128. package/dist/components/OcProjectCard.vue.d.ts +35 -0
  129. package/dist/components/OcProse.vue.d.ts +25 -0
  130. package/dist/components/OcRadio.vue.d.ts +27 -0
  131. package/dist/components/OcRadioGroup.vue.d.ts +32 -0
  132. package/dist/components/OcRecoveryCodes.vue.d.ts +36 -0
  133. package/dist/components/OcScrollArea.vue.d.ts +18 -0
  134. package/dist/components/OcSegmented.vue.d.ts +21 -0
  135. package/dist/components/OcSelect.vue.d.ts +28 -0
  136. package/dist/components/OcSeparator.vue.d.ts +21 -0
  137. package/dist/components/OcSeverityCard.vue.d.ts +36 -0
  138. package/dist/components/OcSheet.vue.d.ts +37 -0
  139. package/dist/components/OcSidebar.vue.d.ts +28 -0
  140. package/dist/components/OcSidebarCollapsible.vue.d.ts +27 -0
  141. package/dist/components/OcSidebarGroup.vue.d.ts +16 -0
  142. package/dist/components/OcSidebarMenu.vue.d.ts +12 -0
  143. package/dist/components/OcSidebarMenuButton.vue.d.ts +21 -0
  144. package/dist/components/OcSidebarSeparator.vue.d.ts +2 -0
  145. package/dist/components/OcSkeleton.vue.d.ts +8 -0
  146. package/dist/components/OcSlider.vue.d.ts +18 -0
  147. package/dist/components/OcSortableRow.vue.d.ts +32 -0
  148. package/dist/components/OcSpinner.vue.d.ts +8 -0
  149. package/dist/components/OcStackCard.vue.d.ts +22 -0
  150. package/dist/components/OcStackList.vue.d.ts +28 -0
  151. package/dist/components/OcStatCard.vue.d.ts +25 -0
  152. package/dist/components/OcStepper.vue.d.ts +24 -0
  153. package/dist/components/OcSwitch.vue.d.ts +9 -0
  154. package/dist/components/OcTable.vue.d.ts +61 -0
  155. package/dist/components/OcTableActions.vue.d.ts +18 -0
  156. package/dist/components/OcTableCompact.vue.d.ts +37 -0
  157. package/dist/components/OcTabs.vue.d.ts +28 -0
  158. package/dist/components/OcTagInput.vue.d.ts +18 -0
  159. package/dist/components/OcTerminalLog.vue.d.ts +20 -0
  160. package/dist/components/OcTextarea.vue.d.ts +13 -0
  161. package/dist/components/OcThemeSwitch.vue.d.ts +20 -0
  162. package/dist/components/OcTimeInput.vue.d.ts +14 -0
  163. package/dist/components/OcTimeline.vue.d.ts +33 -0
  164. package/dist/components/OcToast.vue.d.ts +31 -0
  165. package/dist/components/OcToastContainer.vue.d.ts +8 -0
  166. package/dist/components/OcToggle.vue.d.ts +29 -0
  167. package/dist/components/OcToggleField.vue.d.ts +27 -0
  168. package/dist/components/OcToggleGroup.vue.d.ts +27 -0
  169. package/dist/components/OcTooltip.vue.d.ts +16 -0
  170. package/dist/components/OcTopProgress.vue.d.ts +18 -0
  171. package/dist/components/OcTree.vue.d.ts +40 -0
  172. package/dist/components/OcUpgradeBanner.vue.d.ts +41 -0
  173. package/dist/components/OcUser.vue.d.ts +20 -0
  174. package/dist/components/OcVersionBanner.vue.d.ts +32 -0
  175. package/dist/composables/chartLine.d.ts +6 -0
  176. package/dist/composables/keys.d.ts +19 -0
  177. package/dist/composables/useAttrsSplit.d.ts +14 -0
  178. package/dist/composables/useDialog.d.ts +9 -0
  179. package/dist/composables/useToast.d.ts +34 -0
  180. package/dist/composables/useUid.d.ts +5 -0
  181. package/dist/index.d.ts +233 -0
  182. package/dist/omniaui-vue.js +8811 -0
  183. package/dist/omniaui-vue.js.map +1 -0
  184. package/manifest.json +1036 -0
  185. package/package.json +67 -4
  186. package/src/blocks/OcBlockAboutTimeline.vue +44 -0
  187. package/src/blocks/OcBlockAppHeader.vue +36 -0
  188. package/src/blocks/OcBlockAppShell.vue +29 -0
  189. package/src/blocks/OcBlockAuth.vue +24 -0
  190. package/src/blocks/OcBlockAuthSplit.vue +47 -0
  191. package/src/blocks/OcBlockContactGrid.vue +53 -0
  192. package/src/blocks/OcBlockCta.vue +12 -0
  193. package/src/blocks/OcBlockDataTable.vue +27 -0
  194. package/src/blocks/OcBlockFaq.vue +49 -0
  195. package/src/blocks/OcBlockFeatures.vue +23 -0
  196. package/src/blocks/OcBlockFooter.vue +25 -0
  197. package/src/blocks/OcBlockFormPage.vue +24 -0
  198. package/src/blocks/OcBlockHero.vue +13 -0
  199. package/src/blocks/OcBlockHeroCode.vue +42 -0
  200. package/src/blocks/OcBlockHeroOrbit.vue +69 -0
  201. package/src/blocks/OcBlockHeroSplit.vue +15 -0
  202. package/src/blocks/OcBlockModuleHeader.vue +21 -0
  203. package/src/blocks/OcBlockPageHero.vue +13 -0
  204. package/src/blocks/OcBlockPortfolioGrid.vue +63 -0
  205. package/src/blocks/OcBlockPricing.vue +39 -0
  206. package/src/blocks/OcBlockProcess.vue +39 -0
  207. package/src/blocks/OcBlockProductGrid.vue +41 -0
  208. package/src/blocks/OcBlockProfileHeader.vue +50 -0
  209. package/src/blocks/OcBlockShowcase.vue +43 -0
  210. package/src/blocks/OcBlockSiteFooter.vue +54 -0
  211. package/src/blocks/OcBlockSiteHeader.vue +34 -0
  212. package/src/blocks/OcBlockSpotlight.vue +47 -0
  213. package/src/blocks/OcBlockStats.vue +17 -0
  214. package/src/blocks/OcBlockStatsCounter.vue +20 -0
  215. package/src/blocks/OcBlockTeamList.vue +53 -0
  216. package/src/blocks/OcBlockTwoFactor.vue +61 -0
  217. package/src/blocks/OcBlockWizardDialog.vue +67 -0
  218. package/src/components/OcAccordion.vue +12 -0
  219. package/src/components/OcAccordionAccent.vue +27 -0
  220. package/src/components/OcAccordionItem.vue +19 -0
  221. package/src/components/OcAffixInput.vue +40 -0
  222. package/src/components/OcAlert.vue +17 -0
  223. package/src/components/OcAlertDialog.vue +66 -0
  224. package/src/components/OcAlphaTabs.vue +54 -0
  225. package/src/components/OcAspectRatio.vue +21 -0
  226. package/src/components/OcAttachment.vue +59 -0
  227. package/src/components/OcAttachmentImage.vue +13 -0
  228. package/src/components/OcAttachmentList.vue +31 -0
  229. package/src/components/OcAttachmentThumb.vue +14 -0
  230. package/src/components/OcAvatar.vue +18 -0
  231. package/src/components/OcAvatarGroup.vue +7 -0
  232. package/src/components/OcBackLink.vue +8 -0
  233. package/src/components/OcBadge.vue +13 -0
  234. package/src/components/OcBarcodeInput.vue +51 -0
  235. package/src/components/OcBreadcrumb.vue +22 -0
  236. package/src/components/OcBrowserFrame.vue +33 -0
  237. package/src/components/OcBusyOverlay.vue +32 -0
  238. package/src/components/OcButton.vue +47 -0
  239. package/src/components/OcButtonGroup.vue +10 -0
  240. package/src/components/OcButtonGroupText.vue +7 -0
  241. package/src/components/OcCard.vue +20 -0
  242. package/src/components/OcChartLine.vue +80 -0
  243. package/src/components/OcChatComposer.vue +42 -0
  244. package/src/components/OcCheckbox.vue +26 -0
  245. package/src/components/OcChecklist.vue +29 -0
  246. package/src/components/OcChipFilter.vue +48 -0
  247. package/src/components/OcCollapsible.vue +19 -0
  248. package/src/components/OcColorField.vue +15 -0
  249. package/src/components/OcColorSelect.vue +33 -0
  250. package/src/components/OcColumnMenu.vue +50 -0
  251. package/src/components/OcCommand.vue +119 -0
  252. package/src/components/OcConfirmDialog.vue +65 -0
  253. package/src/components/OcCookieConsent.vue +119 -0
  254. package/src/components/OcCopyField.vue +37 -0
  255. package/src/components/OcCounter.vue +15 -0
  256. package/src/components/OcDataTable.vue +144 -0
  257. package/src/components/OcDecimalInput.vue +53 -0
  258. package/src/components/OcDefinitionList.vue +35 -0
  259. package/src/components/OcDocViewer.vue +79 -0
  260. package/src/components/OcDropdown.vue +23 -0
  261. package/src/components/OcDropdownItem.vue +9 -0
  262. package/src/components/OcDropdownLabel.vue +7 -0
  263. package/src/components/OcDropdownSeparator.vue +7 -0
  264. package/src/components/OcDropzone.vue +36 -0
  265. package/src/components/OcEmojiPicker.vue +45 -0
  266. package/src/components/OcEmptyState.vue +13 -0
  267. package/src/components/OcEntityCard.vue +47 -0
  268. package/src/components/OcFactList.vue +37 -0
  269. package/src/components/OcFilterCounts.vue +38 -0
  270. package/src/components/OcFlipCard.vue +36 -0
  271. package/src/components/OcFormField.vue +36 -0
  272. package/src/components/OcGreeting.vue +52 -0
  273. package/src/components/OcHeading.vue +19 -0
  274. package/src/components/OcHoverCard.vue +25 -0
  275. package/src/components/OcImageZoom.vue +39 -0
  276. package/src/components/OcInput.vue +9 -0
  277. package/src/components/OcInputGroup.vue +12 -0
  278. package/src/components/OcItem.vue +40 -0
  279. package/src/components/OcItemGroup.vue +7 -0
  280. package/src/components/OcItemSeparator.vue +7 -0
  281. package/src/components/OcKbd.vue +7 -0
  282. package/src/components/OcKbdGroup.vue +15 -0
  283. package/src/components/OcLabel.vue +10 -0
  284. package/src/components/OcLanguageSelect.vue +40 -0
  285. package/src/components/OcLauncherCard.vue +34 -0
  286. package/src/components/OcLightbox.vue +63 -0
  287. package/src/components/OcLinkArrow.vue +25 -0
  288. package/src/components/OcListToolbar.vue +44 -0
  289. package/src/components/OcMarquee.vue +36 -0
  290. package/src/components/OcMediaCard.vue +28 -0
  291. package/src/components/OcMediaRow.vue +28 -0
  292. package/src/components/OcMediaThumb.vue +38 -0
  293. package/src/components/OcMessage.vue +91 -0
  294. package/src/components/OcMessageList.vue +43 -0
  295. package/src/components/OcMessageThread.vue +155 -0
  296. package/src/components/OcModal.vue +42 -0
  297. package/src/components/OcNavmenu.vue +18 -0
  298. package/src/components/OcNavmenuList.vue +38 -0
  299. package/src/components/OcNextTeaser.vue +25 -0
  300. package/src/components/OcNumberInput.vue +47 -0
  301. package/src/components/OcOtpInput.vue +34 -0
  302. package/src/components/OcPageHeader.vue +34 -0
  303. package/src/components/OcPagination.vue +33 -0
  304. package/src/components/OcPasswordInput.vue +27 -0
  305. package/src/components/OcPasswordRequirements.vue +28 -0
  306. package/src/components/OcPhoneInput.vue +72 -0
  307. package/src/components/OcPopover.vue +25 -0
  308. package/src/components/OcPriceCard.vue +69 -0
  309. package/src/components/OcProductMark.vue +31 -0
  310. package/src/components/OcProgress.vue +21 -0
  311. package/src/components/OcProjectCard.vue +36 -0
  312. package/src/components/OcProse.vue +57 -0
  313. package/src/components/OcRadio.vue +40 -0
  314. package/src/components/OcRadioGroup.vue +32 -0
  315. package/src/components/OcRecoveryCodes.vue +55 -0
  316. package/src/components/OcScrollArea.vue +15 -0
  317. package/src/components/OcSegmented.vue +28 -0
  318. package/src/components/OcSelect.vue +21 -0
  319. package/src/components/OcSeparator.vue +18 -0
  320. package/src/components/OcSeverityCard.vue +46 -0
  321. package/src/components/OcSheet.vue +49 -0
  322. package/src/components/OcSidebar.vue +16 -0
  323. package/src/components/OcSidebarCollapsible.vue +19 -0
  324. package/src/components/OcSidebarGroup.vue +11 -0
  325. package/src/components/OcSidebarMenu.vue +7 -0
  326. package/src/components/OcSidebarMenuButton.vue +31 -0
  327. package/src/components/OcSidebarSeparator.vue +7 -0
  328. package/src/components/OcSkeleton.vue +8 -0
  329. package/src/components/OcSlider.vue +27 -0
  330. package/src/components/OcSortableRow.vue +40 -0
  331. package/src/components/OcSpinner.vue +13 -0
  332. package/src/components/OcStackCard.vue +24 -0
  333. package/src/components/OcStackList.vue +31 -0
  334. package/src/components/OcStatCard.vue +39 -0
  335. package/src/components/OcStepper.vue +34 -0
  336. package/src/components/OcSwitch.vue +15 -0
  337. package/src/components/OcTable.vue +115 -0
  338. package/src/components/OcTableActions.vue +26 -0
  339. package/src/components/OcTableCompact.vue +46 -0
  340. package/src/components/OcTabs.vue +37 -0
  341. package/src/components/OcTagInput.vue +50 -0
  342. package/src/components/OcTerminalLog.vue +50 -0
  343. package/src/components/OcTextarea.vue +9 -0
  344. package/src/components/OcThemeSwitch.vue +31 -0
  345. package/src/components/OcTimeInput.vue +50 -0
  346. package/src/components/OcTimeline.vue +36 -0
  347. package/src/components/OcToast.vue +31 -0
  348. package/src/components/OcToastContainer.vue +21 -0
  349. package/src/components/OcToggle.vue +63 -0
  350. package/src/components/OcToggleField.vue +28 -0
  351. package/src/components/OcToggleGroup.vue +40 -0
  352. package/src/components/OcTooltip.vue +8 -0
  353. package/src/components/OcTopProgress.vue +54 -0
  354. package/src/components/OcTree.vue +70 -0
  355. package/src/components/OcUpgradeBanner.vue +42 -0
  356. package/src/components/OcUser.vue +25 -0
  357. package/src/components/OcVersionBanner.vue +34 -0
  358. package/src/composables/chartLine.ts +28 -0
  359. package/src/composables/keys.ts +22 -0
  360. package/src/composables/useAttrsSplit.ts +16 -0
  361. package/src/composables/useDialog.ts +21 -0
  362. package/src/composables/useToast.ts +66 -0
  363. package/src/composables/useUid.ts +12 -0
  364. package/src/index.ts +589 -0
@@ -0,0 +1,44 @@
1
+ <!-- File: packages/vue/src/components/OcListToolbar.vue | Map: toolbar row -> search slot -> count -> spacer -> view radios (built-in icons) -> actions slot -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Toolbar above a list. v-model:view picks the view ("cards", "table" or "list"); render the matching view yourself.
5
+ * Slots: search, actions, view-icon (scoped { view } to replace the built-in icons).
6
+ * Classes: .oc-list-toolbar(--sticky/--bordered), -search, -count, -spacer, -views, -view, -actions
7
+ */
8
+ import { useUid } from '../composables/useUid'
9
+
10
+ withDefaults(
11
+ defineProps<{
12
+ count?: string
13
+ views?: Array<{ value: string; label: string }>
14
+ viewsLabel?: string
15
+ sticky?: boolean
16
+ bordered?: boolean
17
+ }>(),
18
+ { views: () => [], viewsLabel: 'View' },
19
+ )
20
+ const view = defineModel<string>('view', { default: 'cards' })
21
+ const name = useUid('oc-list-view')
22
+ </script>
23
+
24
+ <template>
25
+ <div :class="['oc-list-toolbar', sticky && 'oc-list-toolbar--sticky', bordered && 'oc-list-toolbar--bordered']" role="toolbar">
26
+ <div v-if="$slots.search" class="oc-list-toolbar-search"><slot name="search" /></div>
27
+ <span v-if="count" class="oc-list-toolbar-count">{{ count }}</span>
28
+ <span class="oc-list-toolbar-spacer"></span>
29
+ <div v-if="views.length" class="oc-list-toolbar-views" role="radiogroup" :aria-label="viewsLabel">
30
+ <label v-for="v in views" :key="v.value" class="oc-list-toolbar-view" :title="v.label">
31
+ <input v-model="view" type="radio" :name="name" :value="v.value" :aria-label="v.label" />
32
+ <slot name="view-icon" :view="v">
33
+ <!-- Built-in icons for the three common views. -->
34
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
35
+ <template v-if="v.value === 'cards'"><rect x="3" y="3" width="7" height="7" rx="1" /><rect x="14" y="3" width="7" height="7" rx="1" /><rect x="3" y="14" width="7" height="7" rx="1" /><rect x="14" y="14" width="7" height="7" rx="1" /></template>
36
+ <path v-else-if="v.value === 'table'" d="M3 5h18M3 12h18M3 19h18" />
37
+ <path v-else d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01" />
38
+ </svg>
39
+ </slot>
40
+ </label>
41
+ </div>
42
+ <div v-if="$slots.actions" class="oc-list-toolbar-actions"><slot name="actions" /></div>
43
+ </div>
44
+ </template>
@@ -0,0 +1,36 @@
1
+ <!-- File: packages/vue/src/components/OcMarquee.vue | Map: props -> .oc-marquee -> track (items + aria-hidden copy) -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Endless strip; pauses on hover / focus, stands still with reduced motion. The items are rendered twice
5
+ * (the copy is aria-hidden). Classes: .oc-marquee (--reverse, --slow, --fast, --plain, --no-fade), __track, __item
6
+ */
7
+ withDefaults(
8
+ defineProps<{
9
+ items: string[]
10
+ label?: string
11
+ reverse?: boolean
12
+ speed?: 'default' | 'slow' | 'fast'
13
+ plain?: boolean
14
+ noFade?: boolean
15
+ }>(),
16
+ { speed: 'default' },
17
+ )
18
+ </script>
19
+
20
+ <template>
21
+ <div
22
+ :class="[
23
+ 'oc-marquee',
24
+ reverse && 'oc-marquee--reverse',
25
+ speed !== 'default' && `oc-marquee--${speed}`,
26
+ plain && 'oc-marquee--plain',
27
+ noFade && 'oc-marquee--no-fade',
28
+ ]"
29
+ :aria-label="label"
30
+ >
31
+ <div class="oc-marquee__track">
32
+ <span v-for="(item, i) in items" :key="i" class="oc-marquee__item">{{ item }}</span>
33
+ <span v-for="(item, i) in items" :key="'copy-' + i" class="oc-marquee__item" aria-hidden="true">{{ item }}</span>
34
+ </div>
35
+ </div>
36
+ </template>
@@ -0,0 +1,28 @@
1
+ <!-- File: packages/vue/src/components/OcMediaCard.vue | Map: props -> article -> OcMediaThumb -> body (avatar, title + meta, menu) -> popover menu -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Video feed card (same markup as snippets/media-card.html). Props: title, href (title link covers the card), meta,
5
+ * avatar (initials), thumb (props for OcMediaThumb), compact. Slots: avatar (replaces initials), meta, menu (dropdown items;
6
+ * shows the ⋮ button). Classes: .oc-media-card(--compact), __body, __avatar, __text, __title, __meta, __menu
7
+ */
8
+ import OcMediaThumb from './OcMediaThumb.vue'
9
+ import { useUid } from '../composables/useUid'
10
+
11
+ defineProps<{ title: string; href: string; meta?: string; avatar?: string; thumb?: Record<string, unknown>; compact?: boolean }>()
12
+ const menuId = useUid('oc-media-card-menu')
13
+ </script>
14
+
15
+ <template>
16
+ <article :class="['oc-media-card', compact && 'oc-media-card--compact']">
17
+ <OcMediaThumb v-bind="thumb" />
18
+ <div class="oc-media-card__body">
19
+ <span v-if="avatar || $slots.avatar" class="oc-media-card__avatar" aria-hidden="true"><slot name="avatar">{{ avatar }}</slot></span>
20
+ <div class="oc-media-card__text">
21
+ <h3 class="oc-media-card__title"><a :href="href">{{ title }}</a></h3>
22
+ <p v-if="meta || $slots.meta" class="oc-media-card__meta"><slot name="meta">{{ meta }}</slot></p>
23
+ </div>
24
+ <button v-if="$slots.menu" type="button" class="oc-media-card__menu" :popovertarget="menuId" aria-label="More actions">&#8942;</button>
25
+ </div>
26
+ <div v-if="$slots.menu" :id="menuId" class="oc-dropdown-menu" popover><slot name="menu" /></div>
27
+ </article>
28
+ </template>
@@ -0,0 +1,28 @@
1
+ <!-- File: packages/vue/src/components/OcMediaRow.vue | Map: props -> li row -> OcMediaThumb -> title link + meta -> menu button + popover -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Compact media row (same markup as snippets/media-row.html). Put rows in
5
+ * <ul class="oc-media-row-list"> or <ol class="oc-media-row-list oc-media-row-list--numbered"> (numbered playlist).
6
+ * Props: title, href (link covers the row), meta, thumb (props for OcMediaThumb), current (aria-current).
7
+ * Slots: meta, menu (dropdown items; shows the ⋮ button). Classes: .oc-media-row, __text, __title, __meta, __menu
8
+ */
9
+ import OcMediaThumb from './OcMediaThumb.vue'
10
+ import { useUid } from '../composables/useUid'
11
+
12
+ defineProps<{ title: string; href: string; meta?: string; thumb?: Record<string, unknown>; current?: boolean }>()
13
+ const menuId = useUid('oc-media-row-menu')
14
+ </script>
15
+
16
+ <template>
17
+ <li class="oc-media-row" :aria-current="current ? 'true' : undefined">
18
+ <OcMediaThumb v-bind="thumb" />
19
+ <div class="oc-media-row__text">
20
+ <h3 class="oc-media-row__title"><a :href="href">{{ title }}</a></h3>
21
+ <p v-if="meta || $slots.meta" class="oc-media-row__meta"><slot name="meta">{{ meta }}</slot></p>
22
+ </div>
23
+ <template v-if="$slots.menu">
24
+ <button type="button" class="oc-media-row__menu" :popovertarget="menuId" aria-label="More actions">&#8942;</button>
25
+ <div :id="menuId" class="oc-dropdown-menu" popover><slot name="menu" /></div>
26
+ </template>
27
+ </li>
28
+ </template>
@@ -0,0 +1,38 @@
1
+ <!-- File: packages/vue/src/components/OcMediaThumb.vue | Map: props -> <a>/<div> -> picture -> badge -> duration -> progress -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * 16:9 video thumbnail (same markup as snippets/media-thumb.html). href renders an <a>.
5
+ * Props: src, alt, art (placeholder variant 1-6), duration, badge, live, progress (0-100), watched, ratio (video|square|portrait).
6
+ * Default slot: extra overlay content. Classes: .oc-media-thumb(--square/--portrait, .is-watched), __badge(--live), __duration, __progress
7
+ */
8
+ withDefaults(
9
+ defineProps<{
10
+ src?: string
11
+ alt?: string
12
+ art?: number
13
+ href?: string
14
+ duration?: string
15
+ badge?: string
16
+ live?: boolean
17
+ progress?: number
18
+ watched?: boolean
19
+ ratio?: 'video' | 'square' | 'portrait'
20
+ }>(),
21
+ { alt: '', ratio: 'video' },
22
+ )
23
+ </script>
24
+
25
+ <template>
26
+ <component
27
+ :is="href ? 'a' : 'div'"
28
+ :href="href"
29
+ :class="['oc-media-thumb', ratio !== 'video' && `oc-media-thumb--${ratio}`, watched && 'is-watched']"
30
+ >
31
+ <img v-if="src" :src="src" :alt="alt" />
32
+ <div v-else :class="['oc-media-art', art && art > 1 && `oc-media-art--${art}`]" />
33
+ <span v-if="badge" :class="['oc-media-thumb__badge', live && 'oc-media-thumb__badge--live']">{{ badge }}</span>
34
+ <span v-if="duration" class="oc-media-thumb__duration">{{ duration }}</span>
35
+ <progress v-if="progress != null" class="oc-media-thumb__progress" :value="progress" max="100" :aria-label="`Watched ${progress}%`">{{ progress }}%</progress>
36
+ <slot />
37
+ </component>
38
+ </template>
@@ -0,0 +1,91 @@
1
+ <!-- File: packages/vue/src/components/OcMessage.vue | Map: types + icons -> props -> article (avatar, bubble: sender, quote, text, attachments, meta; actions) -->
2
+ <script lang="ts">
3
+ import type { AttachmentFile } from './OcAttachment.vue'
4
+
5
+ /** File chip (default), image preview or square thumbnail inside a message. */
6
+ export type MessageAttachment =
7
+ | (AttachmentFile & { kind?: 'file' })
8
+ | { kind: 'image'; href?: string; src?: string; alt: string; art?: number; caption?: string }
9
+ | { kind: 'thumb'; src?: string; alt: string; art?: number }
10
+ export interface MessageAction { name: string; label: string; icon?: 'reply' | 'delete'; destructive?: boolean }
11
+ export interface MessageData {
12
+ direction?: 'in' | 'out'
13
+ sender?: string
14
+ avatar?: string
15
+ time?: string
16
+ datetime?: string
17
+ status?: 'sent' | 'read' | 'failed'
18
+ statusLabel?: string
19
+ statusIcon?: boolean
20
+ continued?: boolean
21
+ quote?: { href?: string; sender: string; text: string }
22
+ /** Plain text: one paragraph. */
23
+ text?: string
24
+ /** Trusted markup (p, ul, ol, a, strong, code); escape user text on the server. */
25
+ html?: string
26
+ attachments?: MessageAttachment[]
27
+ actions?: MessageAction[]
28
+ label?: string
29
+ id?: string
30
+ }
31
+ export const MESSAGE_ICONS: Record<string, string> = {
32
+ reply: 'M9 14 4 9l5-5M4 9h10a6 6 0 0 1 6 6v4',
33
+ delete: 'M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v6M14 11v6',
34
+ }
35
+ </script>
36
+
37
+ <script setup lang="ts">
38
+ /**
39
+ * Chat bubble (same markup as snippets/message.html): incoming / outgoing, sender, avatar, time, read receipt, reply quote,
40
+ * attachments and hover actions. Slot default = extra text content. Emits: action(name).
41
+ * Classes: .oc-message(--out/--continued) __avatar __bubble __sender __quote __text __attachments __meta __status(--read/--failed) __actions __action
42
+ */
43
+ import { computed } from 'vue'
44
+ import OcAttachment from './OcAttachment.vue'
45
+ import OcAttachmentImage from './OcAttachmentImage.vue'
46
+ import OcAttachmentThumb from './OcAttachmentThumb.vue'
47
+
48
+ const props = withDefaults(defineProps<MessageData>(), { direction: 'in' })
49
+ const emit = defineEmits<{ action: [name: string] }>()
50
+ const STATUS = { sent: 'Sent', read: 'Read', failed: 'Failed' }
51
+ const thumbsOnly = computed(() => !!props.attachments?.length && props.attachments.every((a) => a.kind === 'thumb'))
52
+ // Props of one attachment without its `kind`.
53
+ type ImageAttachment = Extract<MessageAttachment, { kind: 'image' }>
54
+ type ThumbAttachment = Extract<MessageAttachment, { kind: 'thumb' }>
55
+ const strip = (a: MessageAttachment) => {
56
+ const { kind: _k, ...p } = a
57
+ return p
58
+ }
59
+ const image = (a: MessageAttachment) => strip(a) as Omit<ImageAttachment, 'kind'>
60
+ const thumb = (a: MessageAttachment) => strip(a) as Omit<ThumbAttachment, 'kind'>
61
+ const file = (a: MessageAttachment) => strip(a) as AttachmentFile
62
+ </script>
63
+
64
+ <template>
65
+ <article :id="id" :class="['oc-message', direction === 'out' && 'oc-message--out', continued && 'oc-message--continued']" :aria-label="label">
66
+ <span class="oc-avatar oc-message__avatar">{{ avatar }}</span>
67
+ <div class="oc-message__bubble">
68
+ <p v-if="sender && !continued" class="oc-message__sender">{{ sender }}</p>
69
+ <a v-if="quote" class="oc-message__quote" :href="quote.href"><strong>{{ quote.sender }}</strong><span>{{ quote.text }}</span></a>
70
+ <div v-if="html" class="oc-message__text" v-html="html"></div>
71
+ <div v-else-if="text || $slots.default" class="oc-message__text"><p v-if="text">{{ text }}</p><slot /></div>
72
+ <div v-if="attachments?.length" class="oc-message__attachments">
73
+ <div v-if="thumbsOnly" class="oc-attachment-list"><OcAttachmentThumb v-for="(a, i) in attachments" :key="i" v-bind="thumb(a)" as="span" /></div>
74
+ <template v-for="(a, i) in attachments" v-else :key="i">
75
+ <OcAttachmentImage v-if="a.kind === 'image'" v-bind="image(a)" />
76
+ <OcAttachmentThumb v-else-if="a.kind === 'thumb'" v-bind="thumb(a)" as="span" />
77
+ <OcAttachment v-else v-bind="file(a)" />
78
+ </template>
79
+ </div>
80
+ <p v-if="time || status" class="oc-message__meta">
81
+ <time v-if="time" :datetime="datetime">{{ time }}</time>
82
+ <span v-if="status" :class="['oc-message__status', status !== 'sent' && `oc-message__status--${status}`]"><svg v-if="statusIcon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12.5 7 17.5 18 6.5M13 16.5l1 1L22.5 9" /></svg>{{ statusLabel ?? STATUS[status] }}</span>
83
+ </p>
84
+ </div>
85
+ <div v-if="actions?.length" class="oc-message__actions">
86
+ <button v-for="a in actions" :key="a.name" type="button" :class="['oc-message__action', a.destructive && 'oc-message__action--destructive']" :aria-label="a.label" @click="emit('action', a.name)">
87
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path :d="MESSAGE_ICONS[a.icon ?? a.name] ?? MESSAGE_ICONS.reply" /></svg>
88
+ </button>
89
+ </div>
90
+ </article>
91
+ </template>
@@ -0,0 +1,43 @@
1
+ <!-- File: packages/vue/src/components/OcMessageList.vue | Map: props + demo conversation -> .oc-message-list -> dividers and OcMessage rows -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * Column of messages and dividers (snippets/message.html). items: (MessageData | { divider, system? })[]; demo conversation
5
+ * when empty; slot default replaces them. log = role="log" (default true). Emits: action(name, message, index).
6
+ * Classes: .oc-message-list, .oc-message-divider(--system)
7
+ */
8
+ import OcMessage, { type MessageData } from './OcMessage.vue'
9
+
10
+ export type MessageListItem = MessageData | { divider: string; system?: boolean }
11
+ withDefaults(defineProps<{ items?: MessageListItem[]; log?: boolean; label?: string }>(), {
12
+ log: true,
13
+ label: 'Conversation with Lisa Verbeke',
14
+ items: () => [
15
+ { divider: 'Tuesday 14 October' },
16
+ { sender: 'Lisa Verbeke', avatar: 'LV', time: '09:12', datetime: '2026-10-14T09:12', label: 'Lisa Verbeke, 09:12', text: 'Morning Tom! The worktop supplier sent two samples for Villa Dewitte.' },
17
+ {
18
+ sender: 'Lisa Verbeke', avatar: 'LV', time: '09:13', datetime: '2026-10-14T09:13', label: 'Lisa Verbeke, 09:13', continued: true, id: 'oc-message-demo-question',
19
+ html: '<p>Which finish should we order?</p><ul><li><strong>Calacatta</strong> matt, 20 mm</li><li><strong>Nero Marquina</strong> polished, 12 mm</li></ul><p>Details are on the <a href="#supplier-sheet">supplier sheet</a>.</p>',
20
+ },
21
+ {
22
+ direction: 'out', avatar: 'TP', time: '09:20', datetime: '2026-10-14T09:20', label: 'You, 09:20', status: 'read', statusIcon: true,
23
+ quote: { href: '#oc-message-demo-question', sender: 'Lisa Verbeke', text: 'Which finish should we order? Calacatta matt, 20 mm or Nero Marquina polished, 12 mm' },
24
+ text: 'Calacatta matt. The client wants the lighter look next to the oak fronts.',
25
+ actions: [{ name: 'reply', label: 'Reply to this message' }, { name: 'delete', label: 'Delete this message', destructive: true }],
26
+ },
27
+ { divider: 'Lisa Verbeke marked this question as answered', system: true },
28
+ ],
29
+ })
30
+ const emit = defineEmits<{ action: [name: string, message: MessageData, index: number] }>()
31
+ const isDivider = (item: MessageListItem): item is { divider: string; system?: boolean } => 'divider' in item
32
+ </script>
33
+
34
+ <template>
35
+ <div class="oc-message-list" :role="log ? 'log' : undefined" :aria-label="log ? label : undefined">
36
+ <slot>
37
+ <template v-for="(item, i) in items" :key="i">
38
+ <div v-if="isDivider(item)" :class="['oc-message-divider', item.system && 'oc-message-divider--system']" :role="item.system ? 'note' : undefined"><span>{{ item.divider }}</span></div>
39
+ <OcMessage v-else v-bind="item" @action="(name: string) => emit('action', name, item as MessageData, i)" />
40
+ </template>
41
+ </slot>
42
+ </div>
43
+ </template>
@@ -0,0 +1,155 @@
1
+ <!-- File: packages/vue/src/components/OcMessageThread.vue | Map: props + demo -> state (messages, sending) -> header (back slot, heading, people, badge, menu)
2
+ -> scroll (OcMessageList) -> footer (composer slot / form / note) -> busy overlay -->
3
+ <script setup lang="ts">
4
+ /**
5
+ * Scrolling conversation (same markup as snippets/message-thread.html). Like the snippet script, a sent text is appended as an
6
+ * outgoing bubble after the @send handler (prop onSend, may return a Promise) resolves; aria-busy shows the overlay meanwhile.
7
+ * Ctrl/Cmd + Enter sends. `manual` = you append messages yourself. Emits: menu(name), tool(name).
8
+ * Slots: back (start of the header), composer (replaces the form). Classes: .oc-message-thread(--plain) __header __heading __title
9
+ * __meta __people __actions __icon-btn __scroll __footer __note __busy
10
+ */
11
+ import { ref, watch } from 'vue'
12
+ import OcMessageList, { type MessageListItem } from './OcMessageList.vue'
13
+ import type { MessageData } from './OcMessage.vue'
14
+ import { useUid } from '../composables/useUid'
15
+
16
+ export interface ThreadParticipant { initials: string; name?: string }
17
+ export type ThreadMenuItem = { name: string; label: string; destructive?: boolean } | { separator: true }
18
+
19
+ const props = withDefaults(
20
+ defineProps<{
21
+ title?: string
22
+ project?: string
23
+ meta?: string
24
+ participants?: ThreadParticipant[]
25
+ status?: { label: string; variant?: string } | null
26
+ menu?: ThreadMenuItem[] | null
27
+ messages?: MessageListItem[]
28
+ scrollLabel?: string
29
+ live?: boolean
30
+ busy?: boolean
31
+ /** Overlay title; empty string leaves the overlay out. */
32
+ busyTitle?: string
33
+ busyText?: string
34
+ note?: string
35
+ placeholder?: string
36
+ composerLabel?: string
37
+ inline?: boolean
38
+ tools?: Array<'attach' | 'emoji'>
39
+ hint?: string
40
+ manual?: boolean
41
+ me?: string
42
+ plain?: boolean
43
+ id?: string
44
+ onSend?: (text: string) => void | Promise<void>
45
+ }>(),
46
+ {
47
+ title: 'Kitchen worktop: which finish?',
48
+ project: 'Villa Dewitte',
49
+ meta: 'Lisa Verbeke → Tom Peeters · 14 Oct 2026',
50
+ participants: () => [{ initials: 'LV', name: 'Lisa Verbeke' }, { initials: 'TP', name: 'Tom Peeters' }],
51
+ status: () => ({ label: 'Urgent', variant: 'destructive' }),
52
+ menu: () => [{ name: 'unread', label: 'Mark as unread' }, { name: 'archive', label: 'Move to archive' }, { separator: true }, { name: 'delete', label: 'Delete conversation', destructive: true }],
53
+ messages: () => [
54
+ { divider: 'Tuesday 14 October' },
55
+ { sender: 'Lisa Verbeke', avatar: 'LV', time: '09:12', datetime: '2026-10-14T09:12', text: 'The supplier dropped off two worktop samples at the workshop. Photo attached.',
56
+ attachments: [{ kind: 'image', href: '#samples.jpg', alt: 'Two worktop samples on the workbench', art: 6, caption: 'samples.jpg · 2.1 MB' }] },
57
+ { sender: 'Lisa Verbeke', avatar: 'LV', time: '09:13', datetime: '2026-10-14T09:13', continued: true,
58
+ html: '<p>Which one should we order: <strong>Calacatta matt</strong> or <strong>Nero Marquina polished</strong>? The cutting slot is Friday.</p>' },
59
+ { direction: 'out', avatar: 'TP', time: '09:20', datetime: '2026-10-14T09:20', status: 'read', text: 'Calacatta matt, 20 mm. I\'ll send the updated quote to the client today.',
60
+ attachments: [{ name: 'Quote kitchen Dewitte v2.pdf', size: '1.2 MB', href: '#quote.pdf' }], actions: [{ name: 'delete', label: 'Delete this message', destructive: true }] },
61
+ { divider: 'Today' },
62
+ { sender: 'Lisa Verbeke', avatar: 'LV', time: '10:02', datetime: '2026-10-24T10:02', text: 'Client signed. Can you confirm the edge profile before 16:00?' },
63
+ ],
64
+ scrollLabel: 'Messages',
65
+ live: true,
66
+ busyTitle: 'Sending message…',
67
+ busyText: 'Please wait, do not close this conversation.',
68
+ placeholder: 'Type your reply…',
69
+ composerLabel: 'Reply',
70
+ tools: () => ['attach', 'emoji'],
71
+ hint: 'Ctrl + Enter to send',
72
+ },
73
+ )
74
+ const emit = defineEmits<{ menu: [name: string]; tool: [name: 'attach' | 'emoji'] }>()
75
+ const auto = useUid('oc-thread')
76
+ const base = props.id ?? auto
77
+ const list = ref<MessageListItem[]>([...props.messages])
78
+ const sending = ref(false)
79
+ watch(() => props.messages, (m) => (list.value = [...m]))
80
+ const isOut = (m?: MessageListItem): m is MessageData => !!m && !('divider' in m) && m.direction === 'out'
81
+
82
+ async function send(e: Event) {
83
+ const form = e.target as HTMLFormElement
84
+ const field = form.elements.namedItem('message') as HTMLTextAreaElement
85
+ const text = field.value.trim()
86
+ if (!text) return
87
+ sending.value = true
88
+ try { await props.onSend?.(text) } catch { sending.value = false; return }
89
+ if (!props.manual) {
90
+ const l = list.value
91
+ const mine = props.me ?? [...l].reverse().find(isOut)?.avatar ?? 'Me'
92
+ list.value = [...l, { direction: 'out', avatar: mine, continued: isOut(l[l.length - 1]), text, time: new Date().toTimeString().slice(0, 5), status: 'sent' }]
93
+ }
94
+ field.value = ''
95
+ sending.value = false
96
+ field.focus()
97
+ }
98
+ function ctrlEnter(e: KeyboardEvent) {
99
+ if (e.key !== 'Enter' || !(e.ctrlKey || e.metaKey)) return
100
+ e.preventDefault()
101
+ ;(e.currentTarget as HTMLFormElement).requestSubmit()
102
+ }
103
+ </script>
104
+
105
+ <template>
106
+ <section :class="['oc-message-thread', plain && 'oc-message-thread--plain']" :aria-labelledby="`${base}-title`" :aria-busy="busy || sending ? 'true' : undefined">
107
+ <header class="oc-message-thread__header">
108
+ <slot name="back" />
109
+ <div class="oc-message-thread__heading">
110
+ <h3 :id="`${base}-title`" class="oc-message-thread__title">{{ title }}</h3>
111
+ <p v-if="project || meta" class="oc-message-thread__meta"><strong v-if="project">{{ project }}</strong><template v-if="project && meta"> · </template>{{ meta }}</p>
112
+ </div>
113
+ <div v-if="participants.length" class="oc-avatar-group oc-message-thread__people" :aria-label="`${participants.length} participants`">
114
+ <span v-for="(p, i) in participants" :key="i" class="oc-avatar" :title="p.name">{{ p.initials }}</span>
115
+ </div>
116
+ <div v-if="status || menu" class="oc-message-thread__actions">
117
+ <span v-if="status" :class="['oc-badge', status.variant && `oc-badge--${status.variant}`]">{{ status.label }}</span>
118
+ <template v-if="menu">
119
+ <button type="button" class="oc-message-thread__icon-btn" :popovertarget="`${base}-menu`" aria-label="Conversation actions"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="5" r="1.8" /><circle cx="12" cy="12" r="1.8" /><circle cx="12" cy="19" r="1.8" /></svg></button>
120
+ <div :id="`${base}-menu`" class="oc-dropdown-menu" popover role="menu">
121
+ <template v-for="(m, i) in menu" :key="i">
122
+ <div v-if="'separator' in m" class="oc-dropdown-separator" role="separator"></div>
123
+ <button v-else type="button" :class="['oc-dropdown-item', m.destructive && 'oc-dropdown-item--destructive']" role="menuitem" @click="emit('menu', m.name)">{{ m.label }}</button>
124
+ </template>
125
+ </div>
126
+ </template>
127
+ </div>
128
+ </header>
129
+ <div class="oc-message-thread__scroll" tabindex="0" role="log" :aria-label="scrollLabel" :aria-live="live ? 'polite' : undefined">
130
+ <OcMessageList :items="list" :log="false" />
131
+ </div>
132
+ <div class="oc-message-thread__footer">
133
+ <p v-if="note" class="oc-message-thread__note">{{ note }}</p>
134
+ <slot v-else name="composer">
135
+ <form :class="['oc-chat-composer', inline && 'oc-chat-composer--inline']" action="#" :aria-label="composerLabel" @submit.prevent="send" @keydown="ctrlEnter">
136
+ <label class="oc-visually-hidden" :for="`${base}-input`">Message</label>
137
+ <textarea :id="`${base}-input`" class="oc-chat-composer__input" name="message" rows="1" :placeholder="placeholder" required></textarea>
138
+ <div class="oc-chat-composer__bar">
139
+ <div v-if="tools.length" class="oc-chat-composer__tools">
140
+ <button v-if="tools.includes('attach')" type="button" class="oc-chat-composer__tool" aria-label="Attach a file" @click="emit('tool', 'attach')">&#128206;</button>
141
+ <button v-if="tools.includes('emoji')" type="button" class="oc-chat-composer__tool" aria-label="Insert emoji" @click="emit('tool', 'emoji')">&#128578;</button>
142
+ </div>
143
+ <span v-if="hint" class="oc-chat-composer__hint">{{ hint }}</span>
144
+ <button type="submit" class="oc-chat-composer__send" aria-label="Send">&#10148;</button>
145
+ </div>
146
+ </form>
147
+ </slot>
148
+ </div>
149
+ <div v-if="busyTitle" class="oc-message-thread__busy" role="status">
150
+ <span class="oc-spinner oc-spinner--lg" aria-hidden="true"></span>
151
+ <strong>{{ busyTitle }}</strong>
152
+ <span v-if="busyText">{{ busyText }}</span>
153
+ </div>
154
+ </section>
155
+ </template>
@@ -0,0 +1,42 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Modal on a native <dialog> opened with showModal(). v-model:open controls it; Esc / backdrop /
4
+ * close() update the model. Slots: header (replaces title + description), default (body),
5
+ * footer (scoped: { close }). Classes: .oc-modal, .oc-modal-content(--sm/--lg/--xl/--full), -header, -title,
6
+ * -description, -body, -footer.
7
+ */
8
+ import { ref } from 'vue'
9
+ import { useDialog } from '../composables/useDialog'
10
+ import { useUid } from '../composables/useUid'
11
+
12
+ withDefaults(
13
+ defineProps<{
14
+ title?: string
15
+ description?: string
16
+ size?: 'sm' | 'md' | 'lg' | 'xl' | 'full'
17
+ closedby?: 'any' | 'closerequest' | 'none'
18
+ }>(),
19
+ { size: 'md', closedby: 'any' },
20
+ )
21
+ const open = defineModel<boolean>('open', { default: false })
22
+ const el = ref<HTMLDialogElement | null>(null)
23
+ const { onClose } = useDialog(open, el)
24
+ const titleId = useUid('oc-modal-title')
25
+ const close = () => (open.value = false)
26
+ defineExpose({ close })
27
+ </script>
28
+
29
+ <template>
30
+ <dialog ref="el" class="oc-modal" :closedby="closedby" :aria-labelledby="title ? titleId : undefined" @close="onClose">
31
+ <div :class="['oc-modal-content', size !== 'md' && `oc-modal-content--${size}`]">
32
+ <div v-if="title || description || $slots.header" class="oc-modal-header">
33
+ <slot name="header">
34
+ <h2 v-if="title" :id="titleId" class="oc-modal-title">{{ title }}</h2>
35
+ <p v-if="description" class="oc-modal-description">{{ description }}</p>
36
+ </slot>
37
+ </div>
38
+ <div v-if="$slots.default" class="oc-modal-body"><slot /></div>
39
+ <div v-if="$slots.footer" class="oc-modal-footer"><slot name="footer" :close="close" /></div>
40
+ </div>
41
+ </dialog>
42
+ </template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Horizontal navigation links with optional dropdown children, wrapped in a <nav>.
4
+ * Pass `items` (see OcNavmenuList) or put your own <li> elements in the default slot.
5
+ */
6
+ import OcNavmenuList, { type NavmenuItem } from './OcNavmenuList.vue'
7
+
8
+ withDefaults(defineProps<{ items?: NavmenuItem[]; label?: string }>(), {
9
+ items: () => [],
10
+ label: 'Navigation',
11
+ })
12
+ </script>
13
+
14
+ <template>
15
+ <nav :aria-label="label">
16
+ <OcNavmenuList :items="items"><slot /></OcNavmenuList>
17
+ </nav>
18
+ </template>
@@ -0,0 +1,38 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * The <ul class="oc-navmenu"> of the navigation menu, without the surrounding <nav>
4
+ * (used by OcNavmenu and by blocks that provide their own <nav>).
5
+ * Pass `items`, or put your own <li> elements in the default slot.
6
+ * Classes: .oc-navmenu, .oc-navmenu-link(--caret) with aria-current="page"
7
+ */
8
+ import { useUid } from '../composables/useUid'
9
+
10
+ export interface NavmenuItem {
11
+ label: string
12
+ href?: string
13
+ current?: boolean
14
+ /** Dropdown entries; turns the item into a popover trigger. */
15
+ children?: { label: string; href: string }[]
16
+ /** Heading inside the dropdown. */
17
+ heading?: string
18
+ }
19
+ withDefaults(defineProps<{ items?: NavmenuItem[] }>(), { items: () => [] })
20
+ const base = useUid('oc-navmenu')
21
+ </script>
22
+
23
+ <template>
24
+ <ul class="oc-navmenu">
25
+ <slot>
26
+ <li v-for="(item, i) in items" :key="i">
27
+ <template v-if="item.children?.length">
28
+ <button class="oc-navmenu-link oc-navmenu-link--caret" type="button" :popovertarget="`${base}-${i}`">{{ item.label }}</button>
29
+ <div :id="`${base}-${i}`" class="oc-dropdown-menu" popover>
30
+ <div v-if="item.heading" class="oc-dropdown-label">{{ item.heading }}</div>
31
+ <a v-for="child in item.children" :key="child.href + child.label" class="oc-dropdown-item" :href="child.href">{{ child.label }}</a>
32
+ </div>
33
+ </template>
34
+ <a v-else class="oc-navmenu-link" :href="item.href ?? '#'" :aria-current="item.current ? 'page' : undefined">{{ item.label }}</a>
35
+ </li>
36
+ </slot>
37
+ </ul>
38
+ </template>
@@ -0,0 +1,25 @@
1
+ <!-- File: packages/vue/src/components/OcNextTeaser.vue | Map: props -> a.oc-next-teaser -> label -> name (mark slot) -> tagline -->
2
+ <script setup lang="ts">
3
+ /**
4
+ * "Next product" teaser card. Slots: mark (e.g. an OcProductMark size="sm"), name, tagline.
5
+ * Classes: .oc-next-teaser (--prev), __label, __name, __tagline
6
+ */
7
+ withDefaults(
8
+ defineProps<{
9
+ href: string
10
+ label?: string
11
+ name?: string
12
+ tagline?: string
13
+ prev?: boolean
14
+ }>(),
15
+ { label: 'Next product' },
16
+ )
17
+ </script>
18
+
19
+ <template>
20
+ <a :class="['oc-next-teaser', prev && 'oc-next-teaser--prev']" :href="href">
21
+ <span v-if="label" class="oc-next-teaser__label">{{ label }}</span>
22
+ <span class="oc-next-teaser__name"><slot name="mark" /><slot name="name">{{ name }}</slot></span>
23
+ <span v-if="tagline || $slots.tagline" class="oc-next-teaser__tagline"><slot name="tagline">{{ tagline }}</slot></span>
24
+ </a>
25
+ </template>