@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.
- package/README.md +1 -1
- package/package.json +22 -7
- package/src/DemoApp.tsx +491 -0
- package/src/animation/registerAnimations.test.ts +94 -0
- package/src/animation/registerAnimations.ts +103 -0
- package/src/components/HkAboutModal.scss +95 -0
- package/src/components/HkAboutModal.tsx +114 -0
- package/src/components/HkAdaptiveDialog.scss +22 -0
- package/src/components/HkAdaptiveDialog.test.tsx +271 -0
- package/src/components/HkAdaptiveDialog.tsx +167 -0
- package/src/components/HkAdminHeader.test.tsx +185 -0
- package/src/components/HkAdminHeader.tsx +308 -0
- package/src/components/HkAdminShell.test.tsx +237 -0
- package/src/components/HkAdminShell.tsx +129 -0
- package/src/components/HkAdminTablePage.tsx +70 -0
- package/src/components/HkAdminWidgets.test.ts +89 -0
- package/src/components/HkAlert.tsx +1 -1
- package/src/components/HkAltSignIn.scss +55 -0
- package/src/components/HkAltSignIn.test.tsx +88 -0
- package/src/components/HkAltSignIn.tsx +92 -0
- package/src/components/HkAttachmentModal.scss +49 -0
- package/src/components/HkAttachmentModal.tsx +318 -0
- package/src/components/HkAuthCard.tsx +50 -0
- package/src/components/HkAuthSubmitButton.scss +12 -0
- package/src/components/HkAuthSubmitButton.tsx +94 -0
- package/src/components/HkAvatar.scss +93 -0
- package/src/components/HkAvatar.tsx +2 -2
- package/src/components/HkBlockingToast.scss +123 -0
- package/src/components/HkBlockingToast.test.tsx +221 -0
- package/src/components/HkBlockingToast.tsx +182 -0
- package/src/components/HkBreadcrumb.scss +624 -0
- package/src/components/HkBreadcrumb.tsx +2 -2
- package/src/components/HkButton.scss +16 -2
- package/src/components/HkCaptchaModal.scss +14 -0
- package/src/components/HkCaptchaModal.tsx +62 -0
- package/src/components/HkCaptchaWidget.scss +30 -0
- package/src/components/HkCaptchaWidget.tsx +181 -0
- package/src/components/HkCard.scss +1 -1
- package/src/components/HkChatTypes.ts +65 -0
- package/src/components/HkCheckbox.scss +4 -9
- package/src/components/HkCheckbox.tsx +18 -6
- package/src/components/HkColorPicker.scss +120 -3
- package/src/components/HkColorPicker.tsx +130 -19
- package/src/components/HkColorPickerTouch.test.tsx +145 -0
- package/src/components/HkColorSchemeDialog.scss +52 -0
- package/src/components/HkColorSchemeDialog.test.ts +201 -0
- package/src/components/HkColorSchemeDialog.tsx +96 -0
- package/src/components/HkColorSchemeEditor.test.ts +270 -0
- package/src/components/HkColorSchemeEditor.tsx +410 -0
- package/src/components/HkConfirmDialog.scss +43 -3
- package/src/components/HkConfirmDialog.tsx +7 -4
- package/src/components/HkConnectionInfo.ts +80 -0
- package/src/components/HkConnectionStatus.tsx +158 -0
- package/src/components/HkCookieConsent.scss +22 -0
- package/src/components/HkCookieConsent.test.tsx +70 -0
- package/src/components/HkCookieConsent.tsx +56 -0
- package/src/components/HkCountdownDigit.tsx +105 -0
- package/src/components/HkDatePicker.scss +361 -0
- package/src/components/HkDatePicker.test.ts +459 -0
- package/src/components/HkDatePicker.tsx +568 -0
- package/src/components/HkDateTimePicker.scss +65 -37
- package/src/components/HkDateTimePicker.test.ts +344 -0
- package/src/components/HkDateTimePicker.tsx +249 -82
- package/src/components/HkDraggableGrid.scss +4 -1
- package/src/components/HkDraggableList.scss +4 -1
- package/src/components/HkDrawer.scss +27 -13
- package/src/components/HkDrawer.test.tsx +73 -0
- package/src/components/HkDrawer.tsx +157 -10
- package/src/components/HkErrorBoundary.scss +5 -2
- package/src/components/HkErrorBoundary.tsx +7 -4
- package/src/components/HkExpansionPanel.scss +143 -0
- package/src/components/HkExpansionPanel.test.tsx +109 -0
- package/src/components/HkExpansionPanel.tsx +101 -0
- package/src/components/HkFab.scss +162 -0
- package/src/components/HkFab.test.tsx +217 -0
- package/src/components/HkFab.tsx +214 -0
- package/src/components/HkHoverRevealAction.scss +6 -0
- package/src/components/HkHoverRevealAction.test.ts +68 -0
- package/src/components/HkHoverRevealAction.tsx +84 -6
- package/src/components/HkIcon.scss +123 -0
- package/src/components/HkIcon.tsx +7 -23
- package/src/components/HkIconButton.scss +170 -0
- package/src/components/HkIconButton.test.tsx +75 -0
- package/src/components/HkIconButton.tsx +4 -3
- package/src/components/HkIconButtonVars.scss +180 -0
- package/src/components/HkInput.affix.test.ts +253 -0
- package/src/components/HkInput.enter.test.ts +88 -0
- package/src/components/HkInput.scss +127 -8
- package/src/components/HkInput.tsx +245 -13
- package/src/components/HkKeywordSearchModal.scss +13 -0
- package/src/components/HkKeywordSearchModal.tsx +46 -9
- package/src/components/HkLabel.scss +34 -0
- package/src/components/HkLabel.test.tsx +61 -0
- package/src/components/HkLabel.tsx +45 -0
- package/src/components/HkListTransition.scss +26 -0
- package/src/components/HkListTransition.tsx +57 -0
- package/src/components/HkLocalePicker.scss +37 -0
- package/src/components/HkLocalePicker.tsx +133 -0
- package/src/components/HkLocalePickerPopup.tsx +35 -19
- package/src/components/HkLocalizedInput.scss +277 -0
- package/src/components/HkLocalizedInput.test.tsx +693 -0
- package/src/components/HkLocalizedInput.tsx +495 -0
- package/src/components/HkLogWindow.scss +121 -0
- package/src/components/HkLogWindow.tsx +195 -0
- package/src/components/HkLogo.scss +1 -1
- package/src/components/HkLogo.tsx +1 -1
- package/src/components/HkMarkdownRenderer.scss +22 -2
- package/src/components/HkMarkdownRenderer.tsx +33 -3
- package/src/components/HkMediaControlBar.tsx +20 -13
- package/src/components/HkMenu.scss +200 -0
- package/src/components/HkMenu.test.ts +779 -0
- package/src/components/HkMenu.tsx +770 -0
- package/src/components/HkMenuActionItem.scss +58 -0
- package/src/components/HkMenuActionItem.tsx +41 -0
- package/src/components/HkMenuIdentityItem.scss +70 -0
- package/src/components/HkMenuIdentityItem.tsx +42 -0
- package/src/components/HkMenuPanel.scss +20 -0
- package/src/components/HkMenuPanel.test.tsx +118 -0
- package/src/components/HkMenuPanel.tsx +32 -0
- package/src/components/HkMinimap.tsx +16 -8
- package/src/components/HkModal.autofollow.test.ts +44 -0
- package/src/components/HkModal.scss +170 -53
- package/src/components/HkModal.sheetgap.test.ts +82 -0
- package/src/components/HkModal.test.tsx +334 -0
- package/src/components/HkModal.tsx +314 -68
- package/src/components/HkModalBreadcrumb.scss +4 -1
- package/src/components/HkModalBreadcrumb.test.tsx +111 -0
- package/src/components/HkModalBreadcrumb.tsx +34 -11
- package/src/components/HkModelCatalog.ts +98 -0
- package/src/components/HkModelTag.scss +130 -0
- package/src/components/HkModelTag.test.tsx +111 -0
- package/src/components/HkModelTag.tsx +190 -0
- package/src/components/HkNavItem.scss +13 -2
- package/src/components/HkNavItem.tsx +2 -1
- package/src/components/HkNavSidebar.tsx +99 -0
- package/src/components/HkNumberInput.scss +12 -0
- package/src/components/HkNumberInput.tsx +15 -8
- package/src/components/HkPageHeader.scss +79 -0
- package/src/components/HkPageHeader.test.ts +67 -0
- package/src/components/HkPageHeader.tsx +51 -0
- package/src/components/HkPasswordInput.scss +29 -17
- package/src/components/HkPasswordInput.test.ts +281 -0
- package/src/components/HkPasswordInput.tsx +337 -59
- package/src/components/HkPickerPane.scss +158 -0
- package/src/components/HkPlaceholderMarquee.scss +109 -0
- package/src/components/HkPlaceholderMarquee.test.ts +305 -0
- package/src/components/HkPlaceholderMarquee.tsx +170 -0
- package/src/components/HkPopover.scss +134 -10
- package/src/components/HkPopover.sheetdock.test.ts +34 -0
- package/src/components/HkPopover.surfacevars.test.ts +20 -0
- package/src/components/HkPopover.titleSuppress.test.tsx +265 -0
- package/src/components/HkPopover.tsx +225 -50
- package/src/components/HkPopoverSheet.test.tsx +130 -0
- package/src/components/HkPopupSelect.scss +30 -10
- package/src/components/HkPopupSelect.tsx +21 -1
- package/src/components/HkProgressDialog.scss +31 -0
- package/src/components/HkProgressDialog.tsx +37 -19
- package/src/components/HkProtocolModal.scss +26 -0
- package/src/components/HkProtocolModal.tsx +112 -0
- package/src/components/HkRadio.scss +1 -16
- package/src/components/HkRadio.tsx +5 -2
- package/src/components/HkRichInput.scss +162 -0
- package/src/components/HkRichInput.tsx +335 -0
- package/src/components/HkRollingNumber.test.ts +90 -0
- package/src/components/HkRollingNumber.tsx +39 -1
- package/src/components/HkScrollContainer.scss +71 -54
- package/src/components/HkScrollContainer.test.ts +160 -0
- package/src/components/HkScrollContainer.tsx +187 -160
- package/src/components/HkSearchInput.tsx +3 -3
- package/src/components/HkSecretRevealModal.scss +61 -0
- package/src/components/HkSecretRevealModal.tsx +91 -0
- package/src/components/HkSelect.scss +263 -12
- package/src/components/HkSelect.sheetdock.test.ts +30 -0
- package/src/components/HkSelect.test.tsx +88 -0
- package/src/components/HkSelect.tsx +59 -74
- package/src/components/HkSelectPanel.test.tsx +666 -0
- package/src/components/HkSelectPanel.tsx +595 -0
- package/src/components/HkSelectSheet.test.tsx +132 -0
- package/src/components/HkSelectionGrid.scss +1 -1
- package/src/components/HkSelectionGrid.tsx +2 -1
- package/src/components/HkSelectionWaterfall.scss +1 -1
- package/src/components/HkShareBar.scss +40 -0
- package/src/components/HkShareBar.tsx +50 -0
- package/src/components/HkSidebar.scss +15 -10
- package/src/components/HkSidebar.tsx +26 -2
- package/src/components/HkSignInCard.test.ts +154 -0
- package/src/components/HkSignInCard.tsx +155 -0
- package/src/components/HkSlider.scss +99 -0
- package/src/components/HkSlider.test.tsx +155 -0
- package/src/components/HkSlider.tsx +173 -0
- package/src/components/HkSpinner.scss +36 -1
- package/src/components/HkSpinner.test.tsx +63 -0
- package/src/components/HkSpinner.tsx +16 -1
- package/src/components/HkSplash.scss +1 -1
- package/src/components/HkSplash.tsx +3 -1
- package/src/components/HkStatCard.scss +73 -0
- package/src/components/HkStatCard.tsx +46 -0
- package/src/components/HkStatusBar.test.tsx +178 -0
- package/src/components/HkStatusBar.tsx +379 -0
- package/src/components/HkStatusPill.scss +73 -0
- package/src/components/HkStatusPill.tsx +41 -0
- package/src/components/HkStepFlow.scss +75 -0
- package/src/components/HkStepFlow.test.tsx +246 -0
- package/src/components/HkStepFlow.tsx +115 -0
- package/src/components/HkSwitch.scss +5 -17
- package/src/components/HkSwitch.tsx +6 -3
- package/src/components/HkTable.scss +20 -1
- package/src/components/HkTable.tsx +28 -3
- package/src/components/HkTabs.scss +222 -48
- package/src/components/HkTabs.test.ts +517 -0
- package/src/components/HkTabs.tsx +567 -56
- package/src/components/HkTag.tsx +2 -1
- package/src/components/HkTextarea.tsx +5 -0
- package/src/components/HkThemeToggle.scss +232 -0
- package/src/components/HkThemeToggle.test.ts +231 -0
- package/src/components/HkThemeToggle.tsx +289 -0
- package/src/components/HkTimeline.scss +134 -1
- package/src/components/HkTimeline.test.tsx +319 -0
- package/src/components/HkTimeline.tsx +303 -54
- package/src/components/HkToast.scss +34 -5
- package/src/components/HkToast.test.tsx +109 -0
- package/src/components/HkToast.tsx +57 -8
- package/src/components/HkTokenUsageBadge.scss +53 -0
- package/src/components/HkTokenUsageBadge.test.tsx +59 -0
- package/src/components/HkTokenUsageBadge.tsx +54 -0
- package/src/components/HkTokenUsagePanel.scss +95 -0
- package/src/components/HkTokenUsagePanel.tsx +140 -0
- package/src/components/HkToolBlock.scss +428 -0
- package/src/components/HkToolBlock.tsx +639 -0
- package/src/components/HkTooltip.scss +14 -2
- package/src/components/HkTooltip.tsx +25 -2
- package/src/components/HkTrendChart.tsx +27 -16
- package/src/components/HkVoiceInputPopup.scss +77 -0
- package/src/components/HkVoiceInputPopup.tsx +97 -0
- package/src/components/HkZoomToolbar.scss +4 -1
- package/src/components/HkZoomToolbar.tsx +7 -4
- package/src/components/_hikari-vars.scss +6 -0
- package/src/composables/highlightLanguages.ts +109 -0
- package/src/composables/iconRegistry.ts +127 -0
- package/src/composables/messaging/browserTransport.ts +96 -0
- package/src/composables/messaging/index.ts +204 -0
- package/src/composables/messaging/messaging.test.ts +256 -0
- package/src/composables/messaging/toastTransport.ts +26 -0
- package/src/composables/messaging/types.ts +115 -0
- package/src/composables/useActionBar.ts +66 -0
- package/src/composables/useAttachments.ts +154 -0
- package/src/composables/useConnectionProbe.ts +142 -0
- package/src/composables/useDeferredTransition.ts +16 -0
- package/src/composables/useEngineHealth.ts +69 -0
- package/src/composables/useHighlight.ts +124 -0
- package/src/composables/useMeasuredHighlight.ts +150 -0
- package/src/composables/useOverlayScrollbar.test.ts +221 -0
- package/src/composables/useOverlayScrollbar.ts +296 -0
- package/src/composables/usePageTitle.ts +37 -0
- package/src/composables/useReducedMotion.ts +34 -0
- package/src/composables/useResourceListModal.tsx +147 -0
- package/src/composables/useSafeArea.ts +137 -0
- package/src/composables/useSendShortcut.ts +35 -0
- package/src/composables/useSizeMorph.test.ts +156 -0
- package/src/composables/useSizeMorph.ts +149 -0
- package/src/composables/useSurfaceTransition.test.ts +96 -0
- package/src/composables/useSurfaceTransition.ts +71 -0
- package/src/composables/useZoomPan.ts +192 -0
- package/src/demo.scss +9 -1
- package/src/demo.ts +5 -1
- package/src/i18n/locales/ar/chat.json +38 -0
- package/src/i18n/locales/ar/components.json +141 -40
- package/src/i18n/locales/ar/components.toml +59 -0
- package/src/i18n/locales/ar/platform.json +65 -0
- package/src/i18n/locales/de/chat.json +38 -0
- package/src/i18n/locales/de/components.json +139 -38
- package/src/i18n/locales/de/components.toml +59 -0
- package/src/i18n/locales/de/platform.json +65 -0
- package/src/i18n/locales/en/chat.json +38 -0
- package/src/i18n/locales/en/components.json +104 -3
- package/src/i18n/locales/en/components.toml +59 -0
- package/src/i18n/locales/en/platform.json +65 -0
- package/src/i18n/locales/es/chat.json +38 -0
- package/src/i18n/locales/es/components.json +141 -40
- package/src/i18n/locales/es/components.toml +59 -0
- package/src/i18n/locales/es/platform.json +65 -0
- package/src/i18n/locales/fr/chat.json +38 -0
- package/src/i18n/locales/fr/components.json +137 -36
- package/src/i18n/locales/fr/components.toml +59 -0
- package/src/i18n/locales/fr/platform.json +65 -0
- package/src/i18n/locales/ja/chat.json +38 -0
- package/src/i18n/locales/ja/components.json +104 -3
- package/src/i18n/locales/ja/components.toml +59 -0
- package/src/i18n/locales/ja/platform.json +65 -0
- package/src/i18n/locales/ko/chat.json +38 -0
- package/src/i18n/locales/ko/components.json +104 -3
- package/src/i18n/locales/ko/components.toml +59 -0
- package/src/i18n/locales/ko/platform.json +65 -0
- package/src/i18n/locales/pt/chat.json +38 -0
- package/src/i18n/locales/pt/components.json +141 -40
- package/src/i18n/locales/pt/components.toml +59 -0
- package/src/i18n/locales/pt/platform.json +65 -0
- package/src/i18n/locales/ru/chat.json +38 -0
- package/src/i18n/locales/ru/components.json +141 -40
- package/src/i18n/locales/ru/components.toml +59 -0
- package/src/i18n/locales/ru/platform.json +65 -0
- package/src/i18n/locales/zh-Hans/chat.json +38 -0
- package/src/i18n/locales/zh-Hans/components.json +109 -4
- package/src/i18n/locales/zh-Hans/components.toml +59 -0
- package/src/i18n/locales/zh-Hans/platform.json +65 -0
- package/src/i18n/locales/zh-Hant/chat.json +38 -0
- package/src/i18n/locales/zh-Hant/components.json +109 -4
- package/src/i18n/locales/zh-Hant/components.toml +59 -0
- package/src/i18n/locales/zh-Hant/platform.json +65 -0
- package/src/index.ts +225 -6
- package/src/plugins/bootScriptsPlugin.ts +47 -0
- package/src/plugins/buildHashPlugin.ts +67 -0
- package/src/plugins/index.ts +2 -0
- package/src/render.ts +1 -1
- package/src/runtime/animationBus.test.ts +112 -0
- package/src/runtime/animationBus.ts +33 -2
- package/src/runtime/backStack.test.ts +334 -0
- package/src/runtime/backStack.ts +377 -0
- package/src/runtime/env.ts +4 -0
- package/src/runtime/index.ts +15 -3
- package/src/runtime/intervalBus.test.ts +118 -0
- package/src/runtime/intervalBus.ts +189 -0
- package/src/runtime/mobileViewport.test.ts +132 -0
- package/src/runtime/mobileViewport.ts +157 -0
- package/src/runtime/pageLifecycle.ts +91 -0
- package/src/runtime/useBlockingToast.ts +112 -0
- package/src/runtime/useClipboard.ts +28 -0
- package/src/runtime/useConfirm.ts +15 -7
- package/src/runtime/useMediaQuery.test.ts +67 -0
- package/src/runtime/useMediaQuery.ts +89 -0
- package/src/runtime/useOverlay.test.ts +160 -0
- package/src/runtime/useOverlay.ts +59 -12
- package/src/runtime/usePopupManager.test.ts +200 -0
- package/src/runtime/usePopupManager.ts +106 -10
- package/src/runtime/useToast.test.ts +90 -0
- package/src/runtime/useToast.ts +20 -2
- package/src/styles/admin-tokens.scss +744 -0
- package/src/styles/index.scss +5 -3
- package/src/styles/theme/_glass.scss +33 -0
- package/src/styles/theme/_layout.scss +123 -0
- package/src/styles/theme/_scrollbar.scss +73 -0
- package/src/styles/theme/_tokens.scss +69 -0
- package/src/styles/theme/base.scss +617 -0
- package/src/styles/theme/foundation.scss +219 -0
- package/src/styles/theme/mixins.scss +793 -0
- package/src/styles/theme/themes.scss +25 -0
- package/src/styles/theme/variables.scss +125 -0
- package/src/theme/_field.scss +116 -0
- package/src/theme/fontContext.test.ts +179 -0
- package/src/theme/fontContext.ts +169 -0
- package/src/theme/index.ts +19 -2
- package/src/theme/presets.ts +86 -18
- package/src/theme/theme.scss +61 -1
- package/src/theme/tokenGroups.test.ts +534 -0
- package/src/theme/tokenGroups.ts +552 -0
- package/src/theme/useSolarTime.test.ts +113 -0
- package/src/theme/useSolarTime.ts +95 -20
- package/src/theme/useTheme.test.ts +72 -0
- package/src/theme/useTheme.ts +144 -9
- package/src/tokens.scss +110 -0
- package/src/utils/base64.ts +31 -0
- package/src/utils/connectivity.ts +51 -0
- package/src/utils/dom.test.ts +131 -0
- package/src/utils/dom.ts +133 -0
- package/src/utils/download.ts +22 -0
- package/src/utils/fileType.ts +127 -0
- package/src/utils/format.ts +98 -0
- package/src/utils/fuzzy.ts +77 -0
- package/src/utils/fuzzySearch.test.ts +87 -0
- package/src/utils/healthProbe.ts +64 -0
- package/src/utils/objectPath.ts +59 -0
- package/src/utils/password.ts +53 -0
- package/src/utils/pow.test.ts +45 -0
- package/src/utils/pow.ts +226 -0
- package/src/utils/powNonce.ts +95 -0
- package/src/utils/validation.test.ts +78 -0
- package/src/DemoApp.vue +0 -400
- package/src/components/HkCollapse.tsx +0 -48
- package/src/components/HkMorphingTabs.scss +0 -141
- package/src/components/HkMorphingTabs.tsx +0 -113
- package/src/composables/useBreakpoint.ts +0 -41
- package/src/composables/useClipboard.ts +0 -37
- package/src/composables/useConfirm.ts +0 -35
- package/src/composables/useToast.ts +0 -2
- package/src/runtime/useAsyncData.ts +0 -30
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { createApp, defineComponent, h, nextTick, ref } from "vue";
|
|
3
|
+
|
|
4
|
+
import HkModal from "./HkModal";
|
|
5
|
+
import { closeAll } from "../runtime/useOverlay";
|
|
6
|
+
|
|
7
|
+
const mounts: ReturnType<typeof createApp>[] = [];
|
|
8
|
+
const containers: HTMLElement[] = [];
|
|
9
|
+
|
|
10
|
+
afterEach(async () => {
|
|
11
|
+
for (const app of mounts.splice(0)) app.unmount();
|
|
12
|
+
for (const el of containers.splice(0)) el.remove();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("HkModal overlay integration", () => {
|
|
16
|
+
it("closeAll() closes an open closable modal through its update:modelValue", async () => {
|
|
17
|
+
const container = document.createElement("div");
|
|
18
|
+
document.body.appendChild(container);
|
|
19
|
+
containers.push(container);
|
|
20
|
+
|
|
21
|
+
const open = ref(true);
|
|
22
|
+
const emitted: boolean[] = [];
|
|
23
|
+
const Wrapper = defineComponent({
|
|
24
|
+
setup() {
|
|
25
|
+
return () =>
|
|
26
|
+
h(HkModal, {
|
|
27
|
+
modelValue: open.value,
|
|
28
|
+
closable: true,
|
|
29
|
+
"onUpdate:modelValue": (v: boolean) => { emitted.push(v); open.value = v; },
|
|
30
|
+
}, { default: () => h("div", "content") });
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
const app = createApp(Wrapper);
|
|
34
|
+
mounts.push(app);
|
|
35
|
+
app.mount(container);
|
|
36
|
+
await nextTick();
|
|
37
|
+
|
|
38
|
+
closeAll();
|
|
39
|
+
await nextTick();
|
|
40
|
+
expect(emitted).toEqual([false]);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("closeAll() leaves a non-closable modal alone", async () => {
|
|
44
|
+
const container = document.createElement("div");
|
|
45
|
+
document.body.appendChild(container);
|
|
46
|
+
containers.push(container);
|
|
47
|
+
|
|
48
|
+
const open = ref(true);
|
|
49
|
+
const emitted: boolean[] = [];
|
|
50
|
+
const Wrapper = defineComponent({
|
|
51
|
+
setup() {
|
|
52
|
+
return () =>
|
|
53
|
+
h(HkModal, {
|
|
54
|
+
modelValue: open.value,
|
|
55
|
+
closable: false,
|
|
56
|
+
"onUpdate:modelValue": (v: boolean) => { emitted.push(v); open.value = v; },
|
|
57
|
+
}, { default: () => h("div", "content") });
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const app = createApp(Wrapper);
|
|
61
|
+
mounts.push(app);
|
|
62
|
+
app.mount(container);
|
|
63
|
+
await nextTick();
|
|
64
|
+
|
|
65
|
+
closeAll();
|
|
66
|
+
await nextTick();
|
|
67
|
+
expect(emitted).toEqual([]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe("HkModal back-guard (window-first back priority)", () => {
|
|
72
|
+
async function settle(): Promise<void> {
|
|
73
|
+
await nextTick();
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
75
|
+
await nextTick();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Wait until pred() holds (history navigation settles asynchronously). */
|
|
79
|
+
async function until(pred: () => boolean, ms = 500): Promise<void> {
|
|
80
|
+
const deadline = Date.now() + ms;
|
|
81
|
+
while (!pred() && Date.now() < deadline) {
|
|
82
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
83
|
+
await nextTick();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
it("pushes a history entry on open and back closes the modal, not the page", async () => {
|
|
88
|
+
const container = document.createElement("div");
|
|
89
|
+
document.body.appendChild(container);
|
|
90
|
+
containers.push(container);
|
|
91
|
+
|
|
92
|
+
const open = ref(true);
|
|
93
|
+
const Wrapper = defineComponent({
|
|
94
|
+
setup() {
|
|
95
|
+
return () =>
|
|
96
|
+
h(HkModal, {
|
|
97
|
+
modelValue: open.value,
|
|
98
|
+
closable: true,
|
|
99
|
+
"onUpdate:modelValue": (v: boolean) => { open.value = v; },
|
|
100
|
+
}, { default: () => h("div", "content") });
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
const app = createApp(Wrapper);
|
|
104
|
+
mounts.push(app);
|
|
105
|
+
app.mount(container);
|
|
106
|
+
await settle();
|
|
107
|
+
|
|
108
|
+
// The open modal owns one marked history entry above the page base.
|
|
109
|
+
expect((window.history.state as Record<string, unknown>)?.__hkBack).toEqual(expect.any(String));
|
|
110
|
+
|
|
111
|
+
// Browser/system back: closes the modal and stays on the page.
|
|
112
|
+
// (happy-dom never fires transition end events, so the leave
|
|
113
|
+
// animation keeps the DOM node — the logical state is what matters.)
|
|
114
|
+
window.history.back();
|
|
115
|
+
await until(() => open.value === false);
|
|
116
|
+
await until(() => window.history.state === null);
|
|
117
|
+
app.unmount();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("closing via the X button rewinds the pushed entry (no dead back)", async () => {
|
|
121
|
+
const container = document.createElement("div");
|
|
122
|
+
document.body.appendChild(container);
|
|
123
|
+
containers.push(container);
|
|
124
|
+
|
|
125
|
+
const open = ref(true);
|
|
126
|
+
const Wrapper = defineComponent({
|
|
127
|
+
setup() {
|
|
128
|
+
return () =>
|
|
129
|
+
h(HkModal, {
|
|
130
|
+
modelValue: open.value,
|
|
131
|
+
closable: true,
|
|
132
|
+
"onUpdate:modelValue": (v: boolean) => { open.value = v; },
|
|
133
|
+
}, { default: () => h("div", "content") });
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
const app = createApp(Wrapper);
|
|
137
|
+
mounts.push(app);
|
|
138
|
+
app.mount(container);
|
|
139
|
+
await settle();
|
|
140
|
+
expect((window.history.state as Record<string, unknown>)?.__hkBack).toEqual(expect.any(String));
|
|
141
|
+
|
|
142
|
+
(document.querySelector(".hk-modal-close") as HTMLButtonElement).click();
|
|
143
|
+
await until(() => open.value === false);
|
|
144
|
+
// History rewound to the page base — a subsequent back leaves the page,
|
|
145
|
+
// it is not consumed by a spent modal entry.
|
|
146
|
+
await until(() => window.history.state === null);
|
|
147
|
+
app.unmount();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("a non-closable modal never owns history", async () => {
|
|
151
|
+
const container = document.createElement("div");
|
|
152
|
+
document.body.appendChild(container);
|
|
153
|
+
containers.push(container);
|
|
154
|
+
|
|
155
|
+
const open = ref(true);
|
|
156
|
+
const Wrapper = defineComponent({
|
|
157
|
+
setup() {
|
|
158
|
+
return () =>
|
|
159
|
+
h(HkModal, {
|
|
160
|
+
modelValue: open.value,
|
|
161
|
+
closable: false,
|
|
162
|
+
"onUpdate:modelValue": (v: boolean) => { open.value = v; },
|
|
163
|
+
}, { default: () => h("div", "content") });
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
const app = createApp(Wrapper);
|
|
167
|
+
mounts.push(app);
|
|
168
|
+
app.mount(container);
|
|
169
|
+
await settle();
|
|
170
|
+
|
|
171
|
+
expect((window.history.state as Record<string, unknown>)?.__hkBack).toBeUndefined();
|
|
172
|
+
app.unmount();
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("HkModal autoFollow", () => {
|
|
177
|
+
const SCROLL_H = 1000;
|
|
178
|
+
const CLIENT_H = 300;
|
|
179
|
+
/** scrollTop that leaves exactly 200px hidden below the fold. */
|
|
180
|
+
const CANCEL_TOP = SCROLL_H - CLIENT_H - 200;
|
|
181
|
+
/** Bottom-anchored scrollTop (distance to bottom = 0). */
|
|
182
|
+
const BOTTOM_TOP = SCROLL_H - CLIENT_H;
|
|
183
|
+
|
|
184
|
+
async function until(pred: () => boolean, ms = 1500): Promise<void> {
|
|
185
|
+
await vi.waitFor(() => {
|
|
186
|
+
if (!pred()) throw new Error("condition not met yet");
|
|
187
|
+
}, { timeout: ms, interval: 10 });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
interface Setup {
|
|
191
|
+
scroller: HTMLElement;
|
|
192
|
+
tag: () => Element | null;
|
|
193
|
+
jump: () => HTMLButtonElement | null;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function stubGeometry(el: HTMLElement) {
|
|
197
|
+
for (const [key, value] of [
|
|
198
|
+
["scrollHeight", SCROLL_H],
|
|
199
|
+
["clientHeight", CLIENT_H],
|
|
200
|
+
] as const) {
|
|
201
|
+
Object.defineProperty(el, key, { configurable: true, value });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Mount an open autoFollow modal and return its scroll container.
|
|
206
|
+
* Geometry stubs land BEFORE the enter transition finishes so the
|
|
207
|
+
* follow setup sees them; a first scroll pass makes the tag appear. */
|
|
208
|
+
async function mountAutoFollow(): Promise<Setup> {
|
|
209
|
+
const container = document.createElement("div");
|
|
210
|
+
document.body.appendChild(container);
|
|
211
|
+
containers.push(container);
|
|
212
|
+
|
|
213
|
+
const Wrapper = defineComponent({
|
|
214
|
+
setup() {
|
|
215
|
+
return () =>
|
|
216
|
+
h(HkModal, {
|
|
217
|
+
modelValue: true,
|
|
218
|
+
autoFollow: true,
|
|
219
|
+
}, { default: () => h("p", { class: "follow-line" }, "log line") });
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
const app = createApp(Wrapper);
|
|
223
|
+
mounts.push(app);
|
|
224
|
+
app.mount(container);
|
|
225
|
+
await nextTick();
|
|
226
|
+
|
|
227
|
+
const scroller = document.body.querySelector<HTMLElement>(".hk-modal-body-scroll");
|
|
228
|
+
if (!scroller) throw new Error("scroller not rendered");
|
|
229
|
+
stubGeometry(scroller);
|
|
230
|
+
|
|
231
|
+
// onAfterEnter wires setupAutoFollow; poll instead of assuming when
|
|
232
|
+
// the Transition hook fires under happy-dom. One synthetic scroll
|
|
233
|
+
// makes the initial overflow sense deterministic whenever it runs.
|
|
234
|
+
await until(() => {
|
|
235
|
+
scroller.dispatchEvent(new Event("scroll"));
|
|
236
|
+
return document.body.querySelector(".hk-modal-autofollow-tag") !== null;
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
scroller,
|
|
241
|
+
tag: () => document.body.querySelector(".hk-modal-autofollow-tag"),
|
|
242
|
+
jump: () => document.body.querySelector<HTMLButtonElement>(".hk-modal-jump .hk-fab-button"),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function flush(): Promise<void> {
|
|
247
|
+
await nextTick();
|
|
248
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
249
|
+
await nextTick();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
it("streaming-style pinning never cancels follow", async () => {
|
|
253
|
+
const s = await mountAutoFollow();
|
|
254
|
+
expect(s.tag()).not.toBeNull();
|
|
255
|
+
expect(s.jump()).toBeNull();
|
|
256
|
+
|
|
257
|
+
// MutationObserver path: append content while pinned at bottom.
|
|
258
|
+
s.scroller.scrollTop = BOTTOM_TOP;
|
|
259
|
+
const inner = document.body.querySelector(".hk-modal-body-inner");
|
|
260
|
+
if (!inner) throw new Error("body inner missing");
|
|
261
|
+
inner.appendChild(document.createElement("p"));
|
|
262
|
+
// Settle frames keep pinning to the (stubbed constant) bottom.
|
|
263
|
+
await until(() => s.scroller.scrollTop === SCROLL_H);
|
|
264
|
+
await flush();
|
|
265
|
+
await flush();
|
|
266
|
+
|
|
267
|
+
expect(s.tag()).not.toBeNull();
|
|
268
|
+
expect(s.jump()).toBeNull();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it("a gesture followed by an over-threshold scroll cancels follow", async () => {
|
|
272
|
+
const s = await mountAutoFollow();
|
|
273
|
+
expect(s.tag()).not.toBeNull();
|
|
274
|
+
|
|
275
|
+
s.scroller.dispatchEvent(new WheelEvent("wheel"));
|
|
276
|
+
s.scroller.scrollTop = CANCEL_TOP; // distance 200 > FOLLOW_THRESHOLD
|
|
277
|
+
s.scroller.dispatchEvent(new Event("scroll"));
|
|
278
|
+
await flush();
|
|
279
|
+
|
|
280
|
+
expect(s.tag()).toBeNull();
|
|
281
|
+
expect(s.jump()).not.toBeNull();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("a slow drag keeps the flag alive across sub-threshold scrolls and cancels", async () => {
|
|
285
|
+
const s = await mountAutoFollow();
|
|
286
|
+
expect(s.tag()).not.toBeNull();
|
|
287
|
+
|
|
288
|
+
s.scroller.dispatchEvent(new WheelEvent("wheel"));
|
|
289
|
+
// First sub-threshold step (<32px): still following — must NOT eat
|
|
290
|
+
// the gesture flag (regression guard for BLOCKER 1).
|
|
291
|
+
s.scroller.scrollTop = BOTTOM_TOP - 10; // distance 10
|
|
292
|
+
s.scroller.dispatchEvent(new Event("scroll"));
|
|
293
|
+
await flush();
|
|
294
|
+
expect(s.tag()).not.toBeNull();
|
|
295
|
+
expect(s.jump()).toBeNull();
|
|
296
|
+
|
|
297
|
+
// Drag crosses the threshold later: cancellation must still happen.
|
|
298
|
+
s.scroller.scrollTop = CANCEL_TOP; // distance 200
|
|
299
|
+
s.scroller.dispatchEvent(new Event("scroll"));
|
|
300
|
+
await flush();
|
|
301
|
+
expect(s.tag()).toBeNull();
|
|
302
|
+
expect(s.jump()).not.toBeNull();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("jump-to-latest pins to bottom, re-arms follow, drops the FAB", async () => {
|
|
306
|
+
const s = await mountAutoFollow();
|
|
307
|
+
|
|
308
|
+
s.scroller.dispatchEvent(new WheelEvent("wheel"));
|
|
309
|
+
s.scroller.scrollTop = CANCEL_TOP;
|
|
310
|
+
s.scroller.dispatchEvent(new Event("scroll"));
|
|
311
|
+
await flush();
|
|
312
|
+
const fab = s.jump();
|
|
313
|
+
if (!fab) throw new Error("jump FAB did not appear after cancel");
|
|
314
|
+
|
|
315
|
+
fab.click(); // resumeJumpLatest: direct pin + settle frames re-kick
|
|
316
|
+
await until(() => s.scroller.scrollTop === SCROLL_H);
|
|
317
|
+
await until(() => s.tag() !== null);
|
|
318
|
+
expect(s.scroller.scrollTop).toBe(SCROLL_H);
|
|
319
|
+
expect(s.jump()).toBeNull();
|
|
320
|
+
// Follow is armed again: the next streaming chunk must neither
|
|
321
|
+
// cancel nor demand a fresh gesture. (happy-dom keeps scrollTop
|
|
322
|
+
// unclamped above scrollHeight - clientHeight, so geometry reads
|
|
323
|
+
// as "past the bottom" here — the render state is what matters.)
|
|
324
|
+
const innerAfterJump = document.body.querySelector(".hk-modal-body-inner");
|
|
325
|
+
if (!innerAfterJump) throw new Error("body inner missing");
|
|
326
|
+
innerAfterJump.appendChild(document.createElement("p"));
|
|
327
|
+
for (let i = 0; i < 8; i++) {
|
|
328
|
+
await new Promise((resolve) => requestAnimationFrame(() => resolve(null)));
|
|
329
|
+
await flush();
|
|
330
|
+
}
|
|
331
|
+
expect(s.tag()).not.toBeNull();
|
|
332
|
+
expect(s.jump()).toBeNull();
|
|
333
|
+
});
|
|
334
|
+
});
|