import { isRef, ref } from 'vue' import { hyphenate, isObject, isString } from '@vue/shared' import { Loading } from './service' import type { Directive, DirectiveBinding, UnwrapRef } from 'vue' import type { LoadingOptions } from './types' import type { LoadingInstance } from './loading' const INSTANCE_KEY = Symbol('ElLoading') export type LoadingBinding = boolean | UnwrapRef export interface ElementLoading extends HTMLElement { [INSTANCE_KEY]?: { instance: LoadingInstance options: LoadingOptions } } const createInstance = ( el: ElementLoading, binding: DirectiveBinding ) => { const vm = binding.instance const getBindingProp = ( key: K ): LoadingOptions[K] => isObject(binding.value) ? binding.value[key] : undefined const resolveExpression = (key: any) => { const data = (isString(key) && vm?.[key]) || key if (data) return ref(data) else return data } const getProp = (name: K) => resolveExpression( getBindingProp(name) || el.getAttribute(`element-loading-${hyphenate(name)}`) ) const fullscreen = getBindingProp('fullscreen') ?? binding.modifiers.fullscreen const options: LoadingOptions = { text: getProp('text'), svg: getProp('svg'), svgViewBox: getProp('svgViewBox'), spinner: getProp('spinner'), background: getProp('background'), customClass: getProp('customClass'), fullscreen, target: getBindingProp('target') ?? (fullscreen ? undefined : el), body: getBindingProp('body') ?? binding.modifiers.body, lock: getBindingProp('lock') ?? binding.modifiers.lock, } el[INSTANCE_KEY] = { options, instance: Loading(options), } } const updateOptions = ( newOptions: UnwrapRef, originalOptions: LoadingOptions ) => { for (const key of Object.keys(originalOptions)) { if (isRef(originalOptions[key])) originalOptions[key].value = newOptions[key] } } export const vLoading: Directive = { mounted(el, binding) { if (binding.value) { createInstance(el, binding) } }, updated(el, binding) { const instance = el[INSTANCE_KEY] if (binding.oldValue !== binding.value) { if (binding.value && !binding.oldValue) { createInstance(el, binding) } else if (binding.value && binding.oldValue) { if (isObject(binding.value)) updateOptions(binding.value, instance!.options) } else { instance?.instance.close() } } }, unmounted(el) { el[INSTANCE_KEY]?.instance.close() }, }