159 lines
4.5 KiB
TypeScript
159 lines
4.5 KiB
TypeScript
import { shallowRef } from 'vue';
|
|
import type { ComputedRef, ShallowRef } from 'vue';
|
|
import { noop } from '@robonen/stdlib';
|
|
import { defaultWindow } from '@/types';
|
|
import type { ConfigurableWindow } from '@/types';
|
|
import { useSupported } from '@/composables/utilities/useSupported';
|
|
import { tryOnMounted } from '@/composables/lifecycle/tryOnMounted';
|
|
|
|
/**
|
|
* A single font face exposed by the [Local Font Access API](https://developer.mozilla.org/en-US/docs/Web/API/FontData).
|
|
*/
|
|
export interface FontData {
|
|
/**
|
|
* The PostScript name of the font (e.g. `"Arial-BoldMT"`)
|
|
*/
|
|
readonly postscriptName: string;
|
|
|
|
/**
|
|
* The full, human-readable name of the font (e.g. `"Arial Bold"`)
|
|
*/
|
|
readonly fullName: string;
|
|
|
|
/**
|
|
* The font family (e.g. `"Arial"`)
|
|
*/
|
|
readonly family: string;
|
|
|
|
/**
|
|
* The font style/subfamily (e.g. `"Bold"`)
|
|
*/
|
|
readonly style: string;
|
|
|
|
/**
|
|
* Resolve the raw font file as a `Blob` (the full SFNT binary)
|
|
*/
|
|
blob: () => Promise<Blob>;
|
|
}
|
|
|
|
export interface QueryLocalFontsOptions {
|
|
/**
|
|
* Restrict the results to the fonts whose PostScript names appear in this list.
|
|
*/
|
|
postscriptNames?: string[];
|
|
}
|
|
|
|
interface WindowWithLocalFonts {
|
|
queryLocalFonts: (options?: QueryLocalFontsOptions) => Promise<FontData[]>;
|
|
}
|
|
|
|
export interface UseLocalFontsOptions extends ConfigurableWindow {
|
|
/**
|
|
* Query the local fonts immediately on mount. The Local Font Access API
|
|
* requires the `local-fonts` permission (which may prompt the user), so this
|
|
* is disabled by default — call `query()` from a user gesture instead.
|
|
*
|
|
* @default false
|
|
*/
|
|
immediate?: boolean;
|
|
|
|
/**
|
|
* Called when a query rejects (e.g. the permission is denied) instead of
|
|
* throwing. The same value is also stored in the returned `error` ref.
|
|
*
|
|
* @default noop
|
|
*/
|
|
onError?: (error: unknown) => void;
|
|
}
|
|
|
|
export interface UseLocalFontsReturn {
|
|
/**
|
|
* Whether the [Local Font Access API](https://developer.mozilla.org/en-US/docs/Web/API/Local_Font_Access_API) is supported
|
|
*/
|
|
isSupported: ComputedRef<boolean>;
|
|
|
|
/**
|
|
* The fonts returned by the most recent successful `query()`
|
|
*/
|
|
fonts: ShallowRef<FontData[]>;
|
|
|
|
/**
|
|
* The last error thrown by `query()`, or `null`
|
|
*/
|
|
error: ShallowRef<unknown | null>;
|
|
|
|
/**
|
|
* Enumerate the locally installed fonts. Resolves with the font list, or
|
|
* `undefined` when the API is unsupported. Pass `postscriptNames` to filter.
|
|
*/
|
|
query: (queryOptions?: QueryLocalFontsOptions) => Promise<FontData[] | undefined>;
|
|
}
|
|
|
|
/**
|
|
* @name useLocalFonts
|
|
* @category Browser
|
|
* @description Reactive wrapper around the [Local Font Access API](https://developer.mozilla.org/en-US/docs/Web/API/Local_Font_Access_API) for enumerating the user's locally installed fonts.
|
|
*
|
|
* @param {UseLocalFontsOptions} [options={}] Options
|
|
* @param {boolean} [options.immediate=false] Query immediately on mount (requires the `local-fonts` permission)
|
|
* @param {Function} [options.onError=noop] Error callback invoked instead of throwing
|
|
* @param {Window} [options.window=defaultWindow] Custom `window` instance
|
|
* @returns {UseLocalFontsReturn} `isSupported`, `fonts`, `error`, and `query()`
|
|
*
|
|
* @example
|
|
* const { isSupported, fonts, query } = useLocalFonts();
|
|
* // Call from a click handler so the permission prompt is allowed
|
|
* async function pickFonts() {
|
|
* await query();
|
|
* console.log(fonts.value.map(font => font.fullName));
|
|
* }
|
|
*
|
|
* @example
|
|
* // Query only specific fonts by PostScript name
|
|
* const { fonts, query } = useLocalFonts();
|
|
* await query({ postscriptNames: ['Arial-BoldMT'] });
|
|
*
|
|
* @since 0.0.14
|
|
*/
|
|
export function useLocalFonts(options: UseLocalFontsOptions = {}): UseLocalFontsReturn {
|
|
const {
|
|
window = defaultWindow,
|
|
immediate = false,
|
|
onError = noop,
|
|
} = options;
|
|
|
|
const isSupported = useSupported(() => !!window && 'queryLocalFonts' in window);
|
|
const fonts = shallowRef<FontData[]>([]);
|
|
const error = shallowRef<unknown | null>(null);
|
|
|
|
async function query(queryOptions?: QueryLocalFontsOptions): Promise<FontData[] | undefined> {
|
|
if (!isSupported.value || !window)
|
|
return undefined;
|
|
|
|
error.value = null;
|
|
|
|
try {
|
|
const result = await (window as unknown as WindowWithLocalFonts).queryLocalFonts(queryOptions);
|
|
fonts.value = result;
|
|
|
|
return result;
|
|
}
|
|
catch (err) {
|
|
error.value = err;
|
|
onError(err);
|
|
|
|
return undefined;
|
|
}
|
|
}
|
|
|
|
if (immediate)
|
|
tryOnMounted(() => query());
|
|
|
|
return {
|
|
isSupported,
|
|
fonts,
|
|
error,
|
|
query,
|
|
};
|
|
}
|