vinicius73/vue-page-title

View on GitHub
lib/composable.ts

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
import type { ComputedRef, ComputedGetter, WatchSource } from 'vue';
import type { SetTitleFn } from './types';
import { inject, computed, ref, watch } from 'vue';
import { PAGE_TITLE, SET_PAGE_TITLE } from './injection-keys';

export type initialValue =
  | string
  | ComputedRef<string>
  | ComputedGetter<string>
  | WatchSource<string>;

/**
 * Get current title or update it.
 *
 * ## Define initial title
 *
 * ```ts
 * const { title } = useTitle('initial title`)
 * ```
 *
 * ## React from ref state
 *
 * ```ts
 * const name = ref('initial name')
 * const { title } = useTitle(name)
 * ```
 *
 * ## Use like a watch source argument
 *
 * ```ts
 * const product = ref({ name: 'One Piece 1017' })
 * const { title } = useTitle(() => product.name)
 * ```
 *
 * ## Pass a computed as argument
 *
 * ```ts
 * const product = ref({ name: 'One Piece 1017' })
 * const name = computed(() => product.name)
 * const { title } = useTitle(name)
 * ```
 *
 * ## Use `setTitle` to dynamically change the title
 *
 * ```ts
 * const product = ref({ name: 'One Piece 1017' })
 * const { setTitle } = useTitle()
 *
 * watchEffect(() => {
 *   setTitle(product.name)
 * })
 * ```
 */
const useTitle = (
  initial?: initialValue
): { title: ComputedRef<string>; setTitle: SetTitleFn } => {
  const title = inject(PAGE_TITLE, ref<string>(''));
  const setTitle = inject(SET_PAGE_TITLE, () => {});

  if (typeof initial === 'string') {
    setTitle(initial);
  } else if (initial != null) {
    watch(initial, setTitle, { immediate: true });
  }

  return {
    title: computed(() => title?.value),
    setTitle,
  };
};

export { useTitle };