Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: improve the dialog and drawer scrollbar experience, fix internal click failure problems and warnings #4391

Merged
merged 2 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/@core/base/design/src/css/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
}

body {
@apply !pointer-events-auto;

min-height: 100vh;

/* pointer-events: auto !important; */

/* overflow: overlay; */

/* -webkit-font-smoothing: antialiased; */
Expand Down
19 changes: 19 additions & 0 deletions packages/@core/base/shared/src/utils/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
1 change: 1 addition & 0 deletions packages/@core/composables/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
48 changes: 48 additions & 0 deletions packages/@core/composables/src/use-scroll-lock.ts
Original file line number Diff line number Diff line change
@@ -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<HTMLElement>(
`.${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<HTMLElement>(
`.${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 = '';
});
}
10 changes: 7 additions & 3 deletions packages/@core/ui-kit/layout-ui/src/vben-layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -478,9 +479,12 @@ function handleHeaderToggle() {
class="flex flex-1 flex-col overflow-hidden transition-all duration-300 ease-in"
>
<div
:class="{
'shadow-[0_16px_24px_hsl(var(--background))]': scrollY > 20,
}"
:class="[
{
'shadow-[0_16px_24px_hsl(var(--background))]': scrollY > 20,
},
SCROLL_FIXED_CLASS,
]"
:style="headerWrapperStyle"
class="overflow-hidden transition-all duration-200"
>
Expand Down
1 change: 1 addition & 0 deletions packages/@core/ui-kit/popup-ui/src/drawer/drawer-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class DrawerApi {
isOpen: false,
loading: false,
modal: true,
openAutoFocus: false,
showCancelButton: true,
showConfirmButton: true,
title: '',
Expand Down
4 changes: 4 additions & 0 deletions packages/@core/ui-kit/popup-ui/src/drawer/drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ export interface DrawerProps {
* @default true
*/
modal?: boolean;
/**
* 是否自动聚焦
*/
openAutoFocus?: boolean;
/**
* 是否显示取消按钮
* @default true
Expand Down
19 changes: 18 additions & 1 deletion packages/@core/ui-kit/popup-ui/src/drawer/drawer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const {
footer: showFooter,
loading: showLoading,
modal,
openAutoFocus,
anncwb marked this conversation as resolved.
Show resolved Hide resolved
showCancelButton,
showConfirmButton,
title,
Expand Down Expand Up @@ -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();
}
</script>
<template>
<Sheet
:modal="modal"
:modal="false"
:open="state?.isOpen"
@update:open="() => drawerApi?.close()"
>
Expand All @@ -100,8 +112,13 @@ function pointerDownOutside(e: Event) {
'!w-full': isMobile,
})
"
:modal="modal"
:open="state?.isOpen"
@close-auto-focus="handleFocusOutside"
@escape-key-down="escapeKeyDown"
@focus-outside="handleFocusOutside"
@interact-outside="interactOutside"
@open-auto-focus="handerOpenAutoFocus"
@pointer-down-outside="pointerDownOutside"
>
<SheetHeader
Expand Down
2 changes: 1 addition & 1 deletion packages/@core/ui-kit/popup-ui/src/drawer/use-drawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ async function checkProps(api: ExtendedDrawerApi, attrs: Record<string, any>) {
const stateKeys = new Set(Object.keys(state));

for (const attr of Object.keys(attrs)) {
if (stateKeys.has(attr)) {
if (stateKeys.has(attr) && !['class'].includes(attr)) {
// connectedComponent存在时,不要传入Drawer的props,会造成复杂度提升,如果你需要修改Drawer的props,请使用 useVbenDrawer 或者api
console.warn(
`[Vben Drawer]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Drawer, please use useVbenDrawer or api.`,
Expand Down
13 changes: 12 additions & 1 deletion packages/@core/ui-kit/popup-ui/src/modal/modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ function handleFullscreen() {
function interactOutside(e: Event) {
if (!closeOnClickModal.value) {
e.preventDefault();
e.stopPropagation();
}
}
function escapeKeyDown(e: KeyboardEvent) {
Expand All @@ -143,12 +144,18 @@ function pointerDownOutside(e: Event) {
const isDismissableModal = !!target?.dataset.dismissableModal;
if (!closeOnClickModal.value || !isDismissableModal) {
e.preventDefault();
e.stopPropagation();
}
}

function handleFocusOutside(e: Event) {
e.preventDefault();
e.stopPropagation();
}
</script>
<template>
<Dialog
:modal="modal"
:modal="false"
:open="state?.isOpen"
@update:open="() => modalApi?.close()"
>
Expand All @@ -166,9 +173,13 @@ function pointerDownOutside(e: Event) {
},
)
"
:modal="modal"
:open="state?.isOpen"
:show-close="closable"
close-class="top-3"
@close-auto-focus="handleFocusOutside"
@escape-key-down="escapeKeyDown"
@focus-outside="handleFocusOutside"
@interact-outside="interactOutside"
@open-auto-focus="handerOpenAutoFocus"
@pointer-down-outside="pointerDownOutside"
Expand Down
2 changes: 1 addition & 1 deletion packages/@core/ui-kit/popup-ui/src/modal/use-modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ async function checkProps(api: ExtendedModalApi, attrs: Record<string, any>) {
const stateKeys = new Set(Object.keys(state));

for (const attr of Object.keys(attrs)) {
if (stateKeys.has(attr)) {
if (stateKeys.has(attr) && !['class'].includes(attr)) {
// connectedComponent存在时,不要传入Modal的props,会造成复杂度提升,如果你需要修改Modal的props,请使用 useModal 或者api
console.warn(
`[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useVbenModal or api.`,
Expand Down
1 change: 1 addition & 0 deletions packages/@core/ui-kit/shadcn-ui/build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default defineBuildConfig({
{
builder: 'mkdist',
input: './src',

pattern: ['**/*'],
},
{
Expand Down
1 change: 1 addition & 0 deletions packages/@core/ui-kit/shadcn-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
},
"dependencies": {
"@radix-icons/vue": "^1.0.0",
"@vben-core/composables": "workspace:*",
"@vben-core/icons": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vben-core/typings": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ import {
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue';

import DialogOverlay from './DialogOverlay.vue';

const props = withDefaults(
defineProps<
{
class?: any;
closeClass?: any;
modal?: boolean;
open?: boolean;
showClose?: boolean;
} & DialogContentProps
>(),
Expand All @@ -27,7 +30,13 @@ const props = withDefaults(
const emits = defineEmits<{ close: [] } & DialogContentEmits>();

const delegatedProps = computed(() => {
const { class: _, showClose: __, ...delegated } = props;
const {
class: _,
modal: _modal,
open: _open,
showClose: __,
...delegated
} = props;

return delegated;
});
Expand All @@ -43,11 +52,7 @@ defineExpose({

<template>
<DialogPortal>
<DialogOverlay
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-overlay fixed inset-0 z-[1000]"
data-dismissable-modal="true"
@click="() => emits('close')"
/>
<DialogOverlay v-if="open && modal" @click="() => emits('close')" />
<DialogContent
ref="contentRef"
v-bind="forwarded"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { useScrollLock } from '@vben-core/composables';

useScrollLock();
</script>
<template>
<div
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 bg-overlay fixed inset-0 z-[1000]"
data-dismissable-modal="true"
></div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ import {
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue';

import { type SheetVariants, sheetVariants } from './sheet';
import SheetOverlay from './SheetOverlay.vue';

interface SheetContentProps extends DialogContentProps {
class?: any;
modal?: boolean;
open?: boolean;
side?: SheetVariants['side'];
}

Expand All @@ -28,7 +30,13 @@ const props = defineProps<SheetContentProps>();
const emits = defineEmits<DialogContentEmits>();

const delegatedProps = computed(() => {
const { class: _, side: _side, ...delegated } = props;
const {
class: _,
modal: _modal,
open: _open,
side: _side,
...delegated
} = props;

return delegated;
});
Expand All @@ -38,10 +46,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);

<template>
<DialogPortal>
<DialogOverlay
class="bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[1000]"
data-dismissable-modal="true"
/>
<SheetOverlay v-if="open && modal" />
<DialogContent
:class="cn(sheetVariants({ side }), 'z-[1000]', props.class)"
v-bind="{ ...forwarded, ...$attrs }"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import { useScrollLock } from '@vben-core/composables';

useScrollLock();
</script>
<template>
<div
class="bg-overlay data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-[1000]"
data-dismissable-modal="true"
></div>
</template>
4 changes: 2 additions & 2 deletions packages/effects/layouts/src/basic/tabbar/tabbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defineProps<{ showIcon?: boolean; theme?: string }>();

const route = useRoute();
const tabbarStore = useTabbarStore();
const { toggleMaximize } = useContentMaximize();
const { contentIsMaximize, toggleMaximize } = useContentMaximize();
const { refreshTab, unpinTab } = useTabs();

const {
Expand Down Expand Up @@ -73,7 +73,7 @@ if (!preferences.tabbar.persist) {
<TabsToolMore v-if="preferences.tabbar.showMore" :menus="menus" />
<TabsToolScreen
v-if="preferences.tabbar.showMaximize"
:screen="preferences.sidebar.hidden"
:screen="contentIsMaximize"
@change="toggleMaximize"
@update:screen="toggleMaximize"
/>
Expand Down
Loading