@wordpress/interactivity-router 2.32.0 → 2.32.1-next.b8c8708f3.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 (41) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/assets/dynamic-importmap/fetch.js +32 -43
  3. package/build/assets/dynamic-importmap/fetch.js.map +7 -1
  4. package/build/assets/dynamic-importmap/index.js +43 -73
  5. package/build/assets/dynamic-importmap/index.js.map +7 -1
  6. package/build/assets/dynamic-importmap/loader.js +139 -172
  7. package/build/assets/dynamic-importmap/loader.js.map +7 -1
  8. package/build/assets/dynamic-importmap/resolver.js +99 -112
  9. package/build/assets/dynamic-importmap/resolver.js.map +7 -1
  10. package/build/assets/script-modules.js +46 -58
  11. package/build/assets/script-modules.js.map +7 -1
  12. package/build/assets/scs.js +30 -39
  13. package/build/assets/scs.js.map +7 -1
  14. package/build/assets/styles.js +81 -171
  15. package/build/assets/styles.js.map +7 -1
  16. package/build/full-page.js +43 -36
  17. package/build/full-page.js.map +7 -1
  18. package/build/index.js +139 -265
  19. package/build/index.js.map +7 -1
  20. package/build-module/assets/dynamic-importmap/fetch.js +11 -39
  21. package/build-module/assets/dynamic-importmap/fetch.js.map +7 -1
  22. package/build-module/assets/dynamic-importmap/index.js +18 -52
  23. package/build-module/assets/dynamic-importmap/index.js.map +7 -1
  24. package/build-module/assets/dynamic-importmap/loader.js +101 -165
  25. package/build-module/assets/dynamic-importmap/loader.js.map +7 -1
  26. package/build-module/assets/dynamic-importmap/resolver.js +78 -108
  27. package/build-module/assets/dynamic-importmap/resolver.js.map +7 -1
  28. package/build-module/assets/script-modules.js +25 -49
  29. package/build-module/assets/script-modules.js.map +7 -1
  30. package/build-module/assets/scs.js +9 -35
  31. package/build-module/assets/scs.js.map +7 -1
  32. package/build-module/assets/styles.js +58 -163
  33. package/build-module/assets/styles.js.map +7 -1
  34. package/build-module/full-page.js +21 -32
  35. package/build-module/full-page.js.map +7 -1
  36. package/build-module/index.js +108 -257
  37. package/build-module/index.js.map +7 -1
  38. package/build-types/index.d.ts.map +1 -1
  39. package/package.json +12 -4
  40. package/src/index.ts +2 -3
  41. package/tsconfig.main.tsbuildinfo +1 -1
@@ -1,16 +1,11 @@
1
- /* wp:polyfill */
2
- /**
3
- * WordPress dependencies
4
- */
5
- import { store, privateApis, getConfig } from '@wordpress/interactivity';
6
-
7
- /**
8
- * Internal dependencies
9
- */
10
- import { preloadStyles, applyStyles } from './assets/styles';
11
- import { preloadScriptModules, importScriptModules, markScriptModuleAsResolved } from './assets/script-modules';
1
+ import { store, privateApis, getConfig } from "@wordpress/interactivity";
2
+ import { preloadStyles, applyStyles } from "./assets/styles";
3
+ import {
4
+ preloadScriptModules,
5
+ importScriptModules,
6
+ markScriptModuleAsResolved
7
+ } from "./assets/script-modules";
12
8
  const {
13
- directivePrefix,
14
9
  getRegionRootFragment,
15
10
  initialVdom,
16
11
  toVdom,
@@ -20,93 +15,43 @@ const {
20
15
  batch,
21
16
  routerRegions,
22
17
  cloneElement
23
- } = privateApis('I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WordPress.');
24
- const regionAttr = `data-${directivePrefix}-router-region`;
25
- const interactiveAttr = `data-${directivePrefix}-interactive`;
18
+ } = privateApis(
19
+ "I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WordPress."
20
+ );
21
+ const regionAttr = `data-wp-router-region`;
22
+ const interactiveAttr = `data-wp-interactive`;
26
23
  const regionsSelector = `[${interactiveAttr}][${regionAttr}], [${interactiveAttr}] [${interactiveAttr}][${regionAttr}]`;
27
- // The cache of visited and prefetched pages, stylesheets and scripts.
28
- const pages = new Map();
29
-
30
- // Helper to remove domain and hash from the URL. We are only interesting in
31
- // caching the path and the query.
32
- const getPagePath = url => {
24
+ const pages = /* @__PURE__ */ new Map();
25
+ const getPagePath = (url) => {
33
26
  const u = new URL(url, window.location.href);
34
27
  return u.pathname + u.search;
35
28
  };
36
-
37
- /**
38
- * Parses the given region's directive.
39
- *
40
- * @param region Region element.
41
- * @return Data contained in the region directive value.
42
- */
43
- const parseRegionAttribute = region => {
29
+ const parseRegionAttribute = (region) => {
44
30
  const value = region.getAttribute(regionAttr);
45
31
  try {
46
- const {
47
- id,
48
- attachTo
49
- } = JSON.parse(value);
50
- return {
51
- id,
52
- attachTo
53
- };
32
+ const { id, attachTo } = JSON.parse(value);
33
+ return { id, attachTo };
54
34
  } catch (e) {
55
- return {
56
- id: value
57
- };
35
+ return { id: value };
58
36
  }
59
37
  };
60
-
61
- /**
62
- * Clones the content of the router region vDOM passed as argument.
63
- *
64
- * The function creates a new VNode instance removing all priority levels up to
65
- * the one containing the router-region directive, which should have evaluated
66
- * in advance.
67
- *
68
- * @param vdom A router region's VNode.
69
- * @return The VNode for the passed router region's content.
70
- */
71
- const cloneRouterRegionContent = vdom => {
38
+ const cloneRouterRegionContent = (vdom) => {
72
39
  if (!vdom) {
73
40
  return vdom;
74
41
  }
75
42
  const allPriorityLevels = vdom.props.priorityLevels;
76
- const routerRegionLevel = allPriorityLevels.findIndex(level => level.includes('router-region'));
43
+ const routerRegionLevel = allPriorityLevels.findIndex(
44
+ (level) => level.includes("router-region")
45
+ );
77
46
  const priorityLevels = routerRegionLevel !== -1 ? allPriorityLevels.slice(routerRegionLevel + 1) : allPriorityLevels;
78
47
  return priorityLevels.length > 0 ? cloneElement(vdom, {
79
48
  ...vdom.props,
80
49
  priorityLevels
81
50
  }) : vdom.props.element;
82
51
  };
83
-
84
- /**
85
- * IDs of router regions with an `attachTo` property pointing to the same parent
86
- * element.
87
- */
88
- const regionsToAttachByParent = new WeakMap();
89
-
90
- /**
91
- * Map of root fragments by parent element, used to render router regions with
92
- * the `attachTo` property. Those elements with the same parent are rendered
93
- * together in the corresponding root fragment.
94
- */
95
- const rootFragmentsByParent = new WeakMap();
96
-
97
- /**
98
- * Fetches and prepares a page from a given URL.
99
- *
100
- * @param url The URL of the page to fetch.
101
- * @param options Options for the fetch operation.
102
- * @param options.html Optional HTML content. If provided, the function will use
103
- * this instead of fetching from the URL.
104
- * @return A Promise that resolves to the prepared page, or false if
105
- * there was an error during fetching or preparation.
106
- */
107
- const fetchPage = async (url, {
108
- html
109
- }) => {
52
+ const regionsToAttachByParent = /* @__PURE__ */ new WeakMap();
53
+ const rootFragmentsByParent = /* @__PURE__ */ new WeakMap();
54
+ const fetchPage = async (url, { html }) => {
110
55
  try {
111
56
  if (!html) {
112
57
  const res = await window.fetch(url);
@@ -115,48 +60,20 @@ const fetchPage = async (url, {
115
60
  }
116
61
  html = await res.text();
117
62
  }
118
- const dom = new window.DOMParser().parseFromString(html, 'text/html');
63
+ const dom = new window.DOMParser().parseFromString(html, "text/html");
119
64
  return await preparePage(url, dom);
120
65
  } catch (e) {
121
66
  return false;
122
67
  }
123
68
  };
124
-
125
- /**
126
- * Processes a DOM document to extract router regions and related resources.
127
- *
128
- * This function analyzes the provided DOM document and creates a virtual DOM
129
- * representation of all HTML regions marked with a `router-region` directive.
130
- * It also extracts and preloads associated styles and scripts to prepare for
131
- * rendering the page.
132
- *
133
- * @param url The URL associated with the page, used for asset
134
- * loading and caching.
135
- * @param dom The DOM document to process.
136
- * @param vdomParams Optional parameters for virtual DOM processing.
137
- * @param vdomParams.vdom An optional existing virtual DOM cache to check for
138
- * regions. If a region exists in this cache, it will be
139
- * reused instead of creating a new vDOM representation.
140
- * @return A Promise that resolves to a {@link Page} object
141
- * containing the virtual DOM for all router regions,
142
- * preloaded styles and scripts, page title, and initial
143
- * server-rendered data.
144
- */
145
- const preparePage = async (url, dom, {
146
- vdom
147
- } = {}) => {
148
- // Remove all noscript elements as they're irrelevant when request is served via router.
149
- // This prevents browsers from extracting styles from noscript tags.
150
- dom.querySelectorAll('noscript').forEach(el => el.remove());
69
+ const preparePage = async (url, dom, { vdom } = {}) => {
70
+ dom.querySelectorAll("noscript").forEach((el) => el.remove());
151
71
  const regions = {};
152
72
  const regionsToAttach = {};
153
- dom.querySelectorAll(regionsSelector).forEach(region => {
154
- const {
155
- id,
156
- attachTo
157
- } = parseRegionAttribute(region);
73
+ dom.querySelectorAll(regionsSelector).forEach((region) => {
74
+ const { id, attachTo } = parseRegionAttribute(region);
158
75
  if (region.parentElement.closest(`[${regionAttr}]`)) {
159
- regions[id] = undefined;
76
+ regions[id] = void 0;
160
77
  } else {
161
78
  regions[id] = vdom?.has(region) ? vdom.get(region) : toVdom(region);
162
79
  }
@@ -164,11 +81,12 @@ const preparePage = async (url, dom, {
164
81
  regionsToAttach[id] = attachTo;
165
82
  }
166
83
  });
167
- const title = dom.querySelector('title')?.innerText;
84
+ const title = dom.querySelector("title")?.innerText;
168
85
  const initialData = parseServerData(dom);
169
-
170
- // Wait for styles and modules to be ready.
171
- const [styles, scriptModules] = await Promise.all([Promise.all(preloadStyles(dom, url)), Promise.all(preloadScriptModules(dom))]);
86
+ const [styles, scriptModules] = await Promise.all([
87
+ Promise.all(preloadStyles(dom, url)),
88
+ Promise.all(preloadScriptModules(dom))
89
+ ]);
172
90
  return {
173
91
  regions,
174
92
  regionsToAttach,
@@ -179,31 +97,15 @@ const preparePage = async (url, dom, {
179
97
  url
180
98
  };
181
99
  };
182
-
183
- /**
184
- * Renders a page by applying styles, populating server data, rendering regions,
185
- * and updating the document title.
186
- *
187
- * @param page The {@link Page} object to render.
188
- */
189
- const renderPage = page => {
100
+ const renderPage = (page) => {
190
101
  applyStyles(page.styles);
191
-
192
- // Clone regionsToAttach.
193
- const regionsToAttach = {
194
- ...page.regionsToAttach
195
- };
102
+ const regionsToAttach = { ...page.regionsToAttach };
196
103
  batch(() => {
197
- // Update server data.
198
104
  populateServerData(page.initialData);
199
-
200
- // Reset all router regions before setting the actual values.
201
- routerRegions.forEach(signal => {
105
+ routerRegions.forEach((signal) => {
202
106
  signal.value = null;
203
107
  });
204
-
205
- //Init regions with attachTo that don't exist yet.
206
- const parentsToUpdate = new Set();
108
+ const parentsToUpdate = /* @__PURE__ */ new Set();
207
109
  for (const id in regionsToAttach) {
208
110
  const parent = document.querySelector(regionsToAttach[id]);
209
111
  if (!regionsToAttachByParent.has(parent)) {
@@ -215,32 +117,27 @@ const renderPage = page => {
215
117
  parentsToUpdate.add(parent);
216
118
  }
217
119
  }
218
-
219
- //Update all existing regions.
220
120
  for (const id in page.regions) {
221
121
  if (routerRegions.has(id)) {
222
- routerRegions.get(id).value = cloneRouterRegionContent(page.regions[id]);
122
+ routerRegions.get(id).value = cloneRouterRegionContent(
123
+ page.regions[id]
124
+ );
223
125
  }
224
126
  }
225
-
226
- // Render regions attached to the same parent in the same fragment.
227
- parentsToUpdate.forEach(parent => {
127
+ parentsToUpdate.forEach((parent) => {
228
128
  const ids = regionsToAttachByParent.get(parent);
229
- const vdoms = ids.map(id => page.regions[id]);
129
+ const vdoms = ids.map((id) => page.regions[id]);
230
130
  if (!rootFragmentsByParent.has(parent)) {
231
- const regions = vdoms.map(({
232
- props,
233
- type
234
- }) => {
235
- const elementType = typeof type === 'function' ? props.type : type;
236
-
237
- // Create an element with the obtained type where the region will be
238
- // rendered. The type should match the one of the root vnode.
131
+ const regions = vdoms.map(({ props, type }) => {
132
+ const elementType = typeof type === "function" ? props.type : type;
239
133
  const region = document.createElement(elementType);
240
134
  parent.appendChild(region);
241
135
  return region;
242
136
  });
243
- rootFragmentsByParent.set(parent, getRegionRootFragment(regions));
137
+ rootFragmentsByParent.set(
138
+ parent,
139
+ getRegionRootFragment(regions)
140
+ );
244
141
  }
245
142
  const fragment = rootFragmentsByParent.get(parent);
246
143
  render(vdoms, fragment);
@@ -250,55 +147,37 @@ const renderPage = page => {
250
147
  document.title = page.title;
251
148
  }
252
149
  };
253
-
254
- /**
255
- * Loads the given page forcing a full page reload.
256
- *
257
- * The function returns a promise that won't resolve, useful to prevent any
258
- * potential feedback indicating that the navigation has finished while the new
259
- * page is being loaded.
260
- *
261
- * @param href The page href.
262
- * @return Promise that never resolves.
263
- */
264
- const forcePageReload = href => {
150
+ const forcePageReload = (href) => {
265
151
  window.location.assign(href);
266
- return new Promise(() => {});
152
+ return new Promise(() => {
153
+ });
267
154
  };
268
-
269
- // Listen to the back and forward buttons and restore the page if it's in the
270
- // cache.
271
- window.addEventListener('popstate', async () => {
272
- const pagePath = getPagePath(window.location.href); // Remove hash.
273
- const page = pages.has(pagePath) && (await pages.get(pagePath));
155
+ window.addEventListener("popstate", async () => {
156
+ const pagePath = getPagePath(window.location.href);
157
+ const page = pages.has(pagePath) && await pages.get(pagePath);
274
158
  if (page) {
275
159
  renderPage(page);
276
- // Update the URL in the state.
277
160
  state.url = window.location.href;
278
161
  } else {
279
162
  window.location.reload();
280
163
  }
281
164
  });
282
-
283
- // Initialize the router and cache the initial page using the initial vDOM.
284
- window.document.querySelectorAll('script[type=module][src]').forEach(({
285
- src
286
- }) => markScriptModuleAsResolved(src));
287
- pages.set(getPagePath(window.location.href), Promise.resolve(preparePage(getPagePath(window.location.href), document, {
288
- vdom: initialVdom
289
- })));
290
-
291
- // Variable to store the current navigation.
292
- let navigatingTo = '';
165
+ window.document.querySelectorAll("script[type=module][src]").forEach(({ src }) => markScriptModuleAsResolved(src));
166
+ pages.set(
167
+ getPagePath(window.location.href),
168
+ Promise.resolve(
169
+ preparePage(getPagePath(window.location.href), document, {
170
+ vdom: initialVdom
171
+ })
172
+ )
173
+ );
174
+ let navigatingTo = "";
293
175
  let hasLoadedNavigationTextsData = false;
294
176
  const navigationTexts = {
295
- loading: 'Loading page, please wait.',
296
- loaded: 'Page Loaded.'
177
+ loading: "Loading page, please wait.",
178
+ loaded: "Page Loaded."
297
179
  };
298
- export const {
299
- state,
300
- actions
301
- } = store('core/router', {
180
+ const { state, actions } = store("core/router", {
302
181
  state: {
303
182
  url: window.location.href,
304
183
  navigation: {
@@ -326,29 +205,22 @@ export const {
326
205
  * @return Promise that resolves once the navigation is completed or aborted.
327
206
  */
328
207
  *navigate(href, options = {}) {
329
- const {
330
- clientNavigationDisabled
331
- } = getConfig();
208
+ const { clientNavigationDisabled } = getConfig();
332
209
  if (clientNavigationDisabled) {
333
210
  yield forcePageReload(href);
334
211
  }
335
212
  const pagePath = getPagePath(href);
336
- const {
337
- navigation
338
- } = state;
213
+ const { navigation } = state;
339
214
  const {
340
215
  loadingAnimation = true,
341
216
  screenReaderAnnouncement = true,
342
- timeout = 10000
217
+ timeout = 1e4
343
218
  } = options;
344
219
  navigatingTo = href;
345
220
  actions.prefetch(pagePath, options);
346
-
347
- // Create a promise that resolves when the specified timeout ends.
348
- // The timeout value is 10 seconds by default.
349
- const timeoutPromise = new Promise(resolve => setTimeout(resolve, timeout));
350
-
351
- // Don't update the navigation status immediately, wait 400 ms.
221
+ const timeoutPromise = new Promise(
222
+ (resolve) => setTimeout(resolve, timeout)
223
+ );
352
224
  const loadingTimeout = setTimeout(() => {
353
225
  if (navigatingTo !== href) {
354
226
  return;
@@ -358,42 +230,30 @@ export const {
358
230
  navigation.hasFinished = false;
359
231
  }
360
232
  if (screenReaderAnnouncement) {
361
- a11ySpeak('loading');
233
+ a11ySpeak("loading");
362
234
  }
363
235
  }, 400);
364
- const page = yield Promise.race([pages.get(pagePath), timeoutPromise]);
365
-
366
- // Dismiss loading message if it hasn't been added yet.
236
+ const page = yield Promise.race([
237
+ pages.get(pagePath),
238
+ timeoutPromise
239
+ ]);
367
240
  clearTimeout(loadingTimeout);
368
-
369
- // Once the page is fetched, the destination URL could have changed
370
- // (e.g., by clicking another link in the meantime). If so, bail
371
- // out, and let the newer execution to update the HTML.
372
241
  if (navigatingTo !== href) {
373
242
  return;
374
243
  }
375
- if (page && !page.initialData?.config?.['core/router']?.clientNavigationDisabled) {
244
+ if (page && !page.initialData?.config?.["core/router"]?.clientNavigationDisabled) {
376
245
  yield importScriptModules(page.scriptModules);
377
246
  renderPage(page);
378
- window.history[options.replace ? 'replaceState' : 'pushState']({}, '', href);
379
-
380
- // Update the URL in the state.
247
+ window.history[options.replace ? "replaceState" : "pushState"]({}, "", href);
381
248
  state.url = href;
382
-
383
- // Update the navigation status once the the new page rendering
384
- // has been completed.
385
249
  if (loadingAnimation) {
386
250
  navigation.hasStarted = false;
387
251
  navigation.hasFinished = true;
388
252
  }
389
253
  if (screenReaderAnnouncement) {
390
- a11ySpeak('loaded');
254
+ a11ySpeak("loaded");
391
255
  }
392
-
393
- // Scroll to the anchor if exits in the link.
394
- const {
395
- hash
396
- } = new URL(href, window.location.href);
256
+ const { hash } = new URL(href, window.location.href);
397
257
  if (hash) {
398
258
  document.querySelector(hash)?.scrollIntoView();
399
259
  }
@@ -415,66 +275,57 @@ export const {
415
275
  * @return Promise that resolves once the page has been fetched.
416
276
  */
417
277
  *prefetch(url, options = {}) {
418
- const {
419
- clientNavigationDisabled
420
- } = getConfig();
278
+ const { clientNavigationDisabled } = getConfig();
421
279
  if (clientNavigationDisabled) {
422
280
  return;
423
281
  }
424
282
  const pagePath = getPagePath(url);
425
283
  if (options.force || !pages.has(pagePath)) {
426
- pages.set(pagePath, fetchPage(pagePath, {
427
- html: options.html
428
- }));
284
+ pages.set(
285
+ pagePath,
286
+ fetchPage(pagePath, { html: options.html })
287
+ );
429
288
  }
430
289
  yield pages.get(pagePath);
431
290
  }
432
291
  }
433
292
  });
434
-
435
- /**
436
- * Announces a message to screen readers.
437
- *
438
- * This is a wrapper around the `@wordpress/a11y` package's `speak` function. It handles importing
439
- * the package on demand and should be used instead of calling `a11y.speak` directly.
440
- *
441
- * @param messageKey The message to be announced by assistive technologies.
442
- */
443
293
  function a11ySpeak(messageKey) {
444
294
  if (!hasLoadedNavigationTextsData) {
445
295
  hasLoadedNavigationTextsData = true;
446
- const content = document.getElementById('wp-script-module-data-@wordpress/interactivity-router')?.textContent;
296
+ const content = document.getElementById(
297
+ "wp-script-module-data-@wordpress/interactivity-router"
298
+ )?.textContent;
447
299
  if (content) {
448
300
  try {
449
301
  const parsed = JSON.parse(content);
450
- if (typeof parsed?.i18n?.loading === 'string') {
302
+ if (typeof parsed?.i18n?.loading === "string") {
451
303
  navigationTexts.loading = parsed.i18n.loading;
452
304
  }
453
- if (typeof parsed?.i18n?.loaded === 'string') {
305
+ if (typeof parsed?.i18n?.loaded === "string") {
454
306
  navigationTexts.loaded = parsed.i18n.loaded;
455
307
  }
456
- } catch {}
308
+ } catch {
309
+ }
457
310
  } else {
458
- // Fallback to localized strings from Interactivity API state.
459
- // @todo This block is for Core < 6.7.0. Remove when support is dropped.
460
-
461
- // @ts-expect-error
462
311
  if (state.navigation.texts?.loading) {
463
- // @ts-expect-error
464
312
  navigationTexts.loading = state.navigation.texts.loading;
465
313
  }
466
- // @ts-expect-error
467
314
  if (state.navigation.texts?.loaded) {
468
- // @ts-expect-error
469
315
  navigationTexts.loaded = state.navigation.texts.loaded;
470
316
  }
471
317
  }
472
318
  }
473
319
  const message = navigationTexts[messageKey];
474
- import('@wordpress/a11y').then(({
475
- speak
476
- }) => speak(message),
477
- // Ignore failures to load the a11y module.
478
- () => {});
320
+ import("@wordpress/a11y").then(
321
+ ({ speak }) => speak(message),
322
+ // Ignore failures to load the a11y module.
323
+ () => {
324
+ }
325
+ );
479
326
  }
480
- //# sourceMappingURL=index.js.map
327
+ export {
328
+ actions,
329
+ state
330
+ };
331
+ //# sourceMappingURL=index.js.map