@celestia-island/hikari 0.4.4 → 0.30.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 (385) hide show
  1. package/README.md +1 -1
  2. package/package.json +22 -7
  3. package/src/DemoApp.tsx +491 -0
  4. package/src/animation/registerAnimations.test.ts +94 -0
  5. package/src/animation/registerAnimations.ts +103 -0
  6. package/src/components/HkAboutModal.scss +95 -0
  7. package/src/components/HkAboutModal.tsx +114 -0
  8. package/src/components/HkAdaptiveDialog.scss +22 -0
  9. package/src/components/HkAdaptiveDialog.test.tsx +271 -0
  10. package/src/components/HkAdaptiveDialog.tsx +167 -0
  11. package/src/components/HkAdminHeader.test.tsx +185 -0
  12. package/src/components/HkAdminHeader.tsx +308 -0
  13. package/src/components/HkAdminShell.test.tsx +237 -0
  14. package/src/components/HkAdminShell.tsx +129 -0
  15. package/src/components/HkAdminTablePage.tsx +70 -0
  16. package/src/components/HkAdminWidgets.test.ts +89 -0
  17. package/src/components/HkAlert.tsx +1 -1
  18. package/src/components/HkAltSignIn.scss +55 -0
  19. package/src/components/HkAltSignIn.test.tsx +88 -0
  20. package/src/components/HkAltSignIn.tsx +92 -0
  21. package/src/components/HkAttachmentModal.scss +49 -0
  22. package/src/components/HkAttachmentModal.tsx +318 -0
  23. package/src/components/HkAuthCard.tsx +50 -0
  24. package/src/components/HkAuthSubmitButton.scss +12 -0
  25. package/src/components/HkAuthSubmitButton.tsx +94 -0
  26. package/src/components/HkAvatar.scss +93 -0
  27. package/src/components/HkAvatar.tsx +2 -2
  28. package/src/components/HkBlockingToast.scss +123 -0
  29. package/src/components/HkBlockingToast.test.tsx +221 -0
  30. package/src/components/HkBlockingToast.tsx +182 -0
  31. package/src/components/HkBreadcrumb.scss +624 -0
  32. package/src/components/HkBreadcrumb.tsx +2 -2
  33. package/src/components/HkButton.scss +16 -2
  34. package/src/components/HkCaptchaModal.scss +14 -0
  35. package/src/components/HkCaptchaModal.tsx +62 -0
  36. package/src/components/HkCaptchaWidget.scss +30 -0
  37. package/src/components/HkCaptchaWidget.tsx +181 -0
  38. package/src/components/HkCard.scss +1 -1
  39. package/src/components/HkChatTypes.ts +65 -0
  40. package/src/components/HkCheckbox.scss +4 -9
  41. package/src/components/HkCheckbox.tsx +18 -6
  42. package/src/components/HkColorPicker.scss +120 -3
  43. package/src/components/HkColorPicker.tsx +130 -19
  44. package/src/components/HkColorPickerTouch.test.tsx +145 -0
  45. package/src/components/HkColorSchemeDialog.scss +52 -0
  46. package/src/components/HkColorSchemeDialog.test.ts +201 -0
  47. package/src/components/HkColorSchemeDialog.tsx +96 -0
  48. package/src/components/HkColorSchemeEditor.test.ts +270 -0
  49. package/src/components/HkColorSchemeEditor.tsx +410 -0
  50. package/src/components/HkConfirmDialog.scss +43 -3
  51. package/src/components/HkConfirmDialog.tsx +7 -4
  52. package/src/components/HkConnectionInfo.ts +80 -0
  53. package/src/components/HkConnectionStatus.tsx +158 -0
  54. package/src/components/HkCookieConsent.scss +22 -0
  55. package/src/components/HkCookieConsent.test.tsx +70 -0
  56. package/src/components/HkCookieConsent.tsx +56 -0
  57. package/src/components/HkCountdownDigit.tsx +105 -0
  58. package/src/components/HkDatePicker.scss +361 -0
  59. package/src/components/HkDatePicker.test.ts +459 -0
  60. package/src/components/HkDatePicker.tsx +568 -0
  61. package/src/components/HkDateTimePicker.scss +65 -37
  62. package/src/components/HkDateTimePicker.test.ts +344 -0
  63. package/src/components/HkDateTimePicker.tsx +249 -82
  64. package/src/components/HkDraggableGrid.scss +4 -1
  65. package/src/components/HkDraggableList.scss +4 -1
  66. package/src/components/HkDrawer.scss +27 -13
  67. package/src/components/HkDrawer.test.tsx +73 -0
  68. package/src/components/HkDrawer.tsx +157 -10
  69. package/src/components/HkErrorBoundary.scss +5 -2
  70. package/src/components/HkErrorBoundary.tsx +7 -4
  71. package/src/components/HkExpansionPanel.scss +143 -0
  72. package/src/components/HkExpansionPanel.test.tsx +109 -0
  73. package/src/components/HkExpansionPanel.tsx +101 -0
  74. package/src/components/HkFab.scss +162 -0
  75. package/src/components/HkFab.test.tsx +217 -0
  76. package/src/components/HkFab.tsx +214 -0
  77. package/src/components/HkHoverRevealAction.scss +6 -0
  78. package/src/components/HkHoverRevealAction.test.ts +68 -0
  79. package/src/components/HkHoverRevealAction.tsx +84 -6
  80. package/src/components/HkIcon.scss +123 -0
  81. package/src/components/HkIcon.tsx +7 -23
  82. package/src/components/HkIconButton.scss +170 -0
  83. package/src/components/HkIconButton.test.tsx +75 -0
  84. package/src/components/HkIconButton.tsx +4 -3
  85. package/src/components/HkIconButtonVars.scss +180 -0
  86. package/src/components/HkInput.affix.test.ts +253 -0
  87. package/src/components/HkInput.enter.test.ts +88 -0
  88. package/src/components/HkInput.scss +127 -8
  89. package/src/components/HkInput.tsx +245 -13
  90. package/src/components/HkKeywordSearchModal.scss +13 -0
  91. package/src/components/HkKeywordSearchModal.tsx +46 -9
  92. package/src/components/HkLabel.scss +34 -0
  93. package/src/components/HkLabel.test.tsx +61 -0
  94. package/src/components/HkLabel.tsx +45 -0
  95. package/src/components/HkListTransition.scss +26 -0
  96. package/src/components/HkListTransition.tsx +57 -0
  97. package/src/components/HkLocalePicker.scss +37 -0
  98. package/src/components/HkLocalePicker.tsx +133 -0
  99. package/src/components/HkLocalePickerPopup.tsx +35 -19
  100. package/src/components/HkLocalizedInput.scss +277 -0
  101. package/src/components/HkLocalizedInput.test.tsx +693 -0
  102. package/src/components/HkLocalizedInput.tsx +495 -0
  103. package/src/components/HkLogWindow.scss +121 -0
  104. package/src/components/HkLogWindow.tsx +195 -0
  105. package/src/components/HkLogo.scss +1 -1
  106. package/src/components/HkLogo.tsx +1 -1
  107. package/src/components/HkMarkdownRenderer.scss +22 -2
  108. package/src/components/HkMarkdownRenderer.tsx +33 -3
  109. package/src/components/HkMediaControlBar.tsx +20 -13
  110. package/src/components/HkMenu.scss +200 -0
  111. package/src/components/HkMenu.test.ts +779 -0
  112. package/src/components/HkMenu.tsx +770 -0
  113. package/src/components/HkMenuActionItem.scss +58 -0
  114. package/src/components/HkMenuActionItem.tsx +41 -0
  115. package/src/components/HkMenuIdentityItem.scss +70 -0
  116. package/src/components/HkMenuIdentityItem.tsx +42 -0
  117. package/src/components/HkMenuPanel.scss +20 -0
  118. package/src/components/HkMenuPanel.test.tsx +118 -0
  119. package/src/components/HkMenuPanel.tsx +32 -0
  120. package/src/components/HkMinimap.tsx +16 -8
  121. package/src/components/HkModal.autofollow.test.ts +44 -0
  122. package/src/components/HkModal.scss +170 -53
  123. package/src/components/HkModal.sheetgap.test.ts +82 -0
  124. package/src/components/HkModal.test.tsx +334 -0
  125. package/src/components/HkModal.tsx +314 -68
  126. package/src/components/HkModalBreadcrumb.scss +4 -1
  127. package/src/components/HkModalBreadcrumb.test.tsx +111 -0
  128. package/src/components/HkModalBreadcrumb.tsx +34 -11
  129. package/src/components/HkModelCatalog.ts +98 -0
  130. package/src/components/HkModelTag.scss +130 -0
  131. package/src/components/HkModelTag.test.tsx +111 -0
  132. package/src/components/HkModelTag.tsx +190 -0
  133. package/src/components/HkNavItem.scss +13 -2
  134. package/src/components/HkNavItem.tsx +2 -1
  135. package/src/components/HkNavSidebar.tsx +99 -0
  136. package/src/components/HkNumberInput.scss +12 -0
  137. package/src/components/HkNumberInput.tsx +15 -8
  138. package/src/components/HkPageHeader.scss +79 -0
  139. package/src/components/HkPageHeader.test.ts +67 -0
  140. package/src/components/HkPageHeader.tsx +51 -0
  141. package/src/components/HkPasswordInput.scss +29 -17
  142. package/src/components/HkPasswordInput.test.ts +281 -0
  143. package/src/components/HkPasswordInput.tsx +337 -59
  144. package/src/components/HkPickerPane.scss +158 -0
  145. package/src/components/HkPlaceholderMarquee.scss +109 -0
  146. package/src/components/HkPlaceholderMarquee.test.ts +305 -0
  147. package/src/components/HkPlaceholderMarquee.tsx +170 -0
  148. package/src/components/HkPopover.scss +134 -10
  149. package/src/components/HkPopover.sheetdock.test.ts +34 -0
  150. package/src/components/HkPopover.surfacevars.test.ts +20 -0
  151. package/src/components/HkPopover.titleSuppress.test.tsx +265 -0
  152. package/src/components/HkPopover.tsx +225 -50
  153. package/src/components/HkPopoverSheet.test.tsx +130 -0
  154. package/src/components/HkPopupSelect.scss +30 -10
  155. package/src/components/HkPopupSelect.tsx +21 -1
  156. package/src/components/HkProgressDialog.scss +31 -0
  157. package/src/components/HkProgressDialog.tsx +37 -19
  158. package/src/components/HkProtocolModal.scss +26 -0
  159. package/src/components/HkProtocolModal.tsx +112 -0
  160. package/src/components/HkRadio.scss +1 -16
  161. package/src/components/HkRadio.tsx +5 -2
  162. package/src/components/HkRichInput.scss +162 -0
  163. package/src/components/HkRichInput.tsx +335 -0
  164. package/src/components/HkRollingNumber.test.ts +90 -0
  165. package/src/components/HkRollingNumber.tsx +39 -1
  166. package/src/components/HkScrollContainer.scss +71 -54
  167. package/src/components/HkScrollContainer.test.ts +160 -0
  168. package/src/components/HkScrollContainer.tsx +187 -160
  169. package/src/components/HkSearchInput.tsx +3 -3
  170. package/src/components/HkSecretRevealModal.scss +61 -0
  171. package/src/components/HkSecretRevealModal.tsx +91 -0
  172. package/src/components/HkSelect.scss +263 -12
  173. package/src/components/HkSelect.sheetdock.test.ts +30 -0
  174. package/src/components/HkSelect.test.tsx +88 -0
  175. package/src/components/HkSelect.tsx +59 -74
  176. package/src/components/HkSelectPanel.test.tsx +666 -0
  177. package/src/components/HkSelectPanel.tsx +595 -0
  178. package/src/components/HkSelectSheet.test.tsx +132 -0
  179. package/src/components/HkSelectionGrid.scss +1 -1
  180. package/src/components/HkSelectionGrid.tsx +2 -1
  181. package/src/components/HkSelectionWaterfall.scss +1 -1
  182. package/src/components/HkShareBar.scss +40 -0
  183. package/src/components/HkShareBar.tsx +50 -0
  184. package/src/components/HkSidebar.scss +15 -10
  185. package/src/components/HkSidebar.tsx +26 -2
  186. package/src/components/HkSignInCard.test.ts +154 -0
  187. package/src/components/HkSignInCard.tsx +155 -0
  188. package/src/components/HkSlider.scss +99 -0
  189. package/src/components/HkSlider.test.tsx +155 -0
  190. package/src/components/HkSlider.tsx +173 -0
  191. package/src/components/HkSpinner.scss +36 -1
  192. package/src/components/HkSpinner.test.tsx +63 -0
  193. package/src/components/HkSpinner.tsx +16 -1
  194. package/src/components/HkSplash.scss +1 -1
  195. package/src/components/HkSplash.tsx +3 -1
  196. package/src/components/HkStatCard.scss +73 -0
  197. package/src/components/HkStatCard.tsx +46 -0
  198. package/src/components/HkStatusBar.test.tsx +178 -0
  199. package/src/components/HkStatusBar.tsx +379 -0
  200. package/src/components/HkStatusPill.scss +73 -0
  201. package/src/components/HkStatusPill.tsx +41 -0
  202. package/src/components/HkStepFlow.scss +75 -0
  203. package/src/components/HkStepFlow.test.tsx +246 -0
  204. package/src/components/HkStepFlow.tsx +115 -0
  205. package/src/components/HkSwitch.scss +5 -17
  206. package/src/components/HkSwitch.tsx +6 -3
  207. package/src/components/HkTable.scss +20 -1
  208. package/src/components/HkTable.tsx +28 -3
  209. package/src/components/HkTabs.scss +222 -48
  210. package/src/components/HkTabs.test.ts +517 -0
  211. package/src/components/HkTabs.tsx +567 -56
  212. package/src/components/HkTag.tsx +2 -1
  213. package/src/components/HkTextarea.tsx +5 -0
  214. package/src/components/HkThemeToggle.scss +232 -0
  215. package/src/components/HkThemeToggle.test.ts +231 -0
  216. package/src/components/HkThemeToggle.tsx +289 -0
  217. package/src/components/HkTimeline.scss +134 -1
  218. package/src/components/HkTimeline.test.tsx +319 -0
  219. package/src/components/HkTimeline.tsx +303 -54
  220. package/src/components/HkToast.scss +34 -5
  221. package/src/components/HkToast.test.tsx +109 -0
  222. package/src/components/HkToast.tsx +57 -8
  223. package/src/components/HkTokenUsageBadge.scss +53 -0
  224. package/src/components/HkTokenUsageBadge.test.tsx +59 -0
  225. package/src/components/HkTokenUsageBadge.tsx +54 -0
  226. package/src/components/HkTokenUsagePanel.scss +95 -0
  227. package/src/components/HkTokenUsagePanel.tsx +140 -0
  228. package/src/components/HkToolBlock.scss +428 -0
  229. package/src/components/HkToolBlock.tsx +639 -0
  230. package/src/components/HkTooltip.scss +14 -2
  231. package/src/components/HkTooltip.tsx +25 -2
  232. package/src/components/HkTrendChart.tsx +27 -16
  233. package/src/components/HkVoiceInputPopup.scss +77 -0
  234. package/src/components/HkVoiceInputPopup.tsx +97 -0
  235. package/src/components/HkZoomToolbar.scss +4 -1
  236. package/src/components/HkZoomToolbar.tsx +7 -4
  237. package/src/components/_hikari-vars.scss +6 -0
  238. package/src/composables/highlightLanguages.ts +109 -0
  239. package/src/composables/iconRegistry.ts +127 -0
  240. package/src/composables/messaging/browserTransport.ts +96 -0
  241. package/src/composables/messaging/index.ts +204 -0
  242. package/src/composables/messaging/messaging.test.ts +256 -0
  243. package/src/composables/messaging/toastTransport.ts +26 -0
  244. package/src/composables/messaging/types.ts +115 -0
  245. package/src/composables/useActionBar.ts +66 -0
  246. package/src/composables/useAttachments.ts +154 -0
  247. package/src/composables/useConnectionProbe.ts +142 -0
  248. package/src/composables/useDeferredTransition.ts +16 -0
  249. package/src/composables/useEngineHealth.ts +69 -0
  250. package/src/composables/useHighlight.ts +124 -0
  251. package/src/composables/useMeasuredHighlight.ts +150 -0
  252. package/src/composables/useOverlayScrollbar.test.ts +221 -0
  253. package/src/composables/useOverlayScrollbar.ts +296 -0
  254. package/src/composables/usePageTitle.ts +37 -0
  255. package/src/composables/useReducedMotion.ts +34 -0
  256. package/src/composables/useResourceListModal.tsx +147 -0
  257. package/src/composables/useSafeArea.ts +137 -0
  258. package/src/composables/useSendShortcut.ts +35 -0
  259. package/src/composables/useSizeMorph.test.ts +156 -0
  260. package/src/composables/useSizeMorph.ts +149 -0
  261. package/src/composables/useSurfaceTransition.test.ts +96 -0
  262. package/src/composables/useSurfaceTransition.ts +71 -0
  263. package/src/composables/useZoomPan.ts +192 -0
  264. package/src/demo.scss +9 -1
  265. package/src/demo.ts +5 -1
  266. package/src/i18n/locales/ar/chat.json +38 -0
  267. package/src/i18n/locales/ar/components.json +141 -40
  268. package/src/i18n/locales/ar/components.toml +59 -0
  269. package/src/i18n/locales/ar/platform.json +65 -0
  270. package/src/i18n/locales/de/chat.json +38 -0
  271. package/src/i18n/locales/de/components.json +139 -38
  272. package/src/i18n/locales/de/components.toml +59 -0
  273. package/src/i18n/locales/de/platform.json +65 -0
  274. package/src/i18n/locales/en/chat.json +38 -0
  275. package/src/i18n/locales/en/components.json +104 -3
  276. package/src/i18n/locales/en/components.toml +59 -0
  277. package/src/i18n/locales/en/platform.json +65 -0
  278. package/src/i18n/locales/es/chat.json +38 -0
  279. package/src/i18n/locales/es/components.json +141 -40
  280. package/src/i18n/locales/es/components.toml +59 -0
  281. package/src/i18n/locales/es/platform.json +65 -0
  282. package/src/i18n/locales/fr/chat.json +38 -0
  283. package/src/i18n/locales/fr/components.json +137 -36
  284. package/src/i18n/locales/fr/components.toml +59 -0
  285. package/src/i18n/locales/fr/platform.json +65 -0
  286. package/src/i18n/locales/ja/chat.json +38 -0
  287. package/src/i18n/locales/ja/components.json +104 -3
  288. package/src/i18n/locales/ja/components.toml +59 -0
  289. package/src/i18n/locales/ja/platform.json +65 -0
  290. package/src/i18n/locales/ko/chat.json +38 -0
  291. package/src/i18n/locales/ko/components.json +104 -3
  292. package/src/i18n/locales/ko/components.toml +59 -0
  293. package/src/i18n/locales/ko/platform.json +65 -0
  294. package/src/i18n/locales/pt/chat.json +38 -0
  295. package/src/i18n/locales/pt/components.json +141 -40
  296. package/src/i18n/locales/pt/components.toml +59 -0
  297. package/src/i18n/locales/pt/platform.json +65 -0
  298. package/src/i18n/locales/ru/chat.json +38 -0
  299. package/src/i18n/locales/ru/components.json +141 -40
  300. package/src/i18n/locales/ru/components.toml +59 -0
  301. package/src/i18n/locales/ru/platform.json +65 -0
  302. package/src/i18n/locales/zh-Hans/chat.json +38 -0
  303. package/src/i18n/locales/zh-Hans/components.json +109 -4
  304. package/src/i18n/locales/zh-Hans/components.toml +59 -0
  305. package/src/i18n/locales/zh-Hans/platform.json +65 -0
  306. package/src/i18n/locales/zh-Hant/chat.json +38 -0
  307. package/src/i18n/locales/zh-Hant/components.json +109 -4
  308. package/src/i18n/locales/zh-Hant/components.toml +59 -0
  309. package/src/i18n/locales/zh-Hant/platform.json +65 -0
  310. package/src/index.ts +225 -6
  311. package/src/plugins/bootScriptsPlugin.ts +47 -0
  312. package/src/plugins/buildHashPlugin.ts +67 -0
  313. package/src/plugins/index.ts +2 -0
  314. package/src/render.ts +1 -1
  315. package/src/runtime/animationBus.test.ts +112 -0
  316. package/src/runtime/animationBus.ts +33 -2
  317. package/src/runtime/backStack.test.ts +334 -0
  318. package/src/runtime/backStack.ts +377 -0
  319. package/src/runtime/env.ts +4 -0
  320. package/src/runtime/index.ts +15 -3
  321. package/src/runtime/intervalBus.test.ts +118 -0
  322. package/src/runtime/intervalBus.ts +189 -0
  323. package/src/runtime/mobileViewport.test.ts +132 -0
  324. package/src/runtime/mobileViewport.ts +157 -0
  325. package/src/runtime/pageLifecycle.ts +91 -0
  326. package/src/runtime/useBlockingToast.ts +112 -0
  327. package/src/runtime/useClipboard.ts +28 -0
  328. package/src/runtime/useConfirm.ts +15 -7
  329. package/src/runtime/useMediaQuery.test.ts +67 -0
  330. package/src/runtime/useMediaQuery.ts +89 -0
  331. package/src/runtime/useOverlay.test.ts +160 -0
  332. package/src/runtime/useOverlay.ts +59 -12
  333. package/src/runtime/usePopupManager.test.ts +200 -0
  334. package/src/runtime/usePopupManager.ts +106 -10
  335. package/src/runtime/useToast.test.ts +90 -0
  336. package/src/runtime/useToast.ts +20 -2
  337. package/src/styles/admin-tokens.scss +744 -0
  338. package/src/styles/index.scss +5 -3
  339. package/src/styles/theme/_glass.scss +33 -0
  340. package/src/styles/theme/_layout.scss +123 -0
  341. package/src/styles/theme/_scrollbar.scss +73 -0
  342. package/src/styles/theme/_tokens.scss +69 -0
  343. package/src/styles/theme/base.scss +617 -0
  344. package/src/styles/theme/foundation.scss +219 -0
  345. package/src/styles/theme/mixins.scss +793 -0
  346. package/src/styles/theme/themes.scss +25 -0
  347. package/src/styles/theme/variables.scss +125 -0
  348. package/src/theme/_field.scss +116 -0
  349. package/src/theme/fontContext.test.ts +179 -0
  350. package/src/theme/fontContext.ts +169 -0
  351. package/src/theme/index.ts +19 -2
  352. package/src/theme/presets.ts +86 -18
  353. package/src/theme/theme.scss +61 -1
  354. package/src/theme/tokenGroups.test.ts +534 -0
  355. package/src/theme/tokenGroups.ts +552 -0
  356. package/src/theme/useSolarTime.test.ts +113 -0
  357. package/src/theme/useSolarTime.ts +95 -20
  358. package/src/theme/useTheme.test.ts +72 -0
  359. package/src/theme/useTheme.ts +144 -9
  360. package/src/tokens.scss +110 -0
  361. package/src/utils/base64.ts +31 -0
  362. package/src/utils/connectivity.ts +51 -0
  363. package/src/utils/dom.test.ts +131 -0
  364. package/src/utils/dom.ts +133 -0
  365. package/src/utils/download.ts +22 -0
  366. package/src/utils/fileType.ts +127 -0
  367. package/src/utils/format.ts +98 -0
  368. package/src/utils/fuzzy.ts +77 -0
  369. package/src/utils/fuzzySearch.test.ts +87 -0
  370. package/src/utils/healthProbe.ts +64 -0
  371. package/src/utils/objectPath.ts +59 -0
  372. package/src/utils/password.ts +53 -0
  373. package/src/utils/pow.test.ts +45 -0
  374. package/src/utils/pow.ts +226 -0
  375. package/src/utils/powNonce.ts +95 -0
  376. package/src/utils/validation.test.ts +78 -0
  377. package/src/DemoApp.vue +0 -400
  378. package/src/components/HkCollapse.tsx +0 -48
  379. package/src/components/HkMorphingTabs.scss +0 -141
  380. package/src/components/HkMorphingTabs.tsx +0 -113
  381. package/src/composables/useBreakpoint.ts +0 -41
  382. package/src/composables/useClipboard.ts +0 -37
  383. package/src/composables/useConfirm.ts +0 -35
  384. package/src/composables/useToast.ts +0 -2
  385. package/src/runtime/useAsyncData.ts +0 -30
@@ -0,0 +1,103 @@
1
+ // CSS animation registrar (动画注册商).
2
+ //
3
+ // Every keyframes animation shipped by hikari is registered here so a
4
+ // single global switch can suspend them all — e.g. when the animation
5
+ // context detects performance problems — without each component
6
+ // re-implementing reduced-motion handling. The runtime frame scheduler
7
+ // (`runtime/animationBus.ts`) covers JS-driven animation; this registry
8
+ // complements it for pure-CSS animations.
9
+ //
10
+ // The switch works by flipping `html[data-css-animations]` between "0"
11
+ // and "1"; the pause rules live in `theme/theme.scss`.
12
+
13
+ export interface CssAnimationOptions {
14
+ /** True for looping animations (`animation-iteration-count: infinite`). */
15
+ infinite?: boolean;
16
+ }
17
+
18
+ export interface RegisteredCssAnimation {
19
+ name: string;
20
+ infinite: boolean;
21
+ }
22
+
23
+ const registry = new Map<string, RegisteredCssAnimation>();
24
+
25
+ /**
26
+ * Register a CSS keyframes animation. Idempotent: re-registering the
27
+ * same name overwrites the previous entry.
28
+ */
29
+ export function registerCssAnimation(name: string, opts?: CssAnimationOptions): RegisteredCssAnimation {
30
+ const entry: RegisteredCssAnimation = { name, infinite: opts?.infinite ?? false };
31
+ registry.set(name, entry);
32
+ return entry;
33
+ }
34
+
35
+ /** All registered CSS animations, sorted by name for stable output. */
36
+ export function listCssAnimations(): RegisteredCssAnimation[] {
37
+ return Array.from(registry.values()).sort((a, b) => a.name.localeCompare(b.name));
38
+ }
39
+
40
+ /**
41
+ * Flip the global CSS animation switch. `false` sets
42
+ * `html[data-css-animations="0"]`, which pauses every registered (and
43
+ * any unregistered) keyframes animation via `animation-play-state` and
44
+ * downgrades smooth scrolling — see `theme/theme.scss`.
45
+ *
46
+ * No-op on the server (no `document`).
47
+ */
48
+ export function setCssAnimationsEnabled(enabled: boolean): void {
49
+ if (typeof document === "undefined") return;
50
+ document.documentElement.dataset.cssAnimations = enabled ? "1" : "0";
51
+ }
52
+
53
+ /** Current switch state; `true` when animations are enabled (or unknown). */
54
+ export function isCssAnimationsEnabled(): boolean {
55
+ if (typeof document === "undefined") return true;
56
+ return document.documentElement.dataset.cssAnimations !== "0";
57
+ }
58
+
59
+ // ── Centralized registrations ────────────────────────────────────────
60
+ // One line per keyframes animation declared under packages/vue/src, with
61
+ // the owning component noted. Keep this list in sync with the SCSS
62
+ // sources — `registerAnimations.test.ts` enforces the parity by parsing
63
+ // every `@keyframes` declaration from the source tree.
64
+
65
+ // styles/admin-tokens.scss — nav badge pulse (loops forever).
66
+ registerCssAnimation("s-nav-item-badge-pulse", { infinite: true });
67
+ // styles/admin-tokens.scss — auth card entrance (plays once).
68
+ registerCssAnimation("s-auth-card-in");
69
+ // components/HkStatusPill.scss — live-dot pulse (loops forever).
70
+ registerCssAnimation("hk-status-pill-pulse", { infinite: true });
71
+ // components/HkRollingNumber.scss — digit roll-up (plays once, forwards).
72
+ registerCssAnimation("hk-rolling-number-up");
73
+ // components/HkSpinner.scss — spinner rotation (loops forever).
74
+ registerCssAnimation("hk-spinner-rotate", { infinite: true });
75
+ // components/HkModalBreadcrumb.scss — breadcrumb entrance (plays once).
76
+ registerCssAnimation("hk-modal-breadcrumb-in");
77
+ // components/HkToast.scss — toast spinner rotation (loops forever).
78
+ registerCssAnimation("hk-toast-spin", { infinite: true });
79
+ // components/HkSkeleton.scss — skeleton shimmer (loops forever).
80
+ registerCssAnimation("hk-skeleton-shimmer", { infinite: true });
81
+ // components/HkProgressBar.scss — indeterminate bar sweep (loops forever).
82
+ registerCssAnimation("hk-progress-indeterminate", { infinite: true });
83
+ // components/HkPasswordInput.scss — caps-lock warning flash (plays once).
84
+ registerCssAnimation("hk-pwd-flash");
85
+ // components/HkPasswordInput.scss — breathing hint glow (loops forever).
86
+ registerCssAnimation("hk-pwd-breathe", { infinite: true });
87
+ // components/HkPickerPane.scss — date/time picker view drill forward
88
+ // (plays once, shared by HkDatePicker and HkDateTimePicker).
89
+ registerCssAnimation("hk-picker-pane-fwd-in");
90
+ registerCssAnimation("hk-picker-pane-fwd-out");
91
+ // components/HkPickerPane.scss — date/time picker view drill back.
92
+ registerCssAnimation("hk-picker-pane-back-in");
93
+ registerCssAnimation("hk-picker-pane-back-out");
94
+ // components/HkCountdownDigit.tsx — countdown digit flip swap (plays
95
+ // once; keyframes ride the component's inline <style>).
96
+ registerCssAnimation("hk-flip-out");
97
+ registerCssAnimation("hk-flip-in");
98
+ // components/HkVoiceInputPopup.scss — voice waveform bounce (loops
99
+ // forever while listening; upstreamed from chest's plana-legacy).
100
+ registerCssAnimation("s-voice-wave-bounce", { infinite: true });
101
+ // components/HkPlaceholderMarquee.scss — overflowing placeholder sweep
102
+ // (loops forever; pure CSS, loop geometry on inline custom properties).
103
+ registerCssAnimation("hk-placeholder-marquee-scroll", { infinite: true });
@@ -0,0 +1,95 @@
1
+ // Use theme variables with namespace to avoid conflicts
2
+ @use "./hikari-vars" as vars;
3
+
4
+ .s-about-modal {
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: var(--space-16, 1rem);
8
+ }
9
+
10
+ .s-about-modal-header {
11
+ display: flex;
12
+ align-items: center;
13
+ gap: var(--space-12, 0.75rem);
14
+ }
15
+
16
+ .s-about-modal-logo {
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ width: 3rem;
21
+ height: 3rem;
22
+ flex-shrink: 0;
23
+ border-radius: var(--radius-lg, 12px);
24
+ background: rgb(var(--color-primary));
25
+ color: rgb(var(--color-on-solid-text, 255 255 255));
26
+ font-size: var(--text-lg, 1.125rem);
27
+ font-weight: 700;
28
+ }
29
+
30
+ .s-about-modal-name {
31
+ margin: 0;
32
+ font-size: var(--text-lg, 1.125rem);
33
+ font-weight: 700;
34
+ color: rgb(var(--color-text));
35
+ }
36
+
37
+ .s-about-modal-version {
38
+ margin: var(--space-4, 0.25rem) 0 0;
39
+ font-size: var(--text-sm, 0.8125rem);
40
+ color: rgb(var(--color-muted));
41
+ }
42
+
43
+ .s-about-modal-rows {
44
+ display: flex;
45
+ flex-direction: column;
46
+ gap: var(--space-8, 0.5rem);
47
+ }
48
+
49
+ .s-about-modal-row {
50
+ display: flex;
51
+ align-items: center;
52
+ justify-content: space-between;
53
+ gap: var(--space-8, 0.5rem);
54
+ }
55
+
56
+ .s-about-modal-row-label {
57
+ font-size: var(--text-sm, 0.8125rem);
58
+ color: rgb(var(--color-muted));
59
+ }
60
+
61
+ .s-about-modal-row-value {
62
+ font-size: var(--text-sm, 0.8125rem);
63
+ color: rgb(var(--color-text));
64
+ font-family: var(--font-mono, vars.$hikari-font-family-mono);
65
+ }
66
+
67
+ .s-about-modal-links {
68
+ display: flex;
69
+ flex-direction: column;
70
+ gap: var(--space-8, 0.5rem);
71
+ }
72
+
73
+ .s-about-modal-links-list {
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ gap: var(--space-8, 0.5rem);
77
+ }
78
+
79
+ .s-about-modal-link {
80
+ padding: var(--space-4, 0.25rem) var(--space-8, 0.5rem);
81
+ border-radius: var(--radius-sm, 6px);
82
+ background: rgb(var(--color-primary) / 12%);
83
+ color: rgb(var(--color-primary));
84
+ font-size: var(--text-xs, 0.75rem);
85
+ text-decoration: none;
86
+ }
87
+
88
+ .s-about-modal-link:hover {
89
+ background: rgb(var(--color-primary) / 20%);
90
+ }
91
+
92
+ .s-about-modal-footer {
93
+ display: flex;
94
+ justify-content: flex-end;
95
+ }
@@ -0,0 +1,114 @@
1
+ import { defineComponent, type PropType } from "vue";
2
+ import { HBadge, HModal } from "@celestia-island/hikari";
3
+
4
+ import { useI18n } from "../i18n/context";
5
+
6
+ import "./HkAboutModal.scss";
7
+
8
+ export interface HAboutLink {
9
+ label: string;
10
+ href: string;
11
+ }
12
+
13
+ /**
14
+ * HkAboutModal — version / about dialog.
15
+ * (Upstreamed from shittim-chest's plana-legacy layer.)
16
+ *
17
+ * Shows the app identity and version metadata plus optional external
18
+ * links. Version/build hashes render as short hashes when longer than 12
19
+ * chars (full value in `title` tooltip).
20
+ */
21
+ export const HkAboutModal = defineComponent({
22
+ name: "HkAboutModal",
23
+ props: {
24
+ modelValue: { type: Boolean, default: false },
25
+ /** Application display name. */
26
+ appName: { type: String, required: true },
27
+ /** Application version (e.g. "0.1.4"). */
28
+ version: { type: String, required: true },
29
+ /** Optional app build hash / commit. */
30
+ buildHash: { type: String, default: undefined },
31
+ /** Optional engine version (backend), e.g. "0.2.1". */
32
+ engineVersion: { type: String, default: undefined },
33
+ /** Optional engine build hash / commit. */
34
+ engineBuildHash: { type: String, default: undefined },
35
+ /** Optional external links (e.g. GitHub, docs). */
36
+ links: { type: Array as PropType<HAboutLink[]>, default: () => [] },
37
+ title: { type: String, default: undefined },
38
+ },
39
+ emits: {
40
+ "update:modelValue": (_v: boolean) => true,
41
+ },
42
+ setup(props, { emit }) {
43
+ const { t } = useI18n();
44
+
45
+ function shortHash(hash: string): string {
46
+ return hash.length > 12 ? `${hash.slice(0, 12)}…` : hash;
47
+ }
48
+
49
+ return () => (
50
+ <HModal
51
+ modelValue={props.modelValue}
52
+ onUpdate:modelValue={(v: boolean) => emit("update:modelValue", v)}
53
+ title={props.title ?? t("hikari::about.title", "About")}
54
+ width="30rem"
55
+ >
56
+ <div class="s-about-modal">
57
+ <header class="s-about-modal-header">
58
+ <div class="s-about-modal-logo">{props.appName.slice(0, 1).toUpperCase()}</div>
59
+ <div>
60
+ <h2 class="s-about-modal-name">{props.appName}</h2>
61
+ <p class="s-about-modal-version">
62
+ {t("hikari::about.version", "Version")} {props.version}
63
+ </p>
64
+ </div>
65
+ </header>
66
+
67
+ <div class="s-about-modal-rows">
68
+ {props.buildHash && (
69
+ <div class="s-about-modal-row">
70
+ <span class="s-about-modal-row-label">{t("hikari::about.buildHash", "Build")}</span>
71
+ <span class="s-about-modal-row-value" title={props.buildHash}>
72
+ {shortHash(props.buildHash)}
73
+ </span>
74
+ </div>
75
+ )}
76
+ {props.engineVersion && (
77
+ <div class="s-about-modal-row">
78
+ <span class="s-about-modal-row-label">{t("hikari::about.engineVersion", "Engine version")}</span>
79
+ <span class="s-about-modal-row-value">{props.engineVersion}</span>
80
+ </div>
81
+ )}
82
+ {props.engineBuildHash && (
83
+ <div class="s-about-modal-row">
84
+ <span class="s-about-modal-row-label">{t("hikari::about.engineBuildHash", "Engine build")}</span>
85
+ <span class="s-about-modal-row-value" title={props.engineBuildHash}>
86
+ {shortHash(props.engineBuildHash)}
87
+ </span>
88
+ </div>
89
+ )}
90
+ </div>
91
+
92
+ {props.links.length > 0 && (
93
+ <div class="s-about-modal-links">
94
+ <span class="s-about-modal-row-label">{t("hikari::about.links", "Links")}</span>
95
+ <div class="s-about-modal-links-list">
96
+ {props.links.map((link) => (
97
+ <a key={link.href} href={link.href} target="_blank" rel="noopener noreferrer" class="s-about-modal-link">
98
+ {link.label}
99
+ </a>
100
+ ))}
101
+ </div>
102
+ </div>
103
+ )}
104
+
105
+ <footer class="s-about-modal-footer">
106
+ <HBadge variant="muted">
107
+ © {new Date().getFullYear()} {props.appName}
108
+ </HBadge>
109
+ </footer>
110
+ </div>
111
+ </HModal>
112
+ );
113
+ },
114
+ });
@@ -0,0 +1,22 @@
1
+ // HkAdaptiveDialog — only the seams the two shells cannot provide
2
+ // themselves: the composed drawer header (title + sub-header stacked in
3
+ // HkDrawer's header slot, which otherwise replaces the title) and the
4
+ // footerActions HButton row rendered inside HkDrawer's footer (HkModal
5
+ // already renders that row itself; HkDrawer has no footerActions prop).
6
+ // Everything visual (overlay, panel, transitions, footer padding and
7
+ // divider) comes from HkModal.scss / HkDrawer.scss.
8
+
9
+ .hk-adaptive-dialog-drawer-header {
10
+ display: flex;
11
+ flex-direction: column;
12
+ align-items: flex-start;
13
+ gap: var(--hi-space-4, 4px);
14
+ flex: 1;
15
+ min-width: 0;
16
+ }
17
+
18
+ .hk-adaptive-dialog-footer {
19
+ display: flex;
20
+ justify-content: flex-end;
21
+ gap: var(--hi-space-8, 8px);
22
+ }
@@ -0,0 +1,271 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { createApp, defineComponent, h, nextTick, ref } from "vue";
3
+
4
+ import HkAdaptiveDialog from "./HkAdaptiveDialog";
5
+ import { setLocale } from "../i18n/context";
6
+ import { usePopupManager } from "../runtime/usePopupManager";
7
+
8
+ /**
9
+ * HkAdaptiveDialog contract tests:
10
+ * - desktop width renders the HkModal shell, mobile width renders the
11
+ * HkDrawer side="bottom" shell, and the shell flips live on resize
12
+ * - the v-model / update:modelValue contract round-trips in both shells
13
+ * - footerActions render in both shells (same order/labels/handlers)
14
+ * - the footer slot wins over footerActions (HkModal's precedence)
15
+ * - afterLeave is forwarded from the active shell
16
+ *
17
+ * (Repo test convention: raw createApp + document queries, no
18
+ * @vue/test-utils dependency.)
19
+ */
20
+
21
+ const mounts: Array<{ app: ReturnType<typeof createApp>; container: HTMLElement }> = [];
22
+ const originalWidth = window.innerWidth;
23
+
24
+ const setWidth = (w: number) => {
25
+ Object.defineProperty(window, "innerWidth", {
26
+ configurable: true,
27
+ writable: true,
28
+ value: w,
29
+ });
30
+ window.dispatchEvent(new Event("resize"));
31
+ };
32
+
33
+ interface DialogHarness {
34
+ container: HTMLElement;
35
+ open: ReturnType<typeof ref<boolean>>;
36
+ emitted: Array<string | null>;
37
+ afterLeaveCount: () => number;
38
+ unmount: () => void;
39
+ }
40
+
41
+ function mountDialog(
42
+ props: Record<string, unknown> = {},
43
+ slots: Record<string, unknown> = {},
44
+ ): DialogHarness {
45
+ const container = document.createElement("div");
46
+ document.body.appendChild(container);
47
+
48
+ const open = ref(true);
49
+ const emitted: Array<string | null> = [];
50
+ const Wrapper = defineComponent({
51
+ setup() {
52
+ return () =>
53
+ h(HkAdaptiveDialog, {
54
+ title: "Test dialog",
55
+ ...props,
56
+ modelValue: open.value,
57
+ "onUpdate:modelValue": (v: boolean) => {
58
+ emitted.push(String(v));
59
+ open.value = v;
60
+ },
61
+ "onAfterLeave": () => {
62
+ emitted.push("afterLeave");
63
+ },
64
+ } as never, slots as never);
65
+ },
66
+ });
67
+
68
+ const app = createApp(Wrapper);
69
+ const entry = { app, container };
70
+ mounts.push(entry);
71
+ app.mount(container);
72
+ return {
73
+ container,
74
+ open,
75
+ emitted,
76
+ afterLeaveCount: () => emitted.filter((e) => e === "afterLeave").length,
77
+ unmount: () => {
78
+ const idx = mounts.indexOf(entry);
79
+ if (idx !== -1) mounts.splice(idx, 1);
80
+ app.unmount();
81
+ container.remove();
82
+ },
83
+ };
84
+ }
85
+
86
+ /** Let Vue's enter/leave transitions (frame/timeout based) settle in happy-dom. */
87
+ async function settle() {
88
+ await nextTick();
89
+ await new Promise((r) => setTimeout(r, 30));
90
+ await nextTick();
91
+ }
92
+
93
+ function modalContent(): HTMLElement | null {
94
+ return document.querySelector<HTMLElement>(".hk-modal-content");
95
+ }
96
+
97
+ function drawerPanel(): HTMLElement | null {
98
+ return document.querySelector<HTMLElement>(".hk-drawer-panel");
99
+ }
100
+
101
+ function footerButtons(root: ParentNode): HTMLButtonElement[] {
102
+ return Array.from(root.querySelectorAll<HTMLButtonElement>("button")).filter(
103
+ (b) => !b.classList.contains("hk-modal-close") && !b.classList.contains("hk-drawer-close"),
104
+ );
105
+ }
106
+
107
+ afterEach(async () => {
108
+ for (const { app, container } of mounts.splice(0)) {
109
+ app.unmount();
110
+ container.remove();
111
+ }
112
+ document.querySelectorAll(".hk-modal-root, .hk-drawer-overlay, [class^='hk-drawer-panel']").forEach((el) => el.remove());
113
+ setWidth(originalWidth);
114
+ await setLocale("en");
115
+ });
116
+
117
+ describe("HkAdaptiveDialog", () => {
118
+ it("renders the modal shell at desktop width and registers kind modal", () => {
119
+ setWidth(1280);
120
+ mountDialog();
121
+ expect(modalContent()).toBeTruthy();
122
+ expect(drawerPanel()).toBeNull();
123
+
124
+ const entries = [...usePopupManager().registry.value.values()];
125
+ expect(entries.some((e) => e.kind === "modal" && e.title === "Test dialog")).toBe(true);
126
+ expect(entries.some((e) => e.kind === "drawer")).toBe(false);
127
+ });
128
+
129
+ it("renders the bottom drawer shell at mobile width and registers kind drawer", () => {
130
+ setWidth(375);
131
+ mountDialog();
132
+ const panel = drawerPanel();
133
+ expect(panel).toBeTruthy();
134
+ expect(panel!.classList.contains("hk-drawer-bottom")).toBe(true);
135
+ expect(modalContent()).toBeNull();
136
+ // No footer slot and no footerActions -> no empty footer band.
137
+ expect(document.querySelector(".hk-drawer-footer")).toBeNull();
138
+
139
+ const entries = [...usePopupManager().registry.value.values()];
140
+ expect(entries.some((e) => e.kind === "drawer")).toBe(true);
141
+ expect(entries.some((e) => e.kind === "modal")).toBe(false);
142
+ });
143
+
144
+ it("flips the shell live when the viewport crosses the breakpoint", async () => {
145
+ setWidth(1280);
146
+ mountDialog();
147
+ expect(modalContent()).toBeTruthy();
148
+ expect(drawerPanel()).toBeNull();
149
+
150
+ setWidth(375);
151
+ await nextTick();
152
+ await settle();
153
+ expect(drawerPanel()).toBeTruthy();
154
+ expect(modalContent()).toBeNull();
155
+
156
+ setWidth(1280);
157
+ await nextTick();
158
+ await settle();
159
+ expect(modalContent()).toBeTruthy();
160
+ expect(drawerPanel()).toBeNull();
161
+ });
162
+
163
+ it("round-trips v-model through the modal shell (close button + reopen)", async () => {
164
+ setWidth(1280);
165
+ const harness = mountDialog();
166
+ expect(modalContent()).toBeTruthy();
167
+
168
+ document.querySelector<HTMLElement>(".hk-modal-close")!.click();
169
+ await settle();
170
+ expect(harness.emitted).toContain("false");
171
+ expect(modalContent()).toBeNull();
172
+
173
+ harness.open.value = true;
174
+ await settle();
175
+ expect(modalContent()).toBeTruthy();
176
+ });
177
+
178
+ it("round-trips v-model through the drawer shell and forwards afterLeave", async () => {
179
+ setWidth(375);
180
+ const harness = mountDialog();
181
+ expect(drawerPanel()).toBeTruthy();
182
+
183
+ document.querySelector<HTMLElement>(".hk-drawer-close")!.click();
184
+ await settle();
185
+ expect(harness.emitted).toContain("false");
186
+ expect(drawerPanel()).toBeNull();
187
+ expect(harness.afterLeaveCount()).toBeGreaterThan(0);
188
+
189
+ harness.open.value = true;
190
+ await settle();
191
+ expect(drawerPanel()).toBeTruthy();
192
+ });
193
+
194
+ it("closes on Escape through the drawer shell", async () => {
195
+ setWidth(375);
196
+ const harness = mountDialog();
197
+ const panel = drawerPanel()!;
198
+ panel.dispatchEvent(new KeyboardEvent("keydown", { key: "Escape", bubbles: true }));
199
+ await settle();
200
+ expect(harness.emitted).toContain("false");
201
+ });
202
+
203
+ it("renders footerActions in the modal footer", () => {
204
+ setWidth(1280);
205
+ mountDialog({
206
+ footerActions: [
207
+ { label: "Keep", variant: "secondary" },
208
+ { label: "Delete", variant: "danger" },
209
+ ],
210
+ });
211
+ const labels = footerButtons(document).map((b) => b.textContent?.trim());
212
+ expect(labels).toEqual(["Keep", "Delete"]);
213
+ });
214
+
215
+ it("renders footerActions as an equivalent button row in the drawer footer", () => {
216
+ setWidth(375);
217
+ const clicked: string[] = [];
218
+ mountDialog({
219
+ footerActions: [
220
+ { label: "Keep", variant: "secondary", onClick: () => clicked.push("keep") },
221
+ { label: "Delete", variant: "danger", onClick: () => clicked.push("delete") },
222
+ ],
223
+ });
224
+ const footer = document.querySelector<HTMLElement>(".hk-drawer-footer");
225
+ expect(footer).toBeTruthy();
226
+ const row = footer!.querySelector<HTMLElement>(".hk-adaptive-dialog-footer");
227
+ expect(row).toBeTruthy();
228
+
229
+ const labels = footerButtons(footer!).map((b) => b.textContent?.trim());
230
+ expect(labels).toEqual(["Keep", "Delete"]);
231
+
232
+ footerButtons(footer!)[1].click();
233
+ expect(clicked).toEqual(["delete"]);
234
+ });
235
+
236
+ it("lets the footer slot win over footerActions in both shells", () => {
237
+ const slots = { footer: () => h("div", { class: "custom-footer" }, "CUSTOM") };
238
+ const actions = [{ label: "SlotShouldWin" }];
239
+
240
+ setWidth(1280);
241
+ const desktop = mountDialog({ footerActions: actions }, slots);
242
+ expect(document.querySelector(".hk-modal-footer .custom-footer")).toBeTruthy();
243
+ expect(footerButtons(document).map((b) => b.textContent?.trim())).toEqual([]);
244
+ desktop.unmount();
245
+
246
+ setWidth(375);
247
+ const mobile = mountDialog({ footerActions: actions }, slots);
248
+ const footer = document.querySelector<HTMLElement>(".hk-drawer-footer")!;
249
+ expect(footer.querySelector(".custom-footer")).toBeTruthy();
250
+ expect(footerButtons(footer).map((b) => b.textContent?.trim())).toEqual([]);
251
+ mobile.unmount();
252
+ });
253
+
254
+ it("maps the header slot to the modal sub-header and keeps the drawer title bar", () => {
255
+ const slots = { header: () => h("div", { class: "custom-header" }, "SUB") };
256
+
257
+ setWidth(1280);
258
+ const desktop = mountDialog({}, slots);
259
+ expect(document.querySelector(".hk-modal-subheader .custom-header")).toBeTruthy();
260
+ expect(document.querySelector<HTMLElement>(".hk-modal-title")!.textContent).toContain("Test dialog");
261
+ desktop.unmount();
262
+
263
+ setWidth(375);
264
+ const mobile = mountDialog({}, slots);
265
+ const composed = document.querySelector<HTMLElement>(".hk-adaptive-dialog-drawer-header");
266
+ expect(composed).toBeTruthy();
267
+ expect(composed!.querySelector(".hk-drawer-title")!.textContent).toContain("Test dialog");
268
+ expect(composed!.querySelector(".custom-header")).toBeTruthy();
269
+ mobile.unmount();
270
+ });
271
+ });