'use client'; import { useEffect, useRef, useState } from 'react'; import type { EditorAsset, EditorError } from '../host'; import type { EditorLabels } from '../labels'; import { readImageDimensions } from './imageDimensions'; export interface DefaultAssetPickerProps { readonly accept: string; readonly labels: EditorLabels['asset']; readonly onPick: (asset: EditorAsset) => void; readonly onError?: (error: EditorError) => void; } function extensionFrom(value: string): string | undefined { const withoutQuery = value.split(/[?#]/, 1)[0]; const extension = withoutQuery.split('.').pop()?.toLowerCase(); return extension && extension !== withoutQuery ? extension : undefined; } function matchesAccept(file: File, accept: string): boolean { return accept.split(',').some((entry) => { const expected = entry.trim(); if (expected.endsWith('/*')) return file.type.startsWith(expected.slice(0, -1)); if (expected.startsWith('.')) return file.name.toLowerCase().endsWith(expected.toLowerCase()); return file.type === expected; }); } function fileToDataUrl(file: File): Promise { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(String(reader.result)); reader.onerror = () => reject(reader.error); reader.readAsDataURL(file); }); } export function DefaultAssetPicker({ accept, labels, onPick, onError }: DefaultAssetPickerProps) { const inputRef = useRef(null); const mountedRef = useRef(true); const [url, setUrl] = useState(''); useEffect(() => { mountedRef.current = true; return () => { mountedRef.current = false; }; }, []); const deliver = async (src: string, ext?: string) => { const dimensions = accept.split(',').some((entry) => entry.trim().startsWith('image/')) ? await readImageDimensions(src) : undefined; if (mountedRef.current) onPick({ src, ext, ...dimensions }); }; const pickFile = async (file: File | undefined) => { if (!file) return; if (!matchesAccept(file, accept)) { onError?.({ code: 'asset-type-mismatch', message: labels.invalidType }); return; } try { await deliver(await fileToDataUrl(file), extensionFrom(file.name)); } catch (cause) { onError?.({ code: 'asset-read-failed', message: labels.readFailed, cause }); } }; const pickUrl = () => { const src = url.trim(); if (!src) return; void deliver(src, extensionFrom(src)); }; return (
void pickFile(event.target.files?.[0])} />
{labels.orUrl}
setUrl(event.target.value)} onKeyDown={(event) => { if (event.key === 'Enter') pickUrl(); }} />
); }