@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.
Files changed (92) hide show
  1. package/README.md +51 -35
  2. package/dist/conditional-logic.js +83 -0
  3. package/{src → dist}/control-context.js +3 -2
  4. package/{src → dist}/controls/MediaCapabilityGate.js +12 -8
  5. package/dist/controls/MediaPicker.js +149 -0
  6. package/dist/controls/MediaTriggerBadges.js +35 -0
  7. package/{src → dist}/controls/PopoverOrModal.js +49 -43
  8. package/dist/controls/SortableItem.js +126 -0
  9. package/dist/controls/button-group.js +46 -0
  10. package/dist/controls/checkbox-group.js +65 -0
  11. package/dist/controls/checkbox.js +15 -0
  12. package/dist/controls/code.js +24 -0
  13. package/dist/controls/color.js +241 -0
  14. package/dist/controls/date.js +55 -0
  15. package/dist/controls/datetime.js +61 -0
  16. package/dist/controls/email.js +17 -0
  17. package/dist/controls/file.js +163 -0
  18. package/dist/controls/gallery.js +371 -0
  19. package/dist/controls/google-map.js +143 -0
  20. package/dist/controls/heading-level.js +93 -0
  21. package/dist/controls/icon.js +292 -0
  22. package/dist/controls/image.js +360 -0
  23. package/dist/controls/index.js +88 -0
  24. package/dist/controls/message.js +86 -0
  25. package/dist/controls/number.js +19 -0
  26. package/dist/controls/oembed.js +42 -0
  27. package/{src → dist}/controls/page-link.js +1 -2
  28. package/dist/controls/post-object.js +913 -0
  29. package/dist/controls/radio.js +19 -0
  30. package/dist/controls/range.js +108 -0
  31. package/{src → dist}/controls/relationship.js +12 -7
  32. package/dist/controls/repeater.js +277 -0
  33. package/dist/controls/richtext.js +494 -0
  34. package/dist/controls/select.js +144 -0
  35. package/dist/controls/size.js +59 -0
  36. package/dist/controls/spacing.js +141 -0
  37. package/dist/controls/taxonomy.js +569 -0
  38. package/dist/controls/text.js +16 -0
  39. package/dist/controls/textarea.js +17 -0
  40. package/dist/controls/toggle-group.js +28 -0
  41. package/dist/controls/toggle.js +15 -0
  42. package/dist/controls/url.js +235 -0
  43. package/dist/controls/user.js +383 -0
  44. package/{src → dist}/controls/wysiwyg.js +1 -1
  45. package/{src → dist}/hooks/useTokens.js +25 -21
  46. package/{src → dist}/index.js +2 -8
  47. package/dist/inspector.js +163 -0
  48. package/{src → dist}/provider.js +18 -17
  49. package/dist/utils/map-utils.js +54 -0
  50. package/dist/utils/token-helper.js +396 -0
  51. package/{src → dist}/validation-context.js +4 -4
  52. package/package.json +35 -13
  53. package/src/conditional-logic.js +0 -77
  54. package/src/controls/MediaPicker.js +0 -139
  55. package/src/controls/MediaTriggerBadges.js +0 -31
  56. package/src/controls/SortableItem.js +0 -110
  57. package/src/controls/button-group.js +0 -49
  58. package/src/controls/checkbox-group.js +0 -55
  59. package/src/controls/checkbox.js +0 -13
  60. package/src/controls/code.js +0 -21
  61. package/src/controls/color.js +0 -235
  62. package/src/controls/date.js +0 -37
  63. package/src/controls/datetime.js +0 -54
  64. package/src/controls/email.js +0 -15
  65. package/src/controls/file.js +0 -134
  66. package/src/controls/gallery.js +0 -338
  67. package/src/controls/google-map.js +0 -117
  68. package/src/controls/heading-level.js +0 -99
  69. package/src/controls/icon.js +0 -301
  70. package/src/controls/image.js +0 -334
  71. package/src/controls/index.js +0 -95
  72. package/src/controls/message.js +0 -56
  73. package/src/controls/number.js +0 -17
  74. package/src/controls/oembed.js +0 -32
  75. package/src/controls/post-object.js +0 -788
  76. package/src/controls/radio.js +0 -18
  77. package/src/controls/range.js +0 -110
  78. package/src/controls/repeater.js +0 -290
  79. package/src/controls/richtext.js +0 -505
  80. package/src/controls/select.js +0 -141
  81. package/src/controls/size.js +0 -49
  82. package/src/controls/spacing.js +0 -141
  83. package/src/controls/taxonomy.js +0 -488
  84. package/src/controls/text.js +0 -14
  85. package/src/controls/textarea.js +0 -15
  86. package/src/controls/toggle-group.js +0 -34
  87. package/src/controls/toggle.js +0 -13
  88. package/src/controls/url.js +0 -164
  89. package/src/controls/user.js +0 -343
  90. package/src/inspector.js +0 -174
  91. package/src/utils/map-utils.js +0 -51
  92. package/src/utils/token-helper.js +0 -243
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * CheckboxGroup — multi-select stored as an array of selected values.
4
+ */
5
+ export default function CheckboxGroupField({
6
+ control,
7
+ value,
8
+ onChange
9
+ }) {
10
+ const current = Array.isArray(value) ? value : [];
11
+ return /*#__PURE__*/_jsxs("div", {
12
+ className: "components-base-control gcb-checkbox-group-control",
13
+ children: [/*#__PURE__*/_jsxs("div", {
14
+ className: "components-base-control__field",
15
+ children: [/*#__PURE__*/_jsx("label", {
16
+ className: "components-base-control__label",
17
+ children: control.label
18
+ }), /*#__PURE__*/_jsx("div", {
19
+ style: {
20
+ display: 'flex',
21
+ alignItems: 'stretch',
22
+ flexDirection: 'column',
23
+ gap: 6,
24
+ justifyContent: 'center'
25
+ },
26
+ children: (control.options || []).map((option, index) => {
27
+ const isChecked = current.includes(option.value);
28
+ const id = `gcb-checkbox-${control.id || control.attributeKey}-${option.value}-${index}`;
29
+ return /*#__PURE__*/_jsx("div", {
30
+ className: "gcb-checkbox-item",
31
+ children: /*#__PURE__*/_jsxs("label", {
32
+ htmlFor: id,
33
+ style: {
34
+ display: 'flex',
35
+ alignItems: 'center',
36
+ gap: 8,
37
+ cursor: 'pointer',
38
+ fontSize: 13
39
+ },
40
+ children: [/*#__PURE__*/_jsx("input", {
41
+ type: "checkbox",
42
+ id: id,
43
+ checked: isChecked,
44
+ onChange: e => {
45
+ const next = e.target.checked ? [...current, option.value] : current.filter(v => v !== option.value);
46
+ onChange(next);
47
+ },
48
+ style: {
49
+ width: 16,
50
+ height: 16,
51
+ cursor: 'pointer'
52
+ }
53
+ }), /*#__PURE__*/_jsx("span", {
54
+ children: option.label
55
+ })]
56
+ })
57
+ }, `${control.id || control.attributeKey}-${option.value}`);
58
+ })
59
+ })]
60
+ }), control.helpText && /*#__PURE__*/_jsx("p", {
61
+ className: "components-base-control__help",
62
+ children: control.helpText
63
+ })]
64
+ });
65
+ }
@@ -0,0 +1,15 @@
1
+ import { CheckboxControl } from '@wordpress/components';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ export default function CheckboxField({
4
+ control,
5
+ value,
6
+ onChange
7
+ }) {
8
+ return /*#__PURE__*/_jsx(CheckboxControl, {
9
+ label: control.label,
10
+ help: control.helpText,
11
+ checked: !!value,
12
+ onChange: onChange,
13
+ __nextHasNoMarginBottom: true
14
+ });
15
+ }
@@ -0,0 +1,24 @@
1
+ import { TextareaControl } from '@wordpress/components';
2
+
3
+ /**
4
+ * Minimal code field — a monospace textarea. The original plugin used CodeMirror
5
+ * here; we can swap in once basic shape is proven. For now, monospace + tab-friendly
6
+ * is good enough for snippets.
7
+ */
8
+ import { jsx as _jsx } from "react/jsx-runtime";
9
+ export default function CodeField({
10
+ control,
11
+ value,
12
+ onChange
13
+ }) {
14
+ return /*#__PURE__*/_jsx(TextareaControl, {
15
+ label: control.label,
16
+ help: control.helpText,
17
+ placeholder: control.placeholder,
18
+ value: value ?? '',
19
+ onChange: onChange,
20
+ rows: control.rows ?? 8,
21
+ className: "gcblite-code-field",
22
+ __nextHasNoMarginBottom: true
23
+ });
24
+ }
@@ -0,0 +1,241 @@
1
+ /**
2
+ * ColorField — ported verbatim from the original GCB.
3
+ * Tabbed color/gradient picker that uses theme.json palettes via useSetting.
4
+ *
5
+ * Control config can opt out of gradients with `showGradients: false`.
6
+ * For dual-attribute mode (separate color + gradient attrs), set
7
+ * `gradientAttributeKey` on the control config.
8
+ */
9
+
10
+ import { __ } from '@wordpress/i18n';
11
+ import { BaseControl, Button, ColorPalette, GradientPicker, TabPanel, __experimentalHStack as HStack } from '@wordpress/components';
12
+ import { useSetting } from '@wordpress/block-editor';
13
+ import PopoverOrModal from './PopoverOrModal';
14
+
15
+ /**
16
+ * The popover contents — palette + (optional) gradient tab.
17
+ */
18
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
19
+ function ColorPanel({
20
+ colorValue,
21
+ gradientValue,
22
+ onColorChange,
23
+ onGradientChange,
24
+ colors,
25
+ gradients,
26
+ enableAlpha,
27
+ disableCustomColors,
28
+ disableCustomGradients,
29
+ showGradients
30
+ }) {
31
+ const palette = /*#__PURE__*/_jsxs(_Fragment, {
32
+ children: [/*#__PURE__*/_jsx(ColorPalette, {
33
+ colors: colors,
34
+ value: colorValue,
35
+ onChange: onColorChange,
36
+ clearable: true,
37
+ disableCustomColors: disableCustomColors,
38
+ enableAlpha: enableAlpha
39
+ }), colorValue && /*#__PURE__*/_jsx(Button, {
40
+ variant: "secondary",
41
+ onClick: () => onColorChange(''),
42
+ style: {
43
+ marginTop: 10
44
+ },
45
+ children: __('Reset Color', 'gcblite')
46
+ })]
47
+ });
48
+ if (!showGradients) {
49
+ return /*#__PURE__*/_jsx("div", {
50
+ style: {
51
+ minWidth: 260,
52
+ padding: 12
53
+ },
54
+ children: palette
55
+ });
56
+ }
57
+ return /*#__PURE__*/_jsx("div", {
58
+ style: {
59
+ minWidth: 260,
60
+ padding: 12
61
+ },
62
+ children: /*#__PURE__*/_jsx(TabPanel, {
63
+ className: "gcb-color-field-tabs",
64
+ activeClass: "is-active",
65
+ tabs: [{
66
+ name: 'color',
67
+ title: __('Color', 'gcblite'),
68
+ className: 'tab-color'
69
+ }, {
70
+ name: 'gradient',
71
+ title: __('Gradient', 'gcblite'),
72
+ className: 'tab-gradient'
73
+ }],
74
+ children: tab => /*#__PURE__*/_jsxs(_Fragment, {
75
+ children: [tab.name === 'color' && palette, tab.name === 'gradient' && /*#__PURE__*/_jsxs(_Fragment, {
76
+ children: [/*#__PURE__*/_jsx(GradientPicker, {
77
+ value: gradientValue || undefined,
78
+ onChange: next => onGradientChange(next || ''),
79
+ gradients: gradients || [],
80
+ clearable: true,
81
+ disableCustomGradients: disableCustomGradients,
82
+ __experimentalIsRenderedInSidebar: true
83
+ }), gradientValue && /*#__PURE__*/_jsx(Button, {
84
+ variant: "secondary",
85
+ onClick: () => onGradientChange(''),
86
+ style: {
87
+ marginTop: 10
88
+ },
89
+ children: __('Reset Gradient', 'gcblite')
90
+ })]
91
+ })]
92
+ })
93
+ })
94
+ });
95
+ }
96
+
97
+ /**
98
+ * The trigger swatch — large white tile with a colour swatch on the left,
99
+ * the resolved value (or label) on the right. Same "popout" pattern as the
100
+ * image / post-object controls.
101
+ */
102
+ function ColorTrigger({
103
+ label,
104
+ colorValue,
105
+ gradientValue,
106
+ onToggle,
107
+ isOpen
108
+ }) {
109
+ const hasValue = !!(colorValue || gradientValue);
110
+ const swatchBackground = gradientValue || colorValue || 'transparent';
111
+ const isCheckered = !hasValue;
112
+ return /*#__PURE__*/_jsx(Button, {
113
+ onClick: onToggle,
114
+ "aria-expanded": isOpen,
115
+ "aria-label": label,
116
+ className: "gcb-modal-toggle-button gcb-color-trigger",
117
+ children: /*#__PURE__*/_jsxs(HStack, {
118
+ spacing: 3,
119
+ children: [/*#__PURE__*/_jsx("span", {
120
+ "aria-hidden": true,
121
+ className: isCheckered ? 'gcb-color-trigger__swatch is-empty' : 'gcb-color-trigger__swatch',
122
+ style: {
123
+ width: 24,
124
+ height: 24,
125
+ borderRadius: '100%',
126
+ background: swatchBackground,
127
+ flexShrink: 0,
128
+ border: '1px solid #ddd',
129
+ display: 'inline-block'
130
+ }
131
+ }), /*#__PURE__*/_jsx("span", {
132
+ style: {
133
+ flex: 1,
134
+ textAlign: 'left',
135
+ fontSize: 13,
136
+ color: '#1e1e1e',
137
+ overflow: 'hidden',
138
+ textOverflow: 'ellipsis',
139
+ whiteSpace: 'nowrap'
140
+ },
141
+ children: hasValue ? gradientValue ? __('Gradient', 'gcblite') : colorValue : __('Select a color', 'gcblite')
142
+ })]
143
+ })
144
+ });
145
+ }
146
+ function ColorFieldImpl({
147
+ label = __('Color', 'gcblite'),
148
+ colorValue,
149
+ gradientValue,
150
+ onColorChange,
151
+ onGradientChange,
152
+ colors,
153
+ gradients,
154
+ enableAlpha = true,
155
+ disableCustomColors = false,
156
+ disableCustomGradients = false,
157
+ showGradients = true,
158
+ className = '',
159
+ help
160
+ }) {
161
+ const themeColors = useSetting('color.palette');
162
+ const themeGradients = useSetting('color.gradients');
163
+
164
+ // Always end up with arrays — `useSetting('color.gradients')` returns
165
+ // undefined on themes that don't declare any gradients, and feeding that
166
+ // to <GradientPicker> crashes on `.orientation`.
167
+ const finalColors = colors && colors.length ? colors : themeColors || [];
168
+ const finalGradients = gradients && gradients.length ? gradients : themeGradients || [];
169
+ return /*#__PURE__*/_jsx(BaseControl, {
170
+ label: label,
171
+ help: help,
172
+ className: `gcb-color-control components-base-control ${className}`.trim(),
173
+ __nextHasNoMarginBottom: true,
174
+ children: /*#__PURE__*/_jsx(PopoverOrModal, {
175
+ modalTitle: label,
176
+ dropdownProps: {
177
+ popoverProps: {
178
+ placement: 'left-start'
179
+ }
180
+ },
181
+ renderToggle: ({
182
+ isOpen,
183
+ onToggle
184
+ }) => /*#__PURE__*/_jsx(ColorTrigger, {
185
+ label: label,
186
+ colorValue: colorValue,
187
+ gradientValue: gradientValue,
188
+ onToggle: onToggle,
189
+ isOpen: isOpen
190
+ }),
191
+ renderContent: () => /*#__PURE__*/_jsx(ColorPanel, {
192
+ colorValue: colorValue,
193
+ gradientValue: gradientValue,
194
+ onColorChange: onColorChange,
195
+ onGradientChange: onGradientChange,
196
+ colors: finalColors,
197
+ gradients: finalGradients,
198
+ enableAlpha: enableAlpha,
199
+ disableCustomColors: disableCustomColors,
200
+ disableCustomGradients: disableCustomGradients,
201
+ showGradients: showGradients
202
+ })
203
+ })
204
+ });
205
+ }
206
+
207
+ /**
208
+ * Adapter for the registry contract.
209
+ *
210
+ * The control stores a single string value — either a colour (e.g. `#ff0000`,
211
+ * `var(--wp--preset--color--primary)`) or a gradient (e.g. `linear-gradient(...)`).
212
+ * When the user picks one, the other is cleared. This matches the WP attribute
213
+ * type `string` that the loader generates for `color` controls.
214
+ *
215
+ * For separate color + gradient attributes on the same block, declare two
216
+ * controls (one with `showGradients: false`, one purely gradient — coming in v0.2).
217
+ */
218
+ export default function ColorField({
219
+ control,
220
+ value,
221
+ onChange
222
+ }) {
223
+ const stringValue = typeof value === 'string' ? value : '';
224
+ const isGradient = stringValue.includes('gradient(');
225
+ const colorValue = isGradient ? '' : stringValue;
226
+ const gradientValue = isGradient ? stringValue : '';
227
+ const handleColor = next => onChange(next || '');
228
+ const handleGradient = next => onChange(next || '');
229
+ return /*#__PURE__*/_jsx(ColorFieldImpl, {
230
+ label: control.label,
231
+ help: control.helpText,
232
+ colorValue: colorValue,
233
+ gradientValue: gradientValue,
234
+ onColorChange: handleColor,
235
+ onGradientChange: handleGradient,
236
+ showGradients: control.showGradients !== false,
237
+ enableAlpha: control.enableAlpha !== false,
238
+ disableCustomColors: control.disableCustomColors === true,
239
+ disableCustomGradients: control.disableCustomGradients === true
240
+ });
241
+ }
@@ -0,0 +1,55 @@
1
+ import { BaseControl, Button, DatePicker } from '@wordpress/components';
2
+ import { __ } from '@wordpress/i18n';
3
+ import PopoverOrModal from './PopoverOrModal';
4
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
5
+ export default function DateField({
6
+ control,
7
+ value,
8
+ onChange
9
+ }) {
10
+ return /*#__PURE__*/_jsx(BaseControl, {
11
+ label: control.label,
12
+ help: control.helpText,
13
+ __nextHasNoMarginBottom: true,
14
+ children: /*#__PURE__*/_jsx(PopoverOrModal, {
15
+ modalTitle: control.label || __('Pick a date', 'gcblite'),
16
+ dropdownProps: {
17
+ popoverProps: {
18
+ placement: 'bottom-start'
19
+ }
20
+ },
21
+ renderToggle: ({
22
+ onToggle
23
+ }) => /*#__PURE__*/_jsxs(_Fragment, {
24
+ children: [/*#__PURE__*/_jsx(Button, {
25
+ variant: "secondary",
26
+ onClick: onToggle,
27
+ children: value ? new Date(value).toLocaleDateString() : __('Pick a date', 'gcblite')
28
+ }), value && /*#__PURE__*/_jsx(Button, {
29
+ variant: "tertiary",
30
+ size: "small",
31
+ isDestructive: true,
32
+ onClick: () => onChange(''),
33
+ style: {
34
+ marginLeft: 8
35
+ },
36
+ children: __('Clear', 'gcblite')
37
+ })]
38
+ }),
39
+ renderContent: ({
40
+ close
41
+ }) => /*#__PURE__*/_jsx("div", {
42
+ style: {
43
+ padding: 8
44
+ },
45
+ children: /*#__PURE__*/_jsx(DatePicker, {
46
+ currentDate: value || undefined,
47
+ onChange: next => {
48
+ onChange(next || '');
49
+ close();
50
+ }
51
+ })
52
+ })
53
+ })
54
+ });
55
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * DateTime — like Date, but with a time picker too. Stores an ISO 8601
3
+ * timestamp string (e.g. "2026-05-25T14:30:00").
4
+ *
5
+ * Uses WP's DateTimePicker rather than DatePicker so the panel shows hours
6
+ * and minutes alongside the calendar. Renders inside PopoverOrModal so it
7
+ * behaves correctly in both sidebar (popover) and metabox (modal) contexts.
8
+ */
9
+
10
+ import { BaseControl, Button, DateTimePicker } from '@wordpress/components';
11
+ import { __ } from '@wordpress/i18n';
12
+ import PopoverOrModal from './PopoverOrModal';
13
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
14
+ export default function DatetimeField({
15
+ control,
16
+ value,
17
+ onChange
18
+ }) {
19
+ const displayLabel = value ? new Date(value).toLocaleString() : __('Pick a date and time', 'gcblite');
20
+ return /*#__PURE__*/_jsx(BaseControl, {
21
+ label: control.label,
22
+ help: control.helpText,
23
+ __nextHasNoMarginBottom: true,
24
+ children: /*#__PURE__*/_jsx(PopoverOrModal, {
25
+ modalTitle: control.label || __('Pick a date and time', 'gcblite'),
26
+ dropdownProps: {
27
+ popoverProps: {
28
+ placement: 'bottom-start'
29
+ }
30
+ },
31
+ renderToggle: ({
32
+ onToggle
33
+ }) => /*#__PURE__*/_jsxs(_Fragment, {
34
+ children: [/*#__PURE__*/_jsx(Button, {
35
+ variant: "secondary",
36
+ onClick: onToggle,
37
+ children: displayLabel
38
+ }), value && /*#__PURE__*/_jsx(Button, {
39
+ variant: "tertiary",
40
+ size: "small",
41
+ isDestructive: true,
42
+ onClick: () => onChange(''),
43
+ style: {
44
+ marginLeft: 8
45
+ },
46
+ children: __('Clear', 'gcblite')
47
+ })]
48
+ }),
49
+ renderContent: () => /*#__PURE__*/_jsx("div", {
50
+ style: {
51
+ padding: 8
52
+ },
53
+ children: /*#__PURE__*/_jsx(DateTimePicker, {
54
+ currentDate: value || undefined,
55
+ onChange: next => onChange(next || ''),
56
+ is12Hour: true
57
+ })
58
+ })
59
+ })
60
+ });
61
+ }
@@ -0,0 +1,17 @@
1
+ import { TextControl } from '@wordpress/components';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ export default function EmailField({
4
+ control,
5
+ value,
6
+ onChange
7
+ }) {
8
+ return /*#__PURE__*/_jsx(TextControl, {
9
+ label: control.label,
10
+ help: control.helpText,
11
+ placeholder: control.placeholder ?? 'name@example.com',
12
+ type: "email",
13
+ value: value ?? '',
14
+ onChange: onChange,
15
+ __nextHasNoMarginBottom: true
16
+ });
17
+ }
@@ -0,0 +1,163 @@
1
+ /**
2
+ * FileField — non-image attachment picker. Stores `{ id, url, filename, title }`.
3
+ *
4
+ * The trigger button mirrors the image control's "popout" tile (file icon +
5
+ * filename + chevron) so the Inspector feels consistent.
6
+ */
7
+
8
+ import { __ } from '@wordpress/i18n';
9
+ import { Button, __experimentalHStack as HStack, __experimentalTruncate as Truncate } from '@wordpress/components';
10
+ import MediaPicker from './MediaPicker';
11
+ import PopoverOrModal from './PopoverOrModal';
12
+ import MediaCapabilityGate from './MediaCapabilityGate';
13
+ import MediaTriggerBadges from './MediaTriggerBadges';
14
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
15
+ const TOGGLE_BUTTON_STYLE = {
16
+ width: '100%',
17
+ height: 'auto',
18
+ padding: '12px',
19
+ justifyContent: 'flex-start',
20
+ border: '1px solid #ddd',
21
+ borderRadius: '2px',
22
+ backgroundColor: '#fff'
23
+ };
24
+ function FileIcon() {
25
+ return /*#__PURE__*/_jsx("svg", {
26
+ xmlns: "http://www.w3.org/2000/svg",
27
+ viewBox: "0 0 24 24",
28
+ width: "20",
29
+ height: "20",
30
+ style: {
31
+ flexShrink: 0,
32
+ fill: '#1e1e1e'
33
+ },
34
+ "aria-hidden": true,
35
+ children: /*#__PURE__*/_jsx("path", {
36
+ d: "M14 9V3.5L19.5 9H14zM6 2h9l5 5v13a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2zm0 2v16h12V11h-5V4H6z"
37
+ })
38
+ });
39
+ }
40
+ export default function FileField({
41
+ control,
42
+ value,
43
+ onChange
44
+ }) {
45
+ const fileValue = typeof value === 'object' && value !== null ? value : {
46
+ id: null,
47
+ url: value || '',
48
+ filename: '',
49
+ title: ''
50
+ };
51
+ const hasFile = !!(fileValue.id || fileValue.url);
52
+ const displayTitle = fileValue.title || fileValue.filename || __('(no title)', 'gcblite');
53
+ return /*#__PURE__*/_jsxs("div", {
54
+ className: "components-base-control gcb-file-control",
55
+ children: [/*#__PURE__*/_jsx("div", {
56
+ className: "components-base-control__field",
57
+ children: /*#__PURE__*/_jsx("label", {
58
+ className: "components-base-control__label",
59
+ children: control.label
60
+ })
61
+ }), control.helpText && /*#__PURE__*/_jsx("p", {
62
+ className: "components-base-control__help",
63
+ children: control.helpText
64
+ }), /*#__PURE__*/_jsx(MediaCapabilityGate, {
65
+ children: /*#__PURE__*/_jsx(MediaPicker, {
66
+ onSelect: media => onChange({
67
+ id: media.id,
68
+ url: media.url,
69
+ filename: media.filename,
70
+ title: media.title
71
+ }),
72
+ allowedTypes: control.allowedTypes || ['application', 'text', 'image', 'video', 'audio'],
73
+ value: fileValue.id,
74
+ render: ({
75
+ open
76
+ }) => /*#__PURE__*/_jsxs("div", {
77
+ children: [!hasFile && /*#__PURE__*/_jsx(Button, {
78
+ onClick: open,
79
+ variant: "secondary",
80
+ style: {
81
+ marginBottom: 8
82
+ },
83
+ children: __('Select File', 'gcblite')
84
+ }), hasFile && /*#__PURE__*/_jsx(PopoverOrModal, {
85
+ modalTitle: control.label || __('File', 'gcblite'),
86
+ dropdownProps: {
87
+ popoverProps: {
88
+ placement: 'left-start'
89
+ }
90
+ },
91
+ renderToggle: ({
92
+ isOpen,
93
+ onToggle
94
+ }) => /*#__PURE__*/_jsx(MediaTriggerBadges, {
95
+ onClear: () => onChange({
96
+ id: null,
97
+ url: '',
98
+ filename: '',
99
+ title: ''
100
+ }),
101
+ children: /*#__PURE__*/_jsx(Button, {
102
+ onClick: onToggle,
103
+ "aria-expanded": isOpen,
104
+ className: "gcb-modal-toggle-button gcb-file-control-toggle",
105
+ style: TOGGLE_BUTTON_STYLE,
106
+ children: /*#__PURE__*/_jsxs(HStack, {
107
+ spacing: 3,
108
+ children: [/*#__PURE__*/_jsx(FileIcon, {}), /*#__PURE__*/_jsx(Truncate, {
109
+ numberOfLines: 1,
110
+ children: displayTitle
111
+ })]
112
+ })
113
+ })
114
+ }),
115
+ renderContent: ({
116
+ close
117
+ }) => /*#__PURE__*/_jsxs("div", {
118
+ style: {
119
+ padding: 16,
120
+ minWidth: 280
121
+ },
122
+ children: [/*#__PURE__*/_jsx(Button, {
123
+ onClick: () => {
124
+ close();
125
+ open();
126
+ },
127
+ variant: "secondary",
128
+ style: {
129
+ width: '100%',
130
+ marginBottom: 12
131
+ },
132
+ children: __('Replace File', 'gcblite')
133
+ }), /*#__PURE__*/_jsx(Button, {
134
+ onClick: () => {
135
+ onChange({
136
+ id: null,
137
+ url: '',
138
+ filename: '',
139
+ title: ''
140
+ });
141
+ close();
142
+ },
143
+ variant: "tertiary",
144
+ isDestructive: true,
145
+ style: {
146
+ width: '100%'
147
+ },
148
+ children: __('Remove File', 'gcblite')
149
+ })]
150
+ })
151
+ }), !hasFile && /*#__PURE__*/_jsx("p", {
152
+ style: {
153
+ fontSize: 13,
154
+ color: '#757575',
155
+ margin: 0
156
+ },
157
+ children: __('No file selected', 'gcblite')
158
+ })]
159
+ })
160
+ })
161
+ })]
162
+ });
163
+ }