Jake Vanderwerf
2026-09-06 eef16f5a0f5af0aea313e411534643678ba4bea1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { useState, useEffect } from '@wordpress/element';
import { MediaUpload } from '@wordpress/media-utils';
import {MediaUploadCheck} from '@wordpress/block-editor';
import { Button } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
 
const SUBTYPE_MAP = { image: 'image', video: 'video', document: 'application', all: '' };
 
const Thumbnail = ({ id, onRemove }) => {
    const [media, setMedia] = useState(null);
 
    useEffect(() => {
        let cancelled = false;
        if (!id) return;
        apiFetch({ path: `/wp/v2/media/${id}` })
            .then((data) => !cancelled && setMedia(data))
            .catch(() => {});
        return () => { cancelled = true; };
    }, [id]);
 
    const thumb = media?.media_details?.sizes?.thumbnail?.source_url || media?.source_url;
    const isImage = media?.media_type === 'image';
 
    return (
        <div className="jvb-upload-thumb">
            {isImage && thumb ? (
                <img src={thumb} alt={media?.alt_text || ''} />
            ) : (
                <div className="jvb-upload-thumb-placeholder">
                    {media?.title?.rendered || `#${id}`}
                </div>
            )}
            <Button variant="link" isDestructive onClick={() => onRemove(id)}>
                Remove
            </Button>
        </div>
    );
};
 
const UploadField = ({ field, value, onChange }) => {
    const multiple = field.multiple || field.type === 'gallery';
    const ids = multiple ? (Array.isArray(value) ? value : []) : value;
    const allowedTypes = SUBTYPE_MAP[field.subtype] ? [SUBTYPE_MAP[field.subtype]] : '';
 
    const onSelect = (media) => onChange(multiple ? media.map((m) => m.id) : media.id);
 
    const onRemove = (id) => {
        onChange(multiple ? ids.filter((existing) => existing !== id) : 0);
    };
 
    return (
        <div className="jvb-upload-field" id={field.name}>
            <p className="jvb-field-label">{field.label}</p>
 
            <div className={multiple ? 'jvb-upload-grid' : 'jvb-upload-single'}>
                {multiple
                    ? ids.map((id) => <Thumbnail key={id} id={id} onRemove={onRemove} />)
                    : !!ids && <Thumbnail id={ids} onRemove={onRemove} />}
            </div>
 
            <MediaUploadCheck>
                <MediaUpload
                    onSelect={onSelect}
                    allowedTypes={allowedTypes}
                    multiple={multiple}
                    value={multiple ? ids : ids || undefined}
                    render={({ open }) => (
                        <Button variant="secondary" onClick={open}>
                            {(multiple ? ids.length : ids) ? 'Change' : 'Select'} {field.label}
                        </Button>
                    )}
                />
            </MediaUploadCheck>
        </div>
    );
};
 
export default UploadField;