From ba66432bf9ef8171bcba0d24f9e1c194735f14e6 Mon Sep 17 00:00:00 2001 From: Troy Chaplin Date: Sat, 4 Apr 2026 10:19:58 -0400 Subject: [PATCH 1/3] add todo docs --- docs/DATASTORE.md | 135 +++++++++++++++++++++++++++++++ docs/REVIEW.md | 200 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 docs/DATASTORE.md create mode 100644 docs/REVIEW.md diff --git a/docs/DATASTORE.md b/docs/DATASTORE.md new file mode 100644 index 0000000..f2e5818 --- /dev/null +++ b/docs/DATASTORE.md @@ -0,0 +1,135 @@ +# Data Store Plan + +## Current State + +Validation state is computed independently by each consumer. The three core hooks — `GetInvalidBlocks`, `GetInvalidMeta`, and `GetInvalidEditorChecks` — each run their own `useSelect` calls against `core/editor` and `core/block-editor`. Two components call all three hooks: + +- **ValidationAPI.js** — locks/unlocks post saving based on errors, manages body classes +- **ValidationSidebar.js** — renders the sidebar UI with deduplicated issues + +This means every block edit triggers both components to independently re-derive the full validation state. + +Additionally, a lightweight in-memory `Map` exists at `src/editor/store/blockValidationStore.js` that shares per-block validation results between the `editor.BlockEdit` filter (writes) and `editor.BlockListBlock` filter (reads). This is not a `@wordpress/data` store — it's a plain module-scoped Map with no reactivity or selectors. + +### Current Consumers and Their Data Sources + +| Consumer | Hooks Used | WordPress Selectors | +|----------|-----------|-------------------| +| ValidationAPI.js | GetInvalidBlocks, GetInvalidMeta, GetInvalidEditorChecks | core/editor (dispatch: lock/unlock saving) | +| ValidationSidebar.js | GetInvalidBlocks, GetInvalidMeta, GetInvalidEditorChecks | core/block-editor (dispatch: selectBlock) | +| withErrorHandling.js (HOC) | useDebouncedValidation + validateBlock | core/block-editor (getBlock) | +| useMetaField.js | useMetaValidation | core/editor (getEditedPostAttribute, editPost) | +| useMetaValidation.js | validateAllMetaChecks | core/editor (getCurrentPostType, getEditedPostAttribute) | + +### Validation Rules Source + +All rules originate from PHP and are exposed via `window.ValidationAPI`: +- `validationRules` — block validation rules by block type +- `metaValidationRules` — meta validation rules by post type +- `editorValidationRules` — editor validation rules by post type +- `editorContext` — current editor context + +--- + +## Problem + +1. **Duplicated computation** — `ValidationAPI` and `ValidationSidebar` each independently call the same three hooks, running identical validation logic twice per change. +2. **No shared reactivity** — the `blockValidationStore` Map has no subscription mechanism, so consumers can't react to changes without their own `useSelect` wiring. +3. **Scaling concern** — adding a new consumer (e.g., toolbar badge, status bar) requires importing and re-running the same hooks again. + +--- + +## Proposed Solution: Custom `@wordpress/data` Store + +Create a `validation-api` store using `createReduxStore` that centralizes validation state and exposes it through selectors. + +### Store Namespace + +``` +validation-api +``` + +### State Shape + +```js +{ + blocks: [], // Array of invalid block results + meta: [], // Array of invalid meta results + editor: [], // Array of editor check issues +} +``` + +### Selectors + +| Selector | Returns | Description | +|----------|---------|-------------| +| `getInvalidBlocks(state)` | `Array` | All invalid block validation results | +| `getInvalidMeta(state)` | `Array` | All invalid meta validation results | +| `getInvalidEditorChecks(state)` | `Array` | All editor-level validation issues | +| `hasErrors(state)` | `boolean` | True if any error exists across all types | +| `hasWarnings(state)` | `boolean` | True if any warning exists (and no errors) | +| `getBlockValidation(state, clientId)` | `Object` | Per-block validation result (replaces Map store) | + +### Actions + +| Action | Payload | Description | +|--------|---------|-------------| +| `setInvalidBlocks(results)` | `Array` | Update block validation results | +| `setInvalidMeta(results)` | `Array` | Update meta validation results | +| `setInvalidEditorChecks(issues)` | `Array` | Update editor check results | +| `setBlockValidation(clientId, result)` | `string, Object` | Set per-block validation (replaces Map) | +| `clearBlockValidation(clientId)` | `string` | Remove per-block validation | + +### File Structure + +``` +src/editor/store/ + index.js // createReduxStore + register, barrel exports + selectors.js // All selector functions + actions.js // All action creators + reducer.js // State reducer + blockValidationStore.js // (removed — absorbed into store) +``` + +--- + +## Migration Path + +### Phase 1: Create the Store + +- Create `reducer.js`, `actions.js`, `selectors.js` +- Register the store via `createReduxStore` in `index.js` +- Keep existing hooks working alongside the store + +### Phase 2: Write to the Store + +- Update `GetInvalidBlocks`, `GetInvalidMeta`, and `GetInvalidEditorChecks` to dispatch results into the store after computing them +- Update `withErrorHandling.js` to use store actions instead of the Map + +### Phase 3: Read from the Store + +- Refactor `ValidationAPI.js` to read from `select('validation-api')` instead of calling hooks directly +- Refactor `ValidationSidebar.js` to read from `select('validation-api')` +- Only one component (or a top-level provider) needs to drive the validation hooks + +### Phase 4: Clean Up + +- Remove `blockValidationStore.js` (Map-based store) +- Simplify the three `Get*` hooks into internal update functions rather than public hooks +- Remove duplicate validation calls + +--- + +## Benefits + +- **Single computation** — validation runs once, multiple components subscribe +- **Memoized selectors** — `useSelect` bails out when results haven't changed, reducing re-renders +- **Decoupled consumers** — any component can `select('validation-api').hasErrors()` without importing hooks +- **Testable** — selectors and reducers are plain functions +- **Replaces Map store** — per-block validation moves into the same reactive system + +## Trade-offs + +- Adds boilerplate (reducer, actions, selectors) +- Slightly more complex mental model for a small plugin +- Store registration must happen early enough for all consumers diff --git a/docs/REVIEW.md b/docs/REVIEW.md new file mode 100644 index 0000000..daeea2e --- /dev/null +++ b/docs/REVIEW.md @@ -0,0 +1,200 @@ +# Code Review — Validation API Plugin + +Branch: `fix/wrapping-div` +Date: 2026-04-04 + +--- + +## 1. Dead Code / Stale Files + +### `src/editor/register.js:23-37` — No-op filter callback + +`addBlockValidationCategory()` returns `settings` unchanged. The `addFilter` call on `blocks.registerBlockType` does nothing. Remove the function, the filter registration, and the `addFilter` import if no longer needed. + +### `src/editor/hoc/index.js` — Empty barrel file + +Contains only comments explaining why nothing is exported. Imported by `src/editor/index.js` via `export * from './hoc'` but contributes nothing. Delete the file and remove the re-export. + +### `src/editor/index.js` — Unused barrel file + +Re-exports from `./components`, `./hoc`, and `./validation` but no file imports from `src/editor/index.js`. The entry point (`src/script.js`) imports each module directly. Delete this file. + +### `src/shared/index.js` — Unused barrel file + +Same pattern. All consumers import from specific paths. Delete this file. + +### `src/shared/utils/index.js` — Unused barrel file + +All consumers import directly from `src/shared/utils/validation`. Delete this file. + +### `src/editor/validation/index.js` — Unused barrel file + +Never imported. Delete this file. + +--- + +## 2. CSS Variable Mismatch + +### `settings.scss` references `--a11y-*` variables that don't exist + +`src/styles/_variables.scss` defines variables with the `--validation-api-*` prefix, but `settings.scss` references the old `--a11y-*` prefix throughout. All of these will resolve to nothing at runtime: + +- `--a11y-settings-space` +- `--a11y-light-grey` +- `--a11y-black` +- `--a11y-lightest-green` +- `--a11y-green` +- `--a11y-dark-green` +- `--a11y-lightest-grey` +- `--a11y-grey` +- `--a11y-dark-grey` +- `--a11y-font-small` +- `--a11y-dark-red` +- `--a11y-settings-space-mobile` (never defined anywhere under any prefix) + +**Fix:** Update all `--a11y-*` references in `settings.scss` to use `--validation-api-*`, and define `--validation-api-settings-space-mobile` if needed. + +### `includes/Core/Assets.php:149-163` — Dead inline CSS + +`enqueue_block_styles()` injects inline CSS defining `--a11y-red`, `--a11y-light-red`, `--a11y-dark-red`, `--a11y-yellow`, `--a11y-light-yellow`, `--a11y-dark-yellow`, `--a11y-border-width`, `--a11y-warning-icon`, and `--a11y-error-icon`. None of these `--a11y-*` variables are referenced in the editor SCSS files (which use `--validation-api-*`). The SVG icon URLs are injected but never consumed by any CSS rule. + +**Fix:** Remove the entire inline CSS block and the SVG URL generation above it (lines 144-165). + +### `src/styles/_variables.scss` — Unused variables + +These variables are defined but never referenced in any SCSS file that is actually built: + +- `--validation-api-light-blue` +- `--validation-api-blue` +- `--validation-api-medium-grey` +- `--validation-api-green` +- `--validation-api-lightest-green` +- `--validation-api-dark-green` +- `--validation-api-border-width` +- `--validation-api-settings-space` +- `--validation-api-font-small` + +**Fix:** Remove unused variables. If `settings.scss` is migrated to use `--validation-api-*`, some of these will become used again — audit after that migration. + +--- + +## 3. Orphaned Style Sheets + +### `src/admin.scss` and `src/settings.scss` — Not built by any entry point + +`webpack.config.js` has a single entry: `src/script.js`. The `styles.scss` imported there includes only the `src/styles/` partials. Neither `admin.scss` nor `settings.scss` is imported by any JS entry point, so they are never compiled into `build/`. + +**Fix:** If these are needed for a settings page, add a separate webpack entry point. If they are leftover from a removed feature, delete them. + +--- + +## 4. Inconsistent Colors in JS + +### Three different warning yellows + +| Location | Value | +|----------|-------| +| `ValidationToolbarButton.js:38` | `#d8c600` | +| `ValidationSidebar.js:209` | `#dbc900` | +| `_variables.scss` | `--validation-api-yellow: #f0dc00` | + +**Fix:** Standardize to one value. Both JS files should use the same hex code, ideally matching the CSS variable. + +--- + +## 5. Redundant / Stale JS Code + +### `src/shared/utils/validation/getInvalidBlocks.js:144` — Redundant filter + +```js +return invalidBlocks.filter(result => !result.isValid); +``` + +`getInvalidBlocksRecursive` already only pushes results where `!result.isValid`. The `.filter()` is redundant. + +### `src/editor/components/ValidationSidebar.js:272-277` — Dead `handleMetaClick` + +Empty function with eslint-disable for unused-vars. Never called anywhere. Remove it. + +### `src/editor/validation/editor/validateEditor.js:68` — Redundant `checkName` assignment + +```js +issue.checkName = checkName; +``` + +`createIssue()` already sets `checkName` on the returned object. Same issue in `src/editor/validation/meta/validateMeta.js:113`. + +### `src/editor/register.js:51-62` — Over-engineered Proxy + +The `blockChecksArray` Proxy wraps a simple window property lookup. Since `window.ValidationAPI.validationRules` is set once by `wp_localize_script` before JS executes, the only consumer (`validateBlock.js`) can read it directly: + +```js +const checks = window.ValidationAPI?.validationRules?.[blockType] || {}; +``` + +Remove the Proxy export from `register.js` and inline the access in `validateBlock.js`. + +--- + +## 6. Import / Global Consistency + +### `src/editor/hoc/withBlockValidationClasses.js:39` — Uses `wp.hooks.addFilter` global + +All other files import `addFilter` from `@wordpress/hooks`. This file uses the global `wp.hooks.addFilter` directly. Import it for consistency. + +--- + +## 7. PHP Observations + +### Redundant type checks in all three registries + +`Block\Registry::register_check()`, `Editor\Registry::register_editor_check()`, and `Meta\Registry::register_meta_check()` all check `! is_string()` and `! is_array()` on parameters that are already type-hinted as `string` and `array` in the method signature. PHP enforces these at call time, making the checks unreachable. + +**Files:** +- `includes/Block/Registry.php:68,73,78` +- `includes/Editor/Registry.php:81,86,91` +- `includes/Meta/Registry.php:82,87,92,98` + +### `includes/Core/Traits/EditorDetection.php` — Duplicated post type array + +`get_editor_context()` (line 40) and `is_site_editor_context()` (line 115) both hardcode `array('wp_template', 'wp_template_part')`. Define once as a class constant. + +--- + +## 8. Naming Inconsistencies + +### `has-meta-validation-errors` / `has-meta-validation-warnings` body classes + +Set in `ValidationAPI.js:163-176`, these classes reflect errors from blocks, meta, AND editor checks — not just meta. The `meta` prefix is misleading. Consider `has-validation-errors` / `has-validation-warnings`. + +### `blockChecksArray` export name + +Defined in `register.js:51`. It's a Proxy object, not an array. If kept, rename to `blockChecks`. + +### `settings.scss` double-comment lines + +Lines 209 and 222 have `// //` prefix — leftover from toggling code blocks. Clean up to single `//`. + +--- + +## 9. Action Summary + +| Priority | Action | Files | +|----------|--------|-------| +| High | Fix `--a11y-*` to `--validation-api-*` variable mismatch | `settings.scss` | +| High | Remove dead inline CSS (`--a11y-*` vars + SVG URLs) | `Assets.php` | +| High | Standardize warning yellow color | `ValidationToolbarButton.js`, `ValidationSidebar.js` | +| Med | Delete 6 unused barrel files | `editor/index.js`, `editor/hoc/index.js`, `shared/index.js`, `shared/utils/index.js`, `editor/validation/index.js` | +| Med | Remove no-op `addBlockValidationCategory` + filter | `register.js` | +| Med | Remove unused CSS variables | `_variables.scss` | +| Med | Remove Proxy, inline window access | `register.js`, `validateBlock.js` | +| Med | Remove dead `handleMetaClick` | `ValidationSidebar.js` | +| Med | Remove redundant `.filter()` | `getInvalidBlocks.js` | +| Med | Remove redundant `checkName` re-assignments | `validateEditor.js`, `validateMeta.js` | +| Med | Verify `admin.scss` / `settings.scss` build status | Webpack config | +| Low | Remove redundant PHP type checks | 3 registry files | +| Low | Import `addFilter` in `withBlockValidationClasses.js` | `withBlockValidationClasses.js` | +| Low | Clean up double-comment lines | `settings.scss` | +| Low | Rename misleading body classes | `ValidationAPI.js` | +| Low | Rename `blockChecksArray` | `register.js` | +| Low | Consolidate duplicated site-editor post type array | `EditorDetection.php` | From 5992aa45a4b22b9532cb9b21ec48d48bda46c351 Mon Sep 17 00:00:00 2001 From: Troy Chaplin Date: Sat, 4 Apr 2026 11:04:58 -0400 Subject: [PATCH 2/3] clean up old code --- build/validation-api-rtl.css | 2 +- build/validation-api.asset.php | 2 +- build/validation-api.css | 2 +- build/validation-api.js | 705 +++++++++--------- docs/REVIEW.md | 200 ----- includes/Block/Registry.php | 9 +- includes/Core/Assets.php | 23 - includes/Core/Traits/EditorDetection.php | 20 +- includes/Editor/Registry.php | 9 +- includes/Meta/Registry.php | 11 +- src/admin.scss | 25 - src/editor/components/ValidationIcon.js | 2 +- src/editor/components/ValidationSidebar.js | 16 - .../components/ValidationToolbarButton.js | 2 +- src/editor/hoc/index.js | 8 - src/editor/hoc/withBlockValidationClasses.js | 7 +- src/editor/index.js | 9 - src/editor/register.js | 52 -- src/editor/validation/ValidationAPI.js | 18 +- src/editor/validation/blocks/validateBlock.js | 3 +- .../validation/editor/validateEditor.js | 2 - src/editor/validation/index.js | 9 - src/editor/validation/meta/validateMeta.js | 2 - src/settings.scss | 356 --------- src/shared/index.js | 8 - src/shared/utils/index.js | 7 - .../utils/validation/getInvalidBlocks.js | 2 +- src/styles/_variables.scss | 9 - src/styles/validation-sidebar.scss | 4 + 29 files changed, 389 insertions(+), 1135 deletions(-) delete mode 100644 docs/REVIEW.md delete mode 100644 src/admin.scss delete mode 100644 src/editor/hoc/index.js delete mode 100644 src/editor/index.js delete mode 100644 src/editor/validation/index.js delete mode 100644 src/settings.scss delete mode 100644 src/shared/index.js delete mode 100644 src/shared/utils/index.js diff --git a/build/validation-api-rtl.css b/build/validation-api-rtl.css index 6165f60..6839069 100644 --- a/build/validation-api-rtl.css +++ b/build/validation-api-rtl.css @@ -1 +1 @@ -:root{--validation-api-white:#fff;--validation-api-light-blue:#dfe9ee;--validation-api-blue:#507a96;--validation-api-lightest-grey:#f7f7f7;--validation-api-light-grey:#e8e8e8;--validation-api-grey:#b9b9b9;--validation-api-medium-grey:#666;--validation-api-dark-grey:#474747;--validation-api-black:#1d2327;--validation-api-red:#d82000;--validation-api-light-red:#ffe4e0;--validation-api-dark-red:#a21800;--validation-api-yellow:#f0dc00;--validation-api-light-yellow:#fffde2;--validation-api-dark-yellow:#807500;--validation-api-lightest-green:#f1fcf2;--validation-api-green:#2aad40;--validation-api-dark-green:#1b6027;--validation-api-border-width:3px solid;--validation-api-settings-space:32px;--validation-api-font-small:0.8rem}.validation-api-block-error,.validation-api-block-warning{position:relative}.validation-api-block-error:before,.validation-api-block-warning:before{clip-path:polygon(0 0,100% 0,0 100%);content:"";height:15px;right:-1px;pointer-events:none;position:absolute;top:-1px;width:15px;z-index:20}.validation-api-block-error:after,.validation-api-block-warning:after{box-shadow:0 0 0 2px var(--validation-api-white)}.validation-api-block-error:before{background-color:var(--validation-api-red)}.validation-api-block-warning:before{background-color:var(--validation-api-yellow)}.validation-api-indicator-errors .validation-api-indicator-section-title-circle,.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{border-radius:2px;display:inline-block;height:10px;margin-bottom:2px;margin-left:8px;vertical-align:middle;width:10px}.validation-api-indicator-errors .validation-api-indicator-section-title-circle{background-color:var(--validation-api-red)}.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{background-color:var(--validation-api-yellow)}.validation-api-indicator-section+.validation-api-indicator-section{margin-top:20px}h2.validation-api-indicator-section-title{font-size:14px;line-height:1.3;margin:0 0 10px}.validation-api-indicator-modal-content .validation-api-indicator-errors ul,.validation-api-indicator-modal-content .validation-api-indicator-warnings ul{font-size:12px;margin:0 3px 0 0;padding:0 28px 0 0}.validation-api-indicator-modal-content .validation-api-indicator-errors li,.validation-api-indicator-modal-content .validation-api-indicator-warnings li{list-style-type:disc;margin:0;padding:0 0 4px}.validation-api-indicator-modal-content .validation-api-indicator-errors li:last-child,.validation-api-indicator-modal-content .validation-api-indicator-warnings li:last-child{padding-bottom:0}.validation-api-meta-error .components-select-control__input,.validation-api-meta-error .components-text-control__input,.validation-api-meta-error .components-textarea-control__input{border-right:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input,.validation-api-meta-warning .components-text-control__input,.validation-api-meta-warning .components-textarea-control__input{border-right:3px solid var(--validation-api-yellow)}.validation-api-meta-error .components-select-control__input:focus,.validation-api-meta-error .components-text-control__input:focus,.validation-api-meta-error .components-textarea-control__input:focus{border:none;border-right:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input:focus,.validation-api-meta-warning .components-text-control__input:focus,.validation-api-meta-warning .components-textarea-control__input:focus{border:none;border-right:3px solid var(--validation-api-yellow)}.validation-api-error-text,.validation-api-warning-text{display:block;font-weight:500;margin-top:4px}.validation-api-error-text{color:var(--validation-api-dark-red)}.validation-api-warning-text{color:var(--validation-api-dark-yellow)}.components-button.is-pressed .validation-api-sidebar-icon path{fill:#fff}.validation-api-errors-panel>.components-panel__body-title button:before,.validation-api-warnings-panel>.components-panel__body-title button:before{border-radius:2px;content:"";flex-shrink:0;height:14px;margin-left:8px;width:14px}.validation-api-errors-panel>.components-panel__body-title button:before{background-color:var(--validation-api-red)}.validation-api-warnings-panel>.components-panel__body-title button:before{background-color:var(--validation-api-yellow)}.validation-api-errors-panel .components-panel__row+.components-panel__row,.validation-api-warnings-panel .components-panel__row+.components-panel__row{margin-top:20px}.validation-api-error-group p,.validation-api-warning-group p{font-weight:500;margin:0 0 6px}.validation-api-error-group ul,.validation-api-warning-group ul{margin:0 20px 0 0;padding:0}.validation-api-error-group li,.validation-api-warning-group li{list-style-type:disc;margin:0;padding:0 0 6px}.validation-api-error-group li:last-child,.validation-api-warning-group li:last-child{padding-bottom:0}.validation-api-error-group .validation-api-issue-link,.validation-api-warning-group .validation-api-issue-link{background:none;border:none;color:var(--wp-admin-theme-color);cursor:pointer;font-weight:500;margin:0;padding:0;text-decoration:underline}.validation-api-error-group .validation-api-issue-link:hover,.validation-api-warning-group .validation-api-issue-link:hover{color:color-mix(in srgb,var(--wp-admin-theme-color) 60%,#000)} +:root{--validation-api-white:#fff;--validation-api-lightest-grey:#f7f7f7;--validation-api-light-grey:#e8e8e8;--validation-api-grey:#b9b9b9;--validation-api-dark-grey:#474747;--validation-api-black:#1d2327;--validation-api-red:#d82000;--validation-api-light-red:#ffe4e0;--validation-api-dark-red:#a21800;--validation-api-yellow:#f0dc00;--validation-api-light-yellow:#fffde2;--validation-api-dark-yellow:#807500}.validation-api-block-error,.validation-api-block-warning{position:relative}.validation-api-block-error:before,.validation-api-block-warning:before{clip-path:polygon(0 0,100% 0,0 100%);content:"";height:15px;right:-1px;pointer-events:none;position:absolute;top:-1px;width:15px;z-index:20}.validation-api-block-error:after,.validation-api-block-warning:after{box-shadow:0 0 0 2px var(--validation-api-white)}.validation-api-block-error:before{background-color:var(--validation-api-red)}.validation-api-block-warning:before{background-color:var(--validation-api-yellow)}.validation-api-indicator-errors .validation-api-indicator-section-title-circle,.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{border-radius:2px;display:inline-block;height:10px;margin-bottom:2px;margin-left:8px;vertical-align:middle;width:10px}.validation-api-indicator-errors .validation-api-indicator-section-title-circle{background-color:var(--validation-api-red)}.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{background-color:var(--validation-api-yellow)}.validation-api-indicator-section+.validation-api-indicator-section{margin-top:20px}h2.validation-api-indicator-section-title{font-size:14px;line-height:1.3;margin:0 0 10px}.validation-api-indicator-modal-content .validation-api-indicator-errors ul,.validation-api-indicator-modal-content .validation-api-indicator-warnings ul{font-size:12px;margin:0 3px 0 0;padding:0 28px 0 0}.validation-api-indicator-modal-content .validation-api-indicator-errors li,.validation-api-indicator-modal-content .validation-api-indicator-warnings li{list-style-type:disc;margin:0;padding:0 0 4px}.validation-api-indicator-modal-content .validation-api-indicator-errors li:last-child,.validation-api-indicator-modal-content .validation-api-indicator-warnings li:last-child{padding-bottom:0}.validation-api-meta-error .components-select-control__input,.validation-api-meta-error .components-text-control__input,.validation-api-meta-error .components-textarea-control__input{border-right:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input,.validation-api-meta-warning .components-text-control__input,.validation-api-meta-warning .components-textarea-control__input{border-right:3px solid var(--validation-api-yellow)}.validation-api-meta-error .components-select-control__input:focus,.validation-api-meta-error .components-text-control__input:focus,.validation-api-meta-error .components-textarea-control__input:focus{border:none;border-right:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input:focus,.validation-api-meta-warning .components-text-control__input:focus,.validation-api-meta-warning .components-textarea-control__input:focus{border:none;border-right:3px solid var(--validation-api-yellow)}.validation-api-error-text,.validation-api-warning-text{display:block;font-weight:500;margin-top:4px}.validation-api-error-text{color:var(--validation-api-dark-red)}.validation-api-warning-text{color:var(--validation-api-dark-yellow)}.components-button.is-pressed .validation-api-sidebar-icon path{fill:#fff}.validation-api-sidebar-icon{padding:2px 0}.validation-api-errors-panel>.components-panel__body-title button:before,.validation-api-warnings-panel>.components-panel__body-title button:before{border-radius:2px;content:"";flex-shrink:0;height:14px;margin-left:8px;width:14px}.validation-api-errors-panel>.components-panel__body-title button:before{background-color:var(--validation-api-red)}.validation-api-warnings-panel>.components-panel__body-title button:before{background-color:var(--validation-api-yellow)}.validation-api-errors-panel .components-panel__row+.components-panel__row,.validation-api-warnings-panel .components-panel__row+.components-panel__row{margin-top:20px}.validation-api-error-group p,.validation-api-warning-group p{font-weight:500;margin:0 0 6px}.validation-api-error-group ul,.validation-api-warning-group ul{margin:0 20px 0 0;padding:0}.validation-api-error-group li,.validation-api-warning-group li{list-style-type:disc;margin:0;padding:0 0 6px}.validation-api-error-group li:last-child,.validation-api-warning-group li:last-child{padding-bottom:0}.validation-api-error-group .validation-api-issue-link,.validation-api-warning-group .validation-api-issue-link{background:none;border:none;color:var(--wp-admin-theme-color);cursor:pointer;font-weight:500;margin:0;padding:0;text-decoration:underline}.validation-api-error-group .validation-api-issue-link:hover,.validation-api-warning-group .validation-api-issue-link:hover{color:color-mix(in srgb,var(--wp-admin-theme-color) 60%,#000)} diff --git a/build/validation-api.asset.php b/build/validation-api.asset.php index e0b9ab6..7ad85b7 100644 --- a/build/validation-api.asset.php +++ b/build/validation-api.asset.php @@ -1 +1 @@ - array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-plugins'), 'version' => '1629071f5778bb3a44b5'); + array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-plugins'), 'version' => '52847e18bf95c1b9a5a4'); diff --git a/build/validation-api.css b/build/validation-api.css index 1dcb5c0..057c3e0 100644 --- a/build/validation-api.css +++ b/build/validation-api.css @@ -1 +1 @@ -:root{--validation-api-white:#fff;--validation-api-light-blue:#dfe9ee;--validation-api-blue:#507a96;--validation-api-lightest-grey:#f7f7f7;--validation-api-light-grey:#e8e8e8;--validation-api-grey:#b9b9b9;--validation-api-medium-grey:#666;--validation-api-dark-grey:#474747;--validation-api-black:#1d2327;--validation-api-red:#d82000;--validation-api-light-red:#ffe4e0;--validation-api-dark-red:#a21800;--validation-api-yellow:#f0dc00;--validation-api-light-yellow:#fffde2;--validation-api-dark-yellow:#807500;--validation-api-lightest-green:#f1fcf2;--validation-api-green:#2aad40;--validation-api-dark-green:#1b6027;--validation-api-border-width:3px solid;--validation-api-settings-space:32px;--validation-api-font-small:0.8rem}.validation-api-block-error,.validation-api-block-warning{position:relative}.validation-api-block-error:before,.validation-api-block-warning:before{clip-path:polygon(0 0,100% 0,0 100%);content:"";height:15px;left:-1px;pointer-events:none;position:absolute;top:-1px;width:15px;z-index:20}.validation-api-block-error:after,.validation-api-block-warning:after{box-shadow:0 0 0 2px var(--validation-api-white)}.validation-api-block-error:before{background-color:var(--validation-api-red)}.validation-api-block-warning:before{background-color:var(--validation-api-yellow)}.validation-api-indicator-errors .validation-api-indicator-section-title-circle,.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{border-radius:2px;display:inline-block;height:10px;margin-bottom:2px;margin-right:8px;vertical-align:middle;width:10px}.validation-api-indicator-errors .validation-api-indicator-section-title-circle{background-color:var(--validation-api-red)}.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{background-color:var(--validation-api-yellow)}.validation-api-indicator-section+.validation-api-indicator-section{margin-top:20px}h2.validation-api-indicator-section-title{font-size:14px;line-height:1.3;margin:0 0 10px}.validation-api-indicator-modal-content .validation-api-indicator-errors ul,.validation-api-indicator-modal-content .validation-api-indicator-warnings ul{font-size:12px;margin:0 0 0 3px;padding:0 0 0 28px}.validation-api-indicator-modal-content .validation-api-indicator-errors li,.validation-api-indicator-modal-content .validation-api-indicator-warnings li{list-style-type:disc;margin:0;padding:0 0 4px}.validation-api-indicator-modal-content .validation-api-indicator-errors li:last-child,.validation-api-indicator-modal-content .validation-api-indicator-warnings li:last-child{padding-bottom:0}.validation-api-meta-error .components-select-control__input,.validation-api-meta-error .components-text-control__input,.validation-api-meta-error .components-textarea-control__input{border-left:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input,.validation-api-meta-warning .components-text-control__input,.validation-api-meta-warning .components-textarea-control__input{border-left:3px solid var(--validation-api-yellow)}.validation-api-meta-error .components-select-control__input:focus,.validation-api-meta-error .components-text-control__input:focus,.validation-api-meta-error .components-textarea-control__input:focus{border:none;border-left:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input:focus,.validation-api-meta-warning .components-text-control__input:focus,.validation-api-meta-warning .components-textarea-control__input:focus{border:none;border-left:3px solid var(--validation-api-yellow)}.validation-api-error-text,.validation-api-warning-text{display:block;font-weight:500;margin-top:4px}.validation-api-error-text{color:var(--validation-api-dark-red)}.validation-api-warning-text{color:var(--validation-api-dark-yellow)}.components-button.is-pressed .validation-api-sidebar-icon path{fill:#fff}.validation-api-errors-panel>.components-panel__body-title button:before,.validation-api-warnings-panel>.components-panel__body-title button:before{border-radius:2px;content:"";flex-shrink:0;height:14px;margin-right:8px;width:14px}.validation-api-errors-panel>.components-panel__body-title button:before{background-color:var(--validation-api-red)}.validation-api-warnings-panel>.components-panel__body-title button:before{background-color:var(--validation-api-yellow)}.validation-api-errors-panel .components-panel__row+.components-panel__row,.validation-api-warnings-panel .components-panel__row+.components-panel__row{margin-top:20px}.validation-api-error-group p,.validation-api-warning-group p{font-weight:500;margin:0 0 6px}.validation-api-error-group ul,.validation-api-warning-group ul{margin:0 0 0 20px;padding:0}.validation-api-error-group li,.validation-api-warning-group li{list-style-type:disc;margin:0;padding:0 0 6px}.validation-api-error-group li:last-child,.validation-api-warning-group li:last-child{padding-bottom:0}.validation-api-error-group .validation-api-issue-link,.validation-api-warning-group .validation-api-issue-link{background:none;border:none;color:var(--wp-admin-theme-color);cursor:pointer;font-weight:500;margin:0;padding:0;text-decoration:underline}.validation-api-error-group .validation-api-issue-link:hover,.validation-api-warning-group .validation-api-issue-link:hover{color:color-mix(in srgb,var(--wp-admin-theme-color) 60%,#000)} +:root{--validation-api-white:#fff;--validation-api-lightest-grey:#f7f7f7;--validation-api-light-grey:#e8e8e8;--validation-api-grey:#b9b9b9;--validation-api-dark-grey:#474747;--validation-api-black:#1d2327;--validation-api-red:#d82000;--validation-api-light-red:#ffe4e0;--validation-api-dark-red:#a21800;--validation-api-yellow:#f0dc00;--validation-api-light-yellow:#fffde2;--validation-api-dark-yellow:#807500}.validation-api-block-error,.validation-api-block-warning{position:relative}.validation-api-block-error:before,.validation-api-block-warning:before{clip-path:polygon(0 0,100% 0,0 100%);content:"";height:15px;left:-1px;pointer-events:none;position:absolute;top:-1px;width:15px;z-index:20}.validation-api-block-error:after,.validation-api-block-warning:after{box-shadow:0 0 0 2px var(--validation-api-white)}.validation-api-block-error:before{background-color:var(--validation-api-red)}.validation-api-block-warning:before{background-color:var(--validation-api-yellow)}.validation-api-indicator-errors .validation-api-indicator-section-title-circle,.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{border-radius:2px;display:inline-block;height:10px;margin-bottom:2px;margin-right:8px;vertical-align:middle;width:10px}.validation-api-indicator-errors .validation-api-indicator-section-title-circle{background-color:var(--validation-api-red)}.validation-api-indicator-warnings .validation-api-indicator-section-title-circle{background-color:var(--validation-api-yellow)}.validation-api-indicator-section+.validation-api-indicator-section{margin-top:20px}h2.validation-api-indicator-section-title{font-size:14px;line-height:1.3;margin:0 0 10px}.validation-api-indicator-modal-content .validation-api-indicator-errors ul,.validation-api-indicator-modal-content .validation-api-indicator-warnings ul{font-size:12px;margin:0 0 0 3px;padding:0 0 0 28px}.validation-api-indicator-modal-content .validation-api-indicator-errors li,.validation-api-indicator-modal-content .validation-api-indicator-warnings li{list-style-type:disc;margin:0;padding:0 0 4px}.validation-api-indicator-modal-content .validation-api-indicator-errors li:last-child,.validation-api-indicator-modal-content .validation-api-indicator-warnings li:last-child{padding-bottom:0}.validation-api-meta-error .components-select-control__input,.validation-api-meta-error .components-text-control__input,.validation-api-meta-error .components-textarea-control__input{border-left:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input,.validation-api-meta-warning .components-text-control__input,.validation-api-meta-warning .components-textarea-control__input{border-left:3px solid var(--validation-api-yellow)}.validation-api-meta-error .components-select-control__input:focus,.validation-api-meta-error .components-text-control__input:focus,.validation-api-meta-error .components-textarea-control__input:focus{border:none;border-left:3px solid var(--validation-api-red)}.validation-api-meta-warning .components-select-control__input:focus,.validation-api-meta-warning .components-text-control__input:focus,.validation-api-meta-warning .components-textarea-control__input:focus{border:none;border-left:3px solid var(--validation-api-yellow)}.validation-api-error-text,.validation-api-warning-text{display:block;font-weight:500;margin-top:4px}.validation-api-error-text{color:var(--validation-api-dark-red)}.validation-api-warning-text{color:var(--validation-api-dark-yellow)}.components-button.is-pressed .validation-api-sidebar-icon path{fill:#fff}.validation-api-sidebar-icon{padding:2px 0}.validation-api-errors-panel>.components-panel__body-title button:before,.validation-api-warnings-panel>.components-panel__body-title button:before{border-radius:2px;content:"";flex-shrink:0;height:14px;margin-right:8px;width:14px}.validation-api-errors-panel>.components-panel__body-title button:before{background-color:var(--validation-api-red)}.validation-api-warnings-panel>.components-panel__body-title button:before{background-color:var(--validation-api-yellow)}.validation-api-errors-panel .components-panel__row+.components-panel__row,.validation-api-warnings-panel .components-panel__row+.components-panel__row{margin-top:20px}.validation-api-error-group p,.validation-api-warning-group p{font-weight:500;margin:0 0 6px}.validation-api-error-group ul,.validation-api-warning-group ul{margin:0 0 0 20px;padding:0}.validation-api-error-group li,.validation-api-warning-group li{list-style-type:disc;margin:0;padding:0 0 6px}.validation-api-error-group li:last-child,.validation-api-warning-group li:last-child{padding-bottom:0}.validation-api-error-group .validation-api-issue-link,.validation-api-warning-group .validation-api-issue-link{background:none;border:none;color:var(--wp-admin-theme-color);cursor:pointer;font-weight:500;margin:0;padding:0;text-decoration:underline}.validation-api-error-group .validation-api-issue-link:hover,.validation-api-warning-group .validation-api-issue-link:hover{color:color-mix(in srgb,var(--wp-admin-theme-color) 60%,#000)} diff --git a/build/validation-api.js b/build/validation-api.js index 36cfd02..9fbb094 100644 --- a/build/validation-api.js +++ b/build/validation-api.js @@ -1,12 +1,11 @@ (() => { 'use strict'; const e = window.wp.plugins, - t = window.wp.hooks, - r = window.wp.data, - n = window.wp.element; - function a(e) { + t = window.wp.data, + r = window.wp.element; + function n(e) { return ( - (a = + (n = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (e) { return typeof e; @@ -19,10 +18,10 @@ ? 'symbol' : typeof e; }), - a(e) + n(e) ); } - function i(e, t) { + function o(e, t) { var r = Object.keys(e); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); @@ -34,35 +33,35 @@ } return r; } - function o(e) { + function a(e) { for (var t = 1; t < arguments.length; t++) { var r = null != arguments[t] ? arguments[t] : {}; t % 2 - ? i(Object(r), !0).forEach(function (t) { - l(e, t, r[t]); + ? o(Object(r), !0).forEach(function (t) { + i(e, t, r[t]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r)) - : i(Object(r)).forEach(function (t) { + : o(Object(r)).forEach(function (t) { Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t)); }); } return e; } - function l(e, t, r) { + function i(e, t, r) { return ( (t = (function (e) { var t = (function (e) { - if ('object' != a(e) || !e) return e; + if ('object' != n(e) || !e) return e; var t = e[Symbol.toPrimitive]; if (void 0 !== t) { var r = t.call(e, 'string'); - if ('object' != a(r)) return r; + if ('object' != n(r)) return r; throw new TypeError('@@toPrimitive must return a primitive value.'); } return String(e); })(e); - return 'symbol' == a(t) ? t : t + ''; + return 'symbol' == n(t) ? t : t + ''; })(t)) in e ? Object.defineProperty(e, t, { value: r, @@ -74,55 +73,56 @@ e ); } - var c = function (e, t) { + var l = function (e, t) { return e.filter(function (e) { return e.type === t; }); }, + c = function (e) { + return l(e, 'error'); + }, u = function (e) { - return c(e, 'error'); + return l(e, 'warning'); }, s = function (e) { - return c(e, 'warning'); - }, - f = function (e) { return e.some(function (e) { return 'error' === e.type; }); }, - m = function (e) { + f = function (e) { return e.some(function (e) { return 'warning' === e.type; }); }, - d = function (e) { + m = function (e) { return null != e && !1 !== e.enabled; }, - p = function (e, t) { + d = function (e, t) { var r = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}, n = e.message || '', - a = e.error_msg || n, + o = e.error_msg || n, i = e.warning_msg || e.error_msg || n, l = e.level || 'error'; - return o( + return a( { check: t, checkName: t, type: l, priority: 'error' === l ? 1 : 'warning' === l ? 2 : 3, message: n, - errorMsg: a, + errorMsg: o, warningMsg: i, - error_msg: a, + error_msg: o, warning_msg: i, }, r ); }, - v = function (e) { + p = function (e) { var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}; - return o({ isValid: 0 === e.length, issues: e, hasErrors: f(e), hasWarnings: m(e) }, t); + return a({ isValid: 0 === e.length, issues: e, hasErrors: s(e), hasWarnings: f(e) }, t); }; + const v = window.wp.hooks; function y(e, t) { (null == t || t > e.length) && (t = e.length); for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r]; @@ -130,20 +130,27 @@ } var b, g = function (e) { - var r = e.name, + var t, + r = e.name, n = e.attributes, - a = [], - i = G[r] || {}; - if (0 === Object.keys(i).length) + o = [], + a = + (null === (t = window.ValidationAPI) || + void 0 === t || + null === (t = t.validationRules) || + void 0 === t + ? void 0 + : t[r]) || {}; + if (0 === Object.keys(a).length) return { isValid: !0, issues: [], mode: 'none', clientId: e.clientId, name: r }; - Object.entries(i).forEach(function (i) { - var o, - l, - c = - ((l = 2), + Object.entries(a).forEach(function (t) { + var a, + i, + l = + ((i = 2), (function (e) { if (Array.isArray(e)) return e; - })((o = i)) || + })((a = t)) || (function (e, t) { var r = null == e @@ -152,40 +159,40 @@ e['@@iterator']; if (null != r) { var n, + o, a, i, - o, l = [], c = !0, u = !1; try { - if (((i = (r = r.call(e)).next), 0 === t)) { + if (((a = (r = r.call(e)).next), 0 === t)) { if (Object(r) !== r) return; c = !1; } else for ( ; - !(c = (n = i.call(r)).done) && + !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t); c = !0 ); } catch (e) { - ((u = !0), (a = e)); + ((u = !0), (o = e)); } finally { try { if ( !c && null != r.return && - ((o = r.return()), Object(o) !== o) + ((i = r.return()), Object(i) !== i) ) return; } finally { - if (u) throw a; + if (u) throw o; } } return l; } - })(o, l) || + })(a, i) || (function (e, t) { if (e) { if ('string' == typeof e) return y(e, t); @@ -200,25 +207,25 @@ : void 0 ); } - })(o, l) || + })(a, i) || (function () { throw new TypeError( 'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.' ); })()), - u = c[0], - s = c[1]; - if (d(s)) { - var f = !0; - ('function' == typeof s.validator && (f = s.validator(n, e)), - (f = (0, t.applyFilters)('validation_api_validate_block', f, r, n, u, e)) || - a.push(p(s, u))); + c = l[0], + u = l[1]; + if (m(u)) { + var s = !0; + ('function' == typeof u.validator && (s = u.validator(n, e)), + (s = (0, v.applyFilters)('validation_api_validate_block', s, r, n, c, e)) || + o.push(d(u, c))); } }); - var o = 'none'; + var i = 'none'; return ( - f(a) ? (o = 'error') : m(a) && (o = 'warning'), - v(a, { mode: o, clientId: e.clientId, name: r }) + s(o) ? (i = 'error') : f(o) && (i = 'warning'), + p(o, { mode: i, clientId: e.clientId, name: r }) ); }; function w(e, t) { @@ -297,24 +304,24 @@ ); } var n, - a = !0, - i = !1; + o = !0, + a = !1; return { s: function () { t = t.call(e); }, n: function () { var e = t.next(); - return ((a = e.done), e); + return ((o = e.done), e); }, e: function (e) { - ((i = !0), (n = e)); + ((a = !0), (n = e)); }, f: function () { try { - a || null == t.return || t.return(); + o || null == t.return || t.return(); } finally { - if (i) throw n; + if (a) throw n; } }, }; @@ -324,8 +331,8 @@ var n = t.value; if ('core/post-content' === n.name) return n; if (n.innerBlocks && n.innerBlocks.length > 0) { - var a = E(n.innerBlocks); - if (a) return a; + var o = E(n.innerBlocks); + if (o) return o; } } } catch (e) { @@ -337,27 +344,27 @@ } function j() { var e, - t = + r = (null === (e = window.ValidationAPI) || void 0 === e ? void 0 : e.editorContext) || 'none', - n = 'post-editor' === t || 'post-editor-template' === t; + n = 'post-editor' === r || 'post-editor-template' === r; return O( - (0, r.useSelect)( + (0, t.useSelect)( function (e) { var t = e('core/block-editor'), r = t.getBlocks(); if (n) { - var a = E(r); - if (a) { - var i = t.getBlock(a.clientId), - o = t - .getBlockOrder(a.clientId) + var o = E(r); + if (o) { + var a = t.getBlock(o.clientId), + i = t + .getBlockOrder(o.clientId) .map(function (e) { var r = t.getBlock(e); return (t.getBlockOrder(e), r); }) .filter(Boolean); - return o.length > 0 ? o : (null == i ? void 0 : i.innerBlocks) || []; + return i.length > 0 ? i : (null == a ? void 0 : a.innerBlocks) || []; } return r; } @@ -365,9 +372,7 @@ }, [n] ) - ).filter(function (e) { - return !e.isValid; - }); + ); } function S(e, t) { return ( @@ -381,30 +386,30 @@ : ('undefined' != typeof Symbol && e[Symbol.iterator]) || e['@@iterator']; if (null != r) { var n, + o, a, i, - o, l = [], c = !0, u = !1; try { - if (((i = (r = r.call(e)).next), 0 === t)) { + if (((a = (r = r.call(e)).next), 0 === t)) { if (Object(r) !== r) return; c = !1; } else for ( ; - !(c = (n = i.call(r)).done) && (l.push(n.value), l.length !== t); + !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t); c = !0 ); } catch (e) { - ((u = !0), (a = e)); + ((u = !0), (o = e)); } finally { try { - if (!c && null != r.return && ((o = r.return()), Object(o) !== o)) + if (!c && null != r.return && ((i = r.return()), Object(i) !== i)) return; } finally { - if (u) throw a; + if (u) throw o; } } return l; @@ -442,34 +447,34 @@ (null === (b = window.ValidationAPI) || void 0 === b ? void 0 : b.metaValidationRules) || {}; - function A(e, r, n, a) { - var i, - o = - null === (i = k[e]) || void 0 === i || null === (i = i[r]) || void 0 === i + function A(e, t, r, n) { + var o, + a = + null === (o = k[e]) || void 0 === o || null === (o = o[t]) || void 0 === o ? void 0 - : i[a]; - if (!d(o)) return !0; - var l = !0; + : o[n]; + if (!m(a)) return !0; + var i = !0; return ( - 'required' === a && (l = '' !== n && null != n), - (0, t.applyFilters)('validation_api_validate_meta', l, n, e, r, a) + 'required' === n && (i = '' !== r && null != r), + (0, v.applyFilters)('validation_api_validate_meta', i, r, e, t, n) ); } function I(e, t, r) { for ( - var n = (k[e] || {})[t] || {}, a = [], i = 0, o = Object.entries(n); - i < o.length; - i++ + var n = (k[e] || {})[t] || {}, o = [], a = 0, i = Object.entries(n); + a < i.length; + a++ ) { - var l = S(o[i], 2), + var l = S(i[a], 2), c = l[0], u = l[1]; - if (d(u) && !A(e, t, r, c)) { - var s = p(u, c, { metaKey: t }); - ((s.checkName = c), a.push(s)); + if (m(u) && !A(e, t, r, c)) { + var s = d(u, c, { metaKey: t }); + o.push(s); } } - return v(a); + return p(o); } function _(e) { return ( @@ -544,30 +549,30 @@ function T() { for ( var e, - t = (0, r.useSelect)(function (e) { + r = (0, t.useSelect)(function (e) { var t = e('core/editor'); return { postType: t.getCurrentPostType(), meta: t.getEditedPostAttribute('meta'), }; }, []), - n = t.postType, - a = t.meta, - i = + n = r.postType, + o = r.meta, + a = ((null === (e = window.ValidationAPI) || void 0 === e ? void 0 : e.metaValidationRules) || {})[n] || {}, - o = [], + i = [], l = 0, - c = Object.keys(i); + c = Object.keys(a); l < c.length; l++ ) { var u = c[l], - s = I(n, u, null == a ? void 0 : a[u]); - s.isValid || o.push(C(C({}, s), {}, { metaKey: u })); + s = I(n, u, null == o ? void 0 : o[u]); + s.isValid || i.push(C(C({}, s), {}, { metaKey: u })); } - return o; + return i; } function B(e, t) { return ( @@ -581,30 +586,30 @@ : ('undefined' != typeof Symbol && e[Symbol.iterator]) || e['@@iterator']; if (null != r) { var n, + o, a, i, - o, l = [], c = !0, u = !1; try { - if (((i = (r = r.call(e)).next), 0 === t)) { + if (((a = (r = r.call(e)).next), 0 === t)) { if (Object(r) !== r) return; c = !1; } else for ( ; - !(c = (n = i.call(r)).done) && (l.push(n.value), l.length !== t); + !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t); c = !0 ); } catch (e) { - ((u = !0), (a = e)); + ((u = !0), (o = e)); } finally { try { - if (!c && null != r.return && ((o = r.return()), Object(o) !== o)) + if (!c && null != r.return && ((i = r.return()), Object(i) !== i)) return; } finally { - if (u) throw a; + if (u) throw o; } } return l; @@ -641,7 +646,7 @@ (null === (R = window.ValidationAPI) || void 0 === R ? void 0 : R.editorValidationRules) || {}; function M() { - var e = (0, r.useSelect)(function (e) { + var e = (0, t.useSelect)(function (e) { var t = e('core/editor'), r = e('core/block-editor'); return { @@ -650,44 +655,44 @@ title: t.getEditedPostAttribute('title'), }; }, []), - n = e.blocks, - a = e.postType; - if (!a || !n) return []; - var i = (function (e, r) { - for (var n = D[e] || {}, a = [], i = 0, o = Object.entries(n); i < o.length; i++) { - var l = B(o[i], 2), - c = l[0], - u = l[1]; + r = e.blocks, + n = e.postType; + if (!n || !r) return []; + var o = (function (e, t) { + for (var r = D[e] || {}, n = [], o = 0, a = Object.entries(r); o < a.length; o++) { + var i = B(a[o], 2), + l = i[0], + c = i[1]; if ( - d(u) && - !(0, t.applyFilters)('validation_api_validate_editor', !0, r, e, c, u) + m(c) && + !(0, v.applyFilters)('validation_api_validate_editor', !0, t, e, l, c) ) { - var s = p(u, c); - ((s.checkName = c), a.push(s)); + var u = d(c, l); + n.push(u); } } return ( - a.sort(function (e, t) { + n.sort(function (e, t) { return e.priority - t.priority; }), - v(a) + p(n) ); - })(a, n); - return i.issues; + })(n, r); + return o.issues; } function x() { var e, - t = + n = (null === (e = window.ValidationAPI) || void 0 === e ? void 0 : e.editorContext) || 'none', - a = 'post-editor' === t || 'post-editor-template' === t, - i = 'core/editor', - o = (0, r.useDispatch)(i), - l = wp.data && wp.data.select && wp.data.select(i), + o = 'post-editor' === n || 'post-editor-template' === n, + a = 'core/editor', + i = (0, t.useDispatch)(a), + l = wp.data && wp.data.select && wp.data.select(a), c = j(), u = T(), - s = M(), - d = o || {}, + m = M(), + d = i || {}, p = d.lockPostSaving, v = d.unlockPostSaving, y = d.lockPostAutosaving, @@ -695,66 +700,64 @@ g = d.disablePublishSidebar, w = d.enablePublishSidebar; return ( - (0, n.useEffect)( + (0, r.useEffect)( function () { - if (a && 'none' !== t && l && p && v) { + if (o && 'none' !== n && l && p && v) { var e = c.some(function (e) { return 'error' === e.mode; }), - r = u.some(function (e) { + t = u.some(function (e) { return e.hasErrors; }), - n = f(s); - e || r || n + r = s(m); + e || t || r ? (p('validation-api'), y && y('validation-api'), g && g()) : (v('validation-api'), b && b('validation-api'), w && w()); } }, - [c, u, s, p, v, y, b, g, w, a, t, l] + [c, u, m, p, v, y, b, g, w, o, n, l] ), - (0, n.useEffect)( + (0, r.useEffect)( function () { - if (a && 'none' !== t && document.body) { + if (o && 'none' !== n && document.body) { var e = c.some(function (e) { return 'error' === e.mode; }), - r = c.some(function (e) { + t = c.some(function (e) { return 'warning' === e.mode; }), - n = u.some(function (e) { + r = u.some(function (e) { return e.hasErrors; }), - i = u.some(function (e) { + a = u.some(function (e) { return e.hasWarnings && !e.hasErrors; }), - o = f(s), - l = m(s), - d = e || n || o, - p = !d && (r || i || l); + i = s(m), + l = f(m), + d = e || r || i, + p = !d && (t || a || l); return ( d - ? (document.body.classList.add('has-meta-validation-errors'), - document.body.classList.remove('has-meta-validation-warnings')) + ? (document.body.classList.add('has-validation-errors'), + document.body.classList.remove('has-validation-warnings')) : p - ? (document.body.classList.add('has-meta-validation-warnings'), - document.body.classList.remove( - 'has-meta-validation-errors' - )) + ? (document.body.classList.add('has-validation-warnings'), + document.body.classList.remove('has-validation-errors')) : document.body.classList.remove( - 'has-meta-validation-errors', - 'has-meta-validation-warnings' + 'has-validation-errors', + 'has-validation-warnings' ), function () { document.body && document.body.classList.remove( - 'has-meta-validation-errors', - 'has-meta-validation-warnings' + 'has-validation-errors', + 'has-validation-warnings' ); } ); } }, - [c, u, s, a, t] + [c, u, m, o, n] ), null ); @@ -769,7 +772,7 @@ return React.createElement( 'svg', { - viewBox: '-2.12 -2.12 28.24 28.24', + viewBox: '-0.81 -0.81 25.62 25.62', xmlns: 'http://www.w3.org/2000/svg', className: 'validation-api-sidebar-icon', }, @@ -787,26 +790,26 @@ var r = new Map(); return ( e.forEach(function (e) { - ('error' === t ? u(e.issues || []) : s(e.issues || [])).forEach(function (n) { - var a, - i, - o = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg, - l = ''.concat(e.name, '|').concat(o); + ('error' === t ? c(e.issues || []) : u(e.issues || [])).forEach(function (n) { + var o, + a, + i = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg, + l = ''.concat(e.name, '|').concat(i); (r.has(l) || r.set(l, { blockName: - ((a = e.name), - (i = (0, $.getBlockType)(a)), - i && i.title - ? i.title - : (a.split('/')[1] || a) + ((o = e.name), + (a = (0, $.getBlockType)(o)), + a && a.title + ? a.title + : (o.split('/')[1] || o) .split(/[-_]/) .map(function (e) { return e.charAt(0).toUpperCase() + e.slice(1); }) .join(' ')), blockType: e.name, - message: o, + message: i, clientIds: [], }), e.clientId && @@ -821,10 +824,10 @@ var r = new Map(); return ( e.forEach(function (e) { - ('error' === t ? u(e.issues || []) : s(e.issues || [])).forEach(function (n) { - var a = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg, - i = ''.concat(e.metaKey, '|').concat(a); - r.has(i) || r.set(i, { metaKey: e.metaKey, message: a }); + ('error' === t ? c(e.issues || []) : u(e.issues || [])).forEach(function (n) { + var o = 'error' === t ? n.error_msg : n.warning_msg || n.error_msg, + a = ''.concat(e.metaKey, '|').concat(o); + r.has(a) || r.set(a, { metaKey: e.metaKey, message: o }); }); }), Array.from(r.values()) @@ -838,25 +841,25 @@ 'error' === t ? e.errorMsg || e.error_msg : e.warningMsg || e.warning_msg || e.errorMsg || e.error_msg, - a = n; - r.has(a) || r.set(a, { message: n, description: e.description }); + o = n; + r.has(o) || r.set(o, { message: n, description: e.description }); }), Array.from(r.values()) ); } function z() { var e = j() || [], - t = T() || [], - a = M() || [], - i = (0, r.useDispatch)('core/block-editor').selectBlock, - o = (0, n.useRef)(null), - l = c(a, 'error'), - u = c(a, 'warning'), + n = T() || [], + o = M() || [], + a = (0, t.useDispatch)('core/block-editor').selectBlock, + i = (0, r.useRef)(null), + c = l(o, 'error'), + u = l(o, 'warning'), s = K(e, 'error'), f = K(e, 'warning'), - m = H(t, 'error'), - d = H(t, 'warning'), - p = Z(l, 'error'), + m = H(n, 'error'), + d = H(n, 'warning'), + p = Z(c, 'error'), v = Z(u, 'warning'), y = s.length + m.length + p.length, b = f.length + d.length + v.length, @@ -865,9 +868,9 @@ var w = React.createElement(q, { fill: g }), h = function (e) { e && - (i(e), - o.current && clearTimeout(o.current), - (o.current = setTimeout(function () { + (a(e), + i.current && clearTimeout(i.current), + (i.current = setTimeout(function () { var t = document.querySelector('[data-block="'.concat(e, '"]')); (t || (t = document.querySelector( @@ -881,9 +884,9 @@ }, 100))); }; return ( - (0, n.useEffect)(function () { + (0, r.useEffect)(function () { return function () { - o.current && clearTimeout(o.current); + i.current && clearTimeout(i.current); }; }, []), 0 === y && 0 === b @@ -1107,22 +1110,6 @@ ) ); } - (0, t.addFilter)( - 'blocks.registerBlockType', - 'validation-api/add-validation-category', - function (e) { - return e; - } - ); - var G = new Proxy( - {}, - { - get: function (e, t) { - if (window.ValidationAPI && window.ValidationAPI.validationRules) - return window.ValidationAPI.validationRules[t]; - }, - } - ); (0, e.registerPlugin)('validation-api', { render: function () { return React.createElement( @@ -1133,20 +1120,20 @@ ); }, }); - const J = window.wp.compose, - Q = window.wp.blockEditor; - function X(e, t) { + const G = window.wp.compose, + J = window.wp.blockEditor; + function Q(e, t) { (null == t || t > e.length) && (t = e.length); for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r]; return n; } - function Y(e) { + function X(e) { var t, - r, - a = e.issues, - i = - ((t = (0, n.useState)(!1)), - (r = 2), + n, + o = e.issues, + a = + ((t = (0, r.useState)(!1)), + (n = 2), (function (e) { if (Array.isArray(e)) return e; })(t) || @@ -1158,43 +1145,43 @@ e['@@iterator']; if (null != r) { var n, + o, a, i, - o, l = [], c = !0, u = !1; try { - if (((i = (r = r.call(e)).next), 0 === t)) { + if (((a = (r = r.call(e)).next), 0 === t)) { if (Object(r) !== r) return; c = !1; } else for ( ; - !(c = (n = i.call(r)).done) && + !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t); c = !0 ); } catch (e) { - ((u = !0), (a = e)); + ((u = !0), (o = e)); } finally { try { if ( !c && null != r.return && - ((o = r.return()), Object(o) !== o) + ((i = r.return()), Object(i) !== i) ) return; } finally { - if (u) throw a; + if (u) throw o; } } return l; } - })(t, r) || + })(t, n) || (function (e, t) { if (e) { - if ('string' == typeof e) return X(e, t); + if ('string' == typeof e) return Q(e, t); var r = {}.toString.call(e).slice(8, -1); return ( 'Object' === r && e.constructor && (r = e.constructor.name), @@ -1202,25 +1189,25 @@ ? Array.from(e) : 'Arguments' === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) - ? X(e, t) + ? Q(e, t) : void 0 ); } - })(t, r) || + })(t, n) || (function () { throw new TypeError( 'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.' ); })()), - o = i[0], - l = i[1]; - if (!a || 0 === a.length) return null; - var c = f(a), - m = u(a), - d = s(a), - p = c + i = a[0], + l = a[1]; + if (!o || 0 === o.length) return null; + var f = s(o), + m = c(o), + d = u(o), + p = f ? React.createElement(q, { fill: '#d82000' }) - : React.createElement(q, { fill: '#d8c600' }); + : React.createElement(q, { fill: '#dbc900' }); return React.createElement( React.Fragment, null, @@ -1233,7 +1220,7 @@ className: 'validation-api-toolbar-button', isCompact: !0, }), - o && + i && React.createElement( U.Modal, { @@ -1304,16 +1291,16 @@ ) ); } - function ee(e, t) { + function Y(e, t) { (null == t || t > e.length) && (t = e.length); for (var r = 0, n = Array(t); r < t; r++) n[r] = e[r]; return n; } - var te = new Map(), - re = Object.freeze({ mode: 'none', issues: [] }); - function ne(e) { + var ee = new Map(), + te = Object.freeze({ mode: 'none', issues: [] }); + function re(e) { return ( - (ne = + (re = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (e) { return typeof e; @@ -1326,10 +1313,10 @@ ? 'symbol' : typeof e; }), - ne(e) + re(e) ); } - function ae(e, t) { + function ne(e, t) { var r = Object.keys(e); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); @@ -1341,35 +1328,35 @@ } return r; } - function ie(e) { + function oe(e) { for (var t = 1; t < arguments.length; t++) { var r = null != arguments[t] ? arguments[t] : {}; t % 2 - ? ae(Object(r), !0).forEach(function (t) { - oe(e, t, r[t]); + ? ne(Object(r), !0).forEach(function (t) { + ae(e, t, r[t]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r)) - : ae(Object(r)).forEach(function (t) { + : ne(Object(r)).forEach(function (t) { Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t)); }); } return e; } - function oe(e, t, r) { + function ae(e, t, r) { return ( (t = (function (e) { var t = (function (e) { - if ('object' != ne(e) || !e) return e; + if ('object' != re(e) || !e) return e; var t = e[Symbol.toPrimitive]; if (void 0 !== t) { var r = t.call(e, 'string'); - if ('object' != ne(r)) return r; + if ('object' != re(r)) return r; throw new TypeError('@@toPrimitive must return a primitive value.'); } return String(e); })(e); - return 'symbol' == ne(t) ? t : t + ''; + return 'symbol' == re(t) ? t : t + ''; })(t)) in e ? Object.defineProperty(e, t, { value: r, @@ -1381,30 +1368,30 @@ e ); } - var le = (0, J.createHigherOrderComponent)(function (e) { - return function (t) { - var a = t.clientId, - i = t.attributes, - o = (0, r.useSelect)( + var ie = (0, G.createHigherOrderComponent)(function (e) { + return function (n) { + var o = n.clientId, + a = n.attributes, + i = (0, t.useSelect)( function (e) { - return e('core/block-editor').getBlock(a); + return e('core/block-editor').getBlock(o); }, - [a] + [o] ), l = (function (e, t) { - var r, - a, - i = (arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}) + var n, + o, + a = (arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}) .delay, - o = void 0 === i ? 300 : i, + i = void 0 === a ? 300 : a, l = - ((r = (0, n.useState)(function () { + ((n = (0, r.useState)(function () { return e(); })), - (a = 2), + (o = 2), (function (e) { if (Array.isArray(e)) return e; - })(r) || + })(n) || (function (e, t) { var r = null == e @@ -1414,43 +1401,43 @@ e['@@iterator']; if (null != r) { var n, + o, a, i, - o, l = [], c = !0, u = !1; try { - if (((i = (r = r.call(e)).next), 0 === t)) { + if (((a = (r = r.call(e)).next), 0 === t)) { if (Object(r) !== r) return; c = !1; } else for ( ; - !(c = (n = i.call(r)).done) && + !(c = (n = a.call(r)).done) && (l.push(n.value), l.length !== t); c = !0 ); } catch (e) { - ((u = !0), (a = e)); + ((u = !0), (o = e)); } finally { try { if ( !c && null != r.return && - ((o = r.return()), Object(o) !== o) + ((i = r.return()), Object(i) !== i) ) return; } finally { - if (u) throw a; + if (u) throw o; } } return l; } - })(r, a) || + })(n, o) || (function (e, t) { if (e) { - if ('string' == typeof e) return ee(e, t); + if ('string' == typeof e) return Y(e, t); var r = {}.toString.call(e).slice(8, -1); return ( 'Object' === r && @@ -1462,11 +1449,11 @@ /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test( r ) - ? ee(e, t) + ? Y(e, t) : void 0 ); } - })(r, a) || + })(n, o) || (function () { throw new TypeError( 'Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.' @@ -1474,16 +1461,16 @@ })()), c = l[0], u = l[1], - s = (0, n.useRef)(null), - f = (0, n.useRef)(!0); + s = (0, r.useRef)(null), + f = (0, r.useRef)(!0); return ( - (0, n.useEffect)(function () { + (0, r.useEffect)(function () { return f.current ? ((f.current = !1), void u(e())) : (s.current && clearTimeout(s.current), (s.current = setTimeout(function () { u(e()); - }, o)), + }, i)), function () { s.current && clearTimeout(s.current); }); @@ -1492,46 +1479,46 @@ ); })( function () { - if (!o) return { isValid: !0, issues: [], mode: 'none' }; - var e = ie(ie({}, o), {}, { attributes: i || o.attributes }); + if (!i) return { isValid: !0, issues: [], mode: 'none' }; + var e = oe(oe({}, i), {}, { attributes: a || i.attributes }); return g(e); }, - [o, i], + [i, a], { delay: 300 } ); return ( - (0, n.useEffect)( + (0, r.useEffect)( function () { return ( (function (e, t) { - te.set(e, t); - })(a, l), + ee.set(e, t); + })(o, l), function () { return (function (e) { - te.delete(e); - })(a); + ee.delete(e); + })(o); } ); }, - [a, l] + [o, l] ), React.createElement( React.Fragment, null, - React.createElement(e, t), + React.createElement(e, n), !l.isValid && React.createElement( - Q.BlockControls, + J.BlockControls, { group: 'block' }, - React.createElement(Y, { issues: l.issues }) + React.createElement(X, { issues: l.issues }) ) ) ); }; }, 'withErrorHandling'); - function ce(e) { + function le(e) { return ( - (ce = + (le = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (e) { return typeof e; @@ -1544,12 +1531,12 @@ ? 'symbol' : typeof e; }), - ce(e) + le(e) ); } - function ue() { + function ce() { return ( - (ue = Object.assign + (ce = Object.assign ? Object.assign.bind() : function (e) { for (var t = 1; t < arguments.length; t++) { @@ -1558,10 +1545,10 @@ } return e; }), - ue.apply(null, arguments) + ce.apply(null, arguments) ); } - function se(e, t) { + function ue(e, t) { var r = Object.keys(e); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); @@ -1573,35 +1560,35 @@ } return r; } - function fe(e) { + function se(e) { for (var t = 1; t < arguments.length; t++) { var r = null != arguments[t] ? arguments[t] : {}; t % 2 - ? se(Object(r), !0).forEach(function (t) { - me(e, t, r[t]); + ? ue(Object(r), !0).forEach(function (t) { + fe(e, t, r[t]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r)) - : se(Object(r)).forEach(function (t) { + : ue(Object(r)).forEach(function (t) { Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t)); }); } return e; } - function me(e, t, r) { + function fe(e, t, r) { return ( (t = (function (e) { var t = (function (e) { - if ('object' != ce(e) || !e) return e; + if ('object' != le(e) || !e) return e; var t = e[Symbol.toPrimitive]; if (void 0 !== t) { var r = t.call(e, 'string'); - if ('object' != ce(r)) return r; + if ('object' != le(r)) return r; throw new TypeError('@@toPrimitive must return a primitive value.'); } return String(e); })(e); - return 'symbol' == ce(t) ? t : t + ''; + return 'symbol' == le(t) ? t : t + ''; })(t)) in e ? Object.defineProperty(e, t, { value: r, @@ -1613,9 +1600,9 @@ e ); } - function de(e) { + function me(e) { return ( - (de = + (me = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (e) { return typeof e; @@ -1628,10 +1615,10 @@ ? 'symbol' : typeof e; }), - de(e) + me(e) ); } - function pe(e, t) { + function de(e, t) { var r = Object.keys(e); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); @@ -1643,35 +1630,35 @@ } return r; } - function ve(e) { + function pe(e) { for (var t = 1; t < arguments.length; t++) { var r = null != arguments[t] ? arguments[t] : {}; t % 2 - ? pe(Object(r), !0).forEach(function (t) { - ye(e, t, r[t]); + ? de(Object(r), !0).forEach(function (t) { + ve(e, t, r[t]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r)) - : pe(Object(r)).forEach(function (t) { + : de(Object(r)).forEach(function (t) { Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t)); }); } return e; } - function ye(e, t, r) { + function ve(e, t, r) { return ( (t = (function (e) { var t = (function (e) { - if ('object' != de(e) || !e) return e; + if ('object' != me(e) || !e) return e; var t = e[Symbol.toPrimitive]; if (void 0 !== t) { var r = t.call(e, 'string'); - if ('object' != de(r)) return r; + if ('object' != me(r)) return r; throw new TypeError('@@toPrimitive must return a primitive value.'); } return String(e); })(e); - return 'symbol' == de(t) ? t : t + ''; + return 'symbol' == me(t) ? t : t + ''; })(t)) in e ? Object.defineProperty(e, t, { value: r, @@ -1683,9 +1670,9 @@ e ); } - function be(e) { + function ye(e) { return ( - (be = + (ye = 'function' == typeof Symbol && 'symbol' == typeof Symbol.iterator ? function (e) { return typeof e; @@ -1698,44 +1685,44 @@ ? 'symbol' : typeof e; }), - be(e) + ye(e) ); } - (wp.hooks.addFilter('editor.BlockEdit', 'validation-api/with-error-handling', le), - wp.hooks.addFilter( + (wp.hooks.addFilter('editor.BlockEdit', 'validation-api/with-error-handling', ie), + (0, v.addFilter)( 'editor.BlockListBlock', 'validation-api/with-block-validation-classes', function (e) { return function (t) { var r, - n = ((r = t.clientId), te.get(r) || re); + n = ((r = t.clientId), ee.get(r) || te); if ('none' === n.mode) return React.createElement(e, t); - var a = + var o = 'error' === n.mode ? 'validation-api-block-error' : 'validation-api-block-warning', - i = t.wrapperProps || {}, - o = fe( - fe({}, i), + a = t.wrapperProps || {}, + i = se( + se({}, a), {}, - { className: [i.className, a].filter(Boolean).join(' ') } + { className: [a.className, o].filter(Boolean).join(' ') } ); - return React.createElement(e, ue({}, t, { wrapperProps: o })); + return React.createElement(e, ce({}, t, { wrapperProps: i })); }; } ), void 0 === window.ValidationAPI && (window.ValidationAPI = {}), (window.ValidationAPI.useMetaField = function (e) { - var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : '', + var r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : '', n = (function (e) { - return (0, r.useSelect)( + return (0, t.useSelect)( function (t) { var r = t('core/editor'), n = r.getEditedPostAttribute, - a = (0, r.getCurrentPostType)(), - i = n('meta'), - o = i ? i[e] : ''; - if (!a || !e) + o = (0, r.getCurrentPostType)(), + a = n('meta'), + i = a ? a[e] : ''; + if (!o || !e) return { isValid: !0, hasErrors: !1, @@ -1743,19 +1730,19 @@ issues: [], wrapperClassName: '', }; - var l = I(a, e, o), + var l = I(o, e, i), c = ''; return ( l.hasErrors ? (c = 'validation-api-meta-error') : l.hasWarnings && (c = 'validation-api-meta-warning'), - ve(ve({}, l), {}, { wrapperClassName: c }) + pe(pe({}, l), {}, { wrapperClassName: c }) ); }, [e] ); })(e), - a = (0, r.useSelect)( + o = (0, t.useSelect)( function (t) { var r = t('core/editor'); if (!r) return { value: '' }; @@ -1764,8 +1751,8 @@ }, [e] ).value, - i = (0, r.useDispatch)('core/editor').editPost, - o = t; + a = (0, t.useDispatch)('core/editor').editPost, + i = r; if (n && (n.hasErrors || n.hasWarnings)) { var l = n.issues .map(function (e) { @@ -1773,51 +1760,51 @@ }) .join('. '), c = n.hasErrors ? 'validation-api-error-text' : 'validation-api-warning-text'; - o = o + i = i ? React.createElement( React.Fragment, null, - o, + i, React.createElement('span', { className: c }, '* ', l) ) : React.createElement('span', { className: c }, '* ', l); } return { - value: a || '', + value: o || '', onChange: function (t) { - var r, n, a; - i && - i({ + var r, n, o; + a && + a({ meta: ((r = {}), (n = e), - (a = t), + (o = t), (n = (function (e) { var t = (function (e) { - if ('object' != be(e) || !e) return e; + if ('object' != ye(e) || !e) return e; var t = e[Symbol.toPrimitive]; if (void 0 !== t) { var r = t.call(e, 'string'); - if ('object' != be(r)) return r; + if ('object' != ye(r)) return r; throw new TypeError( '@@toPrimitive must return a primitive value.' ); } return String(e); })(e); - return 'symbol' == be(t) ? t : t + ''; + return 'symbol' == ye(t) ? t : t + ''; })(n)) in r ? Object.defineProperty(r, n, { - value: a, + value: o, enumerable: !0, configurable: !0, writable: !0, }) - : (r[n] = a), + : (r[n] = o), r), }); }, - help: o, + help: i, className: null != n && n.wrapperClassName ? 'validation-api-field '.concat(n.wrapperClassName) diff --git a/docs/REVIEW.md b/docs/REVIEW.md deleted file mode 100644 index daeea2e..0000000 --- a/docs/REVIEW.md +++ /dev/null @@ -1,200 +0,0 @@ -# Code Review — Validation API Plugin - -Branch: `fix/wrapping-div` -Date: 2026-04-04 - ---- - -## 1. Dead Code / Stale Files - -### `src/editor/register.js:23-37` — No-op filter callback - -`addBlockValidationCategory()` returns `settings` unchanged. The `addFilter` call on `blocks.registerBlockType` does nothing. Remove the function, the filter registration, and the `addFilter` import if no longer needed. - -### `src/editor/hoc/index.js` — Empty barrel file - -Contains only comments explaining why nothing is exported. Imported by `src/editor/index.js` via `export * from './hoc'` but contributes nothing. Delete the file and remove the re-export. - -### `src/editor/index.js` — Unused barrel file - -Re-exports from `./components`, `./hoc`, and `./validation` but no file imports from `src/editor/index.js`. The entry point (`src/script.js`) imports each module directly. Delete this file. - -### `src/shared/index.js` — Unused barrel file - -Same pattern. All consumers import from specific paths. Delete this file. - -### `src/shared/utils/index.js` — Unused barrel file - -All consumers import directly from `src/shared/utils/validation`. Delete this file. - -### `src/editor/validation/index.js` — Unused barrel file - -Never imported. Delete this file. - ---- - -## 2. CSS Variable Mismatch - -### `settings.scss` references `--a11y-*` variables that don't exist - -`src/styles/_variables.scss` defines variables with the `--validation-api-*` prefix, but `settings.scss` references the old `--a11y-*` prefix throughout. All of these will resolve to nothing at runtime: - -- `--a11y-settings-space` -- `--a11y-light-grey` -- `--a11y-black` -- `--a11y-lightest-green` -- `--a11y-green` -- `--a11y-dark-green` -- `--a11y-lightest-grey` -- `--a11y-grey` -- `--a11y-dark-grey` -- `--a11y-font-small` -- `--a11y-dark-red` -- `--a11y-settings-space-mobile` (never defined anywhere under any prefix) - -**Fix:** Update all `--a11y-*` references in `settings.scss` to use `--validation-api-*`, and define `--validation-api-settings-space-mobile` if needed. - -### `includes/Core/Assets.php:149-163` — Dead inline CSS - -`enqueue_block_styles()` injects inline CSS defining `--a11y-red`, `--a11y-light-red`, `--a11y-dark-red`, `--a11y-yellow`, `--a11y-light-yellow`, `--a11y-dark-yellow`, `--a11y-border-width`, `--a11y-warning-icon`, and `--a11y-error-icon`. None of these `--a11y-*` variables are referenced in the editor SCSS files (which use `--validation-api-*`). The SVG icon URLs are injected but never consumed by any CSS rule. - -**Fix:** Remove the entire inline CSS block and the SVG URL generation above it (lines 144-165). - -### `src/styles/_variables.scss` — Unused variables - -These variables are defined but never referenced in any SCSS file that is actually built: - -- `--validation-api-light-blue` -- `--validation-api-blue` -- `--validation-api-medium-grey` -- `--validation-api-green` -- `--validation-api-lightest-green` -- `--validation-api-dark-green` -- `--validation-api-border-width` -- `--validation-api-settings-space` -- `--validation-api-font-small` - -**Fix:** Remove unused variables. If `settings.scss` is migrated to use `--validation-api-*`, some of these will become used again — audit after that migration. - ---- - -## 3. Orphaned Style Sheets - -### `src/admin.scss` and `src/settings.scss` — Not built by any entry point - -`webpack.config.js` has a single entry: `src/script.js`. The `styles.scss` imported there includes only the `src/styles/` partials. Neither `admin.scss` nor `settings.scss` is imported by any JS entry point, so they are never compiled into `build/`. - -**Fix:** If these are needed for a settings page, add a separate webpack entry point. If they are leftover from a removed feature, delete them. - ---- - -## 4. Inconsistent Colors in JS - -### Three different warning yellows - -| Location | Value | -|----------|-------| -| `ValidationToolbarButton.js:38` | `#d8c600` | -| `ValidationSidebar.js:209` | `#dbc900` | -| `_variables.scss` | `--validation-api-yellow: #f0dc00` | - -**Fix:** Standardize to one value. Both JS files should use the same hex code, ideally matching the CSS variable. - ---- - -## 5. Redundant / Stale JS Code - -### `src/shared/utils/validation/getInvalidBlocks.js:144` — Redundant filter - -```js -return invalidBlocks.filter(result => !result.isValid); -``` - -`getInvalidBlocksRecursive` already only pushes results where `!result.isValid`. The `.filter()` is redundant. - -### `src/editor/components/ValidationSidebar.js:272-277` — Dead `handleMetaClick` - -Empty function with eslint-disable for unused-vars. Never called anywhere. Remove it. - -### `src/editor/validation/editor/validateEditor.js:68` — Redundant `checkName` assignment - -```js -issue.checkName = checkName; -``` - -`createIssue()` already sets `checkName` on the returned object. Same issue in `src/editor/validation/meta/validateMeta.js:113`. - -### `src/editor/register.js:51-62` — Over-engineered Proxy - -The `blockChecksArray` Proxy wraps a simple window property lookup. Since `window.ValidationAPI.validationRules` is set once by `wp_localize_script` before JS executes, the only consumer (`validateBlock.js`) can read it directly: - -```js -const checks = window.ValidationAPI?.validationRules?.[blockType] || {}; -``` - -Remove the Proxy export from `register.js` and inline the access in `validateBlock.js`. - ---- - -## 6. Import / Global Consistency - -### `src/editor/hoc/withBlockValidationClasses.js:39` — Uses `wp.hooks.addFilter` global - -All other files import `addFilter` from `@wordpress/hooks`. This file uses the global `wp.hooks.addFilter` directly. Import it for consistency. - ---- - -## 7. PHP Observations - -### Redundant type checks in all three registries - -`Block\Registry::register_check()`, `Editor\Registry::register_editor_check()`, and `Meta\Registry::register_meta_check()` all check `! is_string()` and `! is_array()` on parameters that are already type-hinted as `string` and `array` in the method signature. PHP enforces these at call time, making the checks unreachable. - -**Files:** -- `includes/Block/Registry.php:68,73,78` -- `includes/Editor/Registry.php:81,86,91` -- `includes/Meta/Registry.php:82,87,92,98` - -### `includes/Core/Traits/EditorDetection.php` — Duplicated post type array - -`get_editor_context()` (line 40) and `is_site_editor_context()` (line 115) both hardcode `array('wp_template', 'wp_template_part')`. Define once as a class constant. - ---- - -## 8. Naming Inconsistencies - -### `has-meta-validation-errors` / `has-meta-validation-warnings` body classes - -Set in `ValidationAPI.js:163-176`, these classes reflect errors from blocks, meta, AND editor checks — not just meta. The `meta` prefix is misleading. Consider `has-validation-errors` / `has-validation-warnings`. - -### `blockChecksArray` export name - -Defined in `register.js:51`. It's a Proxy object, not an array. If kept, rename to `blockChecks`. - -### `settings.scss` double-comment lines - -Lines 209 and 222 have `// //` prefix — leftover from toggling code blocks. Clean up to single `//`. - ---- - -## 9. Action Summary - -| Priority | Action | Files | -|----------|--------|-------| -| High | Fix `--a11y-*` to `--validation-api-*` variable mismatch | `settings.scss` | -| High | Remove dead inline CSS (`--a11y-*` vars + SVG URLs) | `Assets.php` | -| High | Standardize warning yellow color | `ValidationToolbarButton.js`, `ValidationSidebar.js` | -| Med | Delete 6 unused barrel files | `editor/index.js`, `editor/hoc/index.js`, `shared/index.js`, `shared/utils/index.js`, `editor/validation/index.js` | -| Med | Remove no-op `addBlockValidationCategory` + filter | `register.js` | -| Med | Remove unused CSS variables | `_variables.scss` | -| Med | Remove Proxy, inline window access | `register.js`, `validateBlock.js` | -| Med | Remove dead `handleMetaClick` | `ValidationSidebar.js` | -| Med | Remove redundant `.filter()` | `getInvalidBlocks.js` | -| Med | Remove redundant `checkName` re-assignments | `validateEditor.js`, `validateMeta.js` | -| Med | Verify `admin.scss` / `settings.scss` build status | Webpack config | -| Low | Remove redundant PHP type checks | 3 registry files | -| Low | Import `addFilter` in `withBlockValidationClasses.js` | `withBlockValidationClasses.js` | -| Low | Clean up double-comment lines | `settings.scss` | -| Low | Rename misleading body classes | `ValidationAPI.js` | -| Low | Rename `blockChecksArray` | `register.js` | -| Low | Consolidate duplicated site-editor post type array | `EditorDetection.php` | diff --git a/includes/Block/Registry.php b/includes/Block/Registry.php index dc78b58..67307ce 100644 --- a/includes/Block/Registry.php +++ b/includes/Block/Registry.php @@ -65,21 +65,16 @@ private function __construct() {} public function register_check( string $block_type, string $check_name, array $check_args ): bool { try { // Validate input parameters. - if ( empty( $block_type ) || ! is_string( $block_type ) ) { + if ( empty( $block_type ) ) { $this->log_error( "Invalid block type provided: {$block_type}" ); return false; } - if ( empty( $check_name ) || ! is_string( $check_name ) ) { + if ( empty( $check_name ) ) { $this->log_error( "Invalid check name provided: {$check_name}" ); return false; } - if ( ! is_array( $check_args ) ) { - $this->log_error( "Check arguments must be an array for {$block_type}/{$check_name}" ); - return false; - } - $defaults = array( 'error_msg' => '', 'warning_msg' => '', diff --git a/includes/Core/Assets.php b/includes/Core/Assets.php index fb0ef53..8122c28 100644 --- a/includes/Core/Assets.php +++ b/includes/Core/Assets.php @@ -140,29 +140,6 @@ private function enqueue_block_styles() { array(), VALIDATION_API_VERSION ); - - // Dynamically generate the SVG URLs. - $warning_icon_url = plugins_url( 'src/assets/universal-access-warning.svg', $this->plugin_file ); - $error_icon_url = plugins_url( 'src/assets/universal-access-error.svg', $this->plugin_file ); - - // Add the SVG URLs and color variables for the editor. - $inline_css = sprintf( - ":root { - --a11y-red: #d82000; - --a11y-light-red: #ffe4e0; - --a11y-dark-red: #a21800; - --a11y-yellow: #dbc900; - --a11y-light-yellow: #fffde2; - --a11y-dark-yellow: #807500; - --a11y-border-width: 3px solid; - --a11y-warning-icon: url('%s'); - --a11y-error-icon: url('%s'); - }", - esc_url( $warning_icon_url ), - esc_url( $error_icon_url ) - ); - - wp_add_inline_style( 'validation-api-style', $inline_css ); } /** diff --git a/includes/Core/Traits/EditorDetection.php b/includes/Core/Traits/EditorDetection.php index 862761b..e509916 100644 --- a/includes/Core/Traits/EditorDetection.php +++ b/includes/Core/Traits/EditorDetection.php @@ -20,6 +20,15 @@ */ trait EditorDetection { + /** + * Get the post types that belong to the Site Editor context. + * + * @return array + */ + private function get_site_editor_post_types(): array { + return array( 'wp_template', 'wp_template_part' ); + } + /** * Get the current editor context. * @@ -36,9 +45,6 @@ private function get_editor_context(): string { global $pagenow; - // Site Editor post types. - $site_editor_post_types = array( 'wp_template', 'wp_template_part' ); - // Check if we're in the Site Editor. if ( $this->is_site_editor_context() ) { return 'site-editor'; @@ -52,14 +58,14 @@ private function get_editor_context(): string { $post_id = intval( $_GET['post'] ); if ( $post_id > 0 ) { $post_type = \get_post_type( $post_id ); - if ( $post_type && ! in_array( $post_type, $site_editor_post_types, true ) ) { + if ( $post_type && ! in_array( $post_type, $this->get_site_editor_post_types(), true ) ) { // For now, return 'post-editor' - JavaScript will determine if template is shown. return 'post-editor'; } } } elseif ( isset( $_GET['post_type'] ) ) { $post_type = sanitize_text_field( wp_unslash( $_GET['post_type'] ) ); - if ( ! in_array( $post_type, $site_editor_post_types, true ) ) { + if ( ! in_array( $post_type, $this->get_site_editor_post_types(), true ) ) { return 'post-editor'; } } else { @@ -73,7 +79,7 @@ private function get_editor_context(): string { if ( function_exists( 'get_current_screen' ) ) { $current_screen = \get_current_screen(); if ( $current_screen && isset( $current_screen->post_type ) ) { - if ( ! in_array( $current_screen->post_type, $site_editor_post_types, true ) ) { + if ( ! in_array( $current_screen->post_type, $this->get_site_editor_post_types(), true ) ) { return 'post-editor'; } } @@ -112,7 +118,7 @@ private function is_site_editor_context(): bool { // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Context detection only. if ( isset( $_GET['postType'] ) ) { $post_type = sanitize_text_field( wp_unslash( $_GET['postType'] ) ); - if ( in_array( $post_type, array( 'wp_template', 'wp_template_part' ), true ) ) { + if ( in_array( $post_type, $this->get_site_editor_post_types(), true ) ) { return true; } } diff --git a/includes/Editor/Registry.php b/includes/Editor/Registry.php index c8a72aa..b895fe3 100644 --- a/includes/Editor/Registry.php +++ b/includes/Editor/Registry.php @@ -78,21 +78,16 @@ private function sort_checks_by_priority( $a, $b ) { public function register_editor_check( string $post_type, string $check_name, array $check_args ): bool { try { // Validate input parameters. - if ( empty( $post_type ) || ! is_string( $post_type ) ) { + if ( empty( $post_type ) ) { $this->log_error( "Invalid post type provided: {$post_type}" ); return false; } - if ( empty( $check_name ) || ! is_string( $check_name ) ) { + if ( empty( $check_name ) ) { $this->log_error( "Invalid check name provided: {$check_name}" ); return false; } - if ( ! is_array( $check_args ) ) { - $this->log_error( "Check arguments must be an array for {$post_type}/{$check_name}" ); - return false; - } - $defaults = array( 'error_msg' => '', 'warning_msg' => '', diff --git a/includes/Meta/Registry.php b/includes/Meta/Registry.php index 481ab86..ac7176a 100644 --- a/includes/Meta/Registry.php +++ b/includes/Meta/Registry.php @@ -79,26 +79,21 @@ private function sort_checks_by_priority( $a, $b ) { public function register_meta_check( string $post_type, string $meta_key, string $check_name, array $check_args ): bool { try { // Validate input parameters. - if ( empty( $post_type ) || ! is_string( $post_type ) ) { + if ( empty( $post_type ) ) { $this->log_error( "Invalid post type provided: {$post_type}" ); return false; } - if ( empty( $meta_key ) || ! is_string( $meta_key ) ) { + if ( empty( $meta_key ) ) { $this->log_error( "Invalid meta key provided: {$meta_key}" ); return false; } - if ( empty( $check_name ) || ! is_string( $check_name ) ) { + if ( empty( $check_name ) ) { $this->log_error( "Invalid check name provided: {$check_name}" ); return false; } - if ( ! is_array( $check_args ) ) { - $this->log_error( "Check arguments must be an array for {$post_type}/{$meta_key}/{$check_name}" ); - return false; - } - $defaults = array( 'error_msg' => '', 'warning_msg' => '', diff --git a/src/admin.scss b/src/admin.scss deleted file mode 100644 index 84fb2e4..0000000 --- a/src/admin.scss +++ /dev/null @@ -1,25 +0,0 @@ -// Plugin Sidebar Icon Styles - -.has-meta-validation-warnings button[aria-controls="validation-api:validation-sidebar"].is-pressed { - background-color: var(--validation-api-light-yellow); - transition: background-color 0.2s ease; -} - -.has-meta-validation-errors button[aria-controls="validation-api:validation-sidebar"].is-pressed { - background-color: var(--validation-api-light-red); - transition: background-color 0.2s ease; -} - -.has-meta-validation-warnings button[aria-controls="validation-api:validation-sidebar"].is-pressed:hover { - background-color: var(--validation-api-light-yellow); - transition: background-color 0.2s ease; -} - -.has-meta-validation-errors button[aria-controls="validation-api:validation-sidebar"].is-pressed:hover { - background-color: var(--validation-api-light-red); - transition: background-color 0.2s ease; -} - -.validation-api-sidebar-icon { - padding: 2px 0; -} diff --git a/src/editor/components/ValidationIcon.js b/src/editor/components/ValidationIcon.js index ac52adf..ee345f3 100644 --- a/src/editor/components/ValidationIcon.js +++ b/src/editor/components/ValidationIcon.js @@ -10,7 +10,7 @@ export function ValidationIcon({ fill = 'currentColor' }) { return ( diff --git a/src/editor/components/ValidationSidebar.js b/src/editor/components/ValidationSidebar.js index bb9fc5a..28f57f9 100644 --- a/src/editor/components/ValidationSidebar.js +++ b/src/editor/components/ValidationSidebar.js @@ -260,22 +260,6 @@ export function ValidationSidebar() { }, 100); }; - /** - * Handle clicking on a meta field validation issue - * - * Placeholder for future enhancement. Meta fields are typically in document - * settings panels that aren't directly scrollable. Users must navigate to - * the appropriate settings panel manually. - * - * @param {string} metaKey - The meta key of the field with the issue (reserved for future use). - */ - // eslint-disable-next-line no-unused-vars - const handleMetaClick = metaKey => { - // Meta fields are in document settings panels that can't be directly scrolled to - // Users should navigate to the appropriate settings panel manually - // Future: Use metaKey to open/focus the relevant settings panel - }; - /** * Cleanup scroll timeout on component unmount * diff --git a/src/editor/components/ValidationToolbarButton.js b/src/editor/components/ValidationToolbarButton.js index 4e55cf1..10ea73b 100644 --- a/src/editor/components/ValidationToolbarButton.js +++ b/src/editor/components/ValidationToolbarButton.js @@ -35,7 +35,7 @@ export function ValidationToolbarButton({ issues }) { const icon = hasBlockErrors ? ( ) : ( - + ); const openModal = () => setIsModalOpen(true); diff --git a/src/editor/hoc/index.js b/src/editor/hoc/index.js deleted file mode 100644 index 9e4f54a..0000000 --- a/src/editor/hoc/index.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Higher-Order Components - * - * Barrel export for editor HOCs. - */ - -// withErrorHandling doesn't have a default export, it's directly defined and registered -// Re-export is not needed as it registers itself via wp.hooks.addFilter diff --git a/src/editor/hoc/withBlockValidationClasses.js b/src/editor/hoc/withBlockValidationClasses.js index 45a1565..fe48560 100644 --- a/src/editor/hoc/withBlockValidationClasses.js +++ b/src/editor/hoc/withBlockValidationClasses.js @@ -1,3 +1,8 @@ +/** + * WordPress dependencies + */ +import { addFilter } from '@wordpress/hooks'; + /** * Internal dependencies */ @@ -36,7 +41,7 @@ function withBlockValidationClasses(BlockListBlock) { }; } -wp.hooks.addFilter( +addFilter( 'editor.BlockListBlock', 'validation-api/with-block-validation-classes', withBlockValidationClasses diff --git a/src/editor/index.js b/src/editor/index.js deleted file mode 100644 index 89bf72d..0000000 --- a/src/editor/index.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Editor Module - * - * Barrel export for all editor code. - */ - -export * from './components'; -export * from './hoc'; -export * from './validation'; diff --git a/src/editor/register.js b/src/editor/register.js index a12617d..f2cc0b5 100644 --- a/src/editor/register.js +++ b/src/editor/register.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { registerPlugin } from '@wordpress/plugins'; -import { addFilter } from '@wordpress/hooks'; /** * Internal dependencies @@ -10,57 +9,6 @@ import { addFilter } from '@wordpress/hooks'; import { ValidationAPI } from './validation/ValidationAPI'; import { ValidationSidebar } from './components/ValidationSidebar'; -/** - * Filter callback for block registration (currently a placeholder). - * - * This function is reserved for future enhancement to add custom categories - * or modify block settings during registration. Currently returns settings - * unchanged to maintain the filter hook registration point. - * - * @param {Object} settings - The block type settings object. - * @return {Object} The unmodified settings object. - */ -function addBlockValidationCategory(settings) { - return settings; -} - -/** - * Register the block settings filter - * - * This filter runs when block types are registered, providing a hook point - * for adding validation-specific categories or settings to blocks in the future. - */ -addFilter( - 'blocks.registerBlockType', - 'validation-api/add-validation-category', - addBlockValidationCategory -); - -/** - * Dynamic proxy for accessing block validation rules from PHP. - * - * This Proxy object provides transparent access to validation rules that are - * registered server-side via PHP and exposed through the window object. The - * proxy allows JavaScript code to access rules as if they were stored locally, - * while actually fetching them from window.ValidationAPI.validationRules. - * - * Usage: blockChecksArray['core/image'] returns validation rules for the image block. - * - * @type {Proxy} - */ -export const blockChecksArray = new Proxy( - {}, - { - get(target, prop) { - // Access validation rules from the window object (populated by PHP) - if (window.ValidationAPI && window.ValidationAPI.validationRules) { - return window.ValidationAPI.validationRules[prop]; - } - return undefined; - }, - } -); - /** * Register the validation plugin with WordPress * diff --git a/src/editor/validation/ValidationAPI.js b/src/editor/validation/ValidationAPI.js index eff167b..de8284a 100644 --- a/src/editor/validation/ValidationAPI.js +++ b/src/editor/validation/ValidationAPI.js @@ -160,29 +160,23 @@ export function ValidationAPI() { // Apply error class if errors exist if (hasAnyErrors) { - document.body.classList.add('has-meta-validation-errors'); - document.body.classList.remove('has-meta-validation-warnings'); + document.body.classList.add('has-validation-errors'); + document.body.classList.remove('has-validation-warnings'); } // Apply warning class only if no errors but warnings exist else if (hasAnyWarnings) { - document.body.classList.add('has-meta-validation-warnings'); - document.body.classList.remove('has-meta-validation-errors'); + document.body.classList.add('has-validation-warnings'); + document.body.classList.remove('has-validation-errors'); } // Remove both classes if no issues else { - document.body.classList.remove( - 'has-meta-validation-errors', - 'has-meta-validation-warnings' - ); + document.body.classList.remove('has-validation-errors', 'has-validation-warnings'); } // Cleanup: Remove classes when component unmounts return () => { if (document.body) { - document.body.classList.remove( - 'has-meta-validation-errors', - 'has-meta-validation-warnings' - ); + document.body.classList.remove('has-validation-errors', 'has-validation-warnings'); } }; }, [invalidBlocks, invalidMeta, invalidEditorChecks, isValidContext, editorContext]); diff --git a/src/editor/validation/blocks/validateBlock.js b/src/editor/validation/blocks/validateBlock.js index 6c20cfd..bf71151 100644 --- a/src/editor/validation/blocks/validateBlock.js +++ b/src/editor/validation/blocks/validateBlock.js @@ -6,7 +6,6 @@ import { applyFilters } from '@wordpress/hooks'; /** * Internal dependencies */ -import { blockChecksArray } from '../../register'; import { isCheckEnabled, createIssue, @@ -32,7 +31,7 @@ export const validateBlock = block => { const issues = []; // All checks come from PHP-registered rules via wp_localize_script. - const checks = blockChecksArray[blockType] || {}; + const checks = window.ValidationAPI?.validationRules?.[blockType] || {}; // No checks registered for this block type - return valid. if (Object.keys(checks).length === 0) { diff --git a/src/editor/validation/editor/validateEditor.js b/src/editor/validation/editor/validateEditor.js index 809de86..4c59d3e 100644 --- a/src/editor/validation/editor/validateEditor.js +++ b/src/editor/validation/editor/validateEditor.js @@ -64,8 +64,6 @@ export function validateEditor(postType, blocks) { if (!isValid) { // Create issue object with all relevant information const issue = createIssue(rule, checkName); - // Ensure checkName is included (createIssue uses 'check' as primary key) - issue.checkName = checkName; issues.push(issue); } } diff --git a/src/editor/validation/index.js b/src/editor/validation/index.js deleted file mode 100644 index 26f3d0f..0000000 --- a/src/editor/validation/index.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Validation Module - * - * Barrel export for all validation code (blocks, editor, meta). - */ - -export * from './blocks'; -export * from './editor'; -export { ValidationAPI } from './ValidationAPI'; diff --git a/src/editor/validation/meta/validateMeta.js b/src/editor/validation/meta/validateMeta.js index 468a572..3c1e745 100644 --- a/src/editor/validation/meta/validateMeta.js +++ b/src/editor/validation/meta/validateMeta.js @@ -108,8 +108,6 @@ export function validateAllMetaChecks(postType, metaKey, value) { if (!isValid) { // Create issue object with all relevant information const issue = createIssue(rule, checkName, { metaKey }); - // Ensure checkName is included (createIssue uses 'check' as primary key) - issue.checkName = checkName; issues.push(issue); } } diff --git a/src/settings.scss b/src/settings.scss deleted file mode 100644 index 1dc2f69..0000000 --- a/src/settings.scss +++ /dev/null @@ -1,356 +0,0 @@ -@use "styles/variables"; - -/** - * Settings Styles - * - * DataViews-inspired table layout with extensible column architecture. - * Used across all settings pages (Core Blocks, Editor Validation, External Plugins). - */ - -// Admin page background -// Applied to all settings pages (core blocks, editor validation, external plugins) -body.toplevel_page_block-a11y-checks, -body.accessibility-validation_page_block-a11y-checks-post-page, -body[class*='accessibility-validation_page_block-a11y-checks-'] { - #wpcontent { - padding-left: 0; - } - - .wrap { - margin: 0; - } -} - -// Header section (React) -.validation-api-settings-header { - padding: var(--a11y-settings-space); - border-bottom: 1px solid var(--a11y-light-grey); - background: #fff; - - h1 { - margin: 0; - padding: 0; - font-size: 1.4rem; - font-weight: 500; - line-height: 1.3; - color: #1d2327; - } - - p { - font-size: 0.85rem; - color: var(--a11y-black); - margin: 5px 0 0 0; - } -} - -// Save notifications -.validation-api-settings-content .components-notice { - margin: calc(var(--a11y-settings-space) / 1.5) var(--a11y-settings-space); - background-color: var(--a11y-lightest-green); - border: 1px solid var(--a11y-green); - border-left: 5px solid var(--a11y-dark-green); - border-radius: 4px; -} - -// DataView container -.validation-api-dataview { - background: #fff; - margin: 32px 24px; - padding: 0; - border-radius: 4px; - overflow-x: auto; -} - -// Table container - using standard HTML table -.validation-api-dataview-table { - width: 100%; - border-collapse: collapse; - border-spacing: 0; - - &.widefat { - border: none; - } - - // Override WordPress widefat striped default styles - tbody tr, - tbody tr:nth-child(odd), - tbody tr:nth-child(even) { - background-color: #fff; - } - - tbody tr:hover { - background-color: var(--a11y-lightest-grey) !important; - } -} - -.validation-api-dataview-thead th, -.validation-api-dataview-table td { - padding: calc(var(--a11y-settings-space) / 2); - vertical-align: middle; - - &.validation-api-dataview-td-level { - padding-top: calc(calc(var(--a11y-settings-space) / 2) - 8px); - } -} - -// Table header -.validation-api-dataview-thead { - th { - font-size: var(--a11y-font-small); - font-weight: 500; - color: var(--a11y-black); - border-bottom: 1px solid var(--a11y-grey); - background: #fff; - text-align: left; - vertical-align: middle; - } - - // Set fixed widths for consistent column sizing across all tables - .validation-api-dataview-th-block { - min-width: 90px; - width: 10%; - } - - .validation-api-dataview-th-category { - min-width: 90px; - width: 10%; - } - - .validation-api-dataview-th-level { - min-width: 220px; - width: 220px; - } - - .validation-api-dataview-th-siteEditor { - width: 90px; - } - - // First column (check) will auto-fill remaining space - .validation-api-dataview-th-check { - min-width: 180px; - width: auto; - } -} - -.validation-api-dataview-th-content { - display: flex; - align-items: center; - gap: 2px; -} - -// Table cells -.validation-api-dataview-cell { - font-size: var(--a11y-font-small); - color: var(--a11y-black); - padding: calc(var(--a11y-settings-space) / 2); - border-bottom: 1px solid var(--a11y-light-grey); - vertical-align: middle; - text-align: left !important; - - &.validation-api-dataview-cell-level { - padding-top: calc(var(--a11y-settings-space) / 4); - } -} - -// Check description -.validation-api-check-description { - color: var(--a11y-black); -} - -// Block badge -.validation-api-block-badge, -.validation-api-category-badge { - display: inline-flex; - padding: 2px 8px; - background: var(--a11y-lightest-grey); - border: 1px solid var(--a11y-light-grey); - border-radius: 2px; - font-size: 0.65rem; - color: var(--a11y-black); - font-weight: 500; - white-space: nowrap; -} - -.validation-api-dataview-td-level { - .components-base-control { - width: 100%; - } - - .components-toggle-group-control { - border: 1px solid var(--a11y-grey); - background: #fff; - - &::before { - display: none; - } - - .components-toggle-group-control-option-base { - color: var(--a11y-black); - background: #fff; - - &:focus { - box-shadow: inset 0 0 0 1px #fff, 0 0 0 1.5px #2271b1; - z-index: 1; - position: relative; - } - - &:hover:not([aria-checked='true']) { - background-color: var(--a11y-lightest-grey); - } - - &[aria-checked='true'] { - background: var(--wp-admin-theme-color); - color: #fff; - } - } - } -} - -// // Heading levels checkboxes -.validation-api-heading-levels-checkboxes { - display: flex; - gap: 20px; - justify-content: flex-end; - - .components-checkbox-control__label { - font-size: var(--a11y-font-small); - font-weight: 500; - color: var(--a11y-black); - } -} - -// // Actions footer -.validation-api-settings-actions { - display: flex; - align-items: center; - gap: 20px; - padding: 0 var(--a11y-settings-space); - - .components-button.is-primary:not(:disabled) { - background-color: #2271b1; - border-color: #2271b1; - - &:hover { - background-color: var(--wp-admin-theme-color); - border-color: var(--wp-admin-theme-color); - } - } - - .validation-api-unsaved-notice { - font-size: var(--a11y-font-small); - color: var(--a11y-dark-red); - font-style: italic; - } -} - -// ======================================== -// Responsive Table Styles -// ======================================== - -// Tablet - reduce margins -@media screen and (max-width: 960px) { - .validation-api-settings-header, - .validation-api-settings-content .components-notice, - .validation-api-settings-actions { - margin-left: 24px; - margin-right: 24px; - padding-left: 24px; - padding-right: 24px; - } -} - -// Mobile - WordPress responsive table pattern -@media screen and (max-width: 782px) { - .validation-api-settings-header, - .validation-api-dataview, - .validation-api-settings-content .components-notice, - .validation-api-settings-actions { - margin-left: var(--a11y-settings-space-mobile); - margin-right: var(--a11y-settings-space-mobile); - padding-left: var(--a11y-settings-space-mobile); - padding-right: var(--a11y-settings-space-mobile); - } - - // Responsive table layout - .validation-api-dataview-table { - border: 0; - - thead { - display: none; - } - - tbody { - display: block; - } - - tr { - display: block; - margin-bottom: 16px; - border: 1px solid var(--a11y-light-grey); - border-radius: 4px; - background: #fff !important; - - &:last-child { - margin-bottom: 0; - } - } - - td { - display: block; - border: none; - text-align: left !important; - - &::before { - content: attr(data-colname) ": "; - font-weight: 600; - color: var(--a11y-dark-grey); - display: block; - margin-bottom: 4px; - font-size: 0.7rem; - text-transform: uppercase; - letter-spacing: 0.5px; - } - - &.validation-api-dataview-td-check { - padding-bottom: 12px; - margin-bottom: 12px; - border-bottom: 1px solid var(--a11y-light-grey); - - &::before { - margin-bottom: 6px; - } - } - - &.validation-api-dataview-td-level, - &.validation-api-dataview-td-siteEditor { - .components-toggle-group-control, - .components-toggle-control { - width: 100%; - } - } - } - } - - // Make heading levels checkboxes stack vertically - .validation-api-heading-levels-checkboxes { - flex-direction: column; - gap: 12px; - align-items: flex-start; - } - - // Settings actions stack vertically - .validation-api-settings-actions { - flex-direction: column; - align-items: stretch; - - .components-button { - width: 100%; - justify-content: center; - margin-bottom: 12px; - } - - .validation-api-unsaved-notice { - text-align: center; - } - } -} diff --git a/src/shared/index.js b/src/shared/index.js deleted file mode 100644 index 0d4ed1e..0000000 --- a/src/shared/index.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Shared Module - * - * Barrel export for all shared code (utilities, components, hooks, constants). - */ - -export * from './hooks'; -export * from './utils'; diff --git a/src/shared/utils/index.js b/src/shared/utils/index.js deleted file mode 100644 index 4e9beac..0000000 --- a/src/shared/utils/index.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Shared Utilities - * - * Barrel export for all shared utility functions. - */ - -export * from './validation'; diff --git a/src/shared/utils/validation/getInvalidBlocks.js b/src/shared/utils/validation/getInvalidBlocks.js index f6ecf78..ce880de 100644 --- a/src/shared/utils/validation/getInvalidBlocks.js +++ b/src/shared/utils/validation/getInvalidBlocks.js @@ -141,5 +141,5 @@ export function GetInvalidBlocks() { // Return the array of invalid block validation results // Note: getInvalidBlocksRecursive already filters to only invalid blocks - return invalidBlocks.filter(result => !result.isValid); + return invalidBlocks; } diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss index 732b725..c87ca37 100755 --- a/src/styles/_variables.scss +++ b/src/styles/_variables.scss @@ -1,11 +1,8 @@ :root { --validation-api-white: #fff; - --validation-api-light-blue: #dfe9ee; - --validation-api-blue: #507a96; --validation-api-lightest-grey: #f7f7f7; --validation-api-light-grey: #e8e8e8; --validation-api-grey: #b9b9b9; - --validation-api-medium-grey: #666; --validation-api-dark-grey: #474747; --validation-api-black: #1d2327; --validation-api-red: #d82000; @@ -14,10 +11,4 @@ --validation-api-yellow: #f0dc00; --validation-api-light-yellow: #fffde2; --validation-api-dark-yellow: #807500; - --validation-api-lightest-green: #f1fcf2; - --validation-api-green: #2aad40; - --validation-api-dark-green: #1b6027; - --validation-api-border-width: 3px solid; - --validation-api-settings-space: 32px; - --validation-api-font-small: 0.8rem; } \ No newline at end of file diff --git a/src/styles/validation-sidebar.scss b/src/styles/validation-sidebar.scss index cf22764..a37664b 100644 --- a/src/styles/validation-sidebar.scss +++ b/src/styles/validation-sidebar.scss @@ -2,6 +2,10 @@ fill: #fff; } +.validation-api-sidebar-icon { + padding: 2px 0; +} + // Colored circle in PanelBody titles (Errors / Warnings) .validation-api-errors-panel > .components-panel__body-title button::before, .validation-api-warnings-panel > .components-panel__body-title button::before { From 8cf60ed589c8a1338326769b3f43ad1fa06ed36d Mon Sep 17 00:00:00 2001 From: Troy Chaplin Date: Sat, 4 Apr 2026 11:13:32 -0400 Subject: [PATCH 3/3] remove unused svg --- src/assets/universal-access-error.svg | 1 - src/assets/universal-access-warning.svg | 1 - 2 files changed, 2 deletions(-) delete mode 100644 src/assets/universal-access-error.svg delete mode 100644 src/assets/universal-access-warning.svg diff --git a/src/assets/universal-access-error.svg b/src/assets/universal-access-error.svg deleted file mode 100644 index 082cb0a..0000000 --- a/src/assets/universal-access-error.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/assets/universal-access-warning.svg b/src/assets/universal-access-warning.svg deleted file mode 100644 index 28c71e2..0000000 --- a/src/assets/universal-access-warning.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file