@siratik/wp-component-library 0.1.1 → 0.1.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/LICENSE +5 -0
- package/README.md +43 -5
- package/components/attachment-image/README.md +118 -0
- package/components/attachment-image/index.js +105 -0
- package/components/attributes-panel/README.md +92 -0
- package/components/attributes-panel/index.js +324 -0
- package/components/badge/README.md +61 -0
- package/components/badge/index.js +105 -0
- package/components/block-appender/README.md +158 -0
- package/components/block-appender/index.js +135 -0
- package/components/block-extension/index.js +214 -0
- package/components/business-hours/SpecialHoursControl.js +211 -0
- package/components/business-hours/WeeklyHoursControl.js +419 -0
- package/components/business-hours/index.js +8 -0
- package/components/button/README.md +172 -0
- package/components/button/index.js +84 -0
- package/components/captcha-placeholder/CloudflareTurnstile.js +111 -0
- package/components/captcha-placeholder/GoogleRecaptcha.js +132 -0
- package/components/captcha-placeholder/HCaptcha.js +99 -0
- package/components/captcha-placeholder/README.md +228 -0
- package/components/captcha-placeholder/index.js +39 -0
- package/components/captcha-placeholder/styles.js +33 -0
- package/components/geocoder/AddressEntryControl.js +390 -0
- package/components/geocoder/GeocoderSearchControl.js +353 -0
- package/components/geocoder/countryOptions.js +66 -0
- package/components/geocoder/geocoder.js +400 -0
- package/components/geocoder/index.js +16 -0
- package/components/icon-picker/Icon.js +53 -0
- package/components/icon-picker/IconPicker.js +70 -0
- package/components/icon-picker/IconPickerModal.js +474 -0
- package/components/icon-picker/IconPickerToolbarButton.js +60 -0
- package/components/icon-picker/InlineIconPicker.js +92 -0
- package/components/icon-picker/api.js +181 -0
- package/components/icon-picker/config-bootstrap.js +108 -0
- package/components/icon-picker/hooks.js +157 -0
- package/components/icon-picker/index.js +39 -0
- package/components/icon-picker/load-script.js +33 -0
- package/components/icon-picker/loaders.js +79 -0
- package/components/icon-picker/store.js +223 -0
- package/components/icon-picker/styles.js +232 -0
- package/components/icon-picker/utils.js +138 -0
- package/components/layout/README.md +268 -0
- package/components/link-tools-panel/README.md +49 -0
- package/components/link-tools-panel/index.js +198 -0
- package/components/link-tools-panel/styles.js +90 -0
- package/components/media/README.md +288 -0
- package/components/media/SettingsMediaUpload.js +187 -0
- package/components/media/editor-media-upload.js +65 -0
- package/components/media/image-controls.js +196 -0
- package/components/media/index.js +13 -0
- package/components/media/inspector-media-upload.js +290 -0
- package/components/media/toolbar-media-upload.js +53 -0
- package/components/media/utils/aspect-ratios.js +118 -0
- package/components/meta/MetaPanel.js +75 -0
- package/components/meta/README.md +46 -0
- package/components/meta/index.js +6 -0
- package/components/meta/meta-gated-editor.js +282 -0
- package/components/query/README.md +340 -0
- package/components/query/cardTemplatePartPanel.js +69 -0
- package/components/query/cardTemplatePartSelect.js +165 -0
- package/components/query/cardTemplatePartUtils.js +119 -0
- package/components/query/columnCountControl.js +63 -0
- package/components/query/displayTypeSelect.js +52 -0
- package/components/query/examples.js +166 -0
- package/components/query/hideCurrentPostControl.js +47 -0
- package/components/query/index.js +20 -0
- package/components/query/manualPostSelector.js +125 -0
- package/components/query/manualTermSelector.js +141 -0
- package/components/query/orderBySelect.js +95 -0
- package/components/query/postTypeSelect.js +67 -0
- package/components/query/postsPerPageControl.js +51 -0
- package/components/query/selectionModeControl.js +61 -0
- package/components/query/taxonomySelect.js +139 -0
- package/components/query/utils.js +75 -0
- package/components/repeater/README.md +159 -0
- package/components/repeater/index.js +829 -0
- package/components/segmented-bar/README.md +30 -0
- package/components/segmented-bar/index.js +68 -0
- package/components/sortable-select/README.md +153 -0
- package/components/sortable-select/custom-sortable-token.js +127 -0
- package/components/sortable-select/index.js +693 -0
- package/components/style-picker/README.md +36 -0
- package/components/style-picker/index.js +92 -0
- package/components/variable-field/README.md +299 -0
- package/components/variable-field/index.js +592 -0
- package/components/variable-field/value-to-chip-html.js +38 -0
- package/components/variable-inserter/README.md +68 -0
- package/components/variable-inserter/index.js +168 -0
- package/constants/statusColors.js +1 -1
- package/editor.js +16 -0
- package/index.js +127 -0
- package/package.json +21 -13
- package/utils/kitaris-localize.js +128 -0
- package/utils/slug-aware-color-setter.js +27 -0
- package/build/index.asset.php +0 -20
- package/build/index.js +0 -1242
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Media Components
|
|
2
|
+
|
|
3
|
+
A comprehensive set of media upload and management components for WordPress blocks, providing different UI patterns for various contexts within the block editor.
|
|
4
|
+
|
|
5
|
+
## Components
|
|
6
|
+
|
|
7
|
+
### ToolbarMediaUpload
|
|
8
|
+
Media upload button for block toolbars with customizable icons and labels.
|
|
9
|
+
|
|
10
|
+
### EditorMediaUpload
|
|
11
|
+
Flexible media upload component for the main editor canvas with image preview support.
|
|
12
|
+
|
|
13
|
+
### InspectorMediaUpload
|
|
14
|
+
Media upload control for inspector panels with integrated preview and management.
|
|
15
|
+
|
|
16
|
+
### SettingsMediaUpload
|
|
17
|
+
Advanced media upload for settings panels with focal point control and additional options.
|
|
18
|
+
|
|
19
|
+
### ImageControls
|
|
20
|
+
Comprehensive image control panel with aspect ratio, object fit, and focal point settings.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```jsx
|
|
25
|
+
import {
|
|
26
|
+
ToolbarMediaUpload,
|
|
27
|
+
EditorMediaUpload,
|
|
28
|
+
InspectorMediaUpload,
|
|
29
|
+
SettingsMediaUpload,
|
|
30
|
+
ImageControls
|
|
31
|
+
} from '@siratik/wp-component-library/components/media';
|
|
32
|
+
|
|
33
|
+
// Toolbar upload
|
|
34
|
+
<BlockControls>
|
|
35
|
+
<ToolbarMediaUpload
|
|
36
|
+
buttonTitle="Select Image"
|
|
37
|
+
onSelect={handleImageSelect}
|
|
38
|
+
allowedTypes={['image']}
|
|
39
|
+
value={imageId}
|
|
40
|
+
/>
|
|
41
|
+
</BlockControls>
|
|
42
|
+
|
|
43
|
+
// Editor canvas upload
|
|
44
|
+
<EditorMediaUpload
|
|
45
|
+
buttonTitle="Choose Background"
|
|
46
|
+
onSelect={handleImageSelect}
|
|
47
|
+
imageUrl={backgroundUrl}
|
|
48
|
+
imageAlt={backgroundAlt}
|
|
49
|
+
/>
|
|
50
|
+
|
|
51
|
+
// Inspector panel upload
|
|
52
|
+
<InspectorControls>
|
|
53
|
+
<InspectorMediaUpload
|
|
54
|
+
buttonTitle="Upload Logo"
|
|
55
|
+
onSelect={handleLogoSelect}
|
|
56
|
+
onRemove={handleLogoRemove}
|
|
57
|
+
imageId={logoId}
|
|
58
|
+
imageUrl={logoUrl}
|
|
59
|
+
/>
|
|
60
|
+
</InspectorControls>
|
|
61
|
+
|
|
62
|
+
// Advanced settings upload
|
|
63
|
+
<SettingsMediaUpload
|
|
64
|
+
label="Hero Image"
|
|
65
|
+
onSelect={handleHeroSelect}
|
|
66
|
+
onRemove={handleHeroRemove}
|
|
67
|
+
value={heroImage}
|
|
68
|
+
focalPoint={focalPoint}
|
|
69
|
+
onFocalPointChange={setFocalPoint}
|
|
70
|
+
/>
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Common Props
|
|
74
|
+
|
|
75
|
+
### Core Props (All Components)
|
|
76
|
+
| Prop | Type | Default | Description |
|
|
77
|
+
|------|------|---------|-------------|
|
|
78
|
+
| `onSelect` | `function` | Required | Media selection handler |
|
|
79
|
+
| `allowedTypes` | `array` | `['image']` | Allowed media types |
|
|
80
|
+
| `buttonTitle` | `string` | Varies | Button label text |
|
|
81
|
+
|
|
82
|
+
### ToolbarMediaUpload Props
|
|
83
|
+
| Prop | Type | Default | Description |
|
|
84
|
+
|------|------|---------|-------------|
|
|
85
|
+
| `value` | `number` | - | Selected media ID |
|
|
86
|
+
| `buttonIcon` | `element` | `image` | Toolbar button icon |
|
|
87
|
+
| `buttonLabel` | `string` | - | Accessibility label |
|
|
88
|
+
| `multiple` | `boolean` | `false` | Allow multiple selection |
|
|
89
|
+
| `gallery` | `boolean` | `false` | Gallery mode |
|
|
90
|
+
|
|
91
|
+
### EditorMediaUpload Props
|
|
92
|
+
| Prop | Type | Default | Description |
|
|
93
|
+
|------|------|---------|-------------|
|
|
94
|
+
| `imageUrl` | `string` | - | Current image URL for preview |
|
|
95
|
+
| `imageAlt` | `string` | - | Image alt text |
|
|
96
|
+
| `imageId` | `number` | - | Current image ID |
|
|
97
|
+
| `onRemove` | `function` | - | Image removal handler |
|
|
98
|
+
| `className` | `string` | - | Additional CSS classes |
|
|
99
|
+
|
|
100
|
+
### InspectorMediaUpload Props
|
|
101
|
+
| Prop | Type | Default | Description |
|
|
102
|
+
|------|------|---------|-------------|
|
|
103
|
+
| `imageId` | `number` | - | Current image ID |
|
|
104
|
+
| `imageUrl` | `string` | - | Current image URL |
|
|
105
|
+
| `onRemove` | `function` | - | Image removal handler |
|
|
106
|
+
| `label` | `string` | - | Control label |
|
|
107
|
+
| `help` | `string` | - | Help text |
|
|
108
|
+
|
|
109
|
+
### SettingsMediaUpload Props
|
|
110
|
+
| Prop | Type | Default | Description |
|
|
111
|
+
|------|------|---------|-------------|
|
|
112
|
+
| `label` | `string` | `"Image"` | Control label |
|
|
113
|
+
| `value` | `object` | - | Image data object |
|
|
114
|
+
| `onRemove` | `function` | - | Image removal handler |
|
|
115
|
+
| `focalPoint` | `object` | - | Focal point coordinates |
|
|
116
|
+
| `onFocalPointChange` | `function` | - | Focal point change handler |
|
|
117
|
+
| `help` | `string` | - | Help text |
|
|
118
|
+
|
|
119
|
+
## ImageControls Component
|
|
120
|
+
|
|
121
|
+
Advanced image settings panel with comprehensive controls:
|
|
122
|
+
|
|
123
|
+
```jsx
|
|
124
|
+
<ImageControls
|
|
125
|
+
imageId={imageId}
|
|
126
|
+
imageUrl={imageUrl}
|
|
127
|
+
onRemove={handleRemove}
|
|
128
|
+
aspectRatio={aspectRatio}
|
|
129
|
+
onAspectRatioChange={setAspectRatio}
|
|
130
|
+
objectFit={objectFit}
|
|
131
|
+
onObjectFitChange={setObjectFit}
|
|
132
|
+
focalPoint={focalPoint}
|
|
133
|
+
onFocalPointChange={setFocalPoint}
|
|
134
|
+
imagePosition={imagePosition}
|
|
135
|
+
onImagePositionChange={setImagePosition}
|
|
136
|
+
/>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### ImageControls Props
|
|
140
|
+
| Prop | Type | Description |
|
|
141
|
+
|------|------|-------------|
|
|
142
|
+
| `imageId` | `number` | Current image ID |
|
|
143
|
+
| `imageUrl` | `string` | Current image URL |
|
|
144
|
+
| `onRemove` | `function` | Image removal handler |
|
|
145
|
+
| `aspectRatio` | `string` | Aspect ratio value |
|
|
146
|
+
| `onAspectRatioChange` | `function` | Aspect ratio change handler |
|
|
147
|
+
| `objectFit` | `string` | Object fit value (cover, contain, etc.) |
|
|
148
|
+
| `onObjectFitChange` | `function` | Object fit change handler |
|
|
149
|
+
| `focalPoint` | `object` | Focal point {x, y} coordinates |
|
|
150
|
+
| `onFocalPointChange` | `function` | Focal point change handler |
|
|
151
|
+
| `imagePosition` | `string` | CSS background position |
|
|
152
|
+
| `onImagePositionChange` | `function` | Position change handler |
|
|
153
|
+
|
|
154
|
+
## Aspect Ratios
|
|
155
|
+
|
|
156
|
+
The library includes predefined aspect ratios via `ASPECT_RATIOS`:
|
|
157
|
+
|
|
158
|
+
```jsx
|
|
159
|
+
import { ASPECT_RATIOS } from '@siratik/wp-component-library/components/media/utils/aspect-ratios';
|
|
160
|
+
|
|
161
|
+
// Available ratios:
|
|
162
|
+
{
|
|
163
|
+
'original': 'Original',
|
|
164
|
+
'1-1': 'Square (1:1)',
|
|
165
|
+
'4-3': 'Standard (4:3)',
|
|
166
|
+
'16-9': 'Widescreen (16:9)',
|
|
167
|
+
'21-9': 'Ultrawide (21:9)',
|
|
168
|
+
'3-2': 'Classic (3:2)',
|
|
169
|
+
'5-4': 'Large Format (5:4)',
|
|
170
|
+
'9-16': 'Portrait (9:16)'
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Examples
|
|
175
|
+
|
|
176
|
+
### Hero Section with Background
|
|
177
|
+
```jsx
|
|
178
|
+
function HeroSection({ attributes, setAttributes }) {
|
|
179
|
+
const { backgroundImage, focalPoint } = attributes;
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<>
|
|
183
|
+
<InspectorControls>
|
|
184
|
+
<PanelBody title="Background">
|
|
185
|
+
<SettingsMediaUpload
|
|
186
|
+
label="Background Image"
|
|
187
|
+
value={backgroundImage}
|
|
188
|
+
onSelect={(media) => setAttributes({
|
|
189
|
+
backgroundImage: {
|
|
190
|
+
id: media.id,
|
|
191
|
+
url: media.url,
|
|
192
|
+
alt: media.alt
|
|
193
|
+
}
|
|
194
|
+
})}
|
|
195
|
+
onRemove={() => setAttributes({ backgroundImage: null })}
|
|
196
|
+
focalPoint={focalPoint}
|
|
197
|
+
onFocalPointChange={(point) => setAttributes({ focalPoint: point })}
|
|
198
|
+
/>
|
|
199
|
+
</PanelBody>
|
|
200
|
+
</InspectorControls>
|
|
201
|
+
|
|
202
|
+
<div
|
|
203
|
+
className="hero"
|
|
204
|
+
style={{
|
|
205
|
+
backgroundImage: `url(${backgroundImage?.url})`,
|
|
206
|
+
backgroundPosition: `${focalPoint?.x * 100}% ${focalPoint?.y * 100}%`
|
|
207
|
+
}}
|
|
208
|
+
>
|
|
209
|
+
{/* Hero content */}
|
|
210
|
+
</div>
|
|
211
|
+
</>
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Gallery Block
|
|
217
|
+
```jsx
|
|
218
|
+
function GalleryBlock({ attributes, setAttributes }) {
|
|
219
|
+
const { images } = attributes;
|
|
220
|
+
|
|
221
|
+
return (
|
|
222
|
+
<BlockControls>
|
|
223
|
+
<ToolbarMediaUpload
|
|
224
|
+
buttonTitle="Add Images"
|
|
225
|
+
buttonIcon={gallery}
|
|
226
|
+
onSelect={(media) => {
|
|
227
|
+
const newImages = media.map(item => ({
|
|
228
|
+
id: item.id,
|
|
229
|
+
url: item.url,
|
|
230
|
+
alt: item.alt
|
|
231
|
+
}));
|
|
232
|
+
setAttributes({ images: [...images, ...newImages] });
|
|
233
|
+
}}
|
|
234
|
+
multiple={true}
|
|
235
|
+
gallery={true}
|
|
236
|
+
allowedTypes={['image']}
|
|
237
|
+
/>
|
|
238
|
+
</BlockControls>
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### Card with Featured Image
|
|
244
|
+
```jsx
|
|
245
|
+
function Card({ attributes, setAttributes }) {
|
|
246
|
+
const { featuredImage, aspectRatio, objectFit } = attributes;
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<InspectorControls>
|
|
250
|
+
<PanelBody title="Featured Image">
|
|
251
|
+
<ImageControls
|
|
252
|
+
imageId={featuredImage?.id}
|
|
253
|
+
imageUrl={featuredImage?.url}
|
|
254
|
+
onRemove={() => setAttributes({ featuredImage: null })}
|
|
255
|
+
aspectRatio={aspectRatio}
|
|
256
|
+
onAspectRatioChange={(ratio) => setAttributes({ aspectRatio: ratio })}
|
|
257
|
+
objectFit={objectFit}
|
|
258
|
+
onObjectFitChange={(fit) => setAttributes({ objectFit: fit })}
|
|
259
|
+
/>
|
|
260
|
+
</PanelBody>
|
|
261
|
+
</InspectorControls>
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Media Selection Handler
|
|
267
|
+
|
|
268
|
+
Standard media selection handler pattern:
|
|
269
|
+
```jsx
|
|
270
|
+
const handleMediaSelect = (media) => {
|
|
271
|
+
setAttributes({
|
|
272
|
+
imageId: media.id,
|
|
273
|
+
imageUrl: media.url,
|
|
274
|
+
imageAlt: media.alt,
|
|
275
|
+
imageWidth: media.width,
|
|
276
|
+
imageHeight: media.height
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Notes
|
|
282
|
+
|
|
283
|
+
- All components integrate with WordPress MediaUpload
|
|
284
|
+
- Components handle both selection and removal of media
|
|
285
|
+
- Focal point control uses WordPress FocalPointPicker
|
|
286
|
+
- Image preview automatically displayed when URL provided
|
|
287
|
+
- Components styled to match WordPress admin UI
|
|
288
|
+
- Supports all WordPress media types via allowedTypes prop
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Media Upload Component
|
|
3
|
+
* Designed for admin settings contexts (not block editor)
|
|
4
|
+
*/
|
|
5
|
+
import { MediaUpload, MediaUploadCheck } from "@wordpress/media-utils";
|
|
6
|
+
import { Button, Flex, Placeholder } from "@wordpress/components";
|
|
7
|
+
import { useSelect } from "@wordpress/data";
|
|
8
|
+
import { __ } from "@wordpress/i18n";
|
|
9
|
+
import styled from '@emotion/styled';
|
|
10
|
+
|
|
11
|
+
const ALLOWED_MEDIA_TYPES = ["image"];
|
|
12
|
+
|
|
13
|
+
// Styled components
|
|
14
|
+
const StyledSettingsMediaUpload = styled.div`
|
|
15
|
+
&__header {
|
|
16
|
+
margin-bottom: 12px;
|
|
17
|
+
}
|
|
18
|
+
`;
|
|
19
|
+
|
|
20
|
+
const StyledLabel = styled.h4`
|
|
21
|
+
margin: 0 0 4px 0;
|
|
22
|
+
font-size: 13px;
|
|
23
|
+
font-weight: 600;
|
|
24
|
+
color: #1e1e1e;
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const StyledHelp = styled.p`
|
|
28
|
+
margin: 0;
|
|
29
|
+
font-size: 13px;
|
|
30
|
+
color: #757575;
|
|
31
|
+
line-height: 1.4;
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
const StyledPreview = styled.div`
|
|
35
|
+
margin-bottom: 12px;
|
|
36
|
+
border: 1px solid #ddd;
|
|
37
|
+
border-radius: 4px;
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
background: #f9f9f9;
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
const StyledImage = styled.img`
|
|
43
|
+
max-width: 100%;
|
|
44
|
+
height: auto;
|
|
45
|
+
display: block;
|
|
46
|
+
max-height: 200px;
|
|
47
|
+
object-fit: cover;
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const StyledPlaceholder = styled(Placeholder)`
|
|
51
|
+
min-height: 120px;
|
|
52
|
+
display: flex;
|
|
53
|
+
align-items: center;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
|
|
56
|
+
.components-placeholder__label {
|
|
57
|
+
font-size: 13px;
|
|
58
|
+
color: #757575;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.components-placeholder__icon {
|
|
62
|
+
margin-bottom: 8px;
|
|
63
|
+
opacity: 0.3;
|
|
64
|
+
}
|
|
65
|
+
`;
|
|
66
|
+
|
|
67
|
+
const StyledButtons = styled.div`
|
|
68
|
+
.components-flex {
|
|
69
|
+
align-items: center;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.components-button {
|
|
73
|
+
min-width: 100px;
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Settings Media Upload
|
|
79
|
+
*
|
|
80
|
+
* @param {object} props
|
|
81
|
+
* @param {number|null} props.imageId - The ID of the selected image
|
|
82
|
+
* @param {Function} props.onSelect - Callback when image is selected
|
|
83
|
+
* @param {Function} props.onRemove - Callback when image is removed
|
|
84
|
+
* @param {string} props.label - Label for the control
|
|
85
|
+
* @param {string} props.help - Help text for the control
|
|
86
|
+
* @param {string} props.buttonTitle - Custom button text
|
|
87
|
+
* @param {boolean} props.showImagePlaceholder - Whether to show image preview
|
|
88
|
+
* @param {string} props.size - Image size for preview (default: 'medium')
|
|
89
|
+
* @returns {JSX.Element}
|
|
90
|
+
*/
|
|
91
|
+
function SettingsMediaUpload({
|
|
92
|
+
imageId,
|
|
93
|
+
onSelect,
|
|
94
|
+
onRemove,
|
|
95
|
+
label = null,
|
|
96
|
+
help = null,
|
|
97
|
+
buttonTitle = null,
|
|
98
|
+
showImagePlaceholder = true,
|
|
99
|
+
}) {
|
|
100
|
+
// Get image data for preview
|
|
101
|
+
const imageData = useSelect(
|
|
102
|
+
(select) => {
|
|
103
|
+
if (!imageId) { return null; }
|
|
104
|
+
return select("core").getEntityRecord("postType", "attachment", imageId);
|
|
105
|
+
},
|
|
106
|
+
[imageId]
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const hasImage = !!imageId;
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<StyledSettingsMediaUpload>
|
|
113
|
+
{/* Label and Help */}
|
|
114
|
+
{(label || help) && (
|
|
115
|
+
<div className="settings-media-upload__header">
|
|
116
|
+
{label && (
|
|
117
|
+
<StyledLabel>
|
|
118
|
+
{label}
|
|
119
|
+
</StyledLabel>
|
|
120
|
+
)}
|
|
121
|
+
{help && (
|
|
122
|
+
<StyledHelp>
|
|
123
|
+
{help}
|
|
124
|
+
</StyledHelp>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
)}
|
|
128
|
+
|
|
129
|
+
{/* Image Preview or Placeholder */}
|
|
130
|
+
{showImagePlaceholder && (
|
|
131
|
+
<StyledPreview>
|
|
132
|
+
{hasImage && imageData ? (
|
|
133
|
+
<StyledImage
|
|
134
|
+
src={imageData.source_url}
|
|
135
|
+
alt={imageData.alt_text || "Selected image"}
|
|
136
|
+
/>
|
|
137
|
+
) : (
|
|
138
|
+
<StyledPlaceholder
|
|
139
|
+
icon="format-image"
|
|
140
|
+
label={__("No image selected", "wp-component-library")}
|
|
141
|
+
/>
|
|
142
|
+
)}
|
|
143
|
+
</StyledPreview>
|
|
144
|
+
)}
|
|
145
|
+
|
|
146
|
+
{/* Buttons */}
|
|
147
|
+
<StyledButtons>
|
|
148
|
+
<MediaUploadCheck>
|
|
149
|
+
<Flex gap={2}>
|
|
150
|
+
<MediaUpload
|
|
151
|
+
onSelect={onSelect}
|
|
152
|
+
allowedTypes={ALLOWED_MEDIA_TYPES}
|
|
153
|
+
value={imageId}
|
|
154
|
+
render={({ open }) => (
|
|
155
|
+
<Button
|
|
156
|
+
variant="secondary"
|
|
157
|
+
onClick={open}
|
|
158
|
+
size="default"
|
|
159
|
+
>
|
|
160
|
+
{buttonTitle ||
|
|
161
|
+
(hasImage
|
|
162
|
+
? __("Change Image", "wp-component-library")
|
|
163
|
+
: __("Upload Image", "wp-component-library")
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
</Button>
|
|
167
|
+
)}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
{hasImage && (
|
|
171
|
+
<Button
|
|
172
|
+
variant="secondary"
|
|
173
|
+
isDestructive={true}
|
|
174
|
+
onClick={onRemove}
|
|
175
|
+
size="default"
|
|
176
|
+
>
|
|
177
|
+
{__("Remove Image", "wp-component-library")}
|
|
178
|
+
</Button>
|
|
179
|
+
)}
|
|
180
|
+
</Flex>
|
|
181
|
+
</MediaUploadCheck>
|
|
182
|
+
</StyledButtons>
|
|
183
|
+
</StyledSettingsMediaUpload>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export { SettingsMediaUpload };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor Media Upload Component
|
|
3
|
+
*/
|
|
4
|
+
import { MediaUpload, MediaUploadCheck } from "@wordpress/block-editor";
|
|
5
|
+
import { Button, Placeholder } from "@wordpress/components";
|
|
6
|
+
import { upload } from "@wordpress/icons";
|
|
7
|
+
|
|
8
|
+
const ALLOWED_MEDIA_TYPES = ["image"];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Editor Media Upload
|
|
12
|
+
*
|
|
13
|
+
* @param {object} props
|
|
14
|
+
* @returns {JSX.Element}
|
|
15
|
+
*/
|
|
16
|
+
function EditorMediaUpload({
|
|
17
|
+
mediaIDs,
|
|
18
|
+
onSelect,
|
|
19
|
+
gallery,
|
|
20
|
+
multiple,
|
|
21
|
+
buttonTitle,
|
|
22
|
+
style,
|
|
23
|
+
}) {
|
|
24
|
+
// Handle both ID and object formats for mediaIDs
|
|
25
|
+
const getMediaId = (mediaData) => {
|
|
26
|
+
if (!mediaData) { return null; }
|
|
27
|
+
if (typeof mediaData === "number") { return mediaData; }
|
|
28
|
+
if (typeof mediaData === "object" && mediaData.id) { return mediaData.id; }
|
|
29
|
+
return null;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const mediaId = getMediaId(mediaIDs);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Placeholder
|
|
36
|
+
style={style}
|
|
37
|
+
withIllustration={true}
|
|
38
|
+
className="placeholder-image placeholder-image--built"
|
|
39
|
+
>
|
|
40
|
+
<MediaUploadCheck>
|
|
41
|
+
<MediaUpload
|
|
42
|
+
onSelect={onSelect}
|
|
43
|
+
allowedTypes={ALLOWED_MEDIA_TYPES}
|
|
44
|
+
value={mediaId}
|
|
45
|
+
render={({ open }) => (
|
|
46
|
+
<Button
|
|
47
|
+
icon={upload}
|
|
48
|
+
variant="primary"
|
|
49
|
+
label="Upload or Select Image(s)"
|
|
50
|
+
showTooltip
|
|
51
|
+
tooltipPosition="top center"
|
|
52
|
+
onClick={open}
|
|
53
|
+
>
|
|
54
|
+
{buttonTitle}
|
|
55
|
+
</Button>
|
|
56
|
+
)}
|
|
57
|
+
gallery={gallery}
|
|
58
|
+
multiple={multiple}
|
|
59
|
+
/>
|
|
60
|
+
</MediaUploadCheck>
|
|
61
|
+
</Placeholder>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { EditorMediaUpload };
|