@dream-encode/wp-js-plugin-utils 0.6.1 → 0.6.3

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.
@@ -173,8 +173,11 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
173
173
  role: "tabpanel",
174
174
  "aria-labelledby": `de-settings-tab-${activeSection.key}`,
175
175
  tabIndex: 0,
176
- children: !settingsLoaded ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Placeholder, {
177
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {})
176
+ children: !settingsLoaded ? /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
177
+ className: "de-settings__loading",
178
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_components.Spinner, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)("p", {
179
+ children: (0, _i18n.__)('Loading settings…', textDomain)
180
+ })]
178
181
  }) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_element.Fragment, {
179
182
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Notices.default, {}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
180
183
  className: "de-settings__pane-head",
@@ -137,6 +137,7 @@
137
137
  }
138
138
 
139
139
  .de-settings__rail {
140
+ margin-left: 1rem;
140
141
  background: var( --de-settings-surface );
141
142
  border-right: 1px solid var( --de-settings-line );
142
143
  }
@@ -262,6 +263,19 @@
262
263
  }
263
264
  }
264
265
 
266
+ .de-settings__loading {
267
+ display: flex;
268
+ align-items: center;
269
+ gap: 8px;
270
+ padding: 32px 0;
271
+ color: var( --de-settings-ink-faint );
272
+
273
+ p {
274
+ margin: 0;
275
+ font-size: 13px;
276
+ }
277
+ }
278
+
265
279
  .de-settings__pane-head {
266
280
  margin-bottom: 18px;
267
281
 
@@ -5,6 +5,16 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
  var _element = require("@wordpress/element");
8
+ /**
9
+ * Read the raw section key carried in the URL hash.
10
+ *
11
+ * @since 0.6.3
12
+ * @return {string} Hash without its leading `#`, or an empty string.
13
+ */
14
+ const readHash = () => {
15
+ return window.location.hash.replace(/^#/, '');
16
+ };
17
+
8
18
  /**
9
19
  * Read the section key carried in the URL hash.
10
20
  *
@@ -13,7 +23,7 @@ var _element = require("@wordpress/element");
13
23
  * @return {string|null} Matching section key, or null when the hash names nothing known.
14
24
  */
15
25
  const readSectionFromHash = keys => {
16
- const hash = window.location.hash.replace(/^#/, '');
26
+ const hash = readHash();
17
27
  return keys.includes(hash) ? hash : null;
18
28
  };
19
29
 
@@ -26,6 +36,15 @@ const readSectionFromHash = keys => {
26
36
  * the browser Back button still leaves the settings page instead of walking back
27
37
  * through the sections that were opened.
28
38
  *
39
+ * A page whose sections depend on a setting registers them in two passes: the first
40
+ * render happens before `/wp/v2/settings` answers, so any section gated behind a
41
+ * value is missing from `sections` at that point. A hash naming one of those is
42
+ * therefore unknown when the page mounts. Rather than discard it and fall back to
43
+ * the first section, the requested key is parked and adopted as soon as it appears,
44
+ * which is what makes a link to a gated section work. The parked key is dropped the
45
+ * moment the reader chooses a section themselves, so a late arriving section can
46
+ * never pull them away from what they are looking at.
47
+ *
29
48
  * @since 0.6.0
30
49
  * @param {Array} sections Section definitions.
31
50
  * @return {Array} The active section key and a setter for it.
@@ -35,15 +54,26 @@ const useActiveSection = sections => {
35
54
  const keys = (0, _element.useMemo)(() => {
36
55
  return keySignature.split('|').filter(Boolean);
37
56
  }, [keySignature]);
57
+ const requestedSection = (0, _element.useRef)(null);
38
58
  const [activeKey, setActiveKey] = (0, _element.useState)(() => {
59
+ const hash = readHash();
60
+ if (hash && !keys.includes(hash)) {
61
+ requestedSection.current = hash;
62
+ }
39
63
  return readSectionFromHash(keys) || keys[0] || '';
40
64
  });
41
65
  (0, _element.useEffect)(() => {
42
66
  const handleHashChange = () => {
43
- const nextKey = readSectionFromHash(keys);
44
- if (nextKey) {
45
- setActiveKey(nextKey);
67
+ const hash = readHash();
68
+ if (!hash) {
69
+ return;
46
70
  }
71
+ if (keys.includes(hash)) {
72
+ requestedSection.current = null;
73
+ setActiveKey(hash);
74
+ return;
75
+ }
76
+ requestedSection.current = hash;
47
77
  };
48
78
  window.addEventListener('hashchange', handleHashChange);
49
79
  return () => {
@@ -51,11 +81,25 @@ const useActiveSection = sections => {
51
81
  };
52
82
  }, [keys]);
53
83
  (0, _element.useEffect)(() => {
84
+ if (!requestedSection.current) {
85
+ return;
86
+ }
87
+ if (!keys.includes(requestedSection.current)) {
88
+ return;
89
+ }
90
+ setActiveKey(requestedSection.current);
91
+ requestedSection.current = null;
92
+ }, [keys]);
93
+ (0, _element.useEffect)(() => {
94
+ if (requestedSection.current) {
95
+ return;
96
+ }
54
97
  if (keys.length && !keys.includes(activeKey)) {
55
98
  setActiveKey(keys[0]);
56
99
  }
57
100
  }, [keys, activeKey]);
58
101
  const selectSection = (0, _element.useCallback)(key => {
102
+ requestedSection.current = null;
59
103
  setActiveKey(key);
60
104
  window.history.replaceState(null, '', `#${key}`);
61
105
  }, []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dream-encode/wp-js-plugin-utils",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "Common JS functionality used by custom WP plugins.",
5
5
  "keywords": [
6
6
  "wordpress",