@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,61 @@
1
+ .s-secret-modal {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--space-12, 0.75rem);
5
+ }
6
+
7
+ .s-secret-modal-notice {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: var(--space-8, 0.5rem);
11
+ padding: var(--space-8, 0.5rem) var(--space-12, 0.75rem);
12
+ border-radius: var(--radius-md, 8px);
13
+ background: rgb(var(--color-warning) / 12%);
14
+ color: rgb(var(--color-warning));
15
+ font-size: var(--text-xs, 0.75rem);
16
+ }
17
+
18
+ .s-secret-modal-value {
19
+ display: block;
20
+ padding: var(--space-12, 0.75rem);
21
+ border-radius: var(--radius-md, 8px);
22
+ background: rgb(var(--color-surface) / 0.6);
23
+ border: 1px solid var(--border-faint, rgb(var(--color-border) / 12%));
24
+ color: rgb(var(--color-text));
25
+ font-size: var(--text-sm, 0.8125rem);
26
+ word-break: break-all;
27
+ white-space: pre-wrap;
28
+ }
29
+
30
+ .s-secret-modal-actions {
31
+ display: flex;
32
+ justify-content: flex-end;
33
+ }
34
+
35
+ .s-secret-modal-copy {
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: var(--space-6, 0.375rem);
39
+ padding: var(--space-6, 0.375rem) var(--space-12, 0.75rem);
40
+ border: none;
41
+ border-radius: var(--radius-sm, 6px);
42
+ background: rgb(var(--color-primary));
43
+ color: rgb(var(--color-on-solid-text, 255 255 255));
44
+ font-size: var(--text-sm, 0.8125rem);
45
+ font-weight: 600;
46
+ cursor: pointer;
47
+ }
48
+
49
+ .s-secret-modal-copy:hover {
50
+ filter: brightness(1.1);
51
+ }
52
+
53
+ .s-secret-modal-copy[data-copied] {
54
+ background: rgb(var(--color-success));
55
+ color: rgb(var(--color-on-solid-text, 255 255 255));
56
+ }
57
+
58
+ .s-secret-modal-copy:disabled {
59
+ opacity: 0.5;
60
+ cursor: not-allowed;
61
+ }
@@ -0,0 +1,91 @@
1
+ import { defineComponent, ref, watch } from "vue";
2
+ import { TriangleAlert as AlertTriangle, Check, Copy } from "lucide-vue-next";
3
+ import { HModal, useClipboard, useI18n } from "@celestia-island/hikari";
4
+
5
+ import "./HkSecretRevealModal.scss";
6
+
7
+
8
+ /**
9
+ * HkSecretRevealModal — show-once secret / API-key reveal panel.
10
+ *
11
+ * Displays a one-time secret (API key, token, password) with a "shown
12
+ * only once" notice and a copy button. `copied` fires on successful copy.
13
+ * The value is a prop: the caller decides how to obtain/discard it (e.g.
14
+ * clear it once the modal closes).
15
+ */
16
+ export const HkSecretRevealModal = defineComponent({
17
+ name: "HkSecretRevealModal",
18
+ props: {
19
+ modelValue: { type: Boolean, default: false },
20
+ /** Secret label (e.g. "API Key"). */
21
+ label: { type: String, required: true },
22
+ /** The secret value to reveal. */
23
+ value: { type: String, required: true },
24
+ /** Copy button label override. */
25
+ copyLabel: { type: String, default: undefined },
26
+ /** "Shown once" notice override. */
27
+ notice: { type: String, default: undefined },
28
+ title: { type: String, default: undefined },
29
+ },
30
+ emits: {
31
+ "update:modelValue": (_v: boolean) => true,
32
+ copied: () => true,
33
+ },
34
+ setup(props, { emit }) {
35
+ const { t } = useI18n();
36
+ const clipboard = useClipboard();
37
+ const copied = ref(false);
38
+
39
+ watch(
40
+ () => props.modelValue,
41
+ (open) => {
42
+ if (open) copied.value = false;
43
+ },
44
+ );
45
+
46
+ async function handleCopy() {
47
+ if (!props.value) return;
48
+ const ok = await clipboard.copy(props.value);
49
+ if (ok) {
50
+ copied.value = true;
51
+ emit("copied");
52
+ }
53
+ }
54
+
55
+ return () => (
56
+ <HModal
57
+ modelValue={props.modelValue}
58
+ onUpdate:modelValue={(v: boolean) => emit("update:modelValue", v)}
59
+ title={props.title ?? `${props.label} — ${t("hikari::secret.title")}`}
60
+ width="34rem"
61
+ footerActions={[
62
+ {
63
+ label: t("hikari::secret.close"),
64
+ variant: "secondary",
65
+ onClick: () => emit("update:modelValue", false),
66
+ },
67
+ ]}
68
+ >
69
+ <div class="s-secret-modal">
70
+ <div class="s-secret-modal-notice">
71
+ <AlertTriangle size={14} />
72
+ <span>{props.notice ?? t("hikari::secret.notice")}</span>
73
+ </div>
74
+ <code class="s-secret-modal-value">{props.value}</code>
75
+ <div class="s-secret-modal-actions">
76
+ <button
77
+ type="button"
78
+ class="s-secret-modal-copy"
79
+ data-copied={copied.value || undefined}
80
+ onClick={() => void handleCopy()}
81
+ disabled={!props.value}
82
+ >
83
+ {copied.value ? <Check size={14} /> : <Copy size={14} />}
84
+ {copied.value ? t("hikari::secret.copied") : props.copyLabel ?? t("hikari::secret.copy")}
85
+ </button>
86
+ </div>
87
+ </div>
88
+ </HModal>
89
+ );
90
+ },
91
+ });
@@ -9,10 +9,13 @@
9
9
 
10
10
  .hk-select-label {
11
11
  display: block;
12
- font-size: var(--text-base);
13
- font-weight: 500;
14
- margin-bottom: var(--space-6);
15
- color: rgb(var(--color-text));
12
+ font-size: var(--text-xs);
13
+ font-weight: 600;
14
+ letter-spacing: 0.02em;
15
+ margin-bottom: var(--space-4);
16
+ /* 72% keeps the caption hierarchy while surviving dark-theme tinted
17
+ * surfaces; override per-app with --hk-field-label-alpha. */
18
+ color: rgb(var(--color-text) / var(--hk-field-label-alpha, 72%));
16
19
  }
17
20
 
18
21
  .hk-select-required {
@@ -26,9 +29,9 @@
26
29
  width: 100%;
27
30
  padding: var(--space-8) var(--space-32) var(--space-8) var(--space-12);
28
31
  min-height: 2.5rem;
29
- background: rgb(var(--color-surface) / var(--opacity-half));
30
- backdrop-filter: blur(var(--blur-sm));
31
- border: 1px solid var(--border-input);
32
+ background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
33
+
34
+ border: 1px solid color-mix(in srgb, rgb(var(--color-text)) 14%, transparent);
32
35
  border-radius: var(--radius-md);
33
36
  font-family: inherit;
34
37
  font-size: var(--text-base);
@@ -87,20 +90,112 @@
87
90
  transform: rotate(180deg);
88
91
  }
89
92
 
90
- .hk-select-popout {
93
+ /* Fixed positioning wrapper around the desktop popout (HkSelectPanel):
94
+ * carries the inline anchor coords + popup-manager z-index and is the
95
+ * track host for the overlay scrollbar (the popout teleports to body,
96
+ * whose box is no positioning context). Geometry-neutral: the popout
97
+ * shrink-wraps the host exactly as the popout shrink-wrapped itself
98
+ * when it was the fixed element. The 180px width floor lives HERE, not
99
+ * on the popout: matchAnchorWidth's inline `min-width` lands on the host,
100
+ * and a stylesheet floor on the CHILD would override that match for
101
+ * anchors narrower than 180px (the floor must lose to the inline style,
102
+ * which can only happen on the same element). */
103
+ .hk-select-popout-host {
91
104
  position: fixed;
92
- z-index: 1100;
93
105
  min-width: 180px;
94
- max-height: 240px;
106
+
107
+ /* Pop motion family — the popout grows out of the anchor edge it sits
108
+ * on (data-side/data-align are set by HkSelectPanel from the RESOLVED
109
+ * placement, including after an auto-flip) and retracts back into it.
110
+ * Same tokens as HkPopover/HkTooltip so every anchored surface moves
111
+ * with one curve. */
112
+ &[data-side="bottom"] { transform-origin: top left; }
113
+ &[data-side="bottom"][data-align="end"] { transform-origin: top right; }
114
+ &[data-side="top"] { transform-origin: bottom left; }
115
+ &[data-side="top"][data-align="end"] { transform-origin: bottom right; }
116
+ }
117
+
118
+ .hk-select-popout-enter-active {
119
+ transition:
120
+ opacity var(--hk-pop-in-duration, 0.2s)
121
+ var(--hk-pop-in-opacity-ease, cubic-bezier(0.16, 1, 0.3, 1)),
122
+ transform var(--hk-pop-in-duration, 0.2s)
123
+ var(--hk-pop-in-transform-ease, cubic-bezier(0.34, 1.56, 0.64, 1));
124
+ }
125
+
126
+ .hk-select-popout-leave-active {
127
+ transition:
128
+ opacity var(--hk-pop-out-duration, 0.15s)
129
+ var(--hk-pop-out-ease, cubic-bezier(0.4, 0, 1, 1)),
130
+ transform var(--hk-pop-out-duration, 0.15s)
131
+ var(--hk-pop-out-ease, cubic-bezier(0.4, 0, 1, 1));
132
+ }
133
+
134
+ .hk-select-popout-enter-from,
135
+ .hk-select-popout-leave-to {
136
+ opacity: 0;
137
+ }
138
+
139
+ .hk-select-popout-host[data-side="bottom"] {
140
+ &.hk-select-popout-enter-from {
141
+ transform: translateY(calc(-1 * var(--hk-pop-offset, 4px)))
142
+ scale(var(--hk-pop-scale, 0.97));
143
+ }
144
+ &.hk-select-popout-leave-to {
145
+ transform: translateY(var(--hk-pop-offset, 4px))
146
+ scale(var(--hk-pop-scale, 0.97));
147
+ }
148
+ }
149
+
150
+ .hk-select-popout-host[data-side="top"] {
151
+ &.hk-select-popout-enter-from {
152
+ transform: translateY(var(--hk-pop-offset, 4px))
153
+ scale(var(--hk-pop-scale, 0.97));
154
+ }
155
+ &.hk-select-popout-leave-to {
156
+ transform: translateY(calc(-1 * var(--hk-pop-offset, 4px)))
157
+ scale(var(--hk-pop-scale, 0.97));
158
+ }
159
+ }
160
+
161
+ @media (prefers-reduced-motion: reduce) {
162
+ .hk-select-popout-enter-active,
163
+ .hk-select-popout-leave-active {
164
+ transition: none;
165
+ }
166
+ }
167
+
168
+ .hk-select-popout {
169
+ /* Positioning lives on the host wrapper above — the popout is its
170
+ * static, box-filling child (width resolves from the host, whose
171
+ * floor/match rule is documented there). */
172
+ position: static;
173
+ /* Menu/switcher panels overflow a bare 240px cap even on tall viewports
174
+ (user feedback 2026-08-30: identity header + rows ≈ 320px+). Keep 240px
175
+ as the floor for select lists on short viewports, otherwise let the
176
+ panel size to its content up to a viewport-relative ceiling. */
177
+ max-height: max(240px, min(36rem, calc(100vh - 32px)));
178
+ max-height: max(240px, min(36rem, calc(100dvh - 32px)));
95
179
  display: flex;
96
180
  flex-direction: column;
97
- padding: var(--space-4);
181
+ gap: var(--space-2);
182
+ /* 8px panel inset (was 4px): option hover blocks used to run almost
183
+ edge-to-edge, reading as a glued full-width strip on touch widths. */
184
+ padding: var(--space-8);
98
185
  border-radius: var(--radius-md);
99
186
  overflow-y: auto;
100
- background: rgb(var(--color-surface) / var(--opacity-half));
187
+ background: color-mix(in srgb, rgb(var(--color-surface)) 55%, transparent);
101
188
  backdrop-filter: blur(var(--blur-md));
102
189
  border: 1px solid var(--border-subtle);
103
190
  box-shadow: var(--shadow-dropdown);
191
+
192
+ /* Overlay scrollbar (useOverlayScrollbar) — the native chrome is
193
+ always hidden, never styled. */
194
+ scrollbar-width: none;
195
+
196
+ &::-webkit-scrollbar {
197
+ display: none;
198
+ }
104
199
  }
105
200
 
106
201
  .hk-select-option {
@@ -141,3 +236,159 @@
141
236
  font-size: var(--text-xs);
142
237
  color: rgb(var(--color-error));
143
238
  }
239
+
240
+ // ------
241
+ // Mobile bottom sheet (useBreakpoint().isMobile) — the popout docks to the
242
+ // bottom edge: scrim (click closes) + grabber + label + touch-sized option
243
+ // rows. Desktop popout above is untouched. Same visual contract as the
244
+ // popover/modal mobile dockings.
245
+ // ------
246
+ .hk-select-sheet-scrim {
247
+ position: fixed;
248
+ inset: 0;
249
+ pointer-events: auto;
250
+ background: rgb(0 0 0 / 40%);
251
+ }
252
+
253
+ .hk-select-sheet-panel {
254
+ position: fixed;
255
+ left: 0;
256
+ right: 0;
257
+ /* Float off the bottom edge with the SAME host-tunable gap as the
258
+ * HkModal mobile docking (--hk-sheet-bottom-gap) — every bottom-up
259
+ * window reads as one sheet family; was glued to bottom: 0, which is
260
+ * exactly why dropdown sheets read as "not the standard modal". */
261
+ bottom: var(--hk-sheet-bottom-gap, 0.375rem);
262
+ display: flex;
263
+ flex-direction: column;
264
+ /* The panel height hugs its content (up to the cap below); the sheet
265
+ * morphs smoothly when content grows/shrinks — a language list gaining
266
+ * or losing rows, a select whose options filter. `height: auto` growth
267
+ * cannot fire a CSS transition, so HkSelectPanel's useSizeMorph pins
268
+ * the measured natural height as px (see useSizeMorph) and the
269
+ * transition below animates old→new px; `interpolate-size: allow-keywords`
270
+ * stays harmless for the enter/leave slide. */
271
+ interpolate-size: allow-keywords;
272
+ transition:
273
+ height var(--duration-fast, 0.15s) var(--ease-standard, cubic-bezier(0.4, 0, 0.2, 1)),
274
+ max-height var(--duration-fast, 0.15s) var(--ease-standard, cubic-bezier(0.4, 0, 0.2, 1));
275
+ max-height: min(
276
+ 72vh,
277
+ calc(
278
+ 100vh - var(--hk-sheet-top-inset, 4.25rem) -
279
+ var(--hk-sheet-bottom-gap, 0.375rem)
280
+ )
281
+ );
282
+ background: rgb(var(--color-surface));
283
+ border-radius: var(--hk-modal-radius, var(--hi-radius-lg, 12px))
284
+ var(--hk-modal-radius, var(--hi-radius-lg, 12px))
285
+ 0 0;
286
+ box-shadow: 0 -8px 32px rgb(0 0 0 / 20%);
287
+ outline: none;
288
+ }
289
+
290
+ .hk-select-sheet-grabber {
291
+ flex-shrink: 0;
292
+ padding: 14px 0 20px;
293
+ margin: 0 auto;
294
+ width: 100%;
295
+ cursor: pointer;
296
+ display: flex;
297
+ justify-content: center;
298
+
299
+ &::before {
300
+ content: "";
301
+ width: 2.25rem;
302
+ height: 4px;
303
+ border-radius: 999px;
304
+ background: rgb(var(--color-border, 100 100 100) / 40%);
305
+ }
306
+ }
307
+
308
+ .hk-select-sheet-title {
309
+ flex-shrink: 0;
310
+ /* Left inset tracks the sheet ENTRIES' text edge, not their card
311
+ * edge: the list pads option blocks in by --space-16 and rows carry
312
+ * roughly another --space-16 of leading padding inside, so the old
313
+ * single --space-16 left the title hanging left of every row it
314
+ * named instead of reading as the list's heading. Hosts tune it via
315
+ * --hk-sheet-title-inset; the trailing inset stays --space-16. */
316
+ padding: 0 var(--space-16) var(--space-8)
317
+ var(--hk-sheet-title-inset, calc(var(--space-16) * 2));
318
+ font-size: var(--text-xs);
319
+ font-weight: 600;
320
+ letter-spacing: 0.02em;
321
+ color: rgb(var(--color-muted));
322
+ }
323
+
324
+ /* Track host for the sheet list's overlay scrollbar — owns the flex
325
+ slot in the sheet column so the rail hugs the LIST band, not the
326
+ grabber/title bands above it. */
327
+ .hk-select-sheet-body {
328
+ flex: 1;
329
+ min-height: 0;
330
+ display: flex;
331
+ flex-direction: column;
332
+ position: relative;
333
+ }
334
+
335
+ .hk-select-sheet-list {
336
+ flex: 1;
337
+ min-height: 0;
338
+ overflow-y: auto;
339
+ overscroll-behavior: contain;
340
+ /* Side insets so the option blocks (full-row hover pills) read as
341
+ cards inside the sheet instead of an edge-to-edge strip glued to
342
+ both screen sides — matching the popover family's breathing room.
343
+ Bottom padding stacks the home-bar safe-area inset ON TOP of the
344
+ base row gap, so the last row never hides behind the gesture bar
345
+ on notched phones (the modal footer adds a --hk-sheet-footer-gap
346
+ on top of this family baseline for its action buttons). */
347
+ padding-inline: var(--space-16);
348
+ padding-bottom: calc(var(--space-16) + env(safe-area-inset-bottom, 0px));
349
+
350
+ /* Overlay scrollbar (useOverlayScrollbar) — native chrome hidden. */
351
+ scrollbar-width: none;
352
+
353
+ &::-webkit-scrollbar {
354
+ display: none;
355
+ }
356
+
357
+ .hk-select-option {
358
+ padding: var(--space-14) var(--space-16);
359
+ font-size: var(--text-base);
360
+ }
361
+ }
362
+
363
+ /* Leading in-content heading hidden by the sheet duplicate-title
364
+ * filter (HkSelectPanel) — must beat any consumer display rule, like
365
+ * the UA [hidden] contract. */
366
+ .hk-select-sheet-list .hk-sheet-dup-title {
367
+ display: none !important;
368
+ }
369
+
370
+ .hk-select-sheet-enter-active {
371
+ transition:
372
+ opacity 0.25s ease-out,
373
+ transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
374
+ }
375
+
376
+ .hk-select-sheet-leave-active {
377
+ transition:
378
+ opacity 0.2s ease-in,
379
+ transform 0.25s cubic-bezier(0.4, 0, 1, 1);
380
+ }
381
+
382
+ .hk-select-sheet-enter-from,
383
+ .hk-select-sheet-leave-to {
384
+ opacity: 0;
385
+ transform: translateY(100%);
386
+ }
387
+
388
+ @media (prefers-reduced-motion: reduce) {
389
+ .hk-select-sheet-enter-active,
390
+ .hk-select-sheet-leave-active,
391
+ .hk-select-sheet-panel {
392
+ transition: none;
393
+ }
394
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Source contract for the dropdown sheet docking (2026-08-30 user
3
+ * report: the localized input's language menu sheet "didn't look like
4
+ * it came from the standard modal"). The HkSelectPanel sheet — the
5
+ * shared surface under HkSelect / HkMenu / HkPopupSelect — must dock
6
+ * with the SAME host-tunable bottom gap and home-bar safe-area padding
7
+ * as the HkModal mobile docking, so every bottom-up window belongs to
8
+ * one visual family. It used to be glued to `bottom: 0`.
9
+ */
10
+ import { describe, expect, it } from "vitest";
11
+ import { readFileSync } from "node:fs";
12
+ import { dirname, join } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+
15
+ const here = dirname(fileURLToPath(import.meta.url));
16
+ const src = readFileSync(join(here, "HkSelect.scss"), "utf-8");
17
+
18
+ describe("HkSelectPanel mobile sheet docking contract", () => {
19
+ it("floats the sheet on --hk-sheet-bottom-gap (not hard 0)", () => {
20
+ const block = src.match(/\.hk-select-sheet-panel\s*{[^}]*}/)?.[0] ?? "";
21
+ expect(block).toContain("bottom: var(--hk-sheet-bottom-gap");
22
+ // Same default as the HkModal sheet contract.
23
+ expect(block).toMatch(/--hk-sheet-bottom-gap,\s*0\.375rem/);
24
+ });
25
+
26
+ it("stacks the safe-area inset on the sheet list bottom padding", () => {
27
+ const block = src.match(/\.hk-select-sheet-list\s*{[^}]*}/)?.[0] ?? "";
28
+ expect(block).toContain("env(safe-area-inset-bottom");
29
+ });
30
+ });
@@ -0,0 +1,88 @@
1
+ import { afterEach, describe, expect, it } from "vitest";
2
+ import { createApp, h, nextTick } from "vue";
3
+
4
+ import { HSelect } from "../index";
5
+
6
+ /**
7
+ * Mobile select contract: below the touch breakpoint the select renders
8
+ * as a bottom sheet (scrim + panel + grabber) instead of an anchored
9
+ * popout. The sheet's option list must carry side insets — full-row
10
+ * option pills used to glue to both screen edges and read as a broken
11
+ * edge-to-edge strip (the language picker popover keeps margins, which
12
+ * made the mismatch visible).
13
+ */
14
+
15
+ const originalWidth = window.innerWidth;
16
+
17
+ function setViewportWidth(px: number) {
18
+ Object.defineProperty(window, "innerWidth", {
19
+ configurable: true,
20
+ writable: true,
21
+ value: px,
22
+ });
23
+ }
24
+
25
+ async function mountSelect() {
26
+ const el = document.createElement("div");
27
+ document.body.appendChild(el);
28
+ const app = createApp({
29
+ render: () =>
30
+ h(HSelect, {
31
+ modelValue: "",
32
+ "onUpdate:modelValue": () => {},
33
+ options: [
34
+ { value: "a", label: "Option A" },
35
+ { value: "b", label: "Option B" },
36
+ ],
37
+ }),
38
+ });
39
+ app.mount(el);
40
+ await nextTick();
41
+ return { el, app };
42
+ }
43
+
44
+ describe("HSelect mobile sheet", () => {
45
+ afterEach(() => {
46
+ setViewportWidth(originalWidth);
47
+ document.body.innerHTML = "";
48
+ });
49
+
50
+ it("renders a bottom sheet with side-inset options on touch widths", async () => {
51
+ setViewportWidth(375);
52
+ const { app } = await mountSelect();
53
+ const trigger = document.querySelector<HTMLButtonElement>(".hk-select-trigger")!;
54
+ trigger.click();
55
+ await nextTick();
56
+
57
+ const panel = document.querySelector<HTMLElement>(".hk-select-sheet-panel");
58
+ expect(panel).not.toBeNull();
59
+ const scrim = document.querySelector(".hk-select-sheet-scrim");
60
+ expect(scrim).not.toBeNull();
61
+ // No anchored popout in sheet mode.
62
+ expect(document.querySelector(".hk-select-popout")).toBeNull();
63
+
64
+ // The list node must exist (side insets are enforced in SCSS —
65
+ // padding-inline on .hk-select-sheet-list — which happy-dom does not
66
+ // compute; the visual assertion lives in the stylesheet).
67
+ const list = document.querySelector<HTMLElement>(".hk-select-sheet-list");
68
+ expect(list).not.toBeNull();
69
+ const options = panel!.querySelectorAll(".hk-select-option");
70
+ expect(options.length).toBe(2);
71
+
72
+ app.unmount();
73
+ });
74
+
75
+ it("renders an anchored popout on desktop widths", async () => {
76
+ setViewportWidth(1280);
77
+ const { app } = await mountSelect();
78
+ const trigger = document.querySelector<HTMLButtonElement>(".hk-select-trigger")!;
79
+ trigger.click();
80
+ await nextTick();
81
+
82
+ expect(document.querySelector(".hk-select-sheet-panel")).toBeNull();
83
+ const popout = document.querySelector<HTMLElement>(".hk-select-popout");
84
+ expect(popout).not.toBeNull();
85
+
86
+ app.unmount();
87
+ });
88
+ });