From d27e5eeef7769378ba6ed4b541e4f88c4afb7dc4 Mon Sep 17 00:00:00 2001 From: Vben Date: Fri, 13 Sep 2024 21:46:56 +0800 Subject: [PATCH] fix: improve the dialog and drawer scrollbar experience, fix internal click failure problems and warnings (#4391) * fix: improve the dialog and drawer scrollbar experience, fix internal click failure problems and warnings * chore: remove test code --- packages/@core/base/design/src/css/global.css | 4 +- packages/@core/base/shared/src/utils/dom.ts | 19 ++++++++ packages/@core/composables/src/index.ts | 1 + .../@core/composables/src/use-scroll-lock.ts | 48 +++++++++++++++++++ .../ui-kit/layout-ui/src/vben-layout.vue | 10 ++-- .../ui-kit/popup-ui/src/drawer/drawer-api.ts | 1 + .../ui-kit/popup-ui/src/drawer/drawer.ts | 4 ++ .../ui-kit/popup-ui/src/drawer/drawer.vue | 19 +++++++- .../ui-kit/popup-ui/src/drawer/use-drawer.ts | 2 +- .../@core/ui-kit/popup-ui/src/modal/modal.vue | 13 ++++- .../ui-kit/popup-ui/src/modal/use-modal.ts | 2 +- .../@core/ui-kit/shadcn-ui/build.config.ts | 1 + packages/@core/ui-kit/shadcn-ui/package.json | 1 + .../components/ui/dialog/DialogContent.vue | 19 +++++--- .../components/ui/dialog/DialogOverlay.vue | 11 +++++ .../src/components/ui/sheet/SheetContent.vue | 17 ++++--- .../src/components/ui/sheet/SheetOverlay.vue | 11 +++++ .../layouts/src/basic/tabbar/tabbar.vue | 4 +- pnpm-lock.yaml | 3 ++ scripts/turbo-run/src/run.ts | 38 ++++++++------- 20 files changed, 186 insertions(+), 42 deletions(-) create mode 100644 packages/@core/composables/src/use-scroll-lock.ts create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/dialog/DialogOverlay.vue create mode 100644 packages/@core/ui-kit/shadcn-ui/src/components/ui/sheet/SheetOverlay.vue diff --git a/packages/@core/base/design/src/css/global.css b/packages/@core/base/design/src/css/global.css index f9810e72b..3c1841091 100644 --- a/packages/@core/base/design/src/css/global.css +++ b/packages/@core/base/design/src/css/global.css @@ -37,10 +37,10 @@ } body { - @apply !pointer-events-auto; - min-height: 100vh; + /* pointer-events: auto !important; */ + /* overflow: overlay; */ /* -webkit-font-smoothing: antialiased; */ diff --git a/packages/@core/base/shared/src/utils/dom.ts b/packages/@core/base/shared/src/utils/dom.ts index 79640d609..16d6ddef7 100644 --- a/packages/@core/base/shared/src/utils/dom.ts +++ b/packages/@core/base/shared/src/utils/dom.ts @@ -50,3 +50,22 @@ export function getElementVisibleRect( width: Math.max(0, right - left), }; } + +export function getScrollbarWidth() { + const scrollDiv = document.createElement('div'); + + scrollDiv.style.visibility = 'hidden'; + scrollDiv.style.overflow = 'scroll'; + scrollDiv.style.position = 'absolute'; + scrollDiv.style.top = '-9999px'; + + document.body.append(scrollDiv); + + const innerDiv = document.createElement('div'); + scrollDiv.append(innerDiv); + + const scrollbarWidth = scrollDiv.offsetWidth - innerDiv.offsetWidth; + + scrollDiv.remove(); + return scrollbarWidth; +} diff --git a/packages/@core/composables/src/index.ts b/packages/@core/composables/src/index.ts index 31a7feabc..abfd9501f 100644 --- a/packages/@core/composables/src/index.ts +++ b/packages/@core/composables/src/index.ts @@ -2,6 +2,7 @@ export * from './use-content-style'; export * from './use-is-mobile'; export * from './use-namespace'; export * from './use-priority-value'; +export * from './use-scroll-lock'; export * from './use-simple-locale'; export * from './use-sortable'; export { diff --git a/packages/@core/composables/src/use-scroll-lock.ts b/packages/@core/composables/src/use-scroll-lock.ts new file mode 100644 index 000000000..b3f40d6bc --- /dev/null +++ b/packages/@core/composables/src/use-scroll-lock.ts @@ -0,0 +1,48 @@ +import { getScrollbarWidth } from '@vben-core/shared/utils'; + +import { + useScrollLock as _useScrollLock, + tryOnBeforeMount, + tryOnBeforeUnmount, +} from '@vueuse/core'; + +export const SCROLL_FIXED_CLASS = `_scroll__fixed_`; + +export function useScrollLock() { + const isLocked = _useScrollLock(document.body); + const scrollbarWidth = getScrollbarWidth(); + + tryOnBeforeMount(() => { + document.body.style.paddingRight = `${scrollbarWidth}px`; + + const layoutFixedNodes = document.querySelectorAll( + `.${SCROLL_FIXED_CLASS}`, + ); + const nodes = [...layoutFixedNodes]; + if (nodes.length > 0) { + nodes.forEach((node) => { + node.dataset.transition = node.style.transition; + node.style.transition = 'none'; + node.style.paddingRight = `${scrollbarWidth}px`; + }); + } + isLocked.value = true; + }); + + tryOnBeforeUnmount(() => { + isLocked.value = false; + const layoutFixedNodes = document.querySelectorAll( + `.${SCROLL_FIXED_CLASS}`, + ); + const nodes = [...layoutFixedNodes]; + if (nodes.length > 0) { + nodes.forEach((node) => { + node.style.paddingRight = ''; + requestAnimationFrame(() => { + node.style.transition = node.dataset.transition || ''; + }); + }); + } + document.body.style.paddingRight = ''; + }); +} diff --git a/packages/@core/ui-kit/layout-ui/src/vben-layout.vue b/packages/@core/ui-kit/layout-ui/src/vben-layout.vue index 67c7278ae..093507754 100644 --- a/packages/@core/ui-kit/layout-ui/src/vben-layout.vue +++ b/packages/@core/ui-kit/layout-ui/src/vben-layout.vue @@ -4,6 +4,7 @@ import type { VbenLayoutProps } from './vben-layout'; import type { CSSProperties } from 'vue'; import { computed, ref, watch } from 'vue'; +import { SCROLL_FIXED_CLASS } from '@vben-core/composables'; import { Menu } from '@vben-core/icons'; import { VbenIconButton } from '@vben-core/shadcn-ui'; @@ -478,9 +479,12 @@ function handleHeaderToggle() { class="flex flex-1 flex-col overflow-hidden transition-all duration-300 ease-in" >
diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts b/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts index ee0025924..15ce8a9ee 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts @@ -39,6 +39,7 @@ export class DrawerApi { isOpen: false, loading: false, modal: true, + openAutoFocus: false, showCancelButton: true, showConfirmButton: true, title: '', diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts index c3db06069..df1798305 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts @@ -52,6 +52,10 @@ export interface DrawerProps { * @default true */ modal?: boolean; + /** + * 是否自动聚焦 + */ + openAutoFocus?: boolean; /** * 是否显示取消按钮 * @default true diff --git a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue index 4c441d98a..025ca7420 100644 --- a/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue +++ b/packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue @@ -51,6 +51,7 @@ const { footer: showFooter, loading: showLoading, modal, + openAutoFocus, showCancelButton, showConfirmButton, title, @@ -87,10 +88,21 @@ function pointerDownOutside(e: Event) { e.preventDefault(); } } + +function handerOpenAutoFocus(e: Event) { + if (!openAutoFocus.value) { + e?.preventDefault(); + } +} + +function handleFocusOutside(e: Event) { + e.preventDefault(); + e.stopPropagation(); +}