@wordpress-gcb/fields 0.2.1 → 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.
Files changed (91) hide show
  1. package/dist/conditional-logic.js +83 -0
  2. package/{src → dist}/control-context.js +3 -2
  3. package/{src → dist}/controls/MediaCapabilityGate.js +12 -8
  4. package/dist/controls/MediaPicker.js +149 -0
  5. package/dist/controls/MediaTriggerBadges.js +35 -0
  6. package/{src → dist}/controls/PopoverOrModal.js +49 -43
  7. package/dist/controls/SortableItem.js +126 -0
  8. package/dist/controls/button-group.js +46 -0
  9. package/dist/controls/checkbox-group.js +65 -0
  10. package/dist/controls/checkbox.js +15 -0
  11. package/dist/controls/code.js +24 -0
  12. package/dist/controls/color.js +241 -0
  13. package/dist/controls/date.js +55 -0
  14. package/dist/controls/datetime.js +61 -0
  15. package/dist/controls/email.js +17 -0
  16. package/dist/controls/file.js +163 -0
  17. package/dist/controls/gallery.js +371 -0
  18. package/dist/controls/google-map.js +143 -0
  19. package/dist/controls/heading-level.js +93 -0
  20. package/dist/controls/icon.js +292 -0
  21. package/dist/controls/image.js +360 -0
  22. package/dist/controls/index.js +88 -0
  23. package/dist/controls/message.js +86 -0
  24. package/dist/controls/number.js +19 -0
  25. package/dist/controls/oembed.js +42 -0
  26. package/{src → dist}/controls/page-link.js +1 -2
  27. package/dist/controls/post-object.js +913 -0
  28. package/dist/controls/radio.js +19 -0
  29. package/dist/controls/range.js +108 -0
  30. package/{src → dist}/controls/relationship.js +12 -7
  31. package/dist/controls/repeater.js +277 -0
  32. package/dist/controls/richtext.js +494 -0
  33. package/dist/controls/select.js +144 -0
  34. package/dist/controls/size.js +59 -0
  35. package/dist/controls/spacing.js +141 -0
  36. package/dist/controls/taxonomy.js +569 -0
  37. package/dist/controls/text.js +16 -0
  38. package/dist/controls/textarea.js +17 -0
  39. package/dist/controls/toggle-group.js +28 -0
  40. package/dist/controls/toggle.js +15 -0
  41. package/dist/controls/url.js +235 -0
  42. package/dist/controls/user.js +383 -0
  43. package/{src → dist}/controls/wysiwyg.js +1 -1
  44. package/{src → dist}/hooks/useTokens.js +25 -21
  45. package/{src → dist}/index.js +2 -8
  46. package/dist/inspector.js +163 -0
  47. package/{src → dist}/provider.js +18 -17
  48. package/dist/utils/map-utils.js +54 -0
  49. package/dist/utils/token-helper.js +396 -0
  50. package/{src → dist}/validation-context.js +4 -4
  51. package/package.json +20 -13
  52. package/src/conditional-logic.js +0 -77
  53. package/src/controls/MediaPicker.js +0 -139
  54. package/src/controls/MediaTriggerBadges.js +0 -31
  55. package/src/controls/SortableItem.js +0 -110
  56. package/src/controls/button-group.js +0 -49
  57. package/src/controls/checkbox-group.js +0 -55
  58. package/src/controls/checkbox.js +0 -13
  59. package/src/controls/code.js +0 -21
  60. package/src/controls/color.js +0 -235
  61. package/src/controls/date.js +0 -37
  62. package/src/controls/datetime.js +0 -54
  63. package/src/controls/email.js +0 -15
  64. package/src/controls/file.js +0 -134
  65. package/src/controls/gallery.js +0 -338
  66. package/src/controls/google-map.js +0 -117
  67. package/src/controls/heading-level.js +0 -99
  68. package/src/controls/icon.js +0 -301
  69. package/src/controls/image.js +0 -334
  70. package/src/controls/index.js +0 -95
  71. package/src/controls/message.js +0 -56
  72. package/src/controls/number.js +0 -17
  73. package/src/controls/oembed.js +0 -32
  74. package/src/controls/post-object.js +0 -788
  75. package/src/controls/radio.js +0 -18
  76. package/src/controls/range.js +0 -110
  77. package/src/controls/repeater.js +0 -290
  78. package/src/controls/richtext.js +0 -505
  79. package/src/controls/select.js +0 -141
  80. package/src/controls/size.js +0 -49
  81. package/src/controls/spacing.js +0 -141
  82. package/src/controls/taxonomy.js +0 -488
  83. package/src/controls/text.js +0 -14
  84. package/src/controls/textarea.js +0 -15
  85. package/src/controls/toggle-group.js +0 -34
  86. package/src/controls/toggle.js +0 -13
  87. package/src/controls/url.js +0 -164
  88. package/src/controls/user.js +0 -343
  89. package/src/inspector.js +0 -174
  90. package/src/utils/map-utils.js +0 -51
  91. package/src/utils/token-helper.js +0 -243
@@ -0,0 +1,235 @@
1
+ import { BaseControl, Button, Popover, Modal, TextControl, CheckboxControl, __experimentalHStack as HStack, __experimentalSpacer as Spacer } from '@wordpress/components';
2
+ import { useState, useContext } from '@wordpress/element';
3
+ import { __ } from '@wordpress/i18n';
4
+ import { __experimentalLinkControl as LinkControl } from '@wordpress/block-editor';
5
+ import { ControlContext } from '../control-context';
6
+
7
+ /**
8
+ * URL control — stores `{ url, text, opensInNewTab }`.
9
+ *
10
+ * Two renderings of the same stored shape:
11
+ * - **Sidebar context** (block Inspector): compact summary + Edit popover
12
+ * that mounts the rich @wordpress/block-editor LinkControl.
13
+ * - **Meta-box context** (post-fields panel): three stacked inputs
14
+ * (URL, link text, open-in-new-tab checkbox). The popover-based UI
15
+ * feels out of place in a wide meta-box and the LinkControl's
16
+ * post/page suggestions push the popover off-screen.
17
+ *
18
+ * Both render the same data; the chooser is the `variant` field on the
19
+ * ControlContext provider supplied by the host (block edit.js vs the
20
+ * post-fields meta-box App). Default is sidebar.
21
+ *
22
+ * When wiring a React component on the frontend:
23
+ * const { url, text, opensInNewTab } = link || {};
24
+ * if (!url) return null;
25
+ * return <a
26
+ * href={url}
27
+ * target={opensInNewTab ? '_blank' : undefined}
28
+ * rel={opensInNewTab ? 'noopener noreferrer' : undefined}
29
+ * >{text || url}</a>;
30
+ */
31
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
32
+ export default function UrlField({
33
+ control,
34
+ value,
35
+ onChange
36
+ }) {
37
+ const ctx = useContext(ControlContext);
38
+ const link = value && typeof value === 'object' ? value : {
39
+ url: '',
40
+ text: '',
41
+ opensInNewTab: false
42
+ };
43
+ if (ctx.variant === 'metabox') {
44
+ return /*#__PURE__*/_jsx(MetaboxUrl, {
45
+ control: control,
46
+ link: link,
47
+ onChange: onChange
48
+ });
49
+ }
50
+ return /*#__PURE__*/_jsx(SidebarUrl, {
51
+ control: control,
52
+ link: link,
53
+ onChange: onChange
54
+ });
55
+ }
56
+ function MetaboxUrl({
57
+ control,
58
+ link,
59
+ onChange
60
+ }) {
61
+ const [editing, setEditing] = useState(false);
62
+ // Draft state so Cancel can discard pending edits without touching the
63
+ // real meta value. Seed from `link` whenever the modal opens.
64
+ const [draft, setDraft] = useState(link);
65
+ const hasUrl = !!link.url;
66
+ const openModal = () => {
67
+ setDraft(link);
68
+ setEditing(true);
69
+ };
70
+ const save = () => {
71
+ onChange({
72
+ url: draft.url || '',
73
+ text: draft.text || '',
74
+ opensInNewTab: !!draft.opensInNewTab
75
+ });
76
+ setEditing(false);
77
+ };
78
+ return /*#__PURE__*/_jsxs(BaseControl, {
79
+ label: control.label,
80
+ help: control.helpText,
81
+ __nextHasNoMarginBottom: true,
82
+ children: [/*#__PURE__*/_jsxs("div", {
83
+ style: {
84
+ display: 'flex',
85
+ gap: 8,
86
+ alignItems: 'center'
87
+ },
88
+ children: [/*#__PURE__*/_jsx("div", {
89
+ style: {
90
+ flex: 1,
91
+ fontSize: 13,
92
+ color: hasUrl ? '#1e1e1e' : '#757575',
93
+ overflow: 'hidden',
94
+ textOverflow: 'ellipsis',
95
+ whiteSpace: 'nowrap'
96
+ },
97
+ children: hasUrl ? link.text || link.url : __('No link set', 'gcblite')
98
+ }), /*#__PURE__*/_jsx(Button, {
99
+ variant: "secondary",
100
+ onClick: openModal,
101
+ children: hasUrl ? __('Edit', 'gcblite') : __('Set link', 'gcblite')
102
+ }), hasUrl && /*#__PURE__*/_jsx(Button, {
103
+ variant: "tertiary",
104
+ isDestructive: true,
105
+ onClick: () => onChange({
106
+ url: '',
107
+ text: '',
108
+ opensInNewTab: false
109
+ }),
110
+ children: __('Clear', 'gcblite')
111
+ })]
112
+ }), editing && /*#__PURE__*/_jsxs(Modal, {
113
+ title: control.label || __('Edit link', 'gcblite'),
114
+ onRequestClose: () => setEditing(false),
115
+ size: "medium",
116
+ children: [/*#__PURE__*/_jsxs("div", {
117
+ style: {
118
+ display: 'grid',
119
+ gap: 16
120
+ },
121
+ children: [/*#__PURE__*/_jsx(TextControl, {
122
+ label: __('URL', 'gcblite'),
123
+ value: draft.url || '',
124
+ onChange: url => setDraft({
125
+ ...draft,
126
+ url
127
+ }),
128
+ placeholder: "https://example.com",
129
+ type: "url",
130
+ __nextHasNoMarginBottom: true,
131
+ __next40pxDefaultSize: true
132
+ }), /*#__PURE__*/_jsx(TextControl, {
133
+ label: __('Link text', 'gcblite'),
134
+ value: draft.text || '',
135
+ onChange: text => setDraft({
136
+ ...draft,
137
+ text
138
+ }),
139
+ placeholder: draft.url || __('Optional display label', 'gcblite'),
140
+ __nextHasNoMarginBottom: true,
141
+ __next40pxDefaultSize: true
142
+ }), /*#__PURE__*/_jsx(CheckboxControl, {
143
+ label: __('Open in new tab', 'gcblite'),
144
+ checked: !!draft.opensInNewTab,
145
+ onChange: opensInNewTab => setDraft({
146
+ ...draft,
147
+ opensInNewTab
148
+ }),
149
+ __nextHasNoMarginBottom: true
150
+ })]
151
+ }), /*#__PURE__*/_jsx(Spacer, {
152
+ marginTop: 6
153
+ }), /*#__PURE__*/_jsxs(HStack, {
154
+ justify: "flex-end",
155
+ spacing: 3,
156
+ children: [/*#__PURE__*/_jsx(Button, {
157
+ variant: "tertiary",
158
+ onClick: () => setEditing(false),
159
+ children: __('Cancel', 'gcblite')
160
+ }), /*#__PURE__*/_jsx(Button, {
161
+ variant: "primary",
162
+ onClick: save,
163
+ children: __('Save link', 'gcblite')
164
+ })]
165
+ })]
166
+ })]
167
+ });
168
+ }
169
+ function SidebarUrl({
170
+ control,
171
+ link,
172
+ onChange
173
+ }) {
174
+ const [editing, setEditing] = useState(false);
175
+ const hasUrl = !!link.url;
176
+ return /*#__PURE__*/_jsxs(BaseControl, {
177
+ label: control.label,
178
+ help: control.helpText,
179
+ __nextHasNoMarginBottom: true,
180
+ children: [/*#__PURE__*/_jsxs("div", {
181
+ style: {
182
+ display: 'flex',
183
+ gap: 8,
184
+ alignItems: 'center'
185
+ },
186
+ children: [/*#__PURE__*/_jsx("div", {
187
+ style: {
188
+ flex: 1,
189
+ fontSize: 12,
190
+ color: hasUrl ? '#1e1e1e' : '#757575',
191
+ overflow: 'hidden',
192
+ textOverflow: 'ellipsis',
193
+ whiteSpace: 'nowrap'
194
+ },
195
+ children: hasUrl ? link.text || link.url : __('No link set', 'gcblite')
196
+ }), /*#__PURE__*/_jsx(Button, {
197
+ variant: "secondary",
198
+ size: "small",
199
+ onClick: () => setEditing(e => !e),
200
+ children: hasUrl ? __('Edit', 'gcblite') : __('Set link', 'gcblite')
201
+ }), hasUrl && /*#__PURE__*/_jsx(Button, {
202
+ variant: "tertiary",
203
+ size: "small",
204
+ isDestructive: true,
205
+ onClick: () => onChange({
206
+ url: '',
207
+ text: '',
208
+ opensInNewTab: false
209
+ }),
210
+ children: __('Clear', 'gcblite')
211
+ })]
212
+ }), editing && /*#__PURE__*/_jsx(Popover, {
213
+ onClose: () => setEditing(false),
214
+ placement: "bottom-start",
215
+ children: /*#__PURE__*/_jsx("div", {
216
+ style: {
217
+ width: 320,
218
+ padding: 8
219
+ },
220
+ children: /*#__PURE__*/_jsx(LinkControl, {
221
+ value: link,
222
+ onChange: next => onChange({
223
+ url: next.url || '',
224
+ text: next.title || link.text || '',
225
+ opensInNewTab: !!next.opensInNewTab
226
+ }),
227
+ settings: [{
228
+ id: 'opensInNewTab',
229
+ title: __('Open in new tab', 'gcblite')
230
+ }]
231
+ })
232
+ })
233
+ })]
234
+ });
235
+ }
@@ -0,0 +1,383 @@
1
+ /**
2
+ * UserField — ported from the original GCB.
3
+ *
4
+ * Single OR multiple user selection (control.multiple). Stored as ID(s) or
5
+ * full user object(s) (control.returnFormat). Drag-and-drop reordering for
6
+ * multi-select.
7
+ */
8
+
9
+ import { __ } from '@wordpress/i18n';
10
+ import { Button, TextControl } from '@wordpress/components';
11
+ import PopoverOrModal from './PopoverOrModal';
12
+ import { useState, useEffect, useMemo, useCallback } from '@wordpress/element';
13
+ import apiFetch from '@wordpress/api-fetch';
14
+ import { DndContext, closestCenter, PointerSensor, useSensor, useSensors, DragOverlay } from '@dnd-kit/core';
15
+ import { SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from '@dnd-kit/sortable';
16
+ import { CSS } from '@dnd-kit/utilities';
17
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
18
+ const TOGGLE_BUTTON_STYLE = {
19
+ width: '100%',
20
+ height: 'auto',
21
+ padding: '12px',
22
+ justifyContent: 'flex-start',
23
+ border: '1px solid #ddd',
24
+ borderRadius: '2px',
25
+ backgroundColor: '#fff'
26
+ };
27
+ function UserIcon() {
28
+ return /*#__PURE__*/_jsx("svg", {
29
+ xmlns: "http://www.w3.org/2000/svg",
30
+ viewBox: "0 0 24 24",
31
+ width: "20",
32
+ height: "20",
33
+ style: {
34
+ marginRight: 8,
35
+ flexShrink: 0,
36
+ opacity: 0.6
37
+ },
38
+ children: /*#__PURE__*/_jsx("path", {
39
+ d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"
40
+ })
41
+ });
42
+ }
43
+ function SortableUserItem({
44
+ user,
45
+ onRemove
46
+ }) {
47
+ const {
48
+ attributes: dndAttributes,
49
+ listeners,
50
+ setNodeRef,
51
+ transform,
52
+ transition,
53
+ isDragging
54
+ } = useSortable({
55
+ id: user.id
56
+ });
57
+ const style = {
58
+ transform: CSS.Transform.toString(transform),
59
+ transition,
60
+ opacity: isDragging ? 0.5 : 1
61
+ };
62
+ return /*#__PURE__*/_jsxs("div", {
63
+ ref: setNodeRef,
64
+ style: style,
65
+ className: "gcb-post-object-selected-item",
66
+ ...dndAttributes,
67
+ ...listeners,
68
+ children: [/*#__PURE__*/_jsx("div", {
69
+ className: "gcb-post-object-drag-handle",
70
+ "aria-hidden": true,
71
+ children: /*#__PURE__*/_jsx("svg", {
72
+ viewBox: "0 0 20 20",
73
+ width: "12",
74
+ children: /*#__PURE__*/_jsx("path", {
75
+ 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"
76
+ })
77
+ })
78
+ }), /*#__PURE__*/_jsx(UserIcon, {}), /*#__PURE__*/_jsx("span", {
79
+ style: {
80
+ flex: 1,
81
+ overflow: 'hidden',
82
+ textOverflow: 'ellipsis',
83
+ whiteSpace: 'nowrap',
84
+ userSelect: 'none'
85
+ },
86
+ children: user.name || __('(no name)', 'gcblite')
87
+ }), /*#__PURE__*/_jsx("button", {
88
+ type: "button",
89
+ onClick: e => {
90
+ e.stopPropagation();
91
+ onRemove(user.id);
92
+ },
93
+ onPointerDown: e => e.stopPropagation(),
94
+ className: "gcb-sortable-remove",
95
+ "aria-label": __('Remove', 'gcblite'),
96
+ children: /*#__PURE__*/_jsx("svg", {
97
+ xmlns: "http://www.w3.org/2000/svg",
98
+ viewBox: "0 0 24 24",
99
+ width: "20",
100
+ height: "20",
101
+ children: /*#__PURE__*/_jsx("path", {
102
+ 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"
103
+ })
104
+ })
105
+ })]
106
+ });
107
+ }
108
+ export default function UserField({
109
+ control,
110
+ value,
111
+ onChange
112
+ }) {
113
+ const [allUsers, setAllUsers] = useState([]);
114
+ const [searchResults, setSearchResults] = useState([]);
115
+ const [loading, setLoading] = useState(false);
116
+ const [search, setSearch] = useState('');
117
+ const [activeId, setActiveId] = useState(null);
118
+ const isMultiple = !!control.multiple;
119
+ const selectedIds = isMultiple ? Array.isArray(value) ? value : value ? [value] : [] : value ? [value] : [];
120
+ const selectedUsers = useMemo(() => selectedIds.map(id => allUsers.find(u => u.id === id)).filter(Boolean), [selectedIds, allUsers]);
121
+ const mergeUsersIntoCache = useCallback(newUsers => {
122
+ setAllUsers(prev => {
123
+ const merged = [...prev];
124
+ newUsers.forEach(nu => {
125
+ if (!merged.find(u => u.id === nu.id)) merged.push(nu);
126
+ });
127
+ return merged;
128
+ });
129
+ }, []);
130
+ const loadUsers = useCallback(async (term = '') => {
131
+ setLoading(true);
132
+ try {
133
+ const response = await apiFetch({
134
+ path: `/wp/v2/users?search=${encodeURIComponent(term)}&per_page=50&_fields=id,name`
135
+ });
136
+ setSearchResults(response);
137
+ mergeUsersIntoCache(response);
138
+ } catch {
139
+ // ignore
140
+ }
141
+ setLoading(false);
142
+ }, [mergeUsersIntoCache]);
143
+ useEffect(() => {
144
+ loadUsers();
145
+ }, [loadUsers]);
146
+ const handleSelect = userId => {
147
+ const newIds = isMultiple ? selectedIds.includes(userId) ? selectedIds.filter(id => id !== userId) : [...selectedIds, userId] : [userId];
148
+ if (control.returnFormat === 'object') {
149
+ const objs = newIds.map(id => allUsers.find(u => u.id === id)).filter(Boolean);
150
+ onChange(isMultiple ? objs : objs[0] || null);
151
+ } else {
152
+ onChange(isMultiple ? newIds : newIds[0] || null);
153
+ }
154
+ };
155
+ const handleRemove = userId => {
156
+ const newIds = selectedIds.filter(id => id !== userId);
157
+ if (control.returnFormat === 'object') {
158
+ const objs = newIds.map(id => allUsers.find(u => u.id === id)).filter(Boolean);
159
+ onChange(isMultiple ? objs : objs[0] || null);
160
+ } else {
161
+ onChange(isMultiple ? newIds : newIds[0] || null);
162
+ }
163
+ };
164
+ const handleReorder = newOrder => {
165
+ if (control.returnFormat === 'object') {
166
+ onChange(newOrder.map(id => allUsers.find(u => u.id === id)).filter(Boolean));
167
+ } else {
168
+ onChange(newOrder);
169
+ }
170
+ };
171
+ const handleClear = () => onChange(isMultiple ? [] : null);
172
+ const sensors = useSensors(useSensor(PointerSensor, {
173
+ activationConstraint: {
174
+ distance: 8
175
+ }
176
+ }));
177
+ const handleDragStart = e => setActiveId(e.active.id);
178
+ const handleDragCancel = () => setActiveId(null);
179
+ const handleDragEnd = e => {
180
+ const {
181
+ active,
182
+ over
183
+ } = e;
184
+ if (over && active.id !== over.id) {
185
+ const oldIndex = selectedIds.indexOf(active.id);
186
+ const newIndex = selectedIds.indexOf(over.id);
187
+ handleReorder(arrayMove(selectedIds, oldIndex, newIndex));
188
+ }
189
+ setActiveId(null);
190
+ };
191
+ const activeUser = activeId ? selectedUsers.find(u => u.id === activeId) : null;
192
+ const availableUsers = searchResults.filter(u => !selectedIds.includes(u.id));
193
+ return /*#__PURE__*/_jsxs("div", {
194
+ className: "components-base-control gcb-user-control",
195
+ children: [/*#__PURE__*/_jsx("div", {
196
+ className: "components-base-control__field",
197
+ children: /*#__PURE__*/_jsx("label", {
198
+ className: "components-base-control__label",
199
+ children: control.label
200
+ })
201
+ }), control.helpText && /*#__PURE__*/_jsx("p", {
202
+ className: "components-base-control__help",
203
+ children: control.helpText
204
+ }), /*#__PURE__*/_jsxs("div", {
205
+ className: "gcb-post-object-stacked",
206
+ children: [/*#__PURE__*/_jsxs("div", {
207
+ style: {
208
+ display: 'flex',
209
+ gap: 8,
210
+ alignItems: 'center'
211
+ },
212
+ children: [/*#__PURE__*/_jsx(PopoverOrModal, {
213
+ modalTitle: control.label || __('Select users', 'gcblite'),
214
+ dropdownProps: {
215
+ popoverProps: {
216
+ placement: 'left-start'
217
+ }
218
+ },
219
+ renderToggle: ({
220
+ isOpen,
221
+ onToggle
222
+ }) => /*#__PURE__*/_jsx(Button, {
223
+ onClick: onToggle,
224
+ "aria-expanded": isOpen,
225
+ className: "gcb-modal-toggle-button",
226
+ style: {
227
+ ...TOGGLE_BUTTON_STYLE,
228
+ flex: 1
229
+ },
230
+ children: selectedUsers.length > 0 ? `${selectedUsers.length} ${selectedUsers.length === 1 ? __('user', 'gcblite') : __('users', 'gcblite')} ${__('selected', 'gcblite')}` : __('Select Users', 'gcblite')
231
+ }),
232
+ renderContent: ({
233
+ close: onClose,
234
+ variant
235
+ }) => /*#__PURE__*/_jsxs("div", {
236
+ style: variant === 'modal' ? {
237
+ width: '100%'
238
+ } : {
239
+ minWidth: 320,
240
+ maxWidth: 400
241
+ },
242
+ children: [/*#__PURE__*/_jsx("div", {
243
+ style: {
244
+ padding: '0 16px 8px 16px'
245
+ },
246
+ children: /*#__PURE__*/_jsx(TextControl, {
247
+ value: search,
248
+ onChange: val => {
249
+ setSearch(val);
250
+ loadUsers(val);
251
+ },
252
+ placeholder: __('Search users…', 'gcblite'),
253
+ __nextHasNoMarginBottom: true
254
+ })
255
+ }), /*#__PURE__*/_jsxs("div", {
256
+ className: "block-editor-link-control__search-results-wrapper",
257
+ style: {
258
+ maxHeight: 300,
259
+ overflowY: 'auto'
260
+ },
261
+ children: [loading && /*#__PURE__*/_jsx("p", {
262
+ style: {
263
+ textAlign: 'center',
264
+ color: '#757575',
265
+ padding: 16
266
+ },
267
+ children: __('Loading…', 'gcblite')
268
+ }), !loading && availableUsers.length === 0 && /*#__PURE__*/_jsx("p", {
269
+ style: {
270
+ textAlign: 'center',
271
+ color: '#757575',
272
+ padding: 16
273
+ },
274
+ children: __('No users found', 'gcblite')
275
+ }), !loading && availableUsers.length > 0 && /*#__PURE__*/_jsx("div", {
276
+ className: "block-editor-link-control__search-results",
277
+ role: "listbox",
278
+ children: /*#__PURE__*/_jsx("div", {
279
+ className: "components-menu-group",
280
+ children: /*#__PURE__*/_jsx("div", {
281
+ role: "group",
282
+ children: availableUsers.map(user => /*#__PURE__*/_jsxs("button", {
283
+ type: "button",
284
+ role: "option",
285
+ className: "components-button components-menu-item__button block-editor-link-control__search-item",
286
+ onClick: () => handleSelect(user.id),
287
+ style: {
288
+ display: 'flex',
289
+ alignItems: 'center',
290
+ width: '100%',
291
+ padding: '8px 16px',
292
+ textAlign: 'left',
293
+ border: 'none',
294
+ background: 'transparent'
295
+ },
296
+ children: [/*#__PURE__*/_jsx(UserIcon, {}), /*#__PURE__*/_jsx("span", {
297
+ className: "components-menu-item__item",
298
+ style: {
299
+ fontWeight: 500,
300
+ overflow: 'hidden',
301
+ textOverflow: 'ellipsis',
302
+ whiteSpace: 'nowrap'
303
+ },
304
+ children: user.name
305
+ })]
306
+ }, user.id))
307
+ })
308
+ })
309
+ })]
310
+ })]
311
+ })
312
+ }), selectedUsers.length > 0 && /*#__PURE__*/_jsx(Button, {
313
+ onClick: handleClear,
314
+ variant: "secondary",
315
+ isSmall: true,
316
+ className: "components-range-control__reset",
317
+ children: __('Reset', 'gcblite')
318
+ })]
319
+ }), selectedUsers.length > 0 && isMultiple && /*#__PURE__*/_jsx("div", {
320
+ className: "gcb-post-object-selected-list",
321
+ style: {
322
+ marginTop: 8
323
+ },
324
+ children: /*#__PURE__*/_jsxs(DndContext, {
325
+ sensors: sensors,
326
+ collisionDetection: closestCenter,
327
+ onDragStart: handleDragStart,
328
+ onDragEnd: handleDragEnd,
329
+ onDragCancel: handleDragCancel,
330
+ children: [/*#__PURE__*/_jsx(SortableContext, {
331
+ items: selectedIds,
332
+ strategy: verticalListSortingStrategy,
333
+ children: selectedUsers.map(user => /*#__PURE__*/_jsx(SortableUserItem, {
334
+ user: user,
335
+ onRemove: handleRemove
336
+ }, user.id))
337
+ }), /*#__PURE__*/_jsx(DragOverlay, {
338
+ children: activeUser ? /*#__PURE__*/_jsxs("div", {
339
+ className: "gcb-post-object-selected-item",
340
+ style: {
341
+ opacity: 0.8,
342
+ boxShadow: '0 2px 8px rgba(0,0,0,0.15)'
343
+ },
344
+ children: [/*#__PURE__*/_jsx("div", {
345
+ className: "gcb-post-object-drag-handle",
346
+ "aria-hidden": true,
347
+ children: /*#__PURE__*/_jsx("svg", {
348
+ viewBox: "0 0 20 20",
349
+ width: "12",
350
+ children: /*#__PURE__*/_jsx("path", {
351
+ 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"
352
+ })
353
+ })
354
+ }), /*#__PURE__*/_jsx(UserIcon, {}), /*#__PURE__*/_jsx("span", {
355
+ style: {
356
+ flex: 1
357
+ },
358
+ children: activeUser.name
359
+ })]
360
+ }) : null
361
+ })]
362
+ })
363
+ }), selectedUsers.length > 0 && !isMultiple && /*#__PURE__*/_jsx("div", {
364
+ className: "gcb-post-object-selected-list",
365
+ style: {
366
+ marginTop: 8
367
+ },
368
+ children: /*#__PURE__*/_jsxs("div", {
369
+ className: "gcb-post-object-selected-item",
370
+ children: [/*#__PURE__*/_jsx(UserIcon, {}), /*#__PURE__*/_jsx("span", {
371
+ style: {
372
+ flex: 1,
373
+ overflow: 'hidden',
374
+ textOverflow: 'ellipsis',
375
+ whiteSpace: 'nowrap'
376
+ },
377
+ children: selectedUsers[0].name
378
+ })]
379
+ })
380
+ })]
381
+ })]
382
+ });
383
+ }
@@ -20,4 +20,4 @@
20
20
  * is kept for back-compat.
21
21
  */
22
22
 
23
- export { default } from './richtext';
23
+ export { default } from './richtext';
@@ -8,37 +8,41 @@
8
8
  import { useState, useEffect } from '@wordpress/element';
9
9
  import { getAllTokenGroups } from '../utils/token-helper';
10
10
  import { useTokensConfig } from '../provider';
11
-
12
11
  export function useTokens() {
13
- const themeTokens = useTokensConfig();
14
- const [tokens, setTokens] = useState(() => getAllTokenGroups(themeTokens));
15
-
16
- useEffect(() => {
17
- setTokens(getAllTokenGroups(themeTokens));
18
- }, [themeTokens]);
19
-
20
- return { tokens, loading: false, error: null };
12
+ const themeTokens = useTokensConfig();
13
+ const [tokens, setTokens] = useState(() => getAllTokenGroups(themeTokens));
14
+ useEffect(() => {
15
+ setTokens(getAllTokenGroups(themeTokens));
16
+ }, [themeTokens]);
17
+ return {
18
+ tokens,
19
+ loading: false,
20
+ error: null
21
+ };
21
22
  }
22
23
 
23
24
  /**
24
25
  * Resolve a `tokenGroup` value (e.g. "custom:gap") to its tokens array.
25
26
  */
26
27
  export function getTokensByGroup(allTokens, tokenGroup) {
27
- if (!allTokens || !tokenGroup) return null;
28
- const [categoryKey, subKey] = tokenGroup.split(':');
29
- const category = allTokens[categoryKey];
30
- if (!category?.children) return null;
31
- return category.children[subKey]?.tokens || null;
28
+ if (!allTokens || !tokenGroup) return null;
29
+ const [categoryKey, subKey] = tokenGroup.split(':');
30
+ const category = allTokens[categoryKey];
31
+ if (!category?.children) return null;
32
+ return category.children[subKey]?.tokens || null;
32
33
  }
33
34
 
34
35
  /**
35
36
  * Build a `key → { label, token }` map for SelectField / RangeField legacy shape.
36
37
  */
37
38
  export function generateMapFromTokens(tokens) {
38
- if (!Array.isArray(tokens)) return null;
39
- const map = {};
40
- tokens.forEach((t) => {
41
- map[t.key] = { label: t.label, token: t.slug || t.value };
42
- });
43
- return map;
44
- }
39
+ if (!Array.isArray(tokens)) return null;
40
+ const map = {};
41
+ tokens.forEach(t => {
42
+ map[t.key] = {
43
+ label: t.label,
44
+ token: t.slug || t.value
45
+ };
46
+ });
47
+ return map;
48
+ }