feat(vue): expand @robonen/vue composable collection
Composables, tests, category barrels, and README for @robonen/vue.
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
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.15
|
||||
*/
|
||||
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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user