import { Switch } from '@/components/ui/switch'; import { mergeAttributes, Node } from '@tiptap/core'; import { NodeViewWrapper, ReactNodeViewRenderer, type ReactNodeViewProps, } from '@tiptap/react'; import { __ } from '@wordpress/i18n'; import { FileUp } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; type Attrs = { label: string; required: boolean; accept: string }; declare module '@tiptap/core' { interface Commands { fileUpload: { insertFileUpload: (attrs?: { label?: string; required?: boolean; accept?: string; }) => ReturnType; }; } } export const FileUpload = Node.create({ name: 'fileUpload', group: 'block', atom: true, selectable: true, draggable: true, addAttributes() { return { label: { default: '' }, required: { default: false }, accept: { default: '' }, autoFocus: { default: false, renderHTML: () => ({}) }, }; }, parseHTML() { return [{ tag: 'div[data-type="file-upload"]' }]; }, renderHTML({ HTMLAttributes }) { return ['div', mergeAttributes(HTMLAttributes, { 'data-type': 'file-upload' })]; }, addNodeView() { return ReactNodeViewRenderer(FileUploadComponent); }, addCommands() { return { insertFileUpload: (attrs = {}) => // eslint-disable-next-line @typescript-eslint/no-explicit-any ({ chain }: any) => chain() .insertContent({ type: 'fileUpload', attrs: { label: attrs.label ?? '', required: attrs.required ?? false, accept: attrs.accept ?? '', autoFocus: true, }, }) .run(), }; }, }); function FileUploadComponent({ node, updateAttributes }: ReactNodeViewProps) { const { label, required, accept, autoFocus } = node.attrs as Attrs & { autoFocus: boolean }; const [attrs, setAttrs] = useState({ label, required, accept }); const labelRef = useRef(null); useEffect(() => { if (autoFocus) { labelRef.current?.focus(); updateAttributes({ autoFocus: false }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); return (
{__('File Upload', 'allcoach')}
{__('Required?', 'allcoach')} { setAttrs((prev) => ({ ...prev, required: v })); updateAttributes({ required: v }); }} />
setAttrs((prev) => ({ ...prev, label: e.target.value }))} onBlur={() => updateAttributes({ label: attrs.label })} className="w-full border-b border-dashed border-gray-200 bg-transparent pb-1 text-[14px] font-semibold text-gray-800 outline-none placeholder:font-normal placeholder:text-gray-400 focus:border-teal-400" placeholder={__('Question…', 'allcoach')} /> {/* Upload zone preview */}
{__('File upload zone', 'allcoach')}
{/* Accepted file types */}
setAttrs((prev) => ({ ...prev, accept: e.target.value }))} onBlur={() => updateAttributes({ accept: attrs.accept })} className="w-full rounded-md border border-gray-100 bg-gray-50 px-2.5 py-1.5 text-[12px] text-gray-700 outline-none placeholder:text-gray-400 focus:border-teal-400" placeholder={__('.pdf, .docx, image/*', 'allcoach')} />
); }