@wordpress-gcb/fields 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -35
- package/dist/conditional-logic.js +83 -0
- package/{src → dist}/control-context.js +3 -2
- package/{src → dist}/controls/MediaCapabilityGate.js +12 -8
- package/dist/controls/MediaPicker.js +149 -0
- package/dist/controls/MediaTriggerBadges.js +35 -0
- package/{src → dist}/controls/PopoverOrModal.js +49 -43
- package/dist/controls/SortableItem.js +126 -0
- package/dist/controls/button-group.js +46 -0
- package/dist/controls/checkbox-group.js +65 -0
- package/dist/controls/checkbox.js +15 -0
- package/dist/controls/code.js +24 -0
- package/dist/controls/color.js +241 -0
- package/dist/controls/date.js +55 -0
- package/dist/controls/datetime.js +61 -0
- package/dist/controls/email.js +17 -0
- package/dist/controls/file.js +163 -0
- package/dist/controls/gallery.js +371 -0
- package/dist/controls/google-map.js +143 -0
- package/dist/controls/heading-level.js +93 -0
- package/dist/controls/icon.js +292 -0
- package/dist/controls/image.js +360 -0
- package/dist/controls/index.js +88 -0
- package/dist/controls/message.js +86 -0
- package/dist/controls/number.js +19 -0
- package/dist/controls/oembed.js +42 -0
- package/{src → dist}/controls/page-link.js +1 -2
- package/dist/controls/post-object.js +913 -0
- package/dist/controls/radio.js +19 -0
- package/dist/controls/range.js +108 -0
- package/{src → dist}/controls/relationship.js +12 -7
- package/dist/controls/repeater.js +277 -0
- package/dist/controls/richtext.js +494 -0
- package/dist/controls/select.js +144 -0
- package/dist/controls/size.js +59 -0
- package/dist/controls/spacing.js +141 -0
- package/dist/controls/taxonomy.js +569 -0
- package/dist/controls/text.js +16 -0
- package/dist/controls/textarea.js +17 -0
- package/dist/controls/toggle-group.js +28 -0
- package/dist/controls/toggle.js +15 -0
- package/dist/controls/url.js +235 -0
- package/dist/controls/user.js +383 -0
- package/{src → dist}/controls/wysiwyg.js +1 -1
- package/{src → dist}/hooks/useTokens.js +25 -21
- package/{src → dist}/index.js +2 -8
- package/dist/inspector.js +163 -0
- package/{src → dist}/provider.js +18 -17
- package/dist/utils/map-utils.js +54 -0
- package/dist/utils/token-helper.js +396 -0
- package/{src → dist}/validation-context.js +4 -4
- package/package.json +35 -13
- package/src/conditional-logic.js +0 -77
- package/src/controls/MediaPicker.js +0 -139
- package/src/controls/MediaTriggerBadges.js +0 -31
- package/src/controls/SortableItem.js +0 -110
- package/src/controls/button-group.js +0 -49
- package/src/controls/checkbox-group.js +0 -55
- package/src/controls/checkbox.js +0 -13
- package/src/controls/code.js +0 -21
- package/src/controls/color.js +0 -235
- package/src/controls/date.js +0 -37
- package/src/controls/datetime.js +0 -54
- package/src/controls/email.js +0 -15
- package/src/controls/file.js +0 -134
- package/src/controls/gallery.js +0 -338
- package/src/controls/google-map.js +0 -117
- package/src/controls/heading-level.js +0 -99
- package/src/controls/icon.js +0 -301
- package/src/controls/image.js +0 -334
- package/src/controls/index.js +0 -95
- package/src/controls/message.js +0 -56
- package/src/controls/number.js +0 -17
- package/src/controls/oembed.js +0 -32
- package/src/controls/post-object.js +0 -788
- package/src/controls/radio.js +0 -18
- package/src/controls/range.js +0 -110
- package/src/controls/repeater.js +0 -290
- package/src/controls/richtext.js +0 -505
- package/src/controls/select.js +0 -141
- package/src/controls/size.js +0 -49
- package/src/controls/spacing.js +0 -141
- package/src/controls/taxonomy.js +0 -488
- package/src/controls/text.js +0 -14
- package/src/controls/textarea.js +0 -15
- package/src/controls/toggle-group.js +0 -34
- package/src/controls/toggle.js +0 -13
- package/src/controls/url.js +0 -164
- package/src/controls/user.js +0 -343
- package/src/inspector.js +0 -174
- package/src/utils/map-utils.js +0 -51
- package/src/utils/token-helper.js +0 -243
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TaxonomyField — ported verbatim from the original GCB.
|
|
3
|
+
*
|
|
4
|
+
* Single OR multiple term selection (control.multiple, default true).
|
|
5
|
+
* Stored as ID(s) or full term object(s) (control.returnFormat).
|
|
6
|
+
* Optional "create new term" UI (control.allowCreateTerms).
|
|
7
|
+
* Drag-and-drop reordering of selected terms (multi-select only).
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { __ } from '@wordpress/i18n';
|
|
11
|
+
import { Button, TextControl } from '@wordpress/components';
|
|
12
|
+
import PopoverOrModal from './PopoverOrModal';
|
|
13
|
+
import { useState, useEffect, useMemo, useCallback } from '@wordpress/element';
|
|
14
|
+
import apiFetch from '@wordpress/api-fetch';
|
|
15
|
+
import { DndContext, closestCenter, PointerSensor, useSensor, useSensors, DragOverlay } from '@dnd-kit/core';
|
|
16
|
+
import { SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from '@dnd-kit/sortable';
|
|
17
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
18
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
19
|
+
const TOGGLE_BUTTON_STYLE = {
|
|
20
|
+
width: '100%',
|
|
21
|
+
height: 'auto',
|
|
22
|
+
padding: '12px',
|
|
23
|
+
justifyContent: 'flex-start',
|
|
24
|
+
border: '1px solid #ddd',
|
|
25
|
+
borderRadius: '2px',
|
|
26
|
+
backgroundColor: '#fff'
|
|
27
|
+
};
|
|
28
|
+
function TermIcon() {
|
|
29
|
+
return /*#__PURE__*/_jsxs("svg", {
|
|
30
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
31
|
+
viewBox: "0 0 24 24",
|
|
32
|
+
width: "20",
|
|
33
|
+
height: "20",
|
|
34
|
+
style: {
|
|
35
|
+
marginRight: 8,
|
|
36
|
+
flexShrink: 0,
|
|
37
|
+
opacity: 0.6
|
|
38
|
+
},
|
|
39
|
+
children: [/*#__PURE__*/_jsx("path", {
|
|
40
|
+
d: "M8 12c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zm8-2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"
|
|
41
|
+
}), /*#__PURE__*/_jsx("path", {
|
|
42
|
+
d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"
|
|
43
|
+
})]
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
function SortableTermItem({
|
|
47
|
+
term,
|
|
48
|
+
onRemove
|
|
49
|
+
}) {
|
|
50
|
+
const {
|
|
51
|
+
attributes: dndAttributes,
|
|
52
|
+
listeners,
|
|
53
|
+
setNodeRef,
|
|
54
|
+
transform,
|
|
55
|
+
transition,
|
|
56
|
+
isDragging
|
|
57
|
+
} = useSortable({
|
|
58
|
+
id: term.id
|
|
59
|
+
});
|
|
60
|
+
const style = {
|
|
61
|
+
transform: CSS.Transform.toString(transform),
|
|
62
|
+
transition,
|
|
63
|
+
opacity: isDragging ? 0.5 : 1
|
|
64
|
+
};
|
|
65
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
66
|
+
ref: setNodeRef,
|
|
67
|
+
style: style,
|
|
68
|
+
className: "gcb-post-object-selected-item",
|
|
69
|
+
...dndAttributes,
|
|
70
|
+
...listeners,
|
|
71
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
72
|
+
className: "gcb-post-object-drag-handle",
|
|
73
|
+
"aria-hidden": true,
|
|
74
|
+
children: /*#__PURE__*/_jsx("svg", {
|
|
75
|
+
viewBox: "0 0 20 20",
|
|
76
|
+
width: "12",
|
|
77
|
+
children: /*#__PURE__*/_jsx("path", {
|
|
78
|
+
d: "M7 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 2zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 14zm6-8a2 2 0 1 0-.001-4.001A2 2 0 0 0 13 6zm0 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 14z"
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
}), /*#__PURE__*/_jsx(TermIcon, {}), /*#__PURE__*/_jsx("span", {
|
|
82
|
+
style: {
|
|
83
|
+
flex: 1,
|
|
84
|
+
overflow: 'hidden',
|
|
85
|
+
textOverflow: 'ellipsis',
|
|
86
|
+
whiteSpace: 'nowrap',
|
|
87
|
+
userSelect: 'none'
|
|
88
|
+
},
|
|
89
|
+
children: term.name || __('(no name)', 'gcblite')
|
|
90
|
+
}), /*#__PURE__*/_jsx("button", {
|
|
91
|
+
type: "button",
|
|
92
|
+
onClick: e => {
|
|
93
|
+
e.stopPropagation();
|
|
94
|
+
onRemove(term.id);
|
|
95
|
+
},
|
|
96
|
+
onPointerDown: e => e.stopPropagation(),
|
|
97
|
+
className: "gcb-sortable-remove",
|
|
98
|
+
"aria-label": __('Remove', 'gcblite'),
|
|
99
|
+
children: /*#__PURE__*/_jsx("svg", {
|
|
100
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
101
|
+
viewBox: "0 0 24 24",
|
|
102
|
+
width: "20",
|
|
103
|
+
height: "20",
|
|
104
|
+
children: /*#__PURE__*/_jsx("path", {
|
|
105
|
+
d: "M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
})]
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Normalise whatever the value used to look like into the canonical
|
|
113
|
+
// { taxonomy, ids[] } shape. Handles:
|
|
114
|
+
// - bare ID (legacy single) → { taxonomy: schemaDefault, ids: [3] }
|
|
115
|
+
// - array of IDs (legacy multi) → { taxonomy: schemaDefault, ids: [3, 5] }
|
|
116
|
+
// - { id, name, taxonomy } (returnFormat=object, single)
|
|
117
|
+
// - array of those objects (returnFormat=object, multi)
|
|
118
|
+
// - new canonical { taxonomy, ids[] } → passes through
|
|
119
|
+
function normaliseTaxonomyValue(value, schemaDefault) {
|
|
120
|
+
if (!value) return {
|
|
121
|
+
taxonomy: schemaDefault,
|
|
122
|
+
ids: []
|
|
123
|
+
};
|
|
124
|
+
// Already canonical.
|
|
125
|
+
if (typeof value === 'object' && !Array.isArray(value) && Array.isArray(value.ids)) {
|
|
126
|
+
return {
|
|
127
|
+
taxonomy: value.taxonomy || schemaDefault,
|
|
128
|
+
ids: value.ids
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Bare scalar (legacy single).
|
|
132
|
+
if (typeof value === 'number' || typeof value === 'string') {
|
|
133
|
+
return {
|
|
134
|
+
taxonomy: schemaDefault,
|
|
135
|
+
ids: [Number(value)]
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// Single object (returnFormat=object).
|
|
139
|
+
if (typeof value === 'object' && !Array.isArray(value) && value.id != null) {
|
|
140
|
+
return {
|
|
141
|
+
taxonomy: value.taxonomy || schemaDefault,
|
|
142
|
+
ids: [Number(value.id)]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
// Array shapes.
|
|
146
|
+
if (Array.isArray(value)) {
|
|
147
|
+
const ids = value.map(entry => typeof entry === 'object' ? Number(entry.id) : Number(entry)).filter(Boolean);
|
|
148
|
+
const tx = value.find(entry => typeof entry === 'object' && entry?.taxonomy)?.taxonomy;
|
|
149
|
+
return {
|
|
150
|
+
taxonomy: tx || schemaDefault,
|
|
151
|
+
ids
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
taxonomy: schemaDefault,
|
|
156
|
+
ids: []
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const REST_BASE_OVERRIDES = {
|
|
160
|
+
category: 'categories',
|
|
161
|
+
post_tag: 'tags'
|
|
162
|
+
};
|
|
163
|
+
function resolveRestBase(taxonomy, override) {
|
|
164
|
+
if (override) return override;
|
|
165
|
+
return REST_BASE_OVERRIDES[taxonomy] || taxonomy;
|
|
166
|
+
}
|
|
167
|
+
export default function TaxonomyField({
|
|
168
|
+
control,
|
|
169
|
+
value,
|
|
170
|
+
onChange
|
|
171
|
+
}) {
|
|
172
|
+
const [allTerms, setAllTerms] = useState([]);
|
|
173
|
+
const [searchResults, setSearchResults] = useState([]);
|
|
174
|
+
const [loading, setLoading] = useState(false);
|
|
175
|
+
const [search, setSearch] = useState('');
|
|
176
|
+
const [creatingTerm, setCreatingTerm] = useState(false);
|
|
177
|
+
const [newTermName, setNewTermName] = useState('');
|
|
178
|
+
const [activeId, setActiveId] = useState(null);
|
|
179
|
+
const [availableTaxonomies, setAvailableTaxonomies] = useState([]);
|
|
180
|
+
const isMultiple = control.multiple !== false;
|
|
181
|
+
// Schema-locked vs author-picks-at-edit-time.
|
|
182
|
+
// When the schema omits `taxonomy`, the editor user picks via a
|
|
183
|
+
// dropdown. The picked value is stored alongside the IDs so the
|
|
184
|
+
// renderer can still resolve them at read-time.
|
|
185
|
+
const dynamic = !control.taxonomy;
|
|
186
|
+
const schemaDefault = control.taxonomy || 'category';
|
|
187
|
+
|
|
188
|
+
// Canonical { taxonomy, ids[] } shape.
|
|
189
|
+
const normalised = useMemo(() => normaliseTaxonomyValue(value, schemaDefault), [value, schemaDefault]);
|
|
190
|
+
const taxonomy = normalised.taxonomy || schemaDefault;
|
|
191
|
+
const selectedIds = normalised.ids;
|
|
192
|
+
const restBase = resolveRestBase(taxonomy, control.restBase);
|
|
193
|
+
const selectedTerms = useMemo(() => selectedIds.map(id => allTerms.find(t => t.id === id)).filter(Boolean), [selectedIds, allTerms]);
|
|
194
|
+
|
|
195
|
+
// Fetch the list of registered taxonomies once, only when the schema
|
|
196
|
+
// didn't lock to one. Used to populate the taxonomy dropdown.
|
|
197
|
+
useEffect(() => {
|
|
198
|
+
if (!dynamic) return;
|
|
199
|
+
let cancelled = false;
|
|
200
|
+
apiFetch({
|
|
201
|
+
path: '/wp/v2/taxonomies?context=view'
|
|
202
|
+
}).then(res => {
|
|
203
|
+
if (cancelled) return;
|
|
204
|
+
// REST returns an object keyed by taxonomy slug.
|
|
205
|
+
const list = Object.entries(res || {}).map(([slug, info]) => ({
|
|
206
|
+
slug,
|
|
207
|
+
name: info?.name || slug,
|
|
208
|
+
restBase: info?.rest_base || slug
|
|
209
|
+
}));
|
|
210
|
+
setAvailableTaxonomies(list);
|
|
211
|
+
}).catch(() => {});
|
|
212
|
+
return () => {
|
|
213
|
+
cancelled = true;
|
|
214
|
+
};
|
|
215
|
+
}, [dynamic]);
|
|
216
|
+
|
|
217
|
+
// Emit the canonical shape — always { taxonomy, ids[] }, regardless
|
|
218
|
+
// of single/multi, so the renderer never has to guess.
|
|
219
|
+
const emitChange = useCallback(ids => {
|
|
220
|
+
onChange({
|
|
221
|
+
taxonomy,
|
|
222
|
+
ids
|
|
223
|
+
});
|
|
224
|
+
}, [onChange, taxonomy]);
|
|
225
|
+
const handleTaxonomyChange = newTax => {
|
|
226
|
+
// Switching taxonomy clears the selected terms — IDs from one
|
|
227
|
+
// taxonomy don't translate to another.
|
|
228
|
+
onChange({
|
|
229
|
+
taxonomy: newTax,
|
|
230
|
+
ids: []
|
|
231
|
+
});
|
|
232
|
+
setAllTerms([]);
|
|
233
|
+
setSearchResults([]);
|
|
234
|
+
};
|
|
235
|
+
const mergeTermsIntoCache = useCallback(newTerms => {
|
|
236
|
+
setAllTerms(prev => {
|
|
237
|
+
const merged = [...prev];
|
|
238
|
+
newTerms.forEach(nt => {
|
|
239
|
+
if (!merged.find(t => t.id === nt.id)) merged.push(nt);
|
|
240
|
+
});
|
|
241
|
+
return merged;
|
|
242
|
+
});
|
|
243
|
+
}, []);
|
|
244
|
+
const loadTerms = useCallback(async (term = '') => {
|
|
245
|
+
setLoading(true);
|
|
246
|
+
try {
|
|
247
|
+
const response = await apiFetch({
|
|
248
|
+
path: `/wp/v2/${restBase}?search=${encodeURIComponent(term)}&per_page=100&_fields=id,name`
|
|
249
|
+
});
|
|
250
|
+
setSearchResults(response);
|
|
251
|
+
mergeTermsIntoCache(response);
|
|
252
|
+
} catch {
|
|
253
|
+
// ignore
|
|
254
|
+
}
|
|
255
|
+
setLoading(false);
|
|
256
|
+
}, [restBase, mergeTermsIntoCache]);
|
|
257
|
+
useEffect(() => {
|
|
258
|
+
loadTerms();
|
|
259
|
+
}, [loadTerms]);
|
|
260
|
+
const handleSelect = termId => {
|
|
261
|
+
const newIds = isMultiple ? selectedIds.includes(termId) ? selectedIds.filter(id => id !== termId) : [...selectedIds, termId] : [termId];
|
|
262
|
+
emitChange(newIds);
|
|
263
|
+
};
|
|
264
|
+
const handleRemove = termId => {
|
|
265
|
+
emitChange(selectedIds.filter(id => id !== termId));
|
|
266
|
+
};
|
|
267
|
+
const handleReorder = newOrder => {
|
|
268
|
+
emitChange(newOrder);
|
|
269
|
+
};
|
|
270
|
+
const handleClear = () => emitChange([]);
|
|
271
|
+
const handleCreateTerm = async () => {
|
|
272
|
+
if (!newTermName.trim() || !control.allowCreateTerms) return;
|
|
273
|
+
setCreatingTerm(true);
|
|
274
|
+
try {
|
|
275
|
+
const newTerm = await apiFetch({
|
|
276
|
+
path: `/wp/v2/${restBase}`,
|
|
277
|
+
method: 'POST',
|
|
278
|
+
data: {
|
|
279
|
+
name: newTermName.trim()
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
mergeTermsIntoCache([newTerm]);
|
|
283
|
+
setSearchResults(prev => [...prev, newTerm]);
|
|
284
|
+
handleSelect(newTerm.id);
|
|
285
|
+
setNewTermName('');
|
|
286
|
+
} catch {
|
|
287
|
+
// ignore
|
|
288
|
+
}
|
|
289
|
+
setCreatingTerm(false);
|
|
290
|
+
};
|
|
291
|
+
const sensors = useSensors(useSensor(PointerSensor, {
|
|
292
|
+
activationConstraint: {
|
|
293
|
+
distance: 8
|
|
294
|
+
}
|
|
295
|
+
}));
|
|
296
|
+
const handleDragStart = e => setActiveId(e.active.id);
|
|
297
|
+
const handleDragCancel = () => setActiveId(null);
|
|
298
|
+
const handleDragEnd = e => {
|
|
299
|
+
const {
|
|
300
|
+
active,
|
|
301
|
+
over
|
|
302
|
+
} = e;
|
|
303
|
+
if (over && active.id !== over.id) {
|
|
304
|
+
const oldIndex = selectedIds.indexOf(active.id);
|
|
305
|
+
const newIndex = selectedIds.indexOf(over.id);
|
|
306
|
+
handleReorder(arrayMove(selectedIds, oldIndex, newIndex));
|
|
307
|
+
}
|
|
308
|
+
setActiveId(null);
|
|
309
|
+
};
|
|
310
|
+
const activeTerm = activeId ? selectedTerms.find(t => t.id === activeId) : null;
|
|
311
|
+
const availableTerms = searchResults.filter(t => !selectedIds.includes(t.id));
|
|
312
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
313
|
+
className: "components-base-control gcb-taxonomy-control",
|
|
314
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
315
|
+
className: "components-base-control__field",
|
|
316
|
+
children: /*#__PURE__*/_jsx("label", {
|
|
317
|
+
className: "components-base-control__label",
|
|
318
|
+
children: control.label
|
|
319
|
+
})
|
|
320
|
+
}), control.helpText && /*#__PURE__*/_jsx("p", {
|
|
321
|
+
className: "components-base-control__help",
|
|
322
|
+
children: control.helpText
|
|
323
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
324
|
+
className: "gcb-post-object-stacked",
|
|
325
|
+
children: [dynamic && /*#__PURE__*/_jsxs("div", {
|
|
326
|
+
style: {
|
|
327
|
+
display: 'flex',
|
|
328
|
+
gap: 8,
|
|
329
|
+
alignItems: 'center',
|
|
330
|
+
marginBottom: 8
|
|
331
|
+
},
|
|
332
|
+
children: [/*#__PURE__*/_jsx("label", {
|
|
333
|
+
style: {
|
|
334
|
+
fontSize: 12,
|
|
335
|
+
fontWeight: 600,
|
|
336
|
+
color: '#1e1e1e',
|
|
337
|
+
minWidth: 70
|
|
338
|
+
},
|
|
339
|
+
children: __('Taxonomy', 'gcblite')
|
|
340
|
+
}), /*#__PURE__*/_jsxs("select", {
|
|
341
|
+
value: taxonomy,
|
|
342
|
+
onChange: e => handleTaxonomyChange(e.target.value),
|
|
343
|
+
style: {
|
|
344
|
+
flex: 1,
|
|
345
|
+
padding: '6px 8px',
|
|
346
|
+
border: '1px solid #8c8f94',
|
|
347
|
+
borderRadius: 4,
|
|
348
|
+
fontSize: 13,
|
|
349
|
+
background: '#fff'
|
|
350
|
+
},
|
|
351
|
+
children: [availableTaxonomies.length === 0 && /*#__PURE__*/_jsx("option", {
|
|
352
|
+
value: taxonomy,
|
|
353
|
+
children: taxonomy
|
|
354
|
+
}), availableTaxonomies.map(tx => /*#__PURE__*/_jsxs("option", {
|
|
355
|
+
value: tx.slug,
|
|
356
|
+
children: [tx.name, " (", tx.slug, ")"]
|
|
357
|
+
}, tx.slug))]
|
|
358
|
+
})]
|
|
359
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
360
|
+
style: {
|
|
361
|
+
display: 'flex',
|
|
362
|
+
gap: 8,
|
|
363
|
+
alignItems: 'center'
|
|
364
|
+
},
|
|
365
|
+
children: [/*#__PURE__*/_jsx(PopoverOrModal, {
|
|
366
|
+
modalTitle: control.label || __('Select terms', 'gcblite'),
|
|
367
|
+
dropdownProps: {
|
|
368
|
+
popoverProps: {
|
|
369
|
+
placement: 'left-start'
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
renderToggle: ({
|
|
373
|
+
isOpen,
|
|
374
|
+
onToggle
|
|
375
|
+
}) => /*#__PURE__*/_jsx(Button, {
|
|
376
|
+
onClick: onToggle,
|
|
377
|
+
"aria-expanded": isOpen,
|
|
378
|
+
className: "gcb-modal-toggle-button",
|
|
379
|
+
style: {
|
|
380
|
+
...TOGGLE_BUTTON_STYLE,
|
|
381
|
+
flex: 1
|
|
382
|
+
},
|
|
383
|
+
children: selectedTerms.length > 0 ? `${selectedTerms.length} ${selectedTerms.length === 1 ? __('term', 'gcblite') : __('terms', 'gcblite')} ${__('selected', 'gcblite')}` : __('Select Terms', 'gcblite')
|
|
384
|
+
}),
|
|
385
|
+
renderContent: ({
|
|
386
|
+
close: onClose,
|
|
387
|
+
variant
|
|
388
|
+
}) => /*#__PURE__*/_jsxs("div", {
|
|
389
|
+
style: variant === 'modal' ? {
|
|
390
|
+
width: '100%'
|
|
391
|
+
} : {
|
|
392
|
+
minWidth: 320,
|
|
393
|
+
maxWidth: 400
|
|
394
|
+
},
|
|
395
|
+
children: [/*#__PURE__*/_jsxs("div", {
|
|
396
|
+
style: {
|
|
397
|
+
padding: '0 16px 8px 16px'
|
|
398
|
+
},
|
|
399
|
+
children: [/*#__PURE__*/_jsx(TextControl, {
|
|
400
|
+
value: search,
|
|
401
|
+
onChange: val => {
|
|
402
|
+
setSearch(val);
|
|
403
|
+
loadTerms(val);
|
|
404
|
+
},
|
|
405
|
+
placeholder: __('Search…', 'gcblite'),
|
|
406
|
+
__nextHasNoMarginBottom: true
|
|
407
|
+
}), control.allowCreateTerms && /*#__PURE__*/_jsxs("div", {
|
|
408
|
+
style: {
|
|
409
|
+
marginTop: 12,
|
|
410
|
+
padding: 12,
|
|
411
|
+
background: '#f0f6fc',
|
|
412
|
+
borderRadius: 4
|
|
413
|
+
},
|
|
414
|
+
children: [/*#__PURE__*/_jsx(TextControl, {
|
|
415
|
+
label: __('Create New Term', 'gcblite'),
|
|
416
|
+
value: newTermName,
|
|
417
|
+
onChange: setNewTermName,
|
|
418
|
+
placeholder: __('Enter term name…', 'gcblite'),
|
|
419
|
+
disabled: creatingTerm,
|
|
420
|
+
__nextHasNoMarginBottom: true
|
|
421
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
422
|
+
variant: "primary",
|
|
423
|
+
size: "small",
|
|
424
|
+
onClick: handleCreateTerm,
|
|
425
|
+
disabled: !newTermName.trim() || creatingTerm,
|
|
426
|
+
style: {
|
|
427
|
+
marginTop: 8
|
|
428
|
+
},
|
|
429
|
+
children: creatingTerm ? __('Creating…', 'gcblite') : __('Create', 'gcblite')
|
|
430
|
+
})]
|
|
431
|
+
})]
|
|
432
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
433
|
+
className: "block-editor-link-control__search-results-wrapper",
|
|
434
|
+
style: {
|
|
435
|
+
maxHeight: 300,
|
|
436
|
+
overflowY: 'auto'
|
|
437
|
+
},
|
|
438
|
+
children: [loading && /*#__PURE__*/_jsx("p", {
|
|
439
|
+
style: {
|
|
440
|
+
textAlign: 'center',
|
|
441
|
+
color: '#757575',
|
|
442
|
+
padding: 16
|
|
443
|
+
},
|
|
444
|
+
children: __('Loading…', 'gcblite')
|
|
445
|
+
}), !loading && availableTerms.length === 0 && /*#__PURE__*/_jsx("p", {
|
|
446
|
+
style: {
|
|
447
|
+
textAlign: 'center',
|
|
448
|
+
color: '#757575',
|
|
449
|
+
padding: 16
|
|
450
|
+
},
|
|
451
|
+
children: __('No terms found', 'gcblite')
|
|
452
|
+
}), !loading && availableTerms.length > 0 && /*#__PURE__*/_jsx("div", {
|
|
453
|
+
className: "block-editor-link-control__search-results",
|
|
454
|
+
role: "listbox",
|
|
455
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
456
|
+
className: "components-menu-group",
|
|
457
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
458
|
+
role: "group",
|
|
459
|
+
children: availableTerms.map(term => /*#__PURE__*/_jsx("button", {
|
|
460
|
+
type: "button",
|
|
461
|
+
role: "option",
|
|
462
|
+
className: "components-button components-menu-item__button block-editor-link-control__search-item",
|
|
463
|
+
onClick: () => handleSelect(term.id),
|
|
464
|
+
style: {
|
|
465
|
+
display: 'flex',
|
|
466
|
+
alignItems: 'center',
|
|
467
|
+
width: '100%',
|
|
468
|
+
padding: '8px 16px',
|
|
469
|
+
textAlign: 'left',
|
|
470
|
+
border: 'none',
|
|
471
|
+
background: 'transparent',
|
|
472
|
+
justifyContent: 'space-between'
|
|
473
|
+
},
|
|
474
|
+
children: /*#__PURE__*/_jsxs("span", {
|
|
475
|
+
style: {
|
|
476
|
+
display: 'flex',
|
|
477
|
+
alignItems: 'center',
|
|
478
|
+
flex: 1,
|
|
479
|
+
overflow: 'hidden'
|
|
480
|
+
},
|
|
481
|
+
children: [/*#__PURE__*/_jsx(TermIcon, {}), /*#__PURE__*/_jsx("span", {
|
|
482
|
+
className: "components-menu-item__item",
|
|
483
|
+
style: {
|
|
484
|
+
fontWeight: 500,
|
|
485
|
+
overflow: 'hidden',
|
|
486
|
+
textOverflow: 'ellipsis',
|
|
487
|
+
whiteSpace: 'nowrap'
|
|
488
|
+
},
|
|
489
|
+
children: term.name
|
|
490
|
+
})]
|
|
491
|
+
})
|
|
492
|
+
}, term.id))
|
|
493
|
+
})
|
|
494
|
+
})
|
|
495
|
+
})]
|
|
496
|
+
})]
|
|
497
|
+
})
|
|
498
|
+
}), selectedTerms.length > 0 && /*#__PURE__*/_jsx(Button, {
|
|
499
|
+
onClick: handleClear,
|
|
500
|
+
variant: "secondary",
|
|
501
|
+
isSmall: true,
|
|
502
|
+
className: "components-range-control__reset",
|
|
503
|
+
children: __('Reset', 'gcblite')
|
|
504
|
+
})]
|
|
505
|
+
}), selectedTerms.length > 0 && isMultiple && /*#__PURE__*/_jsx("div", {
|
|
506
|
+
className: "gcb-post-object-selected-list",
|
|
507
|
+
style: {
|
|
508
|
+
marginTop: 8
|
|
509
|
+
},
|
|
510
|
+
children: /*#__PURE__*/_jsxs(DndContext, {
|
|
511
|
+
sensors: sensors,
|
|
512
|
+
collisionDetection: closestCenter,
|
|
513
|
+
onDragStart: handleDragStart,
|
|
514
|
+
onDragEnd: handleDragEnd,
|
|
515
|
+
onDragCancel: handleDragCancel,
|
|
516
|
+
children: [/*#__PURE__*/_jsx(SortableContext, {
|
|
517
|
+
items: selectedIds,
|
|
518
|
+
strategy: verticalListSortingStrategy,
|
|
519
|
+
children: selectedTerms.map(term => /*#__PURE__*/_jsx(SortableTermItem, {
|
|
520
|
+
term: term,
|
|
521
|
+
onRemove: handleRemove
|
|
522
|
+
}, term.id))
|
|
523
|
+
}), /*#__PURE__*/_jsx(DragOverlay, {
|
|
524
|
+
children: activeTerm ? /*#__PURE__*/_jsxs("div", {
|
|
525
|
+
className: "gcb-post-object-selected-item",
|
|
526
|
+
style: {
|
|
527
|
+
opacity: 0.8,
|
|
528
|
+
boxShadow: '0 2px 8px rgba(0,0,0,0.15)'
|
|
529
|
+
},
|
|
530
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
531
|
+
className: "gcb-post-object-drag-handle",
|
|
532
|
+
"aria-hidden": true,
|
|
533
|
+
children: /*#__PURE__*/_jsx("svg", {
|
|
534
|
+
viewBox: "0 0 20 20",
|
|
535
|
+
width: "12",
|
|
536
|
+
children: /*#__PURE__*/_jsx("path", {
|
|
537
|
+
d: "M7 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 2zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 7 14zm6-8a2 2 0 1 0-.001-4.001A2 2 0 0 0 13 6zm0 2a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 8zm0 6a2 2 0 1 0 .001 4.001A2 2 0 0 0 13 14z"
|
|
538
|
+
})
|
|
539
|
+
})
|
|
540
|
+
}), /*#__PURE__*/_jsx(TermIcon, {}), /*#__PURE__*/_jsx("span", {
|
|
541
|
+
style: {
|
|
542
|
+
flex: 1
|
|
543
|
+
},
|
|
544
|
+
children: activeTerm.name
|
|
545
|
+
})]
|
|
546
|
+
}) : null
|
|
547
|
+
})]
|
|
548
|
+
})
|
|
549
|
+
}), selectedTerms.length > 0 && !isMultiple && /*#__PURE__*/_jsx("div", {
|
|
550
|
+
className: "gcb-post-object-selected-list",
|
|
551
|
+
style: {
|
|
552
|
+
marginTop: 8
|
|
553
|
+
},
|
|
554
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
555
|
+
className: "gcb-post-object-selected-item",
|
|
556
|
+
children: [/*#__PURE__*/_jsx(TermIcon, {}), /*#__PURE__*/_jsx("span", {
|
|
557
|
+
style: {
|
|
558
|
+
flex: 1,
|
|
559
|
+
overflow: 'hidden',
|
|
560
|
+
textOverflow: 'ellipsis',
|
|
561
|
+
whiteSpace: 'nowrap'
|
|
562
|
+
},
|
|
563
|
+
children: selectedTerms[0].name
|
|
564
|
+
})]
|
|
565
|
+
})
|
|
566
|
+
})]
|
|
567
|
+
})]
|
|
568
|
+
});
|
|
569
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { TextControl } from '@wordpress/components';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
export default function TextField({
|
|
4
|
+
control,
|
|
5
|
+
value,
|
|
6
|
+
onChange
|
|
7
|
+
}) {
|
|
8
|
+
return /*#__PURE__*/_jsx(TextControl, {
|
|
9
|
+
label: control.label,
|
|
10
|
+
help: control.helpText,
|
|
11
|
+
placeholder: control.placeholder,
|
|
12
|
+
value: value ?? '',
|
|
13
|
+
onChange: onChange,
|
|
14
|
+
__nextHasNoMarginBottom: true
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TextareaControl } from '@wordpress/components';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
export default function TextareaField({
|
|
4
|
+
control,
|
|
5
|
+
value,
|
|
6
|
+
onChange
|
|
7
|
+
}) {
|
|
8
|
+
return /*#__PURE__*/_jsx(TextareaControl, {
|
|
9
|
+
label: control.label,
|
|
10
|
+
help: control.helpText,
|
|
11
|
+
placeholder: control.placeholder,
|
|
12
|
+
value: value ?? '',
|
|
13
|
+
onChange: onChange,
|
|
14
|
+
rows: 4,
|
|
15
|
+
__nextHasNoMarginBottom: true
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ToggleGroup — radio-style segmented control. Stores a single value.
|
|
3
|
+
*/
|
|
4
|
+
import { __experimentalToggleGroupControl as ToggleGroupControl, __experimentalToggleGroupControlOption as ToggleGroupControlOption } from '@wordpress/components';
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export default function ToggleGroupField({
|
|
7
|
+
control,
|
|
8
|
+
value,
|
|
9
|
+
onChange
|
|
10
|
+
}) {
|
|
11
|
+
// ToggleGroupControl needs undefined (not '') when nothing is selected,
|
|
12
|
+
// otherwise it shows every option as checked.
|
|
13
|
+
const controlValue = value || undefined;
|
|
14
|
+
return /*#__PURE__*/_jsx(ToggleGroupControl, {
|
|
15
|
+
label: control.label,
|
|
16
|
+
value: controlValue,
|
|
17
|
+
onChange: onChange,
|
|
18
|
+
help: control.helpText,
|
|
19
|
+
isBlock: control.isBlock !== false,
|
|
20
|
+
className: "gcb-toggle-group-control",
|
|
21
|
+
__nextHasNoMarginBottom: true,
|
|
22
|
+
__next40pxDefaultSize: true,
|
|
23
|
+
children: (control.options || []).map((option, idx) => /*#__PURE__*/_jsx(ToggleGroupControlOption, {
|
|
24
|
+
value: option.value,
|
|
25
|
+
label: option.label
|
|
26
|
+
}, option.value || idx))
|
|
27
|
+
});
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ToggleControl } from '@wordpress/components';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
export default function ToggleField({
|
|
4
|
+
control,
|
|
5
|
+
value,
|
|
6
|
+
onChange
|
|
7
|
+
}) {
|
|
8
|
+
return /*#__PURE__*/_jsx(ToggleControl, {
|
|
9
|
+
label: control.label,
|
|
10
|
+
help: control.helpText,
|
|
11
|
+
checked: !!value,
|
|
12
|
+
onChange: onChange,
|
|
13
|
+
__nextHasNoMarginBottom: true
|
|
14
|
+
});
|
|
15
|
+
}
|