@secretstache/wordpress-gutenberg 0.5.3 → 0.5.5

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/build/styles.css CHANGED
@@ -153,6 +153,8 @@
153
153
  .editor-sidebar .block-editor-link-control {
154
154
  min-width: 100%;
155
155
  width: 100%; }
156
+ .editor-sidebar .block-editor-link-control .block-editor-url-input {
157
+ min-width: 100%; }
156
158
  .editor-sidebar .block-editor-link-control .block-editor-url-input__input {
157
159
  width: 100%; }
158
160
  .editor-sidebar .block-editor-link-control .components-base-control {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secretstache/wordpress-gutenberg",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "",
5
5
  "author": "Secret Stache",
6
6
  "license": "GPL-2.0-or-later",
@@ -1,4 +1,4 @@
1
- import { Button, Icon as WPIcon } from '@wordpress/components';
1
+ import { BaseControl, Button, FocalPointPicker, Icon as WPIcon } from '@wordpress/components';
2
2
  import { MediaUpload, MediaUploadCheck } from '@wordpress/block-editor';
3
3
  import { page as pageIcon } from '@wordpress/icons';
4
4
 
@@ -110,81 +110,114 @@ export const AnimationRenderer = ({
110
110
  };
111
111
 
112
112
  export const MediaControl = ({
113
+ type = MEDIA_TYPE.IMAGE,
114
+ label,
115
+
113
116
  mediaId,
114
117
  mediaUrl,
115
118
  mediaFileName = '',
119
+
116
120
  onSelect,
117
121
  onRemove,
118
- type = MEDIA_TYPE.IMAGE,
122
+
119
123
  selectButtonLabel,
120
124
  removeButtonLabel,
125
+
126
+ hasFocalPoint = true,
127
+ focalPointLabel = 'Focal Point',
128
+ focalPoint = { x: 0.5, y: 0.5 },
129
+ onFocalPointChange,
130
+
121
131
  ...other
122
132
  }) => {
123
133
  if (type === MEDIA_TYPE.IMAGE) {
124
134
  return (
125
- <MediaUploadCheck>
126
- <MediaUpload
127
- onSelect={onSelect}
128
- allowedTypes={['image', 'image/svg+xml']}
129
- accept="image/*"
130
- value={mediaId}
131
- render={({ open }) => (
132
- <ImageRenderer
133
- imageId={mediaId}
134
- imageUrl={mediaUrl}
135
- onImageClick={open}
136
- onSelectClick={open}
137
- onRemoveClick={onRemove}
138
- selectButtonLabel={selectButtonLabel}
139
- removeButtonLabel={removeButtonLabel}
135
+ <>
136
+ <BaseControl label={label || 'Image'}>
137
+ <MediaUploadCheck>
138
+ <MediaUpload
139
+ onSelect={onSelect}
140
+ allowedTypes={['image', 'image/svg+xml']}
141
+ accept="image/*"
142
+ value={mediaId}
143
+ render={({ open }) => (
144
+ <ImageRenderer
145
+ imageId={mediaId}
146
+ imageUrl={mediaUrl}
147
+ onImageClick={open}
148
+ onSelectClick={open}
149
+ onRemoveClick={onRemove}
150
+ selectButtonLabel={selectButtonLabel || 'Select Image'}
151
+ removeButtonLabel={removeButtonLabel || 'Remove Image'}
152
+ />
153
+ )}
154
+ {...other}
140
155
  />
141
- )}
142
- {...other}
143
- />
144
- </MediaUploadCheck>
156
+ </MediaUploadCheck>
157
+ </BaseControl>
158
+
159
+ {
160
+ hasFocalPoint && mediaId && mediaUrl && (
161
+ <BaseControl label={focalPointLabel}>
162
+ <FocalPointPicker
163
+ __nextHasNoMarginBottom
164
+ url={mediaUrl}
165
+ value={focalPoint}
166
+ onDragStart={onFocalPointChange}
167
+ onDrag={onFocalPointChange}
168
+ onChange={onFocalPointChange}
169
+ />
170
+ </BaseControl>
171
+ )
172
+ }
173
+ </>
145
174
  );
146
175
  } else if (type === MEDIA_TYPE.VIDEO) {
147
176
  return (
148
- <MediaUploadCheck>
149
- <MediaUpload
150
- onSelect={onSelect}
151
- allowedTypes={['video']}
152
- value={mediaId}
153
- render={({ open }) => (
154
- <VideoRenderer
155
- videoId={mediaId}
156
- videoUrl={mediaUrl}
157
- onSelectClick={open}
158
- onRemoveClick={onRemove}
159
- selectButtonLabel={selectButtonLabel}
160
- removeButtonLabel={removeButtonLabel}
161
- />
162
- )}
163
- {...other}
164
- />
165
- </MediaUploadCheck>
177
+ <BaseControl label={label || 'Video'}>
178
+ <MediaUploadCheck>
179
+ <MediaUpload
180
+ onSelect={onSelect}
181
+ allowedTypes={['video']}
182
+ value={mediaId}
183
+ render={({ open }) => (
184
+ <VideoRenderer
185
+ videoId={mediaId}
186
+ videoUrl={mediaUrl}
187
+ onSelectClick={open}
188
+ onRemoveClick={onRemove}
189
+ selectButtonLabel={selectButtonLabel || 'Select Video'}
190
+ removeButtonLabel={removeButtonLabel || 'Remove Video'}
191
+ />
192
+ )}
193
+ {...other}
194
+ />
195
+ </MediaUploadCheck>
196
+ </BaseControl>
166
197
  );
167
198
  } else if (type === MEDIA_TYPE.ANIMATION) {
168
199
  return (
169
- <MediaUploadCheck>
170
- <MediaUpload
171
- onSelect={onSelect}
172
- allowedTypes={['application/json', 'text/plain', 'application/lottie']}
173
- value={mediaId}
174
- render={({ open }) => (
175
- <AnimationRenderer
176
- animationFileId={mediaId}
177
- animationFileUrl={mediaUrl}
178
- animationFileName={mediaFileName}
179
- onSelectClick={open}
180
- onRemoveClick={onRemove}
181
- selectButtonLabel={selectButtonLabel}
182
- removeButtonLabel={removeButtonLabel}
183
- />
184
- )}
185
- {...other}
186
- />
187
- </MediaUploadCheck>
200
+ <BaseControl label={label || 'Animation'}>
201
+ <MediaUploadCheck>
202
+ <MediaUpload
203
+ onSelect={onSelect}
204
+ allowedTypes={['application/json', 'text/plain', 'application/lottie']}
205
+ value={mediaId}
206
+ render={({ open }) => (
207
+ <AnimationRenderer
208
+ animationFileId={mediaId}
209
+ animationFileUrl={mediaUrl}
210
+ animationFileName={mediaFileName}
211
+ onSelectClick={open}
212
+ onRemoveClick={onRemove}
213
+ selectButtonLabel={selectButtonLabel || 'Select Animation'}
214
+ removeButtonLabel={removeButtonLabel || 'Remove Animation'}
215
+ />
216
+ )}
217
+ {...other}
218
+ />
219
+ </MediaUploadCheck>
220
+ </BaseControl>
188
221
  );
189
222
  } else {
190
223
  throw new Error('Unrecognized media type.');
@@ -0,0 +1,78 @@
1
+ import { BaseControl, FocalPointPicker } from '@wordpress/components';
2
+ import { useCallback, memo } from '@wordpress/element';
3
+
4
+ import { MediaControl } from './MediaControl.js';
5
+ import { MEDIA_TYPE } from '../utils/index.js';
6
+
7
+ /**
8
+ * Media control with focal point functionality
9
+ *
10
+ * @param {Object} props - Component props
11
+ * @returns {JSX.Element} Component JSX
12
+ */
13
+ export const MediaWithFocalPointControl = memo(({
14
+ attributes,
15
+ setAttributes,
16
+ mediaAttributeName = 'media',
17
+ focalPointAttributeName = 'focalPoint',
18
+ mediaLabel = 'Image',
19
+ focalPointLabel = 'Focal Point',
20
+ mediaControlProps = {},
21
+ }) => {
22
+ const media = attributes[mediaAttributeName];
23
+ const focalPoint = attributes[focalPointAttributeName] || { x: 0.5, y: 0.5 };
24
+
25
+ const onFocalPointChange = useCallback((newFocalPoint) => {
26
+ setAttributes({ [focalPointAttributeName]: newFocalPoint });
27
+ }, [ focalPointAttributeName ]);
28
+
29
+ const onMediaSelect = useCallback((newMedia) => {
30
+ setAttributes({
31
+ [mediaAttributeName]: {
32
+ id: newMedia.id,
33
+ url: newMedia.url,
34
+ alt: newMedia.alt || '',
35
+ },
36
+
37
+ [focalPointAttributeName]: { x: 0.5, y: 0.5 }
38
+ });
39
+ }, [ mediaAttributeName ]);
40
+
41
+ const onMediaRemove = useCallback(() => {
42
+ setAttributes({
43
+ [mediaAttributeName]: {
44
+ id: null,
45
+ url: null,
46
+ alt: null,
47
+ }
48
+ });
49
+ }, [ mediaAttributeName ]);
50
+
51
+ return (
52
+ <>
53
+ <BaseControl label={mediaLabel}>
54
+ <MediaControl
55
+ type={MEDIA_TYPE.IMAGE}
56
+ mediaId={media?.id}
57
+ mediaUrl={media?.url}
58
+ onSelect={onMediaSelect}
59
+ onRemove={onMediaRemove}
60
+ {...mediaControlProps}
61
+ />
62
+ </BaseControl>
63
+
64
+ {media?.url && (
65
+ <BaseControl label={focalPointLabel}>
66
+ <FocalPointPicker
67
+ __nextHasNoMarginBottom
68
+ url={media.url}
69
+ value={focalPoint}
70
+ onDragStart={onFocalPointChange}
71
+ onDrag={onFocalPointChange}
72
+ onChange={onFocalPointChange}
73
+ />
74
+ </BaseControl>
75
+ )}
76
+ </>
77
+ );
78
+ });
@@ -7,9 +7,10 @@ export { SortableSelect, SortableSelectAsync } from './SortableSelect';
7
7
  export { DataQueryControls } from './DataQueryControls.js';
8
8
  export { SpacingControl } from './SpacingControl.js';
9
9
  export { ResponsiveSpacingControl } from './ResponsiveSpacingControl.js';
10
- export { ResourcesWrapper } from './ResourcesWrapper.js'
11
- export { DividersControl } from './DividersControl.js'
12
- export { MediaTypeControl } from './MediaTypeControl.js'
13
- export { InsertBlockToolbar } from './InsertBlockToolbar.js'
14
- export { PreviewControl } from './PreviewControl.js'
15
- export { EmptyBlockAppender } from './EmptyBlockAppender.js'
10
+ export { ResourcesWrapper } from './ResourcesWrapper.js';
11
+ export { DividersControl } from './DividersControl.js';
12
+ export { MediaTypeControl } from './MediaTypeControl.js';
13
+ export { InsertBlockToolbar } from './InsertBlockToolbar.js';
14
+ export { PreviewControl } from './PreviewControl.js';
15
+ export { EmptyBlockAppender } from './EmptyBlockAppender.js';
16
+ export { MediaWithFocalPointControl } from './MediaWithFocalPointControl.js';
@@ -30,6 +30,10 @@
30
30
  min-width: 100%;
31
31
  width: 100%;
32
32
 
33
+ .block-editor-url-input {
34
+ min-width: 100%;
35
+ }
36
+
33
37
  .block-editor-url-input__input {
34
38
  width: 100%;
35
39
  }
@@ -254,3 +254,22 @@ export function updateBlockApiVersion(blockName, apiVersion = 3) {
254
254
  });
255
255
  }
256
256
  }
257
+
258
+ /**
259
+ * Creates object-position style based on focal point coordinates
260
+ *
261
+ * @param {Object} focalPoint - Focal point coordinates { x, y }
262
+ * @returns {Object} Style object with objectPosition property
263
+ */
264
+ export const getFocalPointStyle = (focalPoint) => {
265
+ if (!focalPoint) {
266
+ return { objectPosition: '50% 50%' };
267
+ }
268
+
269
+ // Handle edge case where x or y is 0
270
+ const x = (focalPoint.x !== undefined && focalPoint.x !== null) ? focalPoint.x * 100 : 50;
271
+ const y = (focalPoint.y !== undefined && focalPoint.y !== null) ? focalPoint.y * 100 : 50;
272
+
273
+ return { objectPosition: `${x}% ${y}%` };
274
+ };
275
+