@wordpress/block-library 8.22.0 → 8.24.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 (266) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/block/edit.js +11 -13
  3. package/build/block/edit.js.map +1 -1
  4. package/build/block/edit.native.js +3 -4
  5. package/build/block/edit.native.js.map +1 -1
  6. package/build/button/edit.js +61 -9
  7. package/build/button/edit.js.map +1 -1
  8. package/build/code/transforms.js +20 -7
  9. package/build/code/transforms.js.map +1 -1
  10. package/build/column/edit.js +1 -1
  11. package/build/column/edit.js.map +1 -1
  12. package/build/column/edit.native.js +1 -1
  13. package/build/column/edit.native.js.map +1 -1
  14. package/build/comments/edit/comments-inspector-controls.js +1 -0
  15. package/build/comments/edit/comments-inspector-controls.js.map +1 -1
  16. package/build/cover/edit/index.js +2 -1
  17. package/build/cover/edit/index.js.map +1 -1
  18. package/build/cover/edit/inspector-controls.js +1 -0
  19. package/build/cover/edit/inspector-controls.js.map +1 -1
  20. package/build/details/edit.js +1 -2
  21. package/build/details/edit.js.map +1 -1
  22. package/build/file/edit.js +8 -9
  23. package/build/file/edit.js.map +1 -1
  24. package/build/file/view.js +4 -6
  25. package/build/file/view.js.map +1 -1
  26. package/build/form/index.js +1 -1
  27. package/build/form/index.js.map +1 -1
  28. package/build/form-submit-button/edit.js +2 -1
  29. package/build/form-submit-button/edit.js.map +1 -1
  30. package/build/gallery/gap-styles.js +12 -7
  31. package/build/gallery/gap-styles.js.map +1 -1
  32. package/build/group/edit.js +4 -7
  33. package/build/group/edit.js.map +1 -1
  34. package/build/html/transforms.js +7 -2
  35. package/build/html/transforms.js.map +1 -1
  36. package/build/image/deprecated.js +8 -0
  37. package/build/image/deprecated.js.map +1 -1
  38. package/build/image/edit.js +17 -18
  39. package/build/image/edit.js.map +1 -1
  40. package/build/image/edit.native.js +22 -15
  41. package/build/image/edit.native.js.map +1 -1
  42. package/build/image/image.js +35 -27
  43. package/build/image/image.js.map +1 -1
  44. package/build/image/index.js +2 -3
  45. package/build/image/index.js.map +1 -1
  46. package/build/image/view.js +234 -266
  47. package/build/image/view.js.map +1 -1
  48. package/build/missing/index.js +1 -1
  49. package/build/navigation/edit/overlay-menu-preview.js +1 -1
  50. package/build/navigation/edit/overlay-menu-preview.js.map +1 -1
  51. package/build/navigation/use-template-part-area-label.js +2 -1
  52. package/build/navigation/use-template-part-area-label.js.map +1 -1
  53. package/build/navigation/view.js +153 -176
  54. package/build/navigation/view.js.map +1 -1
  55. package/build/navigation-link/edit.js +1 -1
  56. package/build/navigation-link/edit.js.map +1 -1
  57. package/build/navigation-link/index.js +2 -1
  58. package/build/navigation-link/index.js.map +1 -1
  59. package/build/pattern/edit.js +2 -4
  60. package/build/pattern/edit.js.map +1 -1
  61. package/build/post-author/edit.js +0 -1
  62. package/build/post-author/edit.js.map +1 -1
  63. package/build/post-featured-image/edit.js +21 -6
  64. package/build/post-featured-image/edit.js.map +1 -1
  65. package/build/post-template/edit.js +2 -8
  66. package/build/post-template/edit.js.map +1 -1
  67. package/build/post-template/index.js +1 -1
  68. package/build/post-terms/edit.js +0 -2
  69. package/build/post-terms/edit.js.map +1 -1
  70. package/build/preformatted/transforms.js +1 -4
  71. package/build/preformatted/transforms.js.map +1 -1
  72. package/build/query/edit/query-content.js +1 -0
  73. package/build/query/edit/query-content.js.map +1 -1
  74. package/build/query/view.js +52 -60
  75. package/build/query/view.js.map +1 -1
  76. package/build/quote/index.js +6 -0
  77. package/build/quote/index.js.map +1 -1
  78. package/build/search/view.js +66 -74
  79. package/build/search/view.js.map +1 -1
  80. package/build/template-part/edit/advanced-controls.js +1 -0
  81. package/build/template-part/edit/advanced-controls.js.map +1 -1
  82. package/build/template-part/edit/index.js +3 -7
  83. package/build/template-part/edit/index.js.map +1 -1
  84. package/build/template-part/index.js +6 -2
  85. package/build/template-part/index.js.map +1 -1
  86. package/build/template-part/variations.js +5 -1
  87. package/build/template-part/variations.js.map +1 -1
  88. package/build/utils/remove-anchor-tag.js +17 -0
  89. package/build/utils/remove-anchor-tag.js.map +1 -0
  90. package/build-module/block/edit.js +11 -13
  91. package/build-module/block/edit.js.map +1 -1
  92. package/build-module/block/edit.native.js +3 -4
  93. package/build-module/block/edit.native.js.map +1 -1
  94. package/build-module/button/edit.js +65 -13
  95. package/build-module/button/edit.js.map +1 -1
  96. package/build-module/code/transforms.js +20 -7
  97. package/build-module/code/transforms.js.map +1 -1
  98. package/build-module/column/edit.js +1 -1
  99. package/build-module/column/edit.js.map +1 -1
  100. package/build-module/column/edit.native.js +1 -1
  101. package/build-module/column/edit.native.js.map +1 -1
  102. package/build-module/comments/edit/comments-inspector-controls.js +1 -0
  103. package/build-module/comments/edit/comments-inspector-controls.js.map +1 -1
  104. package/build-module/cover/edit/index.js +2 -1
  105. package/build-module/cover/edit/index.js.map +1 -1
  106. package/build-module/cover/edit/inspector-controls.js +1 -0
  107. package/build-module/cover/edit/inspector-controls.js.map +1 -1
  108. package/build-module/details/edit.js +1 -2
  109. package/build-module/details/edit.js.map +1 -1
  110. package/build-module/file/edit.js +8 -9
  111. package/build-module/file/edit.js.map +1 -1
  112. package/build-module/file/view.js +5 -7
  113. package/build-module/file/view.js.map +1 -1
  114. package/build-module/form/index.js +1 -1
  115. package/build-module/form/index.js.map +1 -1
  116. package/build-module/form-submit-button/edit.js +2 -1
  117. package/build-module/form-submit-button/edit.js.map +1 -1
  118. package/build-module/gallery/gap-styles.js +13 -8
  119. package/build-module/gallery/gap-styles.js.map +1 -1
  120. package/build-module/group/edit.js +4 -7
  121. package/build-module/group/edit.js.map +1 -1
  122. package/build-module/html/transforms.js +7 -2
  123. package/build-module/html/transforms.js.map +1 -1
  124. package/build-module/image/deprecated.js +8 -0
  125. package/build-module/image/deprecated.js.map +1 -1
  126. package/build-module/image/edit.js +18 -19
  127. package/build-module/image/edit.js.map +1 -1
  128. package/build-module/image/edit.native.js +23 -16
  129. package/build-module/image/edit.native.js.map +1 -1
  130. package/build-module/image/image.js +36 -28
  131. package/build-module/image/image.js.map +1 -1
  132. package/build-module/image/index.js +2 -3
  133. package/build-module/image/index.js.map +1 -1
  134. package/build-module/image/view.js +235 -267
  135. package/build-module/image/view.js.map +1 -1
  136. package/build-module/missing/index.js +1 -1
  137. package/build-module/navigation/edit/overlay-menu-preview.js +1 -1
  138. package/build-module/navigation/edit/overlay-menu-preview.js.map +1 -1
  139. package/build-module/navigation/use-template-part-area-label.js +2 -1
  140. package/build-module/navigation/use-template-part-area-label.js.map +1 -1
  141. package/build-module/navigation/view.js +154 -177
  142. package/build-module/navigation/view.js.map +1 -1
  143. package/build-module/navigation-link/edit.js +2 -2
  144. package/build-module/navigation-link/edit.js.map +1 -1
  145. package/build-module/navigation-link/index.js +2 -1
  146. package/build-module/navigation-link/index.js.map +1 -1
  147. package/build-module/pattern/edit.js +2 -4
  148. package/build-module/pattern/edit.js.map +1 -1
  149. package/build-module/post-author/edit.js +0 -1
  150. package/build-module/post-author/edit.js.map +1 -1
  151. package/build-module/post-featured-image/edit.js +21 -6
  152. package/build-module/post-featured-image/edit.js.map +1 -1
  153. package/build-module/post-template/edit.js +2 -8
  154. package/build-module/post-template/edit.js.map +1 -1
  155. package/build-module/post-template/index.js +1 -1
  156. package/build-module/post-terms/edit.js +0 -2
  157. package/build-module/post-terms/edit.js.map +1 -1
  158. package/build-module/preformatted/transforms.js +1 -4
  159. package/build-module/preformatted/transforms.js.map +1 -1
  160. package/build-module/query/edit/query-content.js +1 -0
  161. package/build-module/query/edit/query-content.js.map +1 -1
  162. package/build-module/query/view.js +53 -61
  163. package/build-module/query/view.js.map +1 -1
  164. package/build-module/quote/index.js +6 -0
  165. package/build-module/quote/index.js.map +1 -1
  166. package/build-module/search/view.js +67 -75
  167. package/build-module/search/view.js.map +1 -1
  168. package/build-module/template-part/edit/advanced-controls.js +1 -0
  169. package/build-module/template-part/edit/advanced-controls.js.map +1 -1
  170. package/build-module/template-part/edit/index.js +5 -9
  171. package/build-module/template-part/edit/index.js.map +1 -1
  172. package/build-module/template-part/index.js +6 -2
  173. package/build-module/template-part/index.js.map +1 -1
  174. package/build-module/template-part/variations.js +5 -1
  175. package/build-module/template-part/variations.js.map +1 -1
  176. package/build-module/utils/remove-anchor-tag.js +11 -0
  177. package/build-module/utils/remove-anchor-tag.js.map +1 -0
  178. package/build-style/cover/style-rtl.css +14 -14
  179. package/build-style/cover/style.css +14 -14
  180. package/build-style/editor-rtl.css +15 -6
  181. package/build-style/editor.css +15 -6
  182. package/build-style/gallery/style-rtl.css +28 -0
  183. package/build-style/gallery/style.css +28 -0
  184. package/build-style/image/style-rtl.css +19 -13
  185. package/build-style/image/style.css +19 -13
  186. package/build-style/post-featured-image/editor-rtl.css +9 -0
  187. package/build-style/post-featured-image/editor.css +9 -0
  188. package/build-style/quote/style-rtl.css +3 -0
  189. package/build-style/quote/style.css +3 -0
  190. package/build-style/read-more/style-rtl.css +2 -2
  191. package/build-style/read-more/style.css +2 -2
  192. package/build-style/style-rtl.css +66 -29
  193. package/build-style/style.css +66 -29
  194. package/package.json +32 -32
  195. package/src/block/edit.js +20 -20
  196. package/src/block/edit.native.js +5 -13
  197. package/src/button/edit.js +76 -10
  198. package/src/buttons/test/__snapshots__/edit.native.js.snap +0 -6
  199. package/src/buttons/test/edit.native.js +0 -27
  200. package/src/code/transforms.js +14 -8
  201. package/src/column/edit.js +1 -1
  202. package/src/column/edit.native.js +1 -1
  203. package/src/comments/edit/comments-inspector-controls.js +1 -0
  204. package/src/cover/edit/index.js +1 -0
  205. package/src/cover/edit/inspector-controls.js +1 -0
  206. package/src/cover/style.scss +1 -1
  207. package/src/cover/test/edit.js +1 -1
  208. package/src/details/edit.js +0 -1
  209. package/src/editor.scss +6 -6
  210. package/src/file/edit.js +11 -10
  211. package/src/file/index.php +30 -11
  212. package/src/file/view.js +5 -7
  213. package/src/form/index.js +1 -1
  214. package/src/form-submit-button/edit.js +1 -0
  215. package/src/gallery/gap-styles.js +10 -9
  216. package/src/gallery/style.scss +1 -0
  217. package/src/group/edit.js +4 -11
  218. package/src/heading/test/__snapshots__/index.native.js.snap +6 -0
  219. package/src/heading/test/index.native.js +40 -0
  220. package/src/html/transforms.js +5 -2
  221. package/src/image/block.json +2 -3
  222. package/src/image/deprecated.js +8 -0
  223. package/src/image/edit.js +16 -21
  224. package/src/image/edit.native.js +17 -18
  225. package/src/image/image.js +48 -51
  226. package/src/image/index.php +57 -49
  227. package/src/image/style.scss +18 -13
  228. package/src/image/view.js +281 -324
  229. package/src/missing/block.json +1 -1
  230. package/src/navigation/edit/overlay-menu-preview.js +1 -1
  231. package/src/navigation/index.php +46 -402
  232. package/src/navigation/use-template-part-area-label.js +4 -2
  233. package/src/navigation/view.js +159 -192
  234. package/src/navigation-link/block.json +2 -1
  235. package/src/navigation-link/edit.js +2 -2
  236. package/src/navigation-link/index.php +57 -0
  237. package/src/paragraph/test/__snapshots__/transforms.native.js.snap +6 -0
  238. package/src/paragraph/test/edit.native.js +37 -1
  239. package/src/paragraph/test/transforms.native.js +1 -0
  240. package/src/pattern/edit.js +7 -4
  241. package/src/pattern/index.php +6 -1
  242. package/src/post-author/edit.js +0 -1
  243. package/src/post-featured-image/edit.js +38 -5
  244. package/src/post-featured-image/editor.scss +19 -0
  245. package/src/post-template/block.json +0 -1
  246. package/src/post-template/edit.js +1 -5
  247. package/src/post-terms/edit.js +0 -2
  248. package/src/preformatted/transforms.js +1 -4
  249. package/src/query/edit/query-content.js +1 -0
  250. package/src/query/index.php +42 -24
  251. package/src/query/view.js +58 -65
  252. package/src/query-pagination-next/index.php +3 -3
  253. package/src/query-pagination-numbers/index.php +1 -1
  254. package/src/query-pagination-previous/index.php +3 -3
  255. package/src/quote/block.json +6 -0
  256. package/src/quote/style.scss +4 -0
  257. package/src/read-more/style.scss +1 -1
  258. package/src/search/index.php +40 -40
  259. package/src/search/view.js +58 -63
  260. package/src/template-part/edit/advanced-controls.js +1 -0
  261. package/src/template-part/edit/index.js +7 -14
  262. package/src/template-part/index.js +4 -3
  263. package/src/template-part/index.php +4 -4
  264. package/src/template-part/variations.js +4 -2
  265. package/src/utils/remove-anchor-tag.js +10 -0
  266. package/tsconfig.json +1 -0
package/src/image/view.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { store } from '@wordpress/interactivity';
4
+ import { store, getContext, getElement } from '@wordpress/interactivity';
5
5
 
6
6
  const focusableSelectors = [
7
7
  'a[href]',
@@ -17,7 +17,7 @@ const focusableSelectors = [
17
17
  '[tabindex]:not([tabindex^="-"])',
18
18
  ];
19
19
 
20
- /*
20
+ /**
21
21
  * Stores a context-bound scroll handler.
22
22
  *
23
23
  * This callback could be defined inline inside of the store
@@ -32,7 +32,7 @@ const focusableSelectors = [
32
32
  */
33
33
  let scrollCallback;
34
34
 
35
- /*
35
+ /**
36
36
  * Tracks whether user is touching screen; used to
37
37
  * differentiate behavior for touch and mouse input.
38
38
  *
@@ -40,7 +40,7 @@ let scrollCallback;
40
40
  */
41
41
  let isTouching = false;
42
42
 
43
- /*
43
+ /**
44
44
  * Tracks the last time the screen was touched; used to
45
45
  * differentiate behavior for touch and mouse input.
46
46
  *
@@ -48,7 +48,7 @@ let isTouching = false;
48
48
  */
49
49
  let lastTouchTime = 0;
50
50
 
51
- /*
51
+ /**
52
52
  * Lightbox page-scroll handler: prevents scrolling.
53
53
  *
54
54
  * This handler is added to prevent scrolling behaviors that
@@ -64,338 +64,296 @@ let lastTouchTime = 0;
64
64
  * instead to not rely on JavaScript, but this seems to be the best approach
65
65
  * for now that provides the best visual experience.
66
66
  *
67
- * @param {Object} context Interactivity page context?
67
+ * @param {Object} ctx Context object with the `core/image` namespace.
68
68
  */
69
- function handleScroll( context ) {
69
+ function handleScroll( ctx ) {
70
70
  // We can't override the scroll behavior on mobile devices
71
71
  // because doing so breaks the pinch to zoom functionality, and we
72
72
  // want to allow users to zoom in further on the high-res image.
73
73
  if ( ! isTouching && Date.now() - lastTouchTime > 450 ) {
74
74
  // We are unable to use event.preventDefault() to prevent scrolling
75
75
  // because the scroll event can't be canceled, so we reset the position instead.
76
- window.scrollTo(
77
- context.core.image.scrollLeftReset,
78
- context.core.image.scrollTopReset
79
- );
76
+ window.scrollTo( ctx.scrollLeftReset, ctx.scrollTopReset );
80
77
  }
81
78
  }
82
79
 
83
- store(
84
- {
85
- state: {
86
- core: {
87
- image: {
88
- windowWidth: window.innerWidth,
89
- windowHeight: window.innerHeight,
90
- },
91
- },
80
+ const { state, actions, callbacks } = store( 'core/image', {
81
+ state: {
82
+ windowWidth: window.innerWidth,
83
+ windowHeight: window.innerHeight,
84
+ get roleAttribute() {
85
+ const ctx = getContext();
86
+ return ctx.lightboxEnabled ? 'dialog' : null;
92
87
  },
93
- actions: {
94
- core: {
95
- image: {
96
- showLightbox: ( { context, event } ) => {
97
- // We can't initialize the lightbox until the reference
98
- // image is loaded, otherwise the UX is broken.
99
- if ( ! context.core.image.imageLoaded ) {
100
- return;
101
- }
102
- context.core.image.initialized = true;
103
- context.core.image.lastFocusedElement =
104
- window.document.activeElement;
105
- context.core.image.scrollDelta = 0;
106
- context.core.image.pointerType = event.pointerType;
107
-
108
- context.core.image.lightboxEnabled = true;
109
- setStyles( context, context.core.image.imageRef );
110
-
111
- context.core.image.scrollTopReset =
112
- window.pageYOffset ||
113
- document.documentElement.scrollTop;
114
-
115
- // In most cases, this value will be 0, but this is included
116
- // in case a user has created a page with horizontal scrolling.
117
- context.core.image.scrollLeftReset =
118
- window.pageXOffset ||
119
- document.documentElement.scrollLeft;
120
-
121
- // We define and bind the scroll callback here so
122
- // that we can pass the context and as an argument.
123
- // We may be able to change this in the future if we
124
- // define the scroll callback in the store instead, but
125
- // this approach seems to tbe clearest for now.
126
- scrollCallback = handleScroll.bind( null, context );
127
-
128
- // We need to add a scroll event listener to the window
129
- // here because we are unable to otherwise access it via
130
- // the Interactivity API directives. If we add a native way
131
- // to access the window, we can remove this.
132
- window.addEventListener(
133
- 'scroll',
134
- scrollCallback,
135
- false
136
- );
137
- },
138
- hideLightbox: async ( { context } ) => {
139
- context.core.image.hideAnimationEnabled = true;
140
- if ( context.core.image.lightboxEnabled ) {
141
- // We want to wait until the close animation is completed
142
- // before allowing a user to scroll again. The duration of this
143
- // animation is defined in the styles.scss and depends on if the
144
- // animation is 'zoom' or 'fade', but in any case we should wait
145
- // a few milliseconds longer than the duration, otherwise a user
146
- // may scroll too soon and cause the animation to look sloppy.
147
- setTimeout( function () {
148
- window.removeEventListener(
149
- 'scroll',
150
- scrollCallback
151
- );
152
- // If we don't delay before changing the focus,
153
- // the focus ring will appear on Firefox before
154
- // the image has finished animating, which looks broken.
155
- context.core.image.lightboxTriggerRef.focus( {
156
- preventScroll: true,
157
- } );
158
- }, 450 );
159
-
160
- context.core.image.lightboxEnabled = false;
161
- }
162
- },
163
- handleKeydown: ( { context, actions, event } ) => {
164
- if ( context.core.image.lightboxEnabled ) {
165
- if ( event.key === 'Tab' || event.keyCode === 9 ) {
166
- // If shift + tab it change the direction
167
- if (
168
- event.shiftKey &&
169
- window.document.activeElement ===
170
- context.core.image.firstFocusableElement
171
- ) {
172
- event.preventDefault();
173
- context.core.image.lastFocusableElement.focus();
174
- } else if (
175
- ! event.shiftKey &&
176
- window.document.activeElement ===
177
- context.core.image.lastFocusableElement
178
- ) {
179
- event.preventDefault();
180
- context.core.image.firstFocusableElement.focus();
181
- }
182
- }
183
-
184
- if (
185
- event.key === 'Escape' ||
186
- event.keyCode === 27
187
- ) {
188
- actions.core.image.hideLightbox( {
189
- context,
190
- event,
191
- } );
192
- }
193
- }
194
- },
195
- // This is fired just by lazily loaded
196
- // images on the page, not all images.
197
- handleLoad: ( { context, effects, ref } ) => {
198
- context.core.image.imageLoaded = true;
199
- context.core.image.imageCurrentSrc = ref.currentSrc;
200
- effects.core.image.setButtonStyles( {
201
- context,
202
- ref,
203
- } );
204
- },
205
- handleTouchStart: () => {
206
- isTouching = true;
207
- },
208
- handleTouchMove: ( { context, event } ) => {
209
- // On mobile devices, we want to prevent triggering the
210
- // scroll event because otherwise the page jumps around as
211
- // we reset the scroll position. This also means that closing
212
- // the lightbox requires that a user perform a simple tap. This
213
- // may be changed in the future if we find a better alternative
214
- // to override or reset the scroll position during swipe actions.
215
- if ( context.core.image.lightboxEnabled ) {
216
- event.preventDefault();
217
- }
218
- },
219
- handleTouchEnd: () => {
220
- // We need to wait a few milliseconds before resetting
221
- // to ensure that pinch to zoom works consistently
222
- // on mobile devices when the lightbox is open.
223
- lastTouchTime = Date.now();
224
- isTouching = false;
225
- },
226
- },
227
- },
88
+ get ariaModal() {
89
+ const ctx = getContext();
90
+ return ctx.lightboxEnabled ? 'true' : null;
228
91
  },
229
- selectors: {
230
- core: {
231
- image: {
232
- roleAttribute: ( { context } ) => {
233
- return context.core.image.lightboxEnabled
234
- ? 'dialog'
235
- : null;
236
- },
237
- ariaModal: ( { context } ) => {
238
- return context.core.image.lightboxEnabled
239
- ? 'true'
240
- : null;
241
- },
242
- dialogLabel: ( { context } ) => {
243
- return context.core.image.lightboxEnabled
244
- ? context.core.image.dialogLabel
245
- : null;
246
- },
247
- lightboxObjectFit: ( { context } ) => {
248
- if ( context.core.image.initialized ) {
249
- return 'cover';
250
- }
251
- },
252
- enlargedImgSrc: ( { context } ) => {
253
- return context.core.image.initialized
254
- ? context.core.image.imageUploadedSrc
255
- : 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
256
- },
257
- },
258
- },
92
+ get dialogLabel() {
93
+ const ctx = getContext();
94
+ return ctx.lightboxEnabled ? ctx.dialogLabel : null;
259
95
  },
260
- effects: {
261
- core: {
262
- image: {
263
- initOriginImage: ( { context, ref } ) => {
264
- context.core.image.imageRef = ref;
265
- context.core.image.lightboxTriggerRef =
266
- ref.parentElement.querySelector(
267
- '.lightbox-trigger'
268
- );
269
- if ( ref.complete ) {
270
- context.core.image.imageLoaded = true;
271
- context.core.image.imageCurrentSrc = ref.currentSrc;
272
- }
273
- },
274
- initLightbox: async ( { context, ref } ) => {
275
- if ( context.core.image.lightboxEnabled ) {
276
- const focusableElements =
277
- ref.querySelectorAll( focusableSelectors );
278
- context.core.image.firstFocusableElement =
279
- focusableElements[ 0 ];
280
- context.core.image.lastFocusableElement =
281
- focusableElements[
282
- focusableElements.length - 1
283
- ];
284
-
285
- // Move focus to the dialog when opening it.
286
- ref.focus();
287
- }
288
- },
289
- setButtonStyles: ( { context, ref } ) => {
290
- const {
291
- naturalWidth,
292
- naturalHeight,
293
- offsetWidth,
294
- offsetHeight,
295
- } = ref;
296
-
297
- // If the image isn't loaded yet, we can't
298
- // calculate where the button should be.
299
- if ( naturalWidth === 0 || naturalHeight === 0 ) {
300
- return;
301
- }
302
-
303
- const figure = ref.parentElement;
304
- const figureWidth = ref.parentElement.clientWidth;
305
-
306
- // We need special handling for the height because
307
- // a caption will cause the figure to be taller than
308
- // the image, which means we need to account for that
309
- // when calculating the placement of the button in the
310
- // top right corner of the image.
311
- let figureHeight = ref.parentElement.clientHeight;
312
- const caption = figure.querySelector( 'figcaption' );
313
- if ( caption ) {
314
- const captionComputedStyle =
315
- window.getComputedStyle( caption );
316
- figureHeight =
317
- figureHeight -
318
- caption.offsetHeight -
319
- parseFloat( captionComputedStyle.marginTop ) -
320
- parseFloat( captionComputedStyle.marginBottom );
321
- }
322
-
323
- const buttonOffsetTop = figureHeight - offsetHeight;
324
- const buttonOffsetRight = figureWidth - offsetWidth;
325
-
326
- // In the case of an image with object-fit: contain, the
327
- // size of the <img> element can be larger than the image itself,
328
- // so we need to calculate where to place the button.
329
- if ( context.core.image.scaleAttr === 'contain' ) {
330
- // Natural ratio of the image.
331
- const naturalRatio = naturalWidth / naturalHeight;
332
- // Offset ratio of the image.
333
- const offsetRatio = offsetWidth / offsetHeight;
334
-
335
- if ( naturalRatio >= offsetRatio ) {
336
- // If it reaches the width first, keep
337
- // the width and compute the height.
338
- const referenceHeight =
339
- offsetWidth / naturalRatio;
340
- context.core.image.imageButtonTop =
341
- ( offsetHeight - referenceHeight ) / 2 +
342
- buttonOffsetTop +
343
- 10;
344
- context.core.image.imageButtonRight =
345
- buttonOffsetRight + 10;
346
- } else {
347
- // If it reaches the height first, keep
348
- // the height and compute the width.
349
- const referenceWidth =
350
- offsetHeight * naturalRatio;
351
- context.core.image.imageButtonTop =
352
- buttonOffsetTop + 10;
353
- context.core.image.imageButtonRight =
354
- ( offsetWidth - referenceWidth ) / 2 +
355
- buttonOffsetRight +
356
- 10;
357
- }
358
- } else {
359
- context.core.image.imageButtonTop =
360
- buttonOffsetTop + 10;
361
- context.core.image.imageButtonRight =
362
- buttonOffsetRight + 10;
363
- }
364
- },
365
- setStylesOnResize: ( { state, context, ref } ) => {
366
- if (
367
- context.core.image.lightboxEnabled &&
368
- ( state.core.image.windowWidth ||
369
- state.core.image.windowHeight )
370
- ) {
371
- setStyles( context, ref );
372
- }
373
- },
374
- },
375
- },
96
+ get lightboxObjectFit() {
97
+ const ctx = getContext();
98
+ if ( ctx.initialized ) {
99
+ return 'cover';
100
+ }
101
+ },
102
+ get enlargedImgSrc() {
103
+ const ctx = getContext();
104
+ return ctx.initialized
105
+ ? ctx.imageUploadedSrc
106
+ : 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
376
107
  },
377
108
  },
378
- {
379
- afterLoad: ( { state } ) => {
380
- window.addEventListener(
381
- 'resize',
382
- debounce( () => {
383
- state.core.image.windowWidth = window.innerWidth;
384
- state.core.image.windowHeight = window.innerHeight;
385
- } )
386
- );
109
+ actions: {
110
+ showLightbox( event ) {
111
+ const ctx = getContext();
112
+ // We can't initialize the lightbox until the reference
113
+ // image is loaded, otherwise the UX is broken.
114
+ if ( ! ctx.imageLoaded ) {
115
+ return;
116
+ }
117
+ ctx.initialized = true;
118
+ ctx.lastFocusedElement = window.document.activeElement;
119
+ ctx.scrollDelta = 0;
120
+ ctx.pointerType = event.pointerType;
121
+
122
+ ctx.lightboxEnabled = true;
123
+ setStyles( ctx, ctx.imageRef );
124
+
125
+ ctx.scrollTopReset =
126
+ window.pageYOffset || document.documentElement.scrollTop;
127
+
128
+ // In most cases, this value will be 0, but this is included
129
+ // in case a user has created a page with horizontal scrolling.
130
+ ctx.scrollLeftReset =
131
+ window.pageXOffset || document.documentElement.scrollLeft;
132
+
133
+ // We define and bind the scroll callback here so
134
+ // that we can pass the context and as an argument.
135
+ // We may be able to change this in the future if we
136
+ // define the scroll callback in the store instead, but
137
+ // this approach seems to tbe clearest for now.
138
+ scrollCallback = handleScroll.bind( null, ctx );
139
+
140
+ // We need to add a scroll event listener to the window
141
+ // here because we are unable to otherwise access it via
142
+ // the Interactivity API directives. If we add a native way
143
+ // to access the window, we can remove this.
144
+ window.addEventListener( 'scroll', scrollCallback, false );
387
145
  },
388
- }
146
+ hideLightbox() {
147
+ const ctx = getContext();
148
+ ctx.hideAnimationEnabled = true;
149
+ if ( ctx.lightboxEnabled ) {
150
+ // We want to wait until the close animation is completed
151
+ // before allowing a user to scroll again. The duration of this
152
+ // animation is defined in the styles.scss and depends on if the
153
+ // animation is 'zoom' or 'fade', but in any case we should wait
154
+ // a few milliseconds longer than the duration, otherwise a user
155
+ // may scroll too soon and cause the animation to look sloppy.
156
+ setTimeout( function () {
157
+ window.removeEventListener( 'scroll', scrollCallback );
158
+ // If we don't delay before changing the focus,
159
+ // the focus ring will appear on Firefox before
160
+ // the image has finished animating, which looks broken.
161
+ ctx.lightboxTriggerRef.focus( {
162
+ preventScroll: true,
163
+ } );
164
+ }, 450 );
165
+
166
+ ctx.lightboxEnabled = false;
167
+ }
168
+ },
169
+ handleKeydown( event ) {
170
+ const ctx = getContext();
171
+ if ( ctx.lightboxEnabled ) {
172
+ if ( event.key === 'Tab' || event.keyCode === 9 ) {
173
+ // If shift + tab it change the direction
174
+ if (
175
+ event.shiftKey &&
176
+ window.document.activeElement ===
177
+ ctx.firstFocusableElement
178
+ ) {
179
+ event.preventDefault();
180
+ ctx.lastFocusableElement.focus();
181
+ } else if (
182
+ ! event.shiftKey &&
183
+ window.document.activeElement ===
184
+ ctx.lastFocusableElement
185
+ ) {
186
+ event.preventDefault();
187
+ ctx.firstFocusableElement.focus();
188
+ }
189
+ }
190
+
191
+ if ( event.key === 'Escape' || event.keyCode === 27 ) {
192
+ actions.hideLightbox( event );
193
+ }
194
+ }
195
+ },
196
+ // This is fired just by lazily loaded
197
+ // images on the page, not all images.
198
+ handleLoad() {
199
+ const ctx = getContext();
200
+ const { ref } = getElement();
201
+ ctx.imageLoaded = true;
202
+ ctx.imageCurrentSrc = ref.currentSrc;
203
+ callbacks.setButtonStyles();
204
+ },
205
+ handleTouchStart() {
206
+ isTouching = true;
207
+ },
208
+ handleTouchMove( event ) {
209
+ const ctx = getContext();
210
+ // On mobile devices, we want to prevent triggering the
211
+ // scroll event because otherwise the page jumps around as
212
+ // we reset the scroll position. This also means that closing
213
+ // the lightbox requires that a user perform a simple tap. This
214
+ // may be changed in the future if we find a better alternative
215
+ // to override or reset the scroll position during swipe actions.
216
+ if ( ctx.lightboxEnabled ) {
217
+ event.preventDefault();
218
+ }
219
+ },
220
+ handleTouchEnd() {
221
+ // We need to wait a few milliseconds before resetting
222
+ // to ensure that pinch to zoom works consistently
223
+ // on mobile devices when the lightbox is open.
224
+ lastTouchTime = Date.now();
225
+ isTouching = false;
226
+ },
227
+ },
228
+ callbacks: {
229
+ initOriginImage() {
230
+ const ctx = getContext();
231
+ const { ref } = getElement();
232
+ ctx.imageRef = ref;
233
+ ctx.lightboxTriggerRef =
234
+ ref.parentElement.querySelector( '.lightbox-trigger' );
235
+ if ( ref.complete ) {
236
+ ctx.imageLoaded = true;
237
+ ctx.imageCurrentSrc = ref.currentSrc;
238
+ }
239
+ },
240
+ initLightbox() {
241
+ const ctx = getContext();
242
+ const { ref } = getElement();
243
+ if ( ctx.lightboxEnabled ) {
244
+ const focusableElements =
245
+ ref.querySelectorAll( focusableSelectors );
246
+ ctx.firstFocusableElement = focusableElements[ 0 ];
247
+ ctx.lastFocusableElement =
248
+ focusableElements[ focusableElements.length - 1 ];
249
+
250
+ // Move focus to the dialog when opening it.
251
+ ref.focus();
252
+ }
253
+ },
254
+ setButtonStyles() {
255
+ const { ref } = getElement();
256
+ const { naturalWidth, naturalHeight, offsetWidth, offsetHeight } =
257
+ ref;
258
+
259
+ // If the image isn't loaded yet, we can't
260
+ // calculate where the button should be.
261
+ if ( naturalWidth === 0 || naturalHeight === 0 ) {
262
+ return;
263
+ }
264
+
265
+ const figure = ref.parentElement;
266
+ const figureWidth = ref.parentElement.clientWidth;
267
+
268
+ // We need special handling for the height because
269
+ // a caption will cause the figure to be taller than
270
+ // the image, which means we need to account for that
271
+ // when calculating the placement of the button in the
272
+ // top right corner of the image.
273
+ let figureHeight = ref.parentElement.clientHeight;
274
+ const caption = figure.querySelector( 'figcaption' );
275
+ if ( caption ) {
276
+ const captionComputedStyle = window.getComputedStyle( caption );
277
+ if (
278
+ ! [ 'absolute', 'fixed' ].includes(
279
+ captionComputedStyle.position
280
+ )
281
+ ) {
282
+ figureHeight =
283
+ figureHeight -
284
+ caption.offsetHeight -
285
+ parseFloat( captionComputedStyle.marginTop ) -
286
+ parseFloat( captionComputedStyle.marginBottom );
287
+ }
288
+ }
289
+
290
+ const buttonOffsetTop = figureHeight - offsetHeight;
291
+ const buttonOffsetRight = figureWidth - offsetWidth;
292
+
293
+ const ctx = getContext();
294
+
295
+ // In the case of an image with object-fit: contain, the
296
+ // size of the <img> element can be larger than the image itself,
297
+ // so we need to calculate where to place the button.
298
+ if ( ctx.scaleAttr === 'contain' ) {
299
+ // Natural ratio of the image.
300
+ const naturalRatio = naturalWidth / naturalHeight;
301
+ // Offset ratio of the image.
302
+ const offsetRatio = offsetWidth / offsetHeight;
303
+
304
+ if ( naturalRatio >= offsetRatio ) {
305
+ // If it reaches the width first, keep
306
+ // the width and compute the height.
307
+ const referenceHeight = offsetWidth / naturalRatio;
308
+ ctx.imageButtonTop =
309
+ ( offsetHeight - referenceHeight ) / 2 +
310
+ buttonOffsetTop +
311
+ 16;
312
+ ctx.imageButtonRight = buttonOffsetRight + 16;
313
+ } else {
314
+ // If it reaches the height first, keep
315
+ // the height and compute the width.
316
+ const referenceWidth = offsetHeight * naturalRatio;
317
+ ctx.imageButtonTop = buttonOffsetTop + 16;
318
+ ctx.imageButtonRight =
319
+ ( offsetWidth - referenceWidth ) / 2 +
320
+ buttonOffsetRight +
321
+ 16;
322
+ }
323
+ } else {
324
+ ctx.imageButtonTop = buttonOffsetTop + 16;
325
+ ctx.imageButtonRight = buttonOffsetRight + 16;
326
+ }
327
+ },
328
+ setStylesOnResize() {
329
+ const ctx = getContext();
330
+ const { ref } = getElement();
331
+ if (
332
+ ctx.lightboxEnabled &&
333
+ ( state.windowWidth || state.windowHeight )
334
+ ) {
335
+ setStyles( ctx, ref );
336
+ }
337
+ },
338
+ },
339
+ } );
340
+
341
+ window.addEventListener(
342
+ 'resize',
343
+ debounce( () => {
344
+ state.windowWidth = window.innerWidth;
345
+ state.windowHeight = window.innerHeight;
346
+ } )
389
347
  );
390
348
 
391
- /*
349
+ /**
392
350
  * Computes styles for the lightbox and adds them to the document.
393
351
  *
394
352
  * @function
395
- * @param {Object} context - An Interactivity API context
396
- * @param {Object} event - A triggering event
353
+ * @param {Object} ctx - Context for the `core/image` namespace.
354
+ * @param {Object} ref - The element reference.
397
355
  */
398
- function setStyles( context, ref ) {
356
+ function setStyles( ctx, ref ) {
399
357
  // The reference img element lies adjacent
400
358
  // to the event target button in the DOM.
401
359
  let {
@@ -413,7 +371,7 @@ function setStyles( context, ref ) {
413
371
 
414
372
  // If it has object-fit: contain, recalculate the original sizes
415
373
  // and the screen position without the blank spaces.
416
- if ( context.core.image.scaleAttr === 'contain' ) {
374
+ if ( ctx.scaleAttr === 'contain' ) {
417
375
  if ( naturalRatio > originalRatio ) {
418
376
  const heightWithoutSpace = originalWidth / naturalRatio;
419
377
  // Recalculate screen position without the top space.
@@ -433,14 +391,10 @@ function setStyles( context, ref ) {
433
391
  // the image's dimensions in the lightbox are the same
434
392
  // as those of the image in the content.
435
393
  let imgMaxWidth = parseFloat(
436
- context.core.image.targetWidth !== 'none'
437
- ? context.core.image.targetWidth
438
- : naturalWidth
394
+ ctx.targetWidth !== 'none' ? ctx.targetWidth : naturalWidth
439
395
  );
440
396
  let imgMaxHeight = parseFloat(
441
- context.core.image.targetHeight !== 'none'
442
- ? context.core.image.targetHeight
443
- : naturalHeight
397
+ ctx.targetHeight !== 'none' ? ctx.targetHeight : naturalHeight
444
398
  );
445
399
 
446
400
  // Ratio of the biggest image stored in the database.
@@ -558,16 +512,19 @@ function setStyles( context, ref ) {
558
512
  --wp--lightbox-image-width: ${ lightboxImgWidth }px;
559
513
  --wp--lightbox-image-height: ${ lightboxImgHeight }px;
560
514
  --wp--lightbox-scale: ${ containerScale };
515
+ --wp--lightbox-scrollbar-width: ${
516
+ window.innerWidth - document.documentElement.clientWidth
517
+ }px;
561
518
  }
562
519
  `;
563
520
  }
564
521
 
565
- /*
522
+ /**
566
523
  * Debounces a function call.
567
524
  *
568
525
  * @function
569
526
  * @param {Function} func - A function to be called
570
- * @param {number} wait - The time to wait before calling the function
527
+ * @param {number} wait - The time to wait before calling the function
571
528
  */
572
529
  function debounce( func, wait = 50 ) {
573
530
  let timeout;
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "originalContent": {
17
17
  "type": "string",
18
- "source": "html"
18
+ "source": "raw"
19
19
  }
20
20
  },
21
21
  "supports": {