@dream-encode/wp-js-plugin-utils 0.1.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.
package/README.md ADDED
@@ -0,0 +1,109 @@
1
+ # @dream-encode/wp-plugin-utils
2
+
3
+ Common JS functionality used by custom WP plugins.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ yarn add @dream-encode/wp-plugin-utils
9
+ ```
10
+
11
+ The package declares `@wordpress/*`, `react`, `webpack`, and the related
12
+ loaders/plugins as peer dependencies. Plugins consuming this package are
13
+ expected to provide their own versions.
14
+
15
+ ## Subpath exports
16
+
17
+ | Import path | Description |
18
+ | --------------------------------------------------- | ------------------------------------------------------ |
19
+ | `@dream-encode/wp-plugin-utils` | All modules grouped under namespaces. |
20
+ | `@dream-encode/wp-plugin-utils/webpack` | `createWebpackConfig` factory (CommonJS). |
21
+ | `@dream-encode/wp-plugin-utils/postcss` | Default PostCSS config (CommonJS). |
22
+ | `@dream-encode/wp-plugin-utils/settings` | `createUseSettings`, `AdminSettingsPage`. |
23
+ | `@dream-encode/wp-plugin-utils/settings/styles` | SCSS partial with the settings-page styles mixin. |
24
+ | `@dream-encode/wp-plugin-utils/data-migrations` | Registry helpers for the Data Migrations plugin. |
25
+ | `@dream-encode/wp-plugin-utils/components` | Shared components (`Notices`). |
26
+ | `@dream-encode/wp-plugin-utils/hooks` | `useValueChangeEffect`, `useBlurableContent`, … |
27
+ | `@dream-encode/wp-plugin-utils/api` | `fetchGetOptions`, `fetchPostOptions`. |
28
+ | `@dream-encode/wp-plugin-utils/utils` | Strings, dates, time, WP url helpers. |
29
+ | `@dream-encode/wp-plugin-utils/constants` | Shared constants (`LOG_LEVELS`, …). |
30
+
31
+ ## Webpack config
32
+
33
+ ```js
34
+ // webpack.config.js
35
+ const createWebpackConfig = require( '@dream-encode/wp-plugin-utils/webpack' )
36
+
37
+ module.exports = createWebpackConfig( {
38
+ context: __dirname,
39
+ appVersion: require( './package.json' ),
40
+ sentry: true,
41
+ entry: {
42
+ 'admin-settings-page': [
43
+ './admin/assets/src/js/admin-settings-page.js',
44
+ './admin/assets/src/scss/admin-settings-page.scss'
45
+ ]
46
+ }
47
+ } )
48
+ ```
49
+
50
+ ## Settings hook + page shell
51
+
52
+ ```jsx
53
+ import { createUseSettings, AdminSettingsPage } from '@dream-encode/wp-plugin-utils/settings'
54
+
55
+ const useSettings = createUseSettings( {
56
+ optionName: 'my_plugin_settings',
57
+ textDomain: 'my-plugin',
58
+ fields: [
59
+ { key: 'plugin_log_level', defaultValue: 'off' },
60
+ { key: 'feature_flag_x', defaultValue: false }
61
+ ]
62
+ } )
63
+
64
+ const SettingsPage = () => {
65
+ const settings = useSettings()
66
+
67
+ return (
68
+ <AdminSettingsPage
69
+ title="My Plugin"
70
+ appVersion={ APP_VERSION }
71
+ textDomain="my-plugin"
72
+ settings={ settings }
73
+ >
74
+ { ( s ) => (
75
+ /* Render your fields, reading from `s.pluginLogLevel`, etc. */
76
+ null
77
+ ) }
78
+ </AdminSettingsPage>
79
+ )
80
+ }
81
+ ```
82
+
83
+ Use the SCSS mixin to style the page:
84
+
85
+ ```scss
86
+ @use "@dream-encode/wp-plugin-utils/settings/styles" as utils;
87
+
88
+ .settings_page_my-plugin-settings {
89
+ @include utils.de-wp-plugin-utils-settings-page;
90
+ }
91
+ ```
92
+
93
+ ## Data Migrations registry
94
+
95
+ ```js
96
+ import domReady from '@wordpress/dom-ready'
97
+ import {
98
+ registerMigratorSettings,
99
+ registerResultsRenderer
100
+ } from '@dream-encode/wp-plugin-utils/data-migrations'
101
+
102
+ import MyMigratorSettings from './components/MyMigratorSettings'
103
+ import MyResultsRenderer from './components/MyResultsRenderer'
104
+
105
+ domReady( () => {
106
+ registerMigratorSettings( 'my_migrator', MyMigratorSettings )
107
+ registerResultsRenderer( 'my_migrator', MyResultsRenderer )
108
+ } )
109
+ ```
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.fetchPostOptions = exports.fetchGetOptions = void 0;
7
+ /**
8
+ * Build fetch GET options with the WP REST nonce header.
9
+ *
10
+ * @param {string} nonce WP REST nonce.
11
+ * @return {Object}
12
+ */
13
+ const fetchGetOptions = nonce => {
14
+ return {
15
+ headers: {
16
+ 'X-WP-Nonce': nonce
17
+ }
18
+ };
19
+ };
20
+
21
+ /**
22
+ * Build fetch POST options with the WP REST nonce header.
23
+ *
24
+ * @param {Object} postData Body to JSON-encode.
25
+ * @param {string} nonce WP REST nonce.
26
+ * @return {Object}
27
+ */
28
+ exports.fetchGetOptions = fetchGetOptions;
29
+ const fetchPostOptions = (postData, nonce) => {
30
+ return {
31
+ method: 'POST',
32
+ headers: {
33
+ 'Content-Type': 'application/json',
34
+ 'X-WP-Nonce': nonce
35
+ },
36
+ body: JSON.stringify(postData)
37
+ };
38
+ };
39
+ exports.fetchPostOptions = fetchPostOptions;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _fetchOptions = require("./fetchOptions");
7
+ Object.keys(_fetchOptions).forEach(function (key) {
8
+ if (key === "default" || key === "__esModule") return;
9
+ if (key in exports && exports[key] === _fetchOptions[key]) return;
10
+ Object.defineProperty(exports, key, {
11
+ enumerable: true,
12
+ get: function () {
13
+ return _fetchOptions[key];
14
+ }
15
+ });
16
+ });
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _data = require("@wordpress/data");
8
+ var _notices = require("@wordpress/notices");
9
+ var _components = require("@wordpress/components");
10
+ var _jsxRuntime = require("react/jsx-runtime");
11
+ const Notices = () => {
12
+ const {
13
+ removeNotice
14
+ } = (0, _data.useDispatch)(_notices.store);
15
+ const notices = (0, _data.useSelect)(select => select(_notices.store).getNotices());
16
+ if (notices.length === 0) {
17
+ return null;
18
+ }
19
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_components.NoticeList, {
20
+ notices: notices,
21
+ onRemove: removeNotice
22
+ });
23
+ };
24
+ var _default = exports.default = Notices;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "Notices", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _Notices.default;
10
+ }
11
+ });
12
+ var _Notices = _interopRequireDefault(require("./Notices"));
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "getMigratorRenderer", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _registry.getMigratorRenderer;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "getMigratorSettingsComponent", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _registry.getMigratorSettingsComponent;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "getResultsRenderer", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _registry.getResultsRenderer;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "registerMigratorRenderer", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _registry.registerMigratorRenderer;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "registerMigratorSettings", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _registry.registerMigratorSettings;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "registerOnReady", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _registerOnReady.default;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "registerResultsRenderer", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _registry.registerResultsRenderer;
46
+ }
47
+ });
48
+ var _registry = require("./registry");
49
+ var _registerOnReady = _interopRequireDefault(require("./registerOnReady"));
50
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _domReady = _interopRequireDefault(require("@wordpress/dom-ready"));
8
+ var _registry = require("./registry");
9
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
+ /**
11
+ * Register a batch of Data Migrations extensions on `domReady`.
12
+ *
13
+ * @param {Object} registrations Registration map.
14
+ * @param {Object} [registrations.migratorSettings] Map of migrator key -> Component.
15
+ * @param {Object} [registrations.resultsRenderers] Map of renderer key -> Component.
16
+ * @param {Object} [registrations.migratorRenderers] Map of migrator key -> Component.
17
+ */
18
+ const registerOnReady = (registrations = {}) => {
19
+ const {
20
+ migratorSettings = {},
21
+ resultsRenderers = {},
22
+ migratorRenderers = {}
23
+ } = registrations;
24
+ (0, _domReady.default)(() => {
25
+ Object.entries(migratorSettings).forEach(([key, Component]) => {
26
+ (0, _registry.registerMigratorSettings)(key, Component);
27
+ });
28
+ Object.entries(resultsRenderers).forEach(([key, Component]) => {
29
+ (0, _registry.registerResultsRenderer)(key, Component);
30
+ });
31
+ Object.entries(migratorRenderers).forEach(([key, Component]) => {
32
+ (0, _registry.registerMigratorRenderer)(key, Component);
33
+ });
34
+ });
35
+ };
36
+ var _default = exports.default = registerOnReady;
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.registerResultsRenderer = exports.registerMigratorSettings = exports.registerMigratorRenderer = exports.getResultsRenderer = exports.getMigratorSettingsComponent = exports.getMigratorRenderer = void 0;
7
+ /**
8
+ * Lightweight wrappers around the global window registry exposed by
9
+ * `max-marine-data-migrations`. Provides a typed-ish API for plugins
10
+ * extending Data Migrations to register migrator settings UIs, custom
11
+ * migrator renderers, and per-migrator results renderers.
12
+ *
13
+ * The Data Migrations plugin is responsible for initializing
14
+ * `window.maxMarineDataMigrations` and the `register*` functions on it
15
+ * before any consumer code runs (its admin scripts populate the slot in
16
+ * a `domReady` handler). These helpers will no-op silently if the host
17
+ * plugin has not been loaded.
18
+ */
19
+
20
+ const NAMESPACE = 'maxMarineDataMigrations';
21
+ const getRegistry = () => {
22
+ if (typeof window === 'undefined') {
23
+ return null;
24
+ }
25
+ return window[NAMESPACE] || null;
26
+ };
27
+
28
+ /**
29
+ * Ensure the registry namespace and a property collection exist on `window`.
30
+ *
31
+ * @param {string} bucket Property name to ensure on the registry.
32
+ * @return {Object|null}
33
+ */
34
+ const ensureRegistry = bucket => {
35
+ if (typeof window === 'undefined') {
36
+ return null;
37
+ }
38
+ window[NAMESPACE] = window[NAMESPACE] || {};
39
+ if (bucket && !window[NAMESPACE][bucket]) {
40
+ window[NAMESPACE][bucket] = {};
41
+ }
42
+ return window[NAMESPACE];
43
+ };
44
+
45
+ /**
46
+ * Register a migrator settings React component for a migrator key.
47
+ *
48
+ * @param {string} migratorKey
49
+ * @param {Function} Component
50
+ */
51
+ const registerMigratorSettings = (migratorKey, Component) => {
52
+ const registry = ensureRegistry('migratorSettings');
53
+ if (!registry) {
54
+ return;
55
+ }
56
+ if (typeof registry.registerMigratorSettings === 'function') {
57
+ registry.registerMigratorSettings(migratorKey, Component);
58
+ return;
59
+ }
60
+ registry.migratorSettings[migratorKey] = Component;
61
+ };
62
+
63
+ /**
64
+ * Register a results renderer React component for a migrator key.
65
+ *
66
+ * @param {string} rendererKey
67
+ * @param {Function} Component
68
+ */
69
+ exports.registerMigratorSettings = registerMigratorSettings;
70
+ const registerResultsRenderer = (rendererKey, Component) => {
71
+ const registry = ensureRegistry('resultsRenderers');
72
+ if (!registry) {
73
+ return;
74
+ }
75
+ if (typeof registry.registerResultsRenderer === 'function') {
76
+ registry.registerResultsRenderer(rendererKey, Component);
77
+ return;
78
+ }
79
+ registry.resultsRenderers[rendererKey] = Component;
80
+ };
81
+
82
+ /**
83
+ * Register a custom migrator renderer React component for a migrator key.
84
+ *
85
+ * @param {string} migratorKey
86
+ * @param {Function} Component
87
+ */
88
+ exports.registerResultsRenderer = registerResultsRenderer;
89
+ const registerMigratorRenderer = (migratorKey, Component) => {
90
+ const registry = ensureRegistry('migratorRenderers');
91
+ if (!registry) {
92
+ return;
93
+ }
94
+ if (typeof registry.registerMigratorRenderer === 'function') {
95
+ registry.registerMigratorRenderer(migratorKey, Component);
96
+ return;
97
+ }
98
+ registry.migratorRenderers[migratorKey] = Component;
99
+ };
100
+
101
+ /**
102
+ * Get the registered settings component for a migrator, if any.
103
+ *
104
+ * @param {string} migratorKey
105
+ * @return {Function|null}
106
+ */
107
+ exports.registerMigratorRenderer = registerMigratorRenderer;
108
+ const getMigratorSettingsComponent = migratorKey => {
109
+ const registry = getRegistry();
110
+ return registry?.migratorSettings?.[migratorKey] || null;
111
+ };
112
+
113
+ /**
114
+ * Get the registered results renderer for a migrator, if any.
115
+ *
116
+ * @param {string} rendererKey
117
+ * @return {Function|null}
118
+ */
119
+ exports.getMigratorSettingsComponent = getMigratorSettingsComponent;
120
+ const getResultsRenderer = rendererKey => {
121
+ const registry = getRegistry();
122
+ return registry?.resultsRenderers?.[rendererKey] || null;
123
+ };
124
+
125
+ /**
126
+ * Get the registered custom migrator renderer for a migrator, if any.
127
+ *
128
+ * @param {string} migratorKey
129
+ * @return {Function|null}
130
+ */
131
+ exports.getResultsRenderer = getResultsRenderer;
132
+ const getMigratorRenderer = migratorKey => {
133
+ const registry = getRegistry();
134
+ return registry?.migratorRenderers?.[migratorKey] || null;
135
+ };
136
+ exports.getMigratorRenderer = getMigratorRenderer;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "useBlurableContent", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _useBlurableContent.default;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "useDebouncedValue", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _useDebouncedValue.default;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "useValueChangeEffect", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _useValueChangeEffect.default;
22
+ }
23
+ });
24
+ var _useValueChangeEffect = _interopRequireDefault(require("./useValueChangeEffect"));
25
+ var _useBlurableContent = _interopRequireDefault(require("./useBlurableContent"));
26
+ var _useDebouncedValue = _interopRequireDefault(require("./useDebouncedValue"));
27
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ /**
8
+ * Custom hook for managing blurable content.
9
+ *
10
+ * @param {boolean} isBlurred Whether the content should be blurred.
11
+ * @return {Object} Object containing the blur class and state.
12
+ */
13
+ const useBlurableContent = isBlurred => {
14
+ return {
15
+ blurClass: isBlurred ? 'blurred' : '',
16
+ isBlurred
17
+ };
18
+ };
19
+ var _default = exports.default = useBlurableContent;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _element = require("@wordpress/element");
8
+ /**
9
+ * Debounce a rapidly-changing value.
10
+ *
11
+ * @param {*} value The value to debounce.
12
+ * @param {number} [delay] Debounce delay in milliseconds.
13
+ * @return {*}
14
+ */
15
+ const useDebouncedValue = (value, delay = 300) => {
16
+ const [debounced, setDebounced] = (0, _element.useState)(value);
17
+ const timeoutRef = (0, _element.useRef)(null);
18
+ (0, _element.useEffect)(() => {
19
+ if (timeoutRef.current) {
20
+ clearTimeout(timeoutRef.current);
21
+ }
22
+ timeoutRef.current = setTimeout(() => {
23
+ setDebounced(value);
24
+ }, delay);
25
+ return () => {
26
+ if (timeoutRef.current) {
27
+ clearTimeout(timeoutRef.current);
28
+ }
29
+ };
30
+ }, [value, delay]);
31
+ return debounced;
32
+ };
33
+ var _default = exports.default = useDebouncedValue;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _element = require("@wordpress/element");
8
+ /**
9
+ * Custom hook to create a fade effect when a value changes.
10
+ *
11
+ * @param {*} value The value to watch for changes.
12
+ * @param {string} speed Animation speed: 'default', 'fast', or 'slow' (default: 'default').
13
+ * @return {Object} Object containing displayValue, ref to attach to the element, and isAnimating state.
14
+ */
15
+ const useValueChangeEffect = (value, speed = 'default') => {
16
+ const stringValue = value === null || value === undefined ? '' : typeof value === 'object' ? JSON.stringify(value) : String(value);
17
+ const elementRef = (0, _element.useRef)(null);
18
+ const [prevValue, setPrevValue] = (0, _element.useState)(stringValue);
19
+ const [displayValue, setDisplayValue] = (0, _element.useState)(stringValue);
20
+ const [isAnimating, setIsAnimating] = (0, _element.useState)(false);
21
+ const getDuration = () => {
22
+ switch (speed) {
23
+ case 'fast':
24
+ return 200;
25
+ case 'slow':
26
+ return 600;
27
+ default:
28
+ return 400;
29
+ }
30
+ };
31
+ const getClassSuffix = () => {
32
+ switch (speed) {
33
+ case 'fast':
34
+ return '-fast';
35
+ case 'slow':
36
+ return '-slow';
37
+ default:
38
+ return '';
39
+ }
40
+ };
41
+ const duration = getDuration();
42
+ const classSuffix = getClassSuffix();
43
+ (0, _element.useEffect)(() => {
44
+ const newStringValue = value === null || value === undefined ? '' : typeof value === 'object' ? JSON.stringify(value) : String(value);
45
+ if (newStringValue !== prevValue && elementRef.current && !isAnimating) {
46
+ setIsAnimating(true);
47
+ elementRef.current.classList.add(`fade-out${classSuffix}`);
48
+ setTimeout(() => {
49
+ setDisplayValue(newStringValue);
50
+ if (elementRef.current) {
51
+ elementRef.current.classList.remove(`fade-out${classSuffix}`);
52
+ void elementRef.current.offsetWidth;
53
+ elementRef.current.classList.add(`fade-in${classSuffix}`);
54
+ setTimeout(() => {
55
+ if (elementRef.current) {
56
+ elementRef.current.classList.remove(`fade-in${classSuffix}`);
57
+ }
58
+ setIsAnimating(false);
59
+ setPrevValue(newStringValue);
60
+ }, duration);
61
+ }
62
+ }, duration);
63
+ } else if (newStringValue !== prevValue && !isAnimating) {
64
+ setDisplayValue(newStringValue);
65
+ setPrevValue(newStringValue);
66
+ }
67
+ }, [value, prevValue, isAnimating, duration, classSuffix]);
68
+ return {
69
+ displayValue,
70
+ elementRef,
71
+ isAnimating
72
+ };
73
+ };
74
+ var _default = exports.default = useValueChangeEffect;
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.utils = exports.settings = exports.hooks = exports.dataMigrations = exports.components = exports.api = void 0;
7
+ var _api = _interopRequireWildcard(require("./api"));
8
+ exports.api = _api;
9
+ var _components = _interopRequireWildcard(require("./components"));
10
+ exports.components = _components;
11
+ var _dataMigrations = _interopRequireWildcard(require("./data-migrations"));
12
+ exports.dataMigrations = _dataMigrations;
13
+ var _hooks = _interopRequireWildcard(require("./hooks"));
14
+ exports.hooks = _hooks;
15
+ var _settings = _interopRequireWildcard(require("./settings"));
16
+ exports.settings = _settings;
17
+ var _utils = _interopRequireWildcard(require("./utils"));
18
+ exports.utils = _utils;
19
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }