44 lines
1.5 KiB
TypeScript
44 lines
1.5 KiB
TypeScript
import { computed, toValue } from 'vue';
|
|
import type { ComputedRef, MaybeRefOrGetter } from 'vue';
|
|
import { isFunction } from '@robonen/stdlib';
|
|
|
|
export type UseArrayJoinReturn = ComputedRef<string>;
|
|
|
|
/**
|
|
* @name useArrayJoin
|
|
* @category Array
|
|
* @description Reactive `Array.prototype.join`, with an optional reactive separator.
|
|
*
|
|
* @param {MaybeRefOrGetter<MaybeRefOrGetter<unknown>[]>} list The source array (items can be reactive)
|
|
* @param {MaybeRefOrGetter<string>} [separator] A reactive separator placed between adjacent elements (defaults to `,`)
|
|
* @returns {UseArrayJoinReturn} A computed string of all elements joined; empty string when the array is empty
|
|
*
|
|
* @example
|
|
* const list = ref(['a', 'b', 'c']);
|
|
* const sep = ref('-');
|
|
* const joined = useArrayJoin(list, sep); // 'a-b-c'
|
|
*
|
|
* @since 0.0.14
|
|
*/
|
|
export function useArrayJoin(
|
|
list: MaybeRefOrGetter<Array<MaybeRefOrGetter<unknown>>>,
|
|
separator?: MaybeRefOrGetter<string>,
|
|
): UseArrayJoinReturn {
|
|
return computed(() => {
|
|
const resolved = toValue(list);
|
|
|
|
// `Array.prototype.join` already stringifies each element, but resolving
|
|
// reactive items first lets the computed track per-item ref dependencies.
|
|
let needsUnwrap = false;
|
|
for (const item of resolved) {
|
|
if (isFunction(item) || (typeof item === 'object' && item !== null && 'value' in item)) {
|
|
needsUnwrap = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const source = needsUnwrap ? resolved.map(item => toValue(item)) : resolved;
|
|
return source.join(toValue(separator));
|
|
});
|
|
}
|