| | |
| | | return (search) => addQueryArgs('/wp/v2/search', { search, type: 'post', subtype: field.post_type, per_page: 20 }); |
| | | }; |
| | | |
| | | const createPayload = (field, subtype, name) => |
| | | subtype === 'post' ? { title: name, status: 'publish', postType: field.post_type } : { name }; |
| | | |
| | | const labelOf = (item, subtype) => (subtype === 'user' ? item.name : item.title?.rendered ?? item.title ?? item.name); |
| | | |
| | | const SelectorField = ({ field, value, onChange }) => { |
| | | const subtype = resolveSubtype(field); |
| | | const canCreate = subtype === 'taxonomy'; |
| | | console.log(field); |
| | | const buildPath = searchPath(field); |
| | | const ids = Array.isArray(value) ? value : value ? [value] : []; |
| | | const ids = Array.isArray(value) ? value : value ? value.split(',') : []; |
| | | |
| | | const [tokens, setTokens] = useState([]); // display strings |
| | | const [idByLabel, setIdByLabel] = useState({}); |
| | | const [options, setOptions] = useState({}); // label -> id, from last search |
| | | const [search, setSearch] = useState(''); |
| | | const [creating, setCreating] = useState(false); |
| | | |
| | | const createLabel = search ? `Not found. Create "${search}"?` : null; |
| | | |
| | | |
| | | // Resolve current IDs to labels on mount / value change |
| | | useEffect(() => { |
| | |
| | | }, [JSON.stringify(ids)]); |
| | | |
| | | const onInputChange = useCallback((search) => { |
| | | if (!search) return; |
| | | setSearch(search); |
| | | if (!search) { setOptions({}); return;} |
| | | |
| | | apiFetch({ path: buildPath(search) }) |
| | | .then((results) => { |
| | | const map = {}; |
| | |
| | | .catch(() => {}); |
| | | }, [buildPath, subtype]); |
| | | |
| | | const onChangeTokens = (newTokens) => { |
| | | setTokens(newTokens); |
| | | const newIds = newTokens |
| | | .map((label) => idByLabel[label] ?? options[label]) |
| | | .filter((id) => id !== undefined); |
| | | setIdByLabel((prev) => ({ ...prev, ...options })); |
| | | |
| | | const commitIds = (newIds) => { |
| | | const isSingle = field.max === 1; |
| | | if (isSingle) { |
| | | onChange(newIds[newIds.length - 1] ?? 0); |
| | |
| | | } |
| | | }; |
| | | |
| | | const onChangeTokens = (newTokens) => { |
| | | const pendingCreate = newTokens.find((t) => t === createLabel); |
| | | |
| | | if (pendingCreate && canCreate && !creating) { |
| | | setCreating(true); |
| | | apiFetch({ path: `/wp/v2/${field.taxonomy}`, method: 'POST', data: createPayload(field, subtype, search) }) |
| | | .then((item) => { |
| | | const label = labelOf(item, subtype); |
| | | setIdByLabel((prev) => ({ ...prev, [label]: item.id })); |
| | | setTokens((prev) => { |
| | | const finalTokens = prev.filter((t) => t !== createLabel).concat(label); |
| | | const newIds = finalTokens.map((l) => idByLabel[l] ?? options[l] ?? (l === label ? item.id : undefined)) |
| | | .filter((id) => id !== undefined); |
| | | commitIds(newIds); |
| | | return finalTokens; |
| | | }); |
| | | }) |
| | | .catch(() => {}) |
| | | .finally(() => setCreating(false)); |
| | | return; |
| | | } |
| | | |
| | | const resolved = newTokens.filter( |
| | | (label) => idByLabel[label] !== undefined || options[label] !== undefined |
| | | ); |
| | | const newIds = resolved.map((label) => idByLabel[label] ?? options[label]); |
| | | setTokens(resolved); |
| | | setIdByLabel((prev) => ({ ...prev, ...options })); |
| | | commitIds(newIds); |
| | | }; |
| | | |
| | | const noMatch = search && !Object.keys(options).some((l) => l.toLowerCase() === search.toLowerCase()); |
| | | const suggestions = field.max === 1 && tokens.length |
| | | ? [] |
| | | : [...Object.keys(options), ...(canCreate && noMatch ? [createLabel] : [])]; |
| | | |
| | | |
| | | return ( |
| | | <FormTokenField |
| | | label={field.label} |
| | | help={field.description} |
| | | value={tokens} |
| | | suggestions={field.max === 1 && tokens.length ? [] : Object.keys(options)} |
| | | suggestions={suggestions} |
| | | onChange={onChangeTokens} |
| | | onInputChange={onInputChange} |
| | | maxLength={field.max || undefined} |
| | | id={field.name} |
| | | __experimentalExpandOnFocus |
| | | /> |
| | | ); |