mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 16:46:19 +08:00
feat: integrate new component Tippy
with demo (#5355)
* 添加新的工具提示组件Tippy
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"dependencies": {
|
||||
"@vben-core/form-ui": "workspace:*",
|
||||
"@vben-core/popup-ui": "workspace:*",
|
||||
"@vben-core/preferences": "workspace:*",
|
||||
"@vben-core/shadcn-ui": "workspace:*",
|
||||
"@vben-core/shared": "workspace:*",
|
||||
"@vben/constants": "workspace:*",
|
||||
@@ -32,8 +33,10 @@
|
||||
"@vueuse/core": "catalog:",
|
||||
"@vueuse/integrations": "catalog:",
|
||||
"qrcode": "catalog:",
|
||||
"tippy.js": "catalog:",
|
||||
"vue": "catalog:",
|
||||
"vue-router": "catalog:"
|
||||
"vue-router": "catalog:",
|
||||
"vue-tippy": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/qrcode": "catalog:"
|
||||
|
@@ -5,6 +5,7 @@ export * from './ellipsis-text';
|
||||
export * from './icon-picker';
|
||||
export * from './page';
|
||||
export * from './resize';
|
||||
export * from './tippy';
|
||||
export * from '@vben-core/form-ui';
|
||||
export * from '@vben-core/popup-ui';
|
||||
|
||||
|
100
packages/effects/common-ui/src/components/tippy/directive.ts
Normal file
100
packages/effects/common-ui/src/components/tippy/directive.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import type { ComputedRef, Directive } from 'vue';
|
||||
|
||||
import { useTippy } from 'vue-tippy';
|
||||
|
||||
export default function useTippyDirective(isDark: ComputedRef<boolean>) {
|
||||
const directive: Directive = {
|
||||
mounted(el, binding, vnode) {
|
||||
const opts =
|
||||
typeof binding.value === 'string'
|
||||
? { content: binding.value }
|
||||
: binding.value || {};
|
||||
|
||||
const modifiers = Object.keys(binding.modifiers || {});
|
||||
const placement = modifiers.find((modifier) => modifier !== 'arrow');
|
||||
const withArrow = modifiers.includes('arrow');
|
||||
|
||||
if (placement) {
|
||||
opts.placement = opts.placement || placement;
|
||||
}
|
||||
|
||||
if (withArrow) {
|
||||
opts.arrow = opts.arrow === undefined ? true : opts.arrow;
|
||||
}
|
||||
|
||||
if (vnode.props && vnode.props.onTippyShow) {
|
||||
opts.onShow = function (...args: any[]) {
|
||||
return vnode.props?.onTippyShow(...args);
|
||||
};
|
||||
}
|
||||
|
||||
if (vnode.props && vnode.props.onTippyShown) {
|
||||
opts.onShown = function (...args: any[]) {
|
||||
return vnode.props?.onTippyShown(...args);
|
||||
};
|
||||
}
|
||||
|
||||
if (vnode.props && vnode.props.onTippyHidden) {
|
||||
opts.onHidden = function (...args: any[]) {
|
||||
return vnode.props?.onTippyHidden(...args);
|
||||
};
|
||||
}
|
||||
|
||||
if (vnode.props && vnode.props.onTippyHide) {
|
||||
opts.onHide = function (...args: any[]) {
|
||||
return vnode.props?.onTippyHide(...args);
|
||||
};
|
||||
}
|
||||
|
||||
if (vnode.props && vnode.props.onTippyMount) {
|
||||
opts.onMount = function (...args: any[]) {
|
||||
return vnode.props?.onTippyMount(...args);
|
||||
};
|
||||
}
|
||||
|
||||
if (el.getAttribute('title') && !opts.content) {
|
||||
opts.content = el.getAttribute('title');
|
||||
el.removeAttribute('title');
|
||||
}
|
||||
|
||||
if (el.getAttribute('content') && !opts.content) {
|
||||
opts.content = el.getAttribute('content');
|
||||
}
|
||||
|
||||
useTippy(el, opts);
|
||||
},
|
||||
unmounted(el) {
|
||||
if (el.$tippy) {
|
||||
el.$tippy.destroy();
|
||||
} else if (el._tippy) {
|
||||
el._tippy.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
updated(el, binding) {
|
||||
const opts =
|
||||
typeof binding.value === 'string'
|
||||
? { content: binding.value, theme: isDark.value ? '' : 'light' }
|
||||
: Object.assign(
|
||||
{ theme: isDark.value ? '' : 'light' },
|
||||
binding.value,
|
||||
);
|
||||
|
||||
if (el.getAttribute('title') && !opts.content) {
|
||||
opts.content = el.getAttribute('title');
|
||||
el.removeAttribute('title');
|
||||
}
|
||||
|
||||
if (el.getAttribute('content') && !opts.content) {
|
||||
opts.content = el.getAttribute('content');
|
||||
}
|
||||
|
||||
if (el.$tippy) {
|
||||
el.$tippy.setProps(opts || {});
|
||||
} else if (el._tippy) {
|
||||
el._tippy.setProps(opts || {});
|
||||
}
|
||||
},
|
||||
};
|
||||
return directive;
|
||||
}
|
66
packages/effects/common-ui/src/components/tippy/index.ts
Normal file
66
packages/effects/common-ui/src/components/tippy/index.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import type { DefaultProps, Props } from 'tippy.js';
|
||||
|
||||
import type { App, SetupContext } from 'vue';
|
||||
|
||||
import { h, watchEffect } from 'vue';
|
||||
import { setDefaultProps, Tippy as TippyComponent } from 'vue-tippy';
|
||||
|
||||
import { usePreferences } from '@vben-core/preferences';
|
||||
|
||||
import useTippyDirective from './directive';
|
||||
|
||||
import 'tippy.js/dist/tippy.css';
|
||||
import 'tippy.js/themes/light.css';
|
||||
import 'tippy.js/animations/scale.css';
|
||||
import 'tippy.js/animations/scale-subtle.css';
|
||||
import 'tippy.js/animations/scale-extreme.css';
|
||||
import 'tippy.js/animations/shift-away.css';
|
||||
import 'tippy.js/animations/perspective.css';
|
||||
|
||||
const { isDark } = usePreferences();
|
||||
export type TippyProps = Props & {
|
||||
animation?:
|
||||
| 'fade'
|
||||
| 'perspective'
|
||||
| 'scale'
|
||||
| 'scale-extreme'
|
||||
| 'scale-subtle'
|
||||
| 'shift-away'
|
||||
| boolean;
|
||||
theme?: 'auto' | 'dark' | 'light';
|
||||
};
|
||||
|
||||
export function initTippy(app: App<Element>, options?: DefaultProps) {
|
||||
setDefaultProps({
|
||||
allowHTML: true,
|
||||
delay: [500, 200],
|
||||
theme: isDark.value ? '' : 'light',
|
||||
...options,
|
||||
});
|
||||
if (!options || !Reflect.has(options, 'theme') || options.theme === 'auto') {
|
||||
watchEffect(() => {
|
||||
setDefaultProps({ theme: isDark.value ? '' : 'light' });
|
||||
});
|
||||
}
|
||||
|
||||
app.directive('tippy', useTippyDirective(isDark));
|
||||
}
|
||||
|
||||
export const Tippy = (props: any, { attrs, slots }: SetupContext) => {
|
||||
let theme: string = (attrs.theme as string) ?? 'auto';
|
||||
if (theme === 'auto') {
|
||||
theme = isDark.value ? '' : 'light';
|
||||
}
|
||||
if (theme === 'dark') {
|
||||
theme = '';
|
||||
}
|
||||
return h(
|
||||
TippyComponent,
|
||||
{
|
||||
...props,
|
||||
...attrs,
|
||||
theme,
|
||||
},
|
||||
slots,
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user