import Col from "@/components/system/Column.vue"; import Row from "@/components/system/Row.vue"; import { CoercableComponent, Component as ComponentKey, GenericComponent } from "@/features/feature"; import { isArray } from "@vue/shared"; import { Component, computed, ComputedRef, DefineComponent, defineComponent, h, PropType, ref, Ref, unref, WritableComputedRef } from "vue"; import { ProcessedComputable } from "./computed"; export function coerceComponent(component: CoercableComponent, defaultWrapper = "span"): Component { if (typeof component === "string") { component = component.trim(); if (component.charAt(0) !== "<") { component = `<${defaultWrapper}>${component}`; } return defineComponent({ template: component }); } return component; } export function render(object: { [ComponentKey]: GenericComponent }): DefineComponent { return defineComponent({ render() { const component = object[ComponentKey]; return h(component, object); } }); } export function renderRow( objects: { [ComponentKey]: GenericComponent }[], props: Record | null = null ): DefineComponent { return defineComponent({ render() { return h( Row as DefineComponent, props, objects.map(obj => h(obj[ComponentKey], obj)) ); } }); } export function renderCol( objects: { [ComponentKey]: GenericComponent }[], props: Record | null = null ): DefineComponent { return defineComponent({ render() { return h( Col as DefineComponent, props, objects.map(obj => h(obj[ComponentKey], obj)) ); } }); } export function isCoercableComponent(component: unknown): component is CoercableComponent { if (typeof component === "string") { return true; } else if (typeof component === "object") { if (component == null) { return false; } return "render" in component || "component" in component; } return false; } export function setupHoldToClick( onClick?: Ref, onHold?: Ref ): { start: VoidFunction; stop: VoidFunction; handleHolding: VoidFunction; } { const interval = ref(null); function start() { if (!interval.value) { interval.value = setInterval(handleHolding, 250); } } function stop() { if (interval.value) { clearInterval(interval.value); interval.value = null; } } function handleHolding() { if (onHold && onHold.value) { onHold.value(); } else if (onClick && onClick.value) { onClick.value(); } } return { start, stop, handleHolding }; } export function computeComponent( component: Ref> ): ComputedRef { return computed(() => { return coerceComponent(unref(unref>(component))); }); } export function computeOptionalComponent( component: Ref | undefined> ): ComputedRef { return computed(() => { let currComponent = unref | undefined>( component ); if (currComponent == null) return; currComponent = unref(currComponent); return currComponent == null ? undefined : coerceComponent(currComponent); }); } export function wrapRef(ref: Ref>): ComputedRef { return computed(() => unwrapRef(ref)); } export function unwrapRef(ref: Ref>): T { return unref(unref>(ref)); } type PropTypes = | typeof Boolean | typeof String | typeof Number | typeof Function | typeof Object | typeof Array; // TODO Unfortunately, the typescript engine gives up on typing completely when you use this method, // Even though it has the same typing as when doing it manually export function processedPropType(...types: PropTypes[]): PropType> { if (!types.includes(Object)) { types.push(Object); } return types as PropType>; }