Skip to content

Commit

Permalink
feat: integrate new component Tippy with demo (#5355)
Browse files Browse the repository at this point in the history
* 添加新的工具提示组件Tippy
  • Loading branch information
mynetfan authored Jan 11, 2025
1 parent 4676895 commit a263731
Show file tree
Hide file tree
Showing 12 changed files with 462 additions and 1 deletion.
4 changes: 4 additions & 0 deletions apps/web-antd/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp, watchEffect } from 'vue';

import { registerAccessDirective } from '@vben/access';
import { initTippy } from '@vben/common-ui';
import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
Expand Down Expand Up @@ -29,6 +30,9 @@ async function bootstrap(namespace: string) {
// 安装权限指令
registerAccessDirective(app);

// 初始化 tippy
initTippy(app);

// 配置路由及路由守卫
app.use(router);

Expand Down
4 changes: 4 additions & 0 deletions apps/web-ele/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp, watchEffect } from 'vue';

import { registerAccessDirective } from '@vben/access';
import { initTippy } from '@vben/common-ui';
import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
Expand Down Expand Up @@ -32,6 +33,9 @@ async function bootstrap(namespace: string) {
// 安装权限指令
registerAccessDirective(app);

// 初始化 tippy
initTippy(app);

// 配置路由及路由守卫
app.use(router);

Expand Down
4 changes: 4 additions & 0 deletions apps/web-naive/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp, watchEffect } from 'vue';

import { registerAccessDirective } from '@vben/access';
import { initTippy } from '@vben/common-ui';
import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
Expand Down Expand Up @@ -28,6 +29,9 @@ async function bootstrap(namespace: string) {
// 安装权限指令
registerAccessDirective(app);

// 初始化 tippy
initTippy(app);

// 配置路由及路由守卫
app.use(router);

Expand Down
5 changes: 4 additions & 1 deletion packages/effects/common-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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:*",
Expand All @@ -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:"
Expand Down
1 change: 1 addition & 0 deletions packages/effects/common-ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down
100 changes: 100 additions & 0 deletions packages/effects/common-ui/src/components/tippy/directive.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 66 additions & 0 deletions packages/effects/common-ui/src/components/tippy/index.ts
Original file line number Diff line number Diff line change
@@ -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,
);
};
4 changes: 4 additions & 0 deletions playground/src/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createApp, watchEffect } from 'vue';

import { registerAccessDirective } from '@vben/access';
import { initTippy } from '@vben/common-ui';
import { preferences } from '@vben/preferences';
import { initStores } from '@vben/stores';
import '@vben/styles';
Expand Down Expand Up @@ -30,6 +31,9 @@ async function bootstrap(namespace: string) {
// 安装权限指令
registerAccessDirective(app);

// 初始化 tippy
initTippy(app);

// 配置路由及路由守卫
app.use(router);

Expand Down
9 changes: 9 additions & 0 deletions playground/src/router/routes/modules/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,15 @@ const routes: RouteRecordRaw[] = [
title: $t('examples.layout.col-page'),
},
},
{
name: 'TippyDemo',
path: '/examples/tippy',
component: () => import('#/views/examples/tippy/index.vue'),
meta: {
icon: 'material-symbols:chat-bubble',
title: 'Tippy',
},
},
],
},
];
Expand Down
Loading

0 comments on commit a263731

Please sign in to comment.