diff --git a/playground/pages/Index.vue b/playground/pages/Index.vue index 5588c20..05409e7 100644 --- a/playground/pages/Index.vue +++ b/playground/pages/Index.vue @@ -195,6 +195,26 @@ +
+ useTippy + plain string: + +
+ +
+ useTippy + computed string: + +
+
Tippy component + change content and props realtime using component @@ -413,6 +433,15 @@ export default defineComponent({ content: 'Test Vue component', }) + const buttonText = ref() + + useTippy(buttonText, 'String content') + + const buttonTextComputed = ref() + const computedText = computed(() => `Counter: ${counter.value}`) + + useTippy(buttonTextComputed, computedText); + const { x, y } = useMousePosition() const { tippy } = useTippy(() => document.body, { @@ -494,6 +523,8 @@ export default defineComponent({ button7, target7, vueComponentButton, + buttonText, + buttonTextComputed, tippyComponent1, log: console.log, } diff --git a/src/composables/useTippy.ts b/src/composables/useTippy.ts index 4e67263..5f72f8a 100644 --- a/src/composables/useTippy.ts +++ b/src/composables/useTippy.ts @@ -2,7 +2,6 @@ import tippy, { Instance, Props, Content } from 'tippy.js' import { ref, onMounted, - Ref, isRef, isReactive, isVNode, @@ -15,7 +14,8 @@ import { shallowRef, App, } from 'vue' -import { TippyOptions, TippyContent } from '../types' +import { TippyOptions, TippyContent, MaybeRef, MaybeRefOrGetter } from '../types' +import { isObject, isString, toValue, isComponentInstance } from '../utils' tippy.setDefaultProps({ //@ts-ignore @@ -24,15 +24,11 @@ tippy.setDefaultProps({ }, }) -const isComponentInstance = (value: any): value is { $el: any } => { - return value instanceof Object && '$' in value && '$el' in value -} - type TippyElement = Element | any // TODO: use ComponentPublicInstance export function useTippy( - el: TippyElement | (() => TippyElement) | Ref | Ref, - opts: TippyOptions = {}, + el: MaybeRefOrGetter, + opts: TippyOptions | MaybeRef = {}, settings: { mount: boolean, appName: string, @@ -109,15 +105,15 @@ export function useTippy( return newContent! } - const getProps = (opts: TippyOptions): Partial => { + const getProps = (opts: TippyOptions | MaybeRef): Partial => { + const value = toValue(opts); + let options: any = {} - if (isRef(opts)) { - options = opts.value || {} - } else if (isReactive(opts)) { - options = { ...opts } + if (isString(value)) { + options = { content: value } } else { - options = { ...opts } + options = { ...value } } if (options.content) { @@ -173,23 +169,41 @@ export function useTippy( return options as Props } + const getOptsContent = () => { + const value = toValue(opts) + + if (isString(value)) { + return value + } + + return value?.content + } + const refresh = () => { if (!instance.value) return - instance.value.setProps(getProps(opts)) + if (isObject(toValue(opts))) { + instance.value.setProps(getProps(opts)) + } else { + refreshContent() + } } const refreshContent = () => { - if (!instance.value || !opts.content) return + if (!instance.value) return + + const content = getOptsContent() + + if (!content) return - instance.value.setContent(getContent(opts.content)) + instance.value.setContent(getContent(content)) } const setContent = (value: TippyContent) => { instance.value?.setContent(getContent(value)) } - const setProps = (value: TippyOptions) => { + const setProps = (value: TippyOptions | MaybeRef) => { instance.value?.setProps(getProps(value)) } @@ -283,9 +297,9 @@ export function useTippy( }) } - if (isRef(opts) || isReactive(opts)) { + if ((isRef(opts) || isReactive(opts)) && !isString(opts)) { watch(opts, refresh, { immediate: false }) - } else if (isRef(opts.content)) { + } else if (isObject(opts) && isRef(opts.content)) { watch(opts.content, refreshContent, { immediate: false }) } diff --git a/src/types/index.ts b/src/types/index.ts index 48b62e5..99bacde 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,7 +1,7 @@ import Tippy from '../components/Tippy' import { useTippy } from '../composables' import { Props, Content, DefaultProps, Instance } from 'tippy.js' -import { VNode, Ref, Component, UnwrapNestedRefs } from 'vue' +import { VNode, Ref, Component, UnwrapNestedRefs, ShallowRef, WritableComputedRef, ComputedRef } from 'vue' export declare type TippyContent = Content | VNode | Component | Ref export declare type TippyTarget = @@ -35,3 +35,11 @@ export interface TippyPluginOptions { export type TippyInstance = Instance | Element | undefined export type TippyInstances = Ref[] | Ref | (() => TippyInstance[]) + +export type MaybeRef = + | T + | Ref + | ShallowRef + | WritableComputedRef + +export type MaybeRefOrGetter = MaybeRef | ComputedRef | (() => T) \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 0000000..a7e8047 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,27 @@ +import { isRef, unref } from 'vue' +import { MaybeRefOrGetter } from '../types' + +export const isComponentInstance = (value: any): value is { $el: any } => { + return value instanceof Object && '$' in value && '$el' in value +} + +export const isString = (val: unknown): val is string => typeof val === 'string' + +export const isFunction = (val: unknown): val is Function => + typeof val === 'function' + +export const isObject = (val: unknown): val is Record => + val !== null && typeof val === 'object' + + +export function toValue(source: MaybeRefOrGetter): T { + if (isRef(source)) { + return unref(source) + } + + if (isFunction(source)) { + return source() + } + + return source; +} \ No newline at end of file