@wordpress/block-library 7.1.1 → 7.2.0

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 (304) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/build/avatar/edit.js +205 -0
  3. package/build/avatar/edit.js.map +1 -0
  4. package/build/avatar/hooks.js +111 -0
  5. package/build/avatar/hooks.js.map +1 -0
  6. package/build/avatar/index.js +83 -0
  7. package/build/avatar/index.js.map +1 -0
  8. package/build/avatar/user-control.js +63 -0
  9. package/build/avatar/user-control.js.map +1 -0
  10. package/build/column/index.js +2 -1
  11. package/build/column/index.js.map +1 -1
  12. package/build/comment-author-avatar/index.js +1 -0
  13. package/build/comment-author-avatar/index.js.map +1 -1
  14. package/build/comment-date/edit.js +10 -25
  15. package/build/comment-date/edit.js.map +1 -1
  16. package/build/comment-template/edit.js +79 -52
  17. package/build/comment-template/edit.js.map +1 -1
  18. package/build/cover/edit.js +23 -33
  19. package/build/cover/edit.js.map +1 -1
  20. package/build/embed/variations.js +2 -2
  21. package/build/embed/variations.js.map +1 -1
  22. package/build/gallery/edit.js +18 -5
  23. package/build/gallery/edit.js.map +1 -1
  24. package/build/gallery/gallery.js +1 -1
  25. package/build/gallery/gallery.js.map +1 -1
  26. package/build/gallery/gap-styles.js +29 -0
  27. package/build/gallery/gap-styles.js.map +1 -0
  28. package/build/gallery/index.js +17 -1
  29. package/build/gallery/index.js.map +1 -1
  30. package/build/group/index.js +3 -1
  31. package/build/group/index.js.map +1 -1
  32. package/build/group/variations.js +1 -2
  33. package/build/group/variations.js.map +1 -1
  34. package/build/image/image.js +3 -1
  35. package/build/image/image.js.map +1 -1
  36. package/build/index.js +8 -2
  37. package/build/index.js.map +1 -1
  38. package/build/list/index.js +5 -7
  39. package/build/list/index.js.map +1 -1
  40. package/build/list/v2/edit.js +85 -0
  41. package/build/list/v2/edit.js.map +1 -0
  42. package/build/list/v2/index.js +33 -0
  43. package/build/list/v2/index.js.map +1 -0
  44. package/build/list/v2/save.js +34 -0
  45. package/build/list/v2/save.js.map +1 -0
  46. package/build/list/v2/transforms.js +121 -0
  47. package/build/list/v2/transforms.js.map +1 -0
  48. package/build/list-item/edit.js +47 -0
  49. package/build/list-item/edit.js.map +1 -0
  50. package/build/list-item/index.js +67 -0
  51. package/build/list-item/index.js.map +1 -0
  52. package/build/list-item/save.js +23 -0
  53. package/build/list-item/save.js.map +1 -0
  54. package/build/media-text/edit.js +3 -1
  55. package/build/media-text/edit.js.map +1 -1
  56. package/build/navigation/use-navigation-entities.js +26 -54
  57. package/build/navigation/use-navigation-entities.js.map +1 -1
  58. package/build/navigation-link/edit.js +88 -34
  59. package/build/navigation-link/edit.js.map +1 -1
  60. package/build/post-date/edit.js +31 -37
  61. package/build/post-date/edit.js.map +1 -1
  62. package/build/post-featured-image/edit.js +2 -1
  63. package/build/post-featured-image/edit.js.map +1 -1
  64. package/build/pullquote/edit.js +5 -3
  65. package/build/pullquote/edit.js.map +1 -1
  66. package/build/query/variations.js +4 -4
  67. package/build/query/variations.js.map +1 -1
  68. package/build/query-no-results/edit.js +28 -0
  69. package/build/query-no-results/edit.js.map +1 -0
  70. package/build/query-no-results/index.js +54 -0
  71. package/build/query-no-results/index.js.map +1 -0
  72. package/build/query-no-results/save.js +18 -0
  73. package/build/query-no-results/save.js.map +1 -0
  74. package/build/search/edit.js +2 -3
  75. package/build/search/edit.js.map +1 -1
  76. package/build/separator/deprecated.js +83 -0
  77. package/build/separator/deprecated.js.map +1 -0
  78. package/build/separator/edit.js +31 -23
  79. package/build/separator/edit.js.map +1 -1
  80. package/build/separator/index.js +17 -7
  81. package/build/separator/index.js.map +1 -1
  82. package/build/separator/save.js +18 -13
  83. package/build/separator/save.js.map +1 -1
  84. package/build/separator/use-deprecated-opacity.js +39 -0
  85. package/build/separator/use-deprecated-opacity.js.map +1 -0
  86. package/build/social-links/edit.js +14 -3
  87. package/build/social-links/edit.js.map +1 -1
  88. package/build/social-links/index.js +1 -1
  89. package/build/spacer/controls.js +6 -16
  90. package/build/spacer/controls.js.map +1 -1
  91. package/build/spacer/controls.native.js +3 -1
  92. package/build/spacer/controls.native.js.map +1 -1
  93. package/build/spacer/edit.js +4 -5
  94. package/build/spacer/edit.js.map +1 -1
  95. package/build/table/deprecated.js +1 -1
  96. package/build/table/deprecated.js.map +1 -1
  97. package/build/tag-cloud/edit.js +58 -2
  98. package/build/tag-cloud/edit.js.map +1 -1
  99. package/build/tag-cloud/index.js +8 -0
  100. package/build/tag-cloud/index.js.map +1 -1
  101. package/build-module/avatar/edit.js +190 -0
  102. package/build-module/avatar/edit.js.map +1 -0
  103. package/build-module/avatar/hooks.js +99 -0
  104. package/build-module/avatar/hooks.js.map +1 -0
  105. package/build-module/avatar/index.js +70 -0
  106. package/build-module/avatar/index.js.map +1 -0
  107. package/build-module/avatar/user-control.js +52 -0
  108. package/build-module/avatar/user-control.js.map +1 -0
  109. package/build-module/column/index.js +2 -1
  110. package/build-module/column/index.js.map +1 -1
  111. package/build-module/comment-author-avatar/index.js +1 -0
  112. package/build-module/comment-author-avatar/index.js.map +1 -1
  113. package/build-module/comment-date/edit.js +13 -30
  114. package/build-module/comment-date/edit.js.map +1 -1
  115. package/build-module/comment-template/edit.js +79 -52
  116. package/build-module/comment-template/edit.js.map +1 -1
  117. package/build-module/cover/edit.js +23 -34
  118. package/build-module/cover/edit.js.map +1 -1
  119. package/build-module/embed/variations.js +2 -2
  120. package/build-module/embed/variations.js.map +1 -1
  121. package/build-module/gallery/edit.js +17 -5
  122. package/build-module/gallery/edit.js.map +1 -1
  123. package/build-module/gallery/gallery.js +1 -1
  124. package/build-module/gallery/gallery.js.map +1 -1
  125. package/build-module/gallery/gap-styles.js +22 -0
  126. package/build-module/gallery/gap-styles.js.map +1 -0
  127. package/build-module/gallery/index.js +17 -1
  128. package/build-module/gallery/index.js.map +1 -1
  129. package/build-module/group/index.js +3 -1
  130. package/build-module/group/index.js.map +1 -1
  131. package/build-module/group/variations.js +1 -2
  132. package/build-module/group/variations.js.map +1 -1
  133. package/build-module/image/image.js +3 -1
  134. package/build-module/image/image.js.map +1 -1
  135. package/build-module/index.js +5 -2
  136. package/build-module/index.js.map +1 -1
  137. package/build-module/list/index.js +5 -1
  138. package/build-module/list/index.js.map +1 -1
  139. package/build-module/list/v2/edit.js +69 -0
  140. package/build-module/list/v2/edit.js.map +1 -0
  141. package/build-module/list/v2/index.js +19 -0
  142. package/build-module/list/v2/index.js.map +1 -0
  143. package/build-module/list/v2/save.js +23 -0
  144. package/build-module/list/v2/save.js.map +1 -0
  145. package/build-module/list/v2/transforms.js +111 -0
  146. package/build-module/list/v2/transforms.js.map +1 -0
  147. package/build-module/list-item/edit.js +37 -0
  148. package/build-module/list-item/edit.js.map +1 -0
  149. package/build-module/list-item/index.js +53 -0
  150. package/build-module/list-item/index.js.map +1 -0
  151. package/build-module/list-item/save.js +15 -0
  152. package/build-module/list-item/save.js.map +1 -0
  153. package/build-module/media-text/edit.js +3 -1
  154. package/build-module/media-text/edit.js.map +1 -1
  155. package/build-module/navigation/use-navigation-entities.js +27 -54
  156. package/build-module/navigation/use-navigation-entities.js.map +1 -1
  157. package/build-module/navigation-link/edit.js +88 -33
  158. package/build-module/navigation-link/edit.js.map +1 -1
  159. package/build-module/post-date/edit.js +32 -43
  160. package/build-module/post-date/edit.js.map +1 -1
  161. package/build-module/post-featured-image/edit.js +2 -1
  162. package/build-module/post-featured-image/edit.js.map +1 -1
  163. package/build-module/pullquote/edit.js +6 -3
  164. package/build-module/pullquote/edit.js.map +1 -1
  165. package/build-module/query/variations.js +4 -4
  166. package/build-module/query/variations.js.map +1 -1
  167. package/build-module/query-no-results/edit.js +18 -0
  168. package/build-module/query-no-results/edit.js.map +1 -0
  169. package/build-module/query-no-results/index.js +40 -0
  170. package/build-module/query-no-results/index.js.map +1 -0
  171. package/build-module/query-no-results/save.js +10 -0
  172. package/build-module/query-no-results/save.js.map +1 -0
  173. package/build-module/search/edit.js +2 -3
  174. package/build-module/search/edit.js.map +1 -1
  175. package/build-module/separator/deprecated.js +70 -0
  176. package/build-module/separator/deprecated.js.map +1 -0
  177. package/build-module/separator/edit.js +31 -22
  178. package/build-module/separator/edit.js.map +1 -1
  179. package/build-module/separator/index.js +16 -7
  180. package/build-module/separator/index.js.map +1 -1
  181. package/build-module/separator/save.js +19 -14
  182. package/build-module/separator/save.js.map +1 -1
  183. package/build-module/separator/use-deprecated-opacity.js +30 -0
  184. package/build-module/separator/use-deprecated-opacity.js.map +1 -0
  185. package/build-module/social-links/edit.js +15 -4
  186. package/build-module/social-links/edit.js.map +1 -1
  187. package/build-module/social-links/index.js +1 -1
  188. package/build-module/spacer/controls.js +8 -19
  189. package/build-module/spacer/controls.js.map +1 -1
  190. package/build-module/spacer/controls.native.js +2 -1
  191. package/build-module/spacer/controls.native.js.map +1 -1
  192. package/build-module/spacer/edit.js +3 -3
  193. package/build-module/spacer/edit.js.map +1 -1
  194. package/build-module/table/deprecated.js +1 -1
  195. package/build-module/table/deprecated.js.map +1 -1
  196. package/build-module/tag-cloud/edit.js +60 -4
  197. package/build-module/tag-cloud/edit.js.map +1 -1
  198. package/build-module/tag-cloud/index.js +8 -0
  199. package/build-module/tag-cloud/index.js.map +1 -1
  200. package/build-style/avatar/editor-rtl.css +79 -0
  201. package/build-style/avatar/editor.css +79 -0
  202. package/build-style/editor-rtl.css +23 -2
  203. package/build-style/editor.css +23 -2
  204. package/build-style/gallery/editor-rtl.css +0 -1
  205. package/build-style/gallery/editor.css +0 -1
  206. package/build-style/gallery/style-rtl.css +102 -169
  207. package/build-style/gallery/style.css +102 -169
  208. package/build-style/image/style-rtl.css +2 -0
  209. package/build-style/image/style.css +2 -0
  210. package/build-style/navigation-link/editor-rtl.css +13 -0
  211. package/build-style/navigation-link/editor.css +13 -0
  212. package/build-style/pullquote/style-rtl.css +0 -4
  213. package/build-style/pullquote/style.css +0 -4
  214. package/build-style/separator/editor-rtl.css +3 -0
  215. package/build-style/separator/editor.css +3 -0
  216. package/build-style/separator/theme-rtl.css +7 -1
  217. package/build-style/separator/theme.css +7 -1
  218. package/build-style/site-logo/editor-rtl.css +3 -1
  219. package/build-style/site-logo/editor.css +3 -1
  220. package/build-style/style-rtl.css +104 -173
  221. package/build-style/style.css +104 -173
  222. package/build-style/theme-rtl.css +7 -1
  223. package/build-style/theme.css +7 -1
  224. package/package.json +28 -28
  225. package/src/avatar/block.json +53 -0
  226. package/src/avatar/edit.js +222 -0
  227. package/src/avatar/editor.scss +3 -0
  228. package/src/avatar/hooks.js +96 -0
  229. package/src/avatar/index.js +18 -0
  230. package/src/avatar/index.php +146 -0
  231. package/src/avatar/user-control.js +56 -0
  232. package/src/column/block.json +2 -1
  233. package/src/comment-author-avatar/block.json +1 -0
  234. package/src/comment-date/edit.js +20 -30
  235. package/src/comment-template/edit.js +65 -44
  236. package/src/cover/edit.js +26 -31
  237. package/src/editor.scss +1 -0
  238. package/src/embed/variations.js +2 -2
  239. package/src/gallery/block.json +17 -1
  240. package/src/gallery/deprecated.scss +2 -2
  241. package/src/gallery/edit.js +15 -8
  242. package/src/gallery/editor.scss +0 -1
  243. package/src/gallery/gallery.js +8 -7
  244. package/src/gallery/gap-styles.js +21 -0
  245. package/src/gallery/index.php +42 -1
  246. package/src/gallery/style.scss +11 -44
  247. package/src/group/block.json +3 -1
  248. package/src/group/variations.js +1 -1
  249. package/src/image/image.js +4 -1
  250. package/src/image/style.scss +3 -0
  251. package/src/index.js +6 -1
  252. package/src/list/index.js +6 -1
  253. package/src/list/v2/edit.js +77 -0
  254. package/src/list/v2/index.js +20 -0
  255. package/src/list/v2/save.js +18 -0
  256. package/src/list/v2/transforms.js +116 -0
  257. package/src/list-item/block.json +26 -0
  258. package/src/list-item/edit.js +47 -0
  259. package/src/list-item/index.js +27 -0
  260. package/src/list-item/save.js +13 -0
  261. package/src/media-text/edit.js +1 -1
  262. package/src/navigation/index.php +22 -2
  263. package/src/navigation/use-navigation-entities.js +37 -73
  264. package/src/navigation-link/edit.js +145 -61
  265. package/src/navigation-link/editor.scss +11 -0
  266. package/src/post-date/edit.js +63 -52
  267. package/src/post-date/index.php +1 -1
  268. package/src/post-date/test/edit.js +17 -0
  269. package/src/post-featured-image/edit.js +9 -1
  270. package/src/post-featured-image/index.php +2 -1
  271. package/src/pullquote/edit.js +4 -3
  272. package/src/pullquote/style.scss +0 -5
  273. package/src/query/variations.js +4 -0
  274. package/src/query-no-results/block.json +20 -0
  275. package/src/query-no-results/edit.js +28 -0
  276. package/src/query-no-results/index.js +20 -0
  277. package/src/query-no-results/index.php +59 -0
  278. package/src/query-no-results/save.js +8 -0
  279. package/src/search/edit.js +1 -2
  280. package/src/separator/block.json +13 -6
  281. package/src/separator/deprecated.js +57 -0
  282. package/src/separator/deprecated.scss +6 -0
  283. package/src/separator/edit.js +36 -14
  284. package/src/separator/editor.scss +6 -0
  285. package/src/separator/index.js +2 -0
  286. package/src/separator/save.js +22 -14
  287. package/src/separator/test/edit.js +113 -0
  288. package/src/separator/theme.scss +7 -1
  289. package/src/separator/use-deprecated-opacity.js +41 -0
  290. package/src/site-logo/editor.scss +3 -1
  291. package/src/social-links/block.json +1 -1
  292. package/src/social-links/edit.js +15 -5
  293. package/src/spacer/controls.js +12 -18
  294. package/src/spacer/controls.native.js +2 -1
  295. package/src/spacer/edit.js +3 -6
  296. package/src/table/deprecated.js +5 -1
  297. package/src/tag-cloud/block.json +8 -0
  298. package/src/tag-cloud/edit.js +82 -2
  299. package/src/tag-cloud/index.php +6 -0
  300. package/build/separator/separator-settings.js +0 -36
  301. package/build/separator/separator-settings.js.map +0 -1
  302. package/build-module/separator/separator-settings.js +0 -27
  303. package/build-module/separator/separator-settings.js.map +0 -1
  304. package/src/separator/separator-settings.js +0 -24
@@ -0,0 +1,222 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classnames from 'classnames';
5
+
6
+ /**
7
+ * WordPress dependencies
8
+ */
9
+ import {
10
+ InspectorControls,
11
+ useBlockProps,
12
+ __experimentalUseBorderProps as useBorderProps,
13
+ } from '@wordpress/block-editor';
14
+ import {
15
+ PanelBody,
16
+ RangeControl,
17
+ ResizableBox,
18
+ ToggleControl,
19
+ } from '@wordpress/components';
20
+ import { __, isRTL } from '@wordpress/i18n';
21
+
22
+ /**
23
+ * Internal dependencies
24
+ */
25
+ import { useUserAvatar, useCommentAvatar } from './hooks';
26
+ import UserControl from './user-control';
27
+
28
+ const AvatarInspectorControls = ( {
29
+ setAttributes,
30
+ avatar,
31
+ attributes,
32
+ selectUser,
33
+ } ) => (
34
+ <InspectorControls>
35
+ <PanelBody title={ __( 'Avatar Settings' ) }>
36
+ <RangeControl
37
+ label={ __( 'Image size' ) }
38
+ onChange={ ( newSize ) =>
39
+ setAttributes( {
40
+ size: newSize,
41
+ } )
42
+ }
43
+ min={ avatar.minSize }
44
+ max={ avatar.maxSize }
45
+ initialPosition={ attributes?.size }
46
+ value={ attributes?.size }
47
+ />
48
+ { selectUser && (
49
+ <UserControl
50
+ value={ attributes?.userId }
51
+ onChange={ ( value ) => {
52
+ setAttributes( {
53
+ userId: value,
54
+ } );
55
+ } }
56
+ />
57
+ ) }
58
+ <ToggleControl
59
+ label={ __( 'Link to user profile' ) }
60
+ onChange={ () =>
61
+ setAttributes( { isLink: ! attributes.isLink } )
62
+ }
63
+ checked={ attributes.isLink }
64
+ />
65
+ { attributes.isLink && (
66
+ <ToggleControl
67
+ label={ __( 'Open in new tab' ) }
68
+ onChange={ ( value ) =>
69
+ setAttributes( {
70
+ linkTarget: value ? '_blank' : '_self',
71
+ } )
72
+ }
73
+ checked={ attributes.linkTarget === '_blank' }
74
+ />
75
+ ) }
76
+ </PanelBody>
77
+ </InspectorControls>
78
+ );
79
+
80
+ const ResizableAvatar = ( {
81
+ setAttributes,
82
+ attributes,
83
+ avatar,
84
+ blockProps,
85
+ isSelected,
86
+ } ) => {
87
+ const borderProps = useBorderProps( attributes );
88
+ return (
89
+ <div { ...blockProps }>
90
+ <ResizableBox
91
+ size={ {
92
+ width: attributes.size,
93
+ height: attributes.size,
94
+ } }
95
+ showHandle={ isSelected }
96
+ onResizeStop={ ( event, direction, elt, delta ) => {
97
+ setAttributes( {
98
+ size: parseInt(
99
+ attributes.size + ( delta.height || delta.width ),
100
+ 10
101
+ ),
102
+ } );
103
+ } }
104
+ lockAspectRatio
105
+ enable={ {
106
+ top: false,
107
+ right: ! isRTL(),
108
+ bottom: true,
109
+ left: isRTL(),
110
+ } }
111
+ minWidth={ avatar.minSize }
112
+ maxWidth={ avatar.maxSize }
113
+ >
114
+ <img
115
+ src={ avatar.src }
116
+ alt={ avatar.alt }
117
+ { ...borderProps }
118
+ className={ classnames(
119
+ 'avatar',
120
+ 'avatar-' + attributes.size,
121
+ 'photo',
122
+ 'wp-block-avatar__image',
123
+ borderProps.className
124
+ ) }
125
+ style={ {
126
+ ...borderProps.style, // Border radius, width and style.
127
+ } }
128
+ />
129
+ </ResizableBox>
130
+ </div>
131
+ );
132
+ };
133
+ const CommentEdit = ( { attributes, context, setAttributes, isSelected } ) => {
134
+ const { commentId } = context;
135
+ const blockProps = useBlockProps();
136
+ const avatar = useCommentAvatar( { commentId } );
137
+ return (
138
+ <>
139
+ <AvatarInspectorControls
140
+ avatar={ avatar }
141
+ setAttributes={ setAttributes }
142
+ attributes={ attributes }
143
+ selectUser={ false }
144
+ />
145
+ { attributes.isLink ? (
146
+ <a
147
+ href="#avatar-pseudo-link"
148
+ className="wp-block-avatar__link"
149
+ onClick={ ( event ) => event.preventDefault() }
150
+ >
151
+ <ResizableAvatar
152
+ attributes={ attributes }
153
+ avatar={ avatar }
154
+ blockProps={ blockProps }
155
+ isSelected={ isSelected }
156
+ setAttributes={ setAttributes }
157
+ />
158
+ </a>
159
+ ) : (
160
+ <ResizableAvatar
161
+ attributes={ attributes }
162
+ avatar={ avatar }
163
+ blockProps={ blockProps }
164
+ isSelected={ isSelected }
165
+ setAttributes={ setAttributes }
166
+ />
167
+ ) }
168
+ </>
169
+ );
170
+ };
171
+
172
+ const UserEdit = ( { attributes, context, setAttributes, isSelected } ) => {
173
+ const { postId, postType } = context;
174
+ const avatar = useUserAvatar( {
175
+ userId: attributes?.userId,
176
+ postId,
177
+ postType,
178
+ } );
179
+ const blockProps = useBlockProps();
180
+ return (
181
+ <>
182
+ <AvatarInspectorControls
183
+ selectUser={ true }
184
+ attributes={ attributes }
185
+ avatar={ avatar }
186
+ setAttributes={ setAttributes }
187
+ />
188
+ <div>
189
+ { attributes.isLink ? (
190
+ <a
191
+ href="#avatar-pseudo-link"
192
+ className="wp-block-avatar__link"
193
+ onClick={ ( event ) => event.preventDefault() }
194
+ >
195
+ <ResizableAvatar
196
+ attributes={ attributes }
197
+ avatar={ avatar }
198
+ blockProps={ blockProps }
199
+ isSelected={ isSelected }
200
+ setAttributes={ setAttributes }
201
+ />
202
+ </a>
203
+ ) : (
204
+ <ResizableAvatar
205
+ attributes={ attributes }
206
+ avatar={ avatar }
207
+ blockProps={ blockProps }
208
+ isSelected={ isSelected }
209
+ setAttributes={ setAttributes }
210
+ />
211
+ ) }
212
+ </div>
213
+ </>
214
+ );
215
+ };
216
+
217
+ export default function Edit( props ) {
218
+ if ( props?.context?.commentId ) {
219
+ return <CommentEdit { ...props } />;
220
+ }
221
+ return <UserEdit { ...props } />;
222
+ }
@@ -0,0 +1,3 @@
1
+ .wp-block-avatar__image img {
2
+ width: 100%;
3
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { store as blockEditorStore } from '@wordpress/block-editor';
5
+ import { store as coreStore, useEntityProp } from '@wordpress/core-data';
6
+ import { __, sprintf } from '@wordpress/i18n';
7
+ import { useSelect } from '@wordpress/data';
8
+
9
+ function getAvatarSizes( sizes ) {
10
+ const minSize = sizes ? sizes[ 0 ] : 24;
11
+ const maxSize = sizes ? sizes[ sizes.length - 1 ] : 96;
12
+ const maxSizeBuffer = Math.floor( maxSize * 2.5 );
13
+ return {
14
+ minSize,
15
+ maxSize: maxSizeBuffer,
16
+ };
17
+ }
18
+
19
+ function useDefaultAvatar() {
20
+ const { avatarURL: defaultAvatarUrl } = useSelect( ( select ) => {
21
+ const { getSettings } = select( blockEditorStore );
22
+ const { __experimentalDiscussionSettings } = getSettings();
23
+ return __experimentalDiscussionSettings;
24
+ } );
25
+ return defaultAvatarUrl;
26
+ }
27
+
28
+ export function useCommentAvatar( { commentId } ) {
29
+ const [ avatars ] = useEntityProp(
30
+ 'root',
31
+ 'comment',
32
+ 'author_avatar_urls',
33
+ commentId
34
+ );
35
+
36
+ const [ authorName ] = useEntityProp(
37
+ 'root',
38
+ 'comment',
39
+ 'author_name',
40
+ commentId
41
+ );
42
+ const avatarUrls = avatars ? Object.values( avatars ) : null;
43
+ const sizes = avatars ? Object.keys( avatars ) : null;
44
+ const { minSize, maxSize } = getAvatarSizes( sizes );
45
+ const defaultAvatar = useDefaultAvatar();
46
+ return {
47
+ src: avatarUrls ? avatarUrls[ avatarUrls.length - 1 ] : defaultAvatar,
48
+ minSize,
49
+ maxSize,
50
+ // translators: %s is the Author name.
51
+ alt: authorName
52
+ ? // translators: %s is the Author name.
53
+ sprintf( __( '%s Avatar' ), authorName )
54
+ : __( 'Default Avatar' ),
55
+ };
56
+ }
57
+
58
+ export function useUserAvatar( { userId, postId, postType } ) {
59
+ const { authorDetails } = useSelect(
60
+ ( select ) => {
61
+ const { getEditedEntityRecord, getUser } = select( coreStore );
62
+ if ( userId ) {
63
+ return {
64
+ authorDetails: getUser( userId ),
65
+ };
66
+ }
67
+ const _authorId = getEditedEntityRecord(
68
+ 'postType',
69
+ postType,
70
+ postId
71
+ )?.author;
72
+
73
+ return {
74
+ authorDetails: _authorId ? getUser( _authorId ) : null,
75
+ };
76
+ },
77
+ [ postType, postId, userId ]
78
+ );
79
+ const avatarUrls = authorDetails
80
+ ? Object.values( authorDetails.avatar_urls )
81
+ : null;
82
+ const sizes = authorDetails
83
+ ? Object.keys( authorDetails.avatar_urls )
84
+ : null;
85
+ const { minSize, maxSize } = getAvatarSizes( sizes );
86
+ const defaultAvatar = useDefaultAvatar();
87
+ return {
88
+ src: avatarUrls ? avatarUrls[ avatarUrls.length - 1 ] : defaultAvatar,
89
+ minSize,
90
+ maxSize,
91
+ alt: authorDetails
92
+ ? // translators: %s is the Author name.
93
+ sprintf( __( '%s Avatar' ), authorDetails?.name )
94
+ : __( 'Default Avatar' ),
95
+ };
96
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { commentAuthorAvatar as icon } from '@wordpress/icons';
5
+
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import metadata from './block.json';
10
+ import edit from './edit';
11
+
12
+ const { name } = metadata;
13
+ export { metadata, name };
14
+
15
+ export const settings = {
16
+ icon,
17
+ edit,
18
+ };
@@ -0,0 +1,146 @@
1
+ <?php
2
+ /**
3
+ * Server-side rendering of the `core/avatar` block.
4
+ *
5
+ * @package WordPress
6
+ */
7
+
8
+ /**
9
+ * Renders the `core/avatar` block on the server.
10
+ *
11
+ * @param array $attributes Block attributes.
12
+ * @param string $content Block default content.
13
+ * @param WP_Block $block Block instance.
14
+ * @return string Return the avatar.
15
+ */
16
+ function render_block_core_avatar( $attributes, $content, $block ) {
17
+ $size = isset( $attributes['size'] ) ? $attributes['size'] : 96;
18
+ $wrapper_attributes = get_block_wrapper_attributes();
19
+
20
+ $image_styles = array();
21
+
22
+ // Add border width styles.
23
+ $has_border_width = ! empty( $attributes['style']['border']['width'] );
24
+
25
+ if ( $has_border_width ) {
26
+ $border_width = $attributes['style']['border']['width'];
27
+ $image_styles[] = sprintf( 'border-width: %s;', esc_attr( $border_width ) );
28
+ }
29
+
30
+ // Add border radius styles.
31
+ $has_border_radius = ! empty( $attributes['style']['border']['radius'] );
32
+
33
+ if ( $has_border_radius ) {
34
+ $border_radius = $attributes['style']['border']['radius'];
35
+
36
+ if ( is_array( $border_radius ) ) {
37
+ // Apply styles for individual corner border radii.
38
+ foreach ( $border_radius as $key => $value ) {
39
+ if ( null !== $value ) {
40
+ $name = _wp_to_kebab_case( $key );
41
+ // Add shared styles for individual border radii.
42
+ $border_style = sprintf(
43
+ 'border-%s-radius: %s;',
44
+ esc_attr( $name ),
45
+ esc_attr( $value )
46
+ );
47
+ $image_styles[] = $border_style;
48
+ }
49
+ }
50
+ } else {
51
+ $border_style = sprintf( 'border-radius: %s;', esc_attr( $border_radius ) );
52
+ $image_styles[] = $border_style;
53
+ }
54
+ }
55
+
56
+ // Add border color styles.
57
+ $has_border_color = ! empty( $attributes['style']['border']['color'] );
58
+
59
+ if ( $has_border_color ) {
60
+ $border_color = $attributes['style']['border']['color'];
61
+ $image_styles[] = sprintf( 'border-color: %s;', esc_attr( $border_color ) );
62
+ }
63
+
64
+ // Add border style (solid, dashed, dotted ).
65
+ $has_border_style = ! empty( $attributes['style']['border']['style'] );
66
+
67
+ if ( $has_border_style ) {
68
+ $border_style = $attributes['style']['border']['style'];
69
+ $image_styles[] = sprintf( 'border-style: %s;', esc_attr( $border_style ) );
70
+ }
71
+
72
+ // Add border classes to the avatar image for both custom colors and palette colors.
73
+ $image_classes = '';
74
+ if ( $has_border_color || isset( $attributes['borderColor'] ) ) {
75
+ $image_classes .= 'has-border-color';
76
+ }
77
+ if ( isset( $attributes['borderColor'] ) ) {
78
+ $image_classes .= ' has-' . $attributes['borderColor'] . '-border-color';
79
+ }
80
+
81
+ if ( ! isset( $block->context['commentId'] ) ) {
82
+ $author_id = isset( $attributes['userId'] ) ? $attributes['userId'] : get_post_field( 'post_author', $block->context['postId'] );
83
+ $author_name = get_the_author_meta( 'display_name', $author_id );
84
+ // translators: %s is the Author name.
85
+ $alt = sprintf( __( '%s Avatar' ), $author_name );
86
+ $avatar_block = get_avatar(
87
+ $author_id,
88
+ $size,
89
+ '',
90
+ $alt,
91
+ array(
92
+ 'extra_attr' => isset( $image_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $image_styles ) ) ) : '',
93
+ 'class' => "wp-block-avatar__image $image_classes ",
94
+ )
95
+ );
96
+ if ( isset( $attributes['isLink'] ) && $attributes['isLink'] ) {
97
+ $label = '';
98
+ if ( '_blank' === $attributes['linkTarget'] ) {
99
+ // translators: %s is the Author name.
100
+ $label = 'aria-label="' . sprintf( esc_attr__( '( %s author archive, opens in a new tab)' ), $author_name ) . '"';
101
+ }
102
+ // translators: %1$s: Author archive link. %2$s: Link target. %3$s Aria label. %4$s Avatar image.
103
+ $avatar_block = sprintf( '<a href="%1$s" target="%2$s" %3$s class="wp-block-avatar__link">%4$s</a>', get_author_posts_url( $author_id ), esc_attr( $attributes['linkTarget'] ), $label, $avatar_block );
104
+ }
105
+ return sprintf( '<div %1s>%2s</div>', $wrapper_attributes, $avatar_block );
106
+ }
107
+ $comment = get_comment( $block->context['commentId'] );
108
+ /* translators: %s is the Comment Author name */
109
+ $alt = sprintf( __( '%s Avatar' ), $comment->comment_author );
110
+ if ( ! $comment ) {
111
+ return '';
112
+ }
113
+ $avatar_block = get_avatar(
114
+ $comment,
115
+ $size,
116
+ '',
117
+ $alt,
118
+ array(
119
+ 'extra_attr' => isset( $image_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $image_styles ) ) ) : '',
120
+ 'class' => "wp-block-avatar__image $image_classes",
121
+ )
122
+ );
123
+ if ( isset( $attributes['isLink'] ) && $attributes['isLink'] && isset( $comment->comment_author_url ) && '' !== $comment->comment_author_url ) {
124
+ $label = '';
125
+ if ( '_blank' === $attributes['linkTarget'] ) {
126
+ // translators: %s is the Comment Author name.
127
+ $label = 'aria-label="' . sprintf( esc_attr__( '( %s website link, opens in a new tab)' ), $comment->comment_author ) . '"';
128
+ }
129
+ // translators: %1$s: Comment Author website link. %2$s: Link target. %3$s Aria label. %4$s Avatar image.
130
+ $avatar_block = sprintf( '<a href="%1$s" target="%2$s" %3$s class="wp-block-avatar__link">%4$s</a>', $comment->comment_author_url, esc_attr( $attributes['linkTarget'] ), $label, $avatar_block );
131
+ }
132
+ return sprintf( '<div %1s>%2s</div>', $wrapper_attributes, $avatar_block );
133
+ }
134
+
135
+ /**
136
+ * Registers the `core/avatar` block on the server.
137
+ */
138
+ function register_block_core_avatar() {
139
+ register_block_type_from_metadata(
140
+ __DIR__ . '/avatar',
141
+ array(
142
+ 'render_callback' => 'render_block_core_avatar',
143
+ )
144
+ );
145
+ }
146
+ add_action( 'init', 'register_block_core_avatar' );
@@ -0,0 +1,56 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { ComboboxControl } from '@wordpress/components';
6
+ import { useSelect } from '@wordpress/data';
7
+ import { store as coreStore } from '@wordpress/core-data';
8
+ import { useState } from '@wordpress/element';
9
+
10
+ const AUTHORS_QUERY = {
11
+ who: 'authors',
12
+ per_page: -1,
13
+ _fields: 'id,name',
14
+ context: 'view',
15
+ };
16
+
17
+ function UserControl( { value, onChange } ) {
18
+ const [ filteredAuthorsList, setFilteredAuthorsList ] = useState();
19
+ const authorsList = useSelect( ( select ) => {
20
+ const { getUsers } = select( coreStore );
21
+ return getUsers( AUTHORS_QUERY );
22
+ }, [] );
23
+ if ( ! authorsList ) {
24
+ return null;
25
+ }
26
+
27
+ const options = authorsList.map( ( author ) => {
28
+ return {
29
+ label: author.name,
30
+ value: author.id,
31
+ };
32
+ } );
33
+
34
+ return (
35
+ <ComboboxControl
36
+ label={ __( 'User' ) }
37
+ help={ __(
38
+ 'Select the avatar user to display, if it is blank it will use the post/page author.'
39
+ ) }
40
+ value={ value }
41
+ onChange={ onChange }
42
+ options={ filteredAuthorsList || options }
43
+ onFilterValueChange={ ( inputValue ) =>
44
+ setFilteredAuthorsList(
45
+ options.filter( ( option ) =>
46
+ option.label
47
+ .toLowerCase()
48
+ .startsWith( inputValue.toLowerCase() )
49
+ )
50
+ )
51
+ }
52
+ />
53
+ );
54
+ }
55
+
56
+ export default UserControl;
@@ -39,6 +39,7 @@
39
39
  "__experimentalDefaultControls": {
40
40
  "padding": true
41
41
  }
42
- }
42
+ },
43
+ "__experimentalLayout": true
43
44
  }
44
45
  }
@@ -20,6 +20,7 @@
20
20
  "usesContext": [ "commentId" ],
21
21
  "supports": {
22
22
  "html": false,
23
+ "inserter": false,
23
24
  "__experimentalBorder": {
24
25
  "radius": true,
25
26
  "width": true,
@@ -2,13 +2,16 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useEntityProp } from '@wordpress/core-data';
5
- import { __experimentalGetSettings, dateI18n } from '@wordpress/date';
6
- import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
7
5
  import {
8
- PanelBody,
9
- CustomSelectControl,
10
- ToggleControl,
11
- } from '@wordpress/components';
6
+ dateI18n,
7
+ __experimentalGetSettings as getDateSettings,
8
+ } from '@wordpress/date';
9
+ import {
10
+ InspectorControls,
11
+ useBlockProps,
12
+ __experimentalDateFormatPicker as DateFormatPicker,
13
+ } from '@wordpress/block-editor';
14
+ import { PanelBody, ToggleControl } from '@wordpress/components';
12
15
  import { __, _x } from '@wordpress/i18n';
13
16
 
14
17
  /**
@@ -31,35 +34,22 @@ export default function Edit( {
31
34
  } ) {
32
35
  const blockProps = useBlockProps();
33
36
  const [ date ] = useEntityProp( 'root', 'comment', 'date', commentId );
34
- const [ siteDateFormat ] = useEntityProp( 'root', 'site', 'date_format' );
35
-
36
- const settings = __experimentalGetSettings();
37
- const formatOptions = Object.values( settings.formats ).map(
38
- ( formatOption ) => ( {
39
- key: formatOption,
40
- name: dateI18n( formatOption, date || new Date() ),
41
- } )
37
+ const [ siteFormat = getDateSettings().formats.date ] = useEntityProp(
38
+ 'root',
39
+ 'site',
40
+ 'date_format'
42
41
  );
43
- const resolvedFormat = format || siteDateFormat || settings.formats.date;
44
42
 
45
43
  const inspectorControls = (
46
44
  <InspectorControls>
47
- <PanelBody title={ __( 'Format settings' ) }>
48
- <CustomSelectControl
49
- hideLabelFromVision
50
- label={ __( 'Date Format' ) }
51
- options={ formatOptions }
52
- onChange={ ( { selectedItem } ) =>
53
- setAttributes( {
54
- format: selectedItem.key,
55
- } )
45
+ <PanelBody title={ __( 'Settings' ) }>
46
+ <DateFormatPicker
47
+ format={ format }
48
+ defaultFormat={ siteFormat }
49
+ onChange={ ( nextFormat ) =>
50
+ setAttributes( { format: nextFormat } )
56
51
  }
57
- value={ formatOptions.find(
58
- ( option ) => option.key === resolvedFormat
59
- ) }
60
52
  />
61
- </PanelBody>
62
- <PanelBody title={ __( 'Link settings' ) }>
63
53
  <ToggleControl
64
54
  label={ __( 'Link to comment' ) }
65
55
  onChange={ () => setAttributes( { isLink: ! isLink } ) }
@@ -82,7 +72,7 @@ export default function Edit( {
82
72
 
83
73
  let commentDate = (
84
74
  <time dateTime={ dateI18n( 'c', date ) }>
85
- { dateI18n( resolvedFormat, date ) }
75
+ { dateI18n( format || siteFormat, date ) }
86
76
  </time>
87
77
  );
88
78