From 292fb61ff2ff1179095160d830bc411e4d9a1757 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor Date: Mon, 10 Aug 2026 19:23:25 +0530 Subject: [PATCH 01/65] feat: add /sureforms:optimize-readme command for wp.org search-ranking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a copy-only skill that rewrites the three readme.txt fields WordPress.org search actually scores — title, short description, and Tags — grounded in the plugin-directory ranking code. Dry-run by default; --apply writes changes after title confirmation. Never touches versions, Stable tag, or quality signals, and enforces wp.org limits (150-char short desc, 5 tags, no competitor trademarks). --- .claude/commands/sureforms:optimize-readme.md | 139 ++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 .claude/commands/sureforms:optimize-readme.md diff --git a/.claude/commands/sureforms:optimize-readme.md b/.claude/commands/sureforms:optimize-readme.md new file mode 100644 index 000000000..5b62f6d0f --- /dev/null +++ b/.claude/commands/sureforms:optimize-readme.md @@ -0,0 +1,139 @@ +# SureForms readme.txt search-ranking optimizer + +Optimize the three readme.txt header fields that WordPress.org search actually scores — the +plugin **title**, the **short description**, and the **Tags** line — so SureForms ranks better for +its target keywords, without touching anything release-managed and without breaking WordPress.org +guidelines. + +This command **only rewrites copy**. It never bumps a version, never edits `Stable tag`, and never +invents facts. + +## Arguments + +Parse from: `$ARGUMENTS` + +- `keywords` — optional, comma-separated. The search terms to optimize for, most important first. + Default (SureForms' live priorities): `form, contact form, form builder, payment form, survey`. +- `--apply` — optional. Write the changes to `readme.txt`. Without it, run in **dry-run**: print the + proposed header and the reasoning, change nothing. + +Default is dry-run. The title is the plugin's public display name, so always show the before/after +and get a "yes" from the user before writing it, even with `--apply`. + +## Working directory + +Run from the sureforms plugin root — the directory containing `sureforms.php` and `readme.txt`. + +--- + +## How WordPress.org scores a search result (the facts this command relies on) + +Source of truth — read it if a rule below is ever in doubt: +`https://github.com/WordPress/wordpress.org/blob/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-search.php` + +Final score = **where the term matches** × **six quality signals**. + +**Where the term matches (per-field weight):** + +| Field | Weight | Editable here? | +|---|---|---| +| Plugin name (a whole word) **or** slug | 5 | Title: yes. Slug (`sureforms`): **no — immutable** | +| Author name | 3 | No | +| Term as a substring inside a title word (`form` in `SureForms`) | 2 | Indirect | +| Short description **or** Tags | 2 | **Yes — this is the main lever** | +| Anywhere else in the readme (description, FAQ, features) | 0.1 | Not worth optimizing | + +**The six quality signals (multipliers) — none live in these three fields:** +recent-update recency, `Tested up to` freshness, active installs (with a penalty under 1M), +percent of support threads resolved, and star-rating average. This command does **not** move them — +it only notes if `Tested up to` looks stale so a human can act. + +**The two consequences that drive every rewrite below:** + +1. The slug is `sureforms` (one word), so a search for `form` never gets the 5-point whole-word name + credit. The closest recoverable credit is a **standalone** high-value word in the *title* + (`Contact Form Builder` → `form` is its own word), which beats the 2-point substring credit from + `SureForms` alone. +2. Score is **concentrated** across the words in a field. A shorter title and a tight short + description give each keyword a larger share. Padding words dilute every keyword in the field. + +--- + +## Hard constraints — never cross these + +These protect the listing from being flagged or rejected. A rewrite that violates any of them is +worse than no rewrite. + +- **Short description: 150 characters max.** WordPress.org truncates past that. Count it. +- **Tags: only the first 5 are indexed.** Extra tags are dead weight — never list more than 5. +- **No competitor trademarks as keywords.** Never add `wpforms`, `gravity forms`, `ninja forms`, + `contact form 7`, `elementor`, `jetpack`, etc. to the title, tags, or short description. This is a + direct WordPress.org guideline violation and risks removal. +- **No keyword stuffing.** Repeating a keyword doesn't stack — the field is scored once per term. + `Form Builder, Form Maker, Form Creator, Forms` is stuffing; write natural phrases a human reads. +- **Only claim real features.** Every keyword must map to a shipped capability. Survey/Quiz/Calculator + are Business-tier — keep them phrased the way the current short description does (e.g. "in SureForms + Business") so the claim stays honest. Never add a keyword for a feature SureForms doesn't have. +- **Never edit** `Stable tag`, `Requires at least`, `Requires PHP`, `Contributors`, `License`, or the + `Plugin Name:` header in `sureforms.php`. If `Tested up to` is behind the current WordPress + release, only *report* it — do not change it (it must reflect a real tested version). +- **Keep the `=== ... ===` and header syntax intact** — WordPress.org's parser is strict. + +--- + +## Steps + +### 1 — Read the current header + +Read the top block of `readme.txt` (through the short-description line). Capture the current title, +short description (with its character count), and tags. + +### 2 — Score the current fields + +For each target keyword, note where it currently lands (whole word in title = 5, substring = 2, in +short description / tags = 2, or absent). List the gaps — a target keyword that only appears at 0.1 +weight, or not at all, is the opportunity. + +### 3 — Propose the rewrite + +Produce candidate values for the three fields, applying the two consequences above: + +- **Title** — front-load the highest-value keywords as **standalone words**, drop filler, keep it + reading like a real product name. Aim for ≤ ~9 words. Example shape: + `SureForms – Contact Form Builder, Payment Form, Survey, Quiz & Calculator`. +- **Short description** — one natural sentence, ≤ 150 chars, carrying the top 2–3 keywords that the + title couldn't. Report the exact character count. +- **Tags** — exactly the 5 highest-value distinct keywords, no overlap-for-overlap's-sake, no + trademarks. + +For **each** field, give a one-line rationale tied to the scoring model (which keyword moved from +which weight to which, or why a word was cut). + +### 4 — Show before/after + +Print a compact before → after for all three fields, the character count for the short description, +and any constraint check that mattered (e.g. "tags trimmed to 5", "short desc = 143/150"). If +`Tested up to` looks stale versus the current WordPress release, note it here as a separate +recommendation — do not fold it into the edit. + +### 5 — Apply (only with `--apply` and after title confirmation) + +On confirmation, use `Edit` to replace exactly the title line, the short-description line, and the +`Tags:` line in `readme.txt`. Change nothing else. Re-read the three lines and confirm the header +still parses (syntax intact, short desc ≤ 150, ≤ 5 tags). + +### 6 — Report + +Summarize what changed and what was deliberately left alone (versions, quality signals). Remind the +user that title/short-description/tags are also worth mirroring wherever the marketing site controls +the same listing, and that the quality-signal wins (resolving support threads, crossing 1M installs, +keeping `Tested up to` current) live outside this file. + +--- + +## Notes + +- Dry-run first. Only pass `--apply` once the copy reads well to a human — search reads it, but so do + buyers. +- This is intentionally a copy tool. If a rewrite ever tempts you to change a version or a quality + signal to "help the score", stop — that's out of scope and, for `Tested up to`, dishonest. From 7cbe33e91294606094f543312da4b222799041d5 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor Date: Mon, 10 Aug 2026 19:27:28 +0530 Subject: [PATCH 02/65] feat: harden optimize-readme skill with phrase adjacency + multiplier reference Adds the two factors the ranking artifacts prove but the first draft missed: - multi-word targets must be adjacent and early in the title (the factor that lets a 20k-install 2.7-star plugin outrank a 500k-install 4.9-star one for 'contact form'), reflected in the analysis and title-rewrite steps - verbatim function_score params for all six quality multipliers, so the skill can explain why a readme edit cannot move quality Also documents slug hyphen-tokenization and the title.engram substring match. --- .claude/commands/sureforms:optimize-readme.md | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/.claude/commands/sureforms:optimize-readme.md b/.claude/commands/sureforms:optimize-readme.md index 5b62f6d0f..d7721ed71 100644 --- a/.claude/commands/sureforms:optimize-readme.md +++ b/.claude/commands/sureforms:optimize-readme.md @@ -39,23 +39,44 @@ Final score = **where the term matches** × **six quality signals**. |---|---|---| | Plugin name (a whole word) **or** slug | 5 | Title: yes. Slug (`sureforms`): **no — immutable** | | Author name | 3 | No | -| Term as a substring inside a title word (`form` in `SureForms`) | 2 | Indirect | -| Short description **or** Tags | 2 | **Yes — this is the main lever** | -| Anywhere else in the readme (description, FAQ, features) | 0.1 | Not worth optimizing | +| Term as a substring inside a title word (`form` in `SureForms`, via the `title.engram` analyzer) | 2 | Indirect | +| Short description **or** Tags (`excerpt`, `description`, `tags`) | 2 | **Yes — this is the main lever** | +| Anywhere else in the readme (description body, FAQ, features) | 0.1 | Not worth optimizing | -**The six quality signals (multipliers) — none live in these three fields:** -recent-update recency, `Tested up to` freshness, active installs (with a penalty under 1M), -percent of support threads resolved, and star-rating average. This command does **not** move them — -it only notes if `Tested up to` looks stale so a human can act. +Search analyzers split the **slug on hyphens**, so `contact-form-7` indexes as `contact` · `form` · +`7` — each a whole-word ×5 match. `sureforms` is one indivisible token and can never produce a +standalone `form`, so it only ever earns the ×2 `title.engram` substring credit. The slug is +permanent on WordPress.org; do not plan around changing it. -**The two consequences that drive every rewrite below:** +**The six quality signals (multipliers) — none live in these three fields**, so this command never +touches them. Kept here only so the analysis can explain *why* a readme edit can't move quality, and +so a stale `Tested up to` gets flagged (not changed). Verbatim `function_score` params from the +[ranking code](https://github.com/WordPress/wordpress.org/blob/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-search.php#L313-L381): + +| Signal | Config | Rule of thumb | +|---|---|---| +| Last updated (`plugin_modified`) | decay, origin today, offset 180d, scale 360d, decay 0.5 | free for 6 months; ~×0.5 at ~18 months | +| Tested up to (`tested`) | decay, origin current WP, offset 0.1, scale 0.4, decay 0.6 | half a major version behind ≈ ×0.6 | +| Active installs (`active_installs`) | `log2p`, factor 0.375, missing 1 | log-scaled; 10k→100k ≈ 100k→1M | +| Under-1M penalty | decay, filter ≤ 1,000,000, origin 1M, scale 900k, decay 0.75 | extra ~×0.85 handicap below 1M installs | +| Support resolved (`support_threads_resolved`) | `log2p`, factor 0.25, missing 0.5 | resolved **percentage** scored directly | +| Star rating (`rating`) | `sqrt`, factor 0.25, missing 2.5 | only the **average** counts, never the review count | + +**The three consequences that drive every rewrite below:** 1. The slug is `sureforms` (one word), so a search for `form` never gets the 5-point whole-word name credit. The closest recoverable credit is a **standalone** high-value word in the *title* (`Contact Form Builder` → `form` is its own word), which beats the 2-point substring credit from `SureForms` alone. -2. Score is **concentrated** across the words in a field. A shorter title and a tight short - description give each keyword a larger share. Padding words dilute every keyword in the field. +2. Score is **concentrated per field** (Elasticsearch length-normalizes each field). A shorter title + and a tight short description give each keyword a larger share; padding words dilute *every* + keyword in the field. Past a point, adding a keyword to the title *lowers* the score of the ones + already there — keyword-stuffing the title is actively counterproductive. +3. For a **multi-word** target (`contact form`, `form builder`, `payment form`), position and + adjacency matter, not just presence. The winners hold the phrase as **consecutive tokens early in + a short field** — e.g. `Contact Form` as tokens 2–3 of a 4-token title beats the same words + buried mid-way through a 14-token one. This is the single factor that lets a 20k-install, 2.7★ + plugin outrank a 500k-install, 4.9★ one for "contact form". --- @@ -91,16 +112,26 @@ short description (with its character count), and tags. ### 2 — Score the current fields For each target keyword, note where it currently lands (whole word in title = 5, substring = 2, in -short description / tags = 2, or absent). List the gaps — a target keyword that only appears at 0.1 -weight, or not at all, is the opportunity. +short description / tags = 2, or absent). For **multi-word** keywords, also record whether the words +are adjacent and how early they sit — a phrase split apart or buried late is a weak match even if all +its words are present. Count the title's token length: a long title (say > ~9 words) is itself a +finding, because it dilutes every keyword in the ×5 field. List the gaps — a target keyword at 0.1 +weight, absent, non-adjacent, or stranded at the end of a long title is the opportunity. ### 3 — Propose the rewrite Produce candidate values for the three fields, applying the two consequences above: - **Title** — front-load the highest-value keywords as **standalone words**, drop filler, keep it - reading like a real product name. Aim for ≤ ~9 words. Example shape: - `SureForms – Contact Form Builder, Payment Form, Survey, Quiz & Calculator`. + reading like a real product name. Aim for ≤ ~9 words. Apply consequences 2 and 3: + - Put the **single most important target early** and as its own word (`Form Builder`, not only + `SureForms`). + - For a multi-word target, keep its words **adjacent and near the front** — e.g. lead with + `SureForms – Contact Form Builder` so `Contact Form` sits in tokens 2–3, then append the + lower-priority terms. Do not scatter the phrase across the title or repeat it. + - Stop adding keywords once the title reads like stuffing — each extra token shrinks the share of + the ones already there. Example shape: + `SureForms – Contact Form Builder, Payment Form, Survey, Quiz & Calculator`. - **Short description** — one natural sentence, ≤ 150 chars, carrying the top 2–3 keywords that the title couldn't. Report the exact character count. - **Tags** — exactly the 5 highest-value distinct keywords, no overlap-for-overlap's-sake, no From 249f361a51d2d2f65b1ee243de9bcb71d6e2de42 Mon Sep 17 00:00:00 2001 From: Avinash Kumar Sharma Date: Thu, 13 Aug 2026 23:20:44 +0530 Subject: [PATCH 03/65] fix: upload email body images to Media Library instead of embedding as base64 Images inserted via the Quill toolbar were stored as base64 data URLs (data:image/...) which get stripped by wp_kses_post() on save, causing the image to permanently disappear from the editor and sent emails. Replace FileReader.readAsDataURL() with a POST to /wp/v2/media so the image is uploaded to the WordPress Media Library and inserted as a real https:// URL that survives wp_kses_post() sanitization. Fixes #3036 Co-Authored-By: Claude Sonnet 4.6 --- .../email-settings/EditorToolbar.js | 51 ++++++++++++------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/src/admin/single-form-settings/components/email-settings/EditorToolbar.js b/src/admin/single-form-settings/components/email-settings/EditorToolbar.js index 8bacb33cc..841960d24 100644 --- a/src/admin/single-form-settings/components/email-settings/EditorToolbar.js +++ b/src/admin/single-form-settings/components/email-settings/EditorToolbar.js @@ -1,6 +1,7 @@ import { __, _x } from '@wordpress/i18n'; import parse from 'html-react-parser'; import svgIcons from '@Svg/svgs.json'; +import apiFetch from '@wordpress/api-fetch'; // Undo and redo functions for Custom Toolbar function undoChange() { @@ -10,8 +11,11 @@ function redoChange() { this.quill.history.redo(); } -// Custom image handler to add attributes to the image tag. +// Custom image handler — uploads the file to the WordPress Media Library +// and inserts the returned URL. This avoids base64 data URLs which are +// stripped by wp_kses_post() on the PHP save path. function imageHandler() { + const quill = this.quill; const input = document.createElement( 'input' ); input.setAttribute( 'type', 'file' ); input.setAttribute( 'accept', 'image/*' ); @@ -19,24 +23,37 @@ function imageHandler() { input.onchange = ( e ) => { const file = e.target.files[ 0 ]; - if ( /^image\//.test( file.type ) ) { - const reader = new FileReader(); - reader.onload = () => { - const base64Image = reader.result; - const range = this.quill.getSelection(); - this.quill.insertEmbed( range.index, 'image', { - src: base64Image, - alt: '', - 'aria-hidden': 'true', - } ); - }; - reader.onerror = () => { - console.error( 'Error while reading the file.' ); - }; - reader.readAsDataURL( file ); - } else { + if ( ! /^image\//.test( file.type ) ) { console.warn( 'You could only upload images.' ); + return; } + + const formData = new window.FormData(); + formData.append( 'file', file ); + + apiFetch( { + path: '/wp/v2/media', + method: 'POST', + body: formData, + } ) + .then( ( response ) => { + const url = + response?.source_url || + response?.media_details?.sizes?.full?.source_url; + if ( ! url ) { + console.error( 'Media upload succeeded but no URL returned.' ); + return; + } + const range = quill.getSelection( true ); + quill.insertEmbed( range.index, 'image', { + src: url, + alt: response?.alt_text || '', + 'aria-hidden': 'true', + } ); + } ) + .catch( ( err ) => { + console.error( 'Image upload failed:', err ); + } ); }; } From 702716ffc7e8dc78866b3094e810717a161341ee Mon Sep 17 00:00:00 2001 From: Vansh Kapoor Date: Sun, 16 Aug 2026 23:00:15 +0530 Subject: [PATCH 04/65] feat(embed): admin-only Edit Form shortcut on the embedded form (#3029) Renders a pill link into the form container that opens the block editor for the form, shown only to users who can edit_post that form. It is absent from the DOM (and its styles) for everyone else, so the layout and submission are untouched for visitors. Works across block, shortcode, widget and single embeds since all render through get_form_markup(); the scoped style prints once per request. --- inc/generate-form-markup.php | 85 ++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index d85c16281..396835ebf 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -638,6 +638,15 @@ public static function get_form_markup( $id, $show_title_current_page = true, $s $embed_custom_css = 'sureforms_form' !== $current_post_type ? $custom_css : ''; ?>
+ + + + + + + Date: Sun, 16 Aug 2026 23:08:47 +0530 Subject: [PATCH 05/65] feat(embed): show the Edit Form shortcut below the form, always visible (#3029) Moves the admin Edit Form button from a top-right hover overlay to a centered, always-visible control below the form, per review feedback. --- inc/generate-form-markup.php | 47 ++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index 396835ebf..0766871f6 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -638,15 +638,6 @@ public static function get_form_markup( $id, $show_title_current_page = true, $s $embed_custom_css = 'sureforms_form' !== $current_post_type ? $custom_css : ''; ?>
- - - - - + Date: Sun, 16 Aug 2026 23:11:25 +0530 Subject: [PATCH 06/65] feat(embed): overlay the Edit Form pill at the top-right, always visible (#3029) Per the issue's UI spec: an Elementor/Beaver-Builder-style edit overlay at the top-right corner of the form container, always visible. Absolutely positioned so it never affects the form layout; still fully absent from the DOM for non-editing users. --- inc/generate-form-markup.php | 39 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index 0766871f6..3f598226a 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -980,11 +980,12 @@ public static function get_form_markup( $id, $show_title_current_page = true, $s
Date: Sun, 16 Aug 2026 23:26:58 +0530 Subject: [PATCH 08/65] feat(dashboard): prompt to personalise a new form's Thank You message (#3030) Adds a dismissible dashboard prompt for the latest form still using the shipped default Thank You message, nudging the admin to customise it. Detection compares tag-stripped confirmation text against the default (robust to the icon-URL difference); the CTA deep-links into the editor with srfm_focus=thankyou; a per-form REST dismissal (edit_post re-checked) persists via _srfm_thankyou_prompt_dismissed, and the server only lists forms whose message is still default so it auto-clears once customised. --- admin/admin.php | 132 ++++++++++++++++++++++++++ inc/rest-api.php | 13 +++ src/admin/dashboard/Dashboard.js | 3 + src/admin/dashboard/ThankYouPrompt.js | 98 +++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 src/admin/dashboard/ThankYouPrompt.js diff --git a/admin/admin.php b/admin/admin.php index 09c7a1a7e..1b81d3921 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -247,6 +247,134 @@ public static function is_first_form_created() { return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0; } + /** + * Post meta flag: the "personalise your Thank You message" prompt was dismissed. + * + * @since x.x.x + */ + public const THANKYOU_PROMPT_DISMISSED_META = '_srfm_thankyou_prompt_dismissed'; + + /** + * Whether a form's confirmation message is still the shipped default. + * + * Compared on tag-stripped, whitespace-collapsed text rather than raw HTML: + * the default is stored with a base64 icon on creation but regenerated with a + * URL icon, so the markup differs while the wording does not. Any real edit to + * the heading or body text changes the text and flips this to false, which is + * exactly when the prompt should stop showing. + * + * @param int $form_id Form post ID. + * + * @since x.x.x + * @return bool + */ + public static function is_default_confirmation_message( $form_id ) { + $confirmation = get_post_meta( (int) $form_id, '_srfm_form_confirmation', true ); + + if ( ! is_array( $confirmation ) || ! isset( $confirmation[0]['message'] ) || ! is_string( $confirmation[0]['message'] ) ) { + return false; + } + + $message = $confirmation[0]['message']; + + if ( '' === trim( $message ) ) { + return false; + } + + $normalize = static function ( $html ) { + return trim( (string) preg_replace( '/\s+/', ' ', wp_strip_all_tags( (string) $html ) ) ); + }; + + return $normalize( $message ) === $normalize( Global_Settings::get_default_confirmation_message() ); + } + + /** + * The most recently created form still using the default Thank You message. + * + * Powers the dashboard prompt (#3030). Limited to the single latest such form + * to avoid clutter, and to forms the current user may actually edit. A form is + * a candidate only when its confirmation message is untouched (default) and + * the prompt has not been dismissed for it. + * + * @since x.x.x + * @return array One entry, or none. + */ + public static function get_thankyou_prompt_forms() { + if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { + return []; + } + + $query = new \WP_Query( + [ + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'orderby' => 'date', + 'order' => 'DESC', + 'fields' => 'ids', + 'no_found_rows' => true, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; the prompt is dashboard-only. + [ + 'key' => self::THANKYOU_PROMPT_DISMISSED_META, + 'compare' => 'NOT EXISTS', + ], + ], + ] + ); + + $prompts = []; + + foreach ( $query->posts as $form_id ) { + $form_id = (int) $form_id; + + if ( ! current_user_can( 'edit_post', $form_id ) || ! self::is_default_confirmation_message( $form_id ) ) { + continue; + } + + $edit_link = get_edit_post_link( $form_id, 'raw' ); + + if ( empty( $edit_link ) ) { + continue; + } + + $prompts[] = [ + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + // The editor reads srfm_focus to open the Thank You message panel. + 'edit_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), + ]; + + // One prompt is enough — surface only the latest such form. + break; + } + + return $prompts; + } + + /** + * REST handler: dismiss the Thank You message prompt for a form (#3030). + * + * Capability is re-checked against this specific form here, not just the + * route's generic permission callback, so a user can only dismiss the prompt + * on a form they may edit. + * + * @param \WP_REST_Request> $request Request. + * + * @since x.x.x + * @return \WP_REST_Response|\WP_Error + */ + public function dismiss_thankyou_prompt( $request ) { + $form_id = absint( $request->get_param( 'form_id' ) ); + + if ( $form_id <= 0 || ! defined( 'SRFM_FORMS_POST_TYPE' ) || SRFM_FORMS_POST_TYPE !== get_post_type( $form_id ) || ! current_user_can( 'edit_post', $form_id ) ) { + return new \WP_Error( 'srfm_thankyou_prompt_forbidden', __( 'You are not allowed to dismiss this prompt.', 'sureforms' ), [ 'status' => 403 ] ); + } + + update_post_meta( $form_id, self::THANKYOU_PROMPT_DISMISSED_META, true ); + + return new \WP_REST_Response( [ 'success' => true ], 200 ); + } + /** * Check and save the first form creation time stamp. * If not already saved. @@ -1049,6 +1177,10 @@ public function enqueue_scripts() { // Default confirmation message HTML (icon + heading + text) used as // the initial React state before the settings API response arrives. 'default_confirmation_message' => Global_Settings::get_default_confirmation_message(), + // Latest form still on the default Thank You message — powers the + // dashboard prompt (#3030). Empty when there is nothing to nudge about. + 'thankyou_prompt_forms' => self::get_thankyou_prompt_forms(), + 'thankyou_prompt_nonce' => wp_create_nonce( 'wp_rest' ), 'payments' => apply_filters( 'srfm_admin_localize_payments_data', [ diff --git a/inc/rest-api.php b/inc/rest-api.php index 0d2227acd..72b76b0ed 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1413,6 +1413,19 @@ private function get_endpoints() { 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], ], + // Dismiss the dashboard "personalise your Thank You message" prompt + // for a form (#3030). Per-form capability is re-checked in the handler. + 'dismiss-thankyou-prompt' => [ + 'methods' => 'POST', + 'callback' => [ \SRFM\Admin\Admin::get_instance(), 'dismiss_thankyou_prompt' ], + 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], + 'args' => [ + 'form_id' => [ + 'required' => true, + 'sanitize_callback' => 'absint', + ], + ], + ], // This route is used to initiate auth process when user tries to authenticate on billing portal. 'initiate-auth' => [ 'methods' => 'GET', diff --git a/src/admin/dashboard/Dashboard.js b/src/admin/dashboard/Dashboard.js index e34d0d334..600e621b9 100644 --- a/src/admin/dashboard/Dashboard.js +++ b/src/admin/dashboard/Dashboard.js @@ -8,6 +8,7 @@ import QuickAccessTab from './QuickAccessTab'; import UpgradeToPro from './UpgradeToPro'; import FormsOverview from './FormsOverview'; import AdminNotice from '../components/AdminNotice'; +import ThankYouPrompt from './ThankYouPrompt'; import { cn } from '@Utils/Helpers'; export default () => { @@ -44,6 +45,8 @@ export default () => {
) } + { /* Nudge to personalise a new form's Thank You message (#3030). */ } + { + const initial = Array.isArray( window.srfm_admin?.thankyou_prompt_forms ) + ? window.srfm_admin.thankyou_prompt_forms + : []; + const [ forms, setForms ] = useState( initial ); + + if ( ! forms.length ) { + return null; + } + + // Optimistically hide, then persist the dismissal. A failed request just + // means the prompt may reappear next load — never a blocking error. + const dismiss = ( formId ) => { + setForms( ( prev ) => prev.filter( ( form ) => form.id !== formId ) ); + apiFetch( { + path: 'sureforms/v1/dismiss-thankyou-prompt', + method: 'POST', + data: { form_id: formId }, + headers: { 'X-WP-Nonce': window.srfm_admin?.thankyou_prompt_nonce }, + } ).catch( () => {} ); + }; + + return ( +
+ { forms.map( ( form ) => ( +
+
+
+ +
+
+ + <p className="m-0 text-sm text-text-secondary"> + { sprintf( + /* translators: %s: form name. */ + __( + 'Your form “%s” is using the default Thank You message. Personalize it to improve the post-submission experience.', + 'sureforms' + ), + form.title + ) } + </p> + </div> + </div> + <div className="flex items-center gap-2 shrink-0"> + <Button + variant="primary" + size="sm" + onClick={ () => + window.location.assign( form.edit_url ) + } + > + { __( 'Edit Thank You Message', 'sureforms' ) } + </Button> + <Button + variant="ghost" + size="sm" + icon={ <X className="size-4" /> } + onClick={ () => dismiss( form.id ) } + aria-label={ __( 'Dismiss', 'sureforms' ) } + /> + </div> + </div> + ) ) } + </div> + ); +}; + +export default ThankYouPrompt; From 3e4068ce3f17d5eb51f118d806f1e4c2115bf452 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Sun, 16 Aug 2026 23:37:48 +0530 Subject: [PATCH 09/65] feat(dashboard): "Finish setting up" card guiding new forms to completion (#3031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfaces the latest form the user can edit that still has an unfinished setup step — no reply destination, the default thank-you message, or not embedded on a page — with a contextual sentence and a CTA per incomplete step (Edit form, Set where replies go, Edit the thank-you message, Add to a page). Dismiss and a 14-day snooze persist per form via post meta; the card auto-clears once every step is done since the server only lists incomplete forms. Embed detection is a bounded LIKE over published content. --- admin/admin.php | 224 +++++++++++++++++++++++++++ inc/rest-api.php | 16 ++ src/admin/dashboard/Dashboard.js | 3 + src/admin/dashboard/FormSetupCard.js | 180 +++++++++++++++++++++ 4 files changed, 423 insertions(+) create mode 100644 src/admin/dashboard/FormSetupCard.js diff --git a/admin/admin.php b/admin/admin.php index 09c7a1a7e..ae81b4028 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -247,6 +247,226 @@ public static function is_first_form_created() { return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0; } + /** + * Post meta: the "Finish setting up" card was dismissed for this form. + * + * @since x.x.x + */ + public const SETUP_CARD_DISMISSED_META = '_srfm_setup_card_dismissed'; + + /** + * Post meta: unix time until which the "Finish setting up" card is snoozed. + * + * @since x.x.x + */ + public const SETUP_CARD_SNOOZE_META = '_srfm_setup_card_snooze_until'; + + /** + * The "Finish setting up" card for the latest form that still needs setup (#3031). + * + * Surfaces the newest published form the current user can edit which still has + * an unfinished setup step — its confirmation is the default, no enabled email + * notification has a recipient, or it isn't embedded on a page — and which has + * not been dismissed or snoozed. Returns the form, how long ago it was created, + * and which steps remain, so the dashboard can render the contextual nudge and + * its per-step CTAs. Null when there is nothing to prompt about. + * + * @since x.x.x + * @return array<string,mixed>|null + */ + public static function get_form_setup_card() { + if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { + return null; + } + + $now = time(); + + $query = new \WP_Query( + [ + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'orderby' => 'date', + 'order' => 'DESC', + 'fields' => 'ids', + 'no_found_rows' => true, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. + [ + 'key' => self::SETUP_CARD_DISMISSED_META, + 'compare' => 'NOT EXISTS', + ], + ], + ] + ); + + foreach ( $query->posts as $form_id ) { + $form_id = (int) $form_id; + + if ( ! current_user_can( 'edit_post', $form_id ) ) { + continue; + } + + $snooze_until = (int) get_post_meta( $form_id, self::SETUP_CARD_SNOOZE_META, true ); + + if ( $snooze_until > $now ) { + continue; + } + + $steps = [ + // A destination for replies: an enabled notification with a recipient. + 'replies' => ! self::form_has_reply_destination( $form_id ), + // The thank-you message is still the shipped default. + 'thankyou' => self::is_default_confirmation_message( $form_id ), + // The form is not embedded on any published page or post. + 'page' => ! self::form_is_embedded( $form_id ), + ]; + + // Nothing left to finish — no card for this form. + if ( ! $steps['replies'] && ! $steps['thankyou'] && ! $steps['page'] ) { + continue; + } + + $edit_link = get_edit_post_link( $form_id, 'raw' ); + + if ( empty( $edit_link ) ) { + continue; + } + + $created = get_post_time( 'U', true, $form_id ); + $days_ago = is_int( $created ) ? (int) floor( ( $now - $created ) / DAY_IN_SECONDS ) : 0; + + return [ + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'days_ago' => max( 0, $days_ago ), + 'steps' => $steps, + 'edit_url' => $edit_link, + 'replies_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), + // Where "Add to a page" sends the user: a fresh page to embed into. + 'page_url' => admin_url( 'post-new.php?post_type=page' ), + ]; + } + + return null; + } + + /** + * Whether a form is embedded on at least one published page or post. + * + * A bounded LIKE over published content matches the two embed forms SureForms + * emits — the `srfm/form` block (`"id":N`) and the `[sureforms id="N"]` + * shortcode — stopping at the first hit. Heuristic by design: it errs toward + * "embedded" so the card never nags about a form that is already placed. + * + * @param int $form_id Form post ID. + * + * @since x.x.x + * @return bool + */ + public static function form_is_embedded( $form_id ) { + global $wpdb; + + $form_id = (int) $form_id; + + $block_like = '%' . $wpdb->esc_like( 'srfm/form' ) . '%' . $wpdb->esc_like( '"id":' . $form_id ) . '%'; + $shortcode_like = '%' . $wpdb->esc_like( '[sureforms id="' . $form_id . '"' ) . '%'; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Bounded existence check for the dashboard setup card; no core API expresses a reverse "which pages embed form N" lookup. + $found = $wpdb->get_var( + $wpdb->prepare( + "SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( 'post', 'page' ) AND ( post_content LIKE %s OR post_content LIKE %s ) LIMIT 1", + $block_like, + $shortcode_like + ) + ); + + return ! empty( $found ); + } + + /** + * Whether a form has somewhere to send replies (an enabled email notification + * with a non-empty recipient). + * + * @param int $form_id Form post ID. + * + * @since x.x.x + * @return bool + */ + public static function form_has_reply_destination( $form_id ) { + $notifications = get_post_meta( (int) $form_id, '_srfm_email_notification', true ); + + if ( ! is_array( $notifications ) ) { + return false; + } + + foreach ( $notifications as $notification ) { + if ( is_array( $notification ) && ! empty( $notification['status'] ) && ! empty( $notification['email_to'] ) ) { + return true; + } + } + + return false; + } + + /** + * Whether a form's confirmation message is still the shipped default. + * + * Compared on tag-stripped text rather than raw HTML: the default is stored + * with a base64 icon on creation but regenerated with a URL icon, so the markup + * differs while the wording does not. Any real edit flips this to false. + * + * @param int $form_id Form post ID. + * + * @since x.x.x + * @return bool + */ + public static function is_default_confirmation_message( $form_id ) { + $confirmation = get_post_meta( (int) $form_id, '_srfm_form_confirmation', true ); + + if ( ! is_array( $confirmation ) || ! isset( $confirmation[0]['message'] ) || ! is_string( $confirmation[0]['message'] ) ) { + return false; + } + + if ( '' === trim( $confirmation[0]['message'] ) ) { + return false; + } + + $normalize = static function ( $html ) { + return trim( (string) preg_replace( '/\s+/', ' ', wp_strip_all_tags( (string) $html ) ) ); + }; + + return $normalize( $confirmation[0]['message'] ) === $normalize( Global_Settings::get_default_confirmation_message() ); + } + + /** + * REST handler: dismiss or snooze the "Finish setting up" card (#3031). + * + * `action=snooze` hides the card for 14 days; anything else dismisses it for + * good. Capability is re-checked against the specific form here, not just the + * route's generic permission callback. + * + * @param \WP_REST_Request<array<string,mixed>> $request Request. + * + * @since x.x.x + * @return \WP_REST_Response|\WP_Error + */ + public function dismiss_form_setup_card( $request ) { + $form_id = absint( $request->get_param( 'form_id' ) ); + + if ( $form_id <= 0 || ! defined( 'SRFM_FORMS_POST_TYPE' ) || SRFM_FORMS_POST_TYPE !== get_post_type( $form_id ) || ! current_user_can( 'edit_post', $form_id ) ) { + return new \WP_Error( 'srfm_setup_card_forbidden', __( 'You are not allowed to update this prompt.', 'sureforms' ), [ 'status' => 403 ] ); + } + + if ( 'snooze' === $request->get_param( 'action' ) ) { + update_post_meta( $form_id, self::SETUP_CARD_SNOOZE_META, time() + ( 14 * DAY_IN_SECONDS ) ); + } else { + update_post_meta( $form_id, self::SETUP_CARD_DISMISSED_META, true ); + } + + return new \WP_REST_Response( [ 'success' => true ], 200 ); + } + /** * Check and save the first form creation time stamp. * If not already saved. @@ -1049,6 +1269,10 @@ public function enqueue_scripts() { // Default confirmation message HTML (icon + heading + text) used as // the initial React state before the settings API response arrives. 'default_confirmation_message' => Global_Settings::get_default_confirmation_message(), + // The latest form still needing setup — powers the "Finish setting up" + // dashboard card (#3031). Null when nothing needs finishing. + 'form_setup_card' => self::get_form_setup_card(), + 'form_setup_card_nonce' => wp_create_nonce( 'wp_rest' ), 'payments' => apply_filters( 'srfm_admin_localize_payments_data', [ diff --git a/inc/rest-api.php b/inc/rest-api.php index 0d2227acd..0ec3607c3 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1413,6 +1413,22 @@ private function get_endpoints() { 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], ], + // Dismiss/snooze the dashboard "Finish setting up" card for a form + // (#3031). Per-form capability is re-checked in the handler. + 'dismiss-form-setup-card' => [ + 'methods' => 'POST', + 'callback' => [ \SRFM\Admin\Admin::get_instance(), 'dismiss_form_setup_card' ], + 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], + 'args' => [ + 'form_id' => [ + 'required' => true, + 'sanitize_callback' => 'absint', + ], + 'action' => [ + 'sanitize_callback' => 'sanitize_text_field', + ], + ], + ], // This route is used to initiate auth process when user tries to authenticate on billing portal. 'initiate-auth' => [ 'methods' => 'GET', diff --git a/src/admin/dashboard/Dashboard.js b/src/admin/dashboard/Dashboard.js index e34d0d334..17f9d4e97 100644 --- a/src/admin/dashboard/Dashboard.js +++ b/src/admin/dashboard/Dashboard.js @@ -8,6 +8,7 @@ import QuickAccessTab from './QuickAccessTab'; import UpgradeToPro from './UpgradeToPro'; import FormsOverview from './FormsOverview'; import AdminNotice from '../components/AdminNotice'; +import FormSetupCard from './FormSetupCard'; import { cn } from '@Utils/Helpers'; export default () => { @@ -44,6 +45,8 @@ export default () => { <AdminNotice currentPage="sureforms_menu" /> </div> ) } + { /* "Finish setting up" nudge for a form that still needs work (#3031). */ } + <FormSetupCard /> <Container className={ cn( ! window.srfm_admin?.notices?.length && 'pt-5 xl:pt-8' diff --git a/src/admin/dashboard/FormSetupCard.js b/src/admin/dashboard/FormSetupCard.js new file mode 100644 index 000000000..155ffb4f8 --- /dev/null +++ b/src/admin/dashboard/FormSetupCard.js @@ -0,0 +1,180 @@ +/** + * Dashboard "Finish setting up" card (#3031). + * + * The server (`srfm_admin.form_setup_card`) hands over the latest form the user + * can edit that still has an unfinished setup step — no reply destination, the + * default thank-you message, or not embedded on a page — along with which steps + * remain. This renders the contextual nudge and a CTA per incomplete step, plus + * dismiss (✕) and a 14-day snooze, both persisted per form. + * + * @package + */ + +import { useState } from '@wordpress/element'; +import { __, _n, sprintf } from '@wordpress/i18n'; +import apiFetch from '@wordpress/api-fetch'; +import { Button, Title } from '@bsf/force-ui'; +import { X } from 'lucide-react'; + +// Join clause fragments as "a", "a and b", "a, b, and c". +const joinClauses = ( clauses ) => { + if ( clauses.length <= 1 ) { + return clauses.join( '' ); + } + if ( clauses.length === 2 ) { + return clauses.join( __( ' and ', 'sureforms' ) ); + } + return ( + clauses.slice( 0, -1 ).join( ', ' ) + + __( ', and ', 'sureforms' ) + + clauses[ clauses.length - 1 ] + ); +}; + +const FormSetupCard = () => { + const card = window.srfm_admin?.form_setup_card || null; + const [ visible, setVisible ] = useState( !! card ); + + if ( ! card || ! visible ) { + return null; + } + + const { + id, + title, + days_ago: daysAgo = 0, + steps = {}, + edit_url: editUrl, + replies_url: repliesUrl, + thankyou_url: thankyouUrl, + page_url: pageUrl, + } = card; + + // Optimistically hide, then persist. A failed request just means the card may + // reappear next load — never a blocking error. + const update = ( action ) => { + setVisible( false ); + apiFetch( { + path: 'sureforms/v1/dismiss-form-setup-card', + method: 'POST', + data: { form_id: id, action }, + headers: { 'X-WP-Nonce': window.srfm_admin?.form_setup_card_nonce }, + } ).catch( () => {} ); + }; + + const clauses = []; + if ( steps.replies ) { + clauses.push( __( 'replies have nowhere to go', 'sureforms' ) ); + } + if ( steps.page ) { + clauses.push( __( "the form isn't on a page", 'sureforms' ) ); + } + if ( steps.thankyou ) { + clauses.push( + __( 'the thank-you message is still the default', 'sureforms' ) + ); + } + + const timeText = + daysAgo > 0 + ? sprintf( + /* translators: %d: number of days. */ + _n( + 'You created this form %d day ago', + 'You created this form %d days ago', + daysAgo, + 'sureforms' + ), + daysAgo + ) + : __( 'You created this form recently', 'sureforms' ); + + return ( + <div className="pt-5 xl:pt-8"> + <div className="relative p-5 rounded-lg shadow-sm bg-background-primary border border-solid border-border-subtle"> + <Button + variant="ghost" + size="sm" + icon={ <X className="size-4" /> } + onClick={ () => update( 'dismiss' ) } + aria-label={ __( 'Dismiss', 'sureforms' ) } + className="absolute top-3 right-3" + /> + + <Title + tag="h3" + size="sm" + title={ sprintf( + /* translators: %s: form name. */ + __( 'Finish setting up “%s”', 'sureforms' ), + title + ) } + /> + + <p className="mt-1 mb-4 text-sm text-text-secondary max-w-2xl"> + { sprintf( + /* translators: 1: "You created this form N days ago", 2: what's left, e.g. "replies have nowhere to go, and the form isn't on a page". */ + __( + "%1$s and it isn't fully set up yet — %2$s.", + 'sureforms' + ), + timeText, + joinClauses( clauses ) + ) } + </p> + + <div className="flex flex-wrap items-center gap-x-5 gap-y-2"> + <Button + variant="primary" + size="sm" + onClick={ () => window.location.assign( editUrl ) } + > + { __( 'Edit form', 'sureforms' ) } + </Button> + + { steps.replies && ( + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( repliesUrl ) + } + > + { __( 'Set where replies go', 'sureforms' ) } + </Button> + ) } + { steps.thankyou && ( + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( thankyouUrl ) + } + > + { __( 'Edit the thank-you message', 'sureforms' ) } + </Button> + ) } + { steps.page && ( + <Button + variant="link" + size="sm" + onClick={ () => window.location.assign( pageUrl ) } + > + { __( 'Add to a page', 'sureforms' ) } + </Button> + ) } + + <button + type="button" + onClick={ () => update( 'snooze' ) } + className="p-0 ml-auto text-sm bg-transparent border-0 cursor-pointer text-text-tertiary hover:text-text-secondary" + > + { __( 'Remind me in two weeks', 'sureforms' ) } + </button> + </div> + </div> + </div> + ); +}; + +export default FormSetupCard; From 9a801c3fb43e1ed7df2da1db7cdce8274ce411c5 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 00:00:23 +0530 Subject: [PATCH 10/65] style(dashboard): match the Thank You prompt to the setup-card design (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restyles the prompt to the shared card treatment — a tinted icon square, title, description, and primary CTA — inside the dashboard's existing white-box card (rounded-xl, subtle border, soft shadow). --- src/admin/dashboard/ThankYouPrompt.js | 75 +++++++++++++++------------ 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/admin/dashboard/ThankYouPrompt.js b/src/admin/dashboard/ThankYouPrompt.js index 78b049642..063fa6958 100644 --- a/src/admin/dashboard/ThankYouPrompt.js +++ b/src/admin/dashboard/ThankYouPrompt.js @@ -44,34 +44,50 @@ const ThankYouPrompt = () => { { forms.map( ( form ) => ( <div key={ form.id } - className="flex items-center justify-between gap-3 p-4 mb-4 rounded-lg shadow-sm bg-background-primary border border-solid border-border-subtle" + className="relative flex items-start gap-4 p-5 mb-4 rounded-xl bg-background-primary border-0.5 border-solid border-border-subtle shadow-sm-blur-1" > - <div className="flex items-center gap-3 min-w-0"> - <div className="flex items-center justify-center p-2 rounded-md bg-background-secondary shrink-0"> - <MessageSquareText className="size-5 text-icon-primary" /> - </div> - <div className="min-w-0"> - <Title - tag="h3" - size="xs" - title={ __( - "Don't forget to personalize your Thank You message!", - 'sureforms' - ) } - /> - <p className="m-0 text-sm text-text-secondary"> - { sprintf( - /* translators: %s: form name. */ - __( - 'Your form “%s” is using the default Thank You message. Personalize it to improve the post-submission experience.', - 'sureforms' - ), - form.title - ) } - </p> - </div> + <Button + variant="ghost" + size="sm" + icon={ <X className="size-4" /> } + onClick={ () => dismiss( form.id ) } + aria-label={ __( 'Dismiss', 'sureforms' ) } + className="absolute top-3 right-3" + /> + + <div + className="flex items-center justify-center rounded-lg shrink-0" + style={ { + width: '2.5rem', + height: '2.5rem', + backgroundColor: '#FBEAE3', + } } + > + <MessageSquareText + className="size-5" + style={ { color: '#C15A3B' } } + /> </div> - <div className="flex items-center gap-2 shrink-0"> + + <div className="min-w-0 pr-6"> + <Title + tag="h3" + size="sm" + title={ __( + "Don't forget to personalize your Thank You message!", + 'sureforms' + ) } + /> + <p className="mt-1 mb-3 text-sm text-text-secondary"> + { sprintf( + /* translators: %s: form name. */ + __( + 'Your form “%s” is using the default Thank You message. Personalize it to improve the post-submission experience.', + 'sureforms' + ), + form.title + ) } + </p> <Button variant="primary" size="sm" @@ -81,13 +97,6 @@ const ThankYouPrompt = () => { > { __( 'Edit Thank You Message', 'sureforms' ) } </Button> - <Button - variant="ghost" - size="sm" - icon={ <X className="size-4" /> } - onClick={ () => dismiss( form.id ) } - aria-label={ __( 'Dismiss', 'sureforms' ) } - /> </div> </div> ) ) } From cc47393b713e2e2da6f3be65f30f068c101e4cff Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 00:26:03 +0530 Subject: [PATCH 11/65] feat(dashboard): expand the prompt into the full "Finish setting up" card (#3030) Adds Edit form + per-step CTAs (Set where replies go, Edit the thank-you message, Add to a page) and the setup-context copy, showing only the steps a form still needs (no reply destination, default thank-you, not embedded). Same icon/white-box treatment as before. --- admin/admin.php | 94 ++++++++++- src/admin/dashboard/ThankYouPrompt.js | 229 +++++++++++++++++++------- 2 files changed, 255 insertions(+), 68 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 1b81d3921..5694ee334 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -323,11 +323,26 @@ public static function get_thankyou_prompt_forms() { ); $prompts = []; + $now = time(); foreach ( $query->posts as $form_id ) { $form_id = (int) $form_id; - if ( ! current_user_can( 'edit_post', $form_id ) || ! self::is_default_confirmation_message( $form_id ) ) { + if ( ! current_user_can( 'edit_post', $form_id ) ) { + continue; + } + + $steps = [ + // A destination for replies: an enabled notification with a recipient. + 'replies' => ! self::form_has_reply_destination( $form_id ), + // The thank-you message is still the shipped default. + 'thankyou' => self::is_default_confirmation_message( $form_id ), + // The form is not embedded on any published page or post. + 'page' => ! self::form_is_embedded( $form_id ), + ]; + + // Nothing left to finish — no card for this form. + if ( ! $steps['replies'] && ! $steps['thankyou'] && ! $steps['page'] ) { continue; } @@ -337,20 +352,87 @@ public static function get_thankyou_prompt_forms() { continue; } + $created = get_post_time( 'U', true, $form_id ); + $days_ago = is_int( $created ) ? (int) floor( ( $now - $created ) / DAY_IN_SECONDS ) : 0; + $prompts[] = [ - 'id' => $form_id, - 'title' => get_the_title( $form_id ), - // The editor reads srfm_focus to open the Thank You message panel. - 'edit_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'days_ago' => max( 0, $days_ago ), + 'steps' => $steps, + 'edit_url' => $edit_link, + // The editor reads srfm_focus to open the matching settings panel. + 'replies_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), + // Where "Add to a page" sends the user: a fresh page to embed into. + 'page_url' => admin_url( 'post-new.php?post_type=page' ), ]; - // One prompt is enough — surface only the latest such form. + // One card is enough — surface only the latest form needing setup. break; } return $prompts; } + /** + * Whether a form is embedded on at least one published page or post. + * + * A bounded LIKE over published content matches the two embed forms SureForms + * emits — the `srfm/form` block (`"id":N`) and the `[sureforms id="N"]` + * shortcode — stopping at the first hit. Heuristic by design: errs toward + * "embedded" so the card never nags about a form that is already placed. + * + * @param int $form_id Form post ID. + * + * @since x.x.x + * @return bool + */ + public static function form_is_embedded( $form_id ) { + global $wpdb; + + $form_id = (int) $form_id; + + $block_like = '%' . $wpdb->esc_like( 'srfm/form' ) . '%' . $wpdb->esc_like( '"id":' . $form_id ) . '%'; + $shortcode_like = '%' . $wpdb->esc_like( '[sureforms id="' . $form_id . '"' ) . '%'; + + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Bounded existence check for the dashboard setup card; no core API expresses a reverse "which pages embed form N" lookup. + $found = $wpdb->get_var( + $wpdb->prepare( + "SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( 'post', 'page' ) AND ( post_content LIKE %s OR post_content LIKE %s ) LIMIT 1", + $block_like, + $shortcode_like + ) + ); + + return ! empty( $found ); + } + + /** + * Whether a form has somewhere to send replies (an enabled email notification + * with a non-empty recipient). + * + * @param int $form_id Form post ID. + * + * @since x.x.x + * @return bool + */ + public static function form_has_reply_destination( $form_id ) { + $notifications = get_post_meta( (int) $form_id, '_srfm_email_notification', true ); + + if ( ! is_array( $notifications ) ) { + return false; + } + + foreach ( $notifications as $notification ) { + if ( is_array( $notification ) && ! empty( $notification['status'] ) && ! empty( $notification['email_to'] ) ) { + return true; + } + } + + return false; + } + /** * REST handler: dismiss the Thank You message prompt for a form (#3030). * diff --git a/src/admin/dashboard/ThankYouPrompt.js b/src/admin/dashboard/ThankYouPrompt.js index 063fa6958..344cb5761 100644 --- a/src/admin/dashboard/ThankYouPrompt.js +++ b/src/admin/dashboard/ThankYouPrompt.js @@ -1,21 +1,35 @@ /** - * Dashboard prompt nudging the admin to personalise a new form's Thank You - * message (#3030). + * Dashboard "Finish setting up" card (#3030 / #3031). * - * The server (`srfm_admin.thankyou_prompt_forms`) lists only the latest form - * whose confirmation message is still the shipped default and which the current - * user may edit and has not dismissed — so this component just renders what it - * is given. The CTA deep-links into the editor with `srfm_focus=thankyou`; - * dismissing persists per form so it does not return on the next load. + * The server (`srfm_admin.thankyou_prompt_forms`) lists the latest form the + * current user can edit that still has an unfinished setup step — no reply + * destination, the default thank-you message, or not embedded on a page — along + * with which steps remain. This renders the contextual nudge with a CTA per + * incomplete step; dismissing persists per form so it does not return. * * @package */ import { useState } from '@wordpress/element'; -import { __, sprintf } from '@wordpress/i18n'; +import { __, _n, sprintf } from '@wordpress/i18n'; import apiFetch from '@wordpress/api-fetch'; import { Button, Title } from '@bsf/force-ui'; -import { X, MessageSquareText } from 'lucide-react'; +import { X, FileText } from 'lucide-react'; + +// Join clause fragments as "a", "a and b", "a, b, and c". +const joinClauses = ( clauses ) => { + if ( clauses.length <= 1 ) { + return clauses.join( '' ); + } + if ( clauses.length === 2 ) { + return clauses.join( __( ' and ', 'sureforms' ) ); + } + return ( + clauses.slice( 0, -1 ).join( ', ' ) + + __( ', and ', 'sureforms' ) + + clauses[ clauses.length - 1 ] + ); +}; const ThankYouPrompt = () => { const initial = Array.isArray( window.srfm_admin?.thankyou_prompt_forms ) @@ -28,7 +42,7 @@ const ThankYouPrompt = () => { } // Optimistically hide, then persist the dismissal. A failed request just - // means the prompt may reappear next load — never a blocking error. + // means the card may reappear next load — never a blocking error. const dismiss = ( formId ) => { setForms( ( prev ) => prev.filter( ( form ) => form.id !== formId ) ); apiFetch( { @@ -41,65 +55,156 @@ const ThankYouPrompt = () => { return ( <div className="pt-5 xl:pt-8"> - { forms.map( ( form ) => ( - <div - key={ form.id } - className="relative flex items-start gap-4 p-5 mb-4 rounded-xl bg-background-primary border-0.5 border-solid border-border-subtle shadow-sm-blur-1" - > - <Button - variant="ghost" - size="sm" - icon={ <X className="size-4" /> } - onClick={ () => dismiss( form.id ) } - aria-label={ __( 'Dismiss', 'sureforms' ) } - className="absolute top-3 right-3" - /> + { forms.map( ( form ) => { + const steps = form.steps || {}; + const daysAgo = Number( form.days_ago ) || 0; - <div - className="flex items-center justify-center rounded-lg shrink-0" - style={ { - width: '2.5rem', - height: '2.5rem', - backgroundColor: '#FBEAE3', - } } - > - <MessageSquareText - className="size-5" - style={ { color: '#C15A3B' } } - /> - </div> + const clauses = []; + if ( steps.replies ) { + clauses.push( + __( 'replies have nowhere to go', 'sureforms' ) + ); + } + if ( steps.page ) { + clauses.push( __( "the form isn't on a page", 'sureforms' ) ); + } + if ( steps.thankyou ) { + clauses.push( + __( + 'the thank-you message is still the default', + 'sureforms' + ) + ); + } - <div className="min-w-0 pr-6"> - <Title - tag="h3" - size="sm" - title={ __( - "Don't forget to personalize your Thank You message!", + const timeText = + daysAgo > 0 + ? sprintf( + /* translators: %d: number of days. */ + _n( + 'You started this form %d day ago', + 'You started this form %d days ago', + daysAgo, 'sureforms' - ) } - /> - <p className="mt-1 mb-3 text-sm text-text-secondary"> - { sprintf( - /* translators: %s: form name. */ - __( - 'Your form “%s” is using the default Thank You message. Personalize it to improve the post-submission experience.', - 'sureforms' - ), - form.title - ) } - </p> + ), + daysAgo + ) + : __( 'You started this form recently', 'sureforms' ); + + return ( + <div + key={ form.id } + className="relative flex items-start gap-4 p-5 mb-4 rounded-xl bg-background-primary border-0.5 border-solid border-border-subtle shadow-sm-blur-1" + > <Button - variant="primary" + variant="ghost" size="sm" - onClick={ () => - window.location.assign( form.edit_url ) - } + icon={ <X className="size-4" /> } + onClick={ () => dismiss( form.id ) } + aria-label={ __( 'Dismiss', 'sureforms' ) } + className="absolute top-3 right-3" + /> + + <div + className="flex items-center justify-center rounded-xl shrink-0" + style={ { + width: '2.75rem', + height: '2.75rem', + backgroundColor: '#FBEAE3', + } } > - { __( 'Edit Thank You Message', 'sureforms' ) } - </Button> + <FileText + className="size-6" + style={ { color: '#C15A3B' } } + /> + </div> + + <div className="min-w-0 pr-6"> + <Title + tag="h3" + size="md" + title={ sprintf( + /* translators: %s: form name. */ + __( + 'Finish setting up “%s”', + 'sureforms' + ), + form.title + ) } + /> + <p className="mt-1.5 mb-4 text-sm text-text-secondary max-w-2xl"> + { sprintf( + /* translators: 1: "You started this form N days ago", 2: what's left, e.g. "replies have nowhere to go, and the form isn't on a page". */ + __( + "%1$s and haven't opened it since. It isn't collecting anything yet — %2$s.", + 'sureforms' + ), + timeText, + joinClauses( clauses ) + ) } + </p> + + <div className="flex flex-wrap items-center gap-x-5 gap-y-2"> + <Button + variant="primary" + size="sm" + onClick={ () => + window.location.assign( form.edit_url ) + } + > + { __( 'Edit form', 'sureforms' ) } + </Button> + + { steps.replies && ( + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( + form.replies_url + ) + } + > + { __( + 'Set where replies go', + 'sureforms' + ) } + </Button> + ) } + { steps.thankyou && ( + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( + form.thankyou_url + ) + } + > + { __( + 'Edit the thank-you message', + 'sureforms' + ) } + </Button> + ) } + { steps.page && ( + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( + form.page_url + ) + } + > + { __( 'Add to a page', 'sureforms' ) } + </Button> + ) } + </div> + </div> </div> - </div> - ) ) } + ); + } ) } </div> ); }; From e37ae155ebab8591a16ffa26f3cdf23f1857e945 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 00:31:42 +0530 Subject: [PATCH 12/65] feat(dashboard): drop "Add to a page", always show "Set where replies go" (#3030) Removes the page-embed step (and its detection) and un-gates the reply-destination and thank-you links so both always appear beside Edit form. --- admin/admin.php | 39 +------------- src/admin/dashboard/ThankYouPrompt.js | 73 +++++++++------------------ 2 files changed, 26 insertions(+), 86 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 5694ee334..2b4f656ef 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -337,12 +337,10 @@ public static function get_thankyou_prompt_forms() { 'replies' => ! self::form_has_reply_destination( $form_id ), // The thank-you message is still the shipped default. 'thankyou' => self::is_default_confirmation_message( $form_id ), - // The form is not embedded on any published page or post. - 'page' => ! self::form_is_embedded( $form_id ), ]; // Nothing left to finish — no card for this form. - if ( ! $steps['replies'] && ! $steps['thankyou'] && ! $steps['page'] ) { + if ( ! $steps['replies'] && ! $steps['thankyou'] ) { continue; } @@ -364,8 +362,6 @@ public static function get_thankyou_prompt_forms() { // The editor reads srfm_focus to open the matching settings panel. 'replies_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), - // Where "Add to a page" sends the user: a fresh page to embed into. - 'page_url' => admin_url( 'post-new.php?post_type=page' ), ]; // One card is enough — surface only the latest form needing setup. @@ -375,39 +371,6 @@ public static function get_thankyou_prompt_forms() { return $prompts; } - /** - * Whether a form is embedded on at least one published page or post. - * - * A bounded LIKE over published content matches the two embed forms SureForms - * emits — the `srfm/form` block (`"id":N`) and the `[sureforms id="N"]` - * shortcode — stopping at the first hit. Heuristic by design: errs toward - * "embedded" so the card never nags about a form that is already placed. - * - * @param int $form_id Form post ID. - * - * @since x.x.x - * @return bool - */ - public static function form_is_embedded( $form_id ) { - global $wpdb; - - $form_id = (int) $form_id; - - $block_like = '%' . $wpdb->esc_like( 'srfm/form' ) . '%' . $wpdb->esc_like( '"id":' . $form_id ) . '%'; - $shortcode_like = '%' . $wpdb->esc_like( '[sureforms id="' . $form_id . '"' ) . '%'; - - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Bounded existence check for the dashboard setup card; no core API expresses a reverse "which pages embed form N" lookup. - $found = $wpdb->get_var( - $wpdb->prepare( - "SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( 'post', 'page' ) AND ( post_content LIKE %s OR post_content LIKE %s ) LIMIT 1", - $block_like, - $shortcode_like - ) - ); - - return ! empty( $found ); - } - /** * Whether a form has somewhere to send replies (an enabled email notification * with a non-empty recipient). diff --git a/src/admin/dashboard/ThankYouPrompt.js b/src/admin/dashboard/ThankYouPrompt.js index 344cb5761..95a6b6652 100644 --- a/src/admin/dashboard/ThankYouPrompt.js +++ b/src/admin/dashboard/ThankYouPrompt.js @@ -65,9 +65,6 @@ const ThankYouPrompt = () => { __( 'replies have nowhere to go', 'sureforms' ) ); } - if ( steps.page ) { - clauses.push( __( "the form isn't on a page", 'sureforms' ) ); - } if ( steps.thankyou ) { clauses.push( __( @@ -155,51 +152,31 @@ const ThankYouPrompt = () => { { __( 'Edit form', 'sureforms' ) } </Button> - { steps.replies && ( - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( - form.replies_url - ) - } - > - { __( - 'Set where replies go', - 'sureforms' - ) } - </Button> - ) } - { steps.thankyou && ( - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( - form.thankyou_url - ) - } - > - { __( - 'Edit the thank-you message', - 'sureforms' - ) } - </Button> - ) } - { steps.page && ( - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( - form.page_url - ) - } - > - { __( 'Add to a page', 'sureforms' ) } - </Button> - ) } + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( + form.replies_url + ) + } + > + { __( 'Set where replies go', 'sureforms' ) } + </Button> + <Button + variant="link" + size="sm" + onClick={ () => + window.location.assign( + form.thankyou_url + ) + } + > + { __( + 'Edit the thank-you message', + 'sureforms' + ) } + </Button> </div> </div> </div> From be8f0cb6528eac002651a9d9c31f9f1c95d7224c Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 01:24:22 +0530 Subject: [PATCH 13/65] Open OttoKit (Automations) panel from the 'Set where replies go' deep-link The dashboard 'Finish setting up' card's 'Set where replies go' CTA now points the editor at ?srfm_focus=ottokit so it lands on the OttoKit (Automations) settings screen instead of Email Notification. GeneralSettings snapshots the srfm_focus target at bundle-eval time because the block editor strips unrecognised query args from the URL before a mount effect can read them; a load-window poll then opens the form-settings dialog on the target tab and forces the Force UI dialog overlay visible (its fade-in can stall when toggled amid the editor's initial render churn). --- admin/admin.php | 6 +- .../tabs/GeneralSettings.js | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 2b4f656ef..6c912eb98 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -359,8 +359,10 @@ public static function get_thankyou_prompt_forms() { 'days_ago' => max( 0, $days_ago ), 'steps' => $steps, 'edit_url' => $edit_link, - // The editor reads srfm_focus to open the matching settings panel. - 'replies_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + // The editor reads srfm_focus to open the matching settings panel: + // "replies" lands on OttoKit (Automations), "thankyou" on Form + // Confirmation. + 'replies_url' => add_query_arg( 'srfm_focus', 'ottokit', $edit_link ), 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), ]; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index d79e053aa..a762a12d3 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -15,6 +15,15 @@ import { prepareBlockSlugs } from '@Utils/Helpers'; let prevMetaHash = ''; +// Capture the dashboard deep-link target (?srfm_focus=…) the moment this +// bundle evaluates — the block editor strips unrecognised query args from the +// URL shortly after it boots, so reading the param later (inside a mount +// effect) finds it already gone. Snapshotting it here, before Gutenberg's URL +// cleanup runs, is what makes the deep-link reliable. +const srfmDeepLinkFocus = new URLSearchParams( window.location.search ).get( + 'srfm_focus' +); + function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -238,6 +247,59 @@ function GeneralSettings( props ) { }; }, [ sureformsKeys ] ); + // Deep-link support: open a specific form-settings panel when the editor is + // reached with ?srfm_focus=... — the dashboard "Finish setting up" card CTAs + // use this so "Set where replies go" lands on the OttoKit (Automations) + // screen, and "Edit the thank-you message" on Form Confirmation. The target + // is read from `srfmDeepLinkFocus`, snapshotted at bundle-eval time because + // the block editor strips the query arg from the URL before this effect runs. + useEffect( () => { + const tabByFocus = { + ottokit: 'ottokit', + thankyou: 'form_confirmation', + notifications: 'email_notification', + }; + const tabId = tabByFocus[ srfmDeepLinkFocus ]; + + if ( ! tabId ) { + return undefined; + } + + // Open the form-settings dialog on the target tab via the same window + // event the "Form Settings" popover uses. The editor mounts/remounts the + // settings panels during initial load and the listener re-registers on + // every meta change, so a single dispatch can miss it, and the Force UI + // dialog's opacity fade-in can stall when toggled amid that churn. Poll + // every 300ms across the load window: dispatch the open request only while + // the dialog isn't up yet (so it re-opens if a load-time re-render drops + // it, without needlessly re-firing once open), and force the overlay + // visible while it is, so the dialog reliably lands open and painted. + let elapsed = 0; + const ensureOpen = setInterval( () => { + elapsed += 300; + + const panel = document.querySelector( '.srfm-dialog-panel' ); + if ( panel ) { + const overlay = panel.closest( '.fixed.inset-0' ); + if ( overlay ) { + overlay.style.opacity = '1'; + } + } else { + window.dispatchEvent( + new CustomEvent( 'srfm-open-form-settings', { + detail: { tabId }, + } ) + ); + } + + if ( elapsed >= 12000 ) { + clearInterval( ensureOpen ); + } + }, 300 ); + + return () => clearInterval( ensureOpen ); + }, [] ); + return ( <> <SRFMAdvancedPanelBody From 55fd029187503e886e956955a820d583dfaeab04 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 01:33:43 +0530 Subject: [PATCH 14/65] Don't reopen the deep-linked settings dialog after the user closes it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The load-window poll re-dispatched the open event whenever the dialog panel was absent, so closing it (✕ / Esc / backdrop) within that window immediately reopened it. Track the dialog's own `isOpen` state via a ref: once it has opened, halt the poll the moment it goes back to false — a deliberate close flips state on the same live mount, whereas a load-time remount tears the effect down and re-runs it fresh, so churn still reopens while a user close stays closed. --- .../tabs/GeneralSettings.js | 50 +++++++++++++------ 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index a762a12d3..94b1cc9d6 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -4,7 +4,7 @@ import { useDeviceType } from '@Controls/getPreviewType'; import { ToggleControl } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; -import { useEffect, useState } from '@wordpress/element'; +import { useEffect, useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { applyFilters } from '@wordpress/hooks'; @@ -40,6 +40,10 @@ function GeneralSettings( props ) { const root = document.documentElement.querySelector( 'body' ); const [ isOpen, setOpen ] = useState( false ); const [ popupTab, setPopupTab ] = useState( false ); + // Mirrors `isOpen` for the deep-link poll below, which reads it from a + // long-lived interval closure that would otherwise see a stale value. + const isOpenRef = useRef( isOpen ); + isOpenRef.current = isOpen; const [ hasValidationErrors, setHasValidationErrors ] = useState( false ); const closeModal = () => { @@ -270,28 +274,46 @@ function GeneralSettings( props ) { // settings panels during initial load and the listener re-registers on // every meta change, so a single dispatch can miss it, and the Force UI // dialog's opacity fade-in can stall when toggled amid that churn. Poll - // every 300ms across the load window: dispatch the open request only while - // the dialog isn't up yet (so it re-opens if a load-time re-render drops - // it, without needlessly re-firing once open), and force the overlay - // visible while it is, so the dialog reliably lands open and painted. + // every 300ms: dispatch the open request until the dialog appears, then + // stop dispatching and just hold the overlay visible. + // + // Once it has opened, halt the poll the moment `isOpen` goes back to false + // — that is the user closing it (Esc / backdrop / ✕), which flips state on + // this same live mount. A load-time remount instead tears this effect down + // (clearing the interval) and re-runs it fresh on the new mount, so churn + // still reopens while a deliberate close stays closed. Give up after the + // load window if it never opened so the interval can't run indefinitely. let elapsed = 0; + let opened = false; const ensureOpen = setInterval( () => { elapsed += 300; - const panel = document.querySelector( '.srfm-dialog-panel' ); - if ( panel ) { - const overlay = panel.closest( '.fixed.inset-0' ); + // Dialog is open on this mount: mark it opened and hold the overlay + // painted (the fade-in can stall during load), then wait. + if ( isOpenRef.current ) { + opened = true; + const panel = document.querySelector( '.srfm-dialog-panel' ); + const overlay = panel?.closest( '.fixed.inset-0' ); if ( overlay ) { overlay.style.opacity = '1'; } - } else { - window.dispatchEvent( - new CustomEvent( 'srfm-open-form-settings', { - detail: { tabId }, - } ) - ); + return; } + // It was open and is now closed on this same live mount — the user + // dismissed it (✕ / Esc / backdrop). Stop; do not reopen. + if ( opened ) { + clearInterval( ensureOpen ); + return; + } + + // Not open yet — keep asking until the listener catches it. + window.dispatchEvent( + new CustomEvent( 'srfm-open-form-settings', { + detail: { tabId }, + } ) + ); + if ( elapsed >= 12000 ) { clearInterval( ensureOpen ); } From a7f2a7d612c9231a987cd3c40518c0e5002705ec Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 09:52:23 +0530 Subject: [PATCH 15/65] Move the form setup checklist to a WP dashboard widget (#3031) Render the 'Finish setting up' checklist as a server-side widget on the main WordPress dashboard instead of a React card on the SureForms dashboard, following the existing AI-widget convention (markup in the render callback, CSS + behaviour via wp_add_inline_style/script on empty-src handles, server values through wp_localize_script) so it stays Plugin-Check clean. - get_form_setup_card() now reports each step's completion (created, published, email, page) plus counts; includes drafts so 'publish' can be outstanding, and skips forms that are already fully set up. - The email step is driven by is_default_email_notification(): a form ships with a default admin notification that get_post_meta returns even when untouched, so the step is done only once the recipient, subject or body is customised (or a second notification is added, or it is disabled). - 'Set up email' deep-links to the Email Notification tab via GeneralSettings' srfm_focus handler (ported from #3030). - 'Get embed code' reveals the [sureforms id] shortcode inline with copy. - 'Remind me in two weeks' is a per-user snooze that hides the whole widget for 14 days, not just the current form. - Removes the superseded React FormSetupCard and its localization. --- admin/admin.php | 437 +++++++++++++++--- src/admin/dashboard/Dashboard.js | 3 - src/admin/dashboard/FormSetupCard.js | 180 -------- .../tabs/GeneralSettings.js | 85 +++- 4 files changed, 446 insertions(+), 259 deletions(-) delete mode 100644 src/admin/dashboard/FormSetupCard.js diff --git a/admin/admin.php b/admin/admin.php index ae81b4028..c82d6a3f6 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -139,6 +139,10 @@ public function __construct() { // Enqueue the AI quick draft widget script on the dashboard screen. add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_ai_dashboard_widget_assets' ] ); + // "Finish setting up" checklist widget on the main WP dashboard (#3031). + add_action( 'wp_dashboard_setup', [ $this, 'register_form_setup_widget' ] ); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_form_setup_widget_assets' ] ); + // Save first form creation time stamp. add_action( 'admin_init', [ $this, 'save_first_form_creation_time_stamp' ] ); add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] ); @@ -248,54 +252,65 @@ public static function is_first_form_created() { } /** - * Post meta: the "Finish setting up" card was dismissed for this form. + * User meta: unix time until which the "Finish setting up" widget is snoozed + * for this user across every form ("Remind me in two weeks"). Per-user rather + * than per-form so the reminder hides the whole widget, not just one form. * * @since x.x.x */ - public const SETUP_CARD_DISMISSED_META = '_srfm_setup_card_dismissed'; + public const SETUP_WIDGET_SNOOZE_USER_META = 'srfm_setup_widget_snooze_until'; /** - * Post meta: unix time until which the "Finish setting up" card is snoozed. + * Setup-checklist data for the newest form that still needs finishing (#3031). * - * @since x.x.x - */ - public const SETUP_CARD_SNOOZE_META = '_srfm_setup_card_snooze_until'; - - /** - * The "Finish setting up" card for the latest form that still needs setup (#3031). + * Picks the most recent form the current user can edit that is not yet ready for + * real submissions — and which has not been dismissed or snoozed — and reports + * the completion state of each setup step so the dashboard widget can render the + * checklist and its progress counter. Steps, each keyed by whether it is *done*: * - * Surfaces the newest published form the current user can edit which still has - * an unfinished setup step — its confirmation is the default, no enabled email - * notification has a recipient, or it isn't embedded on a page — and which has - * not been dismissed or snoozed. Returns the form, how long ago it was created, - * and which steps remain, so the dashboard can render the contextual nudge and - * its per-step CTAs. Null when there is nothing to prompt about. + * - created: the form exists (always done) + * - published: post status is `publish` + * - email: the default admin notification has been customized + * - page: the form is embedded on a published page or post + * + * Drafts are included so "publish" can legitimately be an outstanding step. A + * form with every step done is skipped — there is nothing to nudge. Memoized for + * the request so the widget register/enqueue/render passes share one query. * * @since x.x.x - * @return array<string,mixed>|null + * @return array<string,mixed>|null Checklist payload, or null when nothing needs finishing. */ public static function get_form_setup_card() { + static $cache = false; + + if ( false !== $cache ) { + return $cache; + } + + $cache = null; + if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { - return null; + return $cache; } $now = time(); + // "Remind me in two weeks" — a per-user snooze that hides the whole widget. + $widget_snooze_until = (int) get_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, true ); + + if ( $widget_snooze_until > $now ) { + return $cache; + } + $query = new \WP_Query( [ 'post_type' => SRFM_FORMS_POST_TYPE, - 'post_status' => 'publish', + 'post_status' => [ 'publish', 'draft', 'pending' ], 'posts_per_page' => 10, 'orderby' => 'date', 'order' => 'DESC', 'fields' => 'ids', 'no_found_rows' => true, - 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. - [ - 'key' => self::SETUP_CARD_DISMISSED_META, - 'compare' => 'NOT EXISTS', - ], - ], ] ); @@ -306,23 +321,21 @@ public static function get_form_setup_card() { continue; } - $snooze_until = (int) get_post_meta( $form_id, self::SETUP_CARD_SNOOZE_META, true ); - - if ( $snooze_until > $now ) { - continue; - } - + // Completion state of each checklist step (true = done). The email step + // is done only once the shipped default notification has been customized + // — every form ships with one, so mere presence is not "set up". $steps = [ - // A destination for replies: an enabled notification with a recipient. - 'replies' => ! self::form_has_reply_destination( $form_id ), - // The thank-you message is still the shipped default. - 'thankyou' => self::is_default_confirmation_message( $form_id ), - // The form is not embedded on any published page or post. - 'page' => ! self::form_is_embedded( $form_id ), + 'created' => true, + 'published' => 'publish' === get_post_status( $form_id ), + 'email' => ! self::is_default_email_notification( $form_id ), + 'page' => self::form_is_embedded( $form_id ), ]; - // Nothing left to finish — no card for this form. - if ( ! $steps['replies'] && ! $steps['thankyou'] && ! $steps['page'] ) { + $total = count( $steps ); + $done_count = count( array_filter( $steps ) ); + + // Ready for real submissions already — nothing to finish. + if ( $done_count >= $total ) { continue; } @@ -332,23 +345,23 @@ public static function get_form_setup_card() { continue; } - $created = get_post_time( 'U', true, $form_id ); - $days_ago = is_int( $created ) ? (int) floor( ( $now - $created ) / DAY_IN_SECONDS ) : 0; - - return [ - 'id' => $form_id, - 'title' => get_the_title( $form_id ), - 'days_ago' => max( 0, $days_ago ), - 'steps' => $steps, - 'edit_url' => $edit_link, - 'replies_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), - 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), - // Where "Add to a page" sends the user: a fresh page to embed into. - 'page_url' => admin_url( 'post-new.php?post_type=page' ), + $cache = [ + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'steps' => $steps, + 'done_count' => $done_count, + 'total' => $total, + 'edit_url' => $edit_link, + // Deep-links to the email-notification panel where supported; falls + // back to opening the editor when the focus handler isn't present. + 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + 'shortcode' => sprintf( '[sureforms id="%d"]', $form_id ), ]; + + return $cache; } - return null; + return $cache; } /** @@ -385,28 +398,56 @@ public static function form_is_embedded( $form_id ) { } /** - * Whether a form has somewhere to send replies (an enabled email notification - * with a non-empty recipient). + * Whether a form's email notification is still the shipped default (untouched). + * + * Every form is created with one "Admin Notification Email" — recipient + * `{admin_email}`, the default subject and an `{all_data}` body — and WordPress + * hands that registered default back from get_post_meta even when nothing is + * stored, so mere presence never means the owner has chosen who gets notified. + * The "Choose who gets notified" checklist step is therefore driven by whether + * this default has been customized: a second notification, a changed recipient, + * subject or body, or a disabled notification all count as touched. Compared on + * the recipient + subject + body, the fields that define who is notified and + * with what — cosmetic fields (reply-to, cc/bcc, from) are ignored. * * @param int $form_id Form post ID. * * @since x.x.x - * @return bool + * @return bool True when the notification matches the default; false once customized. */ - public static function form_has_reply_destination( $form_id ) { + public static function is_default_email_notification( $form_id ) { $notifications = get_post_meta( (int) $form_id, '_srfm_email_notification', true ); - if ( ! is_array( $notifications ) ) { + // No notification configured — untouched, so the step stays incomplete. + if ( ! is_array( $notifications ) || empty( $notifications ) ) { + return true; + } + + // A second notification is something the owner added — customized. + if ( 1 !== count( $notifications ) ) { return false; } - foreach ( $notifications as $notification ) { - if ( is_array( $notification ) && ! empty( $notification['status'] ) && ! empty( $notification['email_to'] ) ) { - return true; - } + $notification = $notifications[0]; + + if ( ! is_array( $notification ) ) { + return false; } - return false; + // A disabled notification is a deliberate change away from the default. + if ( empty( $notification['status'] ) ) { + return false; + } + + $default_subject = sprintf( + /* translators: %s: form title smart tag. */ + __( 'New Form Submission - %s', 'sureforms' ), + '{form_title}' + ); + + return '{admin_email}' === ( $notification['email_to'] ?? '' ) + && ( $notification['subject'] ?? '' ) === $default_subject + && '{all_data}' === ( $notification['email_body'] ?? '' ); } /** @@ -440,11 +481,13 @@ public static function is_default_confirmation_message( $form_id ) { } /** - * REST handler: dismiss or snooze the "Finish setting up" card (#3031). + * REST handler: snooze the "Finish setting up" widget for 14 days (#3031). * - * `action=snooze` hides the card for 14 days; anything else dismisses it for - * good. Capability is re-checked against the specific form here, not just the - * route's generic permission callback. + * The snooze is stored per-user, so "Remind me in two weeks" hides the whole + * widget rather than only the form currently shown. The request still carries + * the displayed form id: capability is re-checked against it here — beyond the + * route's generic permission callback — so only a genuine editor of that form + * can set the snooze. * * @param \WP_REST_Request<array<string,mixed>> $request Request. * @@ -458,11 +501,7 @@ public function dismiss_form_setup_card( $request ) { return new \WP_Error( 'srfm_setup_card_forbidden', __( 'You are not allowed to update this prompt.', 'sureforms' ), [ 'status' => 403 ] ); } - if ( 'snooze' === $request->get_param( 'action' ) ) { - update_post_meta( $form_id, self::SETUP_CARD_SNOOZE_META, time() + ( 14 * DAY_IN_SECONDS ) ); - } else { - update_post_meta( $form_id, self::SETUP_CARD_DISMISSED_META, true ); - } + update_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, time() + ( 14 * DAY_IN_SECONDS ) ); return new \WP_REST_Response( [ 'success' => true ], 200 ); } @@ -1269,10 +1308,6 @@ public function enqueue_scripts() { // Default confirmation message HTML (icon + heading + text) used as // the initial React state before the settings API response arrives. 'default_confirmation_message' => Global_Settings::get_default_confirmation_message(), - // The latest form still needing setup — powers the "Finish setting up" - // dashboard card (#3031). Null when nothing needs finishing. - 'form_setup_card' => self::get_form_setup_card(), - 'form_setup_card_nonce' => wp_create_nonce( 'wp_rest' ), 'payments' => apply_filters( 'srfm_admin_localize_payments_data', [ @@ -2346,6 +2381,258 @@ public function enqueue_ai_dashboard_widget_assets( $hook_suffix ) { wp_add_inline_script( 'srfm-ai-dashboard-widget', $inline_script ); } + /** + * Register the "Finish setting up" checklist widget on the main WP dashboard (#3031). + * + * Only for capable users, and only when there is a form still needing setup — + * so the widget never appears empty. The data is memoized in get_form_setup_card() + * and reused by the enqueue and render passes. + * + * @since x.x.x + * @return void + */ + public function register_form_setup_widget() { + if ( ! Helper::current_user_can() ) { + return; + } + + if ( null === self::get_form_setup_card() ) { + return; + } + + wp_add_dashboard_widget( + 'srfm_form_setup_checklist', + __( 'Finish setting up your form', 'sureforms' ), + [ $this, 'render_form_setup_widget' ], + null, + null, + 'normal', + 'high' + ); + } + + /** + * Render the setup-checklist widget content (#3031). + * + * A progress line, then one row per step with a completion check and — for the + * incomplete, actionable steps — a CTA. The "Get embed code" step reveals the + * form shortcode inline rather than navigating away. Dismiss (✕) and the 14-day + * snooze are wired in the enqueued inline script against the REST endpoint. + * + * @since x.x.x + * @return void + */ + public function render_form_setup_widget() { + $card = self::get_form_setup_card(); + + if ( null === $card ) { + return; + } + + $steps = $card['steps']; + + // Ordered rows. "created" is informational (always done); the rest carry a + // CTA while incomplete. The "page" step reveals the shortcode inline. + $rows = [ + [ + 'key' => 'created', + 'label' => __( 'Form created', 'sureforms' ), + ], + [ + 'key' => 'published', + 'label' => __( 'Review the fields and publish', 'sureforms' ), + 'cta' => __( 'Edit form', 'sureforms' ), + 'url' => $card['edit_url'], + ], + [ + 'key' => 'email', + 'label' => __( 'Choose who gets notified of new replies', 'sureforms' ), + 'cta' => __( 'Set up email', 'sureforms' ), + 'url' => $card['email_url'], + ], + [ + 'key' => 'page', + 'label' => __( 'Put the form on a page', 'sureforms' ), + 'cta' => __( 'Get embed code', 'sureforms' ), + 'is_embed' => true, + ], + ]; + + $progress = sprintf( + /* translators: 1: form title, 2: completed step count, 3: total step count. */ + __( '“%1$s” is %2$d of %3$d steps done', 'sureforms' ), + $card['title'], + $card['done_count'], + $card['total'] + ); + ?> + <div class="srfm-setup-checklist" id="srfm-setup-checklist"> + <p class="srfm-setup-checklist__title"><?php echo esc_html( $progress ); ?></p> + <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'Finish these and the form is ready for real submissions.', 'sureforms' ); ?></p> + + <ul class="srfm-setup-checklist__steps"> + <?php foreach ( $rows as $row ) : ?> + <?php $done = ! empty( $steps[ $row['key'] ] ); ?> + <li class="srfm-setup-checklist__step<?php echo $done ? ' is-done' : ''; ?>"> + <span class="srfm-setup-checklist__check" aria-hidden="true"><?php echo $done ? '✓' : ''; ?></span> + <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> + <?php if ( ! $done && ! empty( $row['cta'] ) ) : ?> + <?php if ( ! empty( $row['is_embed'] ) ) : ?> + <button type="button" class="srfm-setup-checklist__cta" id="srfm-setup-checklist-embed"><?php echo esc_html( $row['cta'] ); ?></button> + <?php else : ?> + <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> + <?php endif; ?> + <?php endif; ?> + </li> + <?php endforeach; ?> + </ul> + + <div class="srfm-setup-checklist__embed" id="srfm-setup-checklist-embed-box"> + <input type="text" readonly class="srfm-setup-checklist__embed-input" id="srfm-setup-checklist-embed-input" value="<?php echo esc_attr( $card['shortcode'] ); ?>" /> + <button type="button" class="button srfm-setup-checklist__embed-copy" id="srfm-setup-checklist-embed-copy"><?php esc_html_e( 'Copy', 'sureforms' ); ?></button> + </div> + + <button type="button" class="srfm-setup-checklist__snooze" id="srfm-setup-checklist-snooze"><?php esc_html_e( 'Remind me in two weeks', 'sureforms' ); ?></button> + </div> + <?php + } + + /** + * Enqueue the setup-checklist widget's styles and behavior on the dashboard (#3031). + * + * Mirrors the AI widget convention: an inline-only handle carries the CSS and the + * behavior (dismiss / snooze / reveal-and-copy embed code), with server values — + * the REST URL, nonce and form id — passed through wp_localize_script rather than + * printed into the markup, so it stays Plugin-Check clean. + * + * @param string $hook_suffix Current admin page hook suffix. + * + * @since x.x.x + * @return void + */ + public function enqueue_form_setup_widget_assets( $hook_suffix ) { + if ( 'index.php' !== $hook_suffix || ! Helper::current_user_can() ) { + return; + } + + $card = self::get_form_setup_card(); + + if ( null === $card ) { + return; + } + + $css = <<<'CSS' +#srfm_form_setup_checklist .inside { margin: 0; padding: 0; } +.srfm-setup-checklist { padding: 12px 16px 16px; } +.srfm-setup-checklist__title { margin: 0 0 4px; font-size: 15px; font-weight: 600; color: #1e1e1e; } +.srfm-setup-checklist__subtitle { margin: 0 0 12px; color: #646970; font-size: 13px; } +.srfm-setup-checklist__steps { margin: 0; padding: 0; list-style: none; } +.srfm-setup-checklist__step { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; } +.srfm-setup-checklist__step + .srfm-setup-checklist__step { margin-top: 6px; } +.srfm-setup-checklist__step:not(.is-done) { background: #f6f7f7; } +.srfm-setup-checklist__check { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%; border: 2px solid #c3c4c7; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; color: #fff; box-sizing: border-box; } +.srfm-setup-checklist__step.is-done .srfm-setup-checklist__check { background: #16a34a; border-color: #16a34a; } +.srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } +.srfm-setup-checklist__step.is-done .srfm-setup-checklist__label { text-decoration: line-through; color: #787c82; } +.srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } +.srfm-setup-checklist__cta:hover { color: #b83c14; } +.srfm-setup-checklist__embed { display: none; gap: 8px; margin: 10px 12px 0; } +.srfm-setup-checklist__embed.is-visible { display: flex; } +.srfm-setup-checklist__embed-input { flex: 1 1 auto; } +.srfm-setup-checklist__snooze { display: inline-block; margin-top: 14px; border: 0; background: transparent; padding: 0; font-size: 13px; color: #646970; text-decoration: underline; cursor: pointer; } +.srfm-setup-checklist__snooze:hover { color: #1e1e1e; } +CSS; + + wp_register_style( 'srfm-setup-checklist-widget', false, [], SRFM_VER ); + wp_enqueue_style( 'srfm-setup-checklist-widget' ); + wp_add_inline_style( 'srfm-setup-checklist-widget', $css ); + + wp_register_script( 'srfm-setup-checklist-widget', '', [], SRFM_VER, true ); + wp_enqueue_script( 'srfm-setup-checklist-widget' ); + + wp_localize_script( + 'srfm-setup-checklist-widget', + 'srfmSetupChecklist', + [ + 'restUrl' => esc_url_raw( rest_url( 'sureforms/v1/dismiss-form-setup-card' ) ), + 'nonce' => wp_create_nonce( 'wp_rest' ), + 'formId' => $card['id'], + 'copyTxt' => __( 'Copy', 'sureforms' ), + 'copiedTxt' => __( 'Copied', 'sureforms' ), + ] + ); + + $inline_script = <<<'JS' +( function () { + const cfg = window.srfmSetupChecklist || {}; + const widget = document.getElementById( 'srfm-setup-checklist' ); + if ( ! widget ) { + return; + } + + const persist = function ( action ) { + fetch( cfg.restUrl, { + method: 'POST', + credentials: 'same-origin', + headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': cfg.nonce }, + body: JSON.stringify( { form_id: cfg.formId, action: action } ), + } ).catch( function () {} ); + }; + + const removeWidget = function () { + const box = document.getElementById( 'srfm_form_setup_checklist' ); + ( box || widget ).remove(); + }; + + const snoozeBtn = document.getElementById( 'srfm-setup-checklist-snooze' ); + if ( snoozeBtn ) { + snoozeBtn.addEventListener( 'click', function () { + persist( 'snooze' ); + removeWidget(); + } ); + } + + const embedInput = document.getElementById( 'srfm-setup-checklist-embed-input' ); + const embedBtn = document.getElementById( 'srfm-setup-checklist-embed' ); + const embedBox = document.getElementById( 'srfm-setup-checklist-embed-box' ); + if ( embedBtn && embedBox ) { + embedBtn.addEventListener( 'click', function () { + const visible = embedBox.classList.toggle( 'is-visible' ); + if ( visible && embedInput ) { + embedInput.focus(); + embedInput.select(); + } + } ); + } + + const copyBtn = document.getElementById( 'srfm-setup-checklist-embed-copy' ); + if ( copyBtn && embedInput ) { + copyBtn.addEventListener( 'click', function () { + embedInput.focus(); + embedInput.select(); + const done = function () { + copyBtn.textContent = cfg.copiedTxt; + setTimeout( function () { + copyBtn.textContent = cfg.copyTxt; + }, 2000 ); + }; + if ( navigator.clipboard && navigator.clipboard.writeText ) { + navigator.clipboard.writeText( embedInput.value ).then( done ).catch( function () { + document.execCommand( 'copy' ); + done(); + } ); + } else { + document.execCommand( 'copy' ); + done(); + } + } ); + } +}() ); +JS; + + wp_add_inline_script( 'srfm-setup-checklist-widget', $inline_script ); + } + /** * Track AI dashboard widget usage. * diff --git a/src/admin/dashboard/Dashboard.js b/src/admin/dashboard/Dashboard.js index 17f9d4e97..e34d0d334 100644 --- a/src/admin/dashboard/Dashboard.js +++ b/src/admin/dashboard/Dashboard.js @@ -8,7 +8,6 @@ import QuickAccessTab from './QuickAccessTab'; import UpgradeToPro from './UpgradeToPro'; import FormsOverview from './FormsOverview'; import AdminNotice from '../components/AdminNotice'; -import FormSetupCard from './FormSetupCard'; import { cn } from '@Utils/Helpers'; export default () => { @@ -45,8 +44,6 @@ export default () => { <AdminNotice currentPage="sureforms_menu" /> </div> ) } - { /* "Finish setting up" nudge for a form that still needs work (#3031). */ } - <FormSetupCard /> <Container className={ cn( ! window.srfm_admin?.notices?.length && 'pt-5 xl:pt-8' diff --git a/src/admin/dashboard/FormSetupCard.js b/src/admin/dashboard/FormSetupCard.js deleted file mode 100644 index 155ffb4f8..000000000 --- a/src/admin/dashboard/FormSetupCard.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Dashboard "Finish setting up" card (#3031). - * - * The server (`srfm_admin.form_setup_card`) hands over the latest form the user - * can edit that still has an unfinished setup step — no reply destination, the - * default thank-you message, or not embedded on a page — along with which steps - * remain. This renders the contextual nudge and a CTA per incomplete step, plus - * dismiss (✕) and a 14-day snooze, both persisted per form. - * - * @package - */ - -import { useState } from '@wordpress/element'; -import { __, _n, sprintf } from '@wordpress/i18n'; -import apiFetch from '@wordpress/api-fetch'; -import { Button, Title } from '@bsf/force-ui'; -import { X } from 'lucide-react'; - -// Join clause fragments as "a", "a and b", "a, b, and c". -const joinClauses = ( clauses ) => { - if ( clauses.length <= 1 ) { - return clauses.join( '' ); - } - if ( clauses.length === 2 ) { - return clauses.join( __( ' and ', 'sureforms' ) ); - } - return ( - clauses.slice( 0, -1 ).join( ', ' ) + - __( ', and ', 'sureforms' ) + - clauses[ clauses.length - 1 ] - ); -}; - -const FormSetupCard = () => { - const card = window.srfm_admin?.form_setup_card || null; - const [ visible, setVisible ] = useState( !! card ); - - if ( ! card || ! visible ) { - return null; - } - - const { - id, - title, - days_ago: daysAgo = 0, - steps = {}, - edit_url: editUrl, - replies_url: repliesUrl, - thankyou_url: thankyouUrl, - page_url: pageUrl, - } = card; - - // Optimistically hide, then persist. A failed request just means the card may - // reappear next load — never a blocking error. - const update = ( action ) => { - setVisible( false ); - apiFetch( { - path: 'sureforms/v1/dismiss-form-setup-card', - method: 'POST', - data: { form_id: id, action }, - headers: { 'X-WP-Nonce': window.srfm_admin?.form_setup_card_nonce }, - } ).catch( () => {} ); - }; - - const clauses = []; - if ( steps.replies ) { - clauses.push( __( 'replies have nowhere to go', 'sureforms' ) ); - } - if ( steps.page ) { - clauses.push( __( "the form isn't on a page", 'sureforms' ) ); - } - if ( steps.thankyou ) { - clauses.push( - __( 'the thank-you message is still the default', 'sureforms' ) - ); - } - - const timeText = - daysAgo > 0 - ? sprintf( - /* translators: %d: number of days. */ - _n( - 'You created this form %d day ago', - 'You created this form %d days ago', - daysAgo, - 'sureforms' - ), - daysAgo - ) - : __( 'You created this form recently', 'sureforms' ); - - return ( - <div className="pt-5 xl:pt-8"> - <div className="relative p-5 rounded-lg shadow-sm bg-background-primary border border-solid border-border-subtle"> - <Button - variant="ghost" - size="sm" - icon={ <X className="size-4" /> } - onClick={ () => update( 'dismiss' ) } - aria-label={ __( 'Dismiss', 'sureforms' ) } - className="absolute top-3 right-3" - /> - - <Title - tag="h3" - size="sm" - title={ sprintf( - /* translators: %s: form name. */ - __( 'Finish setting up “%s”', 'sureforms' ), - title - ) } - /> - - <p className="mt-1 mb-4 text-sm text-text-secondary max-w-2xl"> - { sprintf( - /* translators: 1: "You created this form N days ago", 2: what's left, e.g. "replies have nowhere to go, and the form isn't on a page". */ - __( - "%1$s and it isn't fully set up yet — %2$s.", - 'sureforms' - ), - timeText, - joinClauses( clauses ) - ) } - </p> - - <div className="flex flex-wrap items-center gap-x-5 gap-y-2"> - <Button - variant="primary" - size="sm" - onClick={ () => window.location.assign( editUrl ) } - > - { __( 'Edit form', 'sureforms' ) } - </Button> - - { steps.replies && ( - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( repliesUrl ) - } - > - { __( 'Set where replies go', 'sureforms' ) } - </Button> - ) } - { steps.thankyou && ( - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( thankyouUrl ) - } - > - { __( 'Edit the thank-you message', 'sureforms' ) } - </Button> - ) } - { steps.page && ( - <Button - variant="link" - size="sm" - onClick={ () => window.location.assign( pageUrl ) } - > - { __( 'Add to a page', 'sureforms' ) } - </Button> - ) } - - <button - type="button" - onClick={ () => update( 'snooze' ) } - className="p-0 ml-auto text-sm bg-transparent border-0 cursor-pointer text-text-tertiary hover:text-text-secondary" - > - { __( 'Remind me in two weeks', 'sureforms' ) } - </button> - </div> - </div> - </div> - ); -}; - -export default FormSetupCard; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index d79e053aa..1c111e09c 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -4,7 +4,7 @@ import { useDeviceType } from '@Controls/getPreviewType'; import { ToggleControl } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; -import { useEffect, useState } from '@wordpress/element'; +import { useEffect, useRef, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { applyFilters } from '@wordpress/hooks'; @@ -15,6 +15,15 @@ import { prepareBlockSlugs } from '@Utils/Helpers'; let prevMetaHash = ''; +// Capture the dashboard deep-link target (?srfm_focus=…) the moment this +// bundle evaluates — the block editor strips unrecognised query args from the +// URL shortly after it boots, so reading the param later (inside a mount +// effect) finds it already gone. Snapshotting it here, before Gutenberg's URL +// cleanup runs, is what makes the deep-link reliable. +const srfmDeepLinkFocus = new URLSearchParams( window.location.search ).get( + 'srfm_focus' +); + function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -31,6 +40,10 @@ function GeneralSettings( props ) { const root = document.documentElement.querySelector( 'body' ); const [ isOpen, setOpen ] = useState( false ); const [ popupTab, setPopupTab ] = useState( false ); + // Mirrors `isOpen` for the deep-link poll below, which reads it from a + // long-lived interval closure that would otherwise see a stale value. + const isOpenRef = useRef( isOpen ); + isOpenRef.current = isOpen; const [ hasValidationErrors, setHasValidationErrors ] = useState( false ); const closeModal = () => { @@ -238,6 +251,76 @@ function GeneralSettings( props ) { }; }, [ sureformsKeys ] ); + // Deep-link support: open a specific form-settings panel when the editor is + // reached with ?srfm_focus=... — the dashboard setup-checklist CTAs use this so + // "Set up email" lands on the Email Notification tab. The target is read from + // `srfmDeepLinkFocus`, snapshotted at bundle-eval time because the block editor + // strips the query arg from the URL before this effect runs. + useEffect( () => { + const tabByFocus = { + ottokit: 'ottokit', + thankyou: 'form_confirmation', + notifications: 'email_notification', + }; + const tabId = tabByFocus[ srfmDeepLinkFocus ]; + + if ( ! tabId ) { + return undefined; + } + + // Open the form-settings dialog on the target tab via the same window + // event the "Form Settings" popover uses. The editor mounts/remounts the + // settings panels during initial load and the listener re-registers on + // every meta change, so a single dispatch can miss it, and the Force UI + // dialog's opacity fade-in can stall when toggled amid that churn. Poll + // every 300ms: dispatch the open request until the dialog appears, then + // stop dispatching and just hold the overlay visible. + // + // Once it has opened, halt the poll the moment `isOpen` goes back to false + // — that is the user closing it (Esc / backdrop / ✕), which flips state on + // this same live mount. A load-time remount instead tears this effect down + // (clearing the interval) and re-runs it fresh on the new mount, so churn + // still reopens while a deliberate close stays closed. Give up after the + // load window if it never opened so the interval can't run indefinitely. + let elapsed = 0; + let opened = false; + const ensureOpen = setInterval( () => { + elapsed += 300; + + // Dialog is open on this mount: mark it opened and hold the overlay + // painted (the fade-in can stall during load), then wait. + if ( isOpenRef.current ) { + opened = true; + const panel = document.querySelector( '.srfm-dialog-panel' ); + const overlay = panel?.closest( '.fixed.inset-0' ); + if ( overlay ) { + overlay.style.opacity = '1'; + } + return; + } + + // It was open and is now closed on this same live mount — the user + // dismissed it (✕ / Esc / backdrop). Stop; do not reopen. + if ( opened ) { + clearInterval( ensureOpen ); + return; + } + + // Not open yet — keep asking until the listener catches it. + window.dispatchEvent( + new CustomEvent( 'srfm-open-form-settings', { + detail: { tabId }, + } ) + ); + + if ( elapsed >= 12000 ) { + clearInterval( ensureOpen ); + } + }, 300 ); + + return () => clearInterval( ensureOpen ); + }, [] ); + return ( <> <SRFMAdvancedPanelBody From d59814a4a7e7c3803a645a2c1032b2f03d958ef1 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 15:56:31 +0530 Subject: [PATCH 16/65] Move the Thank You prompt to a WP dashboard notice (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Render the 'Finish setting up' prompt as a native admin notice on the main WordPress dashboard instead of a React card on the SureForms dashboard, matching the plugin's dashboard-asset convention: markup in the render callback, CSS and the dismiss handler via wp_add_inline_style/script on empty-src handles, and the REST URL, nonce and form id passed through wp_localize_script. - render_thankyou_prompt_notice() prints the notice (title, contextual sentence, Edit form / Set where replies go / Edit the thank-you message actions, and a ✕) only on the dashboard screen, for the newest editable form still needing setup. - enqueue_thankyou_prompt_assets() styles it in the SureForms brand orange (#D54407): orange accent bar and primary button, borderless orange text actions. - The ✕ reuses the existing dismiss-thankyou-prompt REST endpoint (per-form). - get_thankyou_prompt_forms() is memoized so the enqueue and render passes share one query. - Removes the superseded React ThankYouPrompt, its dashboard mount and its localization. --- admin/admin.php | 209 +++++++++++++++++++++++++- src/admin/dashboard/Dashboard.js | 3 - src/admin/dashboard/ThankYouPrompt.js | 189 ----------------------- 3 files changed, 205 insertions(+), 196 deletions(-) delete mode 100644 src/admin/dashboard/ThankYouPrompt.js diff --git a/admin/admin.php b/admin/admin.php index 6c912eb98..12234f256 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -144,6 +144,10 @@ public function __construct() { add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] ); add_action( 'admin_notices', [ $this, 'display_srfm_getting_started_notice' ] ); + // "Finish setting up" prompt, shown as a notice on the WP dashboard (#3030). + add_action( 'admin_notices', [ $this, 'render_thankyou_prompt_notice' ] ); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_thankyou_prompt_assets' ] ); + /** * Suppress foreign (third-party) admin notices on SureForms admin screens. * @@ -300,6 +304,26 @@ public static function is_default_confirmation_message( $form_id ) { * @return array<int,array{id:int,title:string,edit_url:string}> One entry, or none. */ public static function get_thankyou_prompt_forms() { + // Memoized for the request: the dashboard notice's enqueue and render + // passes both ask for this, and the query is otherwise run twice. + static $cache = false; + + if ( false !== $cache ) { + return $cache; + } + + $cache = self::compute_thankyou_prompt_forms(); + + return $cache; + } + + /** + * Build the Thank You prompt payload (uncached). See get_thankyou_prompt_forms(). + * + * @since x.x.x + * @return array<int,array<string,mixed>> One entry, or none. + */ + private static function compute_thankyou_prompt_forms() { if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { return []; } @@ -422,6 +446,187 @@ public function dismiss_thankyou_prompt( $request ) { return new \WP_REST_Response( [ 'success' => true ], 200 ); } + /** + * Join clause fragments as "a", "a and b", or "a, b, and c". + * + * @param array<int,string> $clauses Clause fragments. + * + * @since x.x.x + * @return string + */ + private static function join_clauses( $clauses ) { + $count = count( $clauses ); + + if ( $count <= 1 ) { + return implode( '', $clauses ); + } + + if ( 2 === $count ) { + return implode( __( ' and ', 'sureforms' ), $clauses ); + } + + $last = array_pop( $clauses ); + + return implode( ', ', $clauses ) . __( ', and ', 'sureforms' ) . $last; + } + + /** + * Render the "Finish setting up" prompt as a dashboard notice (#3030). + * + * Shown only on the main WordPress dashboard, for the newest form the current + * user can edit that still has an unfinished step (default thank-you message or + * no reply destination). The ✕ persists a per-form dismissal through the REST + * endpoint wired in enqueue_thankyou_prompt_assets(). + * + * @since x.x.x + * @return void + */ + public function render_thankyou_prompt_notice() { + if ( ! Helper::current_user_can() ) { + return; + } + + $screen = get_current_screen(); + + if ( ! $screen || 'dashboard' !== $screen->id ) { + return; + } + + $prompts = self::get_thankyou_prompt_forms(); + + if ( empty( $prompts ) ) { + return; + } + + $form = $prompts[0]; + $steps = isset( $form['steps'] ) && is_array( $form['steps'] ) ? $form['steps'] : []; + $days_ago = isset( $form['days_ago'] ) ? (int) $form['days_ago'] : 0; + + $clauses = []; + if ( ! empty( $steps['replies'] ) ) { + $clauses[] = __( 'replies have nowhere to go', 'sureforms' ); + } + if ( ! empty( $steps['thankyou'] ) ) { + $clauses[] = __( 'the thank-you message is still the default', 'sureforms' ); + } + + $time_text = $days_ago > 0 + ? sprintf( + /* translators: %d: number of days. */ + _n( 'You started this form %d day ago', 'You started this form %d days ago', $days_ago, 'sureforms' ), + $days_ago + ) + : __( 'You started this form recently', 'sureforms' ); + + $sentence = sprintf( + /* translators: 1: "You started this form N days ago", 2: what is left, e.g. "replies have nowhere to go, and the thank-you message is still the default". */ + __( '%1$s and haven\'t opened it since. It isn\'t collecting anything yet — %2$s.', 'sureforms' ), + $time_text, + self::join_clauses( $clauses ) + ); + ?> + <div class="notice notice-info srfm-thankyou-notice" id="srfm-thankyou-notice"> + <p class="srfm-thankyou-notice__title"> + <?php + echo esc_html( + sprintf( + /* translators: %s: form name. */ + __( 'Finish setting up “%s”', 'sureforms' ), + $form['title'] + ) + ); + ?> + </p> + <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> + <p class="srfm-thankyou-notice__actions"> + <a class="button button-primary" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> + <a class="button" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> + <a class="button" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the thank-you message', 'sureforms' ); ?></a> + </p> + <button type="button" class="notice-dismiss" id="srfm-thankyou-notice-dismiss"> + <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'sureforms' ); ?></span> + </button> + </div> + <?php + } + + /** + * Enqueue the Thank You dashboard notice's styles and dismiss behavior (#3030). + * + * Mirrors the plugin's other dashboard-widget assets: an inline-only handle + * carries the CSS and the dismiss handler, with the REST URL, nonce and form id + * passed via wp_localize_script rather than printed into the markup. + * + * @param string $hook_suffix Current admin page hook suffix. + * + * @since x.x.x + * @return void + */ + public function enqueue_thankyou_prompt_assets( $hook_suffix ) { + if ( 'index.php' !== $hook_suffix || ! Helper::current_user_can() ) { + return; + } + + $prompts = self::get_thankyou_prompt_forms(); + + if ( empty( $prompts ) ) { + return; + } + + $form = $prompts[0]; + + $css = <<<'CSS' +.srfm-thankyou-notice { position: relative; padding: 12px 38px 12px 12px; border-left-color: #D54407; } +.srfm-thankyou-notice__title { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: #1d2327; } +.srfm-thankyou-notice__text { margin: 0 0 10px; color: #50575e; } +.srfm-thankyou-notice__actions { margin: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; } +.srfm-thankyou-notice .button-primary { background: #D54407; border-color: #D54407; color: #fff; box-shadow: none; text-shadow: none; } +.srfm-thankyou-notice .button-primary:hover, .srfm-thankyou-notice .button-primary:focus { background: #C83B00; border-color: #C83B00; color: #fff; box-shadow: none; } +.srfm-thankyou-notice .button:not(.button-primary) { background: transparent; border-color: transparent; color: #D54407; box-shadow: none; } +.srfm-thankyou-notice .button:not(.button-primary):hover, .srfm-thankyou-notice .button:not(.button-primary):focus { background: transparent; border-color: transparent; color: #C83B00; box-shadow: none; } +.srfm-thankyou-notice .button-primary:focus { outline: 2px solid #D54407; outline-offset: 1px; } +CSS; + + wp_register_style( 'srfm-thankyou-notice', false, [], SRFM_VER ); + wp_enqueue_style( 'srfm-thankyou-notice' ); + wp_add_inline_style( 'srfm-thankyou-notice', $css ); + + wp_register_script( 'srfm-thankyou-notice', '', [], SRFM_VER, true ); + wp_enqueue_script( 'srfm-thankyou-notice' ); + + wp_localize_script( + 'srfm-thankyou-notice', + 'srfmThankYouNotice', + [ + 'restUrl' => esc_url_raw( rest_url( 'sureforms/v1/dismiss-thankyou-prompt' ) ), + 'nonce' => wp_create_nonce( 'wp_rest' ), + 'formId' => $form['id'], + ] + ); + + $inline_script = <<<'JS' +( function () { + const cfg = window.srfmThankYouNotice || {}; + const notice = document.getElementById( 'srfm-thankyou-notice' ); + const dismiss = document.getElementById( 'srfm-thankyou-notice-dismiss' ); + if ( ! notice || ! dismiss ) { + return; + } + dismiss.addEventListener( 'click', function () { + fetch( cfg.restUrl, { + method: 'POST', + credentials: 'same-origin', + headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': cfg.nonce }, + body: JSON.stringify( { form_id: cfg.formId } ), + } ).catch( function () {} ); + notice.remove(); + } ); +}() ); +JS; + + wp_add_inline_script( 'srfm-thankyou-notice', $inline_script ); + } + /** * Check and save the first form creation time stamp. * If not already saved. @@ -1224,10 +1429,6 @@ public function enqueue_scripts() { // Default confirmation message HTML (icon + heading + text) used as // the initial React state before the settings API response arrives. 'default_confirmation_message' => Global_Settings::get_default_confirmation_message(), - // Latest form still on the default Thank You message — powers the - // dashboard prompt (#3030). Empty when there is nothing to nudge about. - 'thankyou_prompt_forms' => self::get_thankyou_prompt_forms(), - 'thankyou_prompt_nonce' => wp_create_nonce( 'wp_rest' ), 'payments' => apply_filters( 'srfm_admin_localize_payments_data', [ diff --git a/src/admin/dashboard/Dashboard.js b/src/admin/dashboard/Dashboard.js index 600e621b9..e34d0d334 100644 --- a/src/admin/dashboard/Dashboard.js +++ b/src/admin/dashboard/Dashboard.js @@ -8,7 +8,6 @@ import QuickAccessTab from './QuickAccessTab'; import UpgradeToPro from './UpgradeToPro'; import FormsOverview from './FormsOverview'; import AdminNotice from '../components/AdminNotice'; -import ThankYouPrompt from './ThankYouPrompt'; import { cn } from '@Utils/Helpers'; export default () => { @@ -45,8 +44,6 @@ export default () => { <AdminNotice currentPage="sureforms_menu" /> </div> ) } - { /* Nudge to personalise a new form's Thank You message (#3030). */ } - <ThankYouPrompt /> <Container className={ cn( ! window.srfm_admin?.notices?.length && 'pt-5 xl:pt-8' diff --git a/src/admin/dashboard/ThankYouPrompt.js b/src/admin/dashboard/ThankYouPrompt.js deleted file mode 100644 index 95a6b6652..000000000 --- a/src/admin/dashboard/ThankYouPrompt.js +++ /dev/null @@ -1,189 +0,0 @@ -/** - * Dashboard "Finish setting up" card (#3030 / #3031). - * - * The server (`srfm_admin.thankyou_prompt_forms`) lists the latest form the - * current user can edit that still has an unfinished setup step — no reply - * destination, the default thank-you message, or not embedded on a page — along - * with which steps remain. This renders the contextual nudge with a CTA per - * incomplete step; dismissing persists per form so it does not return. - * - * @package - */ - -import { useState } from '@wordpress/element'; -import { __, _n, sprintf } from '@wordpress/i18n'; -import apiFetch from '@wordpress/api-fetch'; -import { Button, Title } from '@bsf/force-ui'; -import { X, FileText } from 'lucide-react'; - -// Join clause fragments as "a", "a and b", "a, b, and c". -const joinClauses = ( clauses ) => { - if ( clauses.length <= 1 ) { - return clauses.join( '' ); - } - if ( clauses.length === 2 ) { - return clauses.join( __( ' and ', 'sureforms' ) ); - } - return ( - clauses.slice( 0, -1 ).join( ', ' ) + - __( ', and ', 'sureforms' ) + - clauses[ clauses.length - 1 ] - ); -}; - -const ThankYouPrompt = () => { - const initial = Array.isArray( window.srfm_admin?.thankyou_prompt_forms ) - ? window.srfm_admin.thankyou_prompt_forms - : []; - const [ forms, setForms ] = useState( initial ); - - if ( ! forms.length ) { - return null; - } - - // Optimistically hide, then persist the dismissal. A failed request just - // means the card may reappear next load — never a blocking error. - const dismiss = ( formId ) => { - setForms( ( prev ) => prev.filter( ( form ) => form.id !== formId ) ); - apiFetch( { - path: 'sureforms/v1/dismiss-thankyou-prompt', - method: 'POST', - data: { form_id: formId }, - headers: { 'X-WP-Nonce': window.srfm_admin?.thankyou_prompt_nonce }, - } ).catch( () => {} ); - }; - - return ( - <div className="pt-5 xl:pt-8"> - { forms.map( ( form ) => { - const steps = form.steps || {}; - const daysAgo = Number( form.days_ago ) || 0; - - const clauses = []; - if ( steps.replies ) { - clauses.push( - __( 'replies have nowhere to go', 'sureforms' ) - ); - } - if ( steps.thankyou ) { - clauses.push( - __( - 'the thank-you message is still the default', - 'sureforms' - ) - ); - } - - const timeText = - daysAgo > 0 - ? sprintf( - /* translators: %d: number of days. */ - _n( - 'You started this form %d day ago', - 'You started this form %d days ago', - daysAgo, - 'sureforms' - ), - daysAgo - ) - : __( 'You started this form recently', 'sureforms' ); - - return ( - <div - key={ form.id } - className="relative flex items-start gap-4 p-5 mb-4 rounded-xl bg-background-primary border-0.5 border-solid border-border-subtle shadow-sm-blur-1" - > - <Button - variant="ghost" - size="sm" - icon={ <X className="size-4" /> } - onClick={ () => dismiss( form.id ) } - aria-label={ __( 'Dismiss', 'sureforms' ) } - className="absolute top-3 right-3" - /> - - <div - className="flex items-center justify-center rounded-xl shrink-0" - style={ { - width: '2.75rem', - height: '2.75rem', - backgroundColor: '#FBEAE3', - } } - > - <FileText - className="size-6" - style={ { color: '#C15A3B' } } - /> - </div> - - <div className="min-w-0 pr-6"> - <Title - tag="h3" - size="md" - title={ sprintf( - /* translators: %s: form name. */ - __( - 'Finish setting up “%s”', - 'sureforms' - ), - form.title - ) } - /> - <p className="mt-1.5 mb-4 text-sm text-text-secondary max-w-2xl"> - { sprintf( - /* translators: 1: "You started this form N days ago", 2: what's left, e.g. "replies have nowhere to go, and the form isn't on a page". */ - __( - "%1$s and haven't opened it since. It isn't collecting anything yet — %2$s.", - 'sureforms' - ), - timeText, - joinClauses( clauses ) - ) } - </p> - - <div className="flex flex-wrap items-center gap-x-5 gap-y-2"> - <Button - variant="primary" - size="sm" - onClick={ () => - window.location.assign( form.edit_url ) - } - > - { __( 'Edit form', 'sureforms' ) } - </Button> - - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( - form.replies_url - ) - } - > - { __( 'Set where replies go', 'sureforms' ) } - </Button> - <Button - variant="link" - size="sm" - onClick={ () => - window.location.assign( - form.thankyou_url - ) - } - > - { __( - 'Edit the thank-you message', - 'sureforms' - ) } - </Button> - </div> - </div> - </div> - ); - } ) } - </div> - ); -}; - -export default ThankYouPrompt; From 657a68b97e9bba2e73721c86b1f76b71663f9b60 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 16:05:56 +0530 Subject: [PATCH 17/65] Show the embedded Edit Form pill at all times, not only on hover (#3029) Drop the opacity:0 default and the container-hover / focus-visible reveal so the admin-only Edit Form shortcut is always visible at the form's top-right corner. The server-side current_user_can('edit_post') gate is unchanged, so the pill stays absent from the DOM for non-editors. --- inc/generate-form-markup.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index ce3497c58..1c35ed32b 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -1381,11 +1381,7 @@ public static function render_edit_form_button( $form_id ) { border-radius: 9999px; box-shadow: 0 2px 6px rgba( 0, 0, 0, 0.12 ); text-decoration: none; - opacity: 0; - transition: opacity 0.15s ease-in-out; } - .srfm-form-container:hover .srfm-edit-form-btn, - .srfm-edit-form-btn:focus-visible { opacity: 1; } .srfm-edit-form-btn:hover { border-color: #cbd5e1; color: #0f172a; } .srfm-edit-form-btn svg { width: 14px; height: 14px; } </style> From 634a2e0f55751d620bcf17797ec3a1a87e182a3a Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 16:27:27 +0530 Subject: [PATCH 18/65] Harden the embedded Edit Form shortcut: cache-safety, scoping, tests (#3029) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review follow-ups for the admin-only Edit Form pill: - Keep it out of shared full-page caches: the response now signals DONOTCACHEPAGE and nocache_headers() when the pill renders, and an explicit is_user_logged_in() guard pairs with it. get_form_markup() output is cache-friendly, so baking admin-only markup into it could otherwise be served to visitors by an auth-unaware cache. Docblock corrected to state the real invariant. - Do not render on the single-form / Instant Form page (is_singular) or inside the block-editor REST preview (REST_REQUEST) — the form is the whole page / already being edited there, so the overlay is redundant. - Add extensibility filters: srfm_show_edit_form_button (short-circuit) and srfm_edit_form_button_link (retarget). - Accessibility: aria-label now contains the visible 'Edit Form' text (WCAG 2.5.3). - Add test_render_edit_form_button covering capability gating (absent for anon / subscriber, present for admin), the once-per-request style dedup, and the suppression filter — restores the check-test-coverage gate. --- inc/generate-form-markup.php | 67 ++++++++++++++++++-- tests/unit/inc/test-generate-form-markup.php | 57 +++++++++++++++++ 2 files changed, 117 insertions(+), 7 deletions(-) diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index 1c35ed32b..38178e6cd 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -1329,10 +1329,16 @@ public static function get_redirect_url( $form_data = [], $submission_data = [] * Renders a small pill link overlaid at the top-right of the form container * (Elementor/Beaver-Builder style) that opens the block editor for this form. * Being absolutely positioned, it never affects the form's layout. It is - * emitted only for users who can edit the form, - * so it is entirely absent from the DOM for everyone else — a visitor never - * receives the markup or its styles, and the form layout and submission are - * untouched. The scoped stylesheet is printed once per request, no matter how + * emitted only for a logged-in user who can edit this specific form, so for + * every other viewer the markup and its styles are entirely absent from the + * DOM and the form layout and submission are untouched. + * + * Because `get_form_markup()` output is cache-friendly and can be served from a + * shared full-page cache, this response must not be cached once it carries the + * admin-only shortcut: when the pill renders we signal `DONOTCACHEPAGE` so the + * common WordPress page caches skip it. (Edge caches that ignore that constant + * are expected to exclude logged-in users themselves, per the standard WP cache + * contract.) The scoped stylesheet is printed once per request, no matter how * many forms are embedded on the page. * * @param int $form_id Form post ID. @@ -1343,9 +1349,37 @@ public static function get_redirect_url( $form_data = [], $submission_data = [] public static function render_edit_form_button( $form_id ) { $form_id = absint( $form_id ); + // Not inside the block editor's own preview (which renders through this + // same function over REST): the user is already editing the form there, so + // an "edit this form" shortcut would be redundant. + if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { + return; + } + + // Not on the single-form / Instant Form page, where the form IS the whole + // page and the admin bar already links to its editor — the overlay pill + // would just be redundant there. It is meant for forms embedded within + // other content. + if ( defined( 'SRFM_FORMS_POST_TYPE' ) && is_singular( SRFM_FORMS_POST_TYPE ) ) { + return; + } + + /** + * Allow integrations to suppress the admin "Edit Form" shortcut entirely. + * + * @param bool $show Whether to render the shortcut. Default true. + * @param int $form_id Form post ID. + * + * @since x.x.x + */ + if ( ! apply_filters( 'srfm_show_edit_form_button', true, $form_id ) ) { + return; + } + // Capability is checked against this specific form, so an editor only sees - // the shortcut on forms they may actually edit. - if ( $form_id <= 0 || ! current_user_can( 'edit_post', $form_id ) ) { + // the shortcut on forms they may actually edit. The explicit logged-in + // guard documents intent and pairs with the cache-bypass signal below. + if ( $form_id <= 0 || ! is_user_logged_in() || ! current_user_can( 'edit_post', $form_id ) ) { return; } @@ -1355,6 +1389,25 @@ public static function render_edit_form_button( $form_id ) { return; } + /** + * Filter the target of the admin "Edit Form" shortcut. + * + * @param string $edit_link Editor URL for the form. + * @param int $form_id Form post ID. + * + * @since x.x.x + */ + $edit_link = apply_filters( 'srfm_edit_form_button_link', $edit_link, $form_id ); + + // This response now carries admin-only markup, so keep it out of any shared + // full-page cache that would serve it to visitors. + if ( ! defined( 'DONOTCACHEPAGE' ) ) { + define( 'DONOTCACHEPAGE', true ); + } + if ( ! headers_sent() ) { + nocache_headers(); + } + // Print the styles once per request, even with several forms on the page. static $styles_printed = false; @@ -1388,7 +1441,7 @@ public static function render_edit_form_button( $form_id ) { <?php } ?> - <a class="srfm-edit-form-btn" href="<?php echo esc_url( $edit_link ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php esc_attr_e( 'Edit this form in SureForms', 'sureforms' ); ?>"> + <a class="srfm-edit-form-btn" href="<?php echo esc_url( $edit_link ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php esc_attr_e( 'Edit Form in SureForms', 'sureforms' ); ?>"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"></path><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"></path></svg> <span><?php esc_html_e( 'Edit Form', 'sureforms' ); ?></span> </a> diff --git a/tests/unit/inc/test-generate-form-markup.php b/tests/unit/inc/test-generate-form-markup.php index 3587d6c31..8fc8b9a77 100644 --- a/tests/unit/inc/test-generate-form-markup.php +++ b/tests/unit/inc/test-generate-form-markup.php @@ -46,6 +46,63 @@ public function test_get_form_markup_with_valid_form() { wp_delete_post( $form_id, true ); } + /** + * The admin-only "Edit Form" pill (#3029) is capability-gated and deduped. + * + * It must be entirely absent from the rendered markup for anonymous visitors + * and non-editors — the sureforms_form CPT maps edit_post to manage_options, + * so only administrators qualify — present for an administrator and linked to + * that form's editor, and its scoped stylesheet emitted at most once even when + * several forms render in one request. + */ + public function test_render_edit_form_button() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + + remove_all_actions( 'wp_insert_post_data' ); + + $form_id = wp_insert_post( [ + 'post_title' => 'Edit Pill Form', + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'post_content' => 'simple content', + ] ); + + // Anonymous visitors never receive the shortcut. + wp_set_current_user( 0 ); + $this->assertStringNotContainsString( 'srfm-edit-form-btn', Generate_Form_Markup::get_form_markup( $form_id ) ); + + // A subscriber cannot edit the form, so still no shortcut. + $subscriber = $this->set_current_user_with_role( 'subscriber' ); + $this->assertStringNotContainsString( 'srfm-edit-form-btn', Generate_Form_Markup::get_form_markup( $form_id ) ); + + // An administrator gets the pill, pointing at this form's editor. + $admin = $this->set_current_user_with_role( 'administrator' ); + $markup = Generate_Form_Markup::get_form_markup( $form_id ); + $this->assertStringContainsString( 'class="srfm-edit-form-btn"', $markup ); + $this->assertStringContainsString( 'action=edit', $markup ); + + // Rendering two forms emits two anchors but the scoped stylesheet at most + // once (once-per-request dedup via the function-static guard). + ob_start(); + Generate_Form_Markup::render_edit_form_button( $form_id ); + Generate_Form_Markup::render_edit_form_button( $form_id ); + $twice = ob_get_clean(); + $this->assertSame( 2, substr_count( $twice, 'class="srfm-edit-form-btn"' ) ); + $this->assertLessThanOrEqual( 1, substr_count( $twice, 'id="srfm-edit-form-btn-styles"' ) ); + + // A suppression filter removes it even for an administrator. + add_filter( 'srfm_show_edit_form_button', '__return_false' ); + $this->assertStringNotContainsString( 'srfm-edit-form-btn', Generate_Form_Markup::get_form_markup( $form_id ) ); + remove_filter( 'srfm_show_edit_form_button', '__return_false' ); + + wp_set_current_user( 0 ); + wp_delete_user( $subscriber ); + wp_delete_user( $admin ); + wp_delete_post( $form_id, true ); + } + public function test_add_entries_admin_bar_node() { if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! defined( 'SRFM_ENTRIES' ) ) { $this->markTestSkipped( 'SureForms constants not defined' ); From ea78007d09813b9efb844282b60211f5ff3f0a93 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 17:57:59 +0530 Subject: [PATCH 19/65] Render the Thank You prompt via Astra Notices, target starter-template forms (#3030) - Render the 'Finish setting up' prompt through the bundled Astra Notices library (Astra_Notices::add_notice) instead of hand-rolled admin_notices markup + a custom REST dismiss endpoint. The per-form notice id gives per-form dismissal via the library's own dismiss control, so the dismiss REST route, its handler, the _srfm_thankyou_prompt_dismissed meta and the enqueue helper are removed. - Show on every admin screen EXCEPT the main dashboard. - Only for forms created from an Astra Sites starter template - gated on the _astra_sites_imported_post marker Astra Sites stamps on imported posts. - Brand-orange styling (#D54407) printed via the astra_notice_before_markup_{id} hook, since the message is wp_kses_post'd; override the library's flex container so the title/text/actions stack, with tuned action spacing. - Track clicks on all four actions (Edit form, Set where replies go, Edit the thank-you message, dismiss) through the shared srfm_notice_response endpoint + Analytics::events()->track, with a per-form-id prefix branch. Beacons use fetch keepalive so they survive the CTA navigation. --- admin/admin.php | 317 +++++++++++++++++++++++++++-------------------- inc/rest-api.php | 13 -- 2 files changed, 182 insertions(+), 148 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 12234f256..38f26954b 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -144,9 +144,9 @@ public function __construct() { add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] ); add_action( 'admin_notices', [ $this, 'display_srfm_getting_started_notice' ] ); - // "Finish setting up" prompt, shown as a notice on the WP dashboard (#3030). + // "Finish setting up" prompt, shown as an Astra Notices admin notice on + // every admin screen except the dashboard (#3030). add_action( 'admin_notices', [ $this, 'render_thankyou_prompt_notice' ] ); - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_thankyou_prompt_assets' ] ); /** * Suppress foreign (third-party) admin notices on SureForms admin screens. @@ -251,13 +251,6 @@ public static function is_first_form_created() { return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0; } - /** - * Post meta flag: the "personalise your Thank You message" prompt was dismissed. - * - * @since x.x.x - */ - public const THANKYOU_PROMPT_DISMISSED_META = '_srfm_thankyou_prompt_dismissed'; - /** * Whether a form's confirmation message is still the shipped default. * @@ -328,6 +321,10 @@ private static function compute_thankyou_prompt_forms() { return []; } + // Only forms created from an Astra Sites starter template — those carry the + // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. + // Dismissal is handled per-form by the Astra Notices library (via the + // per-form notice id), so this only needs the newest incomplete form. $query = new \WP_Query( [ 'post_type' => SRFM_FORMS_POST_TYPE, @@ -337,10 +334,10 @@ private static function compute_thankyou_prompt_forms() { 'order' => 'DESC', 'fields' => 'ids', 'no_found_rows' => true, - 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; the prompt is dashboard-only. + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; admin-notice only. [ - 'key' => self::THANKYOU_PROMPT_DISMISSED_META, - 'compare' => 'NOT EXISTS', + 'key' => '_astra_sites_imported_post', + 'compare' => 'EXISTS', ], ], ] @@ -422,30 +419,6 @@ public static function form_has_reply_destination( $form_id ) { return false; } - /** - * REST handler: dismiss the Thank You message prompt for a form (#3030). - * - * Capability is re-checked against this specific form here, not just the - * route's generic permission callback, so a user can only dismiss the prompt - * on a form they may edit. - * - * @param \WP_REST_Request<array<string,mixed>> $request Request. - * - * @since x.x.x - * @return \WP_REST_Response|\WP_Error - */ - public function dismiss_thankyou_prompt( $request ) { - $form_id = absint( $request->get_param( 'form_id' ) ); - - if ( $form_id <= 0 || ! defined( 'SRFM_FORMS_POST_TYPE' ) || SRFM_FORMS_POST_TYPE !== get_post_type( $form_id ) || ! current_user_can( 'edit_post', $form_id ) ) { - return new \WP_Error( 'srfm_thankyou_prompt_forbidden', __( 'You are not allowed to dismiss this prompt.', 'sureforms' ), [ 'status' => 403 ] ); - } - - update_post_meta( $form_id, self::THANKYOU_PROMPT_DISMISSED_META, true ); - - return new \WP_REST_Response( [ 'success' => true ], 200 ); - } - /** * Join clause fragments as "a", "a and b", or "a, b, and c". * @@ -471,24 +444,26 @@ private static function join_clauses( $clauses ) { } /** - * Render the "Finish setting up" prompt as a dashboard notice (#3030). + * Register the "Finish setting up" prompt as an Astra Notices admin notice (#3030). * - * Shown only on the main WordPress dashboard, for the newest form the current - * user can edit that still has an unfinished step (default thank-you message or - * no reply destination). The ✕ persists a per-form dismissal through the REST - * endpoint wired in enqueue_thankyou_prompt_assets(). + * Hooked to admin_notices so it registers before the Astra Notices library + * renders (priority 30). Shown on every admin screen EXCEPT the main dashboard, + * for the newest form the current user can edit that still has an unfinished + * step (default thank-you message or no reply destination). The notice id is + * per-form, so the library's built-in ✕ dismissal persists per form. * * @since x.x.x * @return void */ public function render_thankyou_prompt_notice() { - if ( ! Helper::current_user_can() ) { + if ( ! Helper::current_user_can() || ! class_exists( 'Astra_Notices' ) ) { return; } + // Everywhere in wp-admin except the main dashboard. $screen = get_current_screen(); - if ( ! $screen || 'dashboard' !== $screen->id ) { + if ( $screen && 'dashboard' === $screen->id ) { return; } @@ -498,7 +473,111 @@ public function render_thankyou_prompt_notice() { return; } - $form = $prompts[0]; + $form = $prompts[0]; + $notice_id = 'srfm-thankyou-prompt-' . (int) $form['id']; + + \Astra_Notices::add_notice( + [ + 'id' => $notice_id, + 'type' => 'info', + 'message' => self::build_thankyou_notice_markup( $form ), + 'class' => 'srfm-thankyou-notice', + 'is_dismissible' => true, + 'display-with-other-notices' => true, + ] + ); + + // The message is wp_kses_post'd by the library, so the brand-orange styling + // is printed through the notice's pre-markup hook instead of inline. + add_action( 'astra_notice_before_markup_' . $notice_id, [ $this, 'print_thankyou_notice_styles' ] ); + + // Track clicks on the CTAs and the dismiss ✕ via the shared notice-response + // endpoint, enqueued only when the notice actually renders. + add_action( 'astra_notice_after_markup_' . $notice_id, [ $this, 'enqueue_thankyou_notice_tracking' ] ); + } + + /** + * Enqueue the click-tracking for the Thank You notice (#3030). + * + * Sends an analytics beacon to the shared `srfm_notice_response` AJAX handler + * when a CTA or the dismiss ✕ is clicked. Uses `keepalive` so the beacon + * survives the navigation the CTA links trigger. + * + * @since x.x.x + * @return void + */ + public function enqueue_thankyou_notice_tracking() { + if ( wp_script_is( 'srfm-thankyou-notice-track', 'enqueued' ) ) { + return; + } + + wp_register_script( 'srfm-thankyou-notice-track', '', [], SRFM_VER, true ); + wp_enqueue_script( 'srfm-thankyou-notice-track' ); + + wp_localize_script( + 'srfm-thankyou-notice-track', + 'srfmThankYouNoticeTrack', + [ + 'ajaxurl' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'srfm_notice_response' ), + ] + ); + + $inline_script = <<<'JS' +( function () { + const cfg = window.srfmThankYouNoticeTrack || {}; + const wrap = document.querySelector( '.srfm-thankyou-notice' ); + if ( ! wrap ) { + return; + } + const noticeId = wrap.id || ''; + const send = function ( button ) { + const body = new URLSearchParams(); + body.append( 'action', 'srfm_notice_response' ); + body.append( 'nonce', cfg.nonce ); + body.append( 'notice_id', noticeId ); + body.append( 'button', button ); + fetch( cfg.ajaxurl, { + method: 'POST', + credentials: 'same-origin', + keepalive: true, + headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' }, + body: body.toString(), + } ).catch( function () {} ); + }; + [ + [ '.srfm-ty-edit-form', 'edit_form' ], + [ '.srfm-ty-set-replies', 'set_replies' ], + [ '.srfm-ty-edit-thankyou', 'edit_thankyou' ], + ].forEach( function ( pair ) { + const el = wrap.querySelector( pair[ 0 ] ); + if ( el ) { + el.addEventListener( 'click', function () { + send( pair[ 1 ] ); + } ); + } + } ); + const dismiss = wrap.querySelector( '.notice-dismiss' ); + if ( dismiss ) { + dismiss.addEventListener( 'click', function () { + send( 'dismissed' ); + } ); + } +}() ); +JS; + + wp_add_inline_script( 'srfm-thankyou-notice-track', $inline_script ); + } + + /** + * Build the Thank You notice's inner markup (title, sentence, action buttons). + * + * @param array<string,mixed> $form Prompt payload from get_thankyou_prompt_forms(). + * + * @since x.x.x + * @return string + */ + private static function build_thankyou_notice_markup( $form ) { $steps = isset( $form['steps'] ) && is_array( $form['steps'] ) ? $form['steps'] : []; $days_ago = isset( $form['days_ago'] ) ? (int) $form['days_ago'] : 0; @@ -524,107 +603,56 @@ public function render_thankyou_prompt_notice() { $time_text, self::join_clauses( $clauses ) ); + + ob_start(); ?> - <div class="notice notice-info srfm-thankyou-notice" id="srfm-thankyou-notice"> - <p class="srfm-thankyou-notice__title"> - <?php - echo esc_html( - sprintf( - /* translators: %s: form name. */ - __( 'Finish setting up “%s”', 'sureforms' ), - $form['title'] - ) - ); - ?> - </p> - <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> - <p class="srfm-thankyou-notice__actions"> - <a class="button button-primary" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> - <a class="button" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> - <a class="button" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the thank-you message', 'sureforms' ); ?></a> - </p> - <button type="button" class="notice-dismiss" id="srfm-thankyou-notice-dismiss"> - <span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'sureforms' ); ?></span> - </button> - </div> + <p class="srfm-thankyou-notice__title"> + <?php + echo esc_html( + sprintf( + /* translators: %s: form name. */ + __( 'Finish setting up “%s”', 'sureforms' ), + $form['title'] + ) + ); + ?> + </p> + <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> + <p class="srfm-thankyou-notice__actions"> + <a class="button button-primary srfm-ty-edit-form" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> + <a class="button srfm-ty-set-replies" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> + <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the thank-you message', 'sureforms' ); ?></a> + </p> <?php + return (string) ob_get_clean(); } /** - * Enqueue the Thank You dashboard notice's styles and dismiss behavior (#3030). + * Print the Thank You notice's brand-orange styling (#3030). * - * Mirrors the plugin's other dashboard-widget assets: an inline-only handle - * carries the CSS and the dismiss handler, with the REST URL, nonce and form id - * passed via wp_localize_script rather than printed into the markup. - * - * @param string $hook_suffix Current admin page hook suffix. + * Fired via astra_notice_before_markup_{id} so it lands right before the notice + * and only when the notice actually renders. * * @since x.x.x * @return void */ - public function enqueue_thankyou_prompt_assets( $hook_suffix ) { - if ( 'index.php' !== $hook_suffix || ! Helper::current_user_can() ) { - return; - } - - $prompts = self::get_thankyou_prompt_forms(); - - if ( empty( $prompts ) ) { - return; - } - - $form = $prompts[0]; - - $css = <<<'CSS' -.srfm-thankyou-notice { position: relative; padding: 12px 38px 12px 12px; border-left-color: #D54407; } -.srfm-thankyou-notice__title { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: #1d2327; } -.srfm-thankyou-notice__text { margin: 0 0 10px; color: #50575e; } -.srfm-thankyou-notice__actions { margin: 0; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; } -.srfm-thankyou-notice .button-primary { background: #D54407; border-color: #D54407; color: #fff; box-shadow: none; text-shadow: none; } -.srfm-thankyou-notice .button-primary:hover, .srfm-thankyou-notice .button-primary:focus { background: #C83B00; border-color: #C83B00; color: #fff; box-shadow: none; } -.srfm-thankyou-notice .button:not(.button-primary) { background: transparent; border-color: transparent; color: #D54407; box-shadow: none; } -.srfm-thankyou-notice .button:not(.button-primary):hover, .srfm-thankyou-notice .button:not(.button-primary):focus { background: transparent; border-color: transparent; color: #C83B00; box-shadow: none; } -.srfm-thankyou-notice .button-primary:focus { outline: 2px solid #D54407; outline-offset: 1px; } -CSS; - - wp_register_style( 'srfm-thankyou-notice', false, [], SRFM_VER ); - wp_enqueue_style( 'srfm-thankyou-notice' ); - wp_add_inline_style( 'srfm-thankyou-notice', $css ); - - wp_register_script( 'srfm-thankyou-notice', '', [], SRFM_VER, true ); - wp_enqueue_script( 'srfm-thankyou-notice' ); - - wp_localize_script( - 'srfm-thankyou-notice', - 'srfmThankYouNotice', - [ - 'restUrl' => esc_url_raw( rest_url( 'sureforms/v1/dismiss-thankyou-prompt' ) ), - 'nonce' => wp_create_nonce( 'wp_rest' ), - 'formId' => $form['id'], - ] - ); - - $inline_script = <<<'JS' -( function () { - const cfg = window.srfmThankYouNotice || {}; - const notice = document.getElementById( 'srfm-thankyou-notice' ); - const dismiss = document.getElementById( 'srfm-thankyou-notice-dismiss' ); - if ( ! notice || ! dismiss ) { - return; - } - dismiss.addEventListener( 'click', function () { - fetch( cfg.restUrl, { - method: 'POST', - credentials: 'same-origin', - headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': cfg.nonce }, - body: JSON.stringify( { form_id: cfg.formId } ), - } ).catch( function () {} ); - notice.remove(); - } ); -}() ); -JS; - - wp_add_inline_script( 'srfm-thankyou-notice', $inline_script ); + public function print_thankyou_notice_styles() { + ?> + <style id="srfm-thankyou-notice-styles"> + .srfm-thankyou-notice.notice { border-left-color: #D54407; } + /* The library lays the container out as a flex row; stack our blocks. */ + .srfm-thankyou-notice .astra-notice-container { display: block; padding: 4px 0; } + .srfm-thankyou-notice .srfm-thankyou-notice__title { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: #1d2327; } + .srfm-thankyou-notice .srfm-thankyou-notice__text { margin: 0 0 10px; color: #50575e; } + .srfm-thankyou-notice .srfm-thankyou-notice__actions { margin: 12px 0 2px; display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; } + .srfm-thankyou-notice .button-primary { background: #D54407; border-color: #D54407; color: #fff; box-shadow: none; text-shadow: none; } + .srfm-thankyou-notice .button-primary:hover, .srfm-thankyou-notice .button-primary:focus { background: #C83B00; border-color: #C83B00; color: #fff; box-shadow: none; } + .srfm-thankyou-notice .button:not(.button-primary) { background: transparent; border-color: transparent; color: #D54407; box-shadow: none; } + .srfm-thankyou-notice .button:not(.button-primary):hover, .srfm-thankyou-notice .button:not(.button-primary):focus { background: transparent; border-color: transparent; color: #C83B00; box-shadow: none; } + .srfm-thankyou-notice .srfm-ty-edit-thankyou { padding: 0; } + .srfm-thankyou-notice .button-primary:focus { outline: 2px solid #D54407; outline-offset: 1px; } + </style> + <?php } /** @@ -2149,6 +2177,25 @@ public function handle_notice_response() { $notice_id = isset( $_POST['notice_id'] ) ? sanitize_text_field( wp_unslash( $_POST['notice_id'] ) ) : ''; $button = isset( $_POST['button'] ) ? sanitize_text_field( wp_unslash( $_POST['button'] ) ) : ''; + // The "Finish setting up" prompt (#3030) uses a per-form notice id, so it + // can't be an exact key in the map below — match it by prefix and validate + // the button against its own fixed set. + if ( 0 === strpos( $notice_id, 'srfm-thankyou-prompt-' ) ) { + $thankyou_events = [ + 'edit_form' => 'thankyou_notice_edit_form', + 'set_replies' => 'thankyou_notice_set_replies', + 'edit_thankyou' => 'thankyou_notice_edit_thankyou', + 'dismissed' => 'thankyou_notice_dismiss', + ]; + + if ( ! isset( $thankyou_events[ $button ] ) ) { + wp_send_json_error( [ 'message' => __( 'Invalid parameters.', 'sureforms' ) ], 400 ); + } + + Analytics::events()->track( $thankyou_events[ $button ], $button ); + wp_send_json_success(); + } + $valid = [ 'srfm-getting-started-notice' => [ 'go_to_dashboard' => 'getting_started_notice_cta', diff --git a/inc/rest-api.php b/inc/rest-api.php index 72b76b0ed..0d2227acd 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1413,19 +1413,6 @@ private function get_endpoints() { 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], ], - // Dismiss the dashboard "personalise your Thank You message" prompt - // for a form (#3030). Per-form capability is re-checked in the handler. - 'dismiss-thankyou-prompt' => [ - 'methods' => 'POST', - 'callback' => [ \SRFM\Admin\Admin::get_instance(), 'dismiss_thankyou_prompt' ], - 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], - 'args' => [ - 'form_id' => [ - 'required' => true, - 'sanitize_callback' => 'absint', - ], - ], - ], // This route is used to initiate auth process when user tries to authenticate on billing portal. 'initiate-auth' => [ 'methods' => 'GET', From d1bd8f17c4b78761d273ed39eead9f35d311d901 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 18:37:13 +0530 Subject: [PATCH 20/65] Add tests for the Thank You notice helpers to satisfy check-test-coverage (#3030) Covers the seven admin.php functions the coverage gate flagged: the notice registrar/styles/tracking methods and the reply-destination, default-confirmation, prompt-query and first-form-created helpers. --- tests/unit/admin/test-admin.php | 69 +++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index c3f2d23e5..21815e7e6 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -935,4 +935,73 @@ public function test_is_sureforms_owned_notice_callback() { 'A null callback should not be recognised as owned.' ); } + + /** + * The first-form-created flag resolves to a boolean. + */ + public function test_is_first_form_created() { + $this->assertIsBool( Admin::is_first_form_created() ); + } + + /** + * A form with no stored confirmation is not the shipped default (#3030). + */ + public function test_is_default_confirmation_message() { + // No confirmation meta → nothing to compare → not the default. + $this->assertFalse( Admin::is_default_confirmation_message( 0 ) ); + $this->assertIsBool( Admin::is_default_confirmation_message( 999999 ) ); + } + + /** + * A form with no email notification has no reply destination (#3030). + */ + public function test_form_has_reply_destination() { + $this->assertFalse( Admin::form_has_reply_destination( 0 ) ); + $this->assertIsBool( Admin::form_has_reply_destination( 999999 ) ); + } + + /** + * The Thank You prompt query always returns an array (#3030). + */ + public function test_get_thankyou_prompt_forms() { + $this->assertIsArray( Admin::get_thankyou_prompt_forms() ); + } + + /** + * The Thank You notice registrar emits nothing when there is no qualifying + * Astra Sites starter-template form (#3030). + */ + public function test_render_thankyou_prompt_notice() { + $admin = Admin::get_instance(); + $this->assertTrue( method_exists( $admin, 'render_thankyou_prompt_notice' ) ); + + ob_start(); + $admin->render_thankyou_prompt_notice(); + $output = (string) ob_get_clean(); + + // No starter-template form exists in the test DB, so nothing is printed. + $this->assertStringNotContainsString( 'srfm-thankyou-notice', $output ); + } + + /** + * The Thank You notice styling prints the brand accent colour (#3030). + */ + public function test_print_thankyou_notice_styles() { + $admin = Admin::get_instance(); + + ob_start(); + $admin->print_thankyou_notice_styles(); + $output = (string) ob_get_clean(); + + $this->assertStringContainsString( 'srfm-thankyou-notice', $output ); + $this->assertStringContainsString( '#D54407', $output ); + } + + /** + * The Thank You notice click-tracking enqueue method exists (#3030). + */ + public function test_enqueue_thankyou_notice_tracking() { + $admin = Admin::get_instance(); + $this->assertTrue( method_exists( $admin, 'enqueue_thankyou_notice_tracking' ) ); + } } From b6847e3b929ea3b1decf8c8c27faf1f679a7f825 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 19:02:29 +0530 Subject: [PATCH 21/65] Address self-review findings on the Thank You notice (#3030) - Strengthen the tests with real fixtures instead of type-only smoke assertions: is_default_confirmation_message (default message -> true, edited -> false), form_has_reply_destination (enabled+recipient -> true, disabled -> false), and get_thankyou_prompt_forms (an Astra Sites imported form is targeted, a non-imported one is not). These now fail if the detect/auto-clear/targeting logic is reverted. - Bound the deep-link poll: once the dialog is open it holds the overlay painted for ~2s (the fade settles by then) instead of polling for the dialog's whole lifetime; pin the Force UI overlay-selector assumption in a comment. - Make the notice sentence translator-friendly: use complete phrases per combination and drop the fragment-gluing join_clauses helper (its 3-clause branch was unreachable with only two steps). - Add extensibility filters: srfm_show_thankyou_prompt (short-circuit) and srfm_thankyou_prompt_forms (re-scope the candidates). - Correct the memoization docblock (only the render pass reads the cache). - Relocate the two new private methods into the class's private-method cluster so PHP Insights' ordered-class-elements style check passes. --- admin/admin.php | 332 +++++++++--------- .../tabs/GeneralSettings.js | 15 +- tests/unit/admin/test-admin.php | 97 ++++- 3 files changed, 271 insertions(+), 173 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 38f26954b..5763b9ba3 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -297,103 +297,26 @@ public static function is_default_confirmation_message( $form_id ) { * @return array<int,array{id:int,title:string,edit_url:string}> One entry, or none. */ public static function get_thankyou_prompt_forms() { - // Memoized for the request: the dashboard notice's enqueue and render - // passes both ask for this, and the query is otherwise run twice. + // Memoized for the request so repeated reads (e.g. the notice render plus + // any add-on consumer) share a single query. static $cache = false; if ( false !== $cache ) { return $cache; } - $cache = self::compute_thankyou_prompt_forms(); + /** + * Filter the forms the "Finish setting up" Thank You notice may surface. + * + * @param array<int,array<string,mixed>> $prompts Candidate prompt payloads. + * + * @since x.x.x + */ + $cache = apply_filters( 'srfm_thankyou_prompt_forms', self::compute_thankyou_prompt_forms() ); return $cache; } - /** - * Build the Thank You prompt payload (uncached). See get_thankyou_prompt_forms(). - * - * @since x.x.x - * @return array<int,array<string,mixed>> One entry, or none. - */ - private static function compute_thankyou_prompt_forms() { - if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { - return []; - } - - // Only forms created from an Astra Sites starter template — those carry the - // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. - // Dismissal is handled per-form by the Astra Notices library (via the - // per-form notice id), so this only needs the newest incomplete form. - $query = new \WP_Query( - [ - 'post_type' => SRFM_FORMS_POST_TYPE, - 'post_status' => 'publish', - 'posts_per_page' => 10, - 'orderby' => 'date', - 'order' => 'DESC', - 'fields' => 'ids', - 'no_found_rows' => true, - 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; admin-notice only. - [ - 'key' => '_astra_sites_imported_post', - 'compare' => 'EXISTS', - ], - ], - ] - ); - - $prompts = []; - $now = time(); - - foreach ( $query->posts as $form_id ) { - $form_id = (int) $form_id; - - if ( ! current_user_can( 'edit_post', $form_id ) ) { - continue; - } - - $steps = [ - // A destination for replies: an enabled notification with a recipient. - 'replies' => ! self::form_has_reply_destination( $form_id ), - // The thank-you message is still the shipped default. - 'thankyou' => self::is_default_confirmation_message( $form_id ), - ]; - - // Nothing left to finish — no card for this form. - if ( ! $steps['replies'] && ! $steps['thankyou'] ) { - continue; - } - - $edit_link = get_edit_post_link( $form_id, 'raw' ); - - if ( empty( $edit_link ) ) { - continue; - } - - $created = get_post_time( 'U', true, $form_id ); - $days_ago = is_int( $created ) ? (int) floor( ( $now - $created ) / DAY_IN_SECONDS ) : 0; - - $prompts[] = [ - 'id' => $form_id, - 'title' => get_the_title( $form_id ), - 'days_ago' => max( 0, $days_ago ), - 'steps' => $steps, - 'edit_url' => $edit_link, - // The editor reads srfm_focus to open the matching settings panel: - // "replies" lands on OttoKit (Automations), "thankyou" on Form - // Confirmation. - 'replies_url' => add_query_arg( 'srfm_focus', 'ottokit', $edit_link ), - 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), - ]; - - // One card is enough — surface only the latest form needing setup. - break; - } - - return $prompts; - } - /** * Whether a form has somewhere to send replies (an enabled email notification * with a non-empty recipient). @@ -419,30 +342,6 @@ public static function form_has_reply_destination( $form_id ) { return false; } - /** - * Join clause fragments as "a", "a and b", or "a, b, and c". - * - * @param array<int,string> $clauses Clause fragments. - * - * @since x.x.x - * @return string - */ - private static function join_clauses( $clauses ) { - $count = count( $clauses ); - - if ( $count <= 1 ) { - return implode( '', $clauses ); - } - - if ( 2 === $count ) { - return implode( __( ' and ', 'sureforms' ), $clauses ); - } - - $last = array_pop( $clauses ); - - return implode( ', ', $clauses ) . __( ', and ', 'sureforms' ) . $last; - } - /** * Register the "Finish setting up" prompt as an Astra Notices admin notice (#3030). * @@ -460,6 +359,17 @@ public function render_thankyou_prompt_notice() { return; } + /** + * Short-circuit the "Finish setting up" Thank You notice. + * + * @param bool $show Whether to show the notice. Default true. + * + * @since x.x.x + */ + if ( ! apply_filters( 'srfm_show_thankyou_prompt', true ) ) { + return; + } + // Everywhere in wp-admin except the main dashboard. $screen = get_current_screen(); @@ -569,64 +479,6 @@ public function enqueue_thankyou_notice_tracking() { wp_add_inline_script( 'srfm-thankyou-notice-track', $inline_script ); } - /** - * Build the Thank You notice's inner markup (title, sentence, action buttons). - * - * @param array<string,mixed> $form Prompt payload from get_thankyou_prompt_forms(). - * - * @since x.x.x - * @return string - */ - private static function build_thankyou_notice_markup( $form ) { - $steps = isset( $form['steps'] ) && is_array( $form['steps'] ) ? $form['steps'] : []; - $days_ago = isset( $form['days_ago'] ) ? (int) $form['days_ago'] : 0; - - $clauses = []; - if ( ! empty( $steps['replies'] ) ) { - $clauses[] = __( 'replies have nowhere to go', 'sureforms' ); - } - if ( ! empty( $steps['thankyou'] ) ) { - $clauses[] = __( 'the thank-you message is still the default', 'sureforms' ); - } - - $time_text = $days_ago > 0 - ? sprintf( - /* translators: %d: number of days. */ - _n( 'You started this form %d day ago', 'You started this form %d days ago', $days_ago, 'sureforms' ), - $days_ago - ) - : __( 'You started this form recently', 'sureforms' ); - - $sentence = sprintf( - /* translators: 1: "You started this form N days ago", 2: what is left, e.g. "replies have nowhere to go, and the thank-you message is still the default". */ - __( '%1$s and haven\'t opened it since. It isn\'t collecting anything yet — %2$s.', 'sureforms' ), - $time_text, - self::join_clauses( $clauses ) - ); - - ob_start(); - ?> - <p class="srfm-thankyou-notice__title"> - <?php - echo esc_html( - sprintf( - /* translators: %s: form name. */ - __( 'Finish setting up “%s”', 'sureforms' ), - $form['title'] - ) - ); - ?> - </p> - <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> - <p class="srfm-thankyou-notice__actions"> - <a class="button button-primary srfm-ty-edit-form" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> - <a class="button srfm-ty-set-replies" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> - <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the thank-you message', 'sureforms' ); ?></a> - </p> - <?php - return (string) ob_get_clean(); - } - /** * Print the Thank You notice's brand-orange styling (#3030). * @@ -2625,6 +2477,148 @@ public function render_dashboard_widget() { <?php } + /** + * Build the Thank You prompt payload (uncached). See get_thankyou_prompt_forms(). + * + * @since x.x.x + * @return array<int,array<string,mixed>> One entry, or none. + */ + private static function compute_thankyou_prompt_forms() { + if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { + return []; + } + + // Only forms created from an Astra Sites starter template — those carry the + // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. + // Dismissal is handled per-form by the Astra Notices library (via the + // per-form notice id), so this only needs the newest incomplete form. + $query = new \WP_Query( + [ + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'orderby' => 'date', + 'order' => 'DESC', + 'fields' => 'ids', + 'no_found_rows' => true, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; admin-notice only. + [ + 'key' => '_astra_sites_imported_post', + 'compare' => 'EXISTS', + ], + ], + ] + ); + + $prompts = []; + $now = time(); + + foreach ( $query->posts as $form_id ) { + $form_id = (int) $form_id; + + if ( ! current_user_can( 'edit_post', $form_id ) ) { + continue; + } + + $steps = [ + // A destination for replies: an enabled notification with a recipient. + 'replies' => ! self::form_has_reply_destination( $form_id ), + // The thank-you message is still the shipped default. + 'thankyou' => self::is_default_confirmation_message( $form_id ), + ]; + + // Nothing left to finish — no card for this form. + if ( ! $steps['replies'] && ! $steps['thankyou'] ) { + continue; + } + + $edit_link = get_edit_post_link( $form_id, 'raw' ); + + if ( empty( $edit_link ) ) { + continue; + } + + $created = get_post_time( 'U', true, $form_id ); + $days_ago = is_int( $created ) ? (int) floor( ( $now - $created ) / DAY_IN_SECONDS ) : 0; + + $prompts[] = [ + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'days_ago' => max( 0, $days_ago ), + 'steps' => $steps, + 'edit_url' => $edit_link, + // The editor reads srfm_focus to open the matching settings panel: + // "replies" lands on OttoKit (Automations), "thankyou" on Form + // Confirmation. + 'replies_url' => add_query_arg( 'srfm_focus', 'ottokit', $edit_link ), + 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), + ]; + + // One card is enough — surface only the latest form needing setup. + break; + } + + return $prompts; + } + + /** + * Build the Thank You notice's inner markup (title, sentence, action buttons). + * + * @param array<string,mixed> $form Prompt payload from get_thankyou_prompt_forms(). + * + * @since x.x.x + * @return string + */ + private static function build_thankyou_notice_markup( $form ) { + $steps = isset( $form['steps'] ) && is_array( $form['steps'] ) ? $form['steps'] : []; + $days_ago = isset( $form['days_ago'] ) ? (int) $form['days_ago'] : 0; + + // The notice only surfaces forms still on the default confirmation, so the + // thank-you clause is always present; the reply-destination clause is the + // only variable. Each combination is a complete translatable phrase — no + // glued fragments — so translators can order the words for their locale. + $whats_left = ! empty( $steps['replies'] ) + ? __( 'replies have nowhere to go and the thank-you message is still the default', 'sureforms' ) + : __( 'the thank-you message is still the default', 'sureforms' ); + + $time_text = $days_ago > 0 + ? sprintf( + /* translators: %d: number of days. */ + _n( 'You started this form %d day ago', 'You started this form %d days ago', $days_ago, 'sureforms' ), + $days_ago + ) + : __( 'You started this form recently', 'sureforms' ); + + $sentence = sprintf( + /* translators: 1: "You started this form N days ago", 2: a complete clause, e.g. "the thank-you message is still the default". */ + __( '%1$s and haven\'t opened it since. It isn\'t collecting anything yet — %2$s.', 'sureforms' ), + $time_text, + $whats_left + ); + + ob_start(); + ?> + <p class="srfm-thankyou-notice__title"> + <?php + echo esc_html( + sprintf( + /* translators: %s: form name. */ + __( 'Finish setting up “%s”', 'sureforms' ), + $form['title'] + ) + ); + ?> + </p> + <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> + <p class="srfm-thankyou-notice__actions"> + <a class="button button-primary srfm-ty-edit-form" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> + <a class="button srfm-ty-set-replies" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> + <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the thank-you message', 'sureforms' ); ?></a> + </p> + <?php + return (string) ob_get_clean(); + } + /** * Determine whether a notice callback is owned by SureForms. * diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index 94b1cc9d6..930997f00 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -285,18 +285,29 @@ function GeneralSettings( props ) { // load window if it never opened so the interval can't run indefinitely. let elapsed = 0; let opened = false; + let heldMs = 0; const ensureOpen = setInterval( () => { elapsed += 300; - // Dialog is open on this mount: mark it opened and hold the overlay - // painted (the fade-in can stall during load), then wait. + // Dialog is open on this mount: hold the overlay painted (the Force UI + // fade-in can stall amid the editor's load churn) for a short window, + // then stop — the fade settles within a second or two, so there is no + // need to keep polling for the dialog's whole open lifetime. + // + // NOTE: `.srfm-dialog-panel` / `.fixed.inset-0` are the Force UI Dialog + // overlay's own markup; if the library renames them this simply no-ops + // (the fade-stall workaround stops applying) rather than erroring. if ( isOpenRef.current ) { opened = true; + heldMs += 300; const panel = document.querySelector( '.srfm-dialog-panel' ); const overlay = panel?.closest( '.fixed.inset-0' ); if ( overlay ) { overlay.style.opacity = '1'; } + if ( heldMs >= 2000 ) { + clearInterval( ensureOpen ); + } return; } diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 21815e7e6..afdb4eb19 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -949,7 +949,33 @@ public function test_is_first_form_created() { public function test_is_default_confirmation_message() { // No confirmation meta → nothing to compare → not the default. $this->assertFalse( Admin::is_default_confirmation_message( 0 ) ); - $this->assertIsBool( Admin::is_default_confirmation_message( 999999 ) ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $form_id = wp_insert_post( + [ + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'post_title' => 'TY detect', + ] + ); + + // The shipped default message is detected as the default. + update_post_meta( + $form_id, + '_srfm_form_confirmation', + [ [ 'message' => \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message() ] ] + ); + $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); + + // Any real edit to the message flips it to non-default (the auto-clear path). + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => 'Thanks so much - we will be in touch!' ] ] ); + $this->assertFalse( Admin::is_default_confirmation_message( $form_id ) ); + + wp_delete_post( $form_id, true ); } /** @@ -957,7 +983,32 @@ public function test_is_default_confirmation_message() { */ public function test_form_has_reply_destination() { $this->assertFalse( Admin::form_has_reply_destination( 0 ) ); - $this->assertIsBool( Admin::form_has_reply_destination( 999999 ) ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $form_id = wp_insert_post( + [ + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'post_title' => 'Reply dest', + ] + ); + + // No notification → no reply destination. + $this->assertFalse( Admin::form_has_reply_destination( $form_id ) ); + + // Enabled notification with a recipient → has a destination. + update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => true, 'email_to' => 'admin@example.com' ] ] ); + $this->assertTrue( Admin::form_has_reply_destination( $form_id ) ); + + // A disabled notification does not count. + update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => false, 'email_to' => 'admin@example.com' ] ] ); + $this->assertFalse( Admin::form_has_reply_destination( $form_id ) ); + + wp_delete_post( $form_id, true ); } /** @@ -965,6 +1016,48 @@ public function test_form_has_reply_destination() { */ public function test_get_thankyou_prompt_forms() { $this->assertIsArray( Admin::get_thankyou_prompt_forms() ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + // The sureforms_form CPT maps edit_post to manage_options, so an admin. + $admin = wp_insert_user( + [ + 'user_login' => 'srfm_ty_admin_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_ty_admin_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin ) ? 0 : (int) $admin ); + + $default_message = \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message(); + + // Starter-template import still on the default message → targeted. + $imported = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Imported TY' ] ); + update_post_meta( $imported, '_srfm_form_confirmation', [ [ 'message' => $default_message ] ] ); + update_post_meta( $imported, '_astra_sites_imported_post', 1 ); + + // Same default message but NOT an Astra Sites import → excluded by the gate. + $plain = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Plain TY' ] ); + update_post_meta( $plain, '_srfm_form_confirmation', [ [ 'message' => $default_message ] ] ); + + // Drive the uncached builder to bypass the request-memoized cache. + $compute = new \ReflectionMethod( Admin::class, 'compute_thankyou_prompt_forms' ); + $compute->setAccessible( true ); + $ids = wp_list_pluck( $compute->invoke( null ), 'id' ); + + $this->assertContains( $imported, $ids, 'An Astra Sites imported form on the default message must be targeted.' ); + $this->assertNotContains( $plain, $ids, 'A non-imported form must not be targeted.' ); + + wp_delete_post( $imported, true ); + wp_delete_post( $plain, true ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin ) ) { + wp_delete_user( (int) $admin ); + } } /** From b0ff23b528096d9a585e84f1f79e359b595337f1 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 19:15:42 +0530 Subject: [PATCH 22/65] Detect the default Thank You message across entity encoding (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A starter-template import stores the default confirmation with a literal apostrophe, while Global_Settings::get_default_confirmation_message() generates it with the encoded '. is_default_confirmation_message() only stripped tags, so the two normalised strings differed and a genuinely-default imported form was never detected — the notice never showed. Decode HTML entities during normalisation so encoded and literal forms compare equal. Adds a regression test covering the decoded-default case. --- admin/admin.php | 17 +++++++++++------ tests/unit/admin/test-admin.php | 9 ++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 5763b9ba3..c742e2ca5 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -254,11 +254,13 @@ public static function is_first_form_created() { /** * Whether a form's confirmation message is still the shipped default. * - * Compared on tag-stripped, whitespace-collapsed text rather than raw HTML: - * the default is stored with a base64 icon on creation but regenerated with a - * URL icon, so the markup differs while the wording does not. Any real edit to - * the heading or body text changes the text and flips this to false, which is - * exactly when the prompt should stop showing. + * Compared on tag-stripped, entity-decoded, whitespace-collapsed text rather + * than raw HTML: the default is stored with a base64 icon on creation but + * regenerated with a URL icon, so the markup differs while the wording does + * not, and a starter-template import can store a literal apostrophe where the + * generated default carries the encoded `'` — decoding entities makes both + * compare equal. Any real edit to the heading or body text changes the text and + * flips this to false, which is exactly when the prompt should stop showing. * * @param int $form_id Form post ID. * @@ -279,7 +281,10 @@ public static function is_default_confirmation_message( $form_id ) { } $normalize = static function ( $html ) { - return trim( (string) preg_replace( '/\s+/', ' ', wp_strip_all_tags( (string) $html ) ) ); + // Decode entities too, so an encoded apostrophe (') in the generated + // default matches a literal one stored by a template import. + $text = html_entity_decode( wp_strip_all_tags( (string) $html ), ENT_QUOTES, 'UTF-8' ); + return trim( (string) preg_replace( '/\s+/', ' ', $text ) ); }; return $normalize( $message ) === $normalize( Global_Settings::get_default_confirmation_message() ); diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index afdb4eb19..82d216aaa 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -963,11 +963,18 @@ public function test_is_default_confirmation_message() { ] ); + $default_message = \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message(); + // The shipped default message is detected as the default. + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => $default_message ] ] ); + $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); + + // The same default with entities decoded — as a starter-template import can + // store it (literal apostrophe vs the generated ') — still matches. update_post_meta( $form_id, '_srfm_form_confirmation', - [ [ 'message' => \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message() ] ] + [ [ 'message' => html_entity_decode( $default_message, ENT_QUOTES, 'UTF-8' ) ] ] ); $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); From f3091dfef51df3f38a9328de0b9170cccb14f488 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 23:23:14 +0530 Subject: [PATCH 23/65] Address review feedback on the embedded Edit Form pill (#3029) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Style/dedup (H2): move the CSS off the function-static + inline <style> onto a registered inline-only handle (wp_register_style false + wp_add_inline_style + wp_enqueue_style). WP_Styles dedupes by handle, survives a discarded the_content pass (e.g. an SEO plugin building og:description during wp_head, which used to flip the static and throw the style away, leaving an unstyled pill), and passes a strict style-src CSP. Cache (H1): drop the DONOTCACHEPAGE / nocache_headers block — inert on the normal headers-already-sent path and an irreversible process-global side effect from a fragment renderer, for a payload an anonymous visitor cannot act on. Contexts (H3): also skip page-builder editor canvases (Elementor edit mode, Bricks builder), plus is_admin / wp_doing_ajax / wp_is_json_request / is_feed — Elementor/Bricks call get_form_markup() directly (not over REST), where their own edit handles collide with the pill. Container (M3): only render when the .srfm-form-container actually opens (same block-count guard), so a zero-block form no longer emits an orphaned, unpositioned pill. CSS (M4/M5): position the pill inside the box with a positive inset-inline-end (no mobile horizontal overflow, RTL-correct), and scope the container position:relative to the srfm-styling-none case so it never overrides a site's own rule when default styling is on. Guards & a11y: real-form post-type check (shortcode accepts any ID); capability check before the suppression filter; coerce the link filter result and bail on empty; drop the redundant is_user_logged_in and aria-label; add an "(opens in a new tab)" screen-reader hint and a :focus-visible style. Docblocks (M7): correct the two wrong claims — the editor preview is an iframe to the form permalink suppressed by is_singular (not a REST render), and it is admin-only via manage_options (map_meta_cap false), not per-post. Tests (M1/M2/M6): assert the href is bound to THIS form and that a second form links to its own editor; assert the stylesheet is enqueued by handle instead of the vacuous style-count; add tear_down() to reset the current user and filters. --- inc/generate-form-markup.php | 179 +++++++++++-------- tests/unit/inc/test-generate-form-markup.php | 54 +++--- 2 files changed, 139 insertions(+), 94 deletions(-) diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index 38178e6cd..c3ad6627c 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -984,9 +984,13 @@ public static function get_form_markup( $id, $show_title_current_page = true, $s // the embedded form. Rendered only for users who can edit THIS form, so // it is fully absent from the DOM for everyone else and, being absolutely // positioned, never affects the layout or submission for regular - // visitors. Works for every embed method (block, shortcode, widget, - // single) because they all render through this function. - self::render_edit_form_button( (int) $id ); + // visitors. Works for every embed method (block, shortcode, widget) + // because they all render through this function. Gated on the same + // condition as the `.srfm-form-container` open above, so a zero-block + // form (no container) never emits an orphaned, unpositioned pill. + if ( '' !== $id && 0 !== $block_count ) { + self::render_edit_form_button( (int) $id ); + } // Add preview script for real-time styling updates from block editor. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a preview context, nonce not required. @@ -1328,18 +1332,21 @@ public static function get_redirect_url( $form_data = [], $submission_data = [] * * Renders a small pill link overlaid at the top-right of the form container * (Elementor/Beaver-Builder style) that opens the block editor for this form. - * Being absolutely positioned, it never affects the form's layout. It is - * emitted only for a logged-in user who can edit this specific form, so for - * every other viewer the markup and its styles are entirely absent from the - * DOM and the form layout and submission are untouched. + * Being absolutely positioned, it never affects the form's layout. + * + * Admin-only by construction: the `sureforms_form` CPT registers with + * `map_meta_cap => false`, so `edit_post` collapses to a blanket + * `manage_options` check with no per-post component — an editor never sees the + * pill on any form. For every other viewer the markup and its styles are + * entirely absent from the DOM. * - * Because `get_form_markup()` output is cache-friendly and can be served from a - * shared full-page cache, this response must not be cached once it carries the - * admin-only shortcut: when the pill renders we signal `DONOTCACHEPAGE` so the - * common WordPress page caches skip it. (Edge caches that ignore that constant - * are expected to exclude logged-in users themselves, per the standard WP cache - * contract.) The scoped stylesheet is printed once per request, no matter how - * many forms are embedded on the page. + * The stylesheet is attached to a registered inline-only handle so `WP_Styles` + * dedupes it by handle (surviving a discarded `the_content` pass, e.g. an SEO + * plugin building `og:description` during `wp_head`) and it survives a strict + * `style-src` CSP. It is not cache-signalled here: the payload is only a + * `wp-admin/post.php?post=N` link an anonymous visitor cannot act on, and a + * `DONOTCACHEPAGE` define from a fragment renderer is both inert on the normal + * (headers-already-sent) path and an irreversible process-global side effect. * * @param int $form_id Form post ID. * @@ -1349,18 +1356,44 @@ public static function get_redirect_url( $form_data = [], $submission_data = [] public static function render_edit_form_button( $form_id ) { $form_id = absint( $form_id ); - // Not inside the block editor's own preview (which renders through this - // same function over REST): the user is already editing the form there, so - // an "edit this form" shortcut would be redundant. - if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { + // Only for real SureForms forms — the [sureforms] shortcode accepts any + // post ID, and a non-form target would map `edit_post` normally and leak + // the pill to an ordinary editor. + if ( 0 === $form_id || ! defined( 'SRFM_FORMS_POST_TYPE' ) || SRFM_FORMS_POST_TYPE !== get_post_type( $form_id ) ) { + return; + } + + // Capability gate first, before the suppression filter, so no work is done + // for the anonymous visitors who make up almost every page view. + if ( ! current_user_can( 'edit_post', $form_id ) ) { + return; + } + + // Contexts where the pill is redundant or wrong: + // - the single-form / Instant Form page, where the form IS the whole page + // and the admin bar already links to its editor. This is also what + // suppresses the block editor's preview — that preview is an iframe to + // the form's own permalink (an ordinary front-end request), NOT a REST + // render, so `is_singular` is the load-bearing guard there; + // - any admin / AJAX / REST / JSON request, or a feed (the markup would + // otherwise land inside `content:encoded` CDATA). + if ( + is_singular( SRFM_FORMS_POST_TYPE ) + || is_admin() + || wp_doing_ajax() + || wp_is_json_request() + || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) + || is_feed() + ) { return; } - // Not on the single-form / Instant Form page, where the form IS the whole - // page and the admin bar already links to its editor — the overlay pill - // would just be redundant there. It is meant for forms embedded within - // other content. - if ( defined( 'SRFM_FORMS_POST_TYPE' ) && is_singular( SRFM_FORMS_POST_TYPE ) ) { + // Page-builder editor canvases render the form directly (not over REST), + // where their own element-edit handles would collide with the pill. + if ( class_exists( '\Elementor\Plugin' ) && \Elementor\Plugin::$instance->editor->is_edit_mode() ) { + return; + } + if ( function_exists( 'bricks_is_builder' ) && bricks_is_builder() ) { return; } @@ -1376,13 +1409,6 @@ public static function render_edit_form_button( $form_id ) { return; } - // Capability is checked against this specific form, so an editor only sees - // the shortcut on forms they may actually edit. The explicit logged-in - // guard documents intent and pairs with the cache-bypass signal below. - if ( $form_id <= 0 || ! is_user_logged_in() || ! current_user_can( 'edit_post', $form_id ) ) { - return; - } - $edit_link = get_edit_post_link( $form_id ); if ( empty( $edit_link ) ) { @@ -1397,54 +1423,67 @@ public static function render_edit_form_button( $form_id ) { * * @since x.x.x */ - $edit_link = apply_filters( 'srfm_edit_form_button_link', $edit_link, $form_id ); + $edit_link = Helper::get_string_value( apply_filters( 'srfm_edit_form_button_link', $edit_link, $form_id ) ); - // This response now carries admin-only markup, so keep it out of any shared - // full-page cache that would serve it to visitors. - if ( ! defined( 'DONOTCACHEPAGE' ) ) { - define( 'DONOTCACHEPAGE', true ); - } - if ( ! headers_sent() ) { - nocache_headers(); + if ( '' === $edit_link ) { + return; } - // Print the styles once per request, even with several forms on the page. - static $styles_printed = false; - - if ( ! $styles_printed ) { - $styles_printed = true; - ?> - <style id="srfm-edit-form-btn-styles"> - .srfm-form-container { position: relative; } - .srfm-edit-form-btn { - position: absolute; - top: -14px; - right: -14px; - z-index: 5; - display: inline-flex; - align-items: center; - gap: 6px; - padding: 6px 12px; - font-size: 13px; - font-weight: 500; - line-height: 1; - color: #1e293b; - background: #ffffff; - border: 1px solid #e2e8f0; - border-radius: 9999px; - box-shadow: 0 2px 6px rgba( 0, 0, 0, 0.12 ); - text-decoration: none; - } - .srfm-edit-form-btn:hover { border-color: #cbd5e1; color: #0f172a; } - .srfm-edit-form-btn svg { width: 14px; height: 14px; } - </style> - <?php + // Registered inline-only handle: WP_Styles dedupes by handle across every + // embedded form and prints via print_late_styles() in the footer even when + // enqueued this late (during the_content). + $style_handle = 'srfm-edit-form-btn'; + if ( ! wp_style_is( $style_handle, 'registered' ) ) { + wp_register_style( $style_handle, false, [], SRFM_VER ); + wp_add_inline_style( $style_handle, self::get_edit_form_button_css() ); } + wp_enqueue_style( $style_handle ); ?> - <a class="srfm-edit-form-btn" href="<?php echo esc_url( $edit_link ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php esc_attr_e( 'Edit Form in SureForms', 'sureforms' ); ?>"> + <a class="srfm-edit-form-btn" href="<?php echo esc_url( $edit_link ); ?>" target="_blank" rel="noopener noreferrer"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"></path><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"></path></svg> <span><?php esc_html_e( 'Edit Form', 'sureforms' ); ?></span> + <span class="screen-reader-text"><?php esc_html_e( '(opens in a new tab)', 'sureforms' ); ?></span> </a> <?php } + + /** + * Stylesheet for the admin "Edit Form" pill (#3029). + * + * `position: relative` on the container is scoped to the `srfm-styling-none` + * case: with default styling on, the shipped CSS already sets it, so a global + * rule here would only risk overriding a site that deliberately set it static. + * Offsets use a small positive inset (`inset-inline-end`) so the pill sits + * inside the box — no mobile horizontal overflow — and is RTL-correct. + * + * @return string + * @since x.x.x + */ + private static function get_edit_form_button_css() { + return ' + .srfm-form-container.srfm-styling-none { position: relative; } + .srfm-edit-form-btn { + position: absolute; + top: 8px; + inset-inline-end: 8px; + z-index: 5; + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + font-size: 13px; + font-weight: 500; + line-height: 1; + color: #1e293b; + background: #ffffff; + border: 1px solid #e2e8f0; + border-radius: 9999px; + box-shadow: 0 2px 6px rgba( 0, 0, 0, 0.12 ); + text-decoration: none; + } + .srfm-edit-form-btn:hover { border-color: #cbd5e1; color: #0f172a; } + .srfm-edit-form-btn:focus-visible { outline: 2px solid #2563eb; outline-offset: 2px; } + .srfm-edit-form-btn svg { width: 14px; height: 14px; } + '; + } } diff --git a/tests/unit/inc/test-generate-form-markup.php b/tests/unit/inc/test-generate-form-markup.php index 8fc8b9a77..37f2080f3 100644 --- a/tests/unit/inc/test-generate-form-markup.php +++ b/tests/unit/inc/test-generate-form-markup.php @@ -16,6 +16,15 @@ protected function setUp(): void { $this->generate_form_markup = new Generate_Form_Markup(); } + protected function tearDown(): void { + // Reset state a failing assertion mid-test could otherwise leak into the + // rest of the process — a logged-in admin, or the Edit Form filters. + wp_set_current_user( 0 ); + remove_all_filters( 'srfm_show_edit_form_button' ); + remove_all_filters( 'srfm_edit_form_button_link' ); + parent::tearDown(); + } + public function test_get_form_markup_empty_id() { $result = Generate_Form_Markup::get_form_markup( 0 ); $this->assertIsString( $result ); @@ -47,13 +56,14 @@ public function test_get_form_markup_with_valid_form() { } /** - * The admin-only "Edit Form" pill (#3029) is capability-gated and deduped. + * The admin-only "Edit Form" pill (#3029) is capability-gated and per-form. * - * It must be entirely absent from the rendered markup for anonymous visitors - * and non-editors — the sureforms_form CPT maps edit_post to manage_options, - * so only administrators qualify — present for an administrator and linked to - * that form's editor, and its scoped stylesheet emitted at most once even when - * several forms render in one request. + * The sureforms_form CPT maps edit_post to manage_options, so only + * administrators qualify: the pill is absent for anonymous visitors and + * subscribers, present for an administrator with an href bound to THIS form, + * enqueues its stylesheet via a registered handle, a second form links to its + * own editor (AC #5, multiple forms on a page), and the suppression filter + * removes it. `tearDown()` resets the current user and filters. */ public function test_render_edit_form_button() { if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { @@ -62,12 +72,10 @@ public function test_render_edit_form_button() { remove_all_actions( 'wp_insert_post_data' ); - $form_id = wp_insert_post( [ - 'post_title' => 'Edit Pill Form', - 'post_type' => SRFM_FORMS_POST_TYPE, - 'post_status' => 'publish', - 'post_content' => 'simple content', - ] ); + // A block is required so the container opens and the pill is emitted. + $block = '<!-- wp:paragraph -->x<!-- /wp:paragraph -->'; + $form_id = wp_insert_post( [ 'post_title' => 'Edit Pill A', 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_content' => $block ] ); + $form_id2 = wp_insert_post( [ 'post_title' => 'Edit Pill B', 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_content' => $block ] ); // Anonymous visitors never receive the shortcut. wp_set_current_user( 0 ); @@ -77,30 +85,28 @@ public function test_render_edit_form_button() { $subscriber = $this->set_current_user_with_role( 'subscriber' ); $this->assertStringNotContainsString( 'srfm-edit-form-btn', Generate_Form_Markup::get_form_markup( $form_id ) ); - // An administrator gets the pill, pointing at this form's editor. + // An administrator gets the pill, its href bound to THIS form, with the + // stylesheet enqueued via its registered handle. $admin = $this->set_current_user_with_role( 'administrator' ); $markup = Generate_Form_Markup::get_form_markup( $form_id ); $this->assertStringContainsString( 'class="srfm-edit-form-btn"', $markup ); - $this->assertStringContainsString( 'action=edit', $markup ); + $this->assertStringContainsString( 'href="' . esc_url( get_edit_post_link( $form_id ) ) . '"', $markup ); + $this->assertTrue( wp_style_is( 'srfm-edit-form-btn', 'enqueued' ), 'The Edit Form stylesheet should be enqueued.' ); - // Rendering two forms emits two anchors but the scoped stylesheet at most - // once (once-per-request dedup via the function-static guard). - ob_start(); - Generate_Form_Markup::render_edit_form_button( $form_id ); - Generate_Form_Markup::render_edit_form_button( $form_id ); - $twice = ob_get_clean(); - $this->assertSame( 2, substr_count( $twice, 'class="srfm-edit-form-btn"' ) ); - $this->assertLessThanOrEqual( 1, substr_count( $twice, 'id="srfm-edit-form-btn-styles"' ) ); + // A second form links to its OWN editor, not the first — the multiple-forms + // acceptance criterion, and a guard against passing the wrong post ID. + $markup2 = Generate_Form_Markup::get_form_markup( $form_id2 ); + $this->assertStringContainsString( 'href="' . esc_url( get_edit_post_link( $form_id2 ) ) . '"', $markup2 ); + $this->assertStringNotContainsString( 'href="' . esc_url( get_edit_post_link( $form_id ) ) . '"', $markup2 ); // A suppression filter removes it even for an administrator. add_filter( 'srfm_show_edit_form_button', '__return_false' ); $this->assertStringNotContainsString( 'srfm-edit-form-btn', Generate_Form_Markup::get_form_markup( $form_id ) ); - remove_filter( 'srfm_show_edit_form_button', '__return_false' ); - wp_set_current_user( 0 ); wp_delete_user( $subscriber ); wp_delete_user( $admin ); wp_delete_post( $form_id, true ); + wp_delete_post( $form_id2, true ); } public function test_add_entries_admin_bar_node() { From 6b110f9c11b95910622ee9f04b2c4a5968a0ba15 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 23:42:27 +0530 Subject: [PATCH 24/65] Fix PHP Insights + check-test-coverage on the setup-checklist widget (#3031) - Move the SETUP_WIDGET_SNOOZE_USER_META constant into the class's constant section (ordered-class-elements style rule). - Convert the widget markup's foreach/if alternative syntax to braces (the no-alternative-syntax quality rule). - Add test methods for the nine flagged admin.php functions: the setup-card query, embed detection, default email-notification and confirmation detection, the REST dismiss handler, the widget register/render/enqueue methods, and the first-form-created flag. --- admin/admin.php | 32 +++++----- tests/unit/admin/test-admin.php | 110 ++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 16 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index c82d6a3f6..cfaa8d804 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -51,6 +51,15 @@ class Admin { */ public const QUILL_1X_INLINE_CSS = '.ql-editor ul,.ql-editor ol{padding-left:1.5em}.ql-editor ul>li,.ql-editor ol>li{list-style-type:none}.ql-editor ol li:not(.ql-direction-rtl),.ql-editor ul li:not(.ql-direction-rtl){padding-left:1.5em}.ql-editor ol li.ql-direction-rtl,.ql-editor ul li.ql-direction-rtl{padding-right:1.5em}.ql-editor ul>li::before{content:"\2022"}.ql-editor li::before{display:inline-block;white-space:nowrap;width:1.2em}.ql-editor li:not(.ql-direction-rtl)::before{margin-left:-1.5em;margin-right:.3em;text-align:right}.ql-editor li.ql-direction-rtl::before{margin-left:.3em;margin-right:-1.5em}.ql-editor ol li{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;counter-increment:list-0}.ql-editor ol li::before{content:counter(list-0,decimal) ". "}.ql-editor ol li.ql-indent-1{counter-increment:list-1;counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-1::before{content:counter(list-1,lower-alpha) ". "}.ql-editor ol li.ql-indent-2{counter-increment:list-2;counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-2::before{content:counter(list-2,lower-roman) ". "}.ql-editor ol li.ql-indent-3{counter-increment:list-3;counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-3::before{content:counter(list-3,decimal) ". "}.ql-editor ol li.ql-indent-4{counter-increment:list-4;counter-reset:list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-4::before{content:counter(list-4,lower-alpha) ". "}.ql-editor ol li.ql-indent-5{counter-increment:list-5;counter-reset:list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-5::before{content:counter(list-5,lower-roman) ". "}.ql-editor ol li.ql-indent-6{counter-increment:list-6;counter-reset:list-7 list-8 list-9}.ql-editor ol li.ql-indent-6::before{content:counter(list-6,decimal) ". "}.ql-editor ol li.ql-indent-7{counter-increment:list-7;counter-reset:list-8 list-9}.ql-editor ol li.ql-indent-7::before{content:counter(list-7,lower-alpha) ". "}.ql-editor ol li.ql-indent-8{counter-increment:list-8;counter-reset:list-9}.ql-editor ol li.ql-indent-8::before{content:counter(list-8,lower-roman) ". "}.ql-editor ol li.ql-indent-9{counter-increment:list-9}.ql-editor ol li.ql-indent-9::before{content:counter(list-9,decimal) ". "}'; + /** + * User meta: unix time until which the "Finish setting up" widget is snoozed + * for this user across every form ("Remind me in two weeks"). Per-user rather + * than per-form so the reminder hides the whole widget, not just one form. + * + * @since x.x.x + */ + public const SETUP_WIDGET_SNOOZE_USER_META = 'srfm_setup_widget_snooze_until'; + /** * Dashboard widget entries data. * @@ -251,15 +260,6 @@ public static function is_first_form_created() { return is_int( $first_form_creation_time_stamp ) && $first_form_creation_time_stamp > 0; } - /** - * User meta: unix time until which the "Finish setting up" widget is snoozed - * for this user across every form ("Remind me in two weeks"). Per-user rather - * than per-form so the reminder hides the whole widget, not just one form. - * - * @since x.x.x - */ - public const SETUP_WIDGET_SNOOZE_USER_META = 'srfm_setup_widget_snooze_until'; - /** * Setup-checklist data for the newest form that still needs finishing (#3031). * @@ -2471,20 +2471,20 @@ public function render_form_setup_widget() { <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'Finish these and the form is ready for real submissions.', 'sureforms' ); ?></p> <ul class="srfm-setup-checklist__steps"> - <?php foreach ( $rows as $row ) : ?> + <?php foreach ( $rows as $row ) { ?> <?php $done = ! empty( $steps[ $row['key'] ] ); ?> <li class="srfm-setup-checklist__step<?php echo $done ? ' is-done' : ''; ?>"> <span class="srfm-setup-checklist__check" aria-hidden="true"><?php echo $done ? '✓' : ''; ?></span> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> - <?php if ( ! $done && ! empty( $row['cta'] ) ) : ?> - <?php if ( ! empty( $row['is_embed'] ) ) : ?> + <?php if ( ! $done && ! empty( $row['cta'] ) ) { ?> + <?php if ( ! empty( $row['is_embed'] ) ) { ?> <button type="button" class="srfm-setup-checklist__cta" id="srfm-setup-checklist-embed"><?php echo esc_html( $row['cta'] ); ?></button> - <?php else : ?> + <?php } else { ?> <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> - <?php endif; ?> - <?php endif; ?> + <?php } ?> + <?php } ?> </li> - <?php endforeach; ?> + <?php } ?> </ul> <div class="srfm-setup-checklist__embed" id="srfm-setup-checklist-embed-box"> diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index c3f2d23e5..559f80608 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -935,4 +935,114 @@ public function test_is_sureforms_owned_notice_callback() { 'A null callback should not be recognised as owned.' ); } + + /** + * The first-form-created flag resolves to a boolean. + */ + public function test_is_first_form_created() { + $this->assertIsBool( Admin::is_first_form_created() ); + } + + /** + * A default confirmation message is detected; an edited one is not (#3031). + */ + public function test_is_default_confirmation_message() { + $this->assertFalse( Admin::is_default_confirmation_message( 0 ) ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Conf detect' ] ); + + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message() ] ] ); + $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); + + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => 'Thanks - we will be in touch!' ] ] ); + $this->assertFalse( Admin::is_default_confirmation_message( $form_id ) ); + + wp_delete_post( $form_id, true ); + } + + /** + * The default admin notification is the untouched default until customised (#3031). + */ + public function test_is_default_email_notification() { + // No notification meta at all -> treated as untouched default. + $this->assertTrue( Admin::is_default_email_notification( 0 ) ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Notif detect' ] ); + + // A customised recipient means it has been touched. + update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => true, 'email_to' => 'sales@example.com', 'subject' => 'Hi', 'email_body' => '{all_data}' ] ] ); + $this->assertFalse( Admin::is_default_email_notification( $form_id ) ); + + wp_delete_post( $form_id, true ); + } + + /** + * Embed detection matches the srfm/form block on a published page (#3031). + */ + public function test_form_is_embedded() { + $this->assertFalse( Admin::form_is_embedded( 0 ) ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Embed check' ] ); + + // Not placed anywhere yet. + $this->assertFalse( Admin::form_is_embedded( $form_id ) ); + + // Embedded via the srfm/form block on a published page. + $page_id = wp_insert_post( [ 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => 'Has form', 'post_content' => '<!-- wp:srfm/form {"id":' . $form_id . '} /-->' ] ); + $this->assertTrue( Admin::form_is_embedded( $form_id ) ); + + wp_delete_post( $page_id, true ); + wp_delete_post( $form_id, true ); + } + + /** + * The setup-card query returns a card payload or null. + */ + public function test_get_form_setup_card() { + $card = Admin::get_form_setup_card(); + $this->assertTrue( null === $card || is_array( $card ) ); + } + + /** + * The setup-card REST handler is registered on the Admin instance (#3031). + */ + public function test_dismiss_form_setup_card() { + $this->assertTrue( method_exists( Admin::get_instance(), 'dismiss_form_setup_card' ) ); + } + + /** + * The dashboard-widget registrar is callable (#3031). + */ + public function test_register_form_setup_widget() { + $this->assertTrue( method_exists( Admin::get_instance(), 'register_form_setup_widget' ) ); + } + + /** + * The dashboard-widget renderer is callable (#3031). + */ + public function test_render_form_setup_widget() { + $this->assertTrue( method_exists( Admin::get_instance(), 'render_form_setup_widget' ) ); + } + + /** + * The dashboard-widget asset enqueue is callable (#3031). + */ + public function test_enqueue_form_setup_widget_assets() { + $this->assertTrue( method_exists( Admin::get_instance(), 'enqueue_form_setup_widget_assets' ) ); + } } From 46a0b3ee3e9e733fc8f34b93c64d12ce1c119c7e Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Mon, 17 Aug 2026 23:56:45 +0530 Subject: [PATCH 25/65] Show the setup checklist widget only for starter-template forms (#3031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate get_form_setup_card() on the _astra_sites_imported_post marker Astra Sites stamps on imported posts, so the dashboard widget targets only forms created from a starter template — matching the Thank You notice (#3030). --- admin/admin.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/admin/admin.php b/admin/admin.php index cfaa8d804..f09ef990a 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -302,6 +302,8 @@ public static function get_form_setup_card() { return $cache; } + // Only forms created from an Astra Sites starter template — those carry the + // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. $query = new \WP_Query( [ 'post_type' => SRFM_FORMS_POST_TYPE, @@ -311,6 +313,12 @@ public static function get_form_setup_card() { 'order' => 'DESC', 'fields' => 'ids', 'no_found_rows' => true, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. + [ + 'key' => '_astra_sites_imported_post', + 'compare' => 'EXISTS', + ], + ], ] ); From e399d272156627098697ba29e63de5a71b000886 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 00:00:10 +0530 Subject: [PATCH 26/65] Drop the quotes around the form name in the setup widget heading (#3031) --- admin/admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/admin.php b/admin/admin.php index f09ef990a..9835508a9 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2468,7 +2468,7 @@ public function render_form_setup_widget() { $progress = sprintf( /* translators: 1: form title, 2: completed step count, 3: total step count. */ - __( '“%1$s” is %2$d of %3$d steps done', 'sureforms' ), + __( '%1$s is %2$d of %3$d steps done', 'sureforms' ), $card['title'], $card['done_count'], $card['total'] From 22f29c4484b7014233600518beccdfa35767fae7 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 00:09:31 +0530 Subject: [PATCH 27/65] Render the setup widget as a plain Done/To do task list (#3031) Replace the check-circle icons with a text status label (Done / To do) per row, so the widget reads as a task list rather than a checklist. --- admin/admin.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 9835508a9..01005b919 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2482,7 +2482,7 @@ public function render_form_setup_widget() { <?php foreach ( $rows as $row ) { ?> <?php $done = ! empty( $steps[ $row['key'] ] ); ?> <li class="srfm-setup-checklist__step<?php echo $done ? ' is-done' : ''; ?>"> - <span class="srfm-setup-checklist__check" aria-hidden="true"><?php echo $done ? '✓' : ''; ?></span> + <span class="srfm-setup-checklist__status"><?php echo esc_html( $done ? __( 'Done', 'sureforms' ) : __( 'To do', 'sureforms' ) ); ?></span> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> <?php if ( ! $done && ! empty( $row['cta'] ) ) { ?> <?php if ( ! empty( $row['is_embed'] ) ) { ?> @@ -2538,10 +2538,12 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { .srfm-setup-checklist__step { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; } .srfm-setup-checklist__step + .srfm-setup-checklist__step { margin-top: 6px; } .srfm-setup-checklist__step:not(.is-done) { background: #f6f7f7; } -.srfm-setup-checklist__check { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%; border: 2px solid #c3c4c7; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; color: #fff; box-sizing: border-box; } -.srfm-setup-checklist__step.is-done .srfm-setup-checklist__check { background: #16a34a; border-color: #16a34a; } +.srfm-setup-checklist__status { flex: 0 0 auto; font-size: 14px; font-weight: 600; } +.srfm-setup-checklist__status::after { content: ' \2014'; font-weight: 400; color: #787c82; } +.srfm-setup-checklist__step:not(.is-done) .srfm-setup-checklist__status { color: #d54e21; } +.srfm-setup-checklist__step.is-done .srfm-setup-checklist__status { color: #16a34a; } .srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } -.srfm-setup-checklist__step.is-done .srfm-setup-checklist__label { text-decoration: line-through; color: #787c82; } +.srfm-setup-checklist__step.is-done .srfm-setup-checklist__label { color: #787c82; } .srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__cta:hover { color: #b83c14; } .srfm-setup-checklist__embed { display: none; gap: 8px; margin: 10px 12px 0; } From 346cf5ca89340219ce840319e5445a93ec41235f Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 00:17:17 +0530 Subject: [PATCH 28/65] Drop the Done/To do status label from the setup widget rows (#3031) Show just the task label per row; completed steps read muted and remaining tasks keep the highlighted row and CTA. --- admin/admin.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 01005b919..1883d5f1e 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2482,7 +2482,6 @@ public function render_form_setup_widget() { <?php foreach ( $rows as $row ) { ?> <?php $done = ! empty( $steps[ $row['key'] ] ); ?> <li class="srfm-setup-checklist__step<?php echo $done ? ' is-done' : ''; ?>"> - <span class="srfm-setup-checklist__status"><?php echo esc_html( $done ? __( 'Done', 'sureforms' ) : __( 'To do', 'sureforms' ) ); ?></span> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> <?php if ( ! $done && ! empty( $row['cta'] ) ) { ?> <?php if ( ! empty( $row['is_embed'] ) ) { ?> @@ -2538,10 +2537,6 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { .srfm-setup-checklist__step { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; } .srfm-setup-checklist__step + .srfm-setup-checklist__step { margin-top: 6px; } .srfm-setup-checklist__step:not(.is-done) { background: #f6f7f7; } -.srfm-setup-checklist__status { flex: 0 0 auto; font-size: 14px; font-weight: 600; } -.srfm-setup-checklist__status::after { content: ' \2014'; font-weight: 400; color: #787c82; } -.srfm-setup-checklist__step:not(.is-done) .srfm-setup-checklist__status { color: #d54e21; } -.srfm-setup-checklist__step.is-done .srfm-setup-checklist__status { color: #16a34a; } .srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } .srfm-setup-checklist__step.is-done .srfm-setup-checklist__label { color: #787c82; } .srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } From 428c2723797ea4277d2aff2a694f0988a5469e9a Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 00:28:52 +0530 Subject: [PATCH 29/65] Show setup widget steps as optional actions, not a completion checklist (#3031) get_form_setup_card() no longer computes per-step completion; the widget lists a fixed set of optional next-steps (Edit form / Set up email / Get embed code), each always offering its CTA, with a plain 'Finish setting up <form>' heading and no progress count. --- admin/admin.php | 97 ++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 70 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 1883d5f1e..7bdaac7c4 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -261,24 +261,16 @@ public static function is_first_form_created() { } /** - * Setup-checklist data for the newest form that still needs finishing (#3031). + * Setup-checklist data for the newest starter-template form (#3031). * - * Picks the most recent form the current user can edit that is not yet ready for - * real submissions — and which has not been dismissed or snoozed — and reports - * the completion state of each setup step so the dashboard widget can render the - * checklist and its progress counter. Steps, each keyed by whether it is *done*: - * - * - created: the form exists (always done) - * - published: post status is `publish` - * - email: the default admin notification has been customized - * - page: the form is embedded on a published page or post - * - * Drafts are included so "publish" can legitimately be an outstanding step. A - * form with every step done is skipped — there is nothing to nudge. Memoized for - * the request so the widget register/enqueue/render passes share one query. + * Picks the most recent form the current user can edit that was created from an + * Astra Sites starter template and which the user has not snoozed. The widget + * lists a fixed set of optional next-steps for it — their completion is not + * computed — so the payload carries only the form and the CTA targets. Memoized + * for the request so the widget register/enqueue/render passes share one query. * * @since x.x.x - * @return array<string,mixed>|null Checklist payload, or null when nothing needs finishing. + * @return array<string,mixed>|null Card payload, or null when there is no candidate form. */ public static function get_form_setup_card() { static $cache = false; @@ -329,41 +321,22 @@ public static function get_form_setup_card() { continue; } - // Completion state of each checklist step (true = done). The email step - // is done only once the shipped default notification has been customized - // — every form ships with one, so mere presence is not "set up". - $steps = [ - 'created' => true, - 'published' => 'publish' === get_post_status( $form_id ), - 'email' => ! self::is_default_email_notification( $form_id ), - 'page' => self::form_is_embedded( $form_id ), - ]; - - $total = count( $steps ); - $done_count = count( array_filter( $steps ) ); - - // Ready for real submissions already — nothing to finish. - if ( $done_count >= $total ) { - continue; - } - $edit_link = get_edit_post_link( $form_id, 'raw' ); if ( empty( $edit_link ) ) { continue; } + // The steps are shown as optional next-steps — their completion is not + // computed, so the widget simply lists the actions the owner can take. $cache = [ - 'id' => $form_id, - 'title' => get_the_title( $form_id ), - 'steps' => $steps, - 'done_count' => $done_count, - 'total' => $total, - 'edit_url' => $edit_link, + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'edit_url' => $edit_link, // Deep-links to the email-notification panel where supported; falls // back to opening the editor when the focus handler isn't present. - 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), - 'shortcode' => sprintf( '[sureforms id="%d"]', $form_id ), + 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + 'shortcode' => sprintf( '[sureforms id="%d"]', $form_id ), ]; return $cache; @@ -2437,58 +2410,43 @@ public function render_form_setup_widget() { return; } - $steps = $card['steps']; - - // Ordered rows. "created" is informational (always done); the rest carry a - // CTA while incomplete. The "page" step reveals the shortcode inline. + // Optional next-steps — always offered, their completion is not computed. $rows = [ [ - 'key' => 'created', - 'label' => __( 'Form created', 'sureforms' ), - ], - [ - 'key' => 'published', 'label' => __( 'Review the fields and publish', 'sureforms' ), 'cta' => __( 'Edit form', 'sureforms' ), 'url' => $card['edit_url'], ], [ - 'key' => 'email', 'label' => __( 'Choose who gets notified of new replies', 'sureforms' ), 'cta' => __( 'Set up email', 'sureforms' ), 'url' => $card['email_url'], ], [ - 'key' => 'page', 'label' => __( 'Put the form on a page', 'sureforms' ), 'cta' => __( 'Get embed code', 'sureforms' ), 'is_embed' => true, ], ]; - $progress = sprintf( - /* translators: 1: form title, 2: completed step count, 3: total step count. */ - __( '%1$s is %2$d of %3$d steps done', 'sureforms' ), - $card['title'], - $card['done_count'], - $card['total'] + $heading = sprintf( + /* translators: %s: form title. */ + __( 'Finish setting up %s', 'sureforms' ), + $card['title'] ); ?> <div class="srfm-setup-checklist" id="srfm-setup-checklist"> - <p class="srfm-setup-checklist__title"><?php echo esc_html( $progress ); ?></p> - <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'Finish these and the form is ready for real submissions.', 'sureforms' ); ?></p> + <p class="srfm-setup-checklist__title"><?php echo esc_html( $heading ); ?></p> + <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'A few optional steps to get your form ready for real submissions:', 'sureforms' ); ?></p> <ul class="srfm-setup-checklist__steps"> <?php foreach ( $rows as $row ) { ?> - <?php $done = ! empty( $steps[ $row['key'] ] ); ?> - <li class="srfm-setup-checklist__step<?php echo $done ? ' is-done' : ''; ?>"> + <li class="srfm-setup-checklist__step"> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> - <?php if ( ! $done && ! empty( $row['cta'] ) ) { ?> - <?php if ( ! empty( $row['is_embed'] ) ) { ?> - <button type="button" class="srfm-setup-checklist__cta" id="srfm-setup-checklist-embed"><?php echo esc_html( $row['cta'] ); ?></button> - <?php } else { ?> - <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> - <?php } ?> + <?php if ( ! empty( $row['is_embed'] ) ) { ?> + <button type="button" class="srfm-setup-checklist__cta" id="srfm-setup-checklist-embed"><?php echo esc_html( $row['cta'] ); ?></button> + <?php } else { ?> + <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> <?php } ?> </li> <?php } ?> @@ -2536,9 +2494,8 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { .srfm-setup-checklist__steps { margin: 0; padding: 0; list-style: none; } .srfm-setup-checklist__step { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; } .srfm-setup-checklist__step + .srfm-setup-checklist__step { margin-top: 6px; } -.srfm-setup-checklist__step:not(.is-done) { background: #f6f7f7; } +.srfm-setup-checklist__step { background: #f6f7f7; } .srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } -.srfm-setup-checklist__step.is-done .srfm-setup-checklist__label { color: #787c82; } .srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__cta:hover { color: #b83c14; } .srfm-setup-checklist__embed { display: none; gap: 8px; margin: 10px 12px 0; } From dd771ccc6206185c536c97b62bba801d77e42c1c Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 00:59:17 +0530 Subject: [PATCH 30/65] fix: WP 7.1 iframed editor compatibility Addresses verified issues from the WP 7.1 QA pass: - TC-004: call core/block-editor.getBlocks() instead of the deprecated core/editor.getBlocks() in addInitialAttr.js. - TC-003/TC-014: mark the Text, URL and Email block editor-preview inputs readOnly so React no longer warns about a value prop without onChange (matches the existing Number block preview). - TC-005: return a stable empty-array reference from the quick-action sidebar useSelect to avoid needless re-renders. - TC-023: use fill="currentColor" for the two quick-action sidebar icons (add-block and edit) so they remain visible on light/high-contrast themes. - TC-019: hide SureForms editor UI (quick-action sidebar, Instant Form button, header title editor) when WP Distraction Free mode is active. --- .../quick-action-sidebar/components/Sidebar.js | 4 ++-- modules/quick-action-sidebar/components/blocks.js | 6 +++++- modules/quick-action-sidebar/editor.lazy.scss | 12 ++++++++++++ sass/backend/editor.scss | 15 +++++++++++++++ src/blocks/email/components/default.js | 2 ++ src/blocks/input/components/default.js | 2 +- src/blocks/url/components/default.js | 1 + src/srfm-controls/addInitialAttr.js | 2 +- 8 files changed, 39 insertions(+), 5 deletions(-) diff --git a/modules/quick-action-sidebar/components/Sidebar.js b/modules/quick-action-sidebar/components/Sidebar.js index fe7509ed3..52f9eff64 100644 --- a/modules/quick-action-sidebar/components/Sidebar.js +++ b/modules/quick-action-sidebar/components/Sidebar.js @@ -150,7 +150,7 @@ const Sidebar = () => { width="24" height="24" aria-hidden="true" - fill="#fff" + fill="currentColor" focusable="false" > <path d="M18 11.2h-5.2V6h-1.6v5.2H6v1.6h5.2V18h1.6v-5.2H18z"></path> @@ -217,7 +217,7 @@ const Sidebar = () => { width="24" height="24" aria-hidden="true" - fill="#fff" + fill="currentColor" focusable="false" > <path d="m19 7-3-3-8.5 8.5-1 4 4-1L19 7Zm-7 11.5H5V20h7v-1.5Z"></path> diff --git a/modules/quick-action-sidebar/components/blocks.js b/modules/quick-action-sidebar/components/blocks.js index 08947c294..d2e63c9af 100644 --- a/modules/quick-action-sidebar/components/blocks.js +++ b/modules/quick-action-sidebar/components/blocks.js @@ -6,6 +6,10 @@ import { createBlock, getBlockTypes } from '@wordpress/blocks'; import DraggableBlock from './draggable-block'; import DragAndDropComponent from './move-up-down'; +// Stable reference so `useSelect` doesn't return a fresh empty array on every +// call when no allowed blocks are resolved, which would trigger needless re-renders. +const EMPTY_ALLOWED_BLOCKS = []; + const Blocks = ( { defaultAllowedQuickSidebarBlocks, updateDefaultAllowedQuickSidebarBlocks, @@ -30,7 +34,7 @@ const Blocks = ( { blockInsertionPoint: index, getBlockRootClientId: rootClientId, getSelectedBlockClientId: clientId, - getSelectedBlockAllowedBlocks: allowedBlocks || [], + getSelectedBlockAllowedBlocks: allowedBlocks || EMPTY_ALLOWED_BLOCKS, }; } ); const srfmBlocks = blocks.filter( ( block ) => { diff --git a/modules/quick-action-sidebar/editor.lazy.scss b/modules/quick-action-sidebar/editor.lazy.scss index 9cbfe1dc1..f10827000 100644 --- a/modules/quick-action-sidebar/editor.lazy.scss +++ b/modules/quick-action-sidebar/editor.lazy.scss @@ -473,3 +473,15 @@ div#widgets-editor { .srfm-ee-quick-access__sidebar--prevent-editor-interactions { pointer-events: none; } + +/** + * WP 7.1 Distraction Free mode. + * + * The quick-action sidebar is a fixed element inserted into + * `.interface-interface-skeleton__body`, so core's distraction-free chrome + * hiding never reaches it and it lingers as a floating artifact. Hide it while + * distraction-free is active; toggling the mode off restores it. + */ +.is-distraction-free .srfm-ee-quick-access-container { + display: none; +} diff --git a/sass/backend/editor.scss b/sass/backend/editor.scss index d95fb9c4c..993d07914 100644 --- a/sass/backend/editor.scss +++ b/sass/backend/editor.scss @@ -812,3 +812,18 @@ html[dir="rtl"] body.post-type-sureforms_form { .srfm-upgrade-prompt__link:focus { color: #d54407; } + +/** + * WP 7.1 Distraction Free mode. + * + * SureForms injects its Instant Form button and the header title editor into + * core's editor header. When Distraction Free is enabled these should hide + * along with core's chrome instead of lingering as floating buttons; toggling + * the mode off restores them. + */ +.is-distraction-free { + .srfm-instant-form-root, + .srfm-header-title-input { + display: none !important; + } +} diff --git a/src/blocks/email/components/default.js b/src/blocks/email/components/default.js index 28f0c4d90..97fade697 100644 --- a/src/blocks/email/components/default.js +++ b/src/blocks/email/components/default.js @@ -48,6 +48,7 @@ export const EmailComponent = ( { attributes, blockID, setAttributes } ) => { className={ `srfm-input-common srfm-input-${ slug }` } placeholder={ placeholder } required={ required } + readOnly={ true } /> </div> <div className="srfm-error-wrap"></div> @@ -80,6 +81,7 @@ export const EmailComponent = ( { attributes, blockID, setAttributes } ) => { className={ `srfm-input-common srfm-${ slug }-email-confirm` } placeholder={ placeholder } required={ required } + readOnly={ true } /> </div> <div className="srfm-error-wrap"></div> diff --git a/src/blocks/input/components/default.js b/src/blocks/input/components/default.js index 427b23193..a9c82fb3e 100644 --- a/src/blocks/input/components/default.js +++ b/src/blocks/input/components/default.js @@ -39,7 +39,7 @@ export const InputComponent = ( { attributes, blockID, setAttributes } ) => { className={ `srfm-input-common srfm-input-${ slug }` } placeholder={ placeholder } required={ required } - readOnly={ readOnly } + readOnly={ true } /> </div> </> diff --git a/src/blocks/url/components/default.js b/src/blocks/url/components/default.js index a97d56613..d04da3ea5 100644 --- a/src/blocks/url/components/default.js +++ b/src/blocks/url/components/default.js @@ -38,6 +38,7 @@ export const UrlComponent = ( { attributes, blockID, setAttributes } ) => { className={ `srfm-input-common srfm-input-${ slug }` } placeholder={ placeholder } required={ required } + readOnly={ true } /> </div> </> diff --git a/src/srfm-controls/addInitialAttr.js b/src/srfm-controls/addInitialAttr.js index 8dbdef846..cb8c91063 100644 --- a/src/srfm-controls/addInitialAttr.js +++ b/src/srfm-controls/addInitialAttr.js @@ -46,7 +46,7 @@ const addInitialAttr = ( ChildComponent ) => { useEffect( () => { const newBlockId = clientId.substr( 0, 8 ); const attributeObject = { block_id: newBlockId }; - const getAllBlocks = select( 'core/editor' )?.getBlocks(); + const getAllBlocks = select( 'core/block-editor' )?.getBlocks(); const { blockIds, clientIds } = getAllBlocks ? getUniqId( getAllBlocks ) : { blockIds: [], clientIds: [] }; From c67d5d7f86661be7f9121ebfc9c90add4b70639b Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 01:21:35 +0530 Subject: [PATCH 31/65] fix: replace deprecated defaultProps on function components (TC-009, TC-013) React deprecates `.defaultProps` on function components. Convert all 12 shared SureForms controls to preserve identical default-value behavior: - Destructuring defaults where the component destructures props in-signature or on the first line: separator, select-control, multi-select-control, spectra-helper-panel, matrix-alignment-control. - A `{ ...DEFAULTS, ...props }` merge at the top where the component reads `props.*` directly: text-control, range, number-control, presets, typography/fontloader, responsive-border. - popup-confirm only had an empty `defaultProps = {}`; removed outright. Clears the defaultProps deprecation warnings reported on Text, Signature, Range and other inspector controls (TC-009 signature block, TC-013 wider scope). These are the shared components bundled into blocks.js / signatureAdmin.js, so this covers both reported locations. --- .../matrix-alignment-control/index.js | 13 ++++++------ src/components/multi-select-control/index.js | 20 +++++++------------ src/components/number-control/index.js | 5 +++-- src/components/popup-confirm/index.js | 2 -- src/components/presets/index.js | 5 +++-- src/components/range/Range.js | 5 +++-- src/components/responsive-border/index.js | 4 ++-- src/components/select-control/index.js | 10 ++-------- src/components/separator/index.js | 6 +----- src/components/spectra-helper-panel/index.js | 7 +------ src/components/text-control/index.js | 5 +++-- src/components/typography/fontloader.js | 5 +++-- 12 files changed, 35 insertions(+), 52 deletions(-) diff --git a/src/components/matrix-alignment-control/index.js b/src/components/matrix-alignment-control/index.js index 439b08e66..035e5cf84 100644 --- a/src/components/matrix-alignment-control/index.js +++ b/src/components/matrix-alignment-control/index.js @@ -14,10 +14,6 @@ const propTypes = { }; // Set the Required Default Values. -const defaultProps = { - label: __( 'Alignment', 'sureforms' ), -}; - // Create the SRFM Control. const SRFMMatrixControl = ( props ) => { // Add and remove the CSS on the drop and remove of the component. @@ -29,7 +25,13 @@ const SRFMMatrixControl = ( props ) => { }, [] ); // Extract all props. - const { label, data, onChange, setAttributes, help = false } = props; + const { + label = __( 'Alignment', 'sureforms' ), + data, + onChange, + setAttributes, + help = false, + } = props; // Handle the Appropriate const onChangeHandler = ( newValue ) => { @@ -62,6 +64,5 @@ const SRFMMatrixControl = ( props ) => { }; SRFMMatrixControl.propTypes = propTypes; -SRFMMatrixControl.defaultProps = defaultProps; export default SRFMMatrixControl; diff --git a/src/components/multi-select-control/index.js b/src/components/multi-select-control/index.js index 22ce3b6c7..79b8e6390 100644 --- a/src/components/multi-select-control/index.js +++ b/src/components/multi-select-control/index.js @@ -13,19 +13,14 @@ const propTypes = { setAttributes: PropTypes.func, }; -const defaultProps = { - label: '', - options: [], - data: { - label: '', - value: [], - }, - isSearchable: false, - setAttributes: () => {}, -}; - export default function SRFMMultiSelectControl( props ) { - const { label, options, data, isSearchable, setAttributes } = props; + const { + label = '', + options = [], + data = { label: '', value: [] }, + isSearchable = false, + setAttributes = () => {}, + } = props; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); const { getSelectedBlock } = select( 'core/block-editor' ); @@ -85,4 +80,3 @@ export default function SRFMMultiSelectControl( props ) { } SRFMMultiSelectControl.propTypes = propTypes; -SRFMMultiSelectControl.defaultProps = defaultProps; diff --git a/src/components/number-control/index.js b/src/components/number-control/index.js index 529c982d8..c9c6cf6d9 100644 --- a/src/components/number-control/index.js +++ b/src/components/number-control/index.js @@ -22,7 +22,8 @@ import Separator from '@Components/separator'; import { applyFilters } from '@wordpress/hooks'; import SRFMHelpText from '@Components/help-text'; -const SRFMNumberControl = ( props ) => { +const SRFMNumberControl = ( rawProps ) => { + const props = { ...SRFM_NUMBER_CONTROL_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); // Add and remove the CSS on the drop and remove of the component. @@ -259,7 +260,7 @@ const SRFMNumberControl = ( props ) => { ); }; -SRFMNumberControl.defaultProps = { +const SRFM_NUMBER_CONTROL_DEFAULTS = { label: __( 'Margin', 'sureforms' ), className: '', allowReset: true, diff --git a/src/components/popup-confirm/index.js b/src/components/popup-confirm/index.js index 9f7ed2b84..248fb65f0 100644 --- a/src/components/popup-confirm/index.js +++ b/src/components/popup-confirm/index.js @@ -110,6 +110,4 @@ const SRFMConfirmPopup = ( props ) => { ); }; -SRFMConfirmPopup.defaultProps = {}; - export default SRFMConfirmPopup; diff --git a/src/components/presets/index.js b/src/components/presets/index.js index 499b4a7c9..a07ad7188 100644 --- a/src/components/presets/index.js +++ b/src/components/presets/index.js @@ -15,7 +15,8 @@ import { getIdFromString, getPanelIdFromRef } from '@Utils/Helpers'; import SRFMReset from '../reset'; import SRFMHelpText from '@Components/help-text'; -const SRFMPresets = ( props ) => { +const SRFMPresets = ( rawProps ) => { + const props = { ...SRFM_PRESETS_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); @@ -286,7 +287,7 @@ const SRFMPresets = ( props ) => { ); }; -SRFMPresets.defaultProps = { +const SRFM_PRESETS_DEFAULTS = { presetInputType: 'dropdown', label: __( 'Select Preset', 'sureforms' ), }; diff --git a/src/components/range/Range.js b/src/components/range/Range.js index 4d1e7375a..f0f622998 100644 --- a/src/components/range/Range.js +++ b/src/components/range/Range.js @@ -23,7 +23,8 @@ import SRFMHelpText from '@Components/help-text'; const isNumberControlSupported = !! NumberControl; -const Range = ( props ) => { +const Range = ( rawProps ) => { + const props = { ...RANGE_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); @@ -243,7 +244,7 @@ const Range = ( props ) => { ); }; -Range.defaultProps = { +const RANGE_DEFAULTS = { label: __( 'Margin', 'sureforms' ), className: '', allowReset: true, diff --git a/src/components/responsive-border/index.js b/src/components/responsive-border/index.js index 07683e5cb..24130b57b 100644 --- a/src/components/responsive-border/index.js +++ b/src/components/responsive-border/index.js @@ -31,7 +31,8 @@ const defaultProps = { borderHoverColorLabel: __( 'Hover Color', 'sureforms' ), }; -const ResponsiveBorder = ( props ) => { +const ResponsiveBorder = ( rawProps ) => { + const props = { ...defaultProps, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); @@ -380,4 +381,3 @@ const ResponsiveBorder = ( props ) => { export default ResponsiveBorder; ResponsiveBorder.propTypes = propTypes; -ResponsiveBorder.defaultProps = defaultProps; diff --git a/src/components/select-control/index.js b/src/components/select-control/index.js index 9f5402937..82324d913 100644 --- a/src/components/select-control/index.js +++ b/src/components/select-control/index.js @@ -24,18 +24,13 @@ const propTypes = { help: PropTypes.string, }; -const defaultProps = { - layout: 'inline', - onChange: null, -}; - export default function SRFMSelectControl( { - layout, + layout = 'inline', label, options, data, setAttributes, - onChange, + onChange = null, help, children, } ) { @@ -125,4 +120,3 @@ export default function SRFMSelectControl( { } SRFMSelectControl.propTypes = propTypes; -SRFMSelectControl.defaultProps = defaultProps; diff --git a/src/components/separator/index.js b/src/components/separator/index.js index e6c47e9c6..da73c61f7 100644 --- a/src/components/separator/index.js +++ b/src/components/separator/index.js @@ -17,10 +17,7 @@ const propTypes = { disabledTopSpace: PropTypes.bool, }; -const defaultProps = { - disabledTopSpace: false, -}; -export default function Separator( { disabledTopSpace } ) { +export default function Separator( { disabledTopSpace = false } ) { const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); // Add and remove the CSS on the drop and remove of the component. @@ -62,4 +59,3 @@ export default function Separator( { disabledTopSpace } ) { } Separator.propTypes = propTypes; -Separator.defaultProps = defaultProps; diff --git a/src/components/spectra-helper-panel/index.js b/src/components/spectra-helper-panel/index.js index 166cc6791..3e0351bab 100644 --- a/src/components/spectra-helper-panel/index.js +++ b/src/components/spectra-helper-panel/index.js @@ -10,13 +10,9 @@ const propTypes = { message: PropTypes.string, }; -const defaultProps = { - useLogo: true, -}; - // The SRFM Helper Panel Component. const SRFMHelperPanel = ( props ) => { - const { useLogo, message } = props; + const { useLogo = true, message } = props; // Add and remove the CSS on the drop and remove of the component. useLayoutEffect( () => { @@ -70,4 +66,3 @@ const SRFMHelperPanel = ( props ) => { export default SRFMHelperPanel; SRFMHelperPanel.propTypes = propTypes; -SRFMHelperPanel.defaultProps = defaultProps; diff --git a/src/components/text-control/index.js b/src/components/text-control/index.js index 4dde907a9..b9c18b23e 100644 --- a/src/components/text-control/index.js +++ b/src/components/text-control/index.js @@ -17,7 +17,8 @@ import SRFMHelpText from '@Components/help-text'; import { applyFilters } from '@wordpress/hooks'; import EditorSmartTagList from '@Components/misc/EditorSmartTagList'; -const SRFMTextControl = ( props ) => { +const SRFMTextControl = ( rawProps ) => { + const props = { ...SRFM_TEXT_CONTROL_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); const [ inputData, setInputData ] = useState( props?.value ); @@ -225,7 +226,7 @@ const SRFMTextControl = ( props ) => { ); }; -SRFMTextControl.defaultProps = { +const SRFM_TEXT_CONTROL_DEFAULTS = { label: '', type: 'text', className: '', diff --git a/src/components/typography/fontloader.js b/src/components/typography/fontloader.js index 74db6ed44..618855d0c 100644 --- a/src/components/typography/fontloader.js +++ b/src/components/typography/fontloader.js @@ -11,7 +11,8 @@ const statuses = { }; const noop = () => {}; -const WebfontLoader = ( props ) => { +const WebfontLoader = ( rawProps ) => { + const props = { ...WEBFONT_LOADER_DEFAULTS, ...rawProps }; const [ value, setValue ] = useState( [] ); const status = undefined; @@ -99,7 +100,7 @@ WebfontLoader.propTypes = { onStatus: PropTypes.func?.isRequired, }; -WebfontLoader.defaultProps = { +const WEBFONT_LOADER_DEFAULTS = { onStatus: noop, }; From 14358ebcf99c3dc997be1eeebeb4e0c5cfa69948 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 08:06:23 +0530 Subject: [PATCH 32/65] fix: also fix deprecated core/editor.getBlocks in gutenberg module; drop DFM header rule (TC-004, TC-019) - TC-004: the gutenberg module mirrors addInitialAttr and had the same deprecated `select('core/editor').getBlocks()` call. Point it at core/block-editor too. Verified: inserting/mounting blocks no longer emits the deprecation warning. (Module bundle under modules/gutenberg/build must be regenerated via its own `npm run build`.) - TC-019: remove the Distraction Free header CSS from backend/editor.scss. It did not solve the header (which also shows core buttons) and did not compile into a loaded stylesheet. The quick-action sidebar hide in editor.lazy.scss is the verified fix and stays. --- modules/gutenberg/src/controls/addInitialAttr.js | 2 +- sass/backend/editor.scss | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/modules/gutenberg/src/controls/addInitialAttr.js b/modules/gutenberg/src/controls/addInitialAttr.js index 37111a048..e5b4d5190 100644 --- a/modules/gutenberg/src/controls/addInitialAttr.js +++ b/modules/gutenberg/src/controls/addInitialAttr.js @@ -175,7 +175,7 @@ const addInitialAttr = ( ChildComponent ) => { ]; if ( ! REUSABLE_BLOCK_ISSUE_RESOLVED_BLOCKS.includes( name ) ) { - const getAllBlocks = select( 'core/editor' )?.getBlocks(); + const getAllBlocks = select( 'core/block-editor' )?.getBlocks(); const { blockIds, clientIds } = getAllBlocks ? getUniqId( getAllBlocks ) : { blockIds: [], clientIds: [] }; diff --git a/sass/backend/editor.scss b/sass/backend/editor.scss index 993d07914..d95fb9c4c 100644 --- a/sass/backend/editor.scss +++ b/sass/backend/editor.scss @@ -812,18 +812,3 @@ html[dir="rtl"] body.post-type-sureforms_form { .srfm-upgrade-prompt__link:focus { color: #d54407; } - -/** - * WP 7.1 Distraction Free mode. - * - * SureForms injects its Instant Form button and the header title editor into - * core's editor header. When Distraction Free is enabled these should hide - * along with core's chrome instead of lingering as floating buttons; toggling - * the mode off restores them. - */ -.is-distraction-free { - .srfm-instant-form-root, - .srfm-header-title-input { - display: none !important; - } -} From b4abda5772d00b2b417042251cf34838800f445c Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 09:06:33 +0530 Subject: [PATCH 33/65] fix: restore SureForms editor logo on WP 7.1 header (editor-header__back-button) WP 7.1 replaced the `.edit-post-fullscreen-mode-close` button with the generic `.editor-header__back-button` wrapper, so the header-logo selectors no longer matched and the top-left showed the default back chevron instead of the SureForms "F" logo. Add parallel rules targeting the new markup (the old `.edit-post-*` rules stay for WP < 7.1). Verified live in the WP 7.1 editor. --- sass/header-styles.scss | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sass/header-styles.scss b/sass/header-styles.scss index 512cf7644..4720bafee 100644 --- a/sass/header-styles.scss +++ b/sass/header-styles.scss @@ -33,6 +33,46 @@ body.post-type-sureforms_form .edit-post-header .edit-post-fullscreen-mode-close box-shadow: none; } +// WP 7.1: the `.edit-post-fullscreen-mode-close` button was replaced by the +// generic `.editor-header__back-button` wrapper, so the selectors above no +// longer match and the SureForms logo fell back to the default back chevron. +// Re-apply the logo to the new markup (the rules above stay for WP < 7.1). + +// styles the back-button wrapper as the logo tile. +body.post-type-sureforms_form .editor-header__back-button { + align-items: center; + align-self: stretch; + background: #1e1e1e; + border-radius: 0; + display: flex; + justify-content: center; + position: relative; + width: 60px; +} + +// keeps the (now icon-less) back link filling the tile and clickable. +body.post-type-sureforms_form .editor-header__back-button a.components-button { + color: #fff; + height: 100%; + justify-content: center; + width: 60px; +} + +// hides the default back chevron. +body.post-type-sureforms_form .editor-header__back-button a.components-button svg { + display: none; +} + +// adds the SureForms logo on top of the back link. +body.post-type-sureforms_form .editor-header__back-button:before { + content: url( 'data:image/svg+xml;utf8,<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M32 0H0V32H32V0ZM22.8573 6.85728H9.14304V11.4287V13.7144L11.4288 11.4287H22.8573V6.85728ZM20.5717 13.7146H9.14314V18.286V20.5714V20.5718V25.1428H16.0003V20.5714H9.14351L11.4289 18.286H20.5717V13.7146Z" fill="white"/></svg>' ); + left: 50%; + pointer-events: none; + position: absolute; + top: 50%; + transform: translate( -50%, -50% ); +} + // hides the pinned items other than settings. // When the block is not selected aria-controls is set to edit-post:document. // When the block is selected aria-controls is set to edit-post:block. So we need to exclude these two. From 96b5ada47cb029ab7758d5096183c5473bf7d4f2 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 11:02:39 +0530 Subject: [PATCH 34/65] Address review on the Thank You setup prompt (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reliability and correctness fixes from Adi's review, keeping the three-CTA prompt: - Deep-link CTAs now work regardless of the editor's sidebar state: read ?srfm_focus from the server (Gutenberg strips it client-side before the bundle runs), open the settings sidebar from the always-mounted editor root so the settings panel mounts, then self-open the target tab once (consume-once, no poll, no overlay reach-in). Verified live with the sidebar preference closed and that it does not reopen after the user closes it. - 'Set where replies go' points to the Email Notification tab (srfm_focus= notifications) — where the reply destination is actually set, so the CTA can clear that step; dropped the unused ottokit target. - Notice: single stable id (bounds the autoloaded option and dismissal meta to one row) with a dismissed-user short-circuit before the query, primed post/meta caches, redirect-confirmation guard, filter-payload validation, null memo sentinel, defined() guard, delegated dismiss beacon (the X is injected after parse), and a named constant for the Starter Templates marker. - Copy rewritten: warm, accurate, no false 'still the default' claim; SureForms mark painted as a CSS background (the message is kses'd); secondary links unpadded; 'Set where replies go' ordered last. Tests: reply-destination predicate, redirect-confirmation guard, notice markup/ CTAs, delegated dismiss, and the imported-vs-plain gate. --- admin/admin.php | 269 ++++++++++-------- inc/gutenberg-hooks.php | 11 + src/admin/single-form-settings/Editor.js | 56 +++- .../tabs/GeneralSettings.js | 142 ++++----- tests/unit/admin/test-admin.php | 107 +++++-- 5 files changed, 353 insertions(+), 232 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index c742e2ca5..7ed46524b 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -40,6 +40,16 @@ class Admin { */ public const RATING_NOTICE_THRESHOLD = 3; + /** + * Post meta the Starter Templates (Astra Sites) plugin stamps on every post it + * imports. The "Finish setting up" Thank You prompt (#3030) scopes to these + * forms only. Owned by a plugin that is NOT a SureForms dependency: on installs + * without Starter Templates nothing carries this meta and the prompt never shows. + * + * @since x.x.x + */ + public const ASTRA_SITES_IMPORT_META = '_astra_sites_imported_post'; + /** * Inline CSS for Quill 1.x (react-quill) list markers. * @@ -262,6 +272,10 @@ public static function is_first_form_created() { * compare equal. Any real edit to the heading or body text changes the text and * flips this to false, which is exactly when the prompt should stop showing. * + * Locale caveat: the comparison target is translated at call time, so a form + * whose default was stored under a different active locale won't match. That + * fails safe — the prompt simply doesn't show — never a false nag. + * * @param int $form_id Form post ID. * * @since x.x.x @@ -274,6 +288,15 @@ public static function is_default_confirmation_message( $form_id ) { return false; } + // The default message is only ever shown for a "same page" confirmation. + // A redirect ("different page" / "custom url") never renders it, yet the + // stored settings still seed the default message string — so without this + // guard a redirect form would be nagged forever about a message no visitor + // sees, with no way to clear the prompt by doing what it asks. + if ( ! isset( $confirmation[0]['confirmation_type'] ) || 'same page' !== $confirmation[0]['confirmation_type'] ) { + return false; + } + $message = $confirmation[0]['message']; if ( '' === trim( $message ) ) { @@ -290,38 +313,6 @@ public static function is_default_confirmation_message( $form_id ) { return $normalize( $message ) === $normalize( Global_Settings::get_default_confirmation_message() ); } - /** - * The most recently created form still using the default Thank You message. - * - * Powers the dashboard prompt (#3030). Limited to the single latest such form - * to avoid clutter, and to forms the current user may actually edit. A form is - * a candidate only when its confirmation message is untouched (default) and - * the prompt has not been dismissed for it. - * - * @since x.x.x - * @return array<int,array{id:int,title:string,edit_url:string}> One entry, or none. - */ - public static function get_thankyou_prompt_forms() { - // Memoized for the request so repeated reads (e.g. the notice render plus - // any add-on consumer) share a single query. - static $cache = false; - - if ( false !== $cache ) { - return $cache; - } - - /** - * Filter the forms the "Finish setting up" Thank You notice may surface. - * - * @param array<int,array<string,mixed>> $prompts Candidate prompt payloads. - * - * @since x.x.x - */ - $cache = apply_filters( 'srfm_thankyou_prompt_forms', self::compute_thankyou_prompt_forms() ); - - return $cache; - } - /** * Whether a form has somewhere to send replies (an enabled email notification * with a non-empty recipient). @@ -347,14 +338,51 @@ public static function form_has_reply_destination( $form_id ) { return false; } + /** + * The most recently created form still needing setup (default Thank You + * message, or no reply destination). + * + * Powers the "Finish setting up" prompt (#3030). Limited to the single latest + * such form to avoid clutter, and to forms the current user may actually edit. + * A form is a candidate when it still has an unfinished step (default Thank You + * message, or no reply destination). Dismissal is enforced by the caller, + * before this query runs. + * + * @since x.x.x + * @return array<int,array<string,mixed>> One entry, or none. + */ + public static function get_thankyou_prompt_forms() { + // Memoized for the request so repeated reads (e.g. the notice render plus + // any add-on consumer) share a single query. Sentinel is null, not false, + // so a filter returning false (__return_false to disable) still memoizes. + static $cache = null; + + if ( null !== $cache ) { + return $cache; + } + + /** + * Filter the forms the "Finish setting up" Thank You notice may surface. + * + * @param array<int,array<string,mixed>> $prompts Candidate prompt payloads. + * + * @since x.x.x + */ + $filtered = apply_filters( 'srfm_thankyou_prompt_forms', self::compute_thankyou_prompt_forms() ); + $cache = is_array( $filtered ) ? $filtered : []; + + return $cache; + } + /** * Register the "Finish setting up" prompt as an Astra Notices admin notice (#3030). * * Hooked to admin_notices so it registers before the Astra Notices library * renders (priority 30). Shown on every admin screen EXCEPT the main dashboard, * for the newest form the current user can edit that still has an unfinished - * step (default thank-you message or no reply destination). The notice id is - * per-form, so the library's built-in ✕ dismissal persists per form. + * step (default Thank You message, or no reply destination). Uses a single + * stable notice id so the library's built-in ✕ dismissal is one persistent + * choice ("stop nudging me"), not a per-form row. * * @since x.x.x * @return void @@ -375,21 +403,35 @@ public function render_thankyou_prompt_notice() { return; } - // Everywhere in wp-admin except the main dashboard. + // Everywhere in wp-admin except the main dashboard — the #3031 dashboard + // widget owns the on-dashboard setup nudge. Placement is intentional per #3030. $screen = get_current_screen(); if ( $screen && 'dashboard' === $screen->id ) { return; } - $prompts = self::get_thankyou_prompt_forms(); + // A single stable notice id (not per-form): keeps both the autoloaded + // `allowed_astra_notices` option and the per-user dismissal meta bounded to + // one row, and lets a dismissed user short-circuit before the query runs. + $notice_id = 'srfm-thankyou-prompt'; + + // The library only checks dismissal at render (priority 30, after this + // query would already have run). Check it up front so a user who dismissed + // the prompt never pays for the WP_Query on subsequent admin page views. + if ( 'notice-dismissed' === get_user_meta( get_current_user_id(), $notice_id, true ) ) { + return; + } + + // array_values so a filter returning a key-preserving array (e.g. the + // result of array_filter()) still exposes the newest prompt at index 0. + $prompts = array_values( (array) self::get_thankyou_prompt_forms() ); - if ( empty( $prompts ) ) { + if ( empty( $prompts[0] ) || ! is_array( $prompts[0] ) || empty( $prompts[0]['id'] ) || empty( $prompts[0]['edit_url'] ) ) { return; } - $form = $prompts[0]; - $notice_id = 'srfm-thankyou-prompt-' . (int) $form['id']; + $form = $prompts[0]; \Astra_Notices::add_notice( [ @@ -429,15 +471,15 @@ public function enqueue_thankyou_notice_tracking() { wp_register_script( 'srfm-thankyou-notice-track', '', [], SRFM_VER, true ); wp_enqueue_script( 'srfm-thankyou-notice-track' ); - wp_localize_script( - 'srfm-thankyou-notice-track', - 'srfmThankYouNoticeTrack', + $config = wp_json_encode( [ 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'srfm_notice_response' ), ] ); + wp_add_inline_script( 'srfm-thankyou-notice-track', 'window.srfmThankYouNoticeTrack = ' . $config . ';', 'before' ); + $inline_script = <<<'JS' ( function () { const cfg = window.srfmThankYouNoticeTrack || {}; @@ -460,24 +502,27 @@ public function enqueue_thankyou_notice_tracking() { body: body.toString(), } ).catch( function () {} ); }; - [ + // Delegate from the wrapper: this inline script runs at parse time, before + // core's common.js injects the .notice-dismiss ✕ (on DOMContentLoaded), so a + // direct querySelector for it would find nothing and the dismiss beacon would + // never fire. Delegation catches the ✕ and the CTAs whenever they exist. + const ctas = [ [ '.srfm-ty-edit-form', 'edit_form' ], [ '.srfm-ty-set-replies', 'set_replies' ], [ '.srfm-ty-edit-thankyou', 'edit_thankyou' ], - ].forEach( function ( pair ) { - const el = wrap.querySelector( pair[ 0 ] ); - if ( el ) { - el.addEventListener( 'click', function () { - send( pair[ 1 ] ); - } ); + ]; + wrap.addEventListener( 'click', function ( e ) { + if ( e.target.closest( '.notice-dismiss' ) ) { + send( 'dismissed' ); + return; + } + for ( let i = 0; i < ctas.length; i++ ) { + if ( e.target.closest( ctas[ i ][ 0 ] ) ) { + send( ctas[ i ][ 1 ] ); + return; + } } } ); - const dismiss = wrap.querySelector( '.notice-dismiss' ); - if ( dismiss ) { - dismiss.addEventListener( 'click', function () { - send( 'dismissed' ); - } ); - } }() ); JS; @@ -494,19 +539,25 @@ public function enqueue_thankyou_notice_tracking() { * @return void */ public function print_thankyou_notice_styles() { + // The library wp_kses_post()'s the message, which strips <svg> and data: + // image srcs, so the SureForms mark is painted as a CSS background here + // (this hook fires outside that kses call). URL-encoded, not base64, so the + // value is fully percent-encoded and safe to pass through esc_url. + $icon = 'data:image/svg+xml,' . rawurlencode( + '<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 32 32"><path fill="#D54407" fill-rule="evenodd" clip-rule="evenodd" d="M32 0H0V32H32V0ZM22.8573 6.85728H9.14304V11.4287V13.7144L11.4288 11.4287H22.8573V6.85728ZM20.5717 13.7146H9.14314V18.286V20.5714V20.5718V25.1428H16.0003V20.5714H9.14351L11.4289 18.286H20.5717V13.7146Z"/></svg>' + ); ?> <style id="srfm-thankyou-notice-styles"> .srfm-thankyou-notice.notice { border-left-color: #D54407; } - /* The library lays the container out as a flex row; stack our blocks. */ - .srfm-thankyou-notice .astra-notice-container { display: block; padding: 4px 0; } + /* Stack our blocks (the library lays the container out as a flex row) and reserve room on the left for the SureForms mark. */ + .srfm-thankyou-notice .astra-notice-container { display: block; padding: 4px 0 4px 52px; background: url('<?php echo esc_url( $icon, [ 'data' ] ); ?>') no-repeat 4px 6px; background-size: 32px 32px; } .srfm-thankyou-notice .srfm-thankyou-notice__title { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: #1d2327; } .srfm-thankyou-notice .srfm-thankyou-notice__text { margin: 0 0 10px; color: #50575e; } .srfm-thankyou-notice .srfm-thankyou-notice__actions { margin: 12px 0 2px; display: flex; flex-wrap: wrap; gap: 10px 20px; align-items: center; } .srfm-thankyou-notice .button-primary { background: #D54407; border-color: #D54407; color: #fff; box-shadow: none; text-shadow: none; } .srfm-thankyou-notice .button-primary:hover, .srfm-thankyou-notice .button-primary:focus { background: #C83B00; border-color: #C83B00; color: #fff; box-shadow: none; } - .srfm-thankyou-notice .button:not(.button-primary) { background: transparent; border-color: transparent; color: #D54407; box-shadow: none; } + .srfm-thankyou-notice .button:not(.button-primary) { background: transparent; border-color: transparent; color: #D54407; box-shadow: none; padding: 0; } .srfm-thankyou-notice .button:not(.button-primary):hover, .srfm-thankyou-notice .button:not(.button-primary):focus { background: transparent; border-color: transparent; color: #C83B00; box-shadow: none; } - .srfm-thankyou-notice .srfm-ty-edit-thankyou { padding: 0; } .srfm-thankyou-notice .button-primary:focus { outline: 2px solid #D54407; outline-offset: 1px; } </style> <?php @@ -2034,25 +2085,6 @@ public function handle_notice_response() { $notice_id = isset( $_POST['notice_id'] ) ? sanitize_text_field( wp_unslash( $_POST['notice_id'] ) ) : ''; $button = isset( $_POST['button'] ) ? sanitize_text_field( wp_unslash( $_POST['button'] ) ) : ''; - // The "Finish setting up" prompt (#3030) uses a per-form notice id, so it - // can't be an exact key in the map below — match it by prefix and validate - // the button against its own fixed set. - if ( 0 === strpos( $notice_id, 'srfm-thankyou-prompt-' ) ) { - $thankyou_events = [ - 'edit_form' => 'thankyou_notice_edit_form', - 'set_replies' => 'thankyou_notice_set_replies', - 'edit_thankyou' => 'thankyou_notice_edit_thankyou', - 'dismissed' => 'thankyou_notice_dismiss', - ]; - - if ( ! isset( $thankyou_events[ $button ] ) ) { - wp_send_json_error( [ 'message' => __( 'Invalid parameters.', 'sureforms' ) ], 400 ); - } - - Analytics::events()->track( $thankyou_events[ $button ], $button ); - wp_send_json_success(); - } - $valid = [ 'srfm-getting-started-notice' => [ 'go_to_dashboard' => 'getting_started_notice_cta', @@ -2064,6 +2096,13 @@ public function handle_notice_response() { 'maybe_later' => 'rating_notice_snooze', 'dismissed' => 'rating_notice_dismiss', ], + // The "Finish setting up" prompt (#3030): three CTAs, plus the ✕. + 'srfm-thankyou-prompt' => [ + 'edit_form' => 'thankyou_notice_edit_form', + 'set_replies' => 'thankyou_notice_set_replies', + 'edit_thankyou' => 'thankyou_notice_edit_thankyou', + 'dismissed' => 'thankyou_notice_dismiss', + ], ]; if ( ! isset( $valid[ $notice_id ][ $button ] ) ) { @@ -2489,26 +2528,27 @@ public function render_dashboard_widget() { * @return array<int,array<string,mixed>> One entry, or none. */ private static function compute_thankyou_prompt_forms() { - if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { return []; } - // Only forms created from an Astra Sites starter template — those carry the - // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. - // Dismissal is handled per-form by the Astra Notices library (via the - // per-form notice id), so this only needs the newest incomplete form. + // Only forms imported from a Starter Templates (Astra Sites) starter + // template — see self::ASTRA_SITES_IMPORT_META. Prime post + meta caches + // (the loop reads meta, title and creation time per candidate) so this is a + // single query rather than the main query plus a follow-up per form. $query = new \WP_Query( [ - 'post_type' => SRFM_FORMS_POST_TYPE, - 'post_status' => 'publish', - 'posts_per_page' => 10, - 'orderby' => 'date', - 'order' => 'DESC', - 'fields' => 'ids', - 'no_found_rows' => true, - 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; admin-notice only. + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'orderby' => 'date', + 'order' => 'DESC', + 'no_found_rows' => true, + 'update_post_meta_cache' => true, + 'update_post_term_cache' => false, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; admin-notice only. [ - 'key' => '_astra_sites_imported_post', + 'key' => self::ASTRA_SITES_IMPORT_META, 'compare' => 'EXISTS', ], ], @@ -2518,8 +2558,8 @@ private static function compute_thankyou_prompt_forms() { $prompts = []; $now = time(); - foreach ( $query->posts as $form_id ) { - $form_id = (int) $form_id; + foreach ( $query->posts as $post ) { + $form_id = (int) $post->ID; if ( ! current_user_can( 'edit_post', $form_id ) ) { continue; @@ -2552,10 +2592,11 @@ private static function compute_thankyou_prompt_forms() { 'days_ago' => max( 0, $days_ago ), 'steps' => $steps, 'edit_url' => $edit_link, - // The editor reads srfm_focus to open the matching settings panel: - // "replies" lands on OttoKit (Automations), "thankyou" on Form - // Confirmation. - 'replies_url' => add_query_arg( 'srfm_focus', 'ottokit', $edit_link ), + // The editor reads srfm_focus to open the matching settings tab: + // "notifications" lands on Email Notification (where the reply + // destination is set, so the CTA can actually clear that step) and + // "thankyou" on Form Confirmation. + 'replies_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), ]; @@ -2575,31 +2616,11 @@ private static function compute_thankyou_prompt_forms() { * @return string */ private static function build_thankyou_notice_markup( $form ) { - $steps = isset( $form['steps'] ) && is_array( $form['steps'] ) ? $form['steps'] : []; - $days_ago = isset( $form['days_ago'] ) ? (int) $form['days_ago'] : 0; - - // The notice only surfaces forms still on the default confirmation, so the - // thank-you clause is always present; the reply-destination clause is the - // only variable. Each combination is a complete translatable phrase — no - // glued fragments — so translators can order the words for their locale. - $whats_left = ! empty( $steps['replies'] ) - ? __( 'replies have nowhere to go and the thank-you message is still the default', 'sureforms' ) - : __( 'the thank-you message is still the default', 'sureforms' ); - - $time_text = $days_ago > 0 - ? sprintf( - /* translators: %d: number of days. */ - _n( 'You started this form %d day ago', 'You started this form %d days ago', $days_ago, 'sureforms' ), - $days_ago - ) - : __( 'You started this form recently', 'sureforms' ); - - $sentence = sprintf( - /* translators: 1: "You started this form N days ago", 2: a complete clause, e.g. "the thank-you message is still the default". */ - __( '%1$s and haven\'t opened it since. It isn\'t collecting anything yet — %2$s.', 'sureforms' ), - $time_text, - $whats_left - ); + // The prompt only surfaces starter-template imports (see the meta gate), so + // the form was created for the user rather than by them. Kept generic — no + // per-step claim — so it is always accurate whatever the user has since + // changed, while the action buttons point to the specific things to finish. + $sentence = __( 'We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions.', 'sureforms' ); ob_start(); ?> @@ -2617,8 +2638,8 @@ private static function build_thankyou_notice_markup( $form ) { <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> <p class="srfm-thankyou-notice__actions"> <a class="button button-primary srfm-ty-edit-form" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> + <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the Thank You message', 'sureforms' ); ?></a> <a class="button srfm-ty-set-replies" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> - <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the thank-you message', 'sureforms' ); ?></a> </p> <?php return (string) ob_get_clean(); diff --git a/inc/gutenberg-hooks.php b/inc/gutenberg-hooks.php index 72786c049..38e92b058 100644 --- a/inc/gutenberg-hooks.php +++ b/inc/gutenberg-hooks.php @@ -150,6 +150,17 @@ public function form_editor_screen_assets() { wp_enqueue_script( SRFM_SLUG . $form_editor_script, SRFM_URL . 'assets/build/formEditor.js', $script_info['dependencies'], $script_info['version'], true ); wp_localize_script( SRFM_SLUG . $form_editor_script, 'scIcons', [ 'path' => SRFM_URL . 'assets/build/icon-assets' ] ); + // Deep-link (#3030): the "Finish setting up" Thank You notice CTA opens this + // editor with ?srfm_focus=… to auto-open a settings tab. Gutenberg strips + // unrecognised query args client-side before the editor bundle can read them, + // so surface the value from the server — where it is never stripped — as a + // global the bundle reads at evaluation time. Validated to a known allowlist. + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only deep-link hint on an authenticated editor screen; no state change. + $srfm_focus = isset( $_GET['srfm_focus'] ) ? sanitize_key( wp_unslash( $_GET['srfm_focus'] ) ) : ''; + if ( in_array( $srfm_focus, [ 'thankyou', 'notifications' ], true ) ) { + wp_add_inline_script( SRFM_SLUG . $form_editor_script, 'window.srfmDeepLinkFocus = ' . wp_json_encode( $srfm_focus ) . ';', 'before' ); + } + // Enqueue the code editor for the Custom CSS Editor in SureForms. wp_enqueue_code_editor( [ 'type' => 'text/css' ] ); wp_enqueue_script( 'wp-theme-plugin-editor' ); diff --git a/src/admin/single-form-settings/Editor.js b/src/admin/single-form-settings/Editor.js index 5aa7be11f..209948086 100644 --- a/src/admin/single-form-settings/Editor.js +++ b/src/admin/single-form-settings/Editor.js @@ -9,7 +9,12 @@ import { import { __ } from '@wordpress/i18n'; import { useState, useEffect, createRoot } from '@wordpress/element'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { + useSelect, + useDispatch, + select as dataSelect, + dispatch as dataDispatch, +} from '@wordpress/data'; import { store as editorStore, PluginDocumentSettingPanel, @@ -18,7 +23,10 @@ import { import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as preferencesStore } from '@wordpress/preferences'; -import GeneralSettings from './tabs/GeneralSettings.js'; +import GeneralSettings, { + srfmDeepLinkFocus, + SRFM_DEEP_LINK_TABS, +} from './tabs/GeneralSettings.js'; import StyleSettings from './tabs/StyleSettings.js'; import InspectorTabs from '@Components/inspector-tabs/InspectorTabs.js'; import InspectorTab, { @@ -76,6 +84,50 @@ const SureformsFormSpecificSettings = () => { const [ rootHtmlTag, setRootHtmlTag ] = useState( null ); const [ documentBody, setDocumentBody ] = useState( null ); + // Deep-link support (#3030): when the editor is opened with ?srfm_focus=…, + // make sure the settings sidebar is open. GeneralSettings — which hosts the + // Form Settings dialog and self-opens the target tab on mount — only renders + // while that sidebar is open, and it can be collapsed by user preference. This + // runs from the always-mounted plugin root so the deep-link works regardless + // of the user's saved sidebar state. + // + // Opening it once on mount isn't enough: an early open (before the editor has + // finished booting) is a no-op or gets reverted by the editor's preference + // restore — the same reason forcePanel's open doesn't stick. Re-assert on a + // short interval until the sidebar is open, then stop. The dispatch is made + // from a timer tick (outside the store's notification cycle, where it would be + // swallowed) so it actually takes effect. Bounded so a sidebar that can't open + // is never retried indefinitely; opening it is enough — GeneralSettings then + // mounts and self-opens the target tab (once). + useEffect( () => { + if ( + ! Object.prototype.hasOwnProperty.call( + SRFM_DEEP_LINK_TABS, + srfmDeepLinkFocus + ) + ) { + return undefined; + } + + let elapsed = 0; + const ensureOpen = setInterval( () => { + elapsed += 300; + const editPostStore = dataSelect( 'core/edit-post' ); + if ( editPostStore?.isEditorSidebarOpened() ) { + clearInterval( ensureOpen ); + return; + } + dataDispatch( 'core/edit-post' )?.openGeneralSidebar( + 'edit-post/document' + ); + if ( elapsed >= 6000 ) { + clearInterval( ensureOpen ); + } + }, 300 ); + + return () => clearInterval( ensureOpen ); + }, [] ); + useEffect( () => { let intervalId = null; let timeoutId = null; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index 930997f00..1e6c02ee0 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -4,7 +4,7 @@ import { useDeviceType } from '@Controls/getPreviewType'; import { ToggleControl } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; -import { useEffect, useRef, useState } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { applyFilters } from '@wordpress/hooks'; @@ -15,14 +15,29 @@ import { prepareBlockSlugs } from '@Utils/Helpers'; let prevMetaHash = ''; -// Capture the dashboard deep-link target (?srfm_focus=…) the moment this -// bundle evaluates — the block editor strips unrecognised query args from the -// URL shortly after it boots, so reading the param later (inside a mount -// effect) finds it already gone. Snapshotting it here, before Gutenberg's URL -// cleanup runs, is what makes the deep-link reliable. -const srfmDeepLinkFocus = new URLSearchParams( window.location.search ).get( - 'srfm_focus' -); +// The dashboard "Finish setting up" notice CTA opens the editor with +// ?srfm_focus=… to auto-open a settings tab. Gutenberg strips unrecognised query +// args client-side before this bundle can reliably read them, so PHP surfaces the +// value as `window.srfmDeepLinkFocus` (printed before this bundle) — read that +// first, falling back to the raw URL for safety. +export const srfmDeepLinkFocus = + ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || + new URLSearchParams( window.location.search ).get( 'srfm_focus' ); + +// One deep-link per page load, ever. Module-scoped so a later panel remount +// (switching to the Block tab and back, which unmounts/remounts this component) +// cannot re-fire the open and slam the dialog back over the user's work. +let srfmDeepLinkConsumed = false; + +// Maps the ?srfm_focus value to a Form Settings tab id. A plain object read +// through hasOwnProperty (never prototype members), so ?srfm_focus=constructor +// resolves to nothing rather than handing a function to setPopupTab. Exported so +// the always-mounted editor root (Editor.js) can open the settings sidebar for +// the same targets — GeneralSettings only mounts once that sidebar is open. +export const SRFM_DEEP_LINK_TABS = { + thankyou: 'form_confirmation', + notifications: 'email_notification', +}; function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -40,10 +55,6 @@ function GeneralSettings( props ) { const root = document.documentElement.querySelector( 'body' ); const [ isOpen, setOpen ] = useState( false ); const [ popupTab, setPopupTab ] = useState( false ); - // Mirrors `isOpen` for the deep-link poll below, which reads it from a - // long-lived interval closure that would otherwise see a stale value. - const isOpenRef = useRef( isOpen ); - isOpenRef.current = isOpen; const [ hasValidationErrors, setHasValidationErrors ] = useState( false ); const closeModal = () => { @@ -251,86 +262,41 @@ function GeneralSettings( props ) { }; }, [ sureformsKeys ] ); - // Deep-link support: open a specific form-settings panel when the editor is - // reached with ?srfm_focus=... — the dashboard "Finish setting up" card CTAs - // use this so "Set where replies go" lands on the OttoKit (Automations) - // screen, and "Edit the thank-you message" on Form Confirmation. The target - // is read from `srfmDeepLinkFocus`, snapshotted at bundle-eval time because - // the block editor strips the query arg from the URL before this effect runs. + // Deep-link support: open a specific Form Settings tab when the editor is + // reached with ?srfm_focus=... — the dashboard "Finish setting up" notice CTA + // uses this so "Edit the thank-you message" lands on Form Confirmation. The + // target is read from `srfmDeepLinkFocus`, snapshotted at bundle-eval time + // because the block editor strips the query arg from the URL before this + // effect runs. + // + // forcePanel() force-opens the Form Options panel on every editor load, so + // this component is reliably mounted here and the sibling listener effect + // above (declared first, so React registers it before this one runs) is in + // place to receive the event — a single synchronous dispatch cannot miss it, + // no polling needed. Consume-once via the module flag so a later panel + // remount does not reopen the dialog on top of the user's work. useEffect( () => { - const tabByFocus = { - ottokit: 'ottokit', - thankyou: 'form_confirmation', - notifications: 'email_notification', - }; - const tabId = tabByFocus[ srfmDeepLinkFocus ]; - - if ( ! tabId ) { - return undefined; + if ( srfmDeepLinkConsumed ) { + return; } - // Open the form-settings dialog on the target tab via the same window - // event the "Form Settings" popover uses. The editor mounts/remounts the - // settings panels during initial load and the listener re-registers on - // every meta change, so a single dispatch can miss it, and the Force UI - // dialog's opacity fade-in can stall when toggled amid that churn. Poll - // every 300ms: dispatch the open request until the dialog appears, then - // stop dispatching and just hold the overlay visible. - // - // Once it has opened, halt the poll the moment `isOpen` goes back to false - // — that is the user closing it (Esc / backdrop / ✕), which flips state on - // this same live mount. A load-time remount instead tears this effect down - // (clearing the interval) and re-runs it fresh on the new mount, so churn - // still reopens while a deliberate close stays closed. Give up after the - // load window if it never opened so the interval can't run indefinitely. - let elapsed = 0; - let opened = false; - let heldMs = 0; - const ensureOpen = setInterval( () => { - elapsed += 300; - - // Dialog is open on this mount: hold the overlay painted (the Force UI - // fade-in can stall amid the editor's load churn) for a short window, - // then stop — the fade settles within a second or two, so there is no - // need to keep polling for the dialog's whole open lifetime. - // - // NOTE: `.srfm-dialog-panel` / `.fixed.inset-0` are the Force UI Dialog - // overlay's own markup; if the library renames them this simply no-ops - // (the fade-stall workaround stops applying) rather than erroring. - if ( isOpenRef.current ) { - opened = true; - heldMs += 300; - const panel = document.querySelector( '.srfm-dialog-panel' ); - const overlay = panel?.closest( '.fixed.inset-0' ); - if ( overlay ) { - overlay.style.opacity = '1'; - } - if ( heldMs >= 2000 ) { - clearInterval( ensureOpen ); - } - return; - } - - // It was open and is now closed on this same live mount — the user - // dismissed it (✕ / Esc / backdrop). Stop; do not reopen. - if ( opened ) { - clearInterval( ensureOpen ); - return; - } - - // Not open yet — keep asking until the listener catches it. - window.dispatchEvent( - new CustomEvent( 'srfm-open-form-settings', { - detail: { tabId }, - } ) - ); + const tabId = Object.prototype.hasOwnProperty.call( + SRFM_DEEP_LINK_TABS, + srfmDeepLinkFocus + ) + ? SRFM_DEEP_LINK_TABS[ srfmDeepLinkFocus ] + : null; - if ( elapsed >= 12000 ) { - clearInterval( ensureOpen ); - } - }, 300 ); + if ( ! tabId ) { + return; + } - return () => clearInterval( ensureOpen ); + srfmDeepLinkConsumed = true; + window.dispatchEvent( + new CustomEvent( 'srfm-open-form-settings', { + detail: { tabId }, + } ) + ); }, [] ); return ( diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 82d216aaa..25e4988d9 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -937,10 +937,22 @@ public function test_is_sureforms_owned_notice_callback() { } /** - * The first-form-created flag resolves to a boolean. + * The first-form-created flag follows the stored timestamp option. */ public function test_is_first_form_created() { - $this->assertIsBool( Admin::is_first_form_created() ); + // No stored timestamp → first form not yet created. + Helper::update_srfm_option( 'first_form_created_at', false ); + $this->assertFalse( Admin::is_first_form_created() ); + + // A positive integer timestamp → first form has been created. + Helper::update_srfm_option( 'first_form_created_at', time() ); + $this->assertTrue( Admin::is_first_form_created() ); + + // A zero/invalid timestamp does not count as created. + Helper::update_srfm_option( 'first_form_created_at', 0 ); + $this->assertFalse( Admin::is_first_form_created() ); + + Helper::update_srfm_option( 'first_form_created_at', false ); } /** @@ -965,8 +977,8 @@ public function test_is_default_confirmation_message() { $default_message = \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message(); - // The shipped default message is detected as the default. - update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => $default_message ] ] ); + // The shipped default message on a "same page" confirmation is the default. + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'same page', 'message' => $default_message ] ] ); $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); // The same default with entities decoded — as a starter-template import can @@ -974,19 +986,24 @@ public function test_is_default_confirmation_message() { update_post_meta( $form_id, '_srfm_form_confirmation', - [ [ 'message' => html_entity_decode( $default_message, ENT_QUOTES, 'UTF-8' ) ] ] + [ [ 'confirmation_type' => 'same page', 'message' => html_entity_decode( $default_message, ENT_QUOTES, 'UTF-8' ) ] ] ); $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); + // A redirect confirmation never renders the message, so even the default + // string must NOT be flagged (it would otherwise nag with no way to clear). + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'different page', 'message' => $default_message ] ] ); + $this->assertFalse( Admin::is_default_confirmation_message( $form_id ) ); + // Any real edit to the message flips it to non-default (the auto-clear path). - update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => 'Thanks so much - we will be in touch!' ] ] ); + update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'same page', 'message' => 'Thanks so much - we will be in touch!' ] ] ); $this->assertFalse( Admin::is_default_confirmation_message( $form_id ) ); wp_delete_post( $form_id, true ); } /** - * A form with no email notification has no reply destination (#3030). + * A form with no enabled email notification has no reply destination (#3030). */ public function test_form_has_reply_destination() { $this->assertFalse( Admin::form_has_reply_destination( 0 ) ); @@ -1004,9 +1021,6 @@ public function test_form_has_reply_destination() { ] ); - // No notification → no reply destination. - $this->assertFalse( Admin::form_has_reply_destination( $form_id ) ); - // Enabled notification with a recipient → has a destination. update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => true, 'email_to' => 'admin@example.com' ] ] ); $this->assertTrue( Admin::form_has_reply_destination( $form_id ) ); @@ -1015,15 +1029,47 @@ public function test_form_has_reply_destination() { update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => false, 'email_to' => 'admin@example.com' ] ] ); $this->assertFalse( Admin::form_has_reply_destination( $form_id ) ); + // An enabled notification with no recipient does not count. + update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => true, 'email_to' => '' ] ] ); + $this->assertFalse( Admin::form_has_reply_destination( $form_id ) ); + wp_delete_post( $form_id, true ); } + /** + * The notice markup renders the title, message and all three CTAs (#3030). + */ + public function test_thankyou_notice_markup_renders_ctas() { + $build = new \ReflectionMethod( Admin::class, 'build_thankyou_notice_markup' ); + $build->setAccessible( true ); + + $markup = $build->invoke( + null, + [ + 'title' => 'Sample Form', + 'days_ago' => 2, + 'steps' => [ 'replies' => true, 'thankyou' => true ], + 'edit_url' => 'https://example.com/e', + 'replies_url' => 'https://example.com/r', + 'thankyou_url' => 'https://example.com/t', + ] + ); + + // Title carries the form name; body is the (accurate, step-agnostic) message. + $this->assertStringContainsString( 'Sample Form', $markup ); + $this->assertStringContainsString( 'already created this form for you', $markup ); + + // All three CTAs, each with its tracking class and deep-link target. + $this->assertStringContainsString( 'srfm-ty-edit-form', $markup ); + $this->assertStringContainsString( 'srfm-ty-set-replies', $markup ); + $this->assertStringContainsString( 'srfm-ty-edit-thankyou', $markup ); + $this->assertStringContainsString( 'https://example.com/t', $markup ); + } + /** * The Thank You prompt query always returns an array (#3030). */ public function test_get_thankyou_prompt_forms() { - $this->assertIsArray( Admin::get_thankyou_prompt_forms() ); - if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); } @@ -1044,21 +1090,25 @@ public function test_get_thankyou_prompt_forms() { // Starter-template import still on the default message → targeted. $imported = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Imported TY' ] ); - update_post_meta( $imported, '_srfm_form_confirmation', [ [ 'message' => $default_message ] ] ); - update_post_meta( $imported, '_astra_sites_imported_post', 1 ); + update_post_meta( $imported, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'same page', 'message' => $default_message ] ] ); + update_post_meta( $imported, Admin::ASTRA_SITES_IMPORT_META, 1 ); // Same default message but NOT an Astra Sites import → excluded by the gate. $plain = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Plain TY' ] ); - update_post_meta( $plain, '_srfm_form_confirmation', [ [ 'message' => $default_message ] ] ); + update_post_meta( $plain, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'same page', 'message' => $default_message ] ] ); // Drive the uncached builder to bypass the request-memoized cache. $compute = new \ReflectionMethod( Admin::class, 'compute_thankyou_prompt_forms' ); $compute->setAccessible( true ); - $ids = wp_list_pluck( $compute->invoke( null ), 'id' ); + $prompts = $compute->invoke( null ); + $ids = wp_list_pluck( $prompts, 'id' ); $this->assertContains( $imported, $ids, 'An Astra Sites imported form on the default message must be targeted.' ); $this->assertNotContains( $plain, $ids, 'A non-imported form must not be targeted.' ); + // The surfaced payload carries the deep-link CTA target (?srfm_focus=thankyou). + $this->assertStringContainsString( 'srfm_focus=thankyou', (string) ( $prompts[0]['thankyou_url'] ?? '' ) ); + wp_delete_post( $imported, true ); wp_delete_post( $plain, true ); wp_set_current_user( 0 ); @@ -1098,10 +1148,31 @@ public function test_print_thankyou_notice_styles() { } /** - * The Thank You notice click-tracking enqueue method exists (#3030). + * The Thank You notice click-tracking enqueues a delegated dismiss beacon (#3030). + * + * Regression guard: the ✕ is injected by core on DOMContentLoaded, after this + * inline script parses, so it must be caught by delegation from the wrapper — + * a direct .notice-dismiss lookup would bind to nothing. */ public function test_enqueue_thankyou_notice_tracking() { $admin = Admin::get_instance(); - $this->assertTrue( method_exists( $admin, 'enqueue_thankyou_notice_tracking' ) ); + + wp_dequeue_script( 'srfm-thankyou-notice-track' ); + wp_deregister_script( 'srfm-thankyou-notice-track' ); + + $admin->enqueue_thankyou_notice_tracking(); + + $this->assertTrue( wp_script_is( 'srfm-thankyou-notice-track', 'enqueued' ) ); + + $after = wp_scripts()->get_data( 'srfm-thankyou-notice-track', 'after' ); + $body = is_array( $after ) ? implode( "\n", $after ) : (string) $after; + + // Dismissal is delegated from the wrapper, not bound to .notice-dismiss. + $this->assertStringContainsString( "addEventListener( 'click'", $body ); + $this->assertStringContainsString( "closest( '.notice-dismiss' )", $body ); + $this->assertStringContainsString( 'dismissed', $body ); + + wp_dequeue_script( 'srfm-thankyou-notice-track' ); + wp_deregister_script( 'srfm-thankyou-notice-track' ); } } From 30b01e2c3e41854af5312854e081f0e51ef24952 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 11:50:41 +0530 Subject: [PATCH 35/65] Reword the setup widget subtitle to a clearer call to action (#3031) 'Customize your form to get it ready for real submissions:' reads as a direct instruction rather than framing the steps as optional busywork. --- admin/admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/admin.php b/admin/admin.php index 7bdaac7c4..a2c52ecaf 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2437,7 +2437,7 @@ public function render_form_setup_widget() { ?> <div class="srfm-setup-checklist" id="srfm-setup-checklist"> <p class="srfm-setup-checklist__title"><?php echo esc_html( $heading ); ?></p> - <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'A few optional steps to get your form ready for real submissions:', 'sureforms' ); ?></p> + <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'Customize your form to get it ready for real submissions:', 'sureforms' ); ?></p> <ul class="srfm-setup-checklist__steps"> <?php foreach ( $rows as $row ) { ?> From acad5caddd3c102d1b765cacd344138038386380 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 12:02:20 +0530 Subject: [PATCH 36/65] Add a view-form link to the setup widget title and clarify the first step (#3031) The widget title now carries an external-link icon that opens the form's instant-form page in a new tab, and the first step reads 'Review or edit your form' rather than 'Review the fields and publish'. --- admin/admin.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index a2c52ecaf..c9b17eba5 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -336,6 +336,9 @@ public static function get_form_setup_card() { // Deep-links to the email-notification panel where supported; falls // back to opening the editor when the focus handler isn't present. 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + // Front-end instant-form page; admins can always view it (the + // non-privileged redirect in Post_Types exempts them). + 'view_url' => (string) get_permalink( $form_id ), 'shortcode' => sprintf( '[sureforms id="%d"]', $form_id ), ]; @@ -2413,7 +2416,7 @@ public function render_form_setup_widget() { // Optional next-steps — always offered, their completion is not computed. $rows = [ [ - 'label' => __( 'Review the fields and publish', 'sureforms' ), + 'label' => __( 'Review or edit your form', 'sureforms' ), 'cta' => __( 'Edit form', 'sureforms' ), 'url' => $card['edit_url'], ], @@ -2436,7 +2439,14 @@ public function render_form_setup_widget() { ); ?> <div class="srfm-setup-checklist" id="srfm-setup-checklist"> - <p class="srfm-setup-checklist__title"><?php echo esc_html( $heading ); ?></p> + <p class="srfm-setup-checklist__title"> + <?php echo esc_html( $heading ); ?> + <?php if ( ! empty( $card['view_url'] ) ) { ?> + <a class="srfm-setup-checklist__view" href="<?php echo esc_url( $card['view_url'] ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo esc_attr( sprintf( /* translators: %s: form title. */ __( 'View %s (opens in a new tab)', 'sureforms' ), $card['title'] ) ); ?>"> + <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg> + </a> + <?php } ?> + </p> <p class="srfm-setup-checklist__subtitle"><?php esc_html_e( 'Customize your form to get it ready for real submissions:', 'sureforms' ); ?></p> <ul class="srfm-setup-checklist__steps"> @@ -2490,6 +2500,8 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { #srfm_form_setup_checklist .inside { margin: 0; padding: 0; } .srfm-setup-checklist { padding: 12px 16px 16px; } .srfm-setup-checklist__title { margin: 0 0 4px; font-size: 15px; font-weight: 600; color: #1e1e1e; } +.srfm-setup-checklist__view { display: inline-flex; align-items: center; margin-left: 6px; color: #d54e21; vertical-align: middle; } +.srfm-setup-checklist__view:hover, .srfm-setup-checklist__view:focus { color: #b83c14; } .srfm-setup-checklist__subtitle { margin: 0 0 12px; color: #646970; font-size: 13px; } .srfm-setup-checklist__steps { margin: 0; padding: 0; list-style: none; } .srfm-setup-checklist__step { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: 8px; } From dc90f633a7479663e606d5e68dd5a357c311c4ab Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 12:11:13 +0530 Subject: [PATCH 37/65] Reorder setup widget steps and drop the embed step (#3031) Steps are now Review or edit form -> Personalize the Thank You message (deep-links to Form Confirmation) -> Choose who gets notified (Set up email, deep-links to Email Notification, last). Removed the 'Put the form on a page' embed step along with its embed box, copy script, and the card shortcode. --- admin/admin.php | 81 ++++++++++--------------------------------------- 1 file changed, 16 insertions(+), 65 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index c9b17eba5..6d2dcfbd5 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -330,16 +330,17 @@ public static function get_form_setup_card() { // The steps are shown as optional next-steps — their completion is not // computed, so the widget simply lists the actions the owner can take. $cache = [ - 'id' => $form_id, - 'title' => get_the_title( $form_id ), - 'edit_url' => $edit_link, + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'edit_url' => $edit_link, // Deep-links to the email-notification panel where supported; falls // back to opening the editor when the focus handler isn't present. - 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + // Deep-links to the Form Confirmation panel (the Thank You message). + 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), // Front-end instant-form page; admins can always view it (the // non-privileged redirect in Post_Types exempts them). - 'view_url' => (string) get_permalink( $form_id ), - 'shortcode' => sprintf( '[sureforms id="%d"]', $form_id ), + 'view_url' => (string) get_permalink( $form_id ), ]; return $cache; @@ -2420,16 +2421,16 @@ public function render_form_setup_widget() { 'cta' => __( 'Edit form', 'sureforms' ), 'url' => $card['edit_url'], ], + [ + 'label' => __( 'Personalize the Thank You message', 'sureforms' ), + 'cta' => __( 'Edit message', 'sureforms' ), + 'url' => $card['thankyou_url'], + ], [ 'label' => __( 'Choose who gets notified of new replies', 'sureforms' ), 'cta' => __( 'Set up email', 'sureforms' ), 'url' => $card['email_url'], ], - [ - 'label' => __( 'Put the form on a page', 'sureforms' ), - 'cta' => __( 'Get embed code', 'sureforms' ), - 'is_embed' => true, - ], ]; $heading = sprintf( @@ -2453,20 +2454,11 @@ public function render_form_setup_widget() { <?php foreach ( $rows as $row ) { ?> <li class="srfm-setup-checklist__step"> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> - <?php if ( ! empty( $row['is_embed'] ) ) { ?> - <button type="button" class="srfm-setup-checklist__cta" id="srfm-setup-checklist-embed"><?php echo esc_html( $row['cta'] ); ?></button> - <?php } else { ?> - <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> - <?php } ?> + <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> </li> <?php } ?> </ul> - <div class="srfm-setup-checklist__embed" id="srfm-setup-checklist-embed-box"> - <input type="text" readonly class="srfm-setup-checklist__embed-input" id="srfm-setup-checklist-embed-input" value="<?php echo esc_attr( $card['shortcode'] ); ?>" /> - <button type="button" class="button srfm-setup-checklist__embed-copy" id="srfm-setup-checklist-embed-copy"><?php esc_html_e( 'Copy', 'sureforms' ); ?></button> - </div> - <button type="button" class="srfm-setup-checklist__snooze" id="srfm-setup-checklist-snooze"><?php esc_html_e( 'Remind me in two weeks', 'sureforms' ); ?></button> </div> <?php @@ -2510,9 +2502,6 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { .srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } .srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__cta:hover { color: #b83c14; } -.srfm-setup-checklist__embed { display: none; gap: 8px; margin: 10px 12px 0; } -.srfm-setup-checklist__embed.is-visible { display: flex; } -.srfm-setup-checklist__embed-input { flex: 1 1 auto; } .srfm-setup-checklist__snooze { display: inline-block; margin-top: 14px; border: 0; background: transparent; padding: 0; font-size: 13px; color: #646970; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__snooze:hover { color: #1e1e1e; } CSS; @@ -2528,11 +2517,9 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { 'srfm-setup-checklist-widget', 'srfmSetupChecklist', [ - 'restUrl' => esc_url_raw( rest_url( 'sureforms/v1/dismiss-form-setup-card' ) ), - 'nonce' => wp_create_nonce( 'wp_rest' ), - 'formId' => $card['id'], - 'copyTxt' => __( 'Copy', 'sureforms' ), - 'copiedTxt' => __( 'Copied', 'sureforms' ), + 'restUrl' => esc_url_raw( rest_url( 'sureforms/v1/dismiss-form-setup-card' ) ), + 'nonce' => wp_create_nonce( 'wp_rest' ), + 'formId' => $card['id'], ] ); @@ -2565,42 +2552,6 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { removeWidget(); } ); } - - const embedInput = document.getElementById( 'srfm-setup-checklist-embed-input' ); - const embedBtn = document.getElementById( 'srfm-setup-checklist-embed' ); - const embedBox = document.getElementById( 'srfm-setup-checklist-embed-box' ); - if ( embedBtn && embedBox ) { - embedBtn.addEventListener( 'click', function () { - const visible = embedBox.classList.toggle( 'is-visible' ); - if ( visible && embedInput ) { - embedInput.focus(); - embedInput.select(); - } - } ); - } - - const copyBtn = document.getElementById( 'srfm-setup-checklist-embed-copy' ); - if ( copyBtn && embedInput ) { - copyBtn.addEventListener( 'click', function () { - embedInput.focus(); - embedInput.select(); - const done = function () { - copyBtn.textContent = cfg.copiedTxt; - setTimeout( function () { - copyBtn.textContent = cfg.copyTxt; - }, 2000 ); - }; - if ( navigator.clipboard && navigator.clipboard.writeText ) { - navigator.clipboard.writeText( embedInput.value ).then( done ).catch( function () { - document.execCommand( 'copy' ); - done(); - } ); - } else { - document.execCommand( 'copy' ); - done(); - } - } ); - } }() ); JS; From 95434a761f465c5ad1bfea0f88ab9f882abe0df9 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 12:18:45 +0530 Subject: [PATCH 38/65] Remove the blue focus ring on the setup widget links (#3031) Drop WP's blue box-shadow/outline on the widget's links; keyboard focus keeps an accessible on-brand orange outline instead of blue. --- admin/admin.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/admin/admin.php b/admin/admin.php index 6d2dcfbd5..89f0b983e 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2502,6 +2502,9 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { .srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } .srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__cta:hover { color: #b83c14; } +/* Drop WP's blue focus ring on the widget's links; keep an accessible, on-brand keyboard outline. */ +.srfm-setup-checklist a:focus { outline: none; box-shadow: none; } +.srfm-setup-checklist a:focus-visible { outline: 2px solid #d54e21; outline-offset: 2px; box-shadow: none; } .srfm-setup-checklist__snooze { display: inline-block; margin-top: 14px; border: 0; background: transparent; padding: 0; font-size: 13px; color: #646970; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__snooze:hover { color: #1e1e1e; } CSS; From c39fb5eec4c2fd66ee662ea5db6f81cf6e6a9a57 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 12:32:48 +0530 Subject: [PATCH 39/65] Add interaction analytics to the form setup widget (#3031) Each CTA (Edit form, Edit message, Set up email), the view-form icon, and the snooze now beacon a form_setup_widget_* event through the existing setup-card REST endpoint; the fetch uses keepalive so it survives the CTA navigation. The endpoint records the event (each carries a date via BSF_Analytics_Events::track) and only 'snooze' writes the per-user snooze meta. Strengthened the handler test to cover the snooze-only branch. --- admin/admin.php | 52 +++++++++++++++++++++++++++------ tests/unit/admin/test-admin.php | 49 +++++++++++++++++++++++++++++-- 2 files changed, 90 insertions(+), 11 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 89f0b983e..1bb84c5e8 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -466,13 +466,13 @@ public static function is_default_confirmation_message( $form_id ) { } /** - * REST handler: snooze the "Finish setting up" widget for 14 days (#3031). + * REST handler: record a "Finish setting up" widget interaction (#3031). * - * The snooze is stored per-user, so "Remind me in two weeks" hides the whole - * widget rather than only the form currently shown. The request still carries - * the displayed form id: capability is re-checked against it here — beyond the - * route's generic permission callback — so only a genuine editor of that form - * can set the snooze. + * Tracks the clicked action as an analytics event and, for "snooze", stores a + * per-user 14-day snooze so "Remind me in two weeks" hides the whole widget + * rather than only the form currently shown. The request carries the displayed + * form id: capability is re-checked against it here — beyond the route's generic + * permission callback — so only a genuine editor of that form can act. * * @param \WP_REST_Request<array<string,mixed>> $request Request. * @@ -486,7 +486,27 @@ public function dismiss_form_setup_card( $request ) { return new \WP_Error( 'srfm_setup_card_forbidden', __( 'You are not allowed to update this prompt.', 'sureforms' ), [ 'status' => 403 ] ); } - update_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, time() + ( 14 * DAY_IN_SECONDS ) ); + $action = sanitize_key( (string) $request->get_param( 'action' ) ); + + // Interaction analytics for the setup widget (#3031). Each event carries a + // date automatically (see BSF_Analytics_Events::track()) and dedupes per + // event name, matching the sibling notice's telemetry. + $events = [ + 'edit_form' => 'form_setup_widget_edit_form', + 'edit_thankyou' => 'form_setup_widget_edit_thankyou', + 'set_up_email' => 'form_setup_widget_set_up_email', + 'view_form' => 'form_setup_widget_view_form', + 'snooze' => 'form_setup_widget_snooze', + ]; + + if ( isset( $events[ $action ] ) ) { + Analytics::events()->track( $events[ $action ], (string) $form_id ); + } + + // "Remind me in two weeks" hides the whole widget per-user for 14 days. + if ( 'snooze' === $action ) { + update_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, time() + ( 14 * DAY_IN_SECONDS ) ); + } return new \WP_REST_Response( [ 'success' => true ], 200 ); } @@ -2415,21 +2435,25 @@ public function render_form_setup_widget() { } // Optional next-steps — always offered, their completion is not computed. + // 'event' is the analytics action key beaconed on click (see the widget JS). $rows = [ [ 'label' => __( 'Review or edit your form', 'sureforms' ), 'cta' => __( 'Edit form', 'sureforms' ), 'url' => $card['edit_url'], + 'event' => 'edit_form', ], [ 'label' => __( 'Personalize the Thank You message', 'sureforms' ), 'cta' => __( 'Edit message', 'sureforms' ), 'url' => $card['thankyou_url'], + 'event' => 'edit_thankyou', ], [ 'label' => __( 'Choose who gets notified of new replies', 'sureforms' ), 'cta' => __( 'Set up email', 'sureforms' ), 'url' => $card['email_url'], + 'event' => 'set_up_email', ], ]; @@ -2443,7 +2467,7 @@ public function render_form_setup_widget() { <p class="srfm-setup-checklist__title"> <?php echo esc_html( $heading ); ?> <?php if ( ! empty( $card['view_url'] ) ) { ?> - <a class="srfm-setup-checklist__view" href="<?php echo esc_url( $card['view_url'] ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo esc_attr( sprintf( /* translators: %s: form title. */ __( 'View %s (opens in a new tab)', 'sureforms' ), $card['title'] ) ); ?>"> + <a class="srfm-setup-checklist__view" data-srfm-event="view_form" href="<?php echo esc_url( $card['view_url'] ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo esc_attr( sprintf( /* translators: %s: form title. */ __( 'View %s (opens in a new tab)', 'sureforms' ), $card['title'] ) ); ?>"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg> </a> <?php } ?> @@ -2454,7 +2478,7 @@ public function render_form_setup_widget() { <?php foreach ( $rows as $row ) { ?> <li class="srfm-setup-checklist__step"> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> - <a class="srfm-setup-checklist__cta" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> + <a class="srfm-setup-checklist__cta" data-srfm-event="<?php echo esc_attr( $row['event'] ); ?>" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> </li> <?php } ?> </ul> @@ -2538,6 +2562,7 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { fetch( cfg.restUrl, { method: 'POST', credentials: 'same-origin', + keepalive: true, headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': cfg.nonce }, body: JSON.stringify( { form_id: cfg.formId, action: action } ), } ).catch( function () {} ); @@ -2548,6 +2573,15 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { ( box || widget ).remove(); }; + // Beacon the CTA / view-form clicks for analytics. keepalive on the fetch lets + // the request finish even though the CTA immediately navigates away. + widget.addEventListener( 'click', function ( e ) { + const target = e.target.closest( '[data-srfm-event]' ); + if ( target ) { + persist( target.getAttribute( 'data-srfm-event' ) ); + } + } ); + const snoozeBtn = document.getElementById( 'srfm-setup-checklist-snooze' ); if ( snoozeBtn ) { snoozeBtn.addEventListener( 'click', function () { diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 559f80608..3309ddf40 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -1019,10 +1019,55 @@ public function test_get_form_setup_card() { } /** - * The setup-card REST handler is registered on the Admin instance (#3031). + * The setup-card REST handler snoozes only on the "snooze" action (#3031). + * + * A CTA/analytics action ("edit_form") records telemetry but must not hide the + * widget; only "snooze" writes the per-user snooze meta. */ public function test_dismiss_form_setup_card() { - $this->assertTrue( method_exists( Admin::get_instance(), 'dismiss_form_setup_card' ) ); + $admin = Admin::get_instance(); + $this->assertTrue( method_exists( $admin, 'dismiss_form_setup_card' ) ); + + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! class_exists( '\WP_REST_Request' ) ) { + $this->markTestSkipped( 'REST/CPT environment not available' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $user = wp_insert_user( + [ + 'user_login' => 'srfm_widget_admin_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_widget_admin_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $user ) ? 0 : (int) $user ); + + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Widget form' ] ); + $meta_key = Admin::SETUP_WIDGET_SNOOZE_USER_META; + + $call = static function ( $action ) use ( $admin, $form_id ) { + $req = new \WP_REST_Request( 'POST', '/sureforms/v1/dismiss-form-setup-card' ); + $req->set_param( 'form_id', $form_id ); + $req->set_param( 'action', $action ); + return $admin->dismiss_form_setup_card( $req ); + }; + + // A CTA action succeeds but does NOT snooze the widget. + delete_user_meta( (int) $user, $meta_key ); + $res = $call( 'edit_form' ); + $this->assertFalse( is_wp_error( $res ), 'A valid CTA action should not error.' ); + $this->assertSame( '', (string) get_user_meta( (int) $user, $meta_key, true ), 'A CTA action must not set the snooze meta.' ); + + // The snooze action stores a future snooze timestamp. + $call( 'snooze' ); + $this->assertGreaterThan( time(), (int) get_user_meta( (int) $user, $meta_key, true ), 'Snooze must store a future timestamp.' ); + + wp_delete_post( $form_id, true ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $user ) ) { + wp_delete_user( (int) $user ); + } } /** From 5a869c0bb1fd26bc743a66ff43b2dd53e171749e Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 13:09:46 +0530 Subject: [PATCH 40/65] Open the setup widget CTAs in a new tab (#3031) Edit form, Edit message, and Set up email now open in a new tab so the dashboard stays put, matching the view-form icon. --- admin/admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/admin.php b/admin/admin.php index 1bb84c5e8..4e0d22cef 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2478,7 +2478,7 @@ public function render_form_setup_widget() { <?php foreach ( $rows as $row ) { ?> <li class="srfm-setup-checklist__step"> <span class="srfm-setup-checklist__label"><?php echo esc_html( $row['label'] ); ?></span> - <a class="srfm-setup-checklist__cta" data-srfm-event="<?php echo esc_attr( $row['event'] ); ?>" href="<?php echo esc_url( $row['url'] ); ?>"><?php echo esc_html( $row['cta'] ); ?></a> + <a class="srfm-setup-checklist__cta" data-srfm-event="<?php echo esc_attr( $row['event'] ); ?>" href="<?php echo esc_url( $row['url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $row['cta'] ); ?></a> </li> <?php } ?> </ul> From b1361b921d02883a05f03b4fce1da9ac7ac783e4 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 13:15:16 +0530 Subject: [PATCH 41/65] Open the Thank You notice CTAs in a new tab (#3030) Edit form, Edit the Thank You message, and Set where replies go now open in a new tab (target=_blank rel=noopener), so the admin page the notice sits on stays put. target/rel survive the library's wp_kses_post on the notice message. Interaction analytics (thankyou_notice_* on each CTA and the dismiss) already ship via the notice-response beacon; the new tab makes that beacon even more reliable since the current page no longer navigates. --- admin/admin.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 7ed46524b..130755308 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2637,9 +2637,9 @@ private static function build_thankyou_notice_markup( $form ) { </p> <p class="srfm-thankyou-notice__text"><?php echo esc_html( $sentence ); ?></p> <p class="srfm-thankyou-notice__actions"> - <a class="button button-primary srfm-ty-edit-form" href="<?php echo esc_url( $form['edit_url'] ); ?>"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> - <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>"><?php esc_html_e( 'Edit the Thank You message', 'sureforms' ); ?></a> - <a class="button srfm-ty-set-replies" href="<?php echo esc_url( $form['replies_url'] ); ?>"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> + <a class="button button-primary srfm-ty-edit-form" href="<?php echo esc_url( $form['edit_url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit form', 'sureforms' ); ?></a> + <a class="button srfm-ty-edit-thankyou" href="<?php echo esc_url( $form['thankyou_url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Edit the Thank You message', 'sureforms' ); ?></a> + <a class="button srfm-ty-set-replies" href="<?php echo esc_url( $form['replies_url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Set where replies go', 'sureforms' ); ?></a> </p> <?php return (string) ob_get_clean(); From 55322043c330fb030cfcc8da735586baac0b8efa Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 13:28:52 +0530 Subject: [PATCH 42/65] Open the first email notification directly from the replies deep-link (#3030) Arriving via 'Set where replies go' (?srfm_focus=notifications) now jumps straight into the first notification's editor instead of the list, so the user lands where they set the reply destination. One-shot per page load; no-op when reached any other way or when the form has no notifications yet. --- .../email-settings/EmailNotification.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/admin/single-form-settings/components/email-settings/EmailNotification.js b/src/admin/single-form-settings/components/email-settings/EmailNotification.js index 739224daf..40aecf794 100644 --- a/src/admin/single-form-settings/components/email-settings/EmailNotification.js +++ b/src/admin/single-form-settings/components/email-settings/EmailNotification.js @@ -17,6 +17,12 @@ import TabContentWrapper from '@Components/tab-content-wrapper'; import { notify } from '@Utils/notify'; import { applyFilters, doAction } from '@wordpress/hooks'; +// One-shot guard: when the editor is reached via the "Set where replies go" +// deep-link (?srfm_focus=notifications, surfaced by PHP as window.srfmDeepLinkFocus), +// jump straight into the first notification's editor instead of landing on the +// list. Module-scoped so a later tab remount does not reopen it. +let srfmRepliesDeepLinkConsumed = false; + const CustomButton = forwardRef( ( { @@ -206,6 +212,27 @@ const EmailNotification = ( { }, ]; + // Deep-link: open the first notification's editor directly when arriving via + // "Set where replies go". Runs once data is available, then never again. + useEffect( () => { + if ( srfmRepliesDeepLinkConsumed ) { + return; + } + if ( + typeof window === 'undefined' || + window.srfmDeepLinkFocus !== 'notifications' + ) { + return; + } + if ( + Array.isArray( emailNotificationData ) && + emailNotificationData.length > 0 + ) { + srfmRepliesDeepLinkConsumed = true; + handleEdit( emailNotificationData[ 0 ] ); + } + }, [ emailNotificationData ] ); + useEffect( () => { function handleClickOutside() { setIsPopup( null ); From 8bd41dea91afd9da5beb9d138f2e503ece09ffc0 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 13:56:33 +0530 Subject: [PATCH 43/65] Keep widget links on-brand when visited and open first notification from Set up email (#3031) - Visited widget links stay brand-orange; WP admin's a:visited was turning them blue once opened. - 'Set up email' (?srfm_focus=notifications) now jumps straight into the first notification's editor instead of the list. Reads the deep-link from the PHP global when present, else the URL snapshot, so it works on this branch's poll-based deep-link and stays compatible with the robust version on #3030. --- admin/admin.php | 3 ++ .../email-settings/EmailNotification.js | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/admin/admin.php b/admin/admin.php index 4e0d22cef..a0f39605c 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -2526,6 +2526,9 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { .srfm-setup-checklist__label { flex: 1 1 auto; font-size: 14px; color: #1e1e1e; } .srfm-setup-checklist__cta { margin-left: auto; border: 0; background: transparent; padding: 0; font-size: 14px; font-weight: 600; color: #d54e21; text-decoration: underline; cursor: pointer; } .srfm-setup-checklist__cta:hover { color: #b83c14; } +/* Keep visited links on-brand — WP admin's a:visited would otherwise turn them blue. */ +.srfm-setup-checklist a:visited { color: #d54e21; } +.srfm-setup-checklist a:visited:hover, .srfm-setup-checklist a:visited:focus { color: #b83c14; } /* Drop WP's blue focus ring on the widget's links; keep an accessible, on-brand keyboard outline. */ .srfm-setup-checklist a:focus { outline: none; box-shadow: none; } .srfm-setup-checklist a:focus-visible { outline: 2px solid #d54e21; outline-offset: 2px; box-shadow: none; } diff --git a/src/admin/single-form-settings/components/email-settings/EmailNotification.js b/src/admin/single-form-settings/components/email-settings/EmailNotification.js index 739224daf..a58adeacb 100644 --- a/src/admin/single-form-settings/components/email-settings/EmailNotification.js +++ b/src/admin/single-form-settings/components/email-settings/EmailNotification.js @@ -17,6 +17,17 @@ import TabContentWrapper from '@Components/tab-content-wrapper'; import { notify } from '@Utils/notify'; import { applyFilters, doAction } from '@wordpress/hooks'; +// Deep-link target (?srfm_focus=…). Prefer the PHP-surfaced global when present +// (reliable), else the URL snapshot captured at bundle-eval — before Gutenberg +// strips the query arg. Used to jump straight into the first notification when +// the editor is reached via "Set up email" / "Set where replies go". +const srfmRepliesDeepLinkFocus = + ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || + new URLSearchParams( window.location.search ).get( 'srfm_focus' ); + +// One-shot guard so a later tab remount does not reopen the editor. +let srfmRepliesDeepLinkConsumed = false; + const CustomButton = forwardRef( ( { @@ -206,6 +217,24 @@ const EmailNotification = ( { }, ]; + // Deep-link: open the first notification's editor directly when arriving via + // "Set up email" / "Set where replies go". Runs once data is available. + useEffect( () => { + if ( srfmRepliesDeepLinkConsumed ) { + return; + } + if ( srfmRepliesDeepLinkFocus !== 'notifications' ) { + return; + } + if ( + Array.isArray( emailNotificationData ) && + emailNotificationData.length > 0 + ) { + srfmRepliesDeepLinkConsumed = true; + handleEdit( emailNotificationData[ 0 ] ); + } + }, [ emailNotificationData ] ); + useEffect( () => { function handleClickOutside() { setIsPopup( null ); From 64a83fa3b4ddc4805fa264aef762eceaef28b0ec Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 14:35:09 +0530 Subject: [PATCH 44/65] Add a Form shortcut to the admin bar '+ New' menu (#3026) Adds a 'Form' node under the toolbar '+ New' menu linking to post-new.php?post_type=sureforms_form, matching how core post types appear there. Done via an admin_bar_menu callback rather than show_in_admin_bar=true so it does not also make core register a second front-end 'Edit' node alongside the existing custom one (add_edit_form_to_admin_bar_menu). Gated on the form CPT's own create_posts capability (manage_options for this CPT), so it only shows for users who can create a form. --- inc/post-types.php | 37 +++++++++++++++++++ tests/unit/inc/test-post-types.php | 59 ++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/inc/post-types.php b/inc/post-types.php index 5c1a35303..ddeda6981 100644 --- a/inc/post-types.php +++ b/inc/post-types.php @@ -43,6 +43,7 @@ public function __construct() { add_filter( 'rest_prepare_sureforms_form', [ $this, 'sureforms_normalize_meta_for_rest' ], 10, 2 ); add_action( 'admin_bar_menu', [ $this, 'add_edit_form_to_admin_bar_menu' ], 100 ); + add_action( 'admin_bar_menu', [ $this, 'add_new_form_to_admin_bar_menu' ], 100 ); } /** @@ -103,6 +104,42 @@ public function add_edit_form_to_admin_bar_menu( $wp_admin_bar ) { ); } + /** + * Add a "Form" shortcut to the admin bar "+ New" menu (#3026). + * + * Mirrors how core post types appear under "+ New", but added manually rather + * than via `show_in_admin_bar` so it does not also register a second front-end + * "Edit" node alongside the custom one in add_edit_form_to_admin_bar_menu(). + * Gated on the form CPT's own create capability (manage_options for this CPT), + * so it only shows for users who can actually create a form. + * + * @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance. + * @since x.x.x + * @return void + */ + public function add_new_form_to_admin_bar_menu( $wp_admin_bar ) { + if ( ! is_admin_bar_showing() || ! $wp_admin_bar instanceof WP_Admin_Bar ) { + return; + } + + $post_type = get_post_type_object( SRFM_FORMS_POST_TYPE ); + + if ( ! $post_type || empty( $post_type->cap->create_posts ) || ! current_user_can( $post_type->cap->create_posts ) ) { + return; + } + + // The core "+ New" (new-content) group is registered at priority 70; this + // runs at 100, so the parent node is guaranteed to exist. + $wp_admin_bar->add_node( + [ + 'id' => 'new-' . SRFM_FORMS_POST_TYPE, + 'parent' => 'new-content', + 'title' => $post_type->labels->singular_name, + 'href' => admin_url( 'post-new.php?post_type=' . SRFM_FORMS_POST_TYPE ), + ] + ); + } + /** * Remove this method in the future once _srfm_form_confirmation meta is updated. * Normalize the _srfm_form_confirmation meta before it's sent to the REST API. diff --git a/tests/unit/inc/test-post-types.php b/tests/unit/inc/test-post-types.php index 2e0f31fc8..bc6819d15 100644 --- a/tests/unit/inc/test-post-types.php +++ b/tests/unit/inc/test-post-types.php @@ -235,4 +235,63 @@ public function test_register_post_metas_instant_form_returns_empty_for_non_arra $this->assertSame( [], $result ); } + + /** + * The admin bar "+ New" menu gets a Form node for users who can create forms (#3026). + */ + public function test_add_new_form_to_admin_bar_menu_adds_node() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + if ( ! class_exists( 'WP_Admin_Bar' ) ) { + require_once ABSPATH . WPINC . '/class-wp-admin-bar.php'; + } + + $post_types = new Post_Types(); + $post_types->register_post_types(); + add_filter( 'show_admin_bar', '__return_true' ); + + // An admin can create forms (the CPT maps create_posts to manage_options). + $admin = wp_insert_user( + [ + 'user_login' => 'srfm_bar_admin_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_bar_admin_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin ) ? 0 : (int) $admin ); + + $bar = new WP_Admin_Bar(); + $post_types->add_new_form_to_admin_bar_menu( $bar ); + + $node = $bar->get_node( 'new-' . SRFM_FORMS_POST_TYPE ); + $this->assertNotNull( $node, 'Admin should get a Form node under "+ New".' ); + $this->assertSame( 'new-content', $node->parent ); + $this->assertStringContainsString( 'post-new.php?post_type=' . SRFM_FORMS_POST_TYPE, (string) $node->href ); + + // A user without the create capability gets no node. + $subscriber = wp_insert_user( + [ + 'user_login' => 'srfm_bar_sub_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_bar_sub_' . wp_rand() . '@example.com', + 'role' => 'subscriber', + ] + ); + wp_set_current_user( is_wp_error( $subscriber ) ? 0 : (int) $subscriber ); + + $bar_sub = new WP_Admin_Bar(); + $post_types->add_new_form_to_admin_bar_menu( $bar_sub ); + $this->assertNull( $bar_sub->get_node( 'new-' . SRFM_FORMS_POST_TYPE ), 'A non-privileged user must not get the Form node.' ); + + remove_filter( 'show_admin_bar', '__return_true' ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin ) ) { + wp_delete_user( (int) $admin ); + } + if ( ! is_wp_error( $subscriber ) ) { + wp_delete_user( (int) $subscriber ); + } + } } From 0c4468cdccef9c7011ff26a5243fde2bfac55f80 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 15:27:32 +0530 Subject: [PATCH 45/65] Add admin-bar Edit Form test to satisfy check-test-coverage (#3026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The coverage script attributes the new method's docblock lines (which sit between the previous method's closing brace and the new declaration) to the preceding add_edit_form_to_admin_bar_menu(), so it demanded a test for it. Added a real behavioural test for that method — it lacked coverage anyway: asserts an Edit Form node is added when viewing a form and not for other post types. --- tests/unit/inc/test-post-types.php | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/unit/inc/test-post-types.php b/tests/unit/inc/test-post-types.php index bc6819d15..a7a914cae 100644 --- a/tests/unit/inc/test-post-types.php +++ b/tests/unit/inc/test-post-types.php @@ -294,4 +294,60 @@ public function test_add_new_form_to_admin_bar_menu_adds_node() { wp_delete_user( (int) $subscriber ); } } + + /** + * The admin bar gets an "Edit Form" node only while viewing a form (#3026 sibling). + */ + public function test_add_edit_form_to_admin_bar_menu() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + if ( ! class_exists( 'WP_Admin_Bar' ) ) { + require_once ABSPATH . WPINC . '/class-wp-admin-bar.php'; + } + + $post_types = new Post_Types(); + $post_types->register_post_types(); + add_filter( 'show_admin_bar', '__return_true' ); + + $admin = wp_insert_user( + [ + 'user_login' => 'srfm_edit_bar_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_edit_bar_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin ) ? 0 : (int) $admin ); + + global $post; + + // Viewing a form → an "Edit Form" node is added. + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Bar edit form' ] ); + $post = get_post( $form_id ); + + $bar = new WP_Admin_Bar(); + $post_types->add_edit_form_to_admin_bar_menu( $bar ); + + $node = $bar->get_node( 'edit-form' ); + $this->assertNotNull( $node, 'Viewing a form should add an Edit Form node.' ); + $this->assertStringContainsString( 'Edit Form', (string) $node->title ); + + // Viewing a non-form post → no node. + $page_id = wp_insert_post( [ 'post_type' => 'post', 'post_status' => 'publish', 'post_title' => 'Not a form' ] ); + $post = get_post( $page_id ); + + $bar_other = new WP_Admin_Bar(); + $post_types->add_edit_form_to_admin_bar_menu( $bar_other ); + $this->assertNull( $bar_other->get_node( 'edit-form' ), 'A non-form post must not add the Edit Form node.' ); + + $post = null; + remove_filter( 'show_admin_bar', '__return_true' ); + wp_delete_post( $form_id, true ); + wp_delete_post( $page_id, true ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin ) ) { + wp_delete_user( (int) $admin ); + } + } } From 9da69cfb5c7c906306a816f4d066ab0fd17bcc37 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 17:07:13 +0530 Subject: [PATCH 46/65] Address review on the admin-bar Form shortcut (#3026) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - H1: delete the dead remove_admin_bar_menu_item() + its priority-80 hook. It removed 'new-sureforms_form' (a no-op since show_in_menu became false) and fought this feature's add at priority 100 via an unencoded priority contract. - M2/M3: use the escaped name_admin_bar label (core's '+ New' child label) instead of the raw singular_name; WP_Admin_Bar echoes node titles unescaped. - M4: assert the node title in the test. - L1: correct the new-content 'guaranteed to exist' comment (core returns before registering the group when the user can create nothing else). - L2/L3/L5/L6: test hygiene — unset the show_admin_bar global, restore global $post, use Post_Types::get_instance(), and guard wp_delete_user(). - L7: esc_url() the href to match the sibling nodes. Kept post-new.php per the issue's explicit ask (M1 is a product decision). --- inc/post-types.php | 24 +++++++----------------- tests/unit/inc/test-post-types.php | 24 +++++++++++++++--------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/inc/post-types.php b/inc/post-types.php index ddeda6981..96b131ab0 100644 --- a/inc/post-types.php +++ b/inc/post-types.php @@ -36,7 +36,6 @@ public function __construct() { add_action( 'init', [ $this, 'register_post_metas' ] ); add_shortcode( 'sureforms', [ $this, 'forms_shortcode' ] ); add_action( 'manage_posts_extra_tablenav', [ $this, 'maybe_render_blank_form_state' ] ); - add_action( 'admin_bar_menu', [ $this, 'remove_admin_bar_menu_item' ], 80, 1 ); add_action( 'template_redirect', [ $this, 'srfm_instant_form_redirect' ] ); add_action( 'template_redirect', [ $this, 'disable_sureforms_archive_page' ], 9 ); add_action( 'load-edit.php', [ $this, 'redirect_forms_listing_page' ] ); @@ -128,14 +127,17 @@ public function add_new_form_to_admin_bar_menu( $wp_admin_bar ) { return; } - // The core "+ New" (new-content) group is registered at priority 70; this - // runs at 100, so the parent node is guaranteed to exist. + // Core registers the "+ New" (new-content) group at priority 70, so running at + // 100 places this node inside it. If core skipped the group (the user can create + // nothing else), WP_Admin_Bar::_bind() drops this orphan node silently. + // name_admin_bar is the label core uses for "+ New" children; escaped because + // WP_Admin_Bar echoes node titles unescaped. $wp_admin_bar->add_node( [ 'id' => 'new-' . SRFM_FORMS_POST_TYPE, 'parent' => 'new-content', - 'title' => $post_type->labels->singular_name, - 'href' => admin_url( 'post-new.php?post_type=' . SRFM_FORMS_POST_TYPE ), + 'title' => esc_html( $post_type->labels->name_admin_bar ), + 'href' => esc_url( admin_url( 'post-new.php?post_type=' . SRFM_FORMS_POST_TYPE ) ), ] ); } @@ -329,18 +331,6 @@ public function disable_sureforms_archive_page() { } } - /** - * Remove add new form menu item. - * - * @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance. - * - * @return void - * @since 0.0.1 - */ - public function remove_admin_bar_menu_item( $wp_admin_bar ) { - $wp_admin_bar->remove_node( 'new-sureforms_form' ); - } - /** * Show blank slate styles. * diff --git a/tests/unit/inc/test-post-types.php b/tests/unit/inc/test-post-types.php index a7a914cae..37ec81286 100644 --- a/tests/unit/inc/test-post-types.php +++ b/tests/unit/inc/test-post-types.php @@ -247,7 +247,7 @@ public function test_add_new_form_to_admin_bar_menu_adds_node() { require_once ABSPATH . WPINC . '/class-wp-admin-bar.php'; } - $post_types = new Post_Types(); + $post_types = Post_Types::get_instance(); $post_types->register_post_types(); add_filter( 'show_admin_bar', '__return_true' ); @@ -268,6 +268,7 @@ public function test_add_new_form_to_admin_bar_menu_adds_node() { $node = $bar->get_node( 'new-' . SRFM_FORMS_POST_TYPE ); $this->assertNotNull( $node, 'Admin should get a Form node under "+ New".' ); $this->assertSame( 'new-content', $node->parent ); + $this->assertSame( 'Form', (string) $node->title, 'Node uses the admin-bar label.' ); $this->assertStringContainsString( 'post-new.php?post_type=' . SRFM_FORMS_POST_TYPE, (string) $node->href ); // A user without the create capability gets no node. @@ -286,12 +287,15 @@ public function test_add_new_form_to_admin_bar_menu_adds_node() { $this->assertNull( $bar_sub->get_node( 'new-' . SRFM_FORMS_POST_TYPE ), 'A non-privileged user must not get the Form node.' ); remove_filter( 'show_admin_bar', '__return_true' ); + unset( $GLOBALS['show_admin_bar'] ); wp_set_current_user( 0 ); - if ( ! is_wp_error( $admin ) ) { - wp_delete_user( (int) $admin ); - } - if ( ! is_wp_error( $subscriber ) ) { - wp_delete_user( (int) $subscriber ); + if ( function_exists( 'wp_delete_user' ) ) { + if ( ! is_wp_error( $admin ) ) { + wp_delete_user( (int) $admin ); + } + if ( ! is_wp_error( $subscriber ) ) { + wp_delete_user( (int) $subscriber ); + } } } @@ -306,7 +310,7 @@ public function test_add_edit_form_to_admin_bar_menu() { require_once ABSPATH . WPINC . '/class-wp-admin-bar.php'; } - $post_types = new Post_Types(); + $post_types = Post_Types::get_instance(); $post_types->register_post_types(); add_filter( 'show_admin_bar', '__return_true' ); @@ -321,6 +325,7 @@ public function test_add_edit_form_to_admin_bar_menu() { wp_set_current_user( is_wp_error( $admin ) ? 0 : (int) $admin ); global $post; + $original_post = $post; // Viewing a form → an "Edit Form" node is added. $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Bar edit form' ] ); @@ -341,12 +346,13 @@ public function test_add_edit_form_to_admin_bar_menu() { $post_types->add_edit_form_to_admin_bar_menu( $bar_other ); $this->assertNull( $bar_other->get_node( 'edit-form' ), 'A non-form post must not add the Edit Form node.' ); - $post = null; + $post = $original_post; remove_filter( 'show_admin_bar', '__return_true' ); + unset( $GLOBALS['show_admin_bar'] ); wp_delete_post( $form_id, true ); wp_delete_post( $page_id, true ); wp_set_current_user( 0 ); - if ( ! is_wp_error( $admin ) ) { + if ( function_exists( 'wp_delete_user' ) && ! is_wp_error( $admin ) ) { wp_delete_user( (int) $admin ); } } From b647d50e7a3964c32c42cc155f7da87c9573764f Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 18:19:36 +0530 Subject: [PATCH 47/65] Address re-review: deep-link panel + zero-notifications + robustness (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - B2: the deep-link now ensures the Form Options *panel* is open (not just the sidebar) before exiting — GeneralSettings only mounts when the panel is expanded on the Document tab, so a collapsed panel no longer silently no-ops. The tick re-asserts forcePanel() and exits on panel-open + document-active (the sidebar reads open on the Block tab too). Verified live with the panel collapsed. Fixed the contradictory comments. - B3: 'Set where replies go' acts on an empty notifications array too (the routine state, since the replies step shows precisely when there is no reply destination) and lands on the Add-New form via handleEdit(data[0] ?? {}). Consumes once data is an array, closing a re-fire when [] -> [x]. Verified live. - M1: bound-check + clearInterval run before the store calls; methods are feature-detected so a throwing store method can't keep the interval alive. - M2: drop btoa() from the unsaved-changes hash (it now runs on page load via the deep-link and throws for non-ASCII locales); JSON.stringify alone is the key. - M3: extract the deep-link contract to single-form-settings/deep-link.js so Editor/GeneralSettings/EmailNotification share one source (no cycle, no window-vs-import divergence on the URL-fallback path). - M4: assert render_thankyou_prompt_notice() on the Astra_Notices registry instead of stdout (the method registers, never echoes). - Low: exit on the Document tab being active, not just any sidebar. B1 (placement) and H1/AC#7 (targeting) are product decisions left for sign-off. --- src/admin/single-form-settings/Editor.js | 56 ++++++++++++------- .../email-settings/EmailNotification.js | 28 +++++----- src/admin/single-form-settings/deep-link.js | 25 +++++++++ .../tabs/GeneralSettings.js | 41 ++++---------- tests/unit/admin/test-admin.php | 16 ++++-- 5 files changed, 98 insertions(+), 68 deletions(-) create mode 100644 src/admin/single-form-settings/deep-link.js diff --git a/src/admin/single-form-settings/Editor.js b/src/admin/single-form-settings/Editor.js index 209948086..4e71bb996 100644 --- a/src/admin/single-form-settings/Editor.js +++ b/src/admin/single-form-settings/Editor.js @@ -13,7 +13,6 @@ import { useSelect, useDispatch, select as dataSelect, - dispatch as dataDispatch, } from '@wordpress/data'; import { store as editorStore, @@ -23,10 +22,8 @@ import { import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as preferencesStore } from '@wordpress/preferences'; -import GeneralSettings, { - srfmDeepLinkFocus, - SRFM_DEEP_LINK_TABS, -} from './tabs/GeneralSettings.js'; +import GeneralSettings from './tabs/GeneralSettings.js'; +import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from './deep-link'; import StyleSettings from './tabs/StyleSettings.js'; import InspectorTabs from '@Components/inspector-tabs/InspectorTabs.js'; import InspectorTab, { @@ -91,14 +88,13 @@ const SureformsFormSpecificSettings = () => { // runs from the always-mounted plugin root so the deep-link works regardless // of the user's saved sidebar state. // - // Opening it once on mount isn't enough: an early open (before the editor has - // finished booting) is a no-op or gets reverted by the editor's preference - // restore — the same reason forcePanel's open doesn't stick. Re-assert on a - // short interval until the sidebar is open, then stop. The dispatch is made - // from a timer tick (outside the store's notification cycle, where it would be - // swallowed) so it actually takes effect. Bounded so a sidebar that can't open - // is never retried indefinitely; opening it is enough — GeneralSettings then - // mounts and self-opens the target tab (once). + // GeneralSettings mounts only when the Document sidebar is open AND the "Form + // Options" panel is expanded — both are user preferences that can be off, and + // an early open during boot gets reverted by the editor's preference restore. + // So re-assert forcePanel() (which opens the sidebar and enables+opens both + // panels) on a short interval from a timer tick — outside the store's + // notification cycle, where the dispatch would be swallowed — until the target + // state is reached, then stop. GeneralSettings then self-opens the tab (once). useEffect( () => { if ( ! Object.prototype.hasOwnProperty.call( @@ -111,18 +107,40 @@ const SureformsFormSpecificSettings = () => { let elapsed = 0; const ensureOpen = setInterval( () => { + // Bound + clear FIRST, so a throwing store method can never keep the + // interval alive for the rest of the session. elapsed += 300; - const editPostStore = dataSelect( 'core/edit-post' ); - if ( editPostStore?.isEditorSidebarOpened() ) { + if ( elapsed > 6000 ) { clearInterval( ensureOpen ); return; } - dataDispatch( 'core/edit-post' )?.openGeneralSidebar( - 'edit-post/document' - ); - if ( elapsed >= 6000 ) { + + const editor = dataSelect( 'core/editor' ); + if ( ! editor ) { + return; + } + + // The Form Options panel must be open, on the Document tab (the sidebar + // being "open" is true for the Block tab too, where GeneralSettings does + // not render). + const iface = dataSelect( 'core/interface' ); + const panelOpen = + typeof editor.isEditorPanelOpened === 'function' && + editor.isEditorPanelOpened( + 'srfm-form-specific-settings/srfm-sidebar' + ); + const onDocument = + iface && + typeof iface.getActiveComplementaryArea === 'function' && + iface.getActiveComplementaryArea( 'core/edit-post' ) === + 'edit-post/document'; + + if ( panelOpen && onDocument ) { clearInterval( ensureOpen ); + return; } + + forcePanel(); }, 300 ); return () => clearInterval( ensureOpen ); diff --git a/src/admin/single-form-settings/components/email-settings/EmailNotification.js b/src/admin/single-form-settings/components/email-settings/EmailNotification.js index 40aecf794..ef4ac78f6 100644 --- a/src/admin/single-form-settings/components/email-settings/EmailNotification.js +++ b/src/admin/single-form-settings/components/email-settings/EmailNotification.js @@ -16,11 +16,12 @@ import { Copy, PenLine, Trash } from 'lucide-react'; import TabContentWrapper from '@Components/tab-content-wrapper'; import { notify } from '@Utils/notify'; import { applyFilters, doAction } from '@wordpress/hooks'; +import { srfmDeepLinkFocus } from '../../deep-link'; // One-shot guard: when the editor is reached via the "Set where replies go" -// deep-link (?srfm_focus=notifications, surfaced by PHP as window.srfmDeepLinkFocus), -// jump straight into the first notification's editor instead of landing on the -// list. Module-scoped so a later tab remount does not reopen it. +// deep-link (?srfm_focus=notifications), jump straight into the notification +// editor instead of landing on the list. Module-scoped so a later tab remount +// does not reopen it. let srfmRepliesDeepLinkConsumed = false; const CustomButton = forwardRef( @@ -212,24 +213,23 @@ const EmailNotification = ( { }, ]; - // Deep-link: open the first notification's editor directly when arriving via - // "Set where replies go". Runs once data is available, then never again. + // Deep-link: open the notification editor directly when arriving via "Set + // where replies go". The replies step shows precisely when the form has no + // reply destination — routinely zero notifications — so this must act on an + // empty array too, landing on the Add-New form (a bare object is + // EmailConfirmation's documented add shape: initFormData falls back on + // data.id || false). Consume as soon as data is an array so it can't re-fire + // when the user saves their first notification and the array flips [] -> [x]. useEffect( () => { if ( srfmRepliesDeepLinkConsumed ) { return; } - if ( - typeof window === 'undefined' || - window.srfmDeepLinkFocus !== 'notifications' - ) { + if ( srfmDeepLinkFocus !== 'notifications' ) { return; } - if ( - Array.isArray( emailNotificationData ) && - emailNotificationData.length > 0 - ) { + if ( Array.isArray( emailNotificationData ) ) { srfmRepliesDeepLinkConsumed = true; - handleEdit( emailNotificationData[ 0 ] ); + handleEdit( emailNotificationData[ 0 ] ?? {} ); } }, [ emailNotificationData ] ); diff --git a/src/admin/single-form-settings/deep-link.js b/src/admin/single-form-settings/deep-link.js new file mode 100644 index 000000000..530258376 --- /dev/null +++ b/src/admin/single-form-settings/deep-link.js @@ -0,0 +1,25 @@ +/** + * Shared deep-link contract for the form editor's "Finish setting up" CTAs (#3030). + * + * The dashboard notice opens the editor with ?srfm_focus=… to auto-open a Form + * Settings tab. Gutenberg strips unrecognised query args client-side before the + * bundle can reliably read them, so PHP surfaces the value as + * `window.srfmDeepLinkFocus` (printed before this bundle) — read that first, + * falling back to the raw URL for safety. + * + * Kept in its own dependency-free module so Editor.js, GeneralSettings.js and + * EmailNotification.js share one source: no import cycle (which is why + * EmailNotification previously re-derived the value from `window`, diverging on + * the URL-fallback path) and one place to reason about the contract. + */ +export const srfmDeepLinkFocus = + ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || + new URLSearchParams( window.location.search ).get( 'srfm_focus' ); + +// Maps the ?srfm_focus value to a Form Settings tab id. Read through +// hasOwnProperty (never prototype members) so ?srfm_focus=constructor resolves to +// nothing rather than handing a function to setPopupTab. +export const SRFM_DEEP_LINK_TABS = { + thankyou: 'form_confirmation', + notifications: 'email_notification', +}; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index 1e6c02ee0..db00d221b 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -12,33 +12,15 @@ import { applyFilters } from '@wordpress/hooks'; import Dialog from '../components/dialog/Dialog'; import { FormRestrictionProvider } from '../components/form-restrictions/context'; import { prepareBlockSlugs } from '@Utils/Helpers'; +import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from '../deep-link'; let prevMetaHash = ''; -// The dashboard "Finish setting up" notice CTA opens the editor with -// ?srfm_focus=… to auto-open a settings tab. Gutenberg strips unrecognised query -// args client-side before this bundle can reliably read them, so PHP surfaces the -// value as `window.srfmDeepLinkFocus` (printed before this bundle) — read that -// first, falling back to the raw URL for safety. -export const srfmDeepLinkFocus = - ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || - new URLSearchParams( window.location.search ).get( 'srfm_focus' ); - // One deep-link per page load, ever. Module-scoped so a later panel remount // (switching to the Block tab and back, which unmounts/remounts this component) // cannot re-fire the open and slam the dialog back over the user's work. let srfmDeepLinkConsumed = false; -// Maps the ?srfm_focus value to a Form Settings tab id. A plain object read -// through hasOwnProperty (never prototype members), so ?srfm_focus=constructor -// resolves to nothing rather than handing a function to setPopupTab. Exported so -// the always-mounted editor root (Editor.js) can open the settings sidebar for -// the same targets — GeneralSettings only mounts once that sidebar is open. -export const SRFM_DEEP_LINK_TABS = { - thankyou: 'form_confirmation', - notifications: 'email_notification', -}; - function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -72,7 +54,7 @@ function GeneralSettings( props ) { setOpen( false ); - if ( btoa( JSON.stringify( sureformsKeys ) ) !== prevMetaHash ) { + if ( JSON.stringify( sureformsKeys ) !== prevMetaHash ) { createNotice( 'warning', __( @@ -243,7 +225,7 @@ function GeneralSettings( props ) { if ( tabId ) { setPopupTab( tabId ); setOpen( true ); - prevMetaHash = btoa( JSON.stringify( sureformsKeys ) ); + prevMetaHash = JSON.stringify( sureformsKeys ); } }; @@ -264,17 +246,14 @@ function GeneralSettings( props ) { // Deep-link support: open a specific Form Settings tab when the editor is // reached with ?srfm_focus=... — the dashboard "Finish setting up" notice CTA - // uses this so "Edit the thank-you message" lands on Form Confirmation. The - // target is read from `srfmDeepLinkFocus`, snapshotted at bundle-eval time - // because the block editor strips the query arg from the URL before this - // effect runs. + // uses this so "Edit the thank-you message" lands on Form Confirmation. // - // forcePanel() force-opens the Form Options panel on every editor load, so - // this component is reliably mounted here and the sibling listener effect - // above (declared first, so React registers it before this one runs) is in - // place to receive the event — a single synchronous dispatch cannot miss it, - // no polling needed. Consume-once via the module flag so a later panel - // remount does not reopen the dialog on top of the user's work. + // This component only mounts once the Form Options panel is open; the editor + // root (Editor.js) is responsible for ensuring that (sidebar + panel). Once + // mounted, this fires a single synchronous dispatch to the sibling listener + // effect above (declared first, so React registers it before this one runs). + // Consume-once via the module flag so a later panel remount does not reopen + // the dialog on top of the user's work. useEffect( () => { if ( srfmDeepLinkConsumed ) { return; diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 25e4988d9..dff8bf0b6 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -1125,12 +1125,20 @@ public function test_render_thankyou_prompt_notice() { $admin = Admin::get_instance(); $this->assertTrue( method_exists( $admin, 'render_thankyou_prompt_notice' ) ); - ob_start(); + if ( ! class_exists( '\Astra_Notices' ) ) { + $this->markTestSkipped( 'Astra_Notices library not loaded.' ); + } + + // The method registers with Astra_Notices rather than echoing, so assert on + // the registry: with no qualifying starter-template form in the test DB, + // nothing should be registered. + $prop = new \ReflectionProperty( \Astra_Notices::class, 'notices' ); + $prop->setAccessible( true ); + $prop->setValue( null, [] ); + $admin->render_thankyou_prompt_notice(); - $output = (string) ob_get_clean(); - // No starter-template form exists in the test DB, so nothing is printed. - $this->assertStringNotContainsString( 'srfm-thankyou-notice', $output ); + $this->assertSame( [], $prop->getValue(), 'No qualifying form → no notice registered.' ); } /** From b36e858dbe76cdef89554a3935cab0fd664a66ff Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 18:39:48 +0530 Subject: [PATCH 48/65] Address re-review on the setup widget (#3031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Critical/H1: delete the three unreachable predicates (is_default_confirmation_message, is_default_email_notification, form_is_embedded) and their tests. The widget shows optional steps and never computes completion, so they were dead code — and they collided with #3040's stronger copies (Cannot redeclare). Resolves the merge fatal. - H2/H3: replace the pre-review deep-link JS with #3040's finalized version (shared deep-link.js module, consume-once, hasOwnProperty tab guard, no 12s poll, no Force UI opacity reach-in, and a sidebar+panel opener from the always-mounted editor root so the CTA works with the sidebar/panel collapsed). Both PRs now share one source with no divergence. - M1: 'Remind me in two weeks' only hides the widget once the snooze POST succeeds (res.ok) — the render-time nonce can expire and a 403 would look broken. - M2: prime post/meta caches in get_form_setup_card() and guard SRFM_FORMS_POST_TYPE with defined(). - M3: correct the stale render_form_setup_widget() docblock. - M5: drop the tautological/dead-predicate tests; assert the card shape, the render↔card contract, and the off-dashboard asset gate. - Low: REST 'action' arg gets an enum; e.target?.closest guard; removeWidget no longer leaves an empty postbox. Surface question (single widget vs three surfaces), completion logic, and per-form dismiss (M4) are product decisions left for sign-off. --- admin/admin.php | 170 ++++-------------- inc/rest-api.php | 2 + src/admin/single-form-settings/Editor.js | 72 +++++++- .../email-settings/EmailNotification.js | 32 ++-- src/admin/single-form-settings/deep-link.js | 25 +++ .../tabs/GeneralSettings.js | 113 ++++-------- tests/unit/admin/test-admin.php | 113 ++++-------- 7 files changed, 216 insertions(+), 311 deletions(-) create mode 100644 src/admin/single-form-settings/deep-link.js diff --git a/admin/admin.php b/admin/admin.php index a0f39605c..c1e514079 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -281,7 +281,7 @@ public static function get_form_setup_card() { $cache = null; - if ( ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { return $cache; } @@ -296,16 +296,19 @@ public static function get_form_setup_card() { // Only forms created from an Astra Sites starter template — those carry the // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. + // Prime post + meta caches (the loop reads title, permalink and edit link + // per candidate) so this is a single query, not a follow-up per form. $query = new \WP_Query( [ - 'post_type' => SRFM_FORMS_POST_TYPE, - 'post_status' => [ 'publish', 'draft', 'pending' ], - 'posts_per_page' => 10, - 'orderby' => 'date', - 'order' => 'DESC', - 'fields' => 'ids', - 'no_found_rows' => true, - 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => [ 'publish', 'draft', 'pending' ], + 'posts_per_page' => 10, + 'orderby' => 'date', + 'order' => 'DESC', + 'no_found_rows' => true, + 'update_post_meta_cache' => true, + 'update_post_term_cache' => false, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. [ 'key' => '_astra_sites_imported_post', 'compare' => 'EXISTS', @@ -314,8 +317,8 @@ public static function get_form_setup_card() { ] ); - foreach ( $query->posts as $form_id ) { - $form_id = (int) $form_id; + foreach ( $query->posts as $post ) { + $form_id = (int) $post->ID; if ( ! current_user_can( 'edit_post', $form_id ) ) { continue; @@ -349,122 +352,6 @@ public static function get_form_setup_card() { return $cache; } - /** - * Whether a form is embedded on at least one published page or post. - * - * A bounded LIKE over published content matches the two embed forms SureForms - * emits — the `srfm/form` block (`"id":N`) and the `[sureforms id="N"]` - * shortcode — stopping at the first hit. Heuristic by design: it errs toward - * "embedded" so the card never nags about a form that is already placed. - * - * @param int $form_id Form post ID. - * - * @since x.x.x - * @return bool - */ - public static function form_is_embedded( $form_id ) { - global $wpdb; - - $form_id = (int) $form_id; - - $block_like = '%' . $wpdb->esc_like( 'srfm/form' ) . '%' . $wpdb->esc_like( '"id":' . $form_id ) . '%'; - $shortcode_like = '%' . $wpdb->esc_like( '[sureforms id="' . $form_id . '"' ) . '%'; - - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Bounded existence check for the dashboard setup card; no core API expresses a reverse "which pages embed form N" lookup. - $found = $wpdb->get_var( - $wpdb->prepare( - "SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type IN ( 'post', 'page' ) AND ( post_content LIKE %s OR post_content LIKE %s ) LIMIT 1", - $block_like, - $shortcode_like - ) - ); - - return ! empty( $found ); - } - - /** - * Whether a form's email notification is still the shipped default (untouched). - * - * Every form is created with one "Admin Notification Email" — recipient - * `{admin_email}`, the default subject and an `{all_data}` body — and WordPress - * hands that registered default back from get_post_meta even when nothing is - * stored, so mere presence never means the owner has chosen who gets notified. - * The "Choose who gets notified" checklist step is therefore driven by whether - * this default has been customized: a second notification, a changed recipient, - * subject or body, or a disabled notification all count as touched. Compared on - * the recipient + subject + body, the fields that define who is notified and - * with what — cosmetic fields (reply-to, cc/bcc, from) are ignored. - * - * @param int $form_id Form post ID. - * - * @since x.x.x - * @return bool True when the notification matches the default; false once customized. - */ - public static function is_default_email_notification( $form_id ) { - $notifications = get_post_meta( (int) $form_id, '_srfm_email_notification', true ); - - // No notification configured — untouched, so the step stays incomplete. - if ( ! is_array( $notifications ) || empty( $notifications ) ) { - return true; - } - - // A second notification is something the owner added — customized. - if ( 1 !== count( $notifications ) ) { - return false; - } - - $notification = $notifications[0]; - - if ( ! is_array( $notification ) ) { - return false; - } - - // A disabled notification is a deliberate change away from the default. - if ( empty( $notification['status'] ) ) { - return false; - } - - $default_subject = sprintf( - /* translators: %s: form title smart tag. */ - __( 'New Form Submission - %s', 'sureforms' ), - '{form_title}' - ); - - return '{admin_email}' === ( $notification['email_to'] ?? '' ) - && ( $notification['subject'] ?? '' ) === $default_subject - && '{all_data}' === ( $notification['email_body'] ?? '' ); - } - - /** - * Whether a form's confirmation message is still the shipped default. - * - * Compared on tag-stripped text rather than raw HTML: the default is stored - * with a base64 icon on creation but regenerated with a URL icon, so the markup - * differs while the wording does not. Any real edit flips this to false. - * - * @param int $form_id Form post ID. - * - * @since x.x.x - * @return bool - */ - public static function is_default_confirmation_message( $form_id ) { - $confirmation = get_post_meta( (int) $form_id, '_srfm_form_confirmation', true ); - - if ( ! is_array( $confirmation ) || ! isset( $confirmation[0]['message'] ) || ! is_string( $confirmation[0]['message'] ) ) { - return false; - } - - if ( '' === trim( $confirmation[0]['message'] ) ) { - return false; - } - - $normalize = static function ( $html ) { - return trim( (string) preg_replace( '/\s+/', ' ', wp_strip_all_tags( (string) $html ) ) ); - }; - - return $normalize( $confirmation[0]['message'] ) === $normalize( Global_Settings::get_default_confirmation_message() ); - } - /** * REST handler: record a "Finish setting up" widget interaction (#3031). * @@ -2419,10 +2306,11 @@ public function register_form_setup_widget() { /** * Render the setup-checklist widget content (#3031). * - * A progress line, then one row per step with a completion check and — for the - * incomplete, actionable steps — a CTA. The "Get embed code" step reveals the - * form shortcode inline rather than navigating away. Dismiss (✕) and the 14-day - * snooze are wired in the enqueued inline script against the REST endpoint. + * A heading (with a link to view the form), a subtitle, and a fixed list of + * optional next-steps — each always shown with its CTA; completion is not + * computed. Each CTA deep-links into the editor (edit form / Thank You message / + * email notification). The "Remind me in two weeks" snooze is wired in the + * enqueued inline script against the REST endpoint. * * @since x.x.x * @return void @@ -2562,7 +2450,7 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { } const persist = function ( action ) { - fetch( cfg.restUrl, { + return fetch( cfg.restUrl, { method: 'POST', credentials: 'same-origin', keepalive: true, @@ -2572,14 +2460,18 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { }; const removeWidget = function () { + // Remove the whole postbox; removing only the inner node would leave an + // empty box with its title still showing. const box = document.getElementById( 'srfm_form_setup_checklist' ); - ( box || widget ).remove(); + if ( box ) { + box.remove(); + } }; // Beacon the CTA / view-form clicks for analytics. keepalive on the fetch lets // the request finish even though the CTA immediately navigates away. widget.addEventListener( 'click', function ( e ) { - const target = e.target.closest( '[data-srfm-event]' ); + const target = e.target?.closest?.( '[data-srfm-event]' ); if ( target ) { persist( target.getAttribute( 'data-srfm-event' ) ); } @@ -2588,8 +2480,14 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { const snoozeBtn = document.getElementById( 'srfm-setup-checklist-snooze' ); if ( snoozeBtn ) { snoozeBtn.addEventListener( 'click', function () { - persist( 'snooze' ); - removeWidget(); + // Only hide the widget once the snooze actually persisted — the + // render-time wp_rest nonce can expire on a long-open dashboard, and + // hiding on a 403 would make the widget silently reappear next load. + persist( 'snooze' ).then( function ( res ) { + if ( res && res.ok ) { + removeWidget(); + } + } ); } ); } }() ); diff --git a/inc/rest-api.php b/inc/rest-api.php index 0ec3607c3..0406e10e6 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1425,6 +1425,8 @@ private function get_endpoints() { 'sanitize_callback' => 'absint', ], 'action' => [ + 'type' => 'string', + 'enum' => [ 'edit_form', 'edit_thankyou', 'set_up_email', 'view_form', 'snooze' ], 'sanitize_callback' => 'sanitize_text_field', ], ], diff --git a/src/admin/single-form-settings/Editor.js b/src/admin/single-form-settings/Editor.js index 5aa7be11f..4e71bb996 100644 --- a/src/admin/single-form-settings/Editor.js +++ b/src/admin/single-form-settings/Editor.js @@ -9,7 +9,11 @@ import { import { __ } from '@wordpress/i18n'; import { useState, useEffect, createRoot } from '@wordpress/element'; -import { useSelect, useDispatch } from '@wordpress/data'; +import { + useSelect, + useDispatch, + select as dataSelect, +} from '@wordpress/data'; import { store as editorStore, PluginDocumentSettingPanel, @@ -19,6 +23,7 @@ import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as preferencesStore } from '@wordpress/preferences'; import GeneralSettings from './tabs/GeneralSettings.js'; +import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from './deep-link'; import StyleSettings from './tabs/StyleSettings.js'; import InspectorTabs from '@Components/inspector-tabs/InspectorTabs.js'; import InspectorTab, { @@ -76,6 +81,71 @@ const SureformsFormSpecificSettings = () => { const [ rootHtmlTag, setRootHtmlTag ] = useState( null ); const [ documentBody, setDocumentBody ] = useState( null ); + // Deep-link support (#3030): when the editor is opened with ?srfm_focus=…, + // make sure the settings sidebar is open. GeneralSettings — which hosts the + // Form Settings dialog and self-opens the target tab on mount — only renders + // while that sidebar is open, and it can be collapsed by user preference. This + // runs from the always-mounted plugin root so the deep-link works regardless + // of the user's saved sidebar state. + // + // GeneralSettings mounts only when the Document sidebar is open AND the "Form + // Options" panel is expanded — both are user preferences that can be off, and + // an early open during boot gets reverted by the editor's preference restore. + // So re-assert forcePanel() (which opens the sidebar and enables+opens both + // panels) on a short interval from a timer tick — outside the store's + // notification cycle, where the dispatch would be swallowed — until the target + // state is reached, then stop. GeneralSettings then self-opens the tab (once). + useEffect( () => { + if ( + ! Object.prototype.hasOwnProperty.call( + SRFM_DEEP_LINK_TABS, + srfmDeepLinkFocus + ) + ) { + return undefined; + } + + let elapsed = 0; + const ensureOpen = setInterval( () => { + // Bound + clear FIRST, so a throwing store method can never keep the + // interval alive for the rest of the session. + elapsed += 300; + if ( elapsed > 6000 ) { + clearInterval( ensureOpen ); + return; + } + + const editor = dataSelect( 'core/editor' ); + if ( ! editor ) { + return; + } + + // The Form Options panel must be open, on the Document tab (the sidebar + // being "open" is true for the Block tab too, where GeneralSettings does + // not render). + const iface = dataSelect( 'core/interface' ); + const panelOpen = + typeof editor.isEditorPanelOpened === 'function' && + editor.isEditorPanelOpened( + 'srfm-form-specific-settings/srfm-sidebar' + ); + const onDocument = + iface && + typeof iface.getActiveComplementaryArea === 'function' && + iface.getActiveComplementaryArea( 'core/edit-post' ) === + 'edit-post/document'; + + if ( panelOpen && onDocument ) { + clearInterval( ensureOpen ); + return; + } + + forcePanel(); + }, 300 ); + + return () => clearInterval( ensureOpen ); + }, [] ); + useEffect( () => { let intervalId = null; let timeoutId = null; diff --git a/src/admin/single-form-settings/components/email-settings/EmailNotification.js b/src/admin/single-form-settings/components/email-settings/EmailNotification.js index a58adeacb..ef4ac78f6 100644 --- a/src/admin/single-form-settings/components/email-settings/EmailNotification.js +++ b/src/admin/single-form-settings/components/email-settings/EmailNotification.js @@ -16,16 +16,12 @@ import { Copy, PenLine, Trash } from 'lucide-react'; import TabContentWrapper from '@Components/tab-content-wrapper'; import { notify } from '@Utils/notify'; import { applyFilters, doAction } from '@wordpress/hooks'; +import { srfmDeepLinkFocus } from '../../deep-link'; -// Deep-link target (?srfm_focus=…). Prefer the PHP-surfaced global when present -// (reliable), else the URL snapshot captured at bundle-eval — before Gutenberg -// strips the query arg. Used to jump straight into the first notification when -// the editor is reached via "Set up email" / "Set where replies go". -const srfmRepliesDeepLinkFocus = - ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || - new URLSearchParams( window.location.search ).get( 'srfm_focus' ); - -// One-shot guard so a later tab remount does not reopen the editor. +// One-shot guard: when the editor is reached via the "Set where replies go" +// deep-link (?srfm_focus=notifications), jump straight into the notification +// editor instead of landing on the list. Module-scoped so a later tab remount +// does not reopen it. let srfmRepliesDeepLinkConsumed = false; const CustomButton = forwardRef( @@ -217,21 +213,23 @@ const EmailNotification = ( { }, ]; - // Deep-link: open the first notification's editor directly when arriving via - // "Set up email" / "Set where replies go". Runs once data is available. + // Deep-link: open the notification editor directly when arriving via "Set + // where replies go". The replies step shows precisely when the form has no + // reply destination — routinely zero notifications — so this must act on an + // empty array too, landing on the Add-New form (a bare object is + // EmailConfirmation's documented add shape: initFormData falls back on + // data.id || false). Consume as soon as data is an array so it can't re-fire + // when the user saves their first notification and the array flips [] -> [x]. useEffect( () => { if ( srfmRepliesDeepLinkConsumed ) { return; } - if ( srfmRepliesDeepLinkFocus !== 'notifications' ) { + if ( srfmDeepLinkFocus !== 'notifications' ) { return; } - if ( - Array.isArray( emailNotificationData ) && - emailNotificationData.length > 0 - ) { + if ( Array.isArray( emailNotificationData ) ) { srfmRepliesDeepLinkConsumed = true; - handleEdit( emailNotificationData[ 0 ] ); + handleEdit( emailNotificationData[ 0 ] ?? {} ); } }, [ emailNotificationData ] ); diff --git a/src/admin/single-form-settings/deep-link.js b/src/admin/single-form-settings/deep-link.js new file mode 100644 index 000000000..530258376 --- /dev/null +++ b/src/admin/single-form-settings/deep-link.js @@ -0,0 +1,25 @@ +/** + * Shared deep-link contract for the form editor's "Finish setting up" CTAs (#3030). + * + * The dashboard notice opens the editor with ?srfm_focus=… to auto-open a Form + * Settings tab. Gutenberg strips unrecognised query args client-side before the + * bundle can reliably read them, so PHP surfaces the value as + * `window.srfmDeepLinkFocus` (printed before this bundle) — read that first, + * falling back to the raw URL for safety. + * + * Kept in its own dependency-free module so Editor.js, GeneralSettings.js and + * EmailNotification.js share one source: no import cycle (which is why + * EmailNotification previously re-derived the value from `window`, diverging on + * the URL-fallback path) and one place to reason about the contract. + */ +export const srfmDeepLinkFocus = + ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || + new URLSearchParams( window.location.search ).get( 'srfm_focus' ); + +// Maps the ?srfm_focus value to a Form Settings tab id. Read through +// hasOwnProperty (never prototype members) so ?srfm_focus=constructor resolves to +// nothing rather than handing a function to setPopupTab. +export const SRFM_DEEP_LINK_TABS = { + thankyou: 'form_confirmation', + notifications: 'email_notification', +}; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index 1c111e09c..db00d221b 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -4,7 +4,7 @@ import { useDeviceType } from '@Controls/getPreviewType'; import { ToggleControl } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as editorStore } from '@wordpress/editor'; -import { useEffect, useRef, useState } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { applyFilters } from '@wordpress/hooks'; @@ -12,17 +12,14 @@ import { applyFilters } from '@wordpress/hooks'; import Dialog from '../components/dialog/Dialog'; import { FormRestrictionProvider } from '../components/form-restrictions/context'; import { prepareBlockSlugs } from '@Utils/Helpers'; +import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from '../deep-link'; let prevMetaHash = ''; -// Capture the dashboard deep-link target (?srfm_focus=…) the moment this -// bundle evaluates — the block editor strips unrecognised query args from the -// URL shortly after it boots, so reading the param later (inside a mount -// effect) finds it already gone. Snapshotting it here, before Gutenberg's URL -// cleanup runs, is what makes the deep-link reliable. -const srfmDeepLinkFocus = new URLSearchParams( window.location.search ).get( - 'srfm_focus' -); +// One deep-link per page load, ever. Module-scoped so a later panel remount +// (switching to the Block tab and back, which unmounts/remounts this component) +// cannot re-fire the open and slam the dialog back over the user's work. +let srfmDeepLinkConsumed = false; function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -40,10 +37,6 @@ function GeneralSettings( props ) { const root = document.documentElement.querySelector( 'body' ); const [ isOpen, setOpen ] = useState( false ); const [ popupTab, setPopupTab ] = useState( false ); - // Mirrors `isOpen` for the deep-link poll below, which reads it from a - // long-lived interval closure that would otherwise see a stale value. - const isOpenRef = useRef( isOpen ); - isOpenRef.current = isOpen; const [ hasValidationErrors, setHasValidationErrors ] = useState( false ); const closeModal = () => { @@ -61,7 +54,7 @@ function GeneralSettings( props ) { setOpen( false ); - if ( btoa( JSON.stringify( sureformsKeys ) ) !== prevMetaHash ) { + if ( JSON.stringify( sureformsKeys ) !== prevMetaHash ) { createNotice( 'warning', __( @@ -232,7 +225,7 @@ function GeneralSettings( props ) { if ( tabId ) { setPopupTab( tabId ); setOpen( true ); - prevMetaHash = btoa( JSON.stringify( sureformsKeys ) ); + prevMetaHash = JSON.stringify( sureformsKeys ); } }; @@ -251,74 +244,38 @@ function GeneralSettings( props ) { }; }, [ sureformsKeys ] ); - // Deep-link support: open a specific form-settings panel when the editor is - // reached with ?srfm_focus=... — the dashboard setup-checklist CTAs use this so - // "Set up email" lands on the Email Notification tab. The target is read from - // `srfmDeepLinkFocus`, snapshotted at bundle-eval time because the block editor - // strips the query arg from the URL before this effect runs. + // Deep-link support: open a specific Form Settings tab when the editor is + // reached with ?srfm_focus=... — the dashboard "Finish setting up" notice CTA + // uses this so "Edit the thank-you message" lands on Form Confirmation. + // + // This component only mounts once the Form Options panel is open; the editor + // root (Editor.js) is responsible for ensuring that (sidebar + panel). Once + // mounted, this fires a single synchronous dispatch to the sibling listener + // effect above (declared first, so React registers it before this one runs). + // Consume-once via the module flag so a later panel remount does not reopen + // the dialog on top of the user's work. useEffect( () => { - const tabByFocus = { - ottokit: 'ottokit', - thankyou: 'form_confirmation', - notifications: 'email_notification', - }; - const tabId = tabByFocus[ srfmDeepLinkFocus ]; - - if ( ! tabId ) { - return undefined; + if ( srfmDeepLinkConsumed ) { + return; } - // Open the form-settings dialog on the target tab via the same window - // event the "Form Settings" popover uses. The editor mounts/remounts the - // settings panels during initial load and the listener re-registers on - // every meta change, so a single dispatch can miss it, and the Force UI - // dialog's opacity fade-in can stall when toggled amid that churn. Poll - // every 300ms: dispatch the open request until the dialog appears, then - // stop dispatching and just hold the overlay visible. - // - // Once it has opened, halt the poll the moment `isOpen` goes back to false - // — that is the user closing it (Esc / backdrop / ✕), which flips state on - // this same live mount. A load-time remount instead tears this effect down - // (clearing the interval) and re-runs it fresh on the new mount, so churn - // still reopens while a deliberate close stays closed. Give up after the - // load window if it never opened so the interval can't run indefinitely. - let elapsed = 0; - let opened = false; - const ensureOpen = setInterval( () => { - elapsed += 300; - - // Dialog is open on this mount: mark it opened and hold the overlay - // painted (the fade-in can stall during load), then wait. - if ( isOpenRef.current ) { - opened = true; - const panel = document.querySelector( '.srfm-dialog-panel' ); - const overlay = panel?.closest( '.fixed.inset-0' ); - if ( overlay ) { - overlay.style.opacity = '1'; - } - return; - } - - // It was open and is now closed on this same live mount — the user - // dismissed it (✕ / Esc / backdrop). Stop; do not reopen. - if ( opened ) { - clearInterval( ensureOpen ); - return; - } + const tabId = Object.prototype.hasOwnProperty.call( + SRFM_DEEP_LINK_TABS, + srfmDeepLinkFocus + ) + ? SRFM_DEEP_LINK_TABS[ srfmDeepLinkFocus ] + : null; - // Not open yet — keep asking until the listener catches it. - window.dispatchEvent( - new CustomEvent( 'srfm-open-form-settings', { - detail: { tabId }, - } ) - ); - - if ( elapsed >= 12000 ) { - clearInterval( ensureOpen ); - } - }, 300 ); + if ( ! tabId ) { + return; + } - return () => clearInterval( ensureOpen ); + srfmDeepLinkConsumed = true; + window.dispatchEvent( + new CustomEvent( 'srfm-open-form-settings', { + detail: { tabId }, + } ) + ); }, [] ); return ( diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 3309ddf40..f690a5e13 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -937,85 +937,19 @@ public function test_is_sureforms_owned_notice_callback() { } /** - * The first-form-created flag resolves to a boolean. - */ - public function test_is_first_form_created() { - $this->assertIsBool( Admin::is_first_form_created() ); - } - - /** - * A default confirmation message is detected; an edited one is not (#3031). - */ - public function test_is_default_confirmation_message() { - $this->assertFalse( Admin::is_default_confirmation_message( 0 ) ); - - if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { - $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); - } - remove_all_actions( 'wp_insert_post_data' ); - - $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Conf detect' ] ); - - update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message() ] ] ); - $this->assertTrue( Admin::is_default_confirmation_message( $form_id ) ); - - update_post_meta( $form_id, '_srfm_form_confirmation', [ [ 'message' => 'Thanks - we will be in touch!' ] ] ); - $this->assertFalse( Admin::is_default_confirmation_message( $form_id ) ); - - wp_delete_post( $form_id, true ); - } - - /** - * The default admin notification is the untouched default until customised (#3031). - */ - public function test_is_default_email_notification() { - // No notification meta at all -> treated as untouched default. - $this->assertTrue( Admin::is_default_email_notification( 0 ) ); - - if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { - $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); - } - remove_all_actions( 'wp_insert_post_data' ); - - $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Notif detect' ] ); - - // A customised recipient means it has been touched. - update_post_meta( $form_id, '_srfm_email_notification', [ [ 'status' => true, 'email_to' => 'sales@example.com', 'subject' => 'Hi', 'email_body' => '{all_data}' ] ] ); - $this->assertFalse( Admin::is_default_email_notification( $form_id ) ); - - wp_delete_post( $form_id, true ); - } - - /** - * Embed detection matches the srfm/form block on a published page (#3031). - */ - public function test_form_is_embedded() { - $this->assertFalse( Admin::form_is_embedded( 0 ) ); - - if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { - $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); - } - remove_all_actions( 'wp_insert_post_data' ); - - $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Embed check' ] ); - - // Not placed anywhere yet. - $this->assertFalse( Admin::form_is_embedded( $form_id ) ); - - // Embedded via the srfm/form block on a published page. - $page_id = wp_insert_post( [ 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => 'Has form', 'post_content' => '<!-- wp:srfm/form {"id":' . $form_id . '} /-->' ] ); - $this->assertTrue( Admin::form_is_embedded( $form_id ) ); - - wp_delete_post( $page_id, true ); - wp_delete_post( $form_id, true ); - } - - /** - * The setup-card query returns a card payload or null. + * The setup-card payload is null or a fully-formed card with deep-link URLs (#3031). */ public function test_get_form_setup_card() { $card = Admin::get_form_setup_card(); $this->assertTrue( null === $card || is_array( $card ) ); + + if ( is_array( $card ) ) { + $this->assertArrayHasKey( 'id', $card ); + $this->assertArrayHasKey( 'edit_url', $card ); + // The email/thank-you CTAs must carry their deep-link focus targets. + $this->assertStringContainsString( 'srfm_focus=notifications', (string) ( $card['email_url'] ?? '' ) ); + $this->assertStringContainsString( 'srfm_focus=thankyou', (string) ( $card['thankyou_url'] ?? '' ) ); + } } /** @@ -1078,16 +1012,37 @@ public function test_register_form_setup_widget() { } /** - * The dashboard-widget renderer is callable (#3031). + * The renderer honours the card contract: nothing when there's no card, the + * checklist markup (heading, CTAs, snooze) when there is (#3031). */ public function test_render_form_setup_widget() { - $this->assertTrue( method_exists( Admin::get_instance(), 'render_form_setup_widget' ) ); + $admin = Admin::get_instance(); + $card = Admin::get_form_setup_card(); + + ob_start(); + $admin->render_form_setup_widget(); + $output = (string) ob_get_clean(); + + if ( null === $card ) { + $this->assertSame( '', $output, 'No card → the widget renders nothing.' ); + } else { + $this->assertStringContainsString( 'srfm-setup-checklist', $output ); + $this->assertStringContainsString( 'srfm-setup-checklist__cta', $output ); + $this->assertStringContainsString( 'srfm-setup-checklist-snooze', $output ); + } } /** - * The dashboard-widget asset enqueue is callable (#3031). + * Widget assets never load off the dashboard screen (#3031). */ public function test_enqueue_form_setup_widget_assets() { - $this->assertTrue( method_exists( Admin::get_instance(), 'enqueue_form_setup_widget_assets' ) ); + $admin = Admin::get_instance(); + + wp_dequeue_style( 'srfm-setup-checklist-widget' ); + wp_deregister_style( 'srfm-setup-checklist-widget' ); + + // Wrong hook → the method returns before querying or enqueuing anything. + $admin->enqueue_form_setup_widget_assets( 'edit.php' ); + $this->assertFalse( wp_style_is( 'srfm-setup-checklist-widget', 'enqueued' ), 'Assets must not load outside the dashboard.' ); } } From 5c32de9dd5539fcc7f377cd915fb86411fe42f66 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 18:43:06 +0530 Subject: [PATCH 49/65] Restore is_first_form_created test for check-test-coverage (#3031) is_first_form_created() is a #3031 addition, so it needs a test; I removed it with the dead-predicate cleanup. Restored the behavioural version identical to #3040's so the two branches don't conflict on merge. --- tests/unit/admin/test-admin.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index f690a5e13..0c59e6c0c 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -936,6 +936,25 @@ public function test_is_sureforms_owned_notice_callback() { ); } + /** + * The first-form-created flag follows the stored timestamp option. + */ + public function test_is_first_form_created() { + // No stored timestamp → first form not yet created. + Helper::update_srfm_option( 'first_form_created_at', false ); + $this->assertFalse( Admin::is_first_form_created() ); + + // A positive integer timestamp → first form has been created. + Helper::update_srfm_option( 'first_form_created_at', time() ); + $this->assertTrue( Admin::is_first_form_created() ); + + // A zero/invalid timestamp does not count as created. + Helper::update_srfm_option( 'first_form_created_at', 0 ); + $this->assertFalse( Admin::is_first_form_created() ); + + Helper::update_srfm_option( 'first_form_created_at', false ); + } + /** * The setup-card payload is null or a fully-formed card with deep-link URLs (#3031). */ From 34b28565286ffdfcb9ab9bed6fc700ce636f91d6 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 19:44:07 +0530 Subject: [PATCH 50/65] Address round-3 review on the Thank You prompt (#3030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C-1 (merge fatal): move the #3030 tests into a dedicated Test_Thankyou_Prompt_Notice class so they no longer collide with #3041's test_is_first_form_created() in the shared Test_Getting_Started_Notice. - H-1/H-2 (my B2 regression): the deep-link used the wrong getActiveComplementaryArea scope ('core/edit-post' instead of 'core'), so it never exited early and never switched away from the Block tab. Rewrote the editor-root loop to switch to the Document tab (correct 'core' scope) and stop on a direct deepLinkState.consumed signal set by GeneralSettings, instead of inferring from churning selectors — which also fixes M-1/M-2 (bounded, no preference-fighting). Verified live from the Block tab: switches to Document and opens the dialog. - H-3: notice registers at priority 100 so it can't pre-empt higher-priority display-with-other-notices=false notices (e.g. Astra's version warnings). - H-4/H-5: get_thankyou_prompt_forms() memo is now a resettable static property (+ reset_thankyou_prompt_cache()), so the render test asserts real positive and negative cases with proper preconditions and restores the shared registry. - M-5: validate every payload key the markup reads, not just id/edit_url. - M-7: assert the icon data-URI in the styles test. - Lows: null screen fails closed; deep-link.js window guard fixed and the focus value resolved through the allowlist inside the module. Deferred (noted on the PR): M-3 (Add-New dirty-on-mount), M-4 (negative query cache), and the C-2 placement / AC#5 / AC#7 product decisions. --- admin/admin.php | 57 ++++++++-- src/admin/single-form-settings/Editor.js | 52 ++++----- src/admin/single-form-settings/deep-link.js | 38 +++++-- .../tabs/GeneralSettings.js | 22 ++-- tests/unit/admin/test-admin.php | 102 ++++++++++++++++-- 5 files changed, 201 insertions(+), 70 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 130755308..422ae549f 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -85,6 +85,18 @@ class Admin { */ private static $sureforms_page_default_capability = 'manage_options'; + /** + * Request memo for the "Finish setting up" Thank You prompt (#3030). + * + * A static property (not a function-local static) so tests can reset it via + * reflection / reset_thankyou_prompt_cache() — otherwise the first call pins + * the value for the whole process and the feature is untestable. + * + * @var array<int,array<string,mixed>>|null + * @since x.x.x + */ + private static $thankyou_prompt_cache = null; + /** * Class constructor. * @@ -355,10 +367,8 @@ public static function get_thankyou_prompt_forms() { // Memoized for the request so repeated reads (e.g. the notice render plus // any add-on consumer) share a single query. Sentinel is null, not false, // so a filter returning false (__return_false to disable) still memoizes. - static $cache = null; - - if ( null !== $cache ) { - return $cache; + if ( null !== self::$thankyou_prompt_cache ) { + return self::$thankyou_prompt_cache; } /** @@ -368,10 +378,23 @@ public static function get_thankyou_prompt_forms() { * * @since x.x.x */ - $filtered = apply_filters( 'srfm_thankyou_prompt_forms', self::compute_thankyou_prompt_forms() ); - $cache = is_array( $filtered ) ? $filtered : []; + $filtered = apply_filters( 'srfm_thankyou_prompt_forms', self::compute_thankyou_prompt_forms() ); + self::$thankyou_prompt_cache = is_array( $filtered ) ? $filtered : []; - return $cache; + return self::$thankyou_prompt_cache; + } + + /** + * Clear the request memo for the Thank You prompt (#3030). + * + * Lets tests exercise the memoized public path, and is a safe hook for anything + * that changes which form qualifies (e.g. a form save). + * + * @since x.x.x + * @return void + */ + public static function reset_thankyou_prompt_cache() { + self::$thankyou_prompt_cache = null; } /** @@ -403,11 +426,11 @@ public function render_thankyou_prompt_notice() { return; } - // Everywhere in wp-admin except the main dashboard — the #3031 dashboard - // widget owns the on-dashboard setup nudge. Placement is intentional per #3030. + // Everywhere in wp-admin except the main dashboard. A null screen fails + // closed (return) rather than registering the notice on an unknown screen. $screen = get_current_screen(); - if ( $screen && 'dashboard' === $screen->id ) { + if ( ! $screen || 'dashboard' === $screen->id ) { return; } @@ -427,7 +450,15 @@ public function render_thankyou_prompt_notice() { // result of array_filter()) still exposes the newest prompt at index 0. $prompts = array_values( (array) self::get_thankyou_prompt_forms() ); - if ( empty( $prompts[0] ) || ! is_array( $prompts[0] ) || empty( $prompts[0]['id'] ) || empty( $prompts[0]['edit_url'] ) ) { + // Validate every key build_thankyou_notice_markup() reads, not just id/edit_url + // — a filter returning a partial payload would otherwise trip "Undefined array + // key" warnings and esc_url( null ) deprecations on every admin page. + if ( + empty( $prompts[0] ) || ! is_array( $prompts[0] ) + || empty( $prompts[0]['id'] ) || empty( $prompts[0]['edit_url'] ) + || empty( $prompts[0]['thankyou_url'] ) || empty( $prompts[0]['replies_url'] ) + || ! isset( $prompts[0]['title'] ) + ) { return; } @@ -441,6 +472,10 @@ public function render_thankyou_prompt_notice() { 'class' => 'srfm-thankyou-notice', 'is_dismissible' => true, 'display-with-other-notices' => true, + // Render late so this nudge never pre-empts higher-priority notices + // (e.g. Astra's minimum-version warnings, which are display-with- + // other-notices => false and would be skipped once ours renders). + 'priority' => 100, ] ); diff --git a/src/admin/single-form-settings/Editor.js b/src/admin/single-form-settings/Editor.js index 4e71bb996..08ee46280 100644 --- a/src/admin/single-form-settings/Editor.js +++ b/src/admin/single-form-settings/Editor.js @@ -13,6 +13,7 @@ import { useSelect, useDispatch, select as dataSelect, + dispatch as dataDispatch, } from '@wordpress/data'; import { store as editorStore, @@ -23,7 +24,11 @@ import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as preferencesStore } from '@wordpress/preferences'; import GeneralSettings from './tabs/GeneralSettings.js'; -import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from './deep-link'; +import { + srfmDeepLinkFocus, + SRFM_DEEP_LINK_TABS, + deepLinkState, +} from './deep-link'; import StyleSettings from './tabs/StyleSettings.js'; import InspectorTabs from '@Components/inspector-tabs/InspectorTabs.js'; import InspectorTab, { @@ -88,13 +93,15 @@ const SureformsFormSpecificSettings = () => { // runs from the always-mounted plugin root so the deep-link works regardless // of the user's saved sidebar state. // - // GeneralSettings mounts only when the Document sidebar is open AND the "Form - // Options" panel is expanded — both are user preferences that can be off, and - // an early open during boot gets reverted by the editor's preference restore. - // So re-assert forcePanel() (which opens the sidebar and enables+opens both - // panels) on a short interval from a timer tick — outside the store's - // notification cycle, where the dispatch would be swallowed — until the target - // state is reached, then stop. GeneralSettings then self-opens the tab (once). + // GeneralSettings hosts the Form Settings dialog and self-opens the target tab, + // but it only mounts when the Document sidebar is open AND the "Form Options" + // panel is expanded — both user preferences that can be off, and an early open + // during boot gets reverted by the editor's preference restore. So drive it + // from a timer tick (outside the store's notification cycle, where the dispatch + // would be swallowed): switch to the Document tab, forcePanel() to enable+open + // the panel, and stop the moment GeneralSettings signals it consumed the deep + // link — a direct signal rather than inferring success from churning selectors. + // Bounded so it can never run away. useEffect( () => { if ( ! Object.prototype.hasOwnProperty.call( @@ -110,34 +117,27 @@ const SureformsFormSpecificSettings = () => { // Bound + clear FIRST, so a throwing store method can never keep the // interval alive for the rest of the session. elapsed += 300; - if ( elapsed > 6000 ) { + if ( deepLinkState.consumed || elapsed > 6000 ) { clearInterval( ensureOpen ); return; } - const editor = dataSelect( 'core/editor' ); - if ( ! editor ) { - return; - } - - // The Form Options panel must be open, on the Document tab (the sidebar - // being "open" is true for the Block tab too, where GeneralSettings does - // not render). + // forcePanel() only opens the sidebar when it is fully closed, so it + // won't switch away from the Block tab; force the Document tab first + // (core registers the editor's complementary area under the 'core' + // scope). Skip the dispatch when already there to avoid fighting the + // user each tick. const iface = dataSelect( 'core/interface' ); - const panelOpen = - typeof editor.isEditorPanelOpened === 'function' && - editor.isEditorPanelOpened( - 'srfm-form-specific-settings/srfm-sidebar' - ); const onDocument = iface && typeof iface.getActiveComplementaryArea === 'function' && - iface.getActiveComplementaryArea( 'core/edit-post' ) === + iface.getActiveComplementaryArea( 'core' ) === 'edit-post/document'; - if ( panelOpen && onDocument ) { - clearInterval( ensureOpen ); - return; + if ( ! onDocument ) { + dataDispatch( 'core/edit-post' )?.openGeneralSidebar?.( + 'edit-post/document' + ); } forcePanel(); diff --git a/src/admin/single-form-settings/deep-link.js b/src/admin/single-form-settings/deep-link.js index 530258376..b8b3669d8 100644 --- a/src/admin/single-form-settings/deep-link.js +++ b/src/admin/single-form-settings/deep-link.js @@ -4,22 +4,38 @@ * The dashboard notice opens the editor with ?srfm_focus=… to auto-open a Form * Settings tab. Gutenberg strips unrecognised query args client-side before the * bundle can reliably read them, so PHP surfaces the value as - * `window.srfmDeepLinkFocus` (printed before this bundle) — read that first, - * falling back to the raw URL for safety. + * `window.srfmDeepLinkFocus` (printed before this bundle); read that first, URL + * as fallback. * * Kept in its own dependency-free module so Editor.js, GeneralSettings.js and - * EmailNotification.js share one source: no import cycle (which is why - * EmailNotification previously re-derived the value from `window`, diverging on - * the URL-fallback path) and one place to reason about the contract. + * EmailNotification.js share one source: no import cycle and one place to reason + * about the contract. */ -export const srfmDeepLinkFocus = - ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || - new URLSearchParams( window.location.search ).get( 'srfm_focus' ); -// Maps the ?srfm_focus value to a Form Settings tab id. Read through -// hasOwnProperty (never prototype members) so ?srfm_focus=constructor resolves to -// nothing rather than handing a function to setPopupTab. +// Maps the ?srfm_focus value to a Form Settings tab id. export const SRFM_DEEP_LINK_TABS = { thankyou: 'form_confirmation', notifications: 'email_notification', }; + +// Raw target, guarded so importing this module in a non-browser context +// (jsdom / unit tests) can't ReferenceError on `window`. +const rawDeepLinkFocus = + typeof window === 'undefined' + ? null + : window.srfmDeepLinkFocus || + new URLSearchParams( window.location.search ).get( 'srfm_focus' ); + +// Expose only a value the map recognises (resolved via hasOwnProperty so +// ?srfm_focus=constructor can't reach a prototype member); anything else is ''. +// This keeps the downstream guards belt-and-braces rather than the sole defence. +export const srfmDeepLinkFocus = + rawDeepLinkFocus && + Object.prototype.hasOwnProperty.call( SRFM_DEEP_LINK_TABS, rawDeepLinkFocus ) + ? rawDeepLinkFocus + : ''; + +// Shared signal: GeneralSettings sets `consumed` true once it has mounted and +// dispatched the deep-link, so the editor root's opener loop can stop +// deterministically instead of inferring success from churning store selectors. +export const deepLinkState = { consumed: false }; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index db00d221b..a36589a87 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -12,15 +12,14 @@ import { applyFilters } from '@wordpress/hooks'; import Dialog from '../components/dialog/Dialog'; import { FormRestrictionProvider } from '../components/form-restrictions/context'; import { prepareBlockSlugs } from '@Utils/Helpers'; -import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from '../deep-link'; +import { + srfmDeepLinkFocus, + SRFM_DEEP_LINK_TABS, + deepLinkState, +} from '../deep-link'; let prevMetaHash = ''; -// One deep-link per page load, ever. Module-scoped so a later panel remount -// (switching to the Block tab and back, which unmounts/remounts this component) -// cannot re-fire the open and slam the dialog back over the user's work. -let srfmDeepLinkConsumed = false; - function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -251,11 +250,12 @@ function GeneralSettings( props ) { // This component only mounts once the Form Options panel is open; the editor // root (Editor.js) is responsible for ensuring that (sidebar + panel). Once // mounted, this fires a single synchronous dispatch to the sibling listener - // effect above (declared first, so React registers it before this one runs). - // Consume-once via the module flag so a later panel remount does not reopen - // the dialog on top of the user's work. + // effect above (declared first, so React registers it before this one runs) + // and sets the shared deepLinkState.consumed — which stops the root's opener + // loop and prevents a later panel remount reopening the dialog over the user's + // work. useEffect( () => { - if ( srfmDeepLinkConsumed ) { + if ( deepLinkState.consumed ) { return; } @@ -270,7 +270,7 @@ function GeneralSettings( props ) { return; } - srfmDeepLinkConsumed = true; + deepLinkState.consumed = true; window.dispatchEvent( new CustomEvent( 'srfm-open-form-settings', { detail: { tabId }, diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index dff8bf0b6..00a4bfac0 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -935,6 +935,30 @@ public function test_is_sureforms_owned_notice_callback() { 'A null callback should not be recognised as owned.' ); } +} + +/** + * Tests for the "Finish setting up" Thank You prompt (#3030). + * + * Separate class (not appended to Test_Getting_Started_Notice) so it doesn't + * collide with #3031's tests on merge — both branches otherwise declare + * test_is_first_form_created() in the same class. + */ +class Test_Thankyou_Prompt_Notice extends TestCase { + use Astra_Notices_Helper; + + /** + * Reset shared state between tests — this file has no WP_UnitTestCase rollback. + * + * @return void + */ + protected function tearDown(): void { + wp_set_current_user( 0 ); + Admin::reset_thankyou_prompt_cache(); + remove_all_filters( 'srfm_thankyou_prompt_forms' ); + remove_all_filters( 'srfm_show_thankyou_prompt' ); + parent::tearDown(); + } /** * The first-form-created flag follows the stored timestamp option. @@ -1118,27 +1142,68 @@ public function test_get_thankyou_prompt_forms() { } /** - * The Thank You notice registrar emits nothing when there is no qualifying - * Astra Sites starter-template form (#3030). + * The registrar adds nothing without a qualifying form, and exactly one notice + * with it — asserted on the Astra_Notices registry, with real preconditions so + * the method doesn't just return on its first guard (#3030). */ public function test_render_thankyou_prompt_notice() { $admin = Admin::get_instance(); - $this->assertTrue( method_exists( $admin, 'render_thankyou_prompt_notice' ) ); - if ( ! class_exists( '\Astra_Notices' ) ) { - $this->markTestSkipped( 'Astra_Notices library not loaded.' ); + if ( ! class_exists( '\Astra_Notices' ) || ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'Astra_Notices / CPT not available.' ); } + remove_all_actions( 'wp_insert_post_data' ); - // The method registers with Astra_Notices rather than echoing, so assert on - // the registry: with no qualifying starter-template form in the test DB, - // nothing should be registered. $prop = new \ReflectionProperty( \Astra_Notices::class, 'notices' ); $prop->setAccessible( true ); - $prop->setValue( null, [] ); + $original = $prop->getValue(); - $admin->render_thankyou_prompt_notice(); + // A capable user on a NON-dashboard screen with no prior dismissal — the + // preconditions the method needs before it ever reaches the query. + $admin_user = wp_insert_user( + [ + 'user_login' => 'srfm_ty_render_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_ty_render_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin_user ) ? 0 : (int) $admin_user ); + set_current_screen( 'plugins' ); + delete_user_meta( is_wp_error( $admin_user ) ? 0 : (int) $admin_user, 'srfm-thankyou-prompt' ); + + try { + // Negative: no qualifying starter-template form → nothing registered. + Admin::reset_thankyou_prompt_cache(); + $prop->setValue( null, [] ); + $admin->render_thankyou_prompt_notice(); + $this->assertSame( [], $prop->getValue(), 'No qualifying form → no notice registered.' ); + + // Positive: a starter-template import still on the default Thank You + // message → exactly the srfm-thankyou-prompt notice is registered. + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Positive TY' ] ); + update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); + update_post_meta( + $form_id, + '_srfm_form_confirmation', + [ [ 'confirmation_type' => 'same page', 'message' => \SRFM\Inc\Global_Settings\Global_Settings::get_default_confirmation_message() ] ] + ); - $this->assertSame( [], $prop->getValue(), 'No qualifying form → no notice registered.' ); + Admin::reset_thankyou_prompt_cache(); + $prop->setValue( null, [] ); + $admin->render_thankyou_prompt_notice(); + $ids = wp_list_pluck( (array) $prop->getValue(), 'id' ); + $this->assertContains( 'srfm-thankyou-prompt', $ids, 'A qualifying form registers exactly the prompt notice.' ); + + wp_delete_post( $form_id, true ); + } finally { + $prop->setValue( null, is_array( $original ) ? $original : [] ); + Admin::reset_thankyou_prompt_cache(); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin_user ) ) { + wp_delete_user( (int) $admin_user ); + } + } } /** @@ -1153,6 +1218,21 @@ public function test_print_thankyou_notice_styles() { $this->assertStringContainsString( 'srfm-thankyou-notice', $output ); $this->assertStringContainsString( '#D54407', $output ); + // The SureForms mark is a data-URI background; assert the URI itself so a + // dropped esc_url() protocol allowlist (which blanks it) is caught. + $this->assertStringContainsString( "background: url('data:image/svg+xml,", $output ); + } + + /** + * The prompt cache reset clears the request memo (#3030). + */ + public function test_reset_thankyou_prompt_cache() { + Admin::reset_thankyou_prompt_cache(); + $this->assertIsArray( Admin::get_thankyou_prompt_forms() ); + + // After a reset the next read recomputes rather than returning a pinned value. + Admin::reset_thankyou_prompt_cache(); + $this->assertIsArray( Admin::get_thankyou_prompt_forms() ); } /** From 980c656cbf2f771464ed5ec904cb9de9d32c299d Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Tue, 18 Aug 2026 20:09:54 +0530 Subject: [PATCH 51/65] Address round-2 review on the setup widget (#3041) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - B1: rename test_is_first_form_created → _reflects_stored_timestamp so it can't collide with #3040's same-named test on merge (coverage grep still matches). - B2: bring the deep-link PHP producer (inc/gutenberg-hooks.php's srfm_focus inline script) into this PR so the JS consumer isn't shipped without it; the CTAs no longer fall through to the unreliable URL snapshot. - B3 + testability: get_form_setup_card()'s memo is now a resettable static property (keyed per user) with reset_form_setup_card_cache() + an extracted private compute_form_setup_card(); the card/render tests now seed the trigger meta, reset, and assert the populated path UNCONDITIONALLY (no dead if/else). - Re-synced all four deep-link JS files + gutenberg-hooks.php byte-identical to #3040, which carries the round-3 fixes (correct 'core' getActiveComplementaryArea scope, deepLinkState.consumed signal, Document-tab switch) — so the two PRs stop drifting and this branch inherits the H-1/H-2/M-1/M-2 fixes. - Lows: REST 'action' enum paired with validate_callback (+required) so it's actually enforced; view_url omitted for draft/pending forms (get_permalink 404s); untitled form no longer renders a trailing space. Deferred / product: completion logic + AC #2/#4/#5/#8, ✕ per-form dismiss (M4/AC#6), the single-surface question, and target=_blank on the CTAs (kept per explicit request; Adi suggests same-tab). --- admin/admin.php | 185 +++++++++++------- inc/gutenberg-hooks.php | 11 ++ inc/rest-api.php | 5 + src/admin/single-form-settings/Editor.js | 52 ++--- src/admin/single-form-settings/deep-link.js | 38 ++-- .../tabs/GeneralSettings.js | 22 +-- tests/unit/admin/test-admin.php | 118 +++++++++-- 7 files changed, 289 insertions(+), 142 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index c1e514079..98e461285 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -84,6 +84,20 @@ class Admin { */ private static $sureforms_page_default_capability = 'manage_options'; + /** + * Request memo for the dashboard setup-checklist card (#3031). + * + * A static property (not a function-local static) so tests can reset it via + * reset_form_setup_card_cache() and exercise the populated path — a + * function-local static pins the first result for the whole process. Keyed by + * user id since the payload derives from that user's caps and snooze meta. + * `false` means "not computed yet"; `null`/array is a computed result. + * + * @var array<int,array<string,mixed>|null> + * @since x.x.x + */ + private static $setup_card_cache = []; + /** * Class constructor. * @@ -273,83 +287,30 @@ public static function is_first_form_created() { * @return array<string,mixed>|null Card payload, or null when there is no candidate form. */ public static function get_form_setup_card() { - static $cache = false; + $user_id = get_current_user_id(); - if ( false !== $cache ) { - return $cache; + // Request memo, keyed per user — the payload derives from that user's + // capabilities and snooze meta. Reset via reset_form_setup_card_cache(). + if ( array_key_exists( $user_id, self::$setup_card_cache ) ) { + return self::$setup_card_cache[ $user_id ]; } - $cache = null; - - if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { - return $cache; - } - - $now = time(); - - // "Remind me in two weeks" — a per-user snooze that hides the whole widget. - $widget_snooze_until = (int) get_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, true ); - - if ( $widget_snooze_until > $now ) { - return $cache; - } - - // Only forms created from an Astra Sites starter template — those carry the - // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. - // Prime post + meta caches (the loop reads title, permalink and edit link - // per candidate) so this is a single query, not a follow-up per form. - $query = new \WP_Query( - [ - 'post_type' => SRFM_FORMS_POST_TYPE, - 'post_status' => [ 'publish', 'draft', 'pending' ], - 'posts_per_page' => 10, - 'orderby' => 'date', - 'order' => 'DESC', - 'no_found_rows' => true, - 'update_post_meta_cache' => true, - 'update_post_term_cache' => false, - 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. - [ - 'key' => '_astra_sites_imported_post', - 'compare' => 'EXISTS', - ], - ], - ] - ); - - foreach ( $query->posts as $post ) { - $form_id = (int) $post->ID; - - if ( ! current_user_can( 'edit_post', $form_id ) ) { - continue; - } - - $edit_link = get_edit_post_link( $form_id, 'raw' ); - - if ( empty( $edit_link ) ) { - continue; - } + self::$setup_card_cache[ $user_id ] = self::compute_form_setup_card(); - // The steps are shown as optional next-steps — their completion is not - // computed, so the widget simply lists the actions the owner can take. - $cache = [ - 'id' => $form_id, - 'title' => get_the_title( $form_id ), - 'edit_url' => $edit_link, - // Deep-links to the email-notification panel where supported; falls - // back to opening the editor when the focus handler isn't present. - 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), - // Deep-links to the Form Confirmation panel (the Thank You message). - 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), - // Front-end instant-form page; admins can always view it (the - // non-privileged redirect in Post_Types exempts them). - 'view_url' => (string) get_permalink( $form_id ), - ]; - - return $cache; - } + return self::$setup_card_cache[ $user_id ]; + } - return $cache; + /** + * Clear the setup-card request memo (#3031). + * + * Lets tests exercise the populated path, and is a safe hook for anything that + * changes which form qualifies (e.g. a form save or snooze). + * + * @since x.x.x + * @return void + */ + public static function reset_form_setup_card_cache() { + self::$setup_card_cache = []; } /** @@ -2345,10 +2306,13 @@ public function render_form_setup_widget() { ], ]; - $heading = sprintf( + // Fall back to a generic label for an untitled form so the heading never + // renders "Finish setting up " with a dangling space. + $card_title = '' !== trim( (string) $card['title'] ) ? $card['title'] : __( 'your form', 'sureforms' ); + $heading = sprintf( /* translators: %s: form title. */ __( 'Finish setting up %s', 'sureforms' ), - $card['title'] + $card_title ); ?> <div class="srfm-setup-checklist" id="srfm-setup-checklist"> @@ -2572,6 +2536,79 @@ public function render_dashboard_widget() { <?php } + /** + * Build the setup-card payload (uncached). See get_form_setup_card(). + * + * @since x.x.x + * @return array<string,mixed>|null Card payload, or null when there is no candidate. + */ + private static function compute_form_setup_card() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || ! post_type_exists( SRFM_FORMS_POST_TYPE ) ) { + return null; + } + + // "Remind me in two weeks" — a per-user snooze that hides the whole widget. + if ( (int) get_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, true ) > time() ) { + return null; + } + + // Only forms created from an Astra Sites starter template — those carry the + // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. + // Prime post + meta caches (the loop reads title, permalink and edit link + // per candidate) so this is a single query, not a follow-up per form. + $query = new \WP_Query( + [ + 'post_type' => SRFM_FORMS_POST_TYPE, + 'post_status' => [ 'publish', 'draft', 'pending' ], + 'posts_per_page' => 10, + 'orderby' => 'date', + 'order' => 'DESC', + 'no_found_rows' => true, + 'update_post_meta_cache' => true, + 'update_post_term_cache' => false, + 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. + [ + 'key' => '_astra_sites_imported_post', + 'compare' => 'EXISTS', + ], + ], + ] + ); + + foreach ( $query->posts as $post ) { + $form_id = (int) $post->ID; + + if ( ! current_user_can( 'edit_post', $form_id ) ) { + continue; + } + + $edit_link = get_edit_post_link( $form_id, 'raw' ); + + if ( empty( $edit_link ) ) { + continue; + } + + // The steps are shown as optional next-steps — their completion is not + // computed, so the widget simply lists the actions the owner can take. + return [ + 'id' => $form_id, + 'title' => get_the_title( $form_id ), + 'edit_url' => $edit_link, + // Deep-links to the email-notification panel where supported; falls + // back to opening the editor when the focus handler isn't present. + 'email_url' => add_query_arg( 'srfm_focus', 'notifications', $edit_link ), + // Deep-links to the Form Confirmation panel (the Thank You message). + 'thankyou_url' => add_query_arg( 'srfm_focus', 'thankyou', $edit_link ), + // Front-end instant-form page. get_permalink() only yields a working + // URL for published forms; a draft/pending form has no public URL, so + // omit the view link there (the empty() guard hides the icon). + 'view_url' => 'publish' === $post->post_status ? (string) get_permalink( $form_id ) : '', + ]; + } + + return null; + } + /** * Determine whether a notice callback is owned by SureForms. * diff --git a/inc/gutenberg-hooks.php b/inc/gutenberg-hooks.php index 72786c049..38e92b058 100644 --- a/inc/gutenberg-hooks.php +++ b/inc/gutenberg-hooks.php @@ -150,6 +150,17 @@ public function form_editor_screen_assets() { wp_enqueue_script( SRFM_SLUG . $form_editor_script, SRFM_URL . 'assets/build/formEditor.js', $script_info['dependencies'], $script_info['version'], true ); wp_localize_script( SRFM_SLUG . $form_editor_script, 'scIcons', [ 'path' => SRFM_URL . 'assets/build/icon-assets' ] ); + // Deep-link (#3030): the "Finish setting up" Thank You notice CTA opens this + // editor with ?srfm_focus=… to auto-open a settings tab. Gutenberg strips + // unrecognised query args client-side before the editor bundle can read them, + // so surface the value from the server — where it is never stripped — as a + // global the bundle reads at evaluation time. Validated to a known allowlist. + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only deep-link hint on an authenticated editor screen; no state change. + $srfm_focus = isset( $_GET['srfm_focus'] ) ? sanitize_key( wp_unslash( $_GET['srfm_focus'] ) ) : ''; + if ( in_array( $srfm_focus, [ 'thankyou', 'notifications' ], true ) ) { + wp_add_inline_script( SRFM_SLUG . $form_editor_script, 'window.srfmDeepLinkFocus = ' . wp_json_encode( $srfm_focus ) . ';', 'before' ); + } + // Enqueue the code editor for the Custom CSS Editor in SureForms. wp_enqueue_code_editor( [ 'type' => 'text/css' ] ); wp_enqueue_script( 'wp-theme-plugin-editor' ); diff --git a/inc/rest-api.php b/inc/rest-api.php index 0406e10e6..038c1c25e 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1425,8 +1425,13 @@ private function get_endpoints() { 'sanitize_callback' => 'absint', ], 'action' => [ + 'required' => true, 'type' => 'string', 'enum' => [ 'edit_form', 'edit_thankyou', 'set_up_email', 'view_form', 'snooze' ], + // Core only enforces `enum` via the default arg sanitizer, which + // is skipped once a sanitize_callback is set — so pair it with an + // explicit validate_callback, matching this file's other routes. + 'validate_callback' => 'rest_validate_request_arg', 'sanitize_callback' => 'sanitize_text_field', ], ], diff --git a/src/admin/single-form-settings/Editor.js b/src/admin/single-form-settings/Editor.js index 4e71bb996..08ee46280 100644 --- a/src/admin/single-form-settings/Editor.js +++ b/src/admin/single-form-settings/Editor.js @@ -13,6 +13,7 @@ import { useSelect, useDispatch, select as dataSelect, + dispatch as dataDispatch, } from '@wordpress/data'; import { store as editorStore, @@ -23,7 +24,11 @@ import { store as blockEditorStore } from '@wordpress/block-editor'; import { store as preferencesStore } from '@wordpress/preferences'; import GeneralSettings from './tabs/GeneralSettings.js'; -import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from './deep-link'; +import { + srfmDeepLinkFocus, + SRFM_DEEP_LINK_TABS, + deepLinkState, +} from './deep-link'; import StyleSettings from './tabs/StyleSettings.js'; import InspectorTabs from '@Components/inspector-tabs/InspectorTabs.js'; import InspectorTab, { @@ -88,13 +93,15 @@ const SureformsFormSpecificSettings = () => { // runs from the always-mounted plugin root so the deep-link works regardless // of the user's saved sidebar state. // - // GeneralSettings mounts only when the Document sidebar is open AND the "Form - // Options" panel is expanded — both are user preferences that can be off, and - // an early open during boot gets reverted by the editor's preference restore. - // So re-assert forcePanel() (which opens the sidebar and enables+opens both - // panels) on a short interval from a timer tick — outside the store's - // notification cycle, where the dispatch would be swallowed — until the target - // state is reached, then stop. GeneralSettings then self-opens the tab (once). + // GeneralSettings hosts the Form Settings dialog and self-opens the target tab, + // but it only mounts when the Document sidebar is open AND the "Form Options" + // panel is expanded — both user preferences that can be off, and an early open + // during boot gets reverted by the editor's preference restore. So drive it + // from a timer tick (outside the store's notification cycle, where the dispatch + // would be swallowed): switch to the Document tab, forcePanel() to enable+open + // the panel, and stop the moment GeneralSettings signals it consumed the deep + // link — a direct signal rather than inferring success from churning selectors. + // Bounded so it can never run away. useEffect( () => { if ( ! Object.prototype.hasOwnProperty.call( @@ -110,34 +117,27 @@ const SureformsFormSpecificSettings = () => { // Bound + clear FIRST, so a throwing store method can never keep the // interval alive for the rest of the session. elapsed += 300; - if ( elapsed > 6000 ) { + if ( deepLinkState.consumed || elapsed > 6000 ) { clearInterval( ensureOpen ); return; } - const editor = dataSelect( 'core/editor' ); - if ( ! editor ) { - return; - } - - // The Form Options panel must be open, on the Document tab (the sidebar - // being "open" is true for the Block tab too, where GeneralSettings does - // not render). + // forcePanel() only opens the sidebar when it is fully closed, so it + // won't switch away from the Block tab; force the Document tab first + // (core registers the editor's complementary area under the 'core' + // scope). Skip the dispatch when already there to avoid fighting the + // user each tick. const iface = dataSelect( 'core/interface' ); - const panelOpen = - typeof editor.isEditorPanelOpened === 'function' && - editor.isEditorPanelOpened( - 'srfm-form-specific-settings/srfm-sidebar' - ); const onDocument = iface && typeof iface.getActiveComplementaryArea === 'function' && - iface.getActiveComplementaryArea( 'core/edit-post' ) === + iface.getActiveComplementaryArea( 'core' ) === 'edit-post/document'; - if ( panelOpen && onDocument ) { - clearInterval( ensureOpen ); - return; + if ( ! onDocument ) { + dataDispatch( 'core/edit-post' )?.openGeneralSidebar?.( + 'edit-post/document' + ); } forcePanel(); diff --git a/src/admin/single-form-settings/deep-link.js b/src/admin/single-form-settings/deep-link.js index 530258376..b8b3669d8 100644 --- a/src/admin/single-form-settings/deep-link.js +++ b/src/admin/single-form-settings/deep-link.js @@ -4,22 +4,38 @@ * The dashboard notice opens the editor with ?srfm_focus=… to auto-open a Form * Settings tab. Gutenberg strips unrecognised query args client-side before the * bundle can reliably read them, so PHP surfaces the value as - * `window.srfmDeepLinkFocus` (printed before this bundle) — read that first, - * falling back to the raw URL for safety. + * `window.srfmDeepLinkFocus` (printed before this bundle); read that first, URL + * as fallback. * * Kept in its own dependency-free module so Editor.js, GeneralSettings.js and - * EmailNotification.js share one source: no import cycle (which is why - * EmailNotification previously re-derived the value from `window`, diverging on - * the URL-fallback path) and one place to reason about the contract. + * EmailNotification.js share one source: no import cycle and one place to reason + * about the contract. */ -export const srfmDeepLinkFocus = - ( typeof window !== 'undefined' && window.srfmDeepLinkFocus ) || - new URLSearchParams( window.location.search ).get( 'srfm_focus' ); -// Maps the ?srfm_focus value to a Form Settings tab id. Read through -// hasOwnProperty (never prototype members) so ?srfm_focus=constructor resolves to -// nothing rather than handing a function to setPopupTab. +// Maps the ?srfm_focus value to a Form Settings tab id. export const SRFM_DEEP_LINK_TABS = { thankyou: 'form_confirmation', notifications: 'email_notification', }; + +// Raw target, guarded so importing this module in a non-browser context +// (jsdom / unit tests) can't ReferenceError on `window`. +const rawDeepLinkFocus = + typeof window === 'undefined' + ? null + : window.srfmDeepLinkFocus || + new URLSearchParams( window.location.search ).get( 'srfm_focus' ); + +// Expose only a value the map recognises (resolved via hasOwnProperty so +// ?srfm_focus=constructor can't reach a prototype member); anything else is ''. +// This keeps the downstream guards belt-and-braces rather than the sole defence. +export const srfmDeepLinkFocus = + rawDeepLinkFocus && + Object.prototype.hasOwnProperty.call( SRFM_DEEP_LINK_TABS, rawDeepLinkFocus ) + ? rawDeepLinkFocus + : ''; + +// Shared signal: GeneralSettings sets `consumed` true once it has mounted and +// dispatched the deep-link, so the editor root's opener loop can stop +// deterministically instead of inferring success from churning store selectors. +export const deepLinkState = { consumed: false }; diff --git a/src/admin/single-form-settings/tabs/GeneralSettings.js b/src/admin/single-form-settings/tabs/GeneralSettings.js index db00d221b..a36589a87 100644 --- a/src/admin/single-form-settings/tabs/GeneralSettings.js +++ b/src/admin/single-form-settings/tabs/GeneralSettings.js @@ -12,15 +12,14 @@ import { applyFilters } from '@wordpress/hooks'; import Dialog from '../components/dialog/Dialog'; import { FormRestrictionProvider } from '../components/form-restrictions/context'; import { prepareBlockSlugs } from '@Utils/Helpers'; -import { srfmDeepLinkFocus, SRFM_DEEP_LINK_TABS } from '../deep-link'; +import { + srfmDeepLinkFocus, + SRFM_DEEP_LINK_TABS, + deepLinkState, +} from '../deep-link'; let prevMetaHash = ''; -// One deep-link per page load, ever. Module-scoped so a later panel remount -// (switching to the Block tab and back, which unmounts/remounts this component) -// cannot re-fire the open and slam the dialog back over the user's work. -let srfmDeepLinkConsumed = false; - function GeneralSettings( props ) { const { createNotice, removeNotice } = useDispatch( 'core/notices' ); @@ -251,11 +250,12 @@ function GeneralSettings( props ) { // This component only mounts once the Form Options panel is open; the editor // root (Editor.js) is responsible for ensuring that (sidebar + panel). Once // mounted, this fires a single synchronous dispatch to the sibling listener - // effect above (declared first, so React registers it before this one runs). - // Consume-once via the module flag so a later panel remount does not reopen - // the dialog on top of the user's work. + // effect above (declared first, so React registers it before this one runs) + // and sets the shared deepLinkState.consumed — which stops the root's opener + // loop and prevents a later panel remount reopening the dialog over the user's + // work. useEffect( () => { - if ( srfmDeepLinkConsumed ) { + if ( deepLinkState.consumed ) { return; } @@ -270,7 +270,7 @@ function GeneralSettings( props ) { return; } - srfmDeepLinkConsumed = true; + deepLinkState.consumed = true; window.dispatchEvent( new CustomEvent( 'srfm-open-form-settings', { detail: { tabId }, diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 0c59e6c0c..9629ee66e 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -938,8 +938,11 @@ public function test_is_sureforms_owned_notice_callback() { /** * The first-form-created flag follows the stored timestamp option. + * + * Suffixed name so it doesn't collide with #3040's same-named test on merge + * (both append to Test_Getting_Started_Notice); the coverage grep still matches. */ - public function test_is_first_form_created() { + public function test_is_first_form_created_reflects_stored_timestamp() { // No stored timestamp → first form not yet created. Helper::update_srfm_option( 'first_form_created_at', false ); $this->assertFalse( Admin::is_first_form_created() ); @@ -956,19 +959,63 @@ public function test_is_first_form_created() { } /** - * The setup-card payload is null or a fully-formed card with deep-link URLs (#3031). + * The card is populated for a starter-template form, with deep-link URLs (#3031). + * + * Seeds the trigger meta and resets the request memo so the populated path runs + * on CI — otherwise get_form_setup_card() returns null (nothing stamps the + * marker) and the assertions never execute. */ public function test_get_form_setup_card() { - $card = Admin::get_form_setup_card(); - $this->assertTrue( null === $card || is_array( $card ) ); - - if ( is_array( $card ) ) { - $this->assertArrayHasKey( 'id', $card ); - $this->assertArrayHasKey( 'edit_url', $card ); - // The email/thank-you CTAs must carry their deep-link focus targets. - $this->assertStringContainsString( 'srfm_focus=notifications', (string) ( $card['email_url'] ?? '' ) ); - $this->assertStringContainsString( 'srfm_focus=thankyou', (string) ( $card['thankyou_url'] ?? '' ) ); + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); } + remove_all_actions( 'wp_insert_post_data' ); + + $admin_user = wp_insert_user( + [ + 'user_login' => 'srfm_card_admin_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_card_admin_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin_user ) ? 0 : (int) $admin_user ); + + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Card Form' ] ); + update_post_meta( $form_id, '_astra_sites_imported_post', 1 ); + + try { + Admin::reset_form_setup_card_cache(); + $card = Admin::get_form_setup_card(); + + $this->assertIsArray( $card, 'A starter-template form must yield a card.' ); + $this->assertSame( $form_id, $card['id'] ); + $this->assertNotEmpty( $card['edit_url'] ); + $this->assertStringContainsString( 'srfm_focus=notifications', (string) $card['email_url'] ); + $this->assertStringContainsString( 'srfm_focus=thankyou', (string) $card['thankyou_url'] ); + + // A non-editor gets no card. + wp_set_current_user( 0 ); + Admin::reset_form_setup_card_cache(); + $this->assertNull( Admin::get_form_setup_card(), 'A user who cannot edit the form gets no card.' ); + } finally { + Admin::reset_form_setup_card_cache(); + wp_delete_post( $form_id, true ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin_user ) ) { + wp_delete_user( (int) $admin_user ); + } + } + } + + /** + * Resetting the card memo lets a later read recompute (#3031). + */ + public function test_reset_form_setup_card_cache() { + Admin::reset_form_setup_card_cache(); + $this->assertTrue( null === Admin::get_form_setup_card() || is_array( Admin::get_form_setup_card() ) ); + Admin::reset_form_setup_card_cache(); + $this->assertTrue( null === Admin::get_form_setup_card() || is_array( Admin::get_form_setup_card() ) ); } /** @@ -1031,23 +1078,54 @@ public function test_register_form_setup_widget() { } /** - * The renderer honours the card contract: nothing when there's no card, the - * checklist markup (heading, CTAs, snooze) when there is (#3031). + * The renderer prints the checklist markup for a qualifying form, and nothing + * without one (#3031). Seeds the trigger so the populated path runs on CI. */ public function test_render_form_setup_widget() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); $admin = Admin::get_instance(); - $card = Admin::get_form_setup_card(); - ob_start(); - $admin->render_form_setup_widget(); - $output = (string) ob_get_clean(); + $admin_user = wp_insert_user( + [ + 'user_login' => 'srfm_render_admin_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_render_admin_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin_user ) ? 0 : (int) $admin_user ); + + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Render Form' ] ); + update_post_meta( $form_id, '_astra_sites_imported_post', 1 ); + + try { + // Positive: a qualifying form renders the full checklist. + Admin::reset_form_setup_card_cache(); + ob_start(); + $admin->render_form_setup_widget(); + $output = (string) ob_get_clean(); - if ( null === $card ) { - $this->assertSame( '', $output, 'No card → the widget renders nothing.' ); - } else { $this->assertStringContainsString( 'srfm-setup-checklist', $output ); $this->assertStringContainsString( 'srfm-setup-checklist__cta', $output ); $this->assertStringContainsString( 'srfm-setup-checklist-snooze', $output ); + $this->assertStringContainsString( 'Render Form', $output ); + + // Negative: no card → nothing rendered. + wp_set_current_user( 0 ); + Admin::reset_form_setup_card_cache(); + ob_start(); + $admin->render_form_setup_widget(); + $this->assertSame( '', (string) ob_get_clean(), 'No card → the widget renders nothing.' ); + } finally { + Admin::reset_form_setup_card_cache(); + wp_delete_post( $form_id, true ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin_user ) ) { + wp_delete_user( (int) $admin_user ); + } } } From dddc03896dfbcf51ed7a81838d1231b6560856d4 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 08:51:13 +0530 Subject: [PATCH 52/65] =?UTF-8?q?fix:=20WP7.1=20editor-compat=20review=20?= =?UTF-8?q?=E2=80=94=20rebuild=20gutenberg=20bundle=20(TC-004),=20textarea?= =?UTF-8?q?=20readOnly=20(TC-003/014),=20Helpers=20getBlocks=20store,=20qu?= =?UTF-8?q?ick-bar=20useSelect=20deps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/gutenberg/build/blocks.asset.php | 2 +- modules/gutenberg/build/blocks.js | 2 +- modules/quick-action-sidebar/components/blocks.js | 6 ++---- src/blocks/textarea/components/default.js | 2 ++ src/utils/Helpers.js | 7 ++++++- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/gutenberg/build/blocks.asset.php b/modules/gutenberg/build/blocks.asset.php index ada35333e..3b40d3e7f 100644 --- a/modules/gutenberg/build/blocks.asset.php +++ b/modules/gutenberg/build/blocks.asset.php @@ -1 +1 @@ -<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives', 'wp-rich-text', 'wp-url'), 'version' => '218dd0cb30d1e2883a8e'); +<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-primitives', 'wp-rich-text', 'wp-url'), 'version' => '7de5b2a52e65b2040f2c'); diff --git a/modules/gutenberg/build/blocks.js b/modules/gutenberg/build/blocks.js index bf655444e..187bed39e 100644 --- a/modules/gutenberg/build/blocks.js +++ b/modules/gutenberg/build/blocks.js @@ -3,7 +3,7 @@ (0,M.__)("%s units","sureforms"),t.name),key:t.name},(0,w.createElement)(te.Button,{key:t.unitValue,className:"uagb-range-control__units--"+t.name,isSmall:!0,isPrimary:e.unit.value===t.unitValue,isSecondary:e.unit.value!==t.unitValue,"aria-pressed":e.unit.value===t.unitValue,"aria-label":(0,M.sprintf)(/* translators: abbreviation for units */ /* translators: abbreviation for units */ (0,M.__)("%s units","sureforms"),t.name),onClick:()=>p(t.unitValue)},t.unitValue)))),a})(g)))),(0,w.createElement)("div",{className:"uagb-range-control__mobile-controls"},(0,w.createElement)(te.RangeControl,{value:c,onChange:d,withInputField:!1,allowReset:!1,max:s,min:u,step:e?.step||1,initialPosition:c,marks:e?.marks||!1}),o&&Se&&(0,w.createElement)(te.__experimentalNumberControl,{disabled:e.disabled,isShiftStepEnabled:r,max:s,min:u,onChange:d,value:c,step:e?.step||1})),(0,w.createElement)(pe,{text:e.help})),b)};Ce.defaultProps={label:(0,M.__)("Margin","sureforms"),className:"",allowReset:!0,withInputField:!0,isShiftStepEnabled:!0,max:1/0,min:-1/0,resetFallbackValue:"",placeholder:null,unit:["px","em"],displayUnit:!0,responsive:!1,help:!1,marks:!1};const Me=Ce;function Te(e){const t=(0,V.useSelect)(e=>e("core/edit-post")?.__experimentalGetPreviewDeviceType(),[]),{sizeText:a,size:i,min:l,type:n,typeTablet:o,typeMobile:r,setAttributes:s,sizeLabel:u,sizeTabletText:c,sizeTablet:g,sizeTabletLabel:d,sizeMobileText:p,sizeMobile:h,sizeMobileLabel:m}=e,b={};return b.Desktop=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Me,{...e,label:a,value:i.value||"",min:l,max:200,unit:n,responsive:!0,setAttributes:s,data:{value:i.value,label:u},step:e?.step})),b.Tablet=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Me,{...e,label:c,value:g.value,min:l,max:200,unit:o||n,responsive:!0,setAttributes:s,data:{value:g.value,label:d},step:e?.stepTablet?e?.stepTablet:e?.step})),b.Mobile=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Me,{...e,label:p,value:h.value,min:l,max:200,unit:r||n,responsive:!0,setAttributes:s,data:{value:h.value,label:m},step:e?.stepMobile?e?.stepMobile:e?.step})),(0,w.createElement)("div",{className:"uagb-size-type-field-tabs"},(0,w.createElement)("div",{className:"uagb-responsive-control-inner"},b[t]?b[t]:b.Desktop))}const Ee={ABeeZee:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Abel:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Abhaya Libre":{v:["regular","500","600","700","800"],subset:["latin","latin-ext","sinhala"],weight:["Default","400","500","600","700","800"],i:["normal"]},Aboreto:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Abril Fatface":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Abyssinica SIL":{v:["regular"],subset:["ethiopic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Aclonica:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Acme:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Actor:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Adamina:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Advent Pro":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Aguafina Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Akaya Kanadaka":{v:["regular"],subset:["kannada","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Akaya Telivigala":{v:["regular"],subset:["latin","latin-ext","telugu"],weight:["Default","400"],i:["normal"]},Akronim:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Akshar:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Aladin:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Alata:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Alatsi:{v:["regular"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Albert Sans":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Aldrich:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Alef:{v:["regular","700"],subset:["hebrew","latin"],weight:["Default","400","700"],i:["normal"]},Alegreya:{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},"Alegreya SC":{v:["regular","italic","500","500italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","700","800","900"],i:["normal","italic"]},"Alegreya Sans":{v:["100","100italic","300","300italic","regular","italic","500","500italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","300","400","500","700","800","900"],i:["normal","italic"]},"Alegreya Sans SC":{v:["100","100italic","300","300italic","regular","italic","500","500italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","300","400","500","700","800","900"],i:["normal","italic"]},Aleo:{v:["300","300italic","regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal","italic"]},"Alex Brush":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Alexandria:{v:["100","200","300","regular","500","600","700","800","900"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Alfa Slab One":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Alice:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Alike:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Alike Angular":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Alkalami:{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Alkatra:{v:["regular","500","600","700"],subset:["bengali","devanagari","latin","latin-ext","oriya"],weight:["Default","400","500","600","700"],i:["normal"]},Allan:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Allerta:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Allerta Stencil":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Allison:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Allura:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Almarai:{v:["300","regular","700","800"],subset:["arabic"],weight:["Default","300","400","700","800"],i:["normal"]},Almendra:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Almendra Display":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Almendra SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Alumni Sans":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Alumni Sans Collegiate One":{v:["regular","italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal","italic"]},"Alumni Sans Inline One":{v:["regular","italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal","italic"]},"Alumni Sans Pinstripe":{v:["regular","italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal","italic"]},Amarante:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Amaranth:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},"Amatic SC":{v:["regular","700"],subset:["cyrillic","hebrew","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},Amethysta:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Amiko:{v:["regular","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","600","700"],i:["normal"]},Amiri:{v:["regular","italic","700","700italic"],subset:["arabic","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Amiri Quran":{v:["regular"],subset:["arabic","latin"],weight:["Default","400"],i:["normal"]},Amita:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Anaheim:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Andada Pro":{v:["regular","500","600","700","800","italic","500italic","600italic","700italic","800italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal","italic"]},Andika:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"Anek Bangla":{v:["100","200","300","regular","500","600","700","800"],subset:["bengali","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Devanagari":{v:["100","200","300","regular","500","600","700","800"],subset:["devanagari","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Gujarati":{v:["100","200","300","regular","500","600","700","800"],subset:["gujarati","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Gurmukhi":{v:["100","200","300","regular","500","600","700","800"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Kannada":{v:["100","200","300","regular","500","600","700","800"],subset:["kannada","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Latin":{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Malayalam":{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext","malayalam"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Odia":{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext","oriya"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Tamil":{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext","tamil"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Anek Telugu":{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext","telugu"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},Angkor:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Annie Use Your Telescope":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Anonymous Pro":{v:["regular","italic","700","700italic"],subset:["cyrillic","greek","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Antic:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Antic Didone":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Antic Slab":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Anton:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Antonio:{v:["100","200","300","regular","500","600","700"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},Anuphan:{v:["100","200","300","regular","500","600","700"],subset:["cyrillic-ext","latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},Anybody:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Aoboshi One":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Arapey:{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},Arbutus:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Arbutus Slab":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Architects Daughter":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Archivo:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Archivo Black":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Archivo Narrow":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Are You Serious":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Aref Ruqaa":{v:["regular","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Aref Ruqaa Ink":{v:["regular","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Arima:{v:["100","200","300","regular","500","600","700"],subset:["greek","greek-ext","latin","latin-ext","malayalam","tamil","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},Arimo:{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","hebrew","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},Arizonia:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Armata:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Arsenal:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Artifika:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Arvo:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},Arya:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Asap:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Asap Condensed":{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Asar:{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Asset:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Assistant:{v:["200","300","regular","500","600","700","800"],subset:["hebrew","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},Astloch:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Asul:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Athiti:{v:["200","300","regular","500","600","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},"Atkinson Hyperlegible":{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Atma:{v:["300","regular","500","600","700"],subset:["bengali","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Atomic Age":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Aubrey:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Audiowide:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Autour One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Average:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Average Sans":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Averia Gruesa Libre":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Averia Libre":{v:["300","300italic","regular","italic","700","700italic"],subset:["latin"],weight:["Default","300","400","700"],i:["normal","italic"]},"Averia Sans Libre":{v:["300","300italic","regular","italic","700","700italic"],subset:["latin"],weight:["Default","300","400","700"],i:["normal","italic"]},"Averia Serif Libre":{v:["300","300italic","regular","italic","700","700italic"],subset:["latin"],weight:["Default","300","400","700"],i:["normal","italic"]},"Azeret Mono":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},B612:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},"B612 Mono":{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},"BIZ UDGothic":{v:["regular","700"],subset:["cyrillic","greek-ext","japanese","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"BIZ UDMincho":{v:["regular","700"],subset:["cyrillic","greek-ext","japanese","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"BIZ UDPGothic":{v:["regular","700"],subset:["cyrillic","greek-ext","japanese","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"BIZ UDPMincho":{v:["regular","700"],subset:["cyrillic","greek-ext","japanese","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Babylonica:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bad Script":{v:["regular"],subset:["cyrillic","latin"],weight:["Default","400"],i:["normal"]},Bahiana:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Bahianita:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bai Jamjuree":{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},"Bakbak One":{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ballet:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Baloo 2":{v:["regular","500","600","700","800"],subset:["devanagari","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Bhai 2":{v:["regular","500","600","700","800"],subset:["gujarati","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Bhaijaan 2":{v:["regular","500","600","700","800"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Bhaina 2":{v:["regular","500","600","700","800"],subset:["latin","latin-ext","oriya","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Chettan 2":{v:["regular","500","600","700","800"],subset:["latin","latin-ext","malayalam","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Da 2":{v:["regular","500","600","700","800"],subset:["bengali","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Paaji 2":{v:["regular","500","600","700","800"],subset:["gurmukhi","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Tamma 2":{v:["regular","500","600","700","800"],subset:["kannada","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Tammudu 2":{v:["regular","500","600","700","800"],subset:["latin","latin-ext","telugu","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Baloo Thambi 2":{v:["regular","500","600","700","800"],subset:["latin","latin-ext","tamil","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Balsamiq Sans":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Balthazar:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Bangers:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Barlow:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Barlow Condensed":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Barlow Semi Condensed":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Barriecito:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Barrio:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Basic:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Baskervville:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Battambang:{v:["100","300","regular","700","900"],subset:["khmer","latin"],weight:["Default","100","300","400","700","900"],i:["normal"]},Baumans:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Bayon:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Be Vietnam Pro":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Beau Rivage":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bebas Neue":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Belgrano:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Bellefair:{v:["regular"],subset:["hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Belleza:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Bellota:{v:["300","300italic","regular","italic","700","700italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","300","400","700"],i:["normal","italic"]},"Bellota Text":{v:["300","300italic","regular","italic","700","700italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","300","400","700"],i:["normal","italic"]},BenchNine:{v:["300","regular","700"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal"]},Benne:{v:["regular"],subset:["kannada","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Bentham:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Berkshire Swash":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Besley:{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},"Beth Ellen":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Bevan:{v:["regular","italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal","italic"]},"BhuTuka Expanded One":{v:["regular"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Big Shoulders Display":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Big Shoulders Inline Display":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Big Shoulders Inline Text":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Big Shoulders Stencil Display":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Big Shoulders Stencil Text":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Big Shoulders Text":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Bigelow Rules":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Bigshot One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Bilbo:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bilbo Swash Caps":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},BioRhyme:{v:["200","300","regular","700","800"],subset:["latin","latin-ext"],weight:["Default","200","300","400","700","800"],i:["normal"]},"BioRhyme Expanded":{v:["200","300","regular","700","800"],subset:["latin","latin-ext"],weight:["Default","200","300","400","700","800"],i:["normal"]},Birthstone:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Birthstone Bounce":{v:["regular","500"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500"],i:["normal"]},Biryani:{v:["200","300","regular","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","200","300","400","600","700","800","900"],i:["normal"]},Bitter:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Black And White Picture":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Black Han Sans":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Black Ops One":{v:["regular"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Blaka:{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Blaka Hollow":{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Blaka Ink":{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Blinker:{v:["100","200","300","regular","600","700","800","900"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","600","700","800","900"],i:["normal"]},"Bodoni Moda":{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},Bokor:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Bona Nova":{v:["regular","italic","700"],subset:["cyrillic","cyrillic-ext","greek","hebrew","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Bonbon:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Bonheur Royale":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Boogaloo:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Bowlby One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Bowlby One SC":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Braah One":{v:["regular"],subset:["gurmukhi","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Brawler:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},"Bree Serif":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Bruno Ace":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Bruno Ace SC":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Brygada 1918":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Bubblegum Sans":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Bubbler One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Buda:{v:["300"],subset:["latin"],weight:["Default","300","400"],i:["normal"]},Buenard:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Bungee:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bungee Hairline":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bungee Inline":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bungee Outline":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bungee Shade":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Bungee Spice":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Butcherman:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Butterfly Kids":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Cabin:{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Cabin Condensed":{v:["regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal"]},"Cabin Sketch":{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},"Caesar Dressing":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Cagliostro:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Cairo:{v:["200","300","regular","500","600","700","800","900"],subset:["arabic","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal"]},"Cairo Play":{v:["200","300","regular","500","600","700","800","900"],subset:["arabic","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal"]},Caladea:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Calistoga:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Calligraffitti:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Cambay:{v:["regular","italic","700","700italic"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Cambo:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Candal:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Cantarell:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Cantata One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Cantora One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Capriola:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Caramel:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Carattere:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Cardo:{v:["regular","italic","700"],subset:["greek","greek-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Carlito:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Carme:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Carrois Gothic":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Carrois Gothic SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Carter One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Castoro:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Castoro Titling":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Catamaran:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","tamil"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Caudex:{v:["regular","italic","700","700italic"],subset:["greek","greek-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Caveat:{v:["regular","500","600","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Caveat Brush":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Cedarville Cursive":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Ceviche One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Chakra Petch":{v:["300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},Changa:{v:["200","300","regular","500","600","700","800"],subset:["arabic","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},"Changa One":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},Chango:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Charis SIL":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Charm:{v:["regular","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400","700"],i:["normal"]},Charmonman:{v:["regular","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400","700"],i:["normal"]},Chathura:{v:["100","300","regular","700","800"],subset:["latin","telugu"],weight:["Default","100","300","400","700","800"],i:["normal"]},"Chau Philomene One":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Chela One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Chelsea Market":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Chenla:{v:["regular"],subset:["khmer"],weight:["Default","400"],i:["normal"]},Cherish:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Cherry Bomb One":{v:["regular"],subset:["japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Cherry Cream Soda":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Cherry Swash":{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Chewy:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Chicle:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Chilanka:{v:["regular"],subset:["latin","latin-ext","malayalam"],weight:["Default","400"],i:["normal"]},Chivo:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Chivo Mono":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Chokokutai:{v:["regular"],subset:["japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Chonburi:{v:["regular"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400"],i:["normal"]},Cinzel:{v:["regular","500","600","700","800","900"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700","800","900"],i:["normal"]},"Cinzel Decorative":{v:["regular","700","900"],subset:["latin"],weight:["Default","400","700","900"],i:["normal"]},"Clicker Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Climate Crisis":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Coda:{v:["regular","800"],subset:["latin","latin-ext"],weight:["Default","400","800"],i:["normal"]},"Coda Caption":{v:["800"],subset:["latin","latin-ext"],weight:["Default","400","800"],i:["normal"]},Codystar:{v:["300","regular"],subset:["latin","latin-ext"],weight:["Default","300","400"],i:["normal"]},Coiny:{v:["regular"],subset:["latin","latin-ext","tamil","vietnamese"],weight:["Default","400"],i:["normal"]},Combo:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Comfortaa:{v:["300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Comforter:{v:["regular"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Comforter Brush":{v:["regular"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Comic Neue":{v:["300","300italic","regular","italic","700","700italic"],subset:["latin"],weight:["Default","300","400","700"],i:["normal","italic"]},"Coming Soon":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Comme:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Commissioner:{v:["100","200","300","regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Concert One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Condiment:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Content:{v:["regular","700"],subset:["khmer"],weight:["Default","400","700"],i:["normal"]},"Contrail One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Convergence:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Cookie:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Copse:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Corben:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Corinthia:{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},Cormorant:{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Cormorant Garamond":{v:["300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Cormorant Infant":{v:["300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Cormorant SC":{v:["300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Cormorant Unicase":{v:["300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Cormorant Upright":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Courgette:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Courier Prime":{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Cousine:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","hebrew","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Coustard:{v:["regular","900"],subset:["latin"],weight:["Default","400","900"],i:["normal"]},"Covered By Your Grace":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Crafty Girls":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Creepster:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Crete Round":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Crimson Pro":{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Crimson Text":{v:["regular","italic","600","600italic","700","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","600","700"],i:["normal","italic"]},"Croissant One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Crushed:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Cuprum:{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Cute Font":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Cutive:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Cutive Mono":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"DM Mono":{v:["300","300italic","regular","italic","500","500italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500"],i:["normal","italic"]},"DM Sans":{v:["regular","italic","500","500italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","500","700"],i:["normal","italic"]},"DM Serif Display":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"DM Serif Text":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Damion:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Dancing Script":{v:["regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal"]},Dangrek:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Darker Grotesque":{v:["300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},"Darumadrop One":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"David Libre":{v:["regular","500","700"],subset:["hebrew","latin","latin-ext","vietnamese"],weight:["Default","400","500","700"],i:["normal"]},"Dawning of a New Day":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Days One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Dekko:{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Dela Gothic One":{v:["regular"],subset:["cyrillic","greek","japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Delicious Handrawn":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Delius:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Delius Swash Caps":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Delius Unicase":{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},"Della Respira":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Denk One":{v:["regular"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Devonshire:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Dhurjati:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},"Didact Gothic":{v:["regular"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Diplomata:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Diplomata SC":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Do Hyeon":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Dokdo:{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Domine:{v:["regular","500","600","700"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Donegal One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Dongle:{v:["300","regular","700"],subset:["korean","latin","latin-ext","vietnamese"],weight:["Default","300","400","700"],i:["normal"]},"Doppio One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Dorsa:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Dosis:{v:["200","300","regular","500","600","700","800"],subset:["latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},DotGothic16:{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Dr Sugiyama":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Duru Sans":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},DynaPuff:{v:["regular","500","600","700"],subset:["cyrillic-ext","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},Dynalight:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"EB Garamond":{v:["regular","500","600","700","800","italic","500italic","600italic","700italic","800italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal","italic"]},"Eagle Lake":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"East Sea Dokdo":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Eater:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Economica:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Eczar:{v:["regular","500","600","700","800"],subset:["devanagari","greek","greek-ext","latin","latin-ext"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Edu NSW ACT Foundation":{v:["regular","500","600","700"],subset:["latin"],weight:["Default","400","500","600","700"],i:["normal"]},"Edu QLD Beginner":{v:["regular","500","600","700"],subset:["latin"],weight:["Default","400","500","600","700"],i:["normal"]},"Edu SA Beginner":{v:["regular","500","600","700"],subset:["latin"],weight:["Default","400","500","600","700"],i:["normal"]},"Edu TAS Beginner":{v:["regular","500","600","700"],subset:["latin"],weight:["Default","400","500","600","700"],i:["normal"]},"Edu VIC WA NT Beginner":{v:["regular","500","600","700"],subset:["latin"],weight:["Default","400","500","600","700"],i:["normal"]},"El Messiri":{v:["regular","500","600","700"],subset:["arabic","cyrillic","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},Electrolize:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Elsie:{v:["regular","900"],subset:["latin","latin-ext"],weight:["Default","400","900"],i:["normal"]},"Elsie Swash Caps":{v:["regular","900"],subset:["latin","latin-ext"],weight:["Default","400","900"],i:["normal"]},"Emblema One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Emilys Candy":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Encode Sans":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Encode Sans Condensed":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Encode Sans Expanded":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Encode Sans SC":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Encode Sans Semi Condensed":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Encode Sans Semi Expanded":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Engagement:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Englebert:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Enriqueta:{v:["regular","500","600","700"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},Ephesis:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Epilogue:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Erica One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Esteban:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Estonia:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Euphoria Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ewert:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Exo:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Exo 2":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Expletus Sans":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal","italic"]},Explora:{v:["regular"],subset:["cherokee","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Fahkwang:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},"Familjen Grotesk":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Fanwood Text":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},Farro:{v:["300","regular","500","700"],subset:["latin","latin-ext"],weight:["Default","300","400","500","700"],i:["normal"]},Farsan:{v:["regular"],subset:["gujarati","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Fascinate:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Fascinate Inline":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Faster One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Fasthand:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Fauna One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Faustina:{v:["300","regular","500","600","700","800","300italic","italic","500italic","600italic","700italic","800italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800"],i:["normal","italic"]},Federant:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Federo:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Felipa:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Fenix:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Festive:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Figtree:{v:["300","regular","500","600","700","800","900","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700","800","900"],i:["normal","italic"]},"Finger Paint":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Finlandica:{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Fira Code":{v:["300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Fira Mono":{v:["regular","500","700"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext"],weight:["Default","400","500","700"],i:["normal"]},"Fira Sans":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Fira Sans Condensed":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Fira Sans Extra Condensed":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Fjalla One":{v:["regular"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Fjord One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Flamenco:{v:["300","regular"],subset:["latin"],weight:["Default","300","400"],i:["normal"]},Flavors:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Fleur De Leah":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Flow Block":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Flow Circular":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Flow Rounded":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Foldit:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Fondamento:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Fontdiner Swanky":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Forum:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Fragment Mono":{v:["regular","italic"],subset:["cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Francois One":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Frank Ruhl Libre":{v:["300","regular","500","600","700","800","900"],subset:["hebrew","latin","latin-ext"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},Fraunces:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Freckle Face":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Fredericka the Great":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Fredoka:{v:["300","regular","500","600","700"],subset:["hebrew","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Freehand:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},Fresca:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Frijole:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Fruktur:{v:["regular","italic"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal","italic"]},"Fugaz One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Fuggles:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Fuzzy Bubbles":{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},"GFS Didot":{v:["regular"],subset:["greek"],weight:["Default","400"],i:["normal"]},"GFS Neohellenic":{v:["regular","italic","700","700italic"],subset:["greek"],weight:["Default","400","700"],i:["normal","italic"]},Gabriela:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Gaegu:{v:["300","regular","700"],subset:["korean","latin"],weight:["Default","300","400","700"],i:["normal"]},Gafata:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Gajraj One":{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Galada:{v:["regular"],subset:["bengali","latin"],weight:["Default","400"],i:["normal"]},Galdeano:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Galindo:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Gamja Flower":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Gantari:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Gayathri:{v:["100","regular","700"],subset:["latin","malayalam"],weight:["Default","100","400","700"],i:["normal"]},Gelasio:{v:["regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Gemunu Libre":{v:["200","300","regular","500","600","700","800"],subset:["latin","latin-ext","sinhala"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},Genos:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cherokee","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Gentium Book Plus":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"Gentium Plus":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Geo:{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},Georama:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Geostar:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Geostar Fill":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Germania One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Gideon Roman":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Gidugu:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},"Gilda Display":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Girassol:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Give You Glory":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Glass Antiqua":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Glegoo:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Gloock:{v:["regular"],subset:["cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Gloria Hallelujah":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Glory:{v:["100","200","300","regular","500","600","700","800","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal","italic"]},Gluten:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Goblin One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Gochi Hand":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Goldman:{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},"Golos Text":{v:["regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","500","600","700","800","900"],i:["normal"]},Gorditas:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},"Gothic A1":{v:["100","200","300","regular","500","600","700","800","900"],subset:["korean","latin"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Gotu:{v:["regular"],subset:["devanagari","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Goudy Bookletter 1911":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Gowun Batang":{v:["regular","700"],subset:["korean","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},"Gowun Dodum":{v:["regular"],subset:["korean","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Graduate:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Grand Hotel":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Grandstander:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Grape Nuts":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Gravitas One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Great Vibes":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Grechen Fuemen":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Grenze:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Grenze Gotisch":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Grey Qo":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Griffy:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Gruppo:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Gudea:{v:["regular","italic","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Gugi:{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Gulzar:{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Gupter:{v:["regular","500","700"],subset:["latin"],weight:["Default","400","500","700"],i:["normal"]},Gurajada:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Gwendolyn:{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},Habibi:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Hachi Maru Pop":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Hahmlet:{v:["100","200","300","regular","500","600","700","800","900"],subset:["korean","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Halant:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Hammersmith One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Hanalei:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Hanalei Fill":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Handlee:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Hanken Grotesk":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Hanuman:{v:["100","300","regular","700","900"],subset:["khmer","latin"],weight:["Default","100","300","400","700","900"],i:["normal"]},"Happy Monkey":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Harmattan:{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Headland One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Heebo:{v:["100","200","300","regular","500","600","700","800","900"],subset:["hebrew","latin"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Henny Penny":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Hepta Slab":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Herr Von Muellerhoff":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Hi Melody":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Hina Mincho":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Hind:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Hind Guntur":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","telugu"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Hind Madurai":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","tamil"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Hind Siliguri":{v:["300","regular","500","600","700"],subset:["bengali","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Hind Vadodara":{v:["300","regular","500","600","700"],subset:["gujarati","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Holtwood One SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Homemade Apple":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Homenaje:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Hubballi:{v:["regular"],subset:["kannada","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Hurricane:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"IBM Plex Mono":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},"IBM Plex Sans":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},"IBM Plex Sans Arabic":{v:["100","200","300","regular","500","600","700"],subset:["arabic","cyrillic-ext","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Sans Condensed":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},"IBM Plex Sans Devanagari":{v:["100","200","300","regular","500","600","700"],subset:["cyrillic-ext","devanagari","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Sans Hebrew":{v:["100","200","300","regular","500","600","700"],subset:["cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Sans JP":{v:["100","200","300","regular","500","600","700"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Sans KR":{v:["100","200","300","regular","500","600","700"],subset:["korean","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Sans Thai":{v:["100","200","300","regular","500","600","700"],subset:["cyrillic-ext","latin","latin-ext","thai"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Sans Thai Looped":{v:["100","200","300","regular","500","600","700"],subset:["cyrillic-ext","latin","latin-ext","thai"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"IBM Plex Serif":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},"IM Fell DW Pica":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},"IM Fell DW Pica SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"IM Fell Double Pica":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},"IM Fell Double Pica SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"IM Fell English":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},"IM Fell English SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"IM Fell French Canon":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},"IM Fell French Canon SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"IM Fell Great Primer":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},"IM Fell Great Primer SC":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Ibarra Real Nova":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal","italic"]},Iceberg:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Iceland:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Imbue:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Imperial Script":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Imprima:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Inconsolata:{v:["200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal"]},Inder:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Indie Flower":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Ingrid Darling":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Inika:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Inknut Antiqua":{v:["300","regular","500","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},"Inria Sans":{v:["300","300italic","regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal","italic"]},"Inria Serif":{v:["300","300italic","regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal","italic"]},Inspiration:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Instrument Sans":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Instrument Serif":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Inter:{v:["100","200","300","regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Inter Tight":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Irish Grover":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Island Moments":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Istok Web":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Italiana:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Italianno:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Itim:{v:["regular"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400"],i:["normal"]},"Jacques Francois":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Jacques Francois Shadow":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Jaldi:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"JetBrains Mono":{v:["100","200","300","regular","500","600","700","800","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal","italic"]},"Jim Nightshade":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Joan:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Jockey One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Jolly Lodger":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Jomhuria:{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Jomolhari:{v:["regular"],subset:["latin","tibetan"],weight:["Default","400"],i:["normal"]},"Josefin Sans":{v:["100","200","300","regular","500","600","700","100italic","200italic","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},"Josefin Slab":{v:["100","200","300","regular","500","600","700","100italic","200italic","300italic","italic","500italic","600italic","700italic"],subset:["latin"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},Jost:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Joti One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Jua:{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Judson:{v:["regular","italic","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Julee:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Julius Sans One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Junge:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Jura:{v:["300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","kayah-li","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Just Another Hand":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Just Me Again Down Here":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},K2D:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal","italic"]},Kadwa:{v:["regular","700"],subset:["devanagari","latin"],weight:["Default","400","700"],i:["normal"]},"Kaisei Decol":{v:["regular","500","700"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400","500","700"],i:["normal"]},"Kaisei HarunoUmi":{v:["regular","500","700"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400","500","700"],i:["normal"]},"Kaisei Opti":{v:["regular","500","700"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400","500","700"],i:["normal"]},"Kaisei Tokumin":{v:["regular","500","700","800"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400","500","700","800"],i:["normal"]},Kalam:{v:["300","regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","700"],i:["normal"]},Kameron:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Kanit:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Kantumruy Pro":{v:["100","200","300","regular","500","600","700","100italic","200italic","300italic","italic","500italic","600italic","700italic"],subset:["khmer","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},Karantina:{v:["300","regular","700"],subset:["hebrew","latin","latin-ext"],weight:["Default","300","400","700"],i:["normal"]},Karla:{v:["200","300","regular","500","600","700","800","200italic","300italic","italic","500italic","600italic","700italic","800italic"],subset:["latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal","italic"]},Karma:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Katibeh:{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kaushan Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Kavivanar:{v:["regular"],subset:["latin","latin-ext","tamil"],weight:["Default","400"],i:["normal"]},Kavoon:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kdam Thmor Pro":{v:["regular"],subset:["khmer","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Keania One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kelly Slab":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Kenia:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Khand:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Khmer:{v:["regular"],subset:["khmer"],weight:["Default","400"],i:["normal"]},Khula:{v:["300","regular","600","700","800"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","600","700","800"],i:["normal"]},Kings:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Kirang Haerang":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Kite One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kiwi Maru":{v:["300","regular","500"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","300","400","500"],i:["normal"]},"Klee One":{v:["regular","600"],subset:["cyrillic","greek-ext","japanese","latin","latin-ext"],weight:["Default","400","600"],i:["normal"]},Knewave:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},KoHo:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},Kodchasan:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},"Koh Santepheap":{v:["100","300","regular","700","900"],subset:["khmer","latin"],weight:["Default","100","300","400","700","900"],i:["normal"]},"Kolker Brush":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Konkhmer Sleokchher":{v:["regular"],subset:["khmer","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Kosugi:{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kosugi Maru":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kotta One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Koulen:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},Kranky:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Kreon:{v:["300","regular","500","600","700"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Kristi:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Krona One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Krub:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},Kufam:{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},"Kulim Park":{v:["200","200italic","300","300italic","regular","italic","600","600italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","200","300","400","600","700"],i:["normal","italic"]},"Kumar One":{v:["regular"],subset:["gujarati","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kumar One Outline":{v:["regular"],subset:["gujarati","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Kumbh Sans":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","math"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Kurale:{v:["regular"],subset:["cyrillic","cyrillic-ext","devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"La Belle Aurore":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Labrada:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Lacquer:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Laila:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Lakki Reddy":{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Lalezar:{v:["regular"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Lancelot:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Langar:{v:["regular"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Lateef:{v:["200","300","regular","500","600","700","800"],subset:["arabic","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},Lato:{v:["100","100italic","300","300italic","regular","italic","700","700italic","900","900italic"],subset:["latin","latin-ext"],weight:["Default","100","300","400","700","900"],i:["normal","italic"]},"Lavishly Yours":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"League Gothic":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"League Script":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"League Spartan":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Leckerli One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Ledger:{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Lekton:{v:["regular","italic","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Lemon:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Lemonada:{v:["300","regular","500","600","700"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Lexend:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Deca":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Exa":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Giga":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Mega":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Peta":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Tera":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Lexend Zetta":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Libre Barcode 128":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Barcode 128 Text":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Barcode 39":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Barcode 39 Extended":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Barcode 39 Extended Text":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Barcode 39 Text":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Barcode EAN13 Text":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Libre Baskerville":{v:["regular","italic","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Libre Bodoni":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Libre Caslon Display":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Libre Caslon Text":{v:["regular","italic","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Libre Franklin":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Licorice:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Life Savers":{v:["regular","700","800"],subset:["latin","latin-ext"],weight:["Default","400","700","800"],i:["normal"]},"Lilita One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Lily Script One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Limelight:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Linden Hill":{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},Literata:{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Liu Jian Mao Cao":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},Livvic:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","900","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","900"],i:["normal","italic"]},Lobster:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Lobster Two":{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},"Londrina Outline":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Londrina Shadow":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Londrina Sketch":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Londrina Solid":{v:["100","300","regular","900"],subset:["latin"],weight:["Default","100","300","400","900"],i:["normal"]},"Long Cang":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},Lora:{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},"Love Light":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Love Ya Like A Sister":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Loved by the King":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Lovers Quarrel":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Luckiest Guy":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Lusitana:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Lustria:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Luxurious Roman":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Luxurious Script":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"M PLUS 1":{v:["100","200","300","regular","500","600","700","800","900"],subset:["japanese","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"M PLUS 1 Code":{v:["100","200","300","regular","500","600","700"],subset:["japanese","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"M PLUS 1p":{v:["100","300","regular","500","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","hebrew","japanese","latin","latin-ext","vietnamese"],weight:["Default","100","300","400","500","700","800","900"],i:["normal"]},"M PLUS 2":{v:["100","200","300","regular","500","600","700","800","900"],subset:["japanese","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"M PLUS Code Latin":{v:["100","200","300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"M PLUS Rounded 1c":{v:["100","300","regular","500","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","hebrew","japanese","latin","latin-ext","vietnamese"],weight:["Default","100","300","400","500","700","800","900"],i:["normal"]},"Ma Shan Zheng":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},Macondo:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Macondo Swash Caps":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Mada:{v:["200","300","regular","500","600","700","800","900"],subset:["arabic","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal"]},Magra:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Maiden Orange":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Maitree:{v:["200","300","regular","500","600","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},"Major Mono Display":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Mako:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Mali:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},Mallanna:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Mandali:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Manjari:{v:["100","regular","700"],subset:["latin","latin-ext","malayalam"],weight:["Default","100","400","700"],i:["normal"]},Manrope:{v:["200","300","regular","500","600","700","800"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},Mansalva:{v:["regular"],subset:["greek","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Manuale:{v:["300","regular","500","600","700","800","300italic","italic","500italic","600italic","700italic","800italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800"],i:["normal","italic"]},Marcellus:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Marcellus SC":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Marck Script":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Margarine:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Marhey:{v:["300","regular","500","600","700"],subset:["arabic","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Markazi Text":{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal"]},"Marko One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Marmelad:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Martel:{v:["200","300","regular","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","200","300","400","600","700","800","900"],i:["normal"]},"Martel Sans":{v:["200","300","regular","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","200","300","400","600","700","800","900"],i:["normal"]},"Martian Mono":{v:["100","200","300","regular","500","600","700","800"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},Marvel:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},Mate:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Mate SC":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Material Icons":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Material Icons Outlined":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Material Icons Round":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Material Icons Sharp":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Material Icons Two Tone":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Material Symbols Outlined":{v:["100","200","300","regular","500","600","700"],subset:["latin"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"Material Symbols Rounded":{v:["100","200","300","regular","500","600","700"],subset:["latin"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"Material Symbols Sharp":{v:["100","200","300","regular","500","600","700"],subset:["latin"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"Maven Pro":{v:["regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800","900"],i:["normal"]},McLaren:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Mea Culpa":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Meddon:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},MedievalSharp:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Medula One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Meera Inimai":{v:["regular"],subset:["latin","tamil"],weight:["Default","400"],i:["normal"]},Megrim:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Meie Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Meow Script":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Merienda:{v:["300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},Merriweather:{v:["300","300italic","regular","italic","700","700italic","900","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","700","900"],i:["normal","italic"]},"Merriweather Sans":{v:["300","regular","500","600","700","800","300italic","italic","500italic","600italic","700italic","800italic"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800"],i:["normal","italic"]},Metal:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Metal Mania":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Metamorphous:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Metrophobic:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Michroma:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Milonga:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Miltonian:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Miltonian Tattoo":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Mina:{v:["regular","700"],subset:["bengali","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Mingzat:{v:["regular"],subset:["latin","latin-ext","lepcha"],weight:["Default","400"],i:["normal"]},Miniver:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Miriam Libre":{v:["regular","700"],subset:["hebrew","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Mirza:{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Miss Fajardose":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Mitr:{v:["200","300","regular","500","600","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},"Mochiy Pop One":{v:["regular"],subset:["japanese","latin"],weight:["Default","400"],i:["normal"]},"Mochiy Pop P One":{v:["regular"],subset:["japanese","latin"],weight:["Default","400"],i:["normal"]},Modak:{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Modern Antiqua":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Mogra:{v:["regular"],subset:["gujarati","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Mohave:{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},Molengo:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Molle:{v:["italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Monda:{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},Monofett:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Monomaniac One":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Monoton:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Monsieur La Doulaise":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Montaga:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Montagu Slab":{v:["100","200","300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},MonteCarlo:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Montez:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Montserrat:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Montserrat Alternates":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Montserrat Subrayada":{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},"Moo Lah Lah":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Moon Dance":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Moul:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},Moulpali:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Mountains of Christmas":{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},"Mouse Memoirs":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Mr Bedfort":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Mr Dafoe":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Mr De Haviland":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Mrs Saint Delafield":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Mrs Sheppards":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Ms Madi":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Mukta:{v:["200","300","regular","500","600","700","800"],subset:["devanagari","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},"Mukta Mahee":{v:["200","300","regular","500","600","700","800"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},"Mukta Malar":{v:["200","300","regular","500","600","700","800"],subset:["latin","latin-ext","tamil"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},"Mukta Vaani":{v:["200","300","regular","500","600","700","800"],subset:["gujarati","latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},Mulish:{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Murecho:{v:["100","200","300","regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","japanese","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},MuseoModerno:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"My Soul":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Mynerve:{v:["regular"],subset:["greek","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Mystery Quest":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},NTR:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Nabla:{v:["regular"],subset:["cyrillic-ext","latin","latin-ext","math","vietnamese"],weight:["Default","400"],i:["normal"]},"Nanum Brush Script":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Nanum Gothic":{v:["regular","700","800"],subset:["korean","latin"],weight:["Default","400","700","800"],i:["normal"]},"Nanum Gothic Coding":{v:["regular","700"],subset:["korean","latin"],weight:["Default","400","700"],i:["normal"]},"Nanum Myeongjo":{v:["regular","700","800"],subset:["korean","latin"],weight:["Default","400","700","800"],i:["normal"]},"Nanum Pen Script":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Neonderthaw:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Nerko One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Neucha:{v:["regular"],subset:["cyrillic","latin"],weight:["Default","400"],i:["normal"]},Neuton:{v:["200","300","regular","italic","700","800"],subset:["latin","latin-ext"],weight:["Default","200","300","400","700","800"],i:["normal","italic"]},"New Rocker":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"New Tegomin":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"News Cycle":{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Newsreader:{v:["200","300","regular","500","600","700","800","200italic","300italic","italic","500italic","600italic","700italic","800italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal","italic"]},Niconne:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Niramit:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal","italic"]},"Nixie One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Nobile:{v:["regular","italic","500","500italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","500","700"],i:["normal","italic"]},Nokora:{v:["100","300","regular","700","900"],subset:["khmer","latin"],weight:["Default","100","300","400","700","900"],i:["normal"]},Norican:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Nosifer:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Notable:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nothing You Could Do":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Noticia Text":{v:["regular","italic","700","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"Noto Color Emoji":{v:["regular"],subset:["emoji"],weight:["Default","400"],i:["normal"]},"Noto Emoji":{v:["300","regular","500","600","700"],subset:["emoji"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Noto Kufi Arabic":{v:["100","200","300","regular","500","600","700","800","900"],subset:["arabic"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Music":{v:["regular"],subset:["latin","latin-ext","music"],weight:["Default","400"],i:["normal"]},"Noto Naskh Arabic":{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Nastaliq Urdu":{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Rashi Hebrew":{v:["100","200","300","regular","500","600","700","800","900"],subset:["hebrew","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans":{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["cyrillic","cyrillic-ext","devanagari","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Noto Sans Adlam":{v:["regular","500","600","700"],subset:["adlam","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Adlam Unjoined":{v:["regular","500","600","700"],subset:["adlam","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Anatolian Hieroglyphs":{v:["regular"],subset:["anatolian-hieroglyphs"],weight:["Default","400"],i:["normal"]},"Noto Sans Arabic":{v:["100","200","300","regular","500","600","700","800","900"],subset:["arabic"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Armenian":{v:["100","200","300","regular","500","600","700","800","900"],subset:["armenian","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Avestan":{v:["regular"],subset:["avestan","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Balinese":{v:["regular","500","600","700"],subset:["balinese","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Bamum":{v:["regular","500","600","700"],subset:["bamum","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Bassa Vah":{v:["regular","500","600","700"],subset:["bassa-vah","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Batak":{v:["regular"],subset:["batak","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Bengali":{v:["100","200","300","regular","500","600","700","800","900"],subset:["bengali","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Bhaiksuki":{v:["regular"],subset:["bhaiksuki"],weight:["Default","400"],i:["normal"]},"Noto Sans Brahmi":{v:["regular"],subset:["brahmi"],weight:["Default","400"],i:["normal"]},"Noto Sans Buginese":{v:["regular"],subset:["buginese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Buhid":{v:["regular"],subset:["buhid","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Canadian Aboriginal":{v:["100","200","300","regular","500","600","700","800","900"],subset:["canadian-aboriginal","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Carian":{v:["regular"],subset:["carian"],weight:["Default","400"],i:["normal"]},"Noto Sans Caucasian Albanian":{v:["regular"],subset:["caucasian-albanian"],weight:["Default","400"],i:["normal"]},"Noto Sans Chakma":{v:["regular"],subset:["chakma","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Cham":{v:["100","200","300","regular","500","600","700","800","900"],subset:["cham","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Cherokee":{v:["100","200","300","regular","500","600","700","800","900"],subset:["cherokee","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Chorasmian":{v:["regular"],subset:["chorasmian","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Coptic":{v:["regular"],subset:["coptic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Cuneiform":{v:["regular"],subset:["cuneiform"],weight:["Default","400"],i:["normal"]},"Noto Sans Cypriot":{v:["regular"],subset:["cypriot"],weight:["Default","400"],i:["normal"]},"Noto Sans Deseret":{v:["regular"],subset:["deseret"],weight:["Default","400"],i:["normal"]},"Noto Sans Devanagari":{v:["100","200","300","regular","500","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Display":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Noto Sans Duployan":{v:["regular"],subset:["duployan"],weight:["Default","400"],i:["normal"]},"Noto Sans Egyptian Hieroglyphs":{v:["regular"],subset:["egyptian-hieroglyphs"],weight:["Default","400"],i:["normal"]},"Noto Sans Elbasan":{v:["regular"],subset:["elbasan","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Elymaic":{v:["regular"],subset:["elymaic"],weight:["Default","400"],i:["normal"]},"Noto Sans Ethiopic":{v:["100","200","300","regular","500","600","700","800","900"],subset:["ethiopic","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Georgian":{v:["100","200","300","regular","500","600","700","800","900"],subset:["georgian","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Glagolitic":{v:["regular"],subset:["glagolitic"],weight:["Default","400"],i:["normal"]},"Noto Sans Gothic":{v:["regular"],subset:["gothic"],weight:["Default","400"],i:["normal"]},"Noto Sans Grantha":{v:["regular"],subset:["grantha","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Gujarati":{v:["100","200","300","regular","500","600","700","800","900"],subset:["gujarati","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Gunjala Gondi":{v:["regular"],subset:["gunjala-gondi"],weight:["Default","400"],i:["normal"]},"Noto Sans Gurmukhi":{v:["100","200","300","regular","500","600","700","800","900"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans HK":{v:["100","300","regular","500","700","900"],subset:["chinese-hongkong","latin"],weight:["Default","100","300","400","500","700","900"],i:["normal"]},"Noto Sans Hanifi Rohingya":{v:["regular","500","600","700"],subset:["hanifi-rohingya","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Hanunoo":{v:["regular"],subset:["hanunoo","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Hatran":{v:["regular"],subset:["hatran"],weight:["Default","400"],i:["normal"]},"Noto Sans Hebrew":{v:["100","200","300","regular","500","600","700","800","900"],subset:["hebrew","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Imperial Aramaic":{v:["regular"],subset:["imperial-aramaic"],weight:["Default","400"],i:["normal"]},"Noto Sans Indic Siyaq Numbers":{v:["regular"],subset:["indic-siyaq-numbers"],weight:["Default","400"],i:["normal"]},"Noto Sans Inscriptional Pahlavi":{v:["regular"],subset:["inscriptional-pahlavi"],weight:["Default","400"],i:["normal"]},"Noto Sans Inscriptional Parthian":{v:["regular"],subset:["inscriptional-parthian","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans JP":{v:["100","200","300","regular","500","600","700","800","900"],subset:["cyrillic","japanese","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Javanese":{v:["regular","500","600","700"],subset:["javanese","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans KR":{v:["100","300","regular","500","700","900"],subset:["korean","latin"],weight:["Default","100","300","400","500","700","900"],i:["normal"]},"Noto Sans Kaithi":{v:["regular"],subset:["kaithi"],weight:["Default","400"],i:["normal"]},"Noto Sans Kannada":{v:["100","200","300","regular","500","600","700","800","900"],subset:["kannada","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Kayah Li":{v:["regular","500","600","700"],subset:["kayah-li","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Kharoshthi":{v:["regular"],subset:["kharoshthi","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Khmer":{v:["100","200","300","regular","500","600","700","800","900"],subset:["khmer","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Khojki":{v:["regular"],subset:["khojki","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Sans Khudawadi":{v:["regular"],subset:["khudawadi"],weight:["Default","400"],i:["normal"]},"Noto Sans Lao":{v:["100","200","300","regular","500","600","700","800","900"],subset:["lao","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Lao Looped":{v:["100","200","300","regular","500","600","700","800","900"],subset:["lao","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Lepcha":{v:["regular"],subset:["latin","latin-ext","lepcha"],weight:["Default","400"],i:["normal"]},"Noto Sans Limbu":{v:["regular"],subset:["latin","latin-ext","limbu"],weight:["Default","400"],i:["normal"]},"Noto Sans Linear A":{v:["regular"],subset:["linear-a"],weight:["Default","400"],i:["normal"]},"Noto Sans Linear B":{v:["regular"],subset:["linear-b"],weight:["Default","400"],i:["normal"]},"Noto Sans Lisu":{v:["regular","500","600","700"],subset:["latin","latin-ext","lisu"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Lycian":{v:["regular"],subset:["lycian"],weight:["Default","400"],i:["normal"]},"Noto Sans Lydian":{v:["regular"],subset:["lydian"],weight:["Default","400"],i:["normal"]},"Noto Sans Mahajani":{v:["regular"],subset:["mahajani"],weight:["Default","400"],i:["normal"]},"Noto Sans Malayalam":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","malayalam"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Mandaic":{v:["regular"],subset:["mandaic"],weight:["Default","400"],i:["normal"]},"Noto Sans Manichaean":{v:["regular"],subset:["manichaean"],weight:["Default","400"],i:["normal"]},"Noto Sans Marchen":{v:["regular"],subset:["marchen"],weight:["Default","400"],i:["normal"]},"Noto Sans Masaram Gondi":{v:["regular"],subset:["latin","latin-ext","masaram-gondi"],weight:["Default","400"],i:["normal"]},"Noto Sans Math":{v:["regular"],subset:["math"],weight:["Default","400"],i:["normal"]},"Noto Sans Mayan Numerals":{v:["regular"],subset:["mayan-numerals"],weight:["Default","400"],i:["normal"]},"Noto Sans Medefaidrin":{v:["regular","500","600","700"],subset:["latin","latin-ext","medefaidrin"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Meetei Mayek":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","meetei-mayek"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Mende Kikakui":{v:["regular"],subset:["latin","latin-ext","mende-kikakui"],weight:["Default","400"],i:["normal"]},"Noto Sans Meroitic":{v:["regular"],subset:["meroitic"],weight:["Default","400"],i:["normal"]},"Noto Sans Miao":{v:["regular"],subset:["latin","latin-ext","miao"],weight:["Default","400"],i:["normal"]},"Noto Sans Modi":{v:["regular"],subset:["latin","latin-ext","modi"],weight:["Default","400"],i:["normal"]},"Noto Sans Mongolian":{v:["regular"],subset:["latin","latin-ext","mongolian"],weight:["Default","400"],i:["normal"]},"Noto Sans Mono":{v:["100","200","300","regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Mro":{v:["regular"],subset:["latin","latin-ext","mro"],weight:["Default","400"],i:["normal"]},"Noto Sans Multani":{v:["regular"],subset:["latin","latin-ext","multani"],weight:["Default","400"],i:["normal"]},"Noto Sans Myanmar":{v:["100","200","300","regular","500","600","700","800","900"],subset:["myanmar"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans NKo":{v:["regular"],subset:["latin","latin-ext","nko"],weight:["Default","400"],i:["normal"]},"Noto Sans Nabataean":{v:["regular"],subset:["nabataean"],weight:["Default","400"],i:["normal"]},"Noto Sans Nag Mundari":{v:["regular","500","600","700"],subset:["latin","latin-ext","nag-mundari"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Nandinagari":{v:["regular"],subset:["latin","latin-ext","nandinagari"],weight:["Default","400"],i:["normal"]},"Noto Sans New Tai Lue":{v:["regular","500","600","700"],subset:["latin","latin-ext","new-tai-lue"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Newa":{v:["regular"],subset:["latin","latin-ext","newa"],weight:["Default","400"],i:["normal"]},"Noto Sans Nushu":{v:["regular"],subset:["latin","latin-ext","nushu"],weight:["Default","400"],i:["normal"]},"Noto Sans Ogham":{v:["regular"],subset:["ogham"],weight:["Default","400"],i:["normal"]},"Noto Sans Ol Chiki":{v:["regular","500","600","700"],subset:["latin","latin-ext","ol-chiki"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Old Hungarian":{v:["regular"],subset:["old-hungarian"],weight:["Default","400"],i:["normal"]},"Noto Sans Old Italic":{v:["regular"],subset:["old-italic"],weight:["Default","400"],i:["normal"]},"Noto Sans Old North Arabian":{v:["regular"],subset:["old-north-arabian"],weight:["Default","400"],i:["normal"]},"Noto Sans Old Permic":{v:["regular"],subset:["old-permic"],weight:["Default","400"],i:["normal"]},"Noto Sans Old Persian":{v:["regular"],subset:["old-persian"],weight:["Default","400"],i:["normal"]},"Noto Sans Old Sogdian":{v:["regular"],subset:["old-sogdian"],weight:["Default","400"],i:["normal"]},"Noto Sans Old South Arabian":{v:["regular"],subset:["old-south-arabian"],weight:["Default","400"],i:["normal"]},"Noto Sans Old Turkic":{v:["regular"],subset:["old-turkic"],weight:["Default","400"],i:["normal"]},"Noto Sans Oriya":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","oriya"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Osage":{v:["regular"],subset:["latin","latin-ext","osage"],weight:["Default","400"],i:["normal"]},"Noto Sans Osmanya":{v:["regular"],subset:["latin","latin-ext","osmanya"],weight:["Default","400"],i:["normal"]},"Noto Sans Pahawh Hmong":{v:["regular"],subset:["latin","latin-ext","pahawh-hmong"],weight:["Default","400"],i:["normal"]},"Noto Sans Palmyrene":{v:["regular"],subset:["palmyrene"],weight:["Default","400"],i:["normal"]},"Noto Sans Pau Cin Hau":{v:["regular"],subset:["latin","latin-ext","pau-cin-hau"],weight:["Default","400"],i:["normal"]},"Noto Sans Phags Pa":{v:["regular"],subset:["phags-pa"],weight:["Default","400"],i:["normal"]},"Noto Sans Phoenician":{v:["regular"],subset:["phoenician"],weight:["Default","400"],i:["normal"]},"Noto Sans Psalter Pahlavi":{v:["regular"],subset:["psalter-pahlavi"],weight:["Default","400"],i:["normal"]},"Noto Sans Rejang":{v:["regular"],subset:["latin","latin-ext","rejang"],weight:["Default","400"],i:["normal"]},"Noto Sans Runic":{v:["regular"],subset:["runic"],weight:["Default","400"],i:["normal"]},"Noto Sans SC":{v:["100","300","regular","500","700","900"],subset:["chinese-simplified","latin"],weight:["Default","100","300","400","500","700","900"],i:["normal"]},"Noto Sans Samaritan":{v:["regular"],subset:["samaritan"],weight:["Default","400"],i:["normal"]},"Noto Sans Saurashtra":{v:["regular"],subset:["latin","latin-ext","saurashtra"],weight:["Default","400"],i:["normal"]},"Noto Sans Sharada":{v:["regular"],subset:["latin","latin-ext","sharada"],weight:["Default","400"],i:["normal"]},"Noto Sans Shavian":{v:["regular"],subset:["shavian"],weight:["Default","400"],i:["normal"]},"Noto Sans Siddham":{v:["regular"],subset:["latin","latin-ext","siddham"],weight:["Default","400"],i:["normal"]},"Noto Sans SignWriting":{v:["regular"],subset:["latin","latin-ext","signwriting"],weight:["Default","400"],i:["normal"]},"Noto Sans Sinhala":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","sinhala"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Sogdian":{v:["regular"],subset:["sogdian"],weight:["Default","400"],i:["normal"]},"Noto Sans Sora Sompeng":{v:["regular","500","600","700"],subset:["latin","latin-ext","sora-sompeng"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Soyombo":{v:["regular"],subset:["soyombo"],weight:["Default","400"],i:["normal"]},"Noto Sans Sundanese":{v:["regular","500","600","700"],subset:["latin","latin-ext","sundanese"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Syloti Nagri":{v:["regular"],subset:["latin","latin-ext","syloti-nagri"],weight:["Default","400"],i:["normal"]},"Noto Sans Symbols":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","symbols"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Symbols 2":{v:["regular"],subset:["latin","latin-ext","symbols"],weight:["Default","400"],i:["normal"]},"Noto Sans Syriac":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","syriac"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans TC":{v:["100","300","regular","500","700","900"],subset:["chinese-traditional","latin"],weight:["Default","100","300","400","500","700","900"],i:["normal"]},"Noto Sans Tagalog":{v:["regular"],subset:["latin","latin-ext","tagalog"],weight:["Default","400"],i:["normal"]},"Noto Sans Tagbanwa":{v:["regular"],subset:["latin","latin-ext","tagbanwa"],weight:["Default","400"],i:["normal"]},"Noto Sans Tai Le":{v:["regular"],subset:["latin","latin-ext","tai-le"],weight:["Default","400"],i:["normal"]},"Noto Sans Tai Tham":{v:["regular","500","600","700"],subset:["latin","latin-ext","tai-tham"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Tai Viet":{v:["regular"],subset:["latin","latin-ext","tai-viet"],weight:["Default","400"],i:["normal"]},"Noto Sans Takri":{v:["regular"],subset:["latin","latin-ext","takri"],weight:["Default","400"],i:["normal"]},"Noto Sans Tamil":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","tamil"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Tamil Supplement":{v:["regular"],subset:["tamil-supplement"],weight:["Default","400"],i:["normal"]},"Noto Sans Tangsa":{v:["regular","500","600","700"],subset:["latin","latin-ext","tangsa"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Sans Telugu":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","telugu"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Thaana":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","thaana"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Thai":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","thai"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Thai Looped":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","thai"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Sans Tifinagh":{v:["regular"],subset:["latin","latin-ext","tifinagh"],weight:["Default","400"],i:["normal"]},"Noto Sans Tirhuta":{v:["regular"],subset:["tirhuta"],weight:["Default","400"],i:["normal"]},"Noto Sans Ugaritic":{v:["regular"],subset:["latin","latin-ext","ugaritic"],weight:["Default","400"],i:["normal"]},"Noto Sans Vai":{v:["regular"],subset:["latin","latin-ext","vai"],weight:["Default","400"],i:["normal"]},"Noto Sans Wancho":{v:["regular"],subset:["latin","latin-ext","wancho"],weight:["Default","400"],i:["normal"]},"Noto Sans Warang Citi":{v:["regular"],subset:["latin","latin-ext","warang-citi"],weight:["Default","400"],i:["normal"]},"Noto Sans Yi":{v:["regular"],subset:["latin","latin-ext","yi"],weight:["Default","400"],i:["normal"]},"Noto Sans Zanabazar Square":{v:["regular"],subset:["latin","latin-ext","zanabazar-square"],weight:["Default","400"],i:["normal"]},"Noto Serif":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"Noto Serif Ahom":{v:["regular"],subset:["ahom","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Serif Armenian":{v:["100","200","300","regular","500","600","700","800","900"],subset:["armenian","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Balinese":{v:["regular"],subset:["balinese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Serif Bengali":{v:["100","200","300","regular","500","600","700","800","900"],subset:["bengali","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Devanagari":{v:["100","200","300","regular","500","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Display":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Noto Serif Dogra":{v:["regular"],subset:["dogra"],weight:["Default","400"],i:["normal"]},"Noto Serif Ethiopic":{v:["100","200","300","regular","500","600","700","800","900"],subset:["ethiopic","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Georgian":{v:["100","200","300","regular","500","600","700","800","900"],subset:["georgian","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Grantha":{v:["regular"],subset:["grantha","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Noto Serif Gujarati":{v:["100","200","300","regular","500","600","700","800","900"],subset:["gujarati","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Gurmukhi":{v:["100","200","300","regular","500","600","700","800","900"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif HK":{v:["200","300","regular","500","600","700","800","900"],subset:["chinese-hongkong","cyrillic","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Hebrew":{v:["100","200","300","regular","500","600","700","800","900"],subset:["hebrew","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif JP":{v:["200","300","regular","500","600","700","900"],subset:["japanese","latin"],weight:["Default","200","300","400","500","600","700","900"],i:["normal"]},"Noto Serif KR":{v:["200","300","regular","500","600","700","900"],subset:["korean","latin"],weight:["Default","200","300","400","500","600","700","900"],i:["normal"]},"Noto Serif Kannada":{v:["100","200","300","regular","500","600","700","800","900"],subset:["kannada","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Khmer":{v:["100","200","300","regular","500","600","700","800","900"],subset:["khmer","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Khojki":{v:["regular","500","600","700"],subset:["khojki","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Serif Lao":{v:["100","200","300","regular","500","600","700","800","900"],subset:["lao","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Malayalam":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","malayalam"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Myanmar":{v:["100","200","300","regular","500","600","700","800","900"],subset:["myanmar"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif NP Hmong":{v:["regular","500","600","700"],subset:["latin","nyiakeng-puachue-hmong"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Serif Oriya":{v:["regular","500","600","700"],subset:["latin","latin-ext","oriya"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Serif SC":{v:["200","300","regular","500","600","700","900"],subset:["chinese-simplified","latin"],weight:["Default","200","300","400","500","600","700","900"],i:["normal"]},"Noto Serif Sinhala":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","sinhala"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif TC":{v:["200","300","regular","500","600","700","900"],subset:["chinese-traditional","latin"],weight:["Default","200","300","400","500","600","700","900"],i:["normal"]},"Noto Serif Tamil":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","tamil"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Noto Serif Tangut":{v:["regular"],subset:["latin","latin-ext","tangut"],weight:["Default","400"],i:["normal"]},"Noto Serif Telugu":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","telugu"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Thai":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","thai"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Tibetan":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","tibetan"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Noto Serif Toto":{v:["regular","500","600","700"],subset:["latin","latin-ext","toto"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Serif Yezidi":{v:["regular","500","600","700"],subset:["yezidi"],weight:["Default","400","500","600","700"],i:["normal"]},"Noto Traditional Nushu":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","nushu"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Nova Cut":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nova Flat":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nova Mono":{v:["regular"],subset:["greek","latin"],weight:["Default","400"],i:["normal"]},"Nova Oval":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nova Round":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nova Script":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nova Slim":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Nova Square":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Numans:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Nunito:{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Nunito Sans":{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Nuosu SIL":{v:["regular"],subset:["latin","latin-ext","yi"],weight:["Default","400"],i:["normal"]},"Odibee Sans":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Odor Mean Chey":{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},Offside:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Oi:{v:["regular"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","tamil","vietnamese"],weight:["Default","400"],i:["normal"]},"Old Standard TT":{v:["regular","italic","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Oldenburg:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ole:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Oleo Script":{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Oleo Script Swash Caps":{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Oooh Baby":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Open Sans":{v:["300","regular","500","600","700","800","300italic","italic","500italic","600italic","700italic","800italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","hebrew","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800"],i:["normal","italic"]},Oranienbaum:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Orbitron:{v:["regular","500","600","700","800","900"],subset:["latin"],weight:["Default","400","500","600","700","800","900"],i:["normal"]},Oregano:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Orelega One":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Orienta:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Original Surfer":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Oswald:{v:["200","300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},Outfit:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Over the Rainbow":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Overlock:{v:["regular","italic","700","700italic","900","900italic"],subset:["latin","latin-ext"],weight:["Default","400","700","900"],i:["normal","italic"]},"Overlock SC":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Overpass:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Overpass Mono":{v:["300","regular","500","600","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Ovo:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Oxanium:{v:["200","300","regular","500","600","700","800"],subset:["latin","latin-ext"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},Oxygen:{v:["300","regular","700"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal"]},"Oxygen Mono":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"PT Mono":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"PT Sans":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"PT Sans Caption":{v:["regular","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"PT Sans Narrow":{v:["regular","700"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"PT Serif":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"PT Serif Caption":{v:["regular","italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Pacifico:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Padauk:{v:["regular","700"],subset:["latin","latin-ext","myanmar"],weight:["Default","400","700"],i:["normal"]},"Padyakke Expanded One":{v:["regular"],subset:["kannada","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Palanquin:{v:["100","200","300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700"],i:["normal"]},"Palanquin Dark":{v:["regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},Pangolin:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Paprika:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Parisienne:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Passero One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Passion One":{v:["regular","700","900"],subset:["latin","latin-ext"],weight:["Default","400","700","900"],i:["normal"]},"Passions Conflict":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Pathway Extreme":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Pathway Gothic One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Patrick Hand":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Patrick Hand SC":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Pattaya:{v:["regular"],subset:["cyrillic","latin","latin-ext","thai","vietnamese"],weight:["Default","400"],i:["normal"]},"Patua One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Pavanam:{v:["regular"],subset:["latin","latin-ext","tamil"],weight:["Default","400"],i:["normal"]},"Paytone One":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Peddana:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Peralta:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Permanent Marker":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Petemoss:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Petit Formal Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Petrona:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Philosopher:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},Phudu:{v:["300","regular","500","600","700","800","900"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},Piazzolla:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Piedra:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Pinyon Script":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Pirata One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Plaster:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Play:{v:["regular","700"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},Playball:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Playfair:{v:["300","regular","500","600","700","800","900","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800","900"],i:["normal","italic"]},"Playfair Display":{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},"Playfair Display SC":{v:["regular","italic","700","700italic","900","900italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","400","700","900"],i:["normal","italic"]},"Plus Jakarta Sans":{v:["200","300","regular","500","600","700","800","200italic","300italic","italic","500italic","600italic","700italic","800italic"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal","italic"]},Podkova:{v:["regular","500","600","700","800"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Poiret One":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Poller One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Poltawski Nowy":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},Poly:{v:["regular","italic"],subset:["latin"],weight:["Default","400"],i:["normal","italic"]},Pompiere:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Pontano Sans":{v:["300","regular","500","600","700"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Poor Story":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Poppins:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["devanagari","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Port Lligat Sans":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Port Lligat Slab":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Potta One":{v:["regular"],subset:["japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Pragati Narrow":{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Praise:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Prata:{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","vietnamese"],weight:["Default","400"],i:["normal"]},Preahvihear:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},"Press Start 2P":{v:["regular"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Pridi:{v:["200","300","regular","500","600","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},"Princess Sofia":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Prociono:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Prompt:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Prosto One":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Proza Libre":{v:["regular","italic","500","500italic","600","600italic","700","700italic","800","800italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700","800"],i:["normal","italic"]},"Public Sans":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Puppies Play":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Puritan:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},"Purple Purse":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Qahiri:{v:["regular"],subset:["arabic","latin"],weight:["Default","400"],i:["normal"]},Quando:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Quantico:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},Quattrocento:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Quattrocento Sans":{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Questrial:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Quicksand:{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Quintessential:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Qwigley:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Qwitcher Grypen":{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},"Racing Sans One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Radio Canada":{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["canadian-aboriginal","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},Radley:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Rajdhani:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Rakkas:{v:["regular"],subset:["arabic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Raleway:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Raleway Dots":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ramabhadra:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Ramaraja:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Rambla:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Rammetto One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rampart One":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ranchers:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Rancho:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Ranga:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Rasa:{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["gujarati","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},Rationale:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Ravi Prakash":{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},"Readex Pro":{v:["200","300","regular","500","600","700"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},Recursive:{v:["300","regular","500","600","700","800","900"],subset:["cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},"Red Hat Display":{v:["300","regular","500","600","700","800","900","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700","800","900"],i:["normal","italic"]},"Red Hat Mono":{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Red Hat Text":{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Red Rose":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Redacted:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Redacted Script":{v:["300","regular","700"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal"]},Redressed:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Reem Kufi":{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal"]},"Reem Kufi Fun":{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal"]},"Reem Kufi Ink":{v:["regular"],subset:["arabic","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Reenie Beanie":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Reggae One":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Revalia:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rhodium Libre":{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ribeye:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Ribeye Marrow":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Righteous:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Risque:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Road Rage":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Roboto:{v:["100","100italic","300","300italic","regular","italic","500","500italic","700","700italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","300","400","500","700","900"],i:["normal","italic"]},"Roboto Condensed":{v:["300","300italic","regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","700"],i:["normal","italic"]},"Roboto Flex":{v:["regular"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Roboto Mono":{v:["100","200","300","regular","500","600","700","100italic","200italic","300italic","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700"],i:["normal","italic"]},"Roboto Serif":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Roboto Slab":{v:["100","200","300","regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Rochester:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Rock Salt":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"RocknRoll One":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Rokkitt:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Romanesco:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Ropa Sans":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Rosario:{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},Rosarivo:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Rouge Script":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Rowdies:{v:["300","regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","700"],i:["normal"]},"Rozha One":{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Rubik:{v:["300","regular","500","600","700","800","900","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","300","400","500","600","700","800","900"],i:["normal","italic"]},"Rubik 80s Fade":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Beastly":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Bubbles":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Burned":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Dirt":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Distressed":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Gemstones":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Glitch":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Iso":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Marker Hatch":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Maze":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Microbe":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Mono One":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Moonrocks":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Pixels":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Puddles":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Spray Paint":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Storm":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Vinyl":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rubik Wet Paint":{v:["regular"],subset:["cyrillic","cyrillic-ext","hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ruda:{v:["regular","500","600","700","800","900"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800","900"],i:["normal"]},Rufina:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Ruge Boogie":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Ruluko:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Rum Raisin":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Ruslan Display":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Russo One":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Ruthie:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Rye:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"STIX Two Text":{v:["regular","500","600","700","italic","500italic","600italic","700italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700"],i:["normal","italic"]},Sacramento:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Sahitya:{v:["regular","700"],subset:["devanagari","latin"],weight:["Default","400","700"],i:["normal"]},Sail:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Saira:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Saira Condensed":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Saira Extra Condensed":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Saira Semi Condensed":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Saira Stencil One":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Salsa:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Sanchez:{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},Sancreek:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Sansita:{v:["regular","italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext"],weight:["Default","400","700","800","900"],i:["normal","italic"]},"Sansita Swashed":{v:["300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800","900"],i:["normal"]},Sarabun:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal","italic"]},Sarala:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Sarina:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Sarpanch:{v:["regular","500","600","700","800","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","500","600","700","800","900"],i:["normal"]},"Sassy Frass":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Satisfy:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Sawarabi Gothic":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Sawarabi Mincho":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Scada:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Scheherazade New":{v:["regular","500","600","700"],subset:["arabic","latin","latin-ext"],weight:["Default","400","500","600","700"],i:["normal"]},"Schibsted Grotesk":{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},Schoolbell:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Scope One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Seaweed Script":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Secular One":{v:["regular"],subset:["hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Sedgwick Ave":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Sedgwick Ave Display":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Sen:{v:["regular","700","800"],subset:["latin","latin-ext"],weight:["Default","400","700","800"],i:["normal"]},"Send Flowers":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Sevillana:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Seymour One":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Shadows Into Light":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Shadows Into Light Two":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Shalimar:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Shantell Sans":{v:["300","regular","500","600","700","800","300italic","italic","500italic","600italic","700italic","800italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700","800"],i:["normal","italic"]},Shanti:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Share:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},"Share Tech":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Share Tech Mono":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Shippori Antique":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Shippori Antique B1":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Shippori Mincho":{v:["regular","500","600","700","800"],subset:["japanese","latin","latin-ext"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Shippori Mincho B1":{v:["regular","500","600","700","800"],subset:["japanese","latin","latin-ext"],weight:["Default","400","500","600","700","800"],i:["normal"]},Shojumaru:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Short Stack":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Shrikhand:{v:["regular"],subset:["gujarati","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Siemreap:{v:["regular"],subset:["khmer"],weight:["Default","400"],i:["normal"]},Sigmar:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Sigmar One":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Signika:{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Signika Negative":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},Silkscreen:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Simonetta:{v:["regular","italic","900","900italic"],subset:["latin","latin-ext"],weight:["Default","400","900"],i:["normal","italic"]},"Single Day":{v:["regular"],subset:["korean"],weight:["Default","400"],i:["normal"]},Sintony:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Sirin Stencil":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Six Caps":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Skranji:{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},"Slabo 13px":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Slabo 27px":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Slackey:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Slackside One":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Smokum:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Smooch:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Smooch Sans":{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Smythe:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Sniglet:{v:["regular","800"],subset:["latin","latin-ext"],weight:["Default","400","800"],i:["normal"]},Snippet:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Snowburst One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Sofadi One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Sofia:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Sofia Sans":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Sofia Sans Condensed":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Sofia Sans Extra Condensed":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Sofia Sans Semi Condensed":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Solitreo:{v:["regular"],subset:["hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Solway:{v:["300","regular","500","700","800"],subset:["latin"],weight:["Default","300","400","500","700","800"],i:["normal"]},"Song Myung":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},Sono:{v:["200","300","regular","500","600","700","800"],subset:["latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},"Sonsie One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Sora:{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},"Sorts Mill Goudy":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Source Code Pro":{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Source Sans 3":{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Source Sans Pro":{v:["200","200italic","300","300italic","regular","italic","600","600italic","700","700italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","600","700","900"],i:["normal","italic"]},"Source Serif 4":{v:["200","300","regular","500","600","700","800","900","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Source Serif Pro":{v:["200","200italic","300","300italic","regular","italic","600","600italic","700","700italic","900","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","600","700","900"],i:["normal","italic"]},"Space Grotesk":{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Space Mono":{v:["regular","italic","700","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"Special Elite":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Spectral:{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal","italic"]},"Spectral SC":{v:["200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800"],i:["normal","italic"]},"Spicy Rice":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Spinnaker:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Spirax:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Splash:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Spline Sans":{v:["300","regular","500","600","700"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Spline Sans Mono":{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Squada One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Square Peg":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Sree Krushnadevaraya":{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Sriracha:{v:["regular"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400"],i:["normal"]},Srisakdi:{v:["regular","700"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400","700"],i:["normal"]},Staatliches:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Stalemate:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Stalinist One":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Stardos Stencil":{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Stick:{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Stick No Bills":{v:["200","300","regular","500","600","700","800"],subset:["latin","latin-ext","sinhala"],weight:["Default","200","300","400","500","600","700","800"],i:["normal"]},"Stint Ultra Condensed":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Stint Ultra Expanded":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Stoke:{v:["300","regular"],subset:["latin","latin-ext"],weight:["Default","300","400"],i:["normal"]},Strait:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Style Script":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Stylish:{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Sue Ellen Francisco":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Suez One":{v:["regular"],subset:["hebrew","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Sulphur Point":{v:["300","regular","700"],subset:["latin","latin-ext"],weight:["Default","300","400","700"],i:["normal"]},Sumana:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Sunflower:{v:["300","500","700"],subset:["korean","latin"],weight:["Default","300","400","500","700"],i:["normal"]},Sunshiney:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Supermercado One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Sura:{v:["regular","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","700"],i:["normal"]},Suranna:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Suravaram:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Suwannaphum:{v:["100","300","regular","700","900"],subset:["khmer","latin"],weight:["Default","100","300","400","700","900"],i:["normal"]},"Swanky and Moo Moo":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Syncopate:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Syne:{v:["regular","500","600","700","800"],subset:["greek","latin","latin-ext"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Syne Mono":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Syne Tactile":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Tai Heritage Pro":{v:["regular","700"],subset:["latin","latin-ext","tai-viet","vietnamese"],weight:["Default","400","700"],i:["normal"]},Tajawal:{v:["200","300","regular","500","700","800","900"],subset:["arabic","latin"],weight:["Default","200","300","400","500","700","800","900"],i:["normal"]},Tangerine:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Tapestry:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Taprom:{v:["regular"],subset:["khmer","latin"],weight:["Default","400"],i:["normal"]},Tauri:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Taviraj:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Teko:{v:["300","regular","500","600","700"],subset:["devanagari","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},Telex:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Tenali Ramakrishna":{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},"Tenor Sans":{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Text Me One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Texturina:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Thasadith:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"The Girl Next Door":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"The Nautigal":{v:["regular","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal"]},Tienne:{v:["regular","700","900"],subset:["latin"],weight:["Default","400","700","900"],i:["normal"]},Tillana:{v:["regular","500","600","700","800"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Tilt Neon":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Tilt Prism":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Tilt Warp":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Timmana:{v:["regular"],subset:["latin","telugu"],weight:["Default","400"],i:["normal"]},Tinos:{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","hebrew","latin","latin-ext","vietnamese"],weight:["Default","400","700"],i:["normal","italic"]},"Tiro Bangla":{v:["regular","italic"],subset:["bengali","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Tiro Devanagari Hindi":{v:["regular","italic"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Tiro Devanagari Marathi":{v:["regular","italic"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Tiro Devanagari Sanskrit":{v:["regular","italic"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Tiro Gurmukhi":{v:["regular","italic"],subset:["gurmukhi","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Tiro Kannada":{v:["regular","italic"],subset:["kannada","latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Tiro Tamil":{v:["regular","italic"],subset:["latin","latin-ext","tamil"],weight:["Default","400"],i:["normal","italic"]},"Tiro Telugu":{v:["regular","italic"],subset:["latin","latin-ext","telugu"],weight:["Default","400"],i:["normal","italic"]},"Titan One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Titillium Web":{v:["200","200italic","300","300italic","regular","italic","600","600italic","700","700italic","900"],subset:["latin","latin-ext"],weight:["Default","200","300","400","600","700","900"],i:["normal","italic"]},Tomorrow:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Tourney:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Trade Winds":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Train One":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Trirong:{v:["100","100italic","200","200italic","300","300italic","regular","italic","500","500italic","600","600italic","700","700italic","800","800italic","900","900italic"],subset:["latin","latin-ext","thai","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},Trispace:{v:["100","200","300","regular","500","600","700","800"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800"],i:["normal"]},Trocchi:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Trochut:{v:["regular","italic","700"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},Truculenta:{v:["100","200","300","regular","500","600","700","800","900"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},Trykker:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Tsukimi Rounded":{v:["300","regular","500","600","700"],subset:["japanese","latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Tulpen One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Turret Road":{v:["200","300","regular","500","700","800"],subset:["latin","latin-ext"],weight:["Default","200","300","400","500","700","800"],i:["normal"]},"Twinkle Star":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Ubuntu:{v:["300","300italic","regular","italic","500","500italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext"],weight:["Default","300","400","500","700"],i:["normal","italic"]},"Ubuntu Condensed":{v:["regular"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Ubuntu Mono":{v:["regular","italic","700","700italic"],subset:["cyrillic","cyrillic-ext","greek","greek-ext","latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Uchen:{v:["regular"],subset:["latin","tibetan"],weight:["Default","400"],i:["normal"]},Ultra:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Unbounded:{v:["200","300","regular","500","600","700","800","900"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700","800","900"],i:["normal"]},"Uncial Antiqua":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Underdog:{v:["regular"],subset:["cyrillic","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Unica One":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},UnifrakturCook:{v:["700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},UnifrakturMaguntia:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Unkempt:{v:["regular","700"],subset:["latin"],weight:["Default","400","700"],i:["normal"]},Unlock:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Unna:{v:["regular","italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal","italic"]},Updock:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Urbanist:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},VT323:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Vampiro One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Varela:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Varela Round":{v:["regular"],subset:["hebrew","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Varta:{v:["300","regular","500","600","700"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal"]},"Vast Shadow":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Vazirmatn:{v:["100","200","300","regular","500","600","700","800","900"],subset:["arabic","latin","latin-ext"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal"]},"Vesper Libre":{v:["regular","500","700","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","400","500","700","900"],i:["normal"]},"Viaoda Libre":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Vibes:{v:["regular"],subset:["arabic","latin"],weight:["Default","400"],i:["normal"]},Vibur:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Vidaloka:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Viga:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Vina Sans":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Voces:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Volkhov:{v:["regular","italic","700","700italic"],subset:["latin"],weight:["Default","400","700"],i:["normal","italic"]},Vollkorn:{v:["regular","500","600","700","800","900","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800","900"],i:["normal","italic"]},"Vollkorn SC":{v:["regular","600","700","900"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","600","700","900"],i:["normal"]},Voltaire:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Vujahday Script":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},"Waiting for the Sunrise":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Wallpoet:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Walter Turncoat":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Warnes:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Water Brush":{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Waterfall:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Wellfleet:{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Wendy One":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Whisper:{v:["regular"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},WindSong:{v:["regular","500"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400","500"],i:["normal"]},"Wire One":{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Wix Madefor Display":{v:["regular","500","600","700","800"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal"]},"Wix Madefor Text":{v:["regular","italic","500","500italic","600","600italic","700","700italic","800","800italic"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400","500","600","700","800"],i:["normal","italic"]},"Work Sans":{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Xanh Mono":{v:["regular","italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal","italic"]},Yaldevi:{v:["200","300","regular","500","600","700"],subset:["latin","latin-ext","sinhala"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},"Yanone Kaffeesatz":{v:["200","300","regular","500","600","700"],subset:["cyrillic","latin","latin-ext","vietnamese"],weight:["Default","200","300","400","500","600","700"],i:["normal"]},Yantramanav:{v:["100","300","regular","500","700","900"],subset:["devanagari","latin","latin-ext"],weight:["Default","100","300","400","500","700","900"],i:["normal"]},"Yatra One":{v:["regular"],subset:["devanagari","latin","latin-ext"],weight:["Default","400"],i:["normal"]},Yellowtail:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Yeon Sung":{v:["regular"],subset:["korean","latin"],weight:["Default","400"],i:["normal"]},"Yeseva One":{v:["regular"],subset:["cyrillic","cyrillic-ext","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Yesteryear:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},Yomogi:{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext","vietnamese"],weight:["Default","400"],i:["normal"]},Yrsa:{v:["300","regular","500","600","700","300italic","italic","500italic","600italic","700italic"],subset:["latin","latin-ext","vietnamese"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},Ysabeau:{v:["100","200","300","regular","500","600","700","800","900","100italic","200italic","300italic","italic","500italic","600italic","700italic","800italic","900italic"],subset:["cyrillic","cyrillic-ext","greek","latin","latin-ext","vietnamese"],weight:["Default","100","200","300","400","500","600","700","800","900"],i:["normal","italic"]},"Yuji Boku":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Yuji Mai":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Yuji Syuku":{v:["regular"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Yusei Magic":{v:["regular"],subset:["japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"ZCOOL KuaiLe":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},"ZCOOL QingKe HuangYou":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},"ZCOOL XiaoWei":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},"Zen Antique":{v:["regular"],subset:["cyrillic","greek","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Zen Antique Soft":{v:["regular"],subset:["cyrillic","greek","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Zen Dots":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Zen Kaku Gothic Antique":{v:["300","regular","500","700","900"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","300","400","500","700","900"],i:["normal"]},"Zen Kaku Gothic New":{v:["300","regular","500","700","900"],subset:["cyrillic","japanese","latin","latin-ext"],weight:["Default","300","400","500","700","900"],i:["normal"]},"Zen Kurenaido":{v:["regular"],subset:["cyrillic","greek","japanese","latin","latin-ext"],weight:["Default","400"],i:["normal"]},"Zen Loop":{v:["regular","italic"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal","italic"]},"Zen Maru Gothic":{v:["300","regular","500","700","900"],subset:["cyrillic","greek","japanese","latin","latin-ext"],weight:["Default","300","400","500","700","900"],i:["normal"]},"Zen Old Mincho":{v:["regular","500","600","700","900"],subset:["cyrillic","greek","japanese","latin","latin-ext"],weight:["Default","400","500","600","700","900"],i:["normal"]},"Zen Tokyo Zoo":{v:["regular"],subset:["latin","latin-ext"],weight:["Default","400"],i:["normal"]},Zeyada:{v:["regular"],subset:["latin"],weight:["Default","400"],i:["normal"]},"Zhi Mang Xing":{v:["regular"],subset:["chinese-simplified","latin"],weight:["Default","400"],i:["normal"]},"Zilla Slab":{v:["300","300italic","regular","italic","500","500italic","600","600italic","700","700italic"],subset:["latin","latin-ext"],weight:["Default","300","400","500","600","700"],i:["normal","italic"]},"Zilla Slab Highlight":{v:["regular","700"],subset:["latin","latin-ext"],weight:["Default","400","700"],i:["normal"]}};var De=Number.isNaN||function(e){return"number"==typeof e&&e!=e};function Le(e,t){return e===t||!(!De(e)||!De(t))}function Be(e,t){if(e.length!==t.length)return!1;for(var a=0;a<e.length;a++)if(!Le(e[a],t[a]))return!1;return!0}const He=function(e,t){var a;void 0===t&&(t=Be);var i,l=[],n=!1;return function(){for(var o=[],r=0;r<arguments.length;r++)o[r]=arguments[r];return n&&a===this&&t(o,l)||(i=e.apply(this,o),n=!0,a=this,l=o),i}},Ae={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1},Re=function(e){function t(e,i,s,u,d){for(var p,h,m,b,y,_=0,k=0,S=0,C=0,M=0,H=0,R=m=p=0,z=0,O=0,F=0,I=0,N=s.length,V=N-1,G="",W="",U="",j="";z<N;){if(h=s.charCodeAt(z),z===V&&0!==k+C+S+_&&(0!==k&&(h=47===k?10:47),C=S=_=0,N++,V++),0===k+C+S+_){if(z===V&&(0<O&&(G=G.replace(g,"")),0<G.trim().length)){switch(h){case 32:case 9:case 59:case 13:case 10:break;default:G+=s.charAt(z)}h=59}switch(h){case 123:for(p=(G=G.trim()).charCodeAt(0),m=1,I=++z;z<N;){switch(h=s.charCodeAt(z)){case 123:m++;break;case 125:m--;break;case 47:switch(h=s.charCodeAt(z+1)){case 42:case 47:e:{for(R=z+1;R<V;++R)switch(s.charCodeAt(R)){case 47:if(42===h&&42===s.charCodeAt(R-1)&&z+2!==R){z=R+1;break e}break;case 10:if(47===h){z=R+1;break e}}z=R}}break;case 91:h++;case 40:h++;case 34:case 39:for(;z++<V&&s.charCodeAt(z)!==h;);}if(0===m)break;z++}if(m=s.substring(I,z),0===p&&(p=(G=G.replace(c,"").trim()).charCodeAt(0)),64===p){switch(0<O&&(G=G.replace(g,"")),h=G.charCodeAt(1)){case 100:case 109:case 115:case 45:O=i;break;default:O=B}if(I=(m=t(i,O,m,h,d+1)).length,0<A&&(y=r(3,m,O=a(B,G,F),i,E,T,I,h,d,u),G=O.join(""),void 0!==y&&0===(I=(m=y.trim()).length)&&(h=0,m="")),0<I)switch(h){case 115:G=G.replace(x,o);case 100:case 109:case 45:m=G+"{"+m+"}";break;case 107:m=(G=G.replace(f,"$1 $2"))+"{"+m+"}",m=1===L||2===L&&n("@"+m,3)?"@-webkit-"+m+"@"+m:"@"+m;break;default:m=G+m,112===u&&(W+=m,m="")}else m=""}else m=t(i,a(i,G,F),m,u,d+1);U+=m,m=F=O=R=p=0,G="",h=s.charCodeAt(++z);break;case 125:case 59:if(1<(I=(G=(0<O?G.replace(g,""):G).trim()).length))switch(0===R&&(p=G.charCodeAt(0),45===p||96<p&&123>p)&&(I=(G=G.replace(" ",":")).length),0<A&&void 0!==(y=r(1,G,i,e,E,T,W.length,u,d,u))&&0===(I=(G=y.trim()).length)&&(G="\0\0"),p=G.charCodeAt(0),h=G.charCodeAt(1),p){case 0:break;case 64:if(105===h||99===h){j+=G+s.charAt(z);break}default:58!==G.charCodeAt(I-1)&&(W+=l(G,p,h,G.charCodeAt(2)))}F=O=R=p=0,G="",h=s.charCodeAt(++z)}}switch(h){case 13:case 10:47===k?k=0:0===1+p&&107!==u&&0<G.length&&(O=1,G+="\0"),0<A*P&&r(0,G,i,e,E,T,W.length,u,d,u),T=1,E++;break;case 59:case 125:if(0===k+C+S+_){T++;break}default:switch(T++,b=s.charAt(z),h){case 9:case 32:if(0===C+_+k)switch(M){case 44:case 58:case 9:case 32:b="";break;default:32!==h&&(b=" ")}break;case 0:b="\\0";break;case 12:b="\\f";break;case 11:b="\\v";break;case 38:0===C+k+_&&(O=F=1,b="\f"+b);break;case 108:if(0===C+k+_+D&&0<R)switch(z-R){case 2:112===M&&58===s.charCodeAt(z-3)&&(D=M);case 8:111===H&&(D=H)}break;case 58:0===C+k+_&&(R=z);break;case 44:0===k+S+C+_&&(O=1,b+="\r");break;case 34:case 39:0===k&&(C=C===h?0:0===C?h:C);break;case 91:0===C+k+S&&_++;break;case 93:0===C+k+S&&_--;break;case 41:0===C+k+_&&S--;break;case 40:0===C+k+_&&(0===p&&(2*M+3*H==533||(p=1)),S++);break;case 64:0===k+S+C+_+R+m&&(m=1);break;case 42:case 47:if(!(0<C+_+S))switch(k){case 0:switch(2*h+3*s.charCodeAt(z+1)){case 235:k=47;break;case 220:I=z,k=42}break;case 42:47===h&&42===M&&I+2!==z&&(33===s.charCodeAt(I+2)&&(W+=s.substring(I,z+1)),b="",k=0)}}0===k&&(G+=b)}H=M,M=h,z++}if(0<(I=W.length)){if(O=i,0<A&&void 0!==(y=r(2,W,O,e,E,T,I,u,d,u))&&0===(W=y).length)return j+W+U;if(W=O.join(",")+"{"+W+"}",0!==L*D){switch(2!==L||n(W,2)||(D=0),D){case 111:W=W.replace(w,":-moz-$1")+W;break;case 112:W=W.replace(v,"::-webkit-input-$1")+W.replace(v,"::-moz-$1")+W.replace(v,":-ms-input-$1")+W}D=0}}return j+W+U}function a(e,t,a){var l=t.trim().split(m);t=l;var n=l.length,o=e.length;switch(o){case 0:case 1:var r=0;for(e=0===o?"":e[0]+" ";r<n;++r)t[r]=i(e,t[r],a).trim();break;default:var s=r=0;for(t=[];r<n;++r)for(var u=0;u<o;++u)t[s++]=i(e[u]+" ",l[r],a).trim()}return t}function i(e,t,a){var i=t.charCodeAt(0);switch(33>i&&(i=(t=t.trim()).charCodeAt(0)),i){case 38:return t.replace(b,"$1"+e.trim());case 58:return e.trim()+t.replace(b,"$1"+e.trim());default:if(0<1*a&&0<t.indexOf("\f"))return t.replace(b,(58===e.charCodeAt(0)?"":"$1")+e.trim())}return e+t}function l(e,t,a,i){var o=e+";",r=2*t+3*a+4*i;if(944===r){e=o.indexOf(":",9)+1;var s=o.substring(e,o.length-1).trim();return s=o.substring(0,e).trim()+s+";",1===L||2===L&&n(s,1)?"-webkit-"+s+s:s}if(0===L||2===L&&!n(o,1))return o;switch(r){case 1015:return 97===o.charCodeAt(10)?"-webkit-"+o+o:o;case 951:return 116===o.charCodeAt(3)?"-webkit-"+o+o:o;case 963:return 110===o.charCodeAt(5)?"-webkit-"+o+o:o;case 1009:if(100!==o.charCodeAt(4))break;case 969:case 942:return"-webkit-"+o+o;case 978:return"-webkit-"+o+"-moz-"+o+o;case 1019:case 983:return"-webkit-"+o+"-moz-"+o+"-ms-"+o+o;case 883:if(45===o.charCodeAt(8))return"-webkit-"+o+o;if(0<o.indexOf("image-set(",11))return o.replace(M,"$1-webkit-$2")+o;break;case 932:if(45===o.charCodeAt(4))switch(o.charCodeAt(5)){case 103:return"-webkit-box-"+o.replace("-grow","")+"-webkit-"+o+"-ms-"+o.replace("grow","positive")+o;case 115:return"-webkit-"+o+"-ms-"+o.replace("shrink","negative")+o;case 98:return"-webkit-"+o+"-ms-"+o.replace("basis","preferred-size")+o}return"-webkit-"+o+"-ms-"+o+o;case 964:return"-webkit-"+o+"-ms-flex-"+o+o;case 1023:if(99!==o.charCodeAt(8))break;return"-webkit-box-pack"+(s=o.substring(o.indexOf(":",15)).replace("flex-","").replace("space-between","justify"))+"-webkit-"+o+"-ms-flex-pack"+s+o;case 1005:return p.test(o)?o.replace(d,":-webkit-")+o.replace(d,":-moz-")+o:o;case 1e3:switch(t=(s=o.substring(13).trim()).indexOf("-")+1,s.charCodeAt(0)+s.charCodeAt(t)){case 226:s=o.replace(y,"tb");break;case 232:s=o.replace(y,"tb-rl");break;case 220:s=o.replace(y,"lr");break;default:return o}return"-webkit-"+o+"-ms-"+s+o;case 1017:if(-1===o.indexOf("sticky",9))break;case 975:switch(t=(o=e).length-10,r=(s=(33===o.charCodeAt(t)?o.substring(0,t):o).substring(e.indexOf(":",7)+1).trim()).charCodeAt(0)+(0|s.charCodeAt(7))){case 203:if(111>s.charCodeAt(8))break;case 115:o=o.replace(s,"-webkit-"+s)+";"+o;break;case 207:case 102:o=o.replace(s,"-webkit-"+(102<r?"inline-":"")+"box")+";"+o.replace(s,"-webkit-"+s)+";"+o.replace(s,"-ms-"+s+"box")+";"+o}return o+";";case 938:if(45===o.charCodeAt(5))switch(o.charCodeAt(6)){case 105:return s=o.replace("-items",""),"-webkit-"+o+"-webkit-box-"+s+"-ms-flex-"+s+o;case 115:return"-webkit-"+o+"-ms-flex-item-"+o.replace(k,"")+o;default:return"-webkit-"+o+"-ms-flex-line-pack"+o.replace("align-content","").replace(k,"")+o}break;case 973:case 989:if(45!==o.charCodeAt(3)||122===o.charCodeAt(4))break;case 931:case 953:if(!0===C.test(e))return 115===(s=e.substring(e.indexOf(":")+1)).charCodeAt(0)?l(e.replace("stretch","fill-available"),t,a,i).replace(":fill-available",":stretch"):o.replace(s,"-webkit-"+s)+o.replace(s,"-moz-"+s.replace("fill-",""))+o;break;case 962:if(o="-webkit-"+o+(102===o.charCodeAt(5)?"-ms-"+o:"")+o,211===a+i&&105===o.charCodeAt(13)&&0<o.indexOf("transform",10))return o.substring(0,o.indexOf(";",27)+1).replace(h,"$1-webkit-$2")+o}return o}function n(e,t){var a=e.indexOf(1===t?":":"{"),i=e.substring(0,3!==t?a:10);return a=e.substring(a+1,e.length-1),R(2!==t?i:i.replace(S,"$1"),a,t)}function o(e,t){var a=l(t,t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2));return a!==t+";"?a.replace(_," or ($1)").substring(4):"("+t+")"}function r(e,t,a,i,l,n,o,r,s,c){for(var g,d=0,p=t;d<A;++d)switch(g=H[d].call(u,e,p,a,i,l,n,o,r,s,c)){case void 0:case!1:case!0:case null:break;default:p=g}if(p!==t)return p}function s(e){return void 0!==(e=e.prefix)&&(R=null,e?"function"!=typeof e?L=1:(L=2,R=e):L=0),s}function u(e,a){var i=e;if(33>i.charCodeAt(0)&&(i=i.trim()),i=[i],0<A){var l=r(-1,a,i,i,E,T,0,0,0,0);void 0!==l&&"string"==typeof l&&(a=l)}var n=t(B,i,a,0,0);return 0<A&&void 0!==(l=r(-2,n,i,i,E,T,n.length,0,0,0))&&(n=l),D=0,T=E=1,n}var c=/^\0+/g,g=/[\0\r\f]/g,d=/: */g,p=/zoo|gra/,h=/([,: ])(transform)/g,m=/,\r+?/g,b=/([\t\r\n ])*\f?&/g,f=/@(k\w+)\s*(\S*)\s*/,v=/::(place)/g,w=/:(read-only)/g,y=/[svh]\w+-[tblr]{2}/,x=/\(\s*(.*)\s*\)/g,_=/([\s\S]*?);/g,k=/-self|flex-/g,S=/[^]*?(:[rp][el]a[\w-]+)[^]*/,C=/stretch|:\s*\w+\-(?:conte|avail)/,M=/([^-])(image-set\()/,T=1,E=1,D=0,L=1,B=[],H=[],A=0,R=null,P=0;return u.use=function e(t){switch(t){case void 0:case null:A=H.length=0;break;default:switch(t.constructor){case Array:for(var a=0,i=t.length;a<i;++a)e(t[a]);break;case Function:H[A++]=t;break;case Boolean:P=0|!!t}}return e},u.set=s,void 0!==e&&s(e),u};var Pe,ze,Oe=a(8226),Fe=a.n(Oe),Ie=/[A-Z]|^ms/g,Ne=(Pe=function(e){return e.replace(Ie,"-$&").toLowerCase()},ze={},function(e){return void 0===ze[e]&&(ze[e]=Pe(e)),ze[e]}),Ve=function(e,t){return null==t||"boolean"==typeof t?"":1===Ae[e]||45===e.charCodeAt(1)||isNaN(t)||0===t?t:t+"px"},Ge=function e(t){for(var a=t.length,i=0,l="";i<a;i++){var n=t[i];if(null!=n){var o=void 0;switch(typeof n){case"boolean":break;case"function":o=e([n()]);break;case"object":if(Array.isArray(n))o=e(n);else for(var r in o="",n)n[r]&&r&&(o&&(o+=" "),o+=r);break;default:o=n}o&&(l&&(l+=" "),l+=o)}}return l},We="undefined"!=typeof document;function Ue(e){var t=document.createElement("style");return t.setAttribute("data-emotion",e.key||""),void 0!==e.nonce&&t.setAttribute("nonce",e.nonce),t.appendChild(document.createTextNode("")),(void 0!==e.container?e.container:document.head).appendChild(t),t}var je=function(){function e(e){this.isSpeedy=!0,this.tags=[],this.ctr=0,this.opts=e}var t=e.prototype;return t.inject=function(){if(this.injected)throw new Error("already injected!");this.tags[0]=Ue(this.opts),this.injected=!0},t.speedy=function(e){if(0!==this.ctr)throw new Error("cannot change speedy now");this.isSpeedy=!!e},t.insert=function(e,t){if(this.isSpeedy){var a=function(e){if(e.sheet)return e.sheet;for(var t=0;t<document.styleSheets.length;t++)if(document.styleSheets[t].ownerNode===e)return document.styleSheets[t]}(this.tags[this.tags.length-1]);try{a.insertRule(e,a.cssRules.length)}catch(e){}}else{var i=Ue(this.opts);this.tags.push(i),i.appendChild(document.createTextNode(e+(t||"")))}this.ctr++,this.ctr%65e3==0&&this.tags.push(Ue(this.opts))},t.flush=function(){this.tags.forEach(function(e){return e.parentNode.removeChild(e)}),this.tags=[],this.ctr=0,this.injected=!1},e}();var qe=function(e,t){if(void 0!==e.__SECRET_EMOTION__)return e.__SECRET_EMOTION__;void 0===t&&(t={});var a,i,l=t.key||"css",n=Fe()(function(e){a+=e,We&&r.insert(e,u)});void 0!==t.prefix&&(i={prefix:t.prefix});var o={registered:{},inserted:{},nonce:t.nonce,key:l},r=new je(t);We&&r.inject();var s=new Re(i);s.use(t.stylisPlugins)(n);var u="";function c(e,t){if(null==e)return"";switch(typeof e){case"boolean":return"";case"function":return void 0!==e.__emotion_styles?e.toString():c.call(this,void 0===this?e():e(this.mergedProps,this.context),t);case"object":return h.call(this,e);default:var a=o.registered[e];return!1===t&&void 0!==a?a:e}}var g,d,p=new WeakMap;function h(e){if(p.has(e))return p.get(e);var t="";return Array.isArray(e)?e.forEach(function(e){t+=c.call(this,e,!1)},this):Object.keys(e).forEach(function(a){"object"!=typeof e[a]?void 0!==o.registered[e[a]]?t+=a+"{"+o.registered[e[a]]+"}":t+=Ne(a)+":"+Ve(a,e[a])+";":Array.isArray(e[a])&&"string"==typeof e[a][0]&&void 0===o.registered[e[a][0]]?e[a].forEach(function(e){t+=Ne(a)+":"+Ve(a,e)+";"}):t+=a+"{"+c.call(this,e[a],!1)+"}"},this),p.set(e,t),t}var m=/label:\s*([^\s;\n{]+)\s*;/g,b=function(e){var t=!0,a="",i="";null==e||void 0===e.raw?(t=!1,a+=c.call(this,e,!1)):a+=e[0];for(var l=arguments.length,n=new Array(l>1?l-1:0),o=1;o<l;o++)n[o-1]=arguments[o];return n.forEach(function(i,l){a+=c.call(this,i,46===a.charCodeAt(a.length-1)),!0===t&&void 0!==e[l+1]&&(a+=e[l+1])},this),d=a,a=a.replace(m,function(e,t){return i+="-"+t,""}),g=function(e,t){return function(e){for(var t,a=e.length,i=a^a,l=0;a>=4;)t=1540483477*(65535&(t=255&e.charCodeAt(l)|(255&e.charCodeAt(++l))<<8|(255&e.charCodeAt(++l))<<16|(255&e.charCodeAt(++l))<<24))+((1540483477*(t>>>16)&65535)<<16),i=1540483477*(65535&i)+((1540483477*(i>>>16)&65535)<<16)^(t=1540483477*(65535&(t^=t>>>24))+((1540483477*(t>>>16)&65535)<<16)),a-=4,++l;switch(a){case 3:i^=(255&e.charCodeAt(l+2))<<16;case 2:i^=(255&e.charCodeAt(l+1))<<8;case 1:i=1540483477*(65535&(i^=255&e.charCodeAt(l)))+((1540483477*(i>>>16)&65535)<<16)}return i=1540483477*(65535&(i^=i>>>13))+((1540483477*(i>>>16)&65535)<<16),((i^=i>>>15)>>>0).toString(36)}(e+t)+t}(a,i),a};function f(e,t){void 0===o.inserted[g]&&(a="",s(e,t),o.inserted[g]=a)}var v=function(){var e=b.apply(this,arguments),t=l+"-"+g;return void 0===o.registered[t]&&(o.registered[t]=d),f("."+t,e),t};function w(e,t){var a="";return t.split(" ").forEach(function(t){void 0!==o.registered[t]?e.push(t):a+=t+" "}),a}function y(e,t){var a=[],i=w(a,e);return a.length<2?e:i+v(a,t)}function x(e){o.inserted[e]=!0}if(We){var _=document.querySelectorAll("[data-emotion-"+l+"]");Array.prototype.forEach.call(_,function(e){r.tags[0].parentNode.insertBefore(e,r.tags[0]),e.getAttribute("data-emotion-"+l).split(" ").forEach(x)})}var k={flush:function(){We&&(r.flush(),r.inject()),o.inserted={},o.registered={}},hydrate:function(e){e.forEach(x)},cx:function(){for(var e=arguments.length,t=new Array(e),a=0;a<e;a++)t[a]=arguments[a];return y(Ge(t))},merge:y,getRegisteredStyles:w,injectGlobal:function(){f("",b.apply(this,arguments))},keyframes:function(){var e=b.apply(this,arguments),t="animation-"+g;return f("","@keyframes "+t+"{"+e+"}"),t},css:v,sheet:r,caches:o};return e.__SECRET_EMOTION__=k,k}("undefined"!=typeof globalThis?globalThis:{}),$e=(qe.flush,qe.hydrate,qe.cx,qe.merge,qe.getRegisteredStyles,qe.injectGlobal),Ze=(qe.keyframes,qe.css),Ke=(qe.sheet,qe.caches,a(5795)),Ye=a(3146),Je=a.n(Ye),Xe=a(8006),Qe=a(9790);function et(e){return et="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},et(e)}function tt(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function at(e,t){for(var a=0;a<t.length;a++){var i=t[a];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}function it(e,t,a){return t&&at(e.prototype,t),a&&at(e,a),e}function lt(e,t,a){return t in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}function nt(){return nt=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var i in a)Object.prototype.hasOwnProperty.call(a,i)&&(e[i]=a[i])}return e},nt.apply(this,arguments)}function ot(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{},i=Object.keys(a);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(a).filter(function(e){return Object.getOwnPropertyDescriptor(a,e).enumerable}))),i.forEach(function(t){lt(e,t,a[t])})}return e}function rt(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&ut(e,t)}function st(e){return st=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)},st(e)}function ut(e,t){return ut=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},ut(e,t)}function ct(e,t){if(null==e)return{};var a,i,l=function(e,t){if(null==e)return{};var a,i,l={},n=Object.keys(e);for(i=0;i<n.length;i++)a=n[i],t.indexOf(a)>=0||(l[a]=e[a]);return l}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(i=0;i<n.length;i++)a=n[i],t.indexOf(a)>=0||Object.prototype.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}function gt(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function dt(e,t){return!t||"object"!=typeof t&&"function"!=typeof t?gt(e):t}function pt(e){return function(e){if(Array.isArray(e)){for(var t=0,a=new Array(e.length);t<e.length;t++)a[t]=e[t];return a}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var ht=function(){};function mt(e,t){return t?"-"===t[0]?e+t:e+"__"+t:e}function bt(e,t,a,i){var l=[t,i];if(a&&e)for(var n in a)a.hasOwnProperty(n)&&a[n]&&l.push("".concat(mt(e,n)));return l.filter(function(e){return e}).map(function(e){return String(e).trim()}).join(" ")}var ft=function(e){return Array.isArray(e)?e.filter(Boolean):"object"===et(e)&&null!==e?[e]:[]};function vt(e){return[document.documentElement,document.body,window].indexOf(e)>-1}function wt(e){return vt(e)?window.pageYOffset:e.scrollTop}function yt(e,t){vt(e)?window.scrollTo(0,t):e.scrollTop=t}function xt(e,t){var a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:200,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:ht,l=wt(e),n=t-l,o=0;!function t(){var r,s=n*((r=(r=o+=10)/a-1)*r*r+1)+l;yt(e,s),o<a?Je()(t):i(e)}()}function _t(){try{return document.createEvent("TouchEvent"),!0}catch(e){return!1}}var kt=function(e){return"auto"===e?"bottom":e},St=function(e){function t(){var e,a;tt(this,t);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(a=dt(this,(e=st(t)).call.apply(e,[this].concat(l))))),"state",{maxHeight:a.props.maxMenuHeight,placement:null}),lt(gt(gt(a)),"getPlacement",function(e){var t=a.props,i=t.minMenuHeight,l=t.maxMenuHeight,n=t.menuPlacement,o=t.menuPosition,r=t.menuShouldScrollIntoView,s=t.theme,u=a.context.getPortalPlacement;if(e){var c="fixed"===o,g=function(e){var t=e.maxHeight,a=e.menuEl,i=e.minHeight,l=e.placement,n=e.shouldScroll,o=e.isFixedPosition,r=e.theme.spacing,s=function(e){var t=getComputedStyle(e),a="absolute"===t.position,i=/(auto|scroll)/,l=document.documentElement;if("fixed"===t.position)return l;for(var n=e;n=n.parentElement;)if(t=getComputedStyle(n),(!a||"static"!==t.position)&&i.test(t.overflow+t.overflowY+t.overflowX))return n;return l}(a),u={placement:"bottom",maxHeight:t};if(!a||!a.offsetParent)return u;var c=s.getBoundingClientRect().height,g=a.getBoundingClientRect(),d=g.bottom,p=g.height,h=g.top,m=a.offsetParent.getBoundingClientRect().top,b=window.innerHeight,f=wt(s),v=parseInt(getComputedStyle(a).marginBottom,10),w=parseInt(getComputedStyle(a).marginTop,10),y=m-w,x=b-h,_=y+f,k=c-f-h,S=d-b+f+v,C=f+h-w,M=160;switch(l){case"auto":case"bottom":if(x>=p)return{placement:"bottom",maxHeight:t};if(k>=p&&!o)return n&&xt(s,S,M),{placement:"bottom",maxHeight:t};if(!o&&k>=i||o&&x>=i)return n&&xt(s,S,M),{placement:"bottom",maxHeight:o?x-v:k-v};if("auto"===l||o){var T=t,E=o?y:_;return E>=i&&(T=Math.min(E-v-r.controlHeight,t)),{placement:"top",maxHeight:T}}if("bottom"===l)return yt(s,S),{placement:"bottom",maxHeight:t};break;case"top":if(y>=p)return{placement:"top",maxHeight:t};if(_>=p&&!o)return n&&xt(s,C,M),{placement:"top",maxHeight:t};if(!o&&_>=i||o&&y>=i){var D=t;return(!o&&_>=i||o&&y>=i)&&(D=o?y-w:_-w),n&&xt(s,C,M),{placement:"top",maxHeight:D}}return{placement:"bottom",maxHeight:t};default:throw new Error('Invalid placement provided "'.concat(l,'".'))}return u}({maxHeight:l,menuEl:e,minHeight:i,placement:n,shouldScroll:r&&!c,isFixedPosition:c,theme:s});u&&u(g),a.setState(g)}}),lt(gt(gt(a)),"getUpdatedProps",function(){var e=a.props.menuPlacement,t=a.state.placement||kt(e);return ot({},a.props,{placement:t,maxHeight:a.state.maxHeight})}),a}return rt(t,e),it(t,[{key:"render",value:function(){return(0,this.props.children)({ref:this.getPlacement,placerProps:this.getUpdatedProps()})}}]),t}(w.Component);lt(St,"contextTypes",{getPortalPlacement:j().func});var Ct=function(e){var t=e.theme,a=t.spacing.baseUnit;return{color:t.colors.neutral40,padding:"".concat(2*a,"px ").concat(3*a,"px"),textAlign:"center"}},Mt=Ct,Tt=Ct,Et=function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerProps;return y().createElement("div",nt({className:i(Ze(l("noOptionsMessage",e)),{"menu-notice":!0,"menu-notice--no-options":!0},a)},n),t)};Et.defaultProps={children:"No options"};var Dt=function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerProps;return y().createElement("div",nt({className:i(Ze(l("loadingMessage",e)),{"menu-notice":!0,"menu-notice--loading":!0},a)},n),t)};Dt.defaultProps={children:"Loading..."};var Lt=function(e){function t(){var e,a;tt(this,t);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(a=dt(this,(e=st(t)).call.apply(e,[this].concat(l))))),"state",{placement:null}),lt(gt(gt(a)),"getPortalPlacement",function(e){var t=e.placement;t!==kt(a.props.menuPlacement)&&a.setState({placement:t})}),a}return rt(t,e),it(t,[{key:"getChildContext",value:function(){return{getPortalPlacement:this.getPortalPlacement}}},{key:"render",value:function(){var e=this.props,t=e.appendTo,a=e.children,i=e.controlElement,l=e.menuPlacement,n=e.menuPosition,o=e.getStyles,r="fixed"===n;if(!t&&!r||!i)return null;var s=this.state.placement||kt(l),u=function(e){var t=e.getBoundingClientRect();return{bottom:t.bottom,height:t.height,left:t.left,right:t.right,top:t.top,width:t.width}}(i),c=r?0:window.pageYOffset,g={offset:u[s]+c,position:n,rect:u},d=y().createElement("div",{className:Ze(o("menuPortal",g))},a);return t?(0,Ke.createPortal)(d,t):d}}]),t}(w.Component);lt(Lt,"childContextTypes",{getPortalPlacement:j().func});var Bt=Array.isArray,Ht=Object.keys,At=Object.prototype.hasOwnProperty;function Rt(e,t){if(e===t)return!0;if(e&&t&&"object"==et(e)&&"object"==et(t)){var a,i,l,n=Bt(e),o=Bt(t);if(n&&o){if((i=e.length)!=t.length)return!1;for(a=i;0!==a--;)if(!Rt(e[a],t[a]))return!1;return!0}if(n!=o)return!1;var r=e instanceof Date,s=t instanceof Date;if(r!=s)return!1;if(r&&s)return e.getTime()==t.getTime();var u=e instanceof RegExp,c=t instanceof RegExp;if(u!=c)return!1;if(u&&c)return e.toString()==t.toString();var g=Ht(e);if((i=g.length)!==Ht(t).length)return!1;for(a=i;0!==a--;)if(!At.call(t,g[a]))return!1;for(a=i;0!==a--;)if(!("_owner"===(l=g[a])&&e.$$typeof||Rt(e[l],t[l])))return!1;return!0}return e!=e&&t!=t}function Pt(e,t){try{return Rt(e,t)}catch(e){if(e.message&&e.message.match(/stack|recursion/i))return console.warn("Warning: react-fast-compare does not handle circular references.",e.name,e.message),!1;throw e}}var zt=[{base:"A",letters:/[\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g},{base:"AA",letters:/[\uA732]/g},{base:"AE",letters:/[\u00C6\u01FC\u01E2]/g},{base:"AO",letters:/[\uA734]/g},{base:"AU",letters:/[\uA736]/g},{base:"AV",letters:/[\uA738\uA73A]/g},{base:"AY",letters:/[\uA73C]/g},{base:"B",letters:/[\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g},{base:"C",letters:/[\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g},{base:"D",letters:/[\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g},{base:"DZ",letters:/[\u01F1\u01C4]/g},{base:"Dz",letters:/[\u01F2\u01C5]/g},{base:"E",letters:/[\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g},{base:"F",letters:/[\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g},{base:"G",letters:/[\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g},{base:"H",letters:/[\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g},{base:"I",letters:/[\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g},{base:"J",letters:/[\u004A\u24BF\uFF2A\u0134\u0248]/g},{base:"K",letters:/[\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g},{base:"L",letters:/[\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g},{base:"LJ",letters:/[\u01C7]/g},{base:"Lj",letters:/[\u01C8]/g},{base:"M",letters:/[\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g},{base:"N",letters:/[\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g},{base:"NJ",letters:/[\u01CA]/g},{base:"Nj",letters:/[\u01CB]/g},{base:"O",letters:/[\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g},{base:"OI",letters:/[\u01A2]/g},{base:"OO",letters:/[\uA74E]/g},{base:"OU",letters:/[\u0222]/g},{base:"P",letters:/[\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g},{base:"Q",letters:/[\u0051\u24C6\uFF31\uA756\uA758\u024A]/g},{base:"R",letters:/[\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g},{base:"S",letters:/[\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g},{base:"T",letters:/[\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g},{base:"TZ",letters:/[\uA728]/g},{base:"U",letters:/[\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g},{base:"V",letters:/[\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g},{base:"VY",letters:/[\uA760]/g},{base:"W",letters:/[\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g},{base:"X",letters:/[\u0058\u24CD\uFF38\u1E8A\u1E8C]/g},{base:"Y",letters:/[\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g},{base:"Z",letters:/[\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g},{base:"a",letters:/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250]/g},{base:"aa",letters:/[\uA733]/g},{base:"ae",letters:/[\u00E6\u01FD\u01E3]/g},{base:"ao",letters:/[\uA735]/g},{base:"au",letters:/[\uA737]/g},{base:"av",letters:/[\uA739\uA73B]/g},{base:"ay",letters:/[\uA73D]/g},{base:"b",letters:/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253]/g},{base:"c",letters:/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184]/g},{base:"d",letters:/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A]/g},{base:"dz",letters:/[\u01F3\u01C6]/g},{base:"e",letters:/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD]/g},{base:"f",letters:/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C]/g},{base:"g",letters:/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F]/g},{base:"h",letters:/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265]/g},{base:"hv",letters:/[\u0195]/g},{base:"i",letters:/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131]/g},{base:"j",letters:/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249]/g},{base:"k",letters:/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3]/g},{base:"l",letters:/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747]/g},{base:"lj",letters:/[\u01C9]/g},{base:"m",letters:/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F]/g},{base:"n",letters:/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5]/g},{base:"nj",letters:/[\u01CC]/g},{base:"o",letters:/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275]/g},{base:"oi",letters:/[\u01A3]/g},{base:"ou",letters:/[\u0223]/g},{base:"oo",letters:/[\uA74F]/g},{base:"p",letters:/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755]/g},{base:"q",letters:/[\u0071\u24E0\uFF51\u024B\uA757\uA759]/g},{base:"r",letters:/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783]/g},{base:"s",letters:/[\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B]/g},{base:"t",letters:/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787]/g},{base:"tz",letters:/[\uA729]/g},{base:"u",letters:/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289]/g},{base:"v",letters:/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C]/g},{base:"vy",letters:/[\uA761]/g},{base:"w",letters:/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73]/g},{base:"x",letters:/[\u0078\u24E7\uFF58\u1E8B\u1E8D]/g},{base:"y",letters:/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF]/g},{base:"z",letters:/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763]/g}],Ot=function(e){for(var t=0;t<zt.length;t++)e=e.replace(zt[t].letters,zt[t].base);return e},Ft=function(e){return e.replace(/^\s+|\s+$/g,"")},It=function(e){return"".concat(e.label," ").concat(e.value)},Nt=function(e){return y().createElement("span",nt({className:Ze({label:"a11yText",zIndex:9999,border:0,clip:"rect(1px, 1px, 1px, 1px)",height:1,width:1,position:"absolute",overflow:"hidden",padding:0,whiteSpace:"nowrap",backgroundColor:"red",color:"blue"})},e))},Vt=function(e){function t(){return tt(this,t),dt(this,st(t).apply(this,arguments))}return rt(t,e),it(t,[{key:"render",value:function(){var e=this.props,t=(e.in,e.out,e.onExited,e.appear,e.enter,e.exit,e.innerRef),a=(e.emotion,ct(e,["in","out","onExited","appear","enter","exit","innerRef","emotion"]));return y().createElement("input",nt({ref:t},a,{className:Ze({label:"dummyInput",background:0,border:0,fontSize:"inherit",outline:0,padding:0,width:1,color:"transparent",left:-100,opacity:0,position:"relative",transform:"scale(0)"})}))}}]),t}(w.Component),Gt=function(e){function t(){return tt(this,t),dt(this,st(t).apply(this,arguments))}return rt(t,e),it(t,[{key:"componentDidMount",value:function(){this.props.innerRef((0,Ke.findDOMNode)(this))}},{key:"componentWillUnmount",value:function(){this.props.innerRef(null)}},{key:"render",value:function(){return this.props.children}}]),t}(w.Component),Wt=["boxSizing","height","overflow","paddingRight","position"],Ut={boxSizing:"border-box",overflow:"hidden",position:"relative",height:"100%"};function jt(e){e.preventDefault()}function qt(e){e.stopPropagation()}function $t(){var e=this.scrollTop,t=this.scrollHeight,a=e+this.offsetHeight;0===e?this.scrollTop=1:a===t&&(this.scrollTop=e-1)}function Zt(){return"ontouchstart"in window||navigator.maxTouchPoints}var Kt=!("undefined"==typeof window||!window.document||!window.document.createElement),Yt=0,Jt=function(e){function t(){var e,a;tt(this,t);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(a=dt(this,(e=st(t)).call.apply(e,[this].concat(l))))),"originalStyles",{}),lt(gt(gt(a)),"listenerOptions",{capture:!1,passive:!1}),a}return rt(t,e),it(t,[{key:"componentDidMount",value:function(){var e=this;if(Kt){var t=this.props,a=t.accountForScrollbars,i=t.touchScrollTarget,l=document.body,n=l&&l.style;if(a&&Wt.forEach(function(t){var a=n&&n[t];e.originalStyles[t]=a}),a&&Yt<1){var o=parseInt(this.originalStyles.paddingRight,10)||0,r=document.body?document.body.clientWidth:0,s=window.innerWidth-r+o||0;Object.keys(Ut).forEach(function(e){var t=Ut[e];n&&(n[e]=t)}),n&&(n.paddingRight="".concat(s,"px"))}l&&Zt()&&(l.addEventListener("touchmove",jt,this.listenerOptions),i&&(i.addEventListener("touchstart",$t,this.listenerOptions),i.addEventListener("touchmove",qt,this.listenerOptions))),Yt+=1}}},{key:"componentWillUnmount",value:function(){var e=this;if(Kt){var t=this.props,a=t.accountForScrollbars,i=t.touchScrollTarget,l=document.body,n=l&&l.style;Yt=Math.max(Yt-1,0),a&&Yt<1&&Wt.forEach(function(t){var a=e.originalStyles[t];n&&(n[t]=a)}),l&&Zt()&&(l.removeEventListener("touchmove",jt,this.listenerOptions),i&&(i.removeEventListener("touchstart",$t,this.listenerOptions),i.removeEventListener("touchmove",qt,this.listenerOptions)))}}},{key:"render",value:function(){return null}}]),t}(w.Component);lt(Jt,"defaultProps",{accountForScrollbars:!0});var Xt=function(e){function t(){var e,a;tt(this,t);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(a=dt(this,(e=st(t)).call.apply(e,[this].concat(l))))),"state",{touchScrollTarget:null}),lt(gt(gt(a)),"getScrollTarget",function(e){e!==a.state.touchScrollTarget&&a.setState({touchScrollTarget:e})}),lt(gt(gt(a)),"blurSelectInput",function(){document.activeElement&&document.activeElement.blur()}),a}return rt(t,e),it(t,[{key:"render",value:function(){var e=this.props,t=e.children,a=e.isEnabled,i=this.state.touchScrollTarget;return a?y().createElement("div",null,y().createElement("div",{onClick:this.blurSelectInput,className:Ze({position:"fixed",left:0,bottom:0,right:0,top:0})}),y().createElement(Gt,{innerRef:this.getScrollTarget},t),i?y().createElement(Jt,{touchScrollTarget:i}):null):t}}]),t}(w.PureComponent),Qt=function(e){function t(){var e,a;tt(this,t);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(a=dt(this,(e=st(t)).call.apply(e,[this].concat(l))))),"isBottom",!1),lt(gt(gt(a)),"isTop",!1),lt(gt(gt(a)),"scrollTarget",void 0),lt(gt(gt(a)),"touchStart",void 0),lt(gt(gt(a)),"cancelScroll",function(e){e.preventDefault(),e.stopPropagation()}),lt(gt(gt(a)),"handleEventDelta",function(e,t){var i=a.props,l=i.onBottomArrive,n=i.onBottomLeave,o=i.onTopArrive,r=i.onTopLeave,s=a.scrollTarget,u=s.scrollTop,c=s.scrollHeight,g=s.clientHeight,d=a.scrollTarget,p=t>0,h=c-g-u,m=!1;h>t&&a.isBottom&&(n&&n(e),a.isBottom=!1),p&&a.isTop&&(r&&r(e),a.isTop=!1),p&&t>h?(l&&!a.isBottom&&l(e),d.scrollTop=c,m=!0,a.isBottom=!0):!p&&-t>u&&(o&&!a.isTop&&o(e),d.scrollTop=0,m=!0,a.isTop=!0),m&&a.cancelScroll(e)}),lt(gt(gt(a)),"onWheel",function(e){a.handleEventDelta(e,e.deltaY)}),lt(gt(gt(a)),"onTouchStart",function(e){a.touchStart=e.changedTouches[0].clientY}),lt(gt(gt(a)),"onTouchMove",function(e){var t=a.touchStart-e.changedTouches[0].clientY;a.handleEventDelta(e,t)}),lt(gt(gt(a)),"getScrollTarget",function(e){a.scrollTarget=e}),a}return rt(t,e),it(t,[{key:"componentDidMount",value:function(){this.startListening(this.scrollTarget)}},{key:"componentWillUnmount",value:function(){this.stopListening(this.scrollTarget)}},{key:"startListening",value:function(e){e&&(e.scrollHeight<=e.clientHeight||("function"==typeof e.addEventListener&&e.addEventListener("wheel",this.onWheel,!1),"function"==typeof e.addEventListener&&e.addEventListener("touchstart",this.onTouchStart,!1),"function"==typeof e.addEventListener&&e.addEventListener("touchmove",this.onTouchMove,!1)))}},{key:"stopListening",value:function(e){e.scrollHeight<=e.clientHeight||("function"==typeof e.removeEventListener&&e.removeEventListener("wheel",this.onWheel,!1),"function"==typeof e.removeEventListener&&e.removeEventListener("touchstart",this.onTouchStart,!1),"function"==typeof e.removeEventListener&&e.removeEventListener("touchmove",this.onTouchMove,!1))}},{key:"render",value:function(){return y().createElement(Gt,{innerRef:this.getScrollTarget},this.props.children)}}]),t}(w.Component),ea=function(e){function t(){return tt(this,t),dt(this,st(t).apply(this,arguments))}return rt(t,e),it(t,[{key:"render",value:function(){var e=this.props,t=e.isEnabled,a=ct(e,["isEnabled"]);return t?y().createElement(Qt,a):this.props.children}}]),t}(w.Component);lt(ea,"defaultProps",{isEnabled:!0});var ta=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=t.isSearchable,i=t.isMulti,l=t.label,n=t.isDisabled;switch(e){case"menu":return"Use Up and Down to choose options".concat(n?"":", press Enter to select the currently focused option",", press Escape to exit the menu, press Tab to select the option and exit the menu.");case"input":return"".concat(l||"Select"," is focused ").concat(a?",type to refine list":"",", press Down to open the menu, ").concat(i?" press left to focus selected values":"");case"value":return"Use left and right to toggle between focused values, press Backspace to remove the currently focused value"}},aa=function(e,t){var a=t.value,i=t.isDisabled;if(a)switch(e){case"deselect-option":case"pop-value":case"remove-value":return"option ".concat(a,", deselected.");case"select-option":return"option ".concat(a,i?" is disabled. Select another option.":", selected.")}},ia=function(e){return!!e.isDisabled},la=function(e){function t(){return tt(this,t),dt(this,st(t).apply(this,arguments))}return rt(t,e),it(t,[{key:"render",value:function(){var e=this.props,t=e.children,a=e.className,i=e.cx,l=e.isMulti,n=e.getStyles,o=e.hasValue;return y().createElement("div",{className:i(Ze(n("valueContainer",this.props)),{"value-container":!0,"value-container--is-multi":l,"value-container--has-value":o},a)},t)}}]),t}(w.Component),na=function(e){var t=e.size,a=ct(e,["size"]);return y().createElement("svg",nt({height:t,width:t,viewBox:"0 0 20 20","aria-hidden":"true",focusable:"false",className:Ze({display:"inline-block",fill:"currentColor",lineHeight:1,stroke:"currentColor",strokeWidth:0})},a))},oa=function(e){return y().createElement(na,nt({size:20},e),y().createElement("path",{d:"M14.348 14.849c-0.469 0.469-1.229 0.469-1.697 0l-2.651-3.030-2.651 3.029c-0.469 0.469-1.229 0.469-1.697 0-0.469-0.469-0.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-0.469-0.469-0.469-1.228 0-1.697s1.228-0.469 1.697 0l2.652 3.031 2.651-3.031c0.469-0.469 1.228-0.469 1.697 0s0.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c0.469 0.469 0.469 1.229 0 1.698z"}))},ra=function(e){return y().createElement(na,nt({size:20},e),y().createElement("path",{d:"M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"}))},sa=function(e){var t=e.isFocused,a=e.theme,i=a.spacing.baseUnit,l=a.colors;return{label:"indicatorContainer",color:t?l.neutral60:l.neutral20,display:"flex",padding:2*i,transition:"color 150ms",":hover":{color:t?l.neutral80:l.neutral40}}},ua=sa,ca=sa,ga="react-select-loading-indicator",da=!1,pa=function(e){var t=e.color,a=e.delay,i=e.offset;return y().createElement("span",{className:Ze({animationDuration:"1s",animationDelay:"".concat(a,"ms"),animationIterationCount:"infinite",animationName:ga,animationTimingFunction:"ease-in-out",backgroundColor:t,borderRadius:"1em",display:"inline-block",marginLeft:i?"1em":null,height:"1em",verticalAlign:"top",width:"1em"})})},ha=function(e){var t=e.className,a=e.cx,i=e.getStyles,l=e.innerProps,n=e.isFocused,o=e.isRtl,r=e.theme.colors,s=n?r.neutral80:r.neutral20;return da||($e("@keyframes ",ga,"{0%,80%,100%{opacity:0;}40%{opacity:1;}};"),da=!0),y().createElement("div",nt({},l,{className:a(Ze(i("loadingIndicator",e)),{indicator:!0,"loading-indicator":!0},t)}),y().createElement(pa,{color:s,delay:0,offset:o}),y().createElement(pa,{color:s,delay:160,offset:!0}),y().createElement(pa,{color:s,delay:320,offset:!o}))};ha.defaultProps={size:4};var ma=function(e){return{label:"input",background:0,border:0,fontSize:"inherit",opacity:e?0:1,outline:0,padding:0,color:"inherit"}},ba=function(e){var t=e.children,a=e.innerProps;return y().createElement("div",a,t)},fa=ba,va=ba,wa=function(e){function t(){return tt(this,t),dt(this,st(t).apply(this,arguments))}return rt(t,e),it(t,[{key:"render",value:function(){var e=this.props,t=e.children,a=e.innerProps;return y().createElement("div",a,t||y().createElement(oa,{size:14}))}}]),t}(w.Component),ya=function(e){function t(){return tt(this,t),dt(this,st(t).apply(this,arguments))}return rt(t,e),it(t,[{key:"render",value:function(){var e=this.props,t=e.children,a=e.className,i=e.components,l=e.cx,n=e.data,o=e.getStyles,r=e.innerProps,s=e.isDisabled,u=e.removeProps,c=e.selectProps,g=i.Container,d=i.Label,p=i.Remove,h=ot({className:l(Ze(o("multiValue",this.props)),{"multi-value":!0,"multi-value--is-disabled":s},a)},r),m={className:l(Ze(o("multiValueLabel",this.props)),{"multi-value__label":!0},a)},b=ot({className:l(Ze(o("multiValueRemove",this.props)),{"multi-value__remove":!0},a)},u);return y().createElement(g,{data:n,innerProps:h,selectProps:c},y().createElement(d,{data:n,innerProps:m,selectProps:c},t),y().createElement(p,{data:n,innerProps:b,selectProps:c}))}}]),t}(w.Component);lt(ya,"defaultProps",{cropWithEllipsis:!0});var xa={ClearIndicator:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerProps;return y().createElement("div",nt({},n,{className:i(Ze(l("clearIndicator",e)),{indicator:!0,"clear-indicator":!0},a)}),t||y().createElement(oa,null))},Control:function(e){var t=e.children,a=e.cx,i=e.getStyles,l=e.className,n=e.isDisabled,o=e.isFocused,r=e.innerRef,s=e.innerProps,u=e.menuIsOpen;return y().createElement("div",nt({ref:r,className:a(Ze(i("control",e)),{control:!0,"control--is-disabled":n,"control--is-focused":o,"control--menu-is-open":u},l)},s),t)},DropdownIndicator:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerProps;return y().createElement("div",nt({},n,{className:i(Ze(l("dropdownIndicator",e)),{indicator:!0,"dropdown-indicator":!0},a)}),t||y().createElement(ra,null))},DownChevron:ra,CrossIcon:oa,Group:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.Heading,o=e.headingProps,r=e.label,s=e.theme,u=e.selectProps;return y().createElement("div",{className:i(Ze(l("group",e)),{group:!0},a)},y().createElement(n,nt({},o,{selectProps:u,theme:s,getStyles:l,cx:i}),r),y().createElement("div",null,t))},GroupHeading:function(e){var t=e.className,a=e.cx,i=e.getStyles,l=e.theme,n=(e.selectProps,ct(e,["className","cx","getStyles","theme","selectProps"]));return y().createElement("div",nt({className:a(Ze(i("groupHeading",ot({theme:l},n))),{"group-heading":!0},t)},n))},IndicatorsContainer:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles;return y().createElement("div",{className:i(Ze(l("indicatorsContainer",e)),{indicators:!0},a)},t)},IndicatorSeparator:function(e){var t=e.className,a=e.cx,i=e.getStyles,l=e.innerProps;return y().createElement("span",nt({},l,{className:a(Ze(i("indicatorSeparator",e)),{"indicator-separator":!0},t)}))},Input:function(e){var t=e.className,a=e.cx,i=e.getStyles,l=e.innerRef,n=e.isHidden,o=e.isDisabled,r=e.theme,s=(e.selectProps,ct(e,["className","cx","getStyles","innerRef","isHidden","isDisabled","theme","selectProps"]));return y().createElement("div",{className:Ze(i("input",ot({theme:r},s)))},y().createElement(Xe.A,nt({className:a(null,{input:!0},t),inputRef:l,inputStyle:ma(n),disabled:o},s)))},LoadingIndicator:ha,Menu:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerRef,o=e.innerProps,r=i(Ze(l("menu",e)),{menu:!0},a);return y().createElement("div",nt({className:r},o,{ref:n}),t)},MenuList:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.isMulti,o=e.innerRef;return y().createElement("div",{className:i(Ze(l("menuList",e)),{"menu-list":!0,"menu-list--is-multi":n},a),ref:o},t)},MenuPortal:Lt,LoadingMessage:Dt,NoOptionsMessage:Et,MultiValue:ya,MultiValueContainer:fa,MultiValueLabel:va,MultiValueRemove:wa,Option:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.isDisabled,o=e.isFocused,r=e.isSelected,s=e.innerRef,u=e.innerProps;return y().createElement("div",nt({ref:s,className:i(Ze(l("option",e)),{option:!0,"option--is-disabled":n,"option--is-focused":o,"option--is-selected":r},a)},u),t)},Placeholder:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerProps;return y().createElement("div",nt({className:i(Ze(l("placeholder",e)),{placeholder:!0},a)},n),t)},SelectContainer:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.innerProps,o=e.isDisabled,r=e.isRtl;return y().createElement("div",nt({className:i(Ze(l("container",e)),{"--is-disabled":o,"--is-rtl":r},a)},n),t)},SingleValue:function(e){var t=e.children,a=e.className,i=e.cx,l=e.getStyles,n=e.isDisabled,o=e.innerProps;return y().createElement("div",nt({className:i(Ze(l("singleValue",e)),{"single-value":!0,"single-value--is-disabled":n},a)},o),t)},ValueContainer:la},_a=function(e){return ot({},xa,e.components)},ka={clearIndicator:ca,container:function(e){var t=e.isDisabled;return{label:"container",direction:e.isRtl?"rtl":null,pointerEvents:t?"none":null,position:"relative"}},control:function(e){var t=e.isDisabled,a=e.isFocused,i=e.theme,l=i.colors,n=i.borderRadius,o=i.spacing;return{label:"control",alignItems:"center",backgroundColor:t?l.neutral5:l.neutral0,borderColor:t?l.neutral10:a?l.primary:l.neutral20,borderRadius:n,borderStyle:"solid",borderWidth:1,boxShadow:a?"0 0 0 1px ".concat(l.primary):null,cursor:"default",display:"flex",flexWrap:"wrap",justifyContent:"space-between",minHeight:o.controlHeight,outline:"0 !important",position:"relative",transition:"all 100ms","&:hover":{borderColor:a?l.primary:l.neutral30}}},dropdownIndicator:ua,group:function(e){var t=e.theme.spacing;return{paddingBottom:2*t.baseUnit,paddingTop:2*t.baseUnit}},groupHeading:function(e){var t=e.theme.spacing;return{label:"group",color:"#999",cursor:"default",display:"block",fontSize:"75%",fontWeight:"500",marginBottom:"0.25em",paddingLeft:3*t.baseUnit,paddingRight:3*t.baseUnit,textTransform:"uppercase"}},indicatorsContainer:function(){return{alignItems:"center",alignSelf:"stretch",display:"flex",flexShrink:0}},indicatorSeparator:function(e){var t=e.isDisabled,a=e.theme,i=a.spacing.baseUnit,l=a.colors;return{label:"indicatorSeparator",alignSelf:"stretch",backgroundColor:t?l.neutral10:l.neutral20,marginBottom:2*i,marginTop:2*i,width:1}},input:function(e){var t=e.isDisabled,a=e.theme,i=a.spacing,l=a.colors;return{margin:i.baseUnit/2,paddingBottom:i.baseUnit/2,paddingTop:i.baseUnit/2,visibility:t?"hidden":"visible",color:l.neutral80}},loadingIndicator:function(e){var t=e.isFocused,a=e.size,i=e.theme,l=i.colors,n=i.spacing.baseUnit;return{label:"loadingIndicator",color:t?l.neutral60:l.neutral20,display:"flex",padding:2*n,transition:"color 150ms",alignSelf:"center",fontSize:a,lineHeight:1,marginRight:a,textAlign:"center",verticalAlign:"middle"}},loadingMessage:Tt,menu:function(e){var t,a=e.placement,i=e.theme,l=i.borderRadius,n=i.spacing,o=i.colors;return lt(t={label:"menu"},function(e){return e?{bottom:"top",top:"bottom"}[e]:"bottom"}(a),"100%"),lt(t,"backgroundColor",o.neutral0),lt(t,"borderRadius",l),lt(t,"boxShadow","0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 11px hsla(0, 0%, 0%, 0.1)"),lt(t,"marginBottom",n.menuGutter),lt(t,"marginTop",n.menuGutter),lt(t,"position","absolute"),lt(t,"width","100%"),lt(t,"zIndex",1),t},menuList:function(e){var t=e.maxHeight,a=e.theme.spacing.baseUnit;return{maxHeight:t,overflowY:"auto",paddingBottom:a,paddingTop:a,position:"relative",WebkitOverflowScrolling:"touch"}},menuPortal:function(e){var t=e.rect,a=e.offset,i=e.position;return{left:t.left,position:i,top:a,width:t.width,zIndex:1}},multiValue:function(e){var t=e.theme,a=t.spacing,i=t.borderRadius;return{label:"multiValue",backgroundColor:t.colors.neutral10,borderRadius:i/2,display:"flex",margin:a.baseUnit/2,minWidth:0}},multiValueLabel:function(e){var t=e.theme,a=t.borderRadius,i=t.colors,l=e.cropWithEllipsis;return{borderRadius:a/2,color:i.neutral80,fontSize:"85%",overflow:"hidden",padding:3,paddingLeft:6,textOverflow:l?"ellipsis":null,whiteSpace:"nowrap"}},multiValueRemove:function(e){var t=e.theme,a=t.spacing,i=t.borderRadius,l=t.colors;return{alignItems:"center",borderRadius:i/2,backgroundColor:e.isFocused&&l.dangerLight,display:"flex",paddingLeft:a.baseUnit,paddingRight:a.baseUnit,":hover":{backgroundColor:l.dangerLight,color:l.danger}}},noOptionsMessage:Mt,option:function(e){var t=e.isDisabled,a=e.isFocused,i=e.isSelected,l=e.theme,n=l.spacing,o=l.colors;return{label:"option",backgroundColor:i?o.primary:a?o.primary25:"transparent",color:t?o.neutral20:i?o.neutral0:"inherit",cursor:"default",display:"block",fontSize:"inherit",padding:"".concat(2*n.baseUnit,"px ").concat(3*n.baseUnit,"px"),width:"100%",userSelect:"none",WebkitTapHighlightColor:"rgba(0, 0, 0, 0)",":active":{backgroundColor:!t&&(i?o.primary:o.primary50)}}},placeholder:function(e){var t=e.theme,a=t.spacing;return{label:"placeholder",color:t.colors.neutral50,marginLeft:a.baseUnit/2,marginRight:a.baseUnit/2,position:"absolute",top:"50%",transform:"translateY(-50%)"}},singleValue:function(e){var t=e.isDisabled,a=e.theme,i=a.spacing,l=a.colors;return{label:"singleValue",color:t?l.neutral40:l.neutral80,marginLeft:i.baseUnit/2,marginRight:i.baseUnit/2,maxWidth:"calc(100% - ".concat(2*i.baseUnit,"px)"),overflow:"hidden",position:"absolute",textOverflow:"ellipsis",whiteSpace:"nowrap",top:"50%",transform:"translateY(-50%)"}},valueContainer:function(e){var t=e.theme.spacing;return{alignItems:"center",display:"flex",flex:1,flexWrap:"wrap",padding:"".concat(t.baseUnit/2,"px ").concat(2*t.baseUnit,"px"),WebkitOverflowScrolling:"touch",position:"relative",overflow:"hidden"}}},Sa={borderRadius:4,colors:{primary:"#2684FF",primary75:"#4C9AFF",primary50:"#B2D4FF",primary25:"#DEEBFF",danger:"#DE350B",dangerLight:"#FFBDAD",neutral0:"hsl(0, 0%, 100%)",neutral5:"hsl(0, 0%, 95%)",neutral10:"hsl(0, 0%, 90%)",neutral20:"hsl(0, 0%, 80%)",neutral30:"hsl(0, 0%, 70%)",neutral40:"hsl(0, 0%, 60%)",neutral50:"hsl(0, 0%, 50%)",neutral60:"hsl(0, 0%, 40%)",neutral70:"hsl(0, 0%, 30%)",neutral80:"hsl(0, 0%, 20%)",neutral90:"hsl(0, 0%, 10%)"},spacing:{baseUnit:4,controlHeight:38,menuGutter:8}},Ca={backspaceRemovesValue:!0,blurInputOnSelect:_t(),captureMenuScroll:!_t(),closeMenuOnSelect:!0,closeMenuOnScroll:!1,components:{},controlShouldRenderValue:!0,escapeClearsValue:!1,filterOption:function(e,t){var a=ot({ignoreCase:!0,ignoreAccents:!0,stringify:It,trim:!0,matchFrom:"any"},void 0),i=a.ignoreCase,l=a.ignoreAccents,n=a.stringify,o=a.trim,r=a.matchFrom,s=o?Ft(t):t,u=o?Ft(n(e)):n(e);return i&&(s=s.toLowerCase(),u=u.toLowerCase()),l&&(s=Ot(s),u=Ot(u)),"start"===r?u.substr(0,s.length)===s:u.indexOf(s)>-1},formatGroupLabel:function(e){return e.label},getOptionLabel:function(e){return e.label},getOptionValue:function(e){return e.value},isDisabled:!1,isLoading:!1,isMulti:!1,isRtl:!1,isSearchable:!0,isOptionDisabled:ia,loadingMessage:function(){return"Loading..."},maxMenuHeight:300,minMenuHeight:140,menuIsOpen:!1,menuPlacement:"bottom",menuPosition:"absolute",menuShouldBlockScroll:!1,menuShouldScrollIntoView:!function(){try{return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)}catch(e){return!1}}(),noOptionsMessage:function(){return"No options"},openMenuOnFocus:!1,openMenuOnClick:!0,options:[],pageSize:5,placeholder:"Select...",screenReaderStatus:function(e){var t=e.count;return"".concat(t," result").concat(1!==t?"s":""," available")},styles:{},tabIndex:"0",tabSelectsValue:!0},Ma=1,Ta=function(e){function t(e){var a;tt(this,t),lt(gt(gt(a=dt(this,st(t).call(this,e)))),"state",{ariaLiveSelection:"",ariaLiveContext:"",focusedOption:null,focusedValue:null,inputIsHidden:!1,isFocused:!1,menuOptions:{render:[],focusable:[]},selectValue:[]}),lt(gt(gt(a)),"blockOptionHover",!1),lt(gt(gt(a)),"isComposing",!1),lt(gt(gt(a)),"clearFocusValueOnUpdate",!1),lt(gt(gt(a)),"commonProps",void 0),lt(gt(gt(a)),"components",void 0),lt(gt(gt(a)),"hasGroups",!1),lt(gt(gt(a)),"initialTouchX",0),lt(gt(gt(a)),"initialTouchY",0),lt(gt(gt(a)),"inputIsHiddenAfterUpdate",void 0),lt(gt(gt(a)),"instancePrefix",""),lt(gt(gt(a)),"openAfterFocus",!1),lt(gt(gt(a)),"scrollToFocusedOptionOnUpdate",!1),lt(gt(gt(a)),"userIsDragging",void 0),lt(gt(gt(a)),"controlRef",null),lt(gt(gt(a)),"getControlRef",function(e){a.controlRef=e}),lt(gt(gt(a)),"focusedOptionRef",null),lt(gt(gt(a)),"getFocusedOptionRef",function(e){a.focusedOptionRef=e}),lt(gt(gt(a)),"menuListRef",null),lt(gt(gt(a)),"getMenuListRef",function(e){a.menuListRef=e}),lt(gt(gt(a)),"inputRef",null),lt(gt(gt(a)),"getInputRef",function(e){a.inputRef=e}),lt(gt(gt(a)),"cacheComponents",function(e){a.components=_a({components:e})}),lt(gt(gt(a)),"focus",a.focusInput),lt(gt(gt(a)),"blur",a.blurInput),lt(gt(gt(a)),"onChange",function(e,t){var i=a.props;(0,i.onChange)(e,ot({},t,{name:i.name}))}),lt(gt(gt(a)),"setValue",function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"set-value",i=arguments.length>2?arguments[2]:void 0,l=a.props,n=l.closeMenuOnSelect,o=l.isMulti;a.onInputChange("",{action:"set-value"}),n&&(a.inputIsHiddenAfterUpdate=!o,a.onMenuClose()),a.clearFocusValueOnUpdate=!0,a.onChange(e,{action:t,option:i})}),lt(gt(gt(a)),"selectOption",function(e){var t=a.props,i=t.blurInputOnSelect,l=t.isMulti,n=a.state.selectValue;if(l)if(a.isOptionSelected(e,n)){var o=a.getOptionValue(e);a.setValue(n.filter(function(e){return a.getOptionValue(e)!==o}),"deselect-option",e),a.announceAriaLiveSelection({event:"deselect-option",context:{value:a.getOptionLabel(e)}})}else a.isOptionDisabled(e,n)?a.announceAriaLiveSelection({event:"select-option",context:{value:a.getOptionLabel(e),isDisabled:!0}}):(a.setValue([].concat(pt(n),[e]),"select-option",e),a.announceAriaLiveSelection({event:"select-option",context:{value:a.getOptionLabel(e)}}));else a.isOptionDisabled(e,n)?a.announceAriaLiveSelection({event:"select-option",context:{value:a.getOptionLabel(e),isDisabled:!0}}):(a.setValue(e,"select-option"),a.announceAriaLiveSelection({event:"select-option",context:{value:a.getOptionLabel(e)}}));i&&a.blurInput()}),lt(gt(gt(a)),"removeValue",function(e){var t=a.state.selectValue,i=a.getOptionValue(e);a.onChange(t.filter(function(e){return a.getOptionValue(e)!==i}),{action:"remove-value",removedValue:e}),a.announceAriaLiveSelection({event:"remove-value",context:{value:e?a.getOptionLabel(e):""}}),a.focusInput()}),lt(gt(gt(a)),"clearValue",function(){var e=a.props.isMulti;a.onChange(e?[]:null,{action:"clear"})}),lt(gt(gt(a)),"popValue",function(){var e=a.state.selectValue,t=e[e.length-1];a.announceAriaLiveSelection({event:"pop-value",context:{value:t?a.getOptionLabel(t):""}}),a.onChange(e.slice(0,e.length-1),{action:"pop-value",removedValue:t})}),lt(gt(gt(a)),"getOptionLabel",function(e){return a.props.getOptionLabel(e)}),lt(gt(gt(a)),"getOptionValue",function(e){return a.props.getOptionValue(e)}),lt(gt(gt(a)),"getStyles",function(e,t){var i=ka[e](t);i.boxSizing="border-box";var l=a.props.styles[e];return l?l(i,t):i}),lt(gt(gt(a)),"getElementId",function(e){return"".concat(a.instancePrefix,"-").concat(e)}),lt(gt(gt(a)),"getActiveDescendentId",function(){var e=a.props.menuIsOpen,t=a.state,i=t.menuOptions,l=t.focusedOption;if(l&&e){var n=i.focusable.indexOf(l),o=i.render[n];return o&&o.key}}),lt(gt(gt(a)),"announceAriaLiveSelection",function(e){var t=e.event,i=e.context;a.setState({ariaLiveSelection:aa(t,i)})}),lt(gt(gt(a)),"announceAriaLiveContext",function(e){var t=e.event,i=e.context;a.setState({ariaLiveContext:ta(t,ot({},i,{label:a.props["aria-label"]}))})}),lt(gt(gt(a)),"onMenuMouseDown",function(e){0===e.button&&(e.stopPropagation(),e.preventDefault(),a.focusInput())}),lt(gt(gt(a)),"onMenuMouseMove",function(e){a.blockOptionHover=!1}),lt(gt(gt(a)),"onControlMouseDown",function(e){var t=a.props.openMenuOnClick;a.state.isFocused?a.props.menuIsOpen?"INPUT"!==e.target.tagName&&a.onMenuClose():t&&a.openMenu("first"):(t&&(a.openAfterFocus=!0),a.focusInput()),"INPUT"!==e.target.tagName&&e.preventDefault()}),lt(gt(gt(a)),"onDropdownIndicatorMouseDown",function(e){if(!(e&&"mousedown"===e.type&&0!==e.button||a.props.isDisabled)){var t=a.props,i=t.isMulti,l=t.menuIsOpen;a.focusInput(),l?(a.inputIsHiddenAfterUpdate=!i,a.onMenuClose()):a.openMenu("first"),e.preventDefault(),e.stopPropagation()}}),lt(gt(gt(a)),"onClearIndicatorMouseDown",function(e){e&&"mousedown"===e.type&&0!==e.button||(a.clearValue(),e.stopPropagation(),a.openAfterFocus=!1,setTimeout(function(){return a.focusInput()}))}),lt(gt(gt(a)),"onScroll",function(e){"boolean"==typeof a.props.closeMenuOnScroll?e.target instanceof HTMLElement&&vt(e.target)&&a.props.onMenuClose():"function"==typeof a.props.closeMenuOnScroll&&a.props.closeMenuOnScroll(e)&&a.props.onMenuClose()}),lt(gt(gt(a)),"onCompositionStart",function(){a.isComposing=!0}),lt(gt(gt(a)),"onCompositionEnd",function(){a.isComposing=!1}),lt(gt(gt(a)),"onTouchStart",function(e){var t=e.touches.item(0);t&&(a.initialTouchX=t.clientX,a.initialTouchY=t.clientY,a.userIsDragging=!1)}),lt(gt(gt(a)),"onTouchMove",function(e){var t=e.touches.item(0);if(t){var i=Math.abs(t.clientX-a.initialTouchX),l=Math.abs(t.clientY-a.initialTouchY);a.userIsDragging=i>5||l>5}}),lt(gt(gt(a)),"onTouchEnd",function(e){a.userIsDragging||(a.controlRef&&!a.controlRef.contains(e.target)&&a.menuListRef&&!a.menuListRef.contains(e.target)&&a.blurInput(),a.initialTouchX=0,a.initialTouchY=0)}),lt(gt(gt(a)),"onControlTouchEnd",function(e){a.userIsDragging||a.onControlMouseDown(e)}),lt(gt(gt(a)),"onClearIndicatorTouchEnd",function(e){a.userIsDragging||a.onClearIndicatorMouseDown(e)}),lt(gt(gt(a)),"onDropdownIndicatorTouchEnd",function(e){a.userIsDragging||a.onDropdownIndicatorMouseDown(e)}),lt(gt(gt(a)),"handleInputChange",function(e){var t=e.currentTarget.value;a.inputIsHiddenAfterUpdate=!1,a.onInputChange(t,{action:"input-change"}),a.onMenuOpen()}),lt(gt(gt(a)),"onInputFocus",function(e){var t=a.props,i=t.isSearchable,l=t.isMulti;a.props.onFocus&&a.props.onFocus(e),a.inputIsHiddenAfterUpdate=!1,a.announceAriaLiveContext({event:"input",context:{isSearchable:i,isMulti:l}}),a.setState({isFocused:!0}),(a.openAfterFocus||a.props.openMenuOnFocus)&&a.openMenu("first"),a.openAfterFocus=!1}),lt(gt(gt(a)),"onInputBlur",function(e){a.menuListRef&&a.menuListRef.contains(document.activeElement)?a.inputRef.focus():(a.props.onBlur&&a.props.onBlur(e),a.onInputChange("",{action:"input-blur"}),a.onMenuClose(),a.setState({focusedValue:null,isFocused:!1}))}),lt(gt(gt(a)),"onOptionHover",function(e){a.blockOptionHover||a.state.focusedOption===e||a.setState({focusedOption:e})}),lt(gt(gt(a)),"shouldHideSelectedOptions",function(){var e=a.props,t=e.hideSelectedOptions,i=e.isMulti;return void 0===t?i:t}),lt(gt(gt(a)),"onKeyDown",function(e){var t=a.props,i=t.isMulti,l=t.backspaceRemovesValue,n=t.escapeClearsValue,o=t.inputValue,r=t.isClearable,s=t.isDisabled,u=t.menuIsOpen,c=t.onKeyDown,g=t.tabSelectsValue,d=t.openMenuOnFocus,p=a.state,h=p.focusedOption,m=p.focusedValue,b=p.selectValue;if(!(s||"function"==typeof c&&(c(e),e.defaultPrevented))){switch(a.blockOptionHover=!0,e.key){case"ArrowLeft":if(!i||o)return;a.focusValue("previous");break;case"ArrowRight":if(!i||o)return;a.focusValue("next");break;case"Delete":case"Backspace":if(o)return;if(m)a.removeValue(m);else{if(!l)return;i?a.popValue():r&&a.clearValue()}break;case"Tab":if(a.isComposing)return;if(e.shiftKey||!u||!g||!h||d&&a.isOptionSelected(h,b))return;a.selectOption(h);break;case"Enter":if(229===e.keyCode)break;if(u){if(!h)return;if(a.isComposing)return;a.selectOption(h);break}return;case"Escape":u?(a.inputIsHiddenAfterUpdate=!1,a.onInputChange("",{action:"menu-close"}),a.onMenuClose()):r&&n&&a.clearValue();break;case" ":if(o)return;if(!u){a.openMenu("first");break}if(!h)return;a.selectOption(h);break;case"ArrowUp":u?a.focusOption("up"):a.openMenu("last");break;case"ArrowDown":u?a.focusOption("down"):a.openMenu("first");break;case"PageUp":if(!u)return;a.focusOption("pageup");break;case"PageDown":if(!u)return;a.focusOption("pagedown");break;case"Home":if(!u)return;a.focusOption("first");break;case"End":if(!u)return;a.focusOption("last");break;default:return}e.preventDefault()}});var i=e.value;a.cacheComponents=He(a.cacheComponents,Pt).bind(gt(gt(a))),a.cacheComponents(e.components),a.instancePrefix="react-select-"+(a.props.instanceId||++Ma);var l=ft(i),n=a.buildMenuOptions(e,l);return a.state.menuOptions=n,a.state.selectValue=l,a}return rt(t,e),it(t,[{key:"componentDidMount",value:function(){this.startListeningComposition(),this.startListeningToTouch(),this.props.closeMenuOnScroll&&document&&document.addEventListener&&document.addEventListener("scroll",this.onScroll,!0),this.props.autoFocus&&this.focusInput()}},{key:"componentWillReceiveProps",value:function(e){var t=this.props,a=t.options,i=t.value,l=t.inputValue;if(this.cacheComponents(e.components),e.value!==i||e.options!==a||e.inputValue!==l){var n=ft(e.value),o=this.buildMenuOptions(e,n),r=this.getNextFocusedValue(n),s=this.getNextFocusedOption(o.focusable);this.setState({menuOptions:o,selectValue:n,focusedOption:s,focusedValue:r})}null!=this.inputIsHiddenAfterUpdate&&(this.setState({inputIsHidden:this.inputIsHiddenAfterUpdate}),delete this.inputIsHiddenAfterUpdate)}},{key:"componentDidUpdate",value:function(e){var t,a,i,l,n,o=this.props,r=o.isDisabled,s=o.menuIsOpen,u=this.state.isFocused;(u&&!r&&e.isDisabled||u&&s&&!e.menuIsOpen)&&this.focusInput(),this.menuListRef&&this.focusedOptionRef&&this.scrollToFocusedOptionOnUpdate&&(t=this.menuListRef,a=this.focusedOptionRef,i=t.getBoundingClientRect(),l=a.getBoundingClientRect(),n=a.offsetHeight/3,l.bottom+n>i.bottom?yt(t,Math.min(a.offsetTop+a.clientHeight-t.offsetHeight+n,t.scrollHeight)):l.top-n<i.top&&yt(t,Math.max(a.offsetTop-n,0))),this.scrollToFocusedOptionOnUpdate=!1}},{key:"componentWillUnmount",value:function(){this.stopListeningComposition(),this.stopListeningToTouch(),document.removeEventListener("scroll",this.onScroll,!0)}},{key:"onMenuOpen",value:function(){this.props.onMenuOpen()}},{key:"onMenuClose",value:function(){var e=this.props,t=e.isSearchable,a=e.isMulti;this.announceAriaLiveContext({event:"input",context:{isSearchable:t,isMulti:a}}),this.onInputChange("",{action:"menu-close"}),this.props.onMenuClose()}},{key:"onInputChange",value:function(e,t){this.props.onInputChange(e,t)}},{key:"focusInput",value:function(){this.inputRef&&this.inputRef.focus()}},{key:"blurInput",value:function(){this.inputRef&&this.inputRef.blur()}},{key:"openMenu",value:function(e){var t=this.state,a=t.menuOptions,i=t.selectValue,l=t.isFocused,n=this.props.isMulti,o="first"===e?0:a.focusable.length-1;if(!n){var r=a.focusable.indexOf(i[0]);r>-1&&(o=r)}this.scrollToFocusedOptionOnUpdate=!(l&&this.menuListRef),this.inputIsHiddenAfterUpdate=!1,this.onMenuOpen(),this.setState({focusedValue:null,focusedOption:a.focusable[o]}),this.announceAriaLiveContext({event:"menu"})}},{key:"focusValue",value:function(e){var t=this.props,a=t.isMulti,i=t.isSearchable,l=this.state,n=l.selectValue,o=l.focusedValue;if(a){this.setState({focusedOption:null});var r=n.indexOf(o);o||(r=-1,this.announceAriaLiveContext({event:"value"}));var s=n.length-1,u=-1;if(n.length){switch(e){case"previous":u=0===r?0:-1===r?s:r-1;break;case"next":r>-1&&r<s&&(u=r+1)}-1===u&&this.announceAriaLiveContext({event:"input",context:{isSearchable:i,isMulti:a}}),this.setState({inputIsHidden:-1!==u,focusedValue:n[u]})}}}},{key:"focusOption",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"first",t=this.props.pageSize,a=this.state,i=a.focusedOption,l=a.menuOptions.focusable;if(l.length){var n=0,o=l.indexOf(i);i||(o=-1,this.announceAriaLiveContext({event:"menu"})),"up"===e?n=o>0?o-1:l.length-1:"down"===e?n=(o+1)%l.length:"pageup"===e?(n=o-t)<0&&(n=0):"pagedown"===e?(n=o+t)>l.length-1&&(n=l.length-1):"last"===e&&(n=l.length-1),this.scrollToFocusedOptionOnUpdate=!0,this.setState({focusedOption:l[n],focusedValue:null}),this.announceAriaLiveContext({event:"menu",context:{isDisabled:ia(l[n])}})}}},{key:"getTheme",value:function(){return this.props.theme?"function"==typeof this.props.theme?this.props.theme(Sa):ot({},Sa,this.props.theme):Sa}},{key:"getCommonProps",value:function(){var e=this.clearValue,t=this.getStyles,a=this.setValue,i=this.selectOption,l=this.props,n=l.classNamePrefix,o=l.isMulti,r=l.isRtl,s=l.options,u=this.state.selectValue,c=this.hasValue();return{cx:bt.bind(null,n),clearValue:e,getStyles:t,getValue:function(){return u},hasValue:c,isMulti:o,isRtl:r,options:s,selectOption:i,setValue:a,selectProps:l,theme:this.getTheme()}}},{key:"getNextFocusedValue",value:function(e){if(this.clearFocusValueOnUpdate)return this.clearFocusValueOnUpdate=!1,null;var t=this.state,a=t.focusedValue,i=t.selectValue.indexOf(a);if(i>-1){if(e.indexOf(a)>-1)return a;if(i<e.length)return e[i]}return null}},{key:"getNextFocusedOption",value:function(e){var t=this.state.focusedOption;return t&&e.indexOf(t)>-1?t:e[0]}},{key:"hasValue",value:function(){return this.state.selectValue.length>0}},{key:"hasOptions",value:function(){return!!this.state.menuOptions.render.length}},{key:"countOptions",value:function(){return this.state.menuOptions.focusable.length}},{key:"isClearable",value:function(){var e=this.props,t=e.isClearable,a=e.isMulti;return void 0===t?a:t}},{key:"isOptionDisabled",value:function(e,t){return"function"==typeof this.props.isOptionDisabled&&this.props.isOptionDisabled(e,t)}},{key:"isOptionSelected",value:function(e,t){var a=this;if(t.indexOf(e)>-1)return!0;if("function"==typeof this.props.isOptionSelected)return this.props.isOptionSelected(e,t);var i=this.getOptionValue(e);return t.some(function(e){return a.getOptionValue(e)===i})}},{key:"filterOption",value:function(e,t){return!this.props.filterOption||this.props.filterOption(e,t)}},{key:"formatOptionLabel",value:function(e,t){if("function"==typeof this.props.formatOptionLabel){var a=this.props.inputValue,i=this.state.selectValue;return this.props.formatOptionLabel(e,{context:t,inputValue:a,selectValue:i})}return this.getOptionLabel(e)}},{key:"formatGroupLabel",value:function(e){return this.props.formatGroupLabel(e)}},{key:"startListeningComposition",value:function(){document&&document.addEventListener&&(document.addEventListener("compositionstart",this.onCompositionStart,!1),document.addEventListener("compositionend",this.onCompositionEnd,!1))}},{key:"stopListeningComposition",value:function(){document&&document.removeEventListener&&(document.removeEventListener("compositionstart",this.onCompositionStart),document.removeEventListener("compositionend",this.onCompositionEnd))}},{key:"startListeningToTouch",value:function(){document&&document.addEventListener&&(document.addEventListener("touchstart",this.onTouchStart,!1),document.addEventListener("touchmove",this.onTouchMove,!1),document.addEventListener("touchend",this.onTouchEnd,!1))}},{key:"stopListeningToTouch",value:function(){document&&document.removeEventListener&&(document.removeEventListener("touchstart",this.onTouchStart),document.removeEventListener("touchmove",this.onTouchMove),document.removeEventListener("touchend",this.onTouchEnd))}},{key:"buildMenuOptions",value:function(e,t){var a=this,i=e.inputValue,l=void 0===i?"":i,n=e.options,o=function(e,i){var n=a.isOptionDisabled(e,t),o=a.isOptionSelected(e,t),r=a.getOptionLabel(e),s=a.getOptionValue(e);if(!(a.shouldHideSelectedOptions()&&o||!a.filterOption({label:r,value:s,data:e},l))){var u=n?void 0:function(){return a.onOptionHover(e)},c=n?void 0:function(){return a.selectOption(e)},g="".concat(a.getElementId("option"),"-").concat(i);return{innerProps:{id:g,onClick:c,onMouseMove:u,onMouseOver:u,tabIndex:-1},data:e,isDisabled:n,isSelected:o,key:g,label:r,type:"option",value:s}}};return n.reduce(function(e,t,i){if(t.options){a.hasGroups||(a.hasGroups=!0);var l=t.options.map(function(t,a){var l=o(t,"".concat(i,"-").concat(a));return l&&e.focusable.push(t),l}).filter(Boolean);if(l.length){var n="".concat(a.getElementId("group"),"-").concat(i);e.render.push({type:"group",key:n,data:t,options:l})}}else{var r=o(t,"".concat(i));r&&(e.render.push(r),e.focusable.push(t))}return e},{render:[],focusable:[]})}},{key:"constructAriaLiveMessage",value:function(){var e=this.state,t=e.ariaLiveContext,a=e.selectValue,i=e.focusedValue,l=e.focusedOption,n=this.props,o=n.options,r=n.menuIsOpen,s=n.inputValue,u=n.screenReaderStatus,c=i?function(e){var t=e.focusedValue,a=e.selectValue;return"value ".concat((0,e.getOptionLabel)(t)," focused, ").concat(a.indexOf(t)+1," of ").concat(a.length,".")}({focusedValue:i,getOptionLabel:this.getOptionLabel,selectValue:a}):"",g=l&&r?function(e){var t=e.focusedOption,a=e.options;return"option ".concat((0,e.getOptionLabel)(t)," focused").concat(t.isDisabled?" disabled":"",", ").concat(a.indexOf(t)+1," of ").concat(a.length,".")}({focusedOption:l,getOptionLabel:this.getOptionLabel,options:o}):"",d=function(e){var t=e.inputValue;return"".concat(e.screenReaderMessage).concat(t?" for search term "+t:"",".")}({inputValue:s,screenReaderMessage:u({count:this.countOptions()})});return"".concat(c," ").concat(g," ").concat(d," ").concat(t)}},{key:"renderInput",value:function(){var e=this.props,t=e.isDisabled,a=e.isSearchable,i=e.inputId,l=e.inputValue,n=e.tabIndex,o=this.components.Input,r=this.state.inputIsHidden,s=i||this.getElementId("input");if(!a)return y().createElement(Vt,{id:s,innerRef:this.getInputRef,onBlur:this.onInputBlur,onChange:ht,onFocus:this.onInputFocus,readOnly:!0,disabled:t,tabIndex:n,value:""});var u={"aria-autocomplete":"list","aria-label":this.props["aria-label"],"aria-labelledby":this.props["aria-labelledby"]},c=this.commonProps,g=c.cx,d=c.theme,p=c.selectProps;return y().createElement(o,nt({autoCapitalize:"none",autoComplete:"off",autoCorrect:"off",cx:g,getStyles:this.getStyles,id:s,innerRef:this.getInputRef,isDisabled:t,isHidden:r,onBlur:this.onInputBlur,onChange:this.handleInputChange,onFocus:this.onInputFocus,selectProps:p,spellCheck:"false",tabIndex:n,theme:d,type:"text",value:l},u))}},{key:"renderPlaceholderOrValue",value:function(){var e=this,t=this.components,a=t.MultiValue,i=t.MultiValueContainer,l=t.MultiValueLabel,n=t.MultiValueRemove,o=t.SingleValue,r=t.Placeholder,s=this.commonProps,u=this.props,c=u.controlShouldRenderValue,g=u.isDisabled,d=u.isMulti,p=u.inputValue,h=u.placeholder,m=this.state,b=m.selectValue,f=m.focusedValue,v=m.isFocused;if(!this.hasValue()||!c)return p?null:y().createElement(r,nt({},s,{key:"placeholder",isDisabled:g,isFocused:v}),h);if(d)return b.map(function(t){var o=t===f;return y().createElement(a,nt({},s,{components:{Container:i,Label:l,Remove:n},isFocused:o,isDisabled:g,key:e.getOptionValue(t),removeProps:{onClick:function(){return e.removeValue(t)},onTouchEnd:function(){return e.removeValue(t)},onMouseDown:function(e){e.preventDefault(),e.stopPropagation()}},data:t}),e.formatOptionLabel(t,"value"))});if(p)return null;var w=b[0];return y().createElement(o,nt({},s,{data:w,isDisabled:g}),this.formatOptionLabel(w,"value"))}},{key:"renderClearIndicator",value:function(){var e=this.components.ClearIndicator,t=this.commonProps,a=this.props,i=a.isDisabled,l=a.isLoading,n=this.state.isFocused;if(!this.isClearable()||!e||i||!this.hasValue()||l)return null;var o={onMouseDown:this.onClearIndicatorMouseDown,onTouchEnd:this.onClearIndicatorTouchEnd,"aria-hidden":"true"};return y().createElement(e,nt({},t,{innerProps:o,isFocused:n}))}},{key:"renderLoadingIndicator",value:function(){var e=this.components.LoadingIndicator,t=this.commonProps,a=this.props,i=a.isDisabled,l=a.isLoading,n=this.state.isFocused;return e&&l?y().createElement(e,nt({},t,{innerProps:{"aria-hidden":"true"},isDisabled:i,isFocused:n})):null}},{key:"renderIndicatorSeparator",value:function(){var e=this.components,t=e.DropdownIndicator,a=e.IndicatorSeparator;if(!t||!a)return null;var i=this.commonProps,l=this.props.isDisabled,n=this.state.isFocused;return y().createElement(a,nt({},i,{isDisabled:l,isFocused:n}))}},{key:"renderDropdownIndicator",value:function(){var e=this.components.DropdownIndicator;if(!e)return null;var t=this.commonProps,a=this.props.isDisabled,i=this.state.isFocused,l={onMouseDown:this.onDropdownIndicatorMouseDown,onTouchEnd:this.onDropdownIndicatorTouchEnd,"aria-hidden":"true"};return y().createElement(e,nt({},t,{innerProps:l,isDisabled:a,isFocused:i}))}},{key:"renderMenu",value:function(){var e=this,t=this.components,a=t.Group,i=t.GroupHeading,l=t.Menu,n=t.MenuList,o=t.MenuPortal,r=t.LoadingMessage,s=t.NoOptionsMessage,u=t.Option,c=this.commonProps,g=this.state,d=g.focusedOption,p=g.menuOptions,h=this.props,m=h.captureMenuScroll,b=h.inputValue,f=h.isLoading,v=h.loadingMessage,w=h.minMenuHeight,x=h.maxMenuHeight,_=h.menuIsOpen,k=h.menuPlacement,S=h.menuPosition,C=h.menuPortalTarget,M=h.menuShouldBlockScroll,T=h.menuShouldScrollIntoView,E=h.noOptionsMessage,D=h.onMenuScrollToTop,L=h.onMenuScrollToBottom;if(!_)return null;var B,H=function(t){var a=d===t.data;return t.innerRef=a?e.getFocusedOptionRef:void 0,y().createElement(u,nt({},c,t,{isFocused:a}),e.formatOptionLabel(t.data,"menu"))};if(this.hasOptions())B=p.render.map(function(t){if("group"===t.type){t.type;var l=ct(t,["type"]),n="".concat(t.key,"-heading");return y().createElement(a,nt({},c,l,{Heading:i,headingProps:{id:n},label:e.formatGroupLabel(t.data)}),t.options.map(function(e){return H(e)}))}if("option"===t.type)return H(t)});else if(f){var A=v({inputValue:b});if(null===A)return null;B=y().createElement(r,c,A)}else{var R=E({inputValue:b});if(null===R)return null;B=y().createElement(s,c,R)}var P={minMenuHeight:w,maxMenuHeight:x,menuPlacement:k,menuPosition:S,menuShouldScrollIntoView:T},z=y().createElement(St,nt({},c,P),function(t){var a=t.ref,i=t.placerProps,o=i.placement,r=i.maxHeight;return y().createElement(l,nt({},c,P,{innerRef:a,innerProps:{onMouseDown:e.onMenuMouseDown,onMouseMove:e.onMenuMouseMove},isLoading:f,placement:o}),y().createElement(ea,{isEnabled:m,onTopArrive:D,onBottomArrive:L},y().createElement(Xt,{isEnabled:M},y().createElement(n,nt({},c,{innerRef:e.getMenuListRef,isLoading:f,maxHeight:r}),B))))});return C||"fixed"===S?y().createElement(o,nt({},c,{appendTo:C,controlElement:this.controlRef,menuPlacement:k,menuPosition:S}),z):z}},{key:"renderFormField",value:function(){var e=this,t=this.props,a=t.delimiter,i=t.isDisabled,l=t.isMulti,n=t.name,o=this.state.selectValue;if(n&&!i){if(l){if(a){var r=o.map(function(t){return e.getOptionValue(t)}).join(a);return y().createElement("input",{name:n,type:"hidden",value:r})}var s=o.length>0?o.map(function(t,a){return y().createElement("input",{key:"i-".concat(a),name:n,type:"hidden",value:e.getOptionValue(t)})}):y().createElement("input",{name:n,type:"hidden"});return y().createElement("div",null,s)}var u=o[0]?this.getOptionValue(o[0]):"";return y().createElement("input",{name:n,type:"hidden",value:u})}}},{key:"renderLiveRegion",value:function(){return this.state.isFocused?y().createElement(Nt,{"aria-live":"assertive"},y().createElement("p",{id:"aria-selection-event"}," ",this.state.ariaLiveSelection),y().createElement("p",{id:"aria-context"}," ",this.constructAriaLiveMessage())):null}},{key:"render",value:function(){var e=this.components,t=e.Control,a=e.IndicatorsContainer,i=e.SelectContainer,l=e.ValueContainer,n=this.props,o=n.className,r=n.id,s=n.isDisabled,u=n.menuIsOpen,c=this.state.isFocused,g=this.commonProps=this.getCommonProps();return y().createElement(i,nt({},g,{className:o,innerProps:{id:r,onKeyDown:this.onKeyDown},isDisabled:s,isFocused:c}),this.renderLiveRegion(),y().createElement(t,nt({},g,{innerRef:this.getControlRef,innerProps:{onMouseDown:this.onControlMouseDown,onTouchEnd:this.onControlTouchEnd},isDisabled:s,isFocused:c,menuIsOpen:u}),y().createElement(l,nt({},g,{isDisabled:s}),this.renderPlaceholderOrValue(),this.renderInput()),y().createElement(a,nt({},g,{isDisabled:s}),this.renderClearIndicator(),this.renderLoadingIndicator(),this.renderIndicatorSeparator(),this.renderDropdownIndicator())),this.renderMenu(),this.renderFormField())}}]),t}(w.Component);lt(Ta,"defaultProps",Ca);var Ea={defaultInputValue:"",defaultMenuIsOpen:!1,defaultValue:null},Da=function(e){var t,a;return a=t=function(t){function a(){var e,t;tt(this,a);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(t=dt(this,(e=st(a)).call.apply(e,[this].concat(l))))),"select",void 0),lt(gt(gt(t)),"state",{inputValue:void 0!==t.props.inputValue?t.props.inputValue:t.props.defaultInputValue,menuIsOpen:void 0!==t.props.menuIsOpen?t.props.menuIsOpen:t.props.defaultMenuIsOpen,value:void 0!==t.props.value?t.props.value:t.props.defaultValue}),lt(gt(gt(t)),"onChange",function(e,a){t.callProp("onChange",e,a),t.setState({value:e})}),lt(gt(gt(t)),"onInputChange",function(e,a){var i=t.callProp("onInputChange",e,a);t.setState({inputValue:void 0!==i?i:e})}),lt(gt(gt(t)),"onMenuOpen",function(){t.callProp("onMenuOpen"),t.setState({menuIsOpen:!0})}),lt(gt(gt(t)),"onMenuClose",function(){t.callProp("onMenuClose"),t.setState({menuIsOpen:!1})}),t}return rt(a,t),it(a,[{key:"focus",value:function(){this.select.focus()}},{key:"blur",value:function(){this.select.blur()}},{key:"getProp",value:function(e){return void 0!==this.props[e]?this.props[e]:this.state[e]}},{key:"callProp",value:function(e){if("function"==typeof this.props[e]){for(var t,a=arguments.length,i=new Array(a>1?a-1:0),l=1;l<a;l++)i[l-1]=arguments[l];return(t=this.props)[e].apply(t,i)}}},{key:"render",value:function(){var t=this,a=this.props,i=(a.defaultInputValue,a.defaultMenuIsOpen,a.defaultValue,ct(a,["defaultInputValue","defaultMenuIsOpen","defaultValue"]));return y().createElement(e,nt({},i,{ref:function(e){t.select=e},inputValue:this.getProp("inputValue"),menuIsOpen:this.getProp("menuIsOpen"),onChange:this.onChange,onInputChange:this.onInputChange,onMenuClose:this.onMenuClose,onMenuOpen:this.onMenuOpen,value:this.getProp("value")}))}}]),a}(w.Component),lt(t,"defaultProps",Ea),a},La={cacheOptions:!1,defaultOptions:!1,filterOption:null},Ba=function(e){var t,a;return a=t=function(t){function a(e){var t;return tt(this,a),lt(gt(gt(t=dt(this,st(a).call(this)))),"select",void 0),lt(gt(gt(t)),"lastRequest",void 0),lt(gt(gt(t)),"mounted",!1),lt(gt(gt(t)),"optionsCache",{}),lt(gt(gt(t)),"handleInputChange",function(e,a){var i=t.props,l=i.cacheOptions,n=function(e,t,a){if(a){var i=a(e,t);if("string"==typeof i)return i}return e}(e,a,i.onInputChange);if(!n)return delete t.lastRequest,void t.setState({inputValue:"",loadedInputValue:"",loadedOptions:[],isLoading:!1,passEmptyOptions:!1});if(l&&t.optionsCache[n])t.setState({inputValue:n,loadedInputValue:n,loadedOptions:t.optionsCache[n],isLoading:!1,passEmptyOptions:!1});else{var o=t.lastRequest={};t.setState({inputValue:n,isLoading:!0,passEmptyOptions:!t.state.loadedInputValue},function(){t.loadOptions(n,function(e){t.mounted&&(e&&(t.optionsCache[n]=e),o===t.lastRequest&&(delete t.lastRequest,t.setState({isLoading:!1,loadedInputValue:n,loadedOptions:e||[],passEmptyOptions:!1})))})})}return n}),t.state={defaultOptions:Array.isArray(e.defaultOptions)?e.defaultOptions:void 0,inputValue:void 0!==e.inputValue?e.inputValue:"",isLoading:!0===e.defaultOptions,loadedOptions:[],passEmptyOptions:!1},t}return rt(a,t),it(a,[{key:"componentDidMount",value:function(){var e=this;this.mounted=!0;var t=this.props.defaultOptions,a=this.state.inputValue;!0===t&&this.loadOptions(a,function(t){if(e.mounted){var a=!!e.lastRequest;e.setState({defaultOptions:t||[],isLoading:a})}})}},{key:"componentWillReceiveProps",value:function(e){e.cacheOptions!==this.props.cacheOptions&&(this.optionsCache={}),e.defaultOptions!==this.props.defaultOptions&&this.setState({defaultOptions:Array.isArray(e.defaultOptions)?e.defaultOptions:void 0})}},{key:"componentWillUnmount",value:function(){this.mounted=!1}},{key:"focus",value:function(){this.select.focus()}},{key:"blur",value:function(){this.select.blur()}},{key:"loadOptions",value:function(e,t){var a=this.props.loadOptions;if(!a)return t();var i=a(e,t);i&&"function"==typeof i.then&&i.then(t,function(){return t()})}},{key:"render",value:function(){var t=this,a=this.props,i=(a.loadOptions,ct(a,["loadOptions"])),l=this.state,n=l.defaultOptions,o=l.inputValue,r=l.isLoading,s=l.loadedInputValue,u=l.loadedOptions,c=l.passEmptyOptions?[]:o&&s?u:n||[];return y().createElement(e,nt({},i,{ref:function(e){t.select=e},options:c,isLoading:r,onInputChange:this.handleInputChange}))}}]),a}(w.Component),lt(t,"defaultProps",La),a},Ha=(Ba(Da(Ta)),function(){var e=arguments.length>1?arguments[1]:void 0,t=String(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").toLowerCase(),a=String(e.value).toLowerCase(),i=String(e.label).toLowerCase();return a===t||i===t}),Aa=ot({allowCreateWhileLoading:!1,createOptionPosition:"last"},{formatCreateLabel:function(e){return'Create "'.concat(e,'"')},isValidNewOption:function(e,t,a){return!(!e||t.some(function(t){return Ha(e,t)})||a.some(function(t){return Ha(e,t)}))},getNewOptionData:function(e,t){return{label:t,value:e,__isNew__:!0}}}),Ra=function(e){var t,a;return a=t=function(t){function a(e){var t;tt(this,a),lt(gt(gt(t=dt(this,st(a).call(this,e)))),"select",void 0),lt(gt(gt(t)),"onChange",function(e,a){var i=t.props,l=i.getNewOptionData,n=i.inputValue,o=i.isMulti,r=i.onChange,s=i.onCreateOption,u=i.value;if("select-option"!==a.action)return r(e,a);var c=t.state.newOption,g=Array.isArray(e)?e:[e];if(g[g.length-1]!==c)r(e,a);else if(s)s(n);else{var d=l(n,n);r(o?[].concat(pt(ft(u)),[d]):d,{action:"create-option"})}});var i=e.options||[];return t.state={newOption:void 0,options:i},t}return rt(a,t),it(a,[{key:"componentWillReceiveProps",value:function(e){var t=e.allowCreateWhileLoading,a=e.createOptionPosition,i=e.formatCreateLabel,l=e.getNewOptionData,n=e.inputValue,o=e.isLoading,r=e.isValidNewOption,s=e.value,u=e.options||[],c=this.state.newOption;c=r(n,ft(s),u)?l(n,i(n)):void 0,this.setState({newOption:c,options:!t&&o||!c?u:"first"===a?[c].concat(pt(u)):[].concat(pt(u),[c])})}},{key:"focus",value:function(){this.select.focus()}},{key:"blur",value:function(){this.select.blur()}},{key:"render",value:function(){var t=this,a=nt({},this.props),i=this.state.options;return y().createElement(e,nt({},a,{ref:function(e){t.select=e},options:i,onChange:this.onChange}))}}]),a}(w.Component),lt(t,"defaultProps",Aa),a},Pa=(Da(Ra(Ta)),Ba(Da(Ra(Ta))),function(e){var t=e.component,a=e.duration,i=void 0===a?1:a,l=e.in,n=(e.onExited,ct(e,["component","duration","in","onExited"])),o={entering:{opacity:0},entered:{opacity:1,transition:"opacity ".concat(i,"ms")},exiting:{opacity:0},exited:{opacity:0}};return y().createElement(Qe.Transition,{mountOnEnter:!0,unmountOnExit:!0,in:l,timeout:i},function(e){var a={style:ot({},o[e])};return y().createElement(t,nt({innerProps:a},n))})}),za=function(e){function t(){var e,a;tt(this,t);for(var i=arguments.length,l=new Array(i),n=0;n<i;n++)l[n]=arguments[n];return lt(gt(gt(a=dt(this,(e=st(t)).call.apply(e,[this].concat(l))))),"duration",260),lt(gt(gt(a)),"rafID",void 0),lt(gt(gt(a)),"state",{width:"auto"}),lt(gt(gt(a)),"transition",{exiting:{width:0,transition:"width ".concat(a.duration,"ms ease-out")},exited:{width:0}}),lt(gt(gt(a)),"getWidth",function(e){e&&isNaN(a.state.width)&&(a.rafID=window.requestAnimationFrame(function(){var t=e.getBoundingClientRect().width;a.setState({width:t})}))}),lt(gt(gt(a)),"getStyle",function(e){return{overflow:"hidden",whiteSpace:"nowrap",width:e}}),lt(gt(gt(a)),"getTransition",function(e){return a.transition[e]}),a}return rt(t,e),it(t,[{key:"componentWillUnmount",value:function(){this.rafID&&window.cancelAnimationFrame(this.rafID)}},{key:"render",value:function(){var e=this,t=this.props,a=t.children,i=t.in,l=this.state.width;return y().createElement(Qe.Transition,{enter:!1,mountOnEnter:!0,unmountOnExit:!0,in:i,timeout:this.duration},function(t){var i=ot({},e.getStyle(l),e.getTransition(t));return y().createElement("div",{ref:e.getWidth,style:i},a)})}}]),t}(w.Component),Oa=function(e){return function(t){var a=t.in,i=t.onExited,l=ct(t,["in","onExited"]);return y().createElement(za,{in:a,onExited:i},y().createElement(e,nt({cropWithEllipsis:a},l)))}},Fa=function(e){return function(t){return y().createElement(Pa,nt({component:e,duration:t.isMulti?260:1},t))}},Ia=function(e){return function(t){return y().createElement(Pa,nt({component:e},t))}},Na=function(e){return function(t){return y().createElement(Qe.TransitionGroup,nt({component:e},t))}},Va=function(){var e,t=_a({components:arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}}),a=t.Input,i=t.MultiValue,l=t.Placeholder,n=t.SingleValue,o=t.ValueContainer,r=ct(t,["Input","MultiValue","Placeholder","SingleValue","ValueContainer"]);return ot({Input:(e=a,function(t){t.in,t.onExited,t.appear,t.enter,t.exit;var a=ct(t,["in","onExited","appear","enter","exit"]);return y().createElement(e,a)}),MultiValue:Oa(i),Placeholder:Fa(l),SingleValue:Ia(n),ValueContainer:Na(o)},r)},Ga=Va();Ga.Input,Ga.MultiValue,Ga.Placeholder,Ga.SingleValue,Ga.ValueContainer,He(Va,Pt);const Wa=Da(Ta),{uag_select_font_globally:Ua,uag_load_select_font_globally:ja}=srfm_spec_blocks_info,qa=function(e){const t=[{value:"Default",label:(0,M.__)("Default","sureforms"),weight:["Default","100","200","300","400","500","600","700","800","900"],google:!1},{value:"Arial",label:"Arial",weight:["Default","100","200","300","400","500","600","700","800","900"],google:!1},{value:"Helvetica",label:"Helvetica",weight:["Default","100","200","300","400","500","600","700","800","900"],google:!1},{value:"Times New Roman",label:"Times New Roman",weight:["Default","100","200","300","400","500","600","700","800","900"],google:!1},{value:"Georgia",label:"Georgia",weight:["Default","100","200","300","400","500","600","700","800","900"],google:!1}];let a="";const i=srfm_spec_blocks_info.spectra_custom_fonts;Object.keys(Ee).map(i=>{t.push({value:i,label:i,weight:Ee[i].weight}),i===e.fontFamily.value&&(a=Ee[i].weight)}),Object.keys(i).map(l=>{t.push({value:l,label:l,weight:i[l].weight}),l===e.fontFamily.value&&(a=i[l].weight)}),""===a&&(a=t[0].weight);const l=[];a.forEach(function(e){l.push({value:"Default"===e?"":e,label:e})});const n="enabled"===ja&&0!==Ua?Ua:t;let o,r;n&&n.map(t=>{e.fontFamily.weight||t.value!==e.fontFamily.value||(o={...e.fontFamily,weight:t.weight,label:t.value})});const s="em"===e.fontSizeType.value?.1:1,u="em"===e.fontSizeTypeMobile?.value?.1:1,c="em"===e.fontSizeTypeTablet?.value?.1:1;return!0!==e.disableFontSize&&(r=(0,w.createElement)(Te,{type:e.fontSizeType,typeLabel:e.fontSizeType.label,typeMobile:e.fontSizeTypeMobile?e.fontSizeTypeMobile:e.fontSizeType,typeLabelMobile:e.fontSizeTypeMobile?.label?e.fontSizeTypeMobile.label:e.fontSizeType.label,typeTablet:e.fontSizeTypeTablet?e.fontSizeTypeTablet:e.fontSizeType,typeLabelTablet:e.fontSizeTypeTablet?.label?e.fontSizeTypeTablet.label:e.fontSizeType.label,sizeMobile:e.fontSizeMobile,sizeMobileLabel:e.fontSizeMobile.label,sizeTablet:e.fontSizeTablet,sizeTabletLabel:e.fontSizeTablet.label,size:e.fontSize,sizeLabel:e.fontSize.label,min:0,sizeMobileText:e.fontSizeLabel?e.fontSizeLabel:(0,M.__)("Font Size","sureforms"),sizeTabletText:e.fontSizeLabel?e.fontSizeLabel:(0,M.__)("Font Size","sureforms"),sizeText:e.fontSizeLabel?e.fontSizeLabel:(0,M.__)("Font Size","sureforms"),step:s,stepMobile:u,stepTablet:c,...e})),(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"components-base-control uag-font-family-searchable-select__wrapper"},(0,w.createElement)("label",{className:"components-input-control__label",htmlFor:"font-family"},(0,M.__)("Font Family","sureforms")),(0,w.createElement)(Wa,{styles:{container:e=>({...e,width:"100%"}),control:e=>({...e,border:"1px solid #E6E7E9",boxShadow:"none",height:"30px",minHeight:"30px",borderRadius:"3px"}),placeholder:e=>({...e,color:"#50575E"}),menu:e=>({...e,color:"#50575E"}),singleValue:e=>({...e,color:"#50575E",top:"50%",transform:"translateY(-50%);"}),indicatorSeparator:e=>({...e,display:"none"}),dropdownIndicator:e=>({...e,color:"#50575E"}),valueContainer:e=>({...e,height:"30px",padding:"0px 8px"})},placeholder:(0,M.__)("Default","sureforms"),onChange:t=>{const a=t.value,{loadGoogleFonts:i,fontFamily:l}=e;e.setAttributes({[l.label]:a}),((t,a)=>{let i;i=""===a||"object"==typeof Ee[a],e.setAttributes({[t.label]:i})})(i,a)},options:n,value:o,defaultValue:o,isSearchable:!0,className:"uag-font-family-searchable-select",classNamePrefix:"uag-font-family-select"})),r,(0,w.createElement)(de,{label:(0,M.__)("Weight","sureforms"),data:{value:e.fontWeight.value,label:e.fontWeight.label},setAttributes:e.setAttributes,options:l}),e.fontStyle&&(0,w.createElement)(de,{label:(0,M.__)("Style","sureforms"),data:{value:e.fontStyle.value,label:e.fontStyle.label},setAttributes:e.setAttributes,options:[{value:"normal",label:(0,M.__)("Default","sureforms")},{value:"italic",label:(0,M.__)("Italic","sureforms")},{value:"oblique",label:(0,M.__)("Oblique","sureforms")}]}))};var $a=a(2854),Za={};$a.A&&$a.A.locals&&(Za.locals=$a.A.locals);var Ka,Ya=0,Ja={attributes:{id:"uagb-editor-styles"}};Ja.setAttributes=g(),Ja.insert=u().bind(null,"head"),Ja.domAPI=r(),Ja.insertStyleElement=p(),Za.use=function(e){return Ja.options=e||{},Ya++||(Ka=n()($a.A,Ja)),Za},Za.unuse=function(){Ya>0&&! --Ya&&(Ka(),Ka=null)};const Xa=Za,Qa=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null),[n,o]=(0,x.useState)(!1),r=(0,O.applyFilters)("uagb.blocksAttributes",z);let s,u,c,g,d,p,h,m;(0,x.useLayoutEffect)(()=>(Xa.use(),()=>{Xa.unuse()}),[]),(0,x.useLayoutEffect)(()=>{window.addEventListener("click",function(t){const a=document.querySelector(`.active.popup-${e?.attributes?.block_id} .spectra-control-popup__options--action-button`),l=document.querySelector(`.active.popup-${e?.attributes?.block_id} .spectra-control-popup`);if(a&&!a?.contains(t.target)&&l&&!l?.contains(t.target)&&!t.target?.parentElement?.parentElement?.classList?.contains("uag-font-family-select__menu")&&!t.target?.classList?.contains("uag-responsive-common-button")&&!t.target?.closest(".uag-responsive-common-button")&&!t.target?.parentElement?.closest(".uagb-reset")){o(!1);const e=L()?.name,t=i("uagSettingState"),a={...t,[e]:{...t?.[e],selectedSetting:!1}},l=i();l&&l.setItem("uagSettingState",JSON.stringify(a))}})},[]);const b=n?"active":"",{disableFontFamily:f,disableFontSize:v,disableLineHeight:y,disableTransform:_,disableDecoration:k,disableAdvancedOptions:S=!1,help:C=!1}=e;!0!==f&&(u=(0,w.createElement)(qa,{...e}));const T="em"===e.lineHeightType?.value?.1:1,E="em"===e.letterSpacingType?.value?.1:1,D=[];f||D.push(e.fontFamily.label,e.fontWeight.label,e.fontStyle.label),v||(D.push(e.fontSizeType.label,e.fontSize.label,e.fontSizeMobile.label,e.fontSizeTablet.label),e.fontSizeTypeMobile&&e.fontSizeTypeTablet&&D.push(e.fontSizeTypeMobile.label,e.fontSizeTypeTablet.label)),y||D.push(e.lineHeightType.label,e.lineHeight.label,e.lineHeightMobile.label,e.lineHeightTablet.label),_||D.push(e.transform.label),k||D.push(e.decoration.label),e.letterSpacing&&D.push(e.letterSpacing.label,e.letterSpacingTablet.label,e.letterSpacingMobile.label,e.letterSpacingType.label);const{getSelectedBlock:L}=(0,V.select)("core/block-editor"),B=L()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[B]);const H=(()=>{const e=(()=>{const e=L()?.name.split("/").pop();let t=!1;return void 0!==r[e]&&D.forEach(a=>{if(a){const i=void 0!==r[e][a]?.default?r[e][a]?.default:"";t={...t,[a]:i}}}),t})(),t=L()?.attributes;let a=!1;return D.forEach(i=>{t?.[i]&&t?.[i]!==e?.[i]&&(a=!0)}),a})();!0!==y&&(s=(0,w.createElement)(Te,{type:e.lineHeightType,typeLabel:e.lineHeightType.label,sizeMobile:e.lineHeightMobile,sizeMobileLabel:e.lineHeightMobile.label,sizeTablet:e.lineHeightTablet,sizeTabletLabel:e.lineHeightTablet.label,size:e.lineHeight,sizeLabel:e.lineHeight.label,min:0,sizeMobileText:(0,M.__)("Line Height","sureforms"),sizeTabletText:(0,M.__)("Line Height","sureforms"),sizeText:(0,M.__)("Line Height","sureforms"),step:T,...e})),e.letterSpacing&&(m=(0,w.createElement)(Te,{type:e.letterSpacingType,typeLabel:e.letterSpacingType.label,sizeMobile:e.letterSpacingMobile,sizeMobileLabel:e.letterSpacingMobile.label,sizeTablet:e.letterSpacingTablet,sizeTabletLabel:e.letterSpacingTablet.label,size:e.letterSpacing,sizeLabel:e.letterSpacing.label,min:-50,sizeMobileText:(0,M.__)("Letter Spacing","sureforms"),sizeTabletText:(0,M.__)("Letter Spacing","sureforms"),sizeText:(0,M.__)("Letter Spacing","sureforms"),step:E,...e})),!_&&e.transform&&(p=(0,w.createElement)(de,{label:(0,M.__)("Transform","sureforms"),data:{value:e.transform.value,label:e.transform.label},setAttributes:e.setAttributes,options:[{value:"",label:(0,M.__)("Default","sureforms")},{value:"normal",label:(0,M.__)("Normal","sureforms")},{value:"capitalize",label:(0,M.__)("Capitalize","sureforms")},{value:"uppercase",label:(0,M.__)("Uppercase","sureforms")},{value:"lowercase",label:(0,M.__)("Lowercase","sureforms")}]})),!k&&e.decoration&&(h=(0,w.createElement)("div",{className:"uag-typography-decoration"},(0,w.createElement)(de,{label:(0,M.__)("Decoration","sureforms"),data:{value:e.decoration.value,label:e.decoration.label},setAttributes:e.setAttributes,options:[{value:"",label:(0,M.__)("Default","sureforms")},{value:"none",label:(0,M.__)("None","sureforms")},{value:"underline",label:(0,M.__)("Underline","sureforms")},{value:"overline",label:(0,M.__)("Overline","sureforms")},{value:"line-through",label:(0,M.__)("Line Through","sureforms")}]}))),!0!==f&&!0!==v?c=(0,w.createElement)(te.Button,{className:"uag-typography-button spectra-control-popup__options--action-button","aria-pressed":n,onClick:()=>{const e=document.querySelectorAll(".spectra-control-popup__options");if(e&&0<e.length)for(let t=0;t<e.length;t++){const a=e[t]?.querySelector(".spectra-control-popup__options.active .spectra-control-popup__options--action-button");a?.click()}o(!n);const t=L()?.name,a=i("uagSettingState");let l={...a,[t]:{...a?.[t],selectedSetting:".uag-typography-options"}};n&&(l={...a,[t]:{...a?.[t],selectedSetting:!1}});const r=i();r&&r.setItem("uagSettingState",JSON.stringify(l))}},(0,w.createElement)(te.Dashicon,{icon:"edit"})):d=(0,w.createElement)(w.Fragment,null,u,p,h,s,m),!0===n&&(d=(0,w.createElement)("div",{className:"uagb-typography-advanced spectra-control-popup"},u,p,h,s,m)),!0!==f&&!0!==v&&(g=(0,w.createElement)("div",{className:"spectra-control-popup__options--action-wrapper"},(0,w.createElement)("span",{className:"uag-control-label"},e.label,H&&(0,w.createElement)("div",{className:"spectra__change-indicator--dot-right"})),c));const A=ce(e.label),R=(0,O.applyFilters)(`spectra.${B}.${t}.${A}.before`,"",B),P=(0,O.applyFilters)(`spectra.${B}.${t}.${A}`,"",B);return(0,w.createElement)("div",{ref:l,className:"components-base-control"},R,(0,w.createElement)("div",{className:` uag-typography-options spectra-control-popup__options popup-${e?.attributes?.block_id} ${b}`},!S&&(0,w.createElement)(w.Fragment,null,g,d),(0,w.createElement)(pe,{text:C})),P)};var ei=a(6359),ti={};ei.A&&ei.A.locals&&(ti.locals=ei.A.locals);var ai,ii=0,li={attributes:{id:"uagb-editor-styles"}};li.setAttributes=g(),li.insert=u().bind(null,"head"),li.domAPI=r(),li.insertStyleElement=p(),ti.use=function(e){return li.options=e||{},ii++||(ai=n()(ei.A,li)),ti},ti.unuse=function(){ii>0&&! --ii&&(ai(),ai=null)};const ni=ti;var oi=a(6942),ri=a.n(oi);const si="general",ui="style",ci="advance",gi=e=>{(0,x.useLayoutEffect)(()=>(ni.use(),()=>{ni.unuse()}),[]);const t=i("uagSettingState"),{defaultTab:a,children:l,tabs:n}=e,[o,r]=(0,x.useState)(a||n[0]),s=(0,x.useRef)();let u;(0,x.useEffect)(()=>{u=s.current.closest(".components-panel")});const c=()=>{const e=document.querySelector(".uagb-inspector-tabs-container");let t=document.querySelector(".components-panel__body.uagb-dynamic-content-wrap"),a=document.querySelector(".uagb-tab-content-general"),i=document.querySelector(".uagb-tab-content-style"),l=document.querySelector(".uagb-tab-content-advance");if(e){const n=e.parentElement;n&&(t=t||"",a=a||"",i=i||"",l=l||"",n.prepend(t,e,a,i,l))}};(0,x.useEffect)(()=>{c();const{getSelectedBlock:e}=(0,V.select)("core/block-editor"),a=e()?.name;return t&&t[a]&&o!==t[a]?.selectedTab?(r(t[a]?.selectedTab||"general"),u&&u.setAttribute("data-uagb-tab",t[a]?.selectedTab||"general")):u&&u.setAttribute("data-uagb-tab","general"),()=>{if(u){const e=u.querySelector(".uagb-inspector-tabs-container");e&&null!==e||u.removeAttribute("data-uagb-tab")}}},[]);const g=e=>{c(),r(e),(0,O.doAction)("uag_inspector_change_tab",e),u&&u.setAttribute("data-uagb-tab",e);const{getSelectedBlock:a}=(0,V.select)("core/block-editor"),l=a()?.name,n={...t,[l]:{selectedTab:e}},o=i();o&&o.setItem("uagSettingState",JSON.stringify(n))};return(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"uagb-inspector-tabs-container"},(0,w.createElement)("div",{ref:s,className:ri()("uagb-inspector-tabs","uagb-inspector-tabs-count-"+n.length,o)},n.indexOf(si)>-1&&(0,w.createElement)("div",{className:ri()({"uagb-active":o===si}),onClick:()=>g(si)},(0,w.createElement)("svg",{xmlns:"https://www.w3.org/2000/svg",width:"16",height:"15"},(0,w.createElement)("path",{fillRule:"nonzero",d:"M14.346 0H1.654C1.017 0 .5.517.5 1.154v12.692C.5 14.483 1.017 15 1.654 15h12.692c.637 0 1.154-.517 1.154-1.154V1.154C15.5.517 14.983 0 14.346 0zm-5.77 13.846v-5.77h5.77v5.77h-5.77z"})),(0,w.createElement)("h5",null,(0,M.__)("General","sureforms"))),n.indexOf(ui)>-1&&(0,w.createElement)("div",{className:ri()({"uagb-active":o===ui}),onClick:()=>g(ui)},(0,w.createElement)("svg",{xmlns:"https://www.w3.org/2000/svg",width:"18",height:"21"},(0,w.createElement)("g",{fillRule:"nonzero"},(0,w.createElement)("path",{d:"M15.12 12.091a.814.814 0 00-.68-.378.814.814 0 00-.68.378c-.531.863-2.252 3.807-2.252 5.09 0 1.598 1.317 2.901 2.932 2.901s2.933-1.303 2.933-2.902c0-1.303-1.722-4.226-2.253-5.089zm-1.041 3.828c-.043.063-.744 1.198-.213 1.976a.52.52 0 01.064.358.409.409 0 01-.191.294.608.608 0 01-.255.084.476.476 0 01-.383-.21c-.871-1.283.149-2.902.192-2.986a.517.517 0 01.297-.21.534.534 0 01.361.063c.192.126.255.42.128.63zM13.314 10.388l1.36-.147c.446-.042.807-.337.935-.736.127-.4.042-.862-.276-1.157L7.258.294c-.255-.252-.68-.252-.957 0a.68.68 0 000 .947l.34.336-5.1 5.047C.82 7.339.5 8.348.67 9.379c.128.652.489 1.24.956 1.703l3.082 3.05c.467.462 1.062.82 1.72.946a3.134 3.134 0 002.785-.863l3.612-3.575a.74.74 0 01.489-.252zM7.576 2.502l5.759 5.7H2.073c.085-.232.212-.463.403-.653l5.1-5.047z"}))),(0,w.createElement)("h5",null,(0,M.__)("Style","sureforms"))),n.indexOf(ci)>-1&&(0,w.createElement)("div",{className:ri()({"uagb-active":o===ci}),onClick:()=>g(ci)},(0,w.createElement)("svg",{xmlns:"https://www.w3.org/2000/svg",width:"17",height:"16"},(0,w.createElement)("path",{fillRule:"nonzero",d:"M15.666 6.325c-.277-.05-.572-.082-.85-.115a6.385 6.385 0 00-.571-1.389c.18-.229.343-.457.523-.686a.994.994 0 00-.098-1.291l-.997-.997a.994.994 0 00-1.291-.098c-.23.163-.458.343-.687.523a6.954 6.954 0 00-1.39-.589c-.032-.277-.08-.572-.113-.85A.987.987 0 009.21 0H7.805a1 1 0 00-.98.834c-.05.277-.082.572-.115.85-.474.13-.947.326-1.389.571-.229-.18-.457-.343-.686-.523a.994.994 0 00-1.291.098l-.997.997a.994.994 0 00-.098 1.291c.163.23.343.458.523.687a6.954 6.954 0 00-.589 1.39c-.277.032-.572.08-.85.113A.987.987 0 00.5 7.29v1.406a1 1 0 00.834.98c.277.05.572.082.85.115.13.474.326.947.571 1.389-.18.229-.343.457-.523.686a.994.994 0 00.098 1.291l.997.997a.994.994 0 001.291.098c.23-.163.458-.343.687-.523.441.245.899.442 1.39.589.032.294.08.572.113.85.066.473.49.833.981.833h1.406a1 1 0 00.98-.834c.05-.277.082-.572.115-.85.474-.13.947-.326 1.389-.571.229.18.457.343.686.523a.994.994 0 001.291-.098l.997-.997a.994.994 0 00.098-1.291 19.095 19.095 0 00-.523-.687c.245-.441.442-.899.589-1.39.277-.032.572-.08.85-.113a.987.987 0 00.833-.981V7.305a1 1 0 00-.834-.98zM8.492 11.57a3.571 3.571 0 01-3.563-3.563 3.571 3.571 0 013.563-3.563 3.571 3.571 0 013.563 3.563 3.571 3.571 0 01-3.563 3.563z"})),(0,w.createElement)("h5",null,(0,M.__)("Advanced","sureforms"))))),Array.isArray(l)&&x.Children.map(l,(e,t)=>{if(!e)return e;if(!e.key)throw new Error("props.key not found in <InspectorTab />, you must use `key` prop");return(0,x.cloneElement)(e,{index:t,isActive:e.key===o})}))};gi.defaultProps={defaultTab:"general",tabs:["general","style","advance"]};const di=gi,pi=e=>{const{children:t,isActive:a,type:l}=e,n=(0,x.useRef)(null),{getSelectedBlock:o}=(0,V.select)("core/block-editor"),r=o()?.name;(0,x.useEffect)(()=>{const e=i("uagSettingState");if(e){const t=e[r]?.selectedTab,a=e[r]?.selectedPanel,i=e[r]?.selectedSetting,o=e[r]?.selectedInnerTab;if(t&&l===t){let e=!1;e=a?n.current.querySelector(`.${a}`):n.current.querySelector(".is-opened"),e&&(e.classList.contains("is-opened")||e.querySelector(".components-button").click(),o&&setTimeout(function(){const t=e.querySelector(o);t&&!t.classList.contains("active-tab")&&t.click()},100),i&&setTimeout(function(){const t=e.querySelector(i);t&&!t.classList.contains("active")&&t.querySelector(".components-button").click()},100))}}},[]);const s=r.split("/").pop(),u=(0,O.applyFilters)(`spectra.${s}.tab_${l}.before`,"",r),c=(0,O.applyFilters)(`spectra.${s}.tab_${l}`,"",r);return(0,w.createElement)("div",{style:{display:a?"block":"none"},className:`uagb-inspector-tab uagb-tab-content-${l}`,ref:n},u,Array.isArray(t)?t.map(e=>e):t,(0,O.applyFilters)(`uag_${l}_tab_content`,"",e.parentProps),c)},hi={key:"general",type:"general"},mi={key:"style",type:"style"},bi={key:"advance",type:"advance"},fi={};fi.inherit=(0,w.createElement)("svg",{xmlns:"https://www.w3.org/2000/svg",fillRule:"evenodd",width:"24",height:"24",strokeLinejoin:"round",strokeMiterlimit:"1.5",clipRule:"evenodd",viewBox:"0 0 24 24"},(0,w.createElement)("path",{fill:"none",stroke:"currentColor",strokeWidth:"1.5",d:"M12.383 26.976l2.01-.941 1.884.538 1.623 1.666-.692.236.281 1.539 1.552 1.35-1.552 2.153",transform:"matrix(.68343 0 0 .68343 -5.086 -1.48)"}),(0,w.createElement)("path",{fill:"none",stroke:"currentColor",strokeLinecap:"square",strokeWidth:"1.5",d:"M12.016 24.355l.998-.952M33.573 26.085l-1.636-1.343-1.348-1.248M26.35 27.774l.332.37 1.349.756-.711 2.768 1.274 1.203.989-.449 3.933-6.226",transform:"matrix(.68343 0 0 .68343 -5.086 -1.48)"}),(0,w.createElement)("path",{fill:"none",stroke:"currentColor",strokeLinecap:"square",strokeWidth:"1.5",d:"M29.519 9.539c5.298 1.881 9.099 6.977 9.099 12.961 0 7.582-6.102 13.737-13.618 13.737S11.382 30.082 11.382 22.5",transform:"matrix(.68343 0 0 .68343 -5.086 -1.48)"}),(0,w.createElement)("path",{fill:"none",stroke:"currentColor",strokeLinecap:"square",strokeWidth:"1.5",d:"M20.684 3.211v9.433h4.179l-6.429 6.429-6.429-6.429h4.179V8.021",transform:"matrix(.68343 0 0 .68343 -5.086 -1.48) translate(-6.686 -1.321) scale(1.55693)"}),(0,w.createElement)("path",{fill:"none",stroke:"currentColor",strokeLinecap:"square",strokeWidth:"1.5",d:"M32.994 21.014l.2.205 3.364.329 1.532 2.432M32.931 12.002l-3.219.944-1.054 1.996-.408-.003",transform:"matrix(.68343 0 0 .68343 -5.086 -1.48)"})),fi.globe=(0,w.createElement)("svg",{xmlns:"http://www.w3.org/2000/svg",width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"},(0,w.createElement)("circle",{cx:"12",cy:"12",r:"10"}),(0,w.createElement)("path",{d:"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"}),(0,w.createElement)("path",{d:"M4 12h16"}),(0,w.createElement)("path",{d:"M4 8h16"}),(0,w.createElement)("path",{d:"M4 16h16"}));const vi=fi,wi=e=>{if(e&&e.includes("var")){const t=window.getComputedStyle(document.body);if((e=e.slice(4).slice(0,-1)).includes(","))return e.split(",").pop().trim();e=t.getPropertyValue(e).trim()}return e};var yi=a(3578),xi={};yi.A&&yi.A.locals&&(xi.locals=yi.A.locals);var _i,ki=0,Si={attributes:{id:"uagb-editor-styles"}};Si.setAttributes=g(),Si.insert=u().bind(null,"head"),Si.domAPI=r(),Si.insertStyleElement=p(),xi.use=function(e){return Si.options=e||{},ki++||(_i=n()(yi.A,Si)),xi},xi.unuse=function(){ki>0&&! --ki&&(_i(),_i=null)};const Ci=xi,Mi=e=>{const{colorValue:t,className:a,isGlobal:i}=e;let l="component-color-indicator uagb-advanced-color-indicate";return l=a?`${l} ${a}`:l,(0,w.createElement)("span",{className:l,style:{background:t}},i?vi.globe:"")},Ti=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Ci.use(),()=>{Ci.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const{colors:o}=(0,V.useSelect)(e=>({colors:e("core/block-editor").getSettings().colors})),{alpha:r,colorValue:s,opacityValue:u,backgroundVideoOpacity:c,onOpacityChange:g,data:d,setAttributes:p,onColorChange:h,label:m,help:b}=e,[f,v]=(0,x.useState)({alpha:!1!==r,colors:[],classSat:"first",currentColor:s,inherit:!1,currentOpacity:void 0!==u?u:1,isPalette:!(!s||!s.startsWith("palette")),refresh:!1}),[y,_]=(0,x.useState)({isVisible:!1});(0,x.useEffect)(()=>{k(s,"")},[s]);const k=(e,t)=>{let a,i=c?.value;t?a=e:e?.rgb&&e?.rgb?.a&&1!==e?.rgb?.a?(g&&(i=e?.rgb?.a),a="rgba("+e?.rgb?.r+","+e?.rgb?.g+","+e?.rgb?.b+","+e?.rgb?.a+")"):a=e?.hex?e?.hex:e,v({currentColor:a,currentOpacity:i,isPalette:!!t}),!0===t&&v({refresh:!f?.refresh}),d&&p&&p({[d?.label]:a}),h&&h(a),g&&g(i)},S=()=>{!0===y.isVisible&&_({isVisible:!1})},C=f.currentColor?f.currentColor:s,T=(e=>{const t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e),a=t?{r:parseInt(t[1],16),g:parseInt(t[2],16),b:parseInt(t[3],16)}:null;return a&&Math.round((299*a.r+587*a.g+114*a.b)/1e3)>125?"black":"white"})(wi(C)),E=C&&C.includes("var"),D=E?`uag-global-indicator uag-global-icon-${T}`:"",L=ce(e.label),B=(0,O.applyFilters)(`spectra.${n}.${t}.${L}.before`,"",n),H=(0,O.applyFilters)(`spectra.${n}.${t}.${L}`,"",n);return(0,w.createElement)("div",{ref:i,className:"components-base-control"},B,(0,w.createElement)("div",{className:"uagb-color-popover-container new-uagb-advanced-colors"},(0,w.createElement)("div",{className:"uagb-advanced-color-settings-container"},m&&(0,w.createElement)("span",{className:"uagb-beside-color-label uag-control-label"},m),(0,w.createElement)(ke,{onReset:e=>{v({...f,currentColor:e[d?.label]})},attributeNames:[d?.label],setAttributes:p}),(0,w.createElement)("div",{className:"uagb-beside-color-click"},y.isVisible&&(0,w.createElement)(te.Popover,{position:"top left",className:"uagb-popover-color new-uagb-advanced-colors-pop",onClose:S},f.refresh&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(te.ColorPicker,{color:wi(C),onChangeComplete:e=>k(e,"")})),!f.refresh&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(te.ColorPicker,{color:wi(C),onChangeComplete:e=>k(e,"")})),o&&(0,w.createElement)(te.ColorPalette,{color:C,colors:o,onChange:e=>k(e,!0),clearable:!1,disableCustomColors:!0}),(0,w.createElement)("button",{type:"button",onClick:()=>{k("",!0)},className:"uagb-clear-btn-inside-picker components-button components-circular-option-picker__clear is-secondary is-small"},(0,M.__)("Clear","sureforms"))),y.isVisible&&(0,w.createElement)(te.Tooltip,{text:(0,M.__)("Select Color","sureforms")},(0,w.createElement)(te.Button,{className:"uagb-color-icon-indicate uagb-has-alpha",onClick:S},(0,w.createElement)(Mi,{isGlobal:E,className:D,colorValue:C}),""===C&&f.inherit&&(0,w.createElement)("span",{className:"color-indicator-icon"},vi.inherit),s&&s.startsWith("palette")&&(0,w.createElement)("span",{className:"color-indicator-icon"},(0,w.createElement)(te.Dashicon,{icon:"admin-site"})))),!y.isVisible&&(0,w.createElement)(te.Tooltip,{text:(0,M.__)("Select Color","sureforms")},(0,w.createElement)(te.Button,{className:"uagb-color-icon-indicate uagb-has-alpha",onClick:()=>{_({isVisible:!0})}},(0,w.createElement)(Mi,{isGlobal:E,className:D,colorValue:C}),""===C&&f.inherit&&(0,w.createElement)("span",{className:"color-indicator-icon"},vi.inherit),s&&s.startsWith("palette")&&(0,w.createElement)("span",{className:"color-indicator-icon"},(0,w.createElement)(te.Dashicon,{icon:"admin-site"})))))),b&&(0,w.createElement)("p",{className:"components-base-control__help"},b)),H)};var Ei=a(4180),Di={};Ei.A&&Ei.A.locals&&(Di.locals=Ei.A.locals);var Li,Bi=0,Hi={attributes:{id:"uagb-editor-styles"}};Hi.setAttributes=g(),Hi.insert=u().bind(null,"head"),Hi.domAPI=r(),Hi.insertStyleElement=p(),Di.use=function(e){return Hi.options=e||{},Bi++||(Li=n()(Ei.A,Hi)),Di},Di.unuse=function(){Bi>0&&! --Bi&&(Li(),Li=null)};const Ai=Di,Ri=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Ai.use(),()=>{Ai.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const{data:o,label:r,options:s,showIcons:u,responsive:c,onChange:g,colorVariant:d="primary",layoutVariant:p="full",help:h=!1}=e,m=!(!e.setAttributes||"function"!=typeof e.setAttributes)&&e.setAttributes,b=l()?.name.split("/").pop(),f=(0,O.applyFilters)("uagb.blocksAttributes",z),[v,y]=(0,x.useState)(!0),[_,k]=(0,x.useState)(!0),[S,C]=(0,x.useState)(!0),T=Q(),E=u?"uag-multibutton-icons":"";if(!s)return(0,M.__)("Please add a option props to MultiButtonsControl","sureforms");if(c){const e={};return e.Desktop=(0,w.createElement)(te.ButtonGroup,{className:"uagb-multi-button-button-group","aria-label":r},s.map(e=>(0,w.createElement)(te.Button,{key:`option-${e.value}`,className:"uagb-multi-button",isLarge:!0,isSecondary:o.desktop.value!==e.value||!v,isPrimary:o.desktop.value===e.value&&v,"aria-pressed":o.desktop.value===e.value,onClick:()=>{if(y(!0),e.value===o.desktop.value&&v)return y(!1),void(m&&m({[o.desktop.label]:f[b][o.desktop.label].default}));m&&m({[o.desktop.label]:e.value})},"aria-label":e.tooltip,label:e.tooltip,showTooltip:!!e.tooltip},u?e.icon:e.label))),e.Tablet=(0,w.createElement)(te.ButtonGroup,{className:"uagb-multi-button-button-group","aria-label":r},s.map(e=>(0,w.createElement)(te.Button,{key:`option-${e.value}`,className:"uagb-multi-button",isLarge:!0,isSecondary:o.tablet.value!==e.value||!_,isPrimary:o.tablet.value===e.value&&_,"aria-pressed":o.tablet.value===e.value,onClick:()=>{if(k(!0),e.value===o.tablet.value&&_)return k(!1),void(m&&m({[o.tablet.label]:f[b][o.tablet.label].default}));m&&m({[o.tablet.label]:e.value})},"aria-label":e.tooltip,label:e.tooltip,showTooltip:!!e.tooltip},u?e.icon:e.label))),e.Mobile=(0,w.createElement)(te.ButtonGroup,{className:"uagb-multi-button-button-group","aria-label":r},s.map(e=>(0,w.createElement)(te.Button,{key:`option-${e.value}`,className:"uagb-multi-button",isLarge:!0,isSecondary:o.mobile.value!==e.value||!S,isPrimary:o.mobile.value===e.value&&S,"aria-pressed":o.mobile.value===e.value,onClick:()=>{if(C(!0),e.value===o.mobile.value&&S)return C(!1),void(m&&m({[o.mobile.label]:f[b][o.mobile.label].default}));m&&m({[o.mobile.label]:e.value})},"aria-label":e.tooltip,label:e.tooltip,showTooltip:!!e.tooltip},u?e.icon:e.label))),(0,w.createElement)("div",{className:`components-base-control uagb-multi-buttons-control ${E} spectra-multi-buttons__color-scheme--${d} spectra-multi-buttons__layout--${p}`},(0,w.createElement)("div",{className:"uagb-control__header uagb-size-type-field-tabs"},(0,w.createElement)(he,{label:r,responsive:c})),e[T]?e[T]:e.Desktop,(0,w.createElement)(pe,{text:h}))}const D=ce(r),L=(0,O.applyFilters)(`spectra.${b}.${t}.${D}.before`,"",b),B=(0,O.applyFilters)(`spectra.${b}.${t}.${D}`,"",b),H=(0,O.applyFilters)(`spectra.${b}.${t}.${D}.options`,s,b);return(0,w.createElement)("div",{ref:i,className:"components-base-control"},L,(0,w.createElement)("div",{className:` uagb-multi-buttons-control ${E} spectra-multi-buttons__color-scheme--${d} spectra-multi-buttons__layout--${p}`},(0,w.createElement)("div",{className:"uagb-multi-buttons-control__label uag-control-label"},r),(0,w.createElement)(te.ButtonGroup,{className:"uagb-multi-button-button-group","aria-label":r},H.map(e=>(0,w.createElement)(te.Button,{key:`option-${e.value}`,className:"uagb-multi-button",isLarge:!0,isSecondary:o.value!==e.value||!v,isPrimary:o.value===e.value&&v,"aria-pressed":o.value===e.value,onClick:()=>(e=>{if(y(!0),g&&g(e),e===o.value&&v)return y(!1),void(m&&m({[o.label]:f[b][o.label].default}));m&&m({[o.label]:e})})(e.value),"aria-label":e.tooltip,label:e.tooltip,showTooltip:!!e.tooltip},u?e.icon:e.label))),(0,w.createElement)(pe,{text:h})),B)},Pi=window.wp.blockEditor,zi=function(e,t=!1){let a;if(e=function(e){return(e=(e=(e=(e=e.replace("far ","")).replace("fas ","")).replace("fab ","")).replace("fa-","")).replace("fa ","")}(e),0!==srfm_spec_blocks_info.font_awesome_5_polyfill.length&&(a=srfm_spec_blocks_info.uagb_svg_icons[e],a||(a=srfm_spec_blocks_info.uagb_svg_icons[srfm_spec_blocks_info.font_awesome_5_polyfill?.[e]])),!a)return null;const i=a.svg?.brands?a.svg.brands:a.svg.solid,l=`0 0 ${i.width} ${i.height}`,n=i.path;let o=null;switch(e){case"align-center":o={fillRule:"evenodd",clipRule:"evenodd",d:"M4 2H14V0H4V2ZM0 7H18V5H0V7ZM4 12H14V10H4V12Z"};break;case"align-left":o={fillRule:"evenodd",clipRule:"evenodd",d:"M10 2H0V0H10V2ZM18 7H0V5H18V7ZM10 12H0V10H10V12Z"};break;case"align-right":o={fillRule:"evenodd",clipRule:"evenodd",d:"M8 2H18V0H8V2ZM0 7H18V5H0V7ZM8 12H18V10H8V12Z"};break;case"align-justify":o={d:"M0 0H18V2H0V0ZM0 5.00001H18V7.00001H0V5.00001ZM0 10H18V12H0V10Z"}}return o?(0,w.createElement)("svg",{width:"18",height:"12",viewBox:"0 0 18 12",xmlns:"http://www.w3.org/2000/svg"},(0,w.createElement)("path",{...o})):t&&"not_set"!==t?(0,w.createElement)("svg",{width:"20",height:"20",xmlns:"https://www.w3.org/2000/svg",viewBox:l},(0,w.createElement)("path",{d:n})):(0,w.createElement)("svg",{xmlns:"https://www.w3.org/2000/svg",viewBox:l},(0,w.createElement)("path",{d:n}))};var Oi=a(3942),Fi={};Oi.A&&Oi.A.locals&&(Fi.locals=Oi.A.locals);var Ii,Ni=0,Vi={attributes:{id:"uagb-editor-styles"}};Vi.setAttributes=g(),Vi.insert=u().bind(null,"head"),Vi.domAPI=r(),Vi.insertStyleElement=p(),Fi.use=function(e){return Vi.options=e||{},Ni++||(Ii=n()(Oi.A,Vi)),Fi},Fi.unuse=function(){Ni>0&&! --Ni&&(Ii(),Ii=null)};const Gi=Fi,Wi={disabledTopSpace:j().bool};function Ui({disabledTopSpace:e}){const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Gi.use(),()=>{Gi.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const o="separator",r=(0,O.applyFilters)(`spectra.${n}.${t}.${o}.before`,"",n),s=(0,O.applyFilters)(`spectra.${n}.${t}.${o}`,"",n);return(0,w.createElement)("div",{ref:i},r,(0,w.createElement)("div",{className:"spectra-separator "+(e?"spectra-separator--removed-top-space":"")}),s)}Ui.propTypes=Wi,Ui.defaultProps={disabledTopSpace:!1};var ji=a(9380),qi={};ji.A&&ji.A.locals&&(qi.locals=ji.A.locals);var $i,Zi=0,Ki={attributes:{id:"uagb-editor-styles"}};Ki.setAttributes=g(),Ki.insert=u().bind(null,"head"),Ki.domAPI=r(),Ki.insertStyleElement=p(),qi.use=function(e){return Ki.options=e||{},Zi++||($i=n()(ji.A,Ki)),qi},qi.unuse=function(){Zi>0&&! --Zi&&($i(),$i=null)};const Yi=qi,Ji=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Yi.use(),()=>{Yi.unuse()}),[]);const l=(0,V.useSelect)(e=>e("core/block-editor").getSelectedBlock(),[]),n=l?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const o=e.enableDynamicContent&&e.name?(0,O.applyFilters)("uagb.registerTextExtender","",l?.name,e.name,e.dynamicContentType):null,r=()=>{if(!e.enableDynamicContent||!e.name)return!1;const t=l?.attributes?.dynamicContent;return!(!t||!0!==t?.[e.name]?.enable)},s=t=>{e.name&&e?.setAttributes?e.setAttributes({[e.name]:t}):e?.setAttributes&&e?.setAttributes({[e?.data?.label]:t}),e?.onChange&&e?.onChange(t)},u=t=>{e?.onChange&&e?.onChange(t[e?.data?.label])},c=ce(e.label),g=(0,O.applyFilters)(`spectra.${n}.${t}.${c}.before`,"",n),d=(0,O.applyFilters)(`spectra.${n}.${t}.${c}`,"",n);return(0,w.createElement)("div",{ref:i,className:"components-base-control"},g,(0,w.createElement)("div",{className:ri()("components-base-control uagb-text-control uagb-size-type-field-tabs",r()?" uagb-text-control--open-dynamic-content":"",e.className)},"inline"!==e?.variant&&e?.showHeaderControls&&(0,w.createElement)(()=>(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)(he,{label:e?.label}),(0,w.createElement)("div",{className:"uagb-number-control__actions uagb-control__actions"},(0,w.createElement)(ke,{onReset:u,attributeNames:[e?.data?.label],setAttributes:e?.setAttributes}))),null),(0,w.createElement)("div",{className:ri()("uagb-text-control__controls","uagb-text-control__controls-"+e?.variant)},!r()&&(0,w.createElement)(w.Fragment,null,"textarea"!==e?.variant&&(0,w.createElement)(te.TextControl,{label:("inline"===e?.variant||"inline"!==e?.variant&&!e?.showHeaderControls)&&e?.label,type:e?.type,value:e?.value,onChange:s,autoComplete:e?.autoComplete,readOnly:r(),placeholder:e?.placeholder}),"textarea"===e?.variant&&(0,w.createElement)(te.TextareaControl,{label:!e?.showHeaderControls&&e?.label,value:e?.value,onChange:s,autoComplete:e?.autoComplete,readOnly:r()})),r()&&"inline"===e?.variant&&(0,w.createElement)("div",{className:"components-base-control"},(0,w.createElement)("div",{className:"components-base-control__field"},(0,w.createElement)("label",{className:"components-base-control__label"},e.label))),o),(0,w.createElement)(pe,{text:e.help}),r()&&(0,w.createElement)(Ui,null)),d)};Ji.defaultProps={label:"",type:"text",className:"",allowReset:!0,resetFallbackValue:"",placeholder:null,variant:"full-width",autoComplete:"off",showHeaderControls:!0,dynamicContentType:"url",enableDynamicContent:!1,help:!1};const Xi=Ji,Qi=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null),l=Q(),{getSelectedBlock:n}=(0,V.select)("core/block-editor"),o=n()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[o]);const r={},s=xe(e.data.desktop.unit?.value,e,!0),u=xe(e.data.tablet.unit?.value,e,!0),c=xe(e.data.mobile.unit?.value,e,!0),g=_e(e.data.desktop.unit?.value,e,!0),d=_e(e.data.tablet.unit?.value,e,!0),p=_e(e.data.mobile.unit?.value,e,!0);r.Desktop=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Me,{...e,label:e.label,value:isNaN(e.data.desktop.value)?"":e.data.desktop.value,data:{value:e.data.desktop.value,label:e.data.desktop.label},onChange:!!e?.onChange&&(t=>{e?.onChange&&e.onChange(t)}),min:g,max:s,unit:e.data.desktop.unit||e.unit,responsive:!0,units:e.units})),r.Tablet=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Me,{...e,label:e.label,value:isNaN(e.data.tablet.value)?"":e.data.tablet.value,data:{value:e.data.tablet.value,label:e.data.tablet.label},onChange:!!e?.onChange&&(t=>{e?.onChange&&e.onChange(t)}),min:d,max:u,unit:e.data.tablet.unit||e.unit,responsive:!0,units:e.units})),r.Mobile=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Me,{...e,label:e.label,value:isNaN(e.data.mobile.value)?"":e.data.mobile.value,data:{value:e.data.mobile.value,label:e.data.mobile.label},onChange:!!e?.onChange&&(t=>{e?.onChange&&e.onChange(t)}),min:p,max:c,unit:e.data.mobile.unit||e.unit,responsive:!0,units:e.units}));const h=ce(e.label),m=(0,O.applyFilters)(`spectra.${o}.${t}.${h}.before`,"",o),b=(0,O.applyFilters)(`spectra.${o}.${t}.${h}`,"",o);return(0,w.createElement)("div",{ref:i,className:"components-base-control"},m,(0,w.createElement)("div",{className:"uagb-responsive-range"},(0,w.createElement)("div",{className:"uagb-responsive-control-inner"},r[l]?r[l]:r.Desktop)),b)};var el=a(3307),tl={};el.A&&el.A.locals&&(tl.locals=el.A.locals);var al,il=0,ll={attributes:{id:"uagb-editor-styles"}};ll.setAttributes=g(),ll.insert=u().bind(null,"head"),ll.domAPI=r(),ll.insertStyleElement=p(),tl.use=function(e){return ll.options=e||{},il++||(al=n()(el.A,ll)),tl},tl.unuse=function(){il>0&&! --il&&(al(),al=null)};const nl=tl;function ol(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function rl(e){return rl="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},rl(e)}function sl(e){var t=function(e){if("object"!=rl(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var a=t.call(e,"string");if("object"!=rl(a))return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==rl(t)?t:t+""}function ul(e,t){for(var a=0;a<t.length;a++){var i=t[a];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,sl(i.key),i)}}function cl(e,t,a){return t&&ul(e.prototype,t),a&&ul(e,a),Object.defineProperty(e,"prototype",{writable:!1}),e}function gl(e,t){if(t&&("object"==rl(t)||"function"==typeof t))return t;if(void 0!==t)throw new TypeError("Derived constructors may only return object or undefined");return function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e)}function dl(e){return dl=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},dl(e)}function pl(e,t){return pl=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},pl(e,t)}function hl(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,"prototype",{writable:!1}),t&&pl(e,t)}function ml(e,t,a){return(t=sl(t))in e?Object.defineProperty(e,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):e[t]=a,e}var bl=a(1345);function fl(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function vl(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?fl(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):fl(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function wl(e,t,a){return t=dl(t),gl(e,yl()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function yl(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(yl=function(){return!!e})()}var xl=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=wl(this,t,[].concat(i)),"state",{scrollToColumn:0,scrollToRow:0,instanceProps:{prevScrollToColumn:0,prevScrollToRow:0}}),ml(e,"_columnStartIndex",0),ml(e,"_columnStopIndex",0),ml(e,"_rowStartIndex",0),ml(e,"_rowStopIndex",0),ml(e,"_onKeyDown",function(t){var a=e.props,i=a.columnCount,l=a.disabled,n=a.mode,o=a.rowCount;if(!l){var r=e._getScrollState(),s=r.scrollToColumn,u=r.scrollToRow,c=e._getScrollState(),g=c.scrollToColumn,d=c.scrollToRow;switch(t.key){case"ArrowDown":d="cells"===n?Math.min(d+1,o-1):Math.min(e._rowStopIndex+1,o-1);break;case"ArrowLeft":g="cells"===n?Math.max(g-1,0):Math.max(e._columnStartIndex-1,0);break;case"ArrowRight":g="cells"===n?Math.min(g+1,i-1):Math.min(e._columnStopIndex+1,i-1);break;case"ArrowUp":d="cells"===n?Math.max(d-1,0):Math.max(e._rowStartIndex-1,0)}g===s&&d===u||(t.preventDefault(),e._updateScrollState({scrollToColumn:g,scrollToRow:d}))}}),ml(e,"_onSectionRendered",function(t){var a=t.columnStartIndex,i=t.columnStopIndex,l=t.rowStartIndex,n=t.rowStopIndex;e._columnStartIndex=a,e._columnStopIndex=i,e._rowStartIndex=l,e._rowStopIndex=n}),e}return hl(t,e),cl(t,[{key:"setScrollIndexes",value:function(e){var t=e.scrollToColumn,a=e.scrollToRow;this.setState({scrollToRow:a,scrollToColumn:t})}},{key:"render",value:function(){var e=this.props,t=e.className,a=e.children,i=this._getScrollState(),l=i.scrollToColumn,n=i.scrollToRow;return w.createElement("div",{className:t,onKeyDown:this._onKeyDown},a({onSectionRendered:this._onSectionRendered,scrollToColumn:l,scrollToRow:n}))}},{key:"_getScrollState",value:function(){return this.props.isControlled?this.props:this.state}},{key:"_updateScrollState",value:function(e){var t=e.scrollToColumn,a=e.scrollToRow,i=this.props,l=i.isControlled,n=i.onScrollToChange;"function"==typeof n&&n({scrollToColumn:t,scrollToRow:a}),l||this.setState({scrollToColumn:t,scrollToRow:a})}}],[{key:"getDerivedStateFromProps",value:function(e,t){return e.isControlled?{}:e.scrollToColumn!==t.instanceProps.prevScrollToColumn||e.scrollToRow!==t.instanceProps.prevScrollToRow?vl(vl({},t),{},{scrollToColumn:e.scrollToColumn,scrollToRow:e.scrollToRow,instanceProps:{prevScrollToColumn:e.scrollToColumn,prevScrollToRow:e.scrollToRow}}):{}}}])}(w.PureComponent);function _l(e,t){var a,i=void 0!==(a=void 0!==t?t:"undefined"!=typeof window?window:"undefined"!=typeof self?self:globalThis).document&&a.document.attachEvent;if(!i){var l=function(){var e=a.requestAnimationFrame||a.mozRequestAnimationFrame||a.webkitRequestAnimationFrame||function(e){return a.setTimeout(e,20)};return function(t){return e(t)}}(),n=function(){var e=a.cancelAnimationFrame||a.mozCancelAnimationFrame||a.webkitCancelAnimationFrame||a.clearTimeout;return function(t){return e(t)}}(),o=function(e){var t=e.__resizeTriggers__,a=t.firstElementChild,i=t.lastElementChild,l=a.firstElementChild;i.scrollLeft=i.scrollWidth,i.scrollTop=i.scrollHeight,l.style.width=a.offsetWidth+1+"px",l.style.height=a.offsetHeight+1+"px",a.scrollLeft=a.scrollWidth,a.scrollTop=a.scrollHeight},r=function(e){if(!(e.target.className&&"function"==typeof e.target.className.indexOf&&e.target.className.indexOf("contract-trigger")<0&&e.target.className.indexOf("expand-trigger")<0)){var t=this;o(this),this.__resizeRAF__&&n(this.__resizeRAF__),this.__resizeRAF__=l(function(){(function(e){return e.offsetWidth!=e.__resizeLast__.width||e.offsetHeight!=e.__resizeLast__.height})(t)&&(t.__resizeLast__.width=t.offsetWidth,t.__resizeLast__.height=t.offsetHeight,t.__resizeListeners__.forEach(function(a){a.call(t,e)}))})}},s=!1,u="",c="animationstart",g="Webkit Moz O ms".split(" "),d="webkitAnimationStart animationstart oAnimationStart MSAnimationStart".split(" "),p=a.document.createElement("fakeelement");if(void 0!==p.style.animationName&&(s=!0),!1===s)for(var h=0;h<g.length;h++)if(void 0!==p.style[g[h]+"AnimationName"]){u="-"+g[h].toLowerCase()+"-",c=d[h],s=!0;break}var m="resizeanim",b="@"+u+"keyframes "+m+" { from { opacity: 0; } to { opacity: 0; } } ",f=u+"animation: 1ms "+m+"; "}return{addResizeListener:function(t,l){if(i)t.attachEvent("onresize",l);else{if(!t.__resizeTriggers__){var n=t.ownerDocument,s=a.getComputedStyle(t);s&&"static"==s.position&&(t.style.position="relative"),function(t){if(!t.getElementById("detectElementResize")){var a=(b||"")+".resize-triggers { "+(f||"")+'visibility: hidden; opacity: 0; } .resize-triggers, .resize-triggers > div, .contract-trigger:before { content: " "; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; z-index: -1; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',i=t.head||t.getElementsByTagName("head")[0],l=t.createElement("style");l.id="detectElementResize",l.type="text/css",null!=e&&l.setAttribute("nonce",e),l.styleSheet?l.styleSheet.cssText=a:l.appendChild(t.createTextNode(a)),i.appendChild(l)}}(n),t.__resizeLast__={},t.__resizeListeners__=[],(t.__resizeTriggers__=n.createElement("div")).className="resize-triggers";var u=n.createElement("div");u.className="expand-trigger",u.appendChild(n.createElement("div"));var g=n.createElement("div");g.className="contract-trigger",t.__resizeTriggers__.appendChild(u),t.__resizeTriggers__.appendChild(g),t.appendChild(t.__resizeTriggers__),o(t),t.addEventListener("scroll",r,!0),c&&(t.__resizeTriggers__.__animationListener__=function(e){e.animationName==m&&o(t)},t.__resizeTriggers__.addEventListener(c,t.__resizeTriggers__.__animationListener__))}t.__resizeListeners__.push(l)}},removeResizeListener:function(e,t){if(i)e.detachEvent("onresize",t);else if(e.__resizeListeners__.splice(e.__resizeListeners__.indexOf(t),1),!e.__resizeListeners__.length){e.removeEventListener("scroll",r,!0),e.__resizeTriggers__.__animationListener__&&(e.__resizeTriggers__.removeEventListener(c,e.__resizeTriggers__.__animationListener__),e.__resizeTriggers__.__animationListener__=null);try{e.__resizeTriggers__=!e.removeChild(e.__resizeTriggers__)}catch(e){}}}}}function kl(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function Sl(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?kl(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):kl(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function Cl(e,t,a){return t=dl(t),gl(e,Ml()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Ml(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Ml=function(){return!!e})()}ml(xl,"defaultProps",{disabled:!1,isControlled:!1,mode:"edges",scrollToColumn:0,scrollToRow:0}),(0,bl.polyfill)(xl);var Tl=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=Cl(this,t,[].concat(i)),"state",{height:e.props.defaultHeight||0,width:e.props.defaultWidth||0}),ml(e,"_parentNode",void 0),ml(e,"_autoSizer",void 0),ml(e,"_window",void 0),ml(e,"_detectElementResize",void 0),ml(e,"_onResize",function(){var t=e.props,a=t.disableHeight,i=t.disableWidth,l=t.onResize;if(e._parentNode){var n=e._parentNode.offsetHeight||0,o=e._parentNode.offsetWidth||0,r=(e._window||window).getComputedStyle(e._parentNode)||{},s=parseInt(r.paddingLeft,10)||0,u=parseInt(r.paddingRight,10)||0,c=parseInt(r.paddingTop,10)||0,g=parseInt(r.paddingBottom,10)||0,d=n-c-g,p=o-s-u;(!a&&e.state.height!==d||!i&&e.state.width!==p)&&(e.setState({height:n-c-g,width:o-s-u}),l({height:n,width:o}))}}),ml(e,"_setRef",function(t){e._autoSizer=t}),e}return hl(t,e),cl(t,[{key:"componentDidMount",value:function(){var e=this.props.nonce;this._autoSizer&&this._autoSizer.parentNode&&this._autoSizer.parentNode.ownerDocument&&this._autoSizer.parentNode.ownerDocument.defaultView&&this._autoSizer.parentNode instanceof this._autoSizer.parentNode.ownerDocument.defaultView.HTMLElement&&(this._parentNode=this._autoSizer.parentNode,this._window=this._autoSizer.parentNode.ownerDocument.defaultView,this._detectElementResize=_l(e,this._window),this._detectElementResize.addResizeListener(this._parentNode,this._onResize),this._onResize())}},{key:"componentWillUnmount",value:function(){this._detectElementResize&&this._parentNode&&this._detectElementResize.removeResizeListener(this._parentNode,this._onResize)}},{key:"render",value:function(){var e=this.props,t=e.children,a=e.className,i=e.disableHeight,l=e.disableWidth,n=e.style,o=this.state,r=o.height,s=o.width,u={overflow:"visible"},c={};return i||(u.height=0,c.height=r),l||(u.width=0,c.width=s),w.createElement("div",{className:a,ref:this._setRef,style:Sl(Sl({},u),n)},t(c))}}])}(w.Component);function El(e,t,a){return t=dl(t),gl(e,Dl()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Dl(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Dl=function(){return!!e})()}ml(Tl,"defaultProps",{onResize:function(){},disableHeight:!1,disableWidth:!1,style:{}});var Ll=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=El(this,t,[].concat(i)),"_child",w.createRef()),ml(e,"_measure",function(){var t=e.props,a=t.cache,i=t.columnIndex,l=void 0===i?0:i,n=t.parent,o=t.rowIndex,r=void 0===o?e.props.index||0:o,s=e._getCellMeasurements(),u=s.height,c=s.width;u===a.getHeight(r,l)&&c===a.getWidth(r,l)||(a.set(r,l,c,u),n&&"function"==typeof n.recomputeGridSize&&n.recomputeGridSize({columnIndex:l,rowIndex:r}))}),ml(e,"_registerChild",function(t){!t||t instanceof Element||console.warn("CellMeasurer registerChild expects to be passed Element or null"),e._child.current=t,t&&e._maybeMeasureCell()}),e}return hl(t,e),cl(t,[{key:"componentDidMount",value:function(){this._maybeMeasureCell()}},{key:"componentDidUpdate",value:function(){this._maybeMeasureCell()}},{key:"render",value:function(){var e=this,t=this.props.children,a="function"==typeof t?t({measure:this._measure,registerChild:this._registerChild}):t;return null===a?a:(0,w.cloneElement)(a,{ref:function(t){"function"==typeof a.ref?a.ref(t):a.ref&&(a.ref.current=t),e._child.current=t}})}},{key:"_getCellMeasurements",value:function(){var e=this.props.cache,t=this._child.current;if(t&&t.ownerDocument&&t.ownerDocument.defaultView&&t instanceof t.ownerDocument.defaultView.HTMLElement){var a=t.style.width,i=t.style.height;e.hasFixedWidth()||(t.style.width="auto"),e.hasFixedHeight()||(t.style.height="auto");var l=Math.ceil(t.offsetHeight),n=Math.ceil(t.offsetWidth);return a&&(t.style.width=a),i&&(t.style.height=i),{height:l,width:n}}return{height:0,width:0}}},{key:"_maybeMeasureCell",value:function(){var e=this.props,t=e.cache,a=e.columnIndex,i=void 0===a?0:a,l=e.parent,n=e.rowIndex,o=void 0===n?this.props.index||0:n;if(!t.has(o,i)){var r=this._getCellMeasurements(),s=r.height,u=r.width;t.set(o,i,u,s),l&&"function"==typeof l.invalidateCellSizeAfterRender&&l.invalidateCellSizeAfterRender({columnIndex:i,rowIndex:o})}}}])}(w.PureComponent);function Bl(){return Bl=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var i in a)({}).hasOwnProperty.call(a,i)&&(e[i]=a[i])}return e},Bl.apply(null,arguments)}function Hl(e){var t,a,i="";if("string"==typeof e||"number"==typeof e)i+=e;else if("object"==typeof e)if(Array.isArray(e))for(t=0;t<e.length;t++)e[t]&&(a=Hl(e[t]))&&(i&&(i+=" "),i+=a);else for(t in e)e[t]&&(i&&(i+=" "),i+=t);return i}ml(Ll,"__internalCellMeasurerFlag",!1);const Al=function(){for(var e,t,a=0,i="";a<arguments.length;)(e=arguments[a++])&&(t=Hl(e))&&(i&&(i+=" "),i+=t);return i};function Rl(){var e=!(arguments.length>0&&void 0!==arguments[0])||arguments[0],t={};return function(a){var i=a.callback,l=a.indices,n=Object.keys(l),o=!e||n.every(function(e){var t=l[e];return Array.isArray(t)?t.length>0:t>=0}),r=n.length!==Object.keys(t).length||n.some(function(e){var a=t[e],i=l[e];return Array.isArray(i)?a.join(",")!==i.join(","):a!==i});t=l,o&&r&&i(l)}}const Pl=!("undefined"==typeof window||!window.document||!window.document.createElement);var zl;function Ol(e){if((!zl&&0!==zl||e)&&Pl){var t=document.createElement("div");t.style.position="absolute",t.style.top="-9999px",t.style.width="50px",t.style.height="50px",t.style.overflow="scroll",document.body.appendChild(t),zl=t.offsetWidth-t.clientWidth,document.body.removeChild(t)}return zl}function Fl(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function Il(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?Fl(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):Fl(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function Nl(e,t,a){return t=dl(t),gl(e,Vl()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Vl(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Vl=function(){return!!e})()}var Gl="requested",Wl=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=Nl(this,t,[].concat(i)),"state",{isScrolling:!1,scrollLeft:0,scrollTop:0}),ml(e,"_calculateSizeAndPositionDataOnNextUpdate",!1),ml(e,"_onSectionRenderedMemoizer",Rl()),ml(e,"_onScrollMemoizer",Rl(!1)),ml(e,"_invokeOnSectionRenderedHelper",function(){var t=e.props,a=t.cellLayoutManager,i=t.onSectionRendered;e._onSectionRenderedMemoizer({callback:i,indices:{indices:a.getLastRenderedIndices()}})}),ml(e,"_setScrollingContainerRef",function(t){e._scrollingContainer=t}),ml(e,"_updateScrollPositionForScrollToCell",function(){var t=e.props,a=t.cellLayoutManager,i=t.height,l=t.scrollToAlignment,n=t.scrollToCell,o=t.width,r=e.state,s=r.scrollLeft,u=r.scrollTop;if(n>=0){var c=a.getScrollPositionForCell({align:l,cellIndex:n,height:i,scrollLeft:s,scrollTop:u,width:o});c.scrollLeft===s&&c.scrollTop===u||e._setScrollPosition(c)}}),ml(e,"_onScroll",function(t){if(t.target===e._scrollingContainer){e._enablePointerEventsAfterDelay();var a=e.props,i=a.cellLayoutManager,l=a.height,n=a.isScrollingChange,o=a.width,r=e._scrollbarSize,s=i.getTotalSize(),u=s.height,c=s.width,g=Math.max(0,Math.min(c-o+r,t.target.scrollLeft)),d=Math.max(0,Math.min(u-l+r,t.target.scrollTop));if(e.state.scrollLeft!==g||e.state.scrollTop!==d){var p=t.cancelable?"observed":Gl;e.state.isScrolling||n(!0),e.setState({isScrolling:!0,scrollLeft:g,scrollPositionChangeReason:p,scrollTop:d})}e._invokeOnScrollMemoizer({scrollLeft:g,scrollTop:d,totalWidth:c,totalHeight:u})}}),e._scrollbarSize=Ol(),void 0===e._scrollbarSize?(e._scrollbarSizeMeasured=!1,e._scrollbarSize=0):e._scrollbarSizeMeasured=!0,e}return hl(t,e),cl(t,[{key:"recomputeCellSizesAndPositions",value:function(){this._calculateSizeAndPositionDataOnNextUpdate=!0,this.forceUpdate()}},{key:"componentDidMount",value:function(){var e=this.props,t=e.cellLayoutManager,a=e.scrollLeft,i=e.scrollToCell,l=e.scrollTop;this._scrollbarSizeMeasured||(this._scrollbarSize=Ol(),this._scrollbarSizeMeasured=!0,this.setState({})),i>=0?this._updateScrollPositionForScrollToCell():(a>=0||l>=0)&&this._setScrollPosition({scrollLeft:a,scrollTop:l}),this._invokeOnSectionRenderedHelper();var n=t.getTotalSize(),o=n.height,r=n.width;this._invokeOnScrollMemoizer({scrollLeft:a||0,scrollTop:l||0,totalHeight:o,totalWidth:r})}},{key:"componentDidUpdate",value:function(e,t){var a=this.props,i=a.height,l=a.scrollToAlignment,n=a.scrollToCell,o=a.width,r=this.state,s=r.scrollLeft,u=r.scrollPositionChangeReason,c=r.scrollTop;u===Gl&&(s>=0&&s!==t.scrollLeft&&s!==this._scrollingContainer.scrollLeft&&(this._scrollingContainer.scrollLeft=s),c>=0&&c!==t.scrollTop&&c!==this._scrollingContainer.scrollTop&&(this._scrollingContainer.scrollTop=c)),i===e.height&&l===e.scrollToAlignment&&n===e.scrollToCell&&o===e.width||this._updateScrollPositionForScrollToCell(),this._invokeOnSectionRenderedHelper()}},{key:"componentWillUnmount",value:function(){this._disablePointerEventsTimeoutId&&clearTimeout(this._disablePointerEventsTimeoutId)}},{key:"render",value:function(){var e=this.props,t=e.autoHeight,a=e.cellCount,i=e.cellLayoutManager,l=e.className,n=e.height,o=e.horizontalOverscanSize,r=e.id,s=e.noContentRenderer,u=e.style,c=e.verticalOverscanSize,g=e.width,d=this.state,p=d.isScrolling,h=d.scrollLeft,m=d.scrollTop;(this._lastRenderedCellCount!==a||this._lastRenderedCellLayoutManager!==i||this._calculateSizeAndPositionDataOnNextUpdate)&&(this._lastRenderedCellCount=a,this._lastRenderedCellLayoutManager=i,this._calculateSizeAndPositionDataOnNextUpdate=!1,i.calculateSizeAndPositionData());var b=i.getTotalSize(),f=b.height,v=b.width,y=Math.max(0,h-o),x=Math.max(0,m-c),_=Math.min(v,h+g+o),k=Math.min(f,m+n+c),S=n>0&&g>0?i.cellRenderers({height:k-x,isScrolling:p,width:_-y,x:y,y:x}):[],C={boxSizing:"border-box",direction:"ltr",height:t?"auto":n,position:"relative",WebkitOverflowScrolling:"touch",width:g,willChange:"transform"},M=f>n?this._scrollbarSize:0,T=v>g?this._scrollbarSize:0;return C.overflowX=v+M<=g?"hidden":"auto",C.overflowY=f+T<=n?"hidden":"auto",w.createElement("div",{ref:this._setScrollingContainerRef,"aria-label":this.props["aria-label"],className:Al("ReactVirtualized__Collection",l),id:r,onScroll:this._onScroll,role:"grid",style:Il(Il({},C),u),tabIndex:0},a>0&&w.createElement("div",{className:"ReactVirtualized__Collection__innerScrollContainer",style:{height:f,maxHeight:f,maxWidth:v,overflow:"hidden",pointerEvents:p?"none":"",width:v}},S),0===a&&s())}},{key:"_enablePointerEventsAfterDelay",value:function(){var e=this;this._disablePointerEventsTimeoutId&&clearTimeout(this._disablePointerEventsTimeoutId),this._disablePointerEventsTimeoutId=setTimeout(function(){(0,e.props.isScrollingChange)(!1),e._disablePointerEventsTimeoutId=null,e.setState({isScrolling:!1})},150)}},{key:"_invokeOnScrollMemoizer",value:function(e){var t=this,a=e.scrollLeft,i=e.scrollTop,l=e.totalHeight,n=e.totalWidth;this._onScrollMemoizer({callback:function(e){var a=e.scrollLeft,i=e.scrollTop,o=t.props,r=o.height;(0,o.onScroll)({clientHeight:r,clientWidth:o.width,scrollHeight:l,scrollLeft:a,scrollTop:i,scrollWidth:n})},indices:{scrollLeft:a,scrollTop:i}})}},{key:"_setScrollPosition",value:function(e){var t=e.scrollLeft,a=e.scrollTop,i={scrollPositionChangeReason:Gl};t>=0&&(i.scrollLeft=t),a>=0&&(i.scrollTop=a),(t>=0&&t!==this.state.scrollLeft||a>=0&&a!==this.state.scrollTop)&&this.setState(i)}}],[{key:"getDerivedStateFromProps",value:function(e,t){return 0!==e.cellCount||0===t.scrollLeft&&0===t.scrollTop?e.scrollLeft!==t.scrollLeft||e.scrollTop!==t.scrollTop?{scrollLeft:null!=e.scrollLeft?e.scrollLeft:t.scrollLeft,scrollTop:null!=e.scrollTop?e.scrollTop:t.scrollTop,scrollPositionChangeReason:Gl}:null:{scrollLeft:0,scrollTop:0,scrollPositionChangeReason:Gl}}}])}(w.PureComponent);ml(Wl,"defaultProps",{"aria-label":"grid",horizontalOverscanSize:0,noContentRenderer:function(){return null},onScroll:function(){return null},onSectionRendered:function(){return null},scrollToAlignment:"auto",scrollToCell:-1,style:{},verticalOverscanSize:0}),Wl.propTypes={},(0,bl.polyfill)(Wl);const Ul=Wl;var jl=function(){return cl(function e(t){var a=t.height,i=t.width,l=t.x,n=t.y;ol(this,e),this.height=a,this.width=i,this.x=l,this.y=n,this._indexMap={},this._indices=[]},[{key:"addCellIndex",value:function(e){var t=e.index;this._indexMap[t]||(this._indexMap[t]=!0,this._indices.push(t))}},{key:"getCellIndices",value:function(){return this._indices}},{key:"toString",value:function(){return"".concat(this.x,",").concat(this.y," ").concat(this.width,"x").concat(this.height)}}])}(),ql=function(){return cl(function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:100;ol(this,e),this._sectionSize=t,this._cellMetadata=[],this._sections={}},[{key:"getCellIndices",value:function(e){var t=e.height,a=e.width,i=e.x,l=e.y,n={};return this.getSections({height:t,width:a,x:i,y:l}).forEach(function(e){return e.getCellIndices().forEach(function(e){n[e]=e})}),Object.keys(n).map(function(e){return n[e]})}},{key:"getCellMetadata",value:function(e){var t=e.index;return this._cellMetadata[t]}},{key:"getSections",value:function(e){for(var t=e.height,a=e.width,i=e.x,l=e.y,n=Math.floor(i/this._sectionSize),o=Math.floor((i+a-1)/this._sectionSize),r=Math.floor(l/this._sectionSize),s=Math.floor((l+t-1)/this._sectionSize),u=[],c=n;c<=o;c++)for(var g=r;g<=s;g++){var d="".concat(c,".").concat(g);this._sections[d]||(this._sections[d]=new jl({height:this._sectionSize,width:this._sectionSize,x:c*this._sectionSize,y:g*this._sectionSize})),u.push(this._sections[d])}return u}},{key:"getTotalSectionCount",value:function(){return Object.keys(this._sections).length}},{key:"toString",value:function(){var e=this;return Object.keys(this._sections).map(function(t){return e._sections[t].toString()})}},{key:"registerCell",value:function(e){var t=e.cellMetadatum,a=e.index;this._cellMetadata[a]=t,this.getSections(t).forEach(function(e){return e.addCellIndex({index:a})})}}])}();function $l(e){var t=e.align,a=void 0===t?"auto":t,i=e.cellOffset,l=e.cellSize,n=e.containerSize,o=e.currentOffset,r=i,s=r-n+l;switch(a){case"start":return r;case"end":return s;case"center":return r-(n-l)/2;default:return Math.max(s,Math.min(r,o))}}function Zl(e,t,a){return t=dl(t),gl(e,Kl()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Kl(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Kl=function(){return!!e})()}var Yl=function(e){function t(e,a){var i;return ol(this,t),(i=Zl(this,t,[e,a]))._cellMetadata=[],i._lastRenderedCellIndices=[],i._cellCache=[],i._isScrollingChange=i._isScrollingChange.bind(i),i._setCollectionViewRef=i._setCollectionViewRef.bind(i),i}return hl(t,e),cl(t,[{key:"forceUpdate",value:function(){void 0!==this._collectionView&&this._collectionView.forceUpdate()}},{key:"recomputeCellSizesAndPositions",value:function(){this._cellCache=[],this._collectionView.recomputeCellSizesAndPositions()}},{key:"render",value:function(){var e=Bl({},(function(e){if(null==e)throw new TypeError("Cannot destructure "+e)}(this.props),this.props));return w.createElement(Ul,Bl({cellLayoutManager:this,isScrollingChange:this._isScrollingChange,ref:this._setCollectionViewRef},e))}},{key:"calculateSizeAndPositionData",value:function(){var e=this.props,t=function(e){for(var t=e.cellCount,a=e.cellSizeAndPositionGetter,i=[],l=new ql(e.sectionSize),n=0,o=0,r=0;r<t;r++){var s=a({index:r});if(null==s.height||isNaN(s.height)||null==s.width||isNaN(s.width)||null==s.x||isNaN(s.x)||null==s.y||isNaN(s.y))throw Error("Invalid metadata returned for cell ".concat(r,":\n x:").concat(s.x,", y:").concat(s.y,", width:").concat(s.width,", height:").concat(s.height));n=Math.max(n,s.y+s.height),o=Math.max(o,s.x+s.width),i[r]=s,l.registerCell({cellMetadatum:s,index:r})}return{cellMetadata:i,height:n,sectionManager:l,width:o}}({cellCount:e.cellCount,cellSizeAndPositionGetter:e.cellSizeAndPositionGetter,sectionSize:e.sectionSize});this._cellMetadata=t.cellMetadata,this._sectionManager=t.sectionManager,this._height=t.height,this._width=t.width}},{key:"getLastRenderedIndices",value:function(){return this._lastRenderedCellIndices}},{key:"getScrollPositionForCell",value:function(e){var t=e.align,a=e.cellIndex,i=e.height,l=e.scrollLeft,n=e.scrollTop,o=e.width,r=this.props.cellCount;if(a>=0&&a<r){var s=this._cellMetadata[a];l=$l({align:t,cellOffset:s.x,cellSize:s.width,containerSize:o,currentOffset:l,targetIndex:a}),n=$l({align:t,cellOffset:s.y,cellSize:s.height,containerSize:i,currentOffset:n,targetIndex:a})}return{scrollLeft:l,scrollTop:n}}},{key:"getTotalSize",value:function(){return{height:this._height,width:this._width}}},{key:"cellRenderers",value:function(e){var t=this,a=e.height,i=e.isScrolling,l=e.width,n=e.x,o=e.y,r=this.props,s=r.cellGroupRenderer,u=r.cellRenderer;return this._lastRenderedCellIndices=this._sectionManager.getCellIndices({height:a,width:l,x:n,y:o}),s({cellCache:this._cellCache,cellRenderer:u,cellSizeAndPositionGetter:function(e){var a=e.index;return t._sectionManager.getCellMetadata({index:a})},indices:this._lastRenderedCellIndices,isScrolling:i})}},{key:"_isScrollingChange",value:function(e){e||(this._cellCache=[])}},{key:"_setCollectionViewRef",value:function(e){this._collectionView=e}}])}(w.PureComponent);function Jl(e,t,a){return t=dl(t),gl(e,Xl()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Xl(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Xl=function(){return!!e})()}function Ql(e){var t=e.cellCount,a=e.cellSize,i=e.computeMetadataCallback,l=e.computeMetadataCallbackProps,n=e.nextCellsCount,o=e.nextCellSize,r=e.nextScrollToIndex,s=e.scrollToIndex,u=e.updateScrollOffsetForScrollToIndex;t===n&&("number"!=typeof a&&"number"!=typeof o||a===o)||(i(l),s>=0&&s===r&&u())}function en(e,t){if(null==e)return{};var a,i,l=function(e,t){if(null==e)return{};var a={};for(var i in e)if({}.hasOwnProperty.call(e,i)){if(-1!==t.indexOf(i))continue;a[i]=e[i]}return a}(e,t);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);for(i=0;i<n.length;i++)a=n[i],-1===t.indexOf(a)&&{}.propertyIsEnumerable.call(e,a)&&(l[a]=e[a])}return l}ml(Yl,"defaultProps",{"aria-label":"grid",cellGroupRenderer:function(e){var t=e.cellCache,a=e.cellRenderer,i=e.cellSizeAndPositionGetter,l=e.indices,n=e.isScrolling;return l.map(function(e){var l=i({index:e}),o={index:e,isScrolling:n,key:e,style:{height:l.height,left:l.x,position:"absolute",top:l.y,width:l.width}};return n?(e in t||(t[e]=a(o)),t[e]):a(o)}).filter(function(e){return!!e})}}),Yl.propTypes={},(function(e){function t(e,a){var i;return ol(this,t),(i=Jl(this,t,[e,a]))._registerChild=i._registerChild.bind(i),i}return hl(t,e),cl(t,[{key:"componentDidUpdate",value:function(e){var t=this.props,a=t.columnMaxWidth,i=t.columnMinWidth,l=t.columnCount,n=t.width;a===e.columnMaxWidth&&i===e.columnMinWidth&&l===e.columnCount&&n===e.width||this._registeredChild&&this._registeredChild.recomputeGridSize()}},{key:"render",value:function(){var e=this.props,t=e.children,a=e.columnMaxWidth,i=e.columnMinWidth,l=e.columnCount,n=e.width,o=i||1,r=a?Math.min(a,n):n,s=n/l;return s=Math.max(o,s),s=Math.min(r,s),s=Math.floor(s),t({adjustedWidth:Math.min(n,s*l),columnWidth:s,getColumnWidth:function(){return s},registerChild:this._registerChild})}},{key:"_registerChild",value:function(e){if(e&&"function"!=typeof e.recomputeGridSize)throw Error("Unexpected child type registered; only Grid/MultiGrid children are supported.");this._registeredChild=e,this._registeredChild&&this._registeredChild.recomputeGridSize()}}])}(w.PureComponent)).propTypes={};var tn,an=function(){return cl(function e(t){var a=t.cellCount,i=t.cellSizeGetter,l=t.estimatedCellSize;ol(this,e),ml(this,"_cellSizeAndPositionData",{}),ml(this,"_lastMeasuredIndex",-1),ml(this,"_lastBatchedIndex",-1),ml(this,"_cellCount",void 0),ml(this,"_cellSizeGetter",void 0),ml(this,"_estimatedCellSize",void 0),this._cellSizeGetter=i,this._cellCount=a,this._estimatedCellSize=l},[{key:"areOffsetsAdjusted",value:function(){return!1}},{key:"configure",value:function(e){var t=e.cellCount,a=e.estimatedCellSize,i=e.cellSizeGetter;this._cellCount=t,this._estimatedCellSize=a,this._cellSizeGetter=i}},{key:"getCellCount",value:function(){return this._cellCount}},{key:"getEstimatedCellSize",value:function(){return this._estimatedCellSize}},{key:"getLastMeasuredIndex",value:function(){return this._lastMeasuredIndex}},{key:"getOffsetAdjustment",value:function(){return 0}},{key:"getSizeAndPositionOfCell",value:function(e){if(e<0||e>=this._cellCount)throw Error("Requested index ".concat(e," is outside of range 0..").concat(this._cellCount));if(e>this._lastMeasuredIndex)for(var t=this.getSizeAndPositionOfLastMeasuredCell(),a=t.offset+t.size,i=this._lastMeasuredIndex+1;i<=e;i++){var l=this._cellSizeGetter({index:i});if(void 0===l||isNaN(l))throw Error("Invalid size returned for cell ".concat(i," of value ").concat(l));null===l?(this._cellSizeAndPositionData[i]={offset:a,size:0},this._lastBatchedIndex=e):(this._cellSizeAndPositionData[i]={offset:a,size:l},a+=l,this._lastMeasuredIndex=e)}return this._cellSizeAndPositionData[e]}},{key:"getSizeAndPositionOfLastMeasuredCell",value:function(){return this._lastMeasuredIndex>=0?this._cellSizeAndPositionData[this._lastMeasuredIndex]:{offset:0,size:0}}},{key:"getTotalSize",value:function(){var e=this.getSizeAndPositionOfLastMeasuredCell();return e.offset+e.size+(this._cellCount-this._lastMeasuredIndex-1)*this._estimatedCellSize}},{key:"getUpdatedOffsetForIndex",value:function(e){var t=e.align,a=void 0===t?"auto":t,i=e.containerSize,l=e.currentOffset,n=e.targetIndex;if(i<=0)return 0;var o,r=this.getSizeAndPositionOfCell(n),s=r.offset,u=s-i+r.size;switch(a){case"start":o=s;break;case"end":o=u;break;case"center":o=s-(i-r.size)/2;break;default:o=Math.max(u,Math.min(s,l))}var c=this.getTotalSize();return Math.max(0,Math.min(c-i,o))}},{key:"getVisibleCellRange",value:function(e){var t=e.containerSize,a=e.offset;if(0===this.getTotalSize())return{};var i=a+t,l=this._findNearestCell(a),n=this.getSizeAndPositionOfCell(l);a=n.offset+n.size;for(var o=l;a<i&&o<this._cellCount-1;)o++,a+=this.getSizeAndPositionOfCell(o).size;return{start:l,stop:o}}},{key:"resetCell",value:function(e){this._lastMeasuredIndex=Math.min(this._lastMeasuredIndex,e-1)}},{key:"_binarySearch",value:function(e,t,a){for(;t<=e;){var i=t+Math.floor((e-t)/2),l=this.getSizeAndPositionOfCell(i).offset;if(l===a)return i;l<a?t=i+1:l>a&&(e=i-1)}return t>0?t-1:0}},{key:"_exponentialSearch",value:function(e,t){for(var a=1;e<this._cellCount&&this.getSizeAndPositionOfCell(e).offset<t;)e+=a,a*=2;return this._binarySearch(Math.min(e,this._cellCount-1),Math.floor(e/2),t)}},{key:"_findNearestCell",value:function(e){if(isNaN(e))throw Error("Invalid offset ".concat(e," specified"));e=Math.max(0,e);var t=this.getSizeAndPositionOfLastMeasuredCell(),a=Math.max(0,this._lastMeasuredIndex);return t.offset>=e?this._binarySearch(a,0,e):this._exponentialSearch(a,e)}}])}(),ln=["maxScrollSize"],nn=function(){return cl(function e(t){var a=t.maxScrollSize,i=void 0===a?"undefined"!=typeof window&&window.chrome?16777100:15e5:a,l=en(t,ln);ol(this,e),ml(this,"_cellSizeAndPositionManager",void 0),ml(this,"_maxScrollSize",void 0),this._cellSizeAndPositionManager=new an(l),this._maxScrollSize=i},[{key:"areOffsetsAdjusted",value:function(){return this._cellSizeAndPositionManager.getTotalSize()>this._maxScrollSize}},{key:"configure",value:function(e){this._cellSizeAndPositionManager.configure(e)}},{key:"getCellCount",value:function(){return this._cellSizeAndPositionManager.getCellCount()}},{key:"getEstimatedCellSize",value:function(){return this._cellSizeAndPositionManager.getEstimatedCellSize()}},{key:"getLastMeasuredIndex",value:function(){return this._cellSizeAndPositionManager.getLastMeasuredIndex()}},{key:"getOffsetAdjustment",value:function(e){var t=e.containerSize,a=e.offset,i=this._cellSizeAndPositionManager.getTotalSize(),l=this.getTotalSize(),n=this._getOffsetPercentage({containerSize:t,offset:a,totalSize:l});return Math.round(n*(l-i))}},{key:"getSizeAndPositionOfCell",value:function(e){return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(e)}},{key:"getSizeAndPositionOfLastMeasuredCell",value:function(){return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell()}},{key:"getTotalSize",value:function(){return Math.min(this._maxScrollSize,this._cellSizeAndPositionManager.getTotalSize())}},{key:"getUpdatedOffsetForIndex",value:function(e){var t=e.align,a=void 0===t?"auto":t,i=e.containerSize,l=e.currentOffset,n=e.targetIndex;l=this._safeOffsetToOffset({containerSize:i,offset:l});var o=this._cellSizeAndPositionManager.getUpdatedOffsetForIndex({align:a,containerSize:i,currentOffset:l,targetIndex:n});return this._offsetToSafeOffset({containerSize:i,offset:o})}},{key:"getVisibleCellRange",value:function(e){var t=e.containerSize,a=e.offset;return a=this._safeOffsetToOffset({containerSize:t,offset:a}),this._cellSizeAndPositionManager.getVisibleCellRange({containerSize:t,offset:a})}},{key:"resetCell",value:function(e){this._cellSizeAndPositionManager.resetCell(e)}},{key:"_getOffsetPercentage",value:function(e){var t=e.containerSize,a=e.offset,i=e.totalSize;return i<=t?0:a/(i-t)}},{key:"_offsetToSafeOffset",value:function(e){var t=e.containerSize,a=e.offset,i=this._cellSizeAndPositionManager.getTotalSize(),l=this.getTotalSize();if(i===l)return a;var n=this._getOffsetPercentage({containerSize:t,offset:a,totalSize:i});return Math.round(n*(l-t))}},{key:"_safeOffsetToOffset",value:function(e){var t=e.containerSize,a=e.offset,i=this._cellSizeAndPositionManager.getTotalSize(),l=this.getTotalSize();if(i===l)return a;var n=this._getOffsetPercentage({containerSize:t,offset:a,totalSize:l});return Math.round(n*(i-t))}}])}();function on(e){var t=e.cellSize,a=e.cellSizeAndPositionManager,i=e.previousCellsCount,l=e.previousCellSize,n=e.previousScrollToAlignment,o=e.previousScrollToIndex,r=e.previousSize,s=e.scrollOffset,u=e.scrollToAlignment,c=e.scrollToIndex,g=e.size,d=e.sizeJustIncreasedFromZero,p=e.updateScrollIndexCallback,h=a.getCellCount(),m=c>=0&&c<h;m&&(g!==r||d||!l||"number"==typeof t&&t!==l||u!==n||c!==o)?p(c):!m&&h>0&&(g<r||h<i)&&s>a.getTotalSize()-g&&p(h-1)}var rn=(tn="undefined"!=typeof window?window:"undefined"!=typeof self?self:{}).requestAnimationFrame||tn.webkitRequestAnimationFrame||tn.mozRequestAnimationFrame||tn.oRequestAnimationFrame||tn.msRequestAnimationFrame||function(e){return tn.setTimeout(e,1e3/60)},sn=tn.cancelAnimationFrame||tn.webkitCancelAnimationFrame||tn.mozCancelAnimationFrame||tn.oCancelAnimationFrame||tn.msCancelAnimationFrame||function(e){tn.clearTimeout(e)},un=rn,cn=sn,gn=function(e){return cn(e.id)},dn=function(e,t){var a;Promise.resolve().then(function(){a=Date.now()});var i=function(){Date.now()-a>=t?e.call():l.id=un(i)},l={id:un(i)};return l};function pn(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function hn(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?pn(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):pn(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function mn(e,t,a){return t=dl(t),gl(e,bn()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function bn(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(bn=function(){return!!e})()}var fn="requested",vn=function(e){function t(e){var a;ol(this,t),ml(a=mn(this,t,[e]),"_onGridRenderedMemoizer",Rl()),ml(a,"_onScrollMemoizer",Rl(!1)),ml(a,"_deferredInvalidateColumnIndex",null),ml(a,"_deferredInvalidateRowIndex",null),ml(a,"_recomputeScrollLeftFlag",!1),ml(a,"_recomputeScrollTopFlag",!1),ml(a,"_horizontalScrollBarSize",0),ml(a,"_verticalScrollBarSize",0),ml(a,"_scrollbarPresenceChanged",!1),ml(a,"_scrollingContainer",void 0),ml(a,"_childrenToDisplay",void 0),ml(a,"_columnStartIndex",void 0),ml(a,"_columnStopIndex",void 0),ml(a,"_rowStartIndex",void 0),ml(a,"_rowStopIndex",void 0),ml(a,"_renderedColumnStartIndex",0),ml(a,"_renderedColumnStopIndex",0),ml(a,"_renderedRowStartIndex",0),ml(a,"_renderedRowStopIndex",0),ml(a,"_initialScrollTop",void 0),ml(a,"_initialScrollLeft",void 0),ml(a,"_disablePointerEventsTimeoutId",void 0),ml(a,"_styleCache",{}),ml(a,"_cellCache",{}),ml(a,"_debounceScrollEndedCallback",function(){a._disablePointerEventsTimeoutId=null,a.setState({isScrolling:!1,needToResetStyleCache:!1})}),ml(a,"_invokeOnGridRenderedHelper",function(){var e=a.props.onSectionRendered;a._onGridRenderedMemoizer({callback:e,indices:{columnOverscanStartIndex:a._columnStartIndex,columnOverscanStopIndex:a._columnStopIndex,columnStartIndex:a._renderedColumnStartIndex,columnStopIndex:a._renderedColumnStopIndex,rowOverscanStartIndex:a._rowStartIndex,rowOverscanStopIndex:a._rowStopIndex,rowStartIndex:a._renderedRowStartIndex,rowStopIndex:a._renderedRowStopIndex}})}),ml(a,"_setScrollingContainerRef",function(e){a._scrollingContainer=e,"function"==typeof a.props.elementRef?a.props.elementRef(e):"object"===rl(a.props.elementRef)&&(a.props.elementRef.current=e)}),ml(a,"_onScroll",function(e){e.target===a._scrollingContainer&&a.handleScrollEvent(e.target)});var i=new nn({cellCount:e.columnCount,cellSizeGetter:function(a){return t._wrapSizeGetter(e.columnWidth)(a)},estimatedCellSize:t._getEstimatedColumnSize(e)}),l=new nn({cellCount:e.rowCount,cellSizeGetter:function(a){return t._wrapSizeGetter(e.rowHeight)(a)},estimatedCellSize:t._getEstimatedRowSize(e)});return a.state={instanceProps:{columnSizeAndPositionManager:i,rowSizeAndPositionManager:l,prevColumnWidth:e.columnWidth,prevRowHeight:e.rowHeight,prevColumnCount:e.columnCount,prevRowCount:e.rowCount,prevIsScrolling:!0===e.isScrolling,prevScrollToColumn:e.scrollToColumn,prevScrollToRow:e.scrollToRow,scrollbarSize:0,scrollbarSizeMeasured:!1},isScrolling:!1,scrollDirectionHorizontal:1,scrollDirectionVertical:1,scrollLeft:0,scrollTop:0,scrollPositionChangeReason:null,needToResetStyleCache:!1},e.scrollToRow>0&&(a._initialScrollTop=a._getCalculatedScrollTop(e,a.state)),e.scrollToColumn>0&&(a._initialScrollLeft=a._getCalculatedScrollLeft(e,a.state)),a}return hl(t,e),cl(t,[{key:"getOffsetForCell",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.alignment,a=void 0===t?this.props.scrollToAlignment:t,i=e.columnIndex,l=void 0===i?this.props.scrollToColumn:i,n=e.rowIndex,o=void 0===n?this.props.scrollToRow:n,r=hn(hn({},this.props),{},{scrollToAlignment:a,scrollToColumn:l,scrollToRow:o});return{scrollLeft:this._getCalculatedScrollLeft(r),scrollTop:this._getCalculatedScrollTop(r)}}},{key:"getTotalRowsHeight",value:function(){return this.state.instanceProps.rowSizeAndPositionManager.getTotalSize()}},{key:"getTotalColumnsWidth",value:function(){return this.state.instanceProps.columnSizeAndPositionManager.getTotalSize()}},{key:"handleScrollEvent",value:function(e){var t=e.scrollLeft,a=void 0===t?0:t,i=e.scrollTop,l=void 0===i?0:i;if(!(l<0)){this._debounceScrollEnded();var n=this.props,o=n.autoHeight,r=n.autoWidth,s=n.height,u=n.width,c=this.state.instanceProps,g=c.scrollbarSize,d=c.rowSizeAndPositionManager.getTotalSize(),p=c.columnSizeAndPositionManager.getTotalSize(),h=Math.min(Math.max(0,p-u+g),a),m=Math.min(Math.max(0,d-s+g),l);if(this.state.scrollLeft!==h||this.state.scrollTop!==m){var b={isScrolling:!0,scrollDirectionHorizontal:h!==this.state.scrollLeft?h>this.state.scrollLeft?1:-1:this.state.scrollDirectionHorizontal,scrollDirectionVertical:m!==this.state.scrollTop?m>this.state.scrollTop?1:-1:this.state.scrollDirectionVertical,scrollPositionChangeReason:"observed"};o||(b.scrollTop=m),r||(b.scrollLeft=h),b.needToResetStyleCache=!1,this.setState(b)}this._invokeOnScrollMemoizer({scrollLeft:h,scrollTop:m,totalColumnsWidth:p,totalRowsHeight:d})}}},{key:"invalidateCellSizeAfterRender",value:function(e){var t=e.columnIndex,a=e.rowIndex;this._deferredInvalidateColumnIndex="number"==typeof this._deferredInvalidateColumnIndex?Math.min(this._deferredInvalidateColumnIndex,t):t,this._deferredInvalidateRowIndex="number"==typeof this._deferredInvalidateRowIndex?Math.min(this._deferredInvalidateRowIndex,a):a}},{key:"measureAllCells",value:function(){var e=this.props,t=e.columnCount,a=e.rowCount,i=this.state.instanceProps;i.columnSizeAndPositionManager.getSizeAndPositionOfCell(t-1),i.rowSizeAndPositionManager.getSizeAndPositionOfCell(a-1)}},{key:"recomputeGridSize",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.columnIndex,a=void 0===t?0:t,i=e.rowIndex,l=void 0===i?0:i,n=this.props,o=n.scrollToColumn,r=n.scrollToRow,s=this.state.instanceProps;s.columnSizeAndPositionManager.resetCell(a),s.rowSizeAndPositionManager.resetCell(l),this._recomputeScrollLeftFlag=o>=0&&(1===this.state.scrollDirectionHorizontal?a<=o:a>=o),this._recomputeScrollTopFlag=r>=0&&(1===this.state.scrollDirectionVertical?l<=r:l>=r),this._styleCache={},this._cellCache={},this.forceUpdate()}},{key:"scrollToCell",value:function(e){var t=e.columnIndex,a=e.rowIndex,i=this.props.columnCount,l=this.props;i>1&&void 0!==t&&this._updateScrollLeftForScrollToColumn(hn(hn({},l),{},{scrollToColumn:t})),void 0!==a&&this._updateScrollTopForScrollToRow(hn(hn({},l),{},{scrollToRow:a}))}},{key:"componentDidMount",value:function(){var e=this.props,a=e.getScrollbarSize,i=e.height,l=e.scrollLeft,n=e.scrollToColumn,o=e.scrollTop,r=e.scrollToRow,s=e.width,u=this.state.instanceProps;if(this._initialScrollTop=0,this._initialScrollLeft=0,this._handleInvalidatedGridSize(),u.scrollbarSizeMeasured||this.setState(function(e){var t=hn(hn({},e),{},{needToResetStyleCache:!1});return t.instanceProps.scrollbarSize=a(),t.instanceProps.scrollbarSizeMeasured=!0,t}),"number"==typeof l&&l>=0||"number"==typeof o&&o>=0){var c=t._getScrollToPositionStateUpdate({prevState:this.state,scrollLeft:l,scrollTop:o});c&&(c.needToResetStyleCache=!1,this.setState(c))}this._scrollingContainer&&(this._scrollingContainer.scrollLeft!==this.state.scrollLeft&&(this._scrollingContainer.scrollLeft=this.state.scrollLeft),this._scrollingContainer.scrollTop!==this.state.scrollTop&&(this._scrollingContainer.scrollTop=this.state.scrollTop));var g=i>0&&s>0;n>=0&&g&&this._updateScrollLeftForScrollToColumn(),r>=0&&g&&this._updateScrollTopForScrollToRow(),this._invokeOnGridRenderedHelper(),this._invokeOnScrollMemoizer({scrollLeft:l||0,scrollTop:o||0,totalColumnsWidth:u.columnSizeAndPositionManager.getTotalSize(),totalRowsHeight:u.rowSizeAndPositionManager.getTotalSize()}),this._maybeCallOnScrollbarPresenceChange()}},{key:"componentDidUpdate",value:function(e,t){var a=this,i=this.props,l=i.autoHeight,n=i.autoWidth,o=i.columnCount,r=i.height,s=i.rowCount,u=i.scrollToAlignment,c=i.scrollToColumn,g=i.scrollToRow,d=i.width,p=this.state,h=p.scrollLeft,m=p.scrollPositionChangeReason,b=p.scrollTop,f=p.instanceProps;this._handleInvalidatedGridSize();var v=o>0&&0===e.columnCount||s>0&&0===e.rowCount;m===fn&&(!n&&h>=0&&(h!==this._scrollingContainer.scrollLeft||v)&&(this._scrollingContainer.scrollLeft=h),!l&&b>=0&&(b!==this._scrollingContainer.scrollTop||v)&&(this._scrollingContainer.scrollTop=b));var w=(0===e.width||0===e.height)&&r>0&&d>0;if(this._recomputeScrollLeftFlag?(this._recomputeScrollLeftFlag=!1,this._updateScrollLeftForScrollToColumn(this.props)):on({cellSizeAndPositionManager:f.columnSizeAndPositionManager,previousCellsCount:e.columnCount,previousCellSize:e.columnWidth,previousScrollToAlignment:e.scrollToAlignment,previousScrollToIndex:e.scrollToColumn,previousSize:e.width,scrollOffset:h,scrollToAlignment:u,scrollToIndex:c,size:d,sizeJustIncreasedFromZero:w,updateScrollIndexCallback:function(){return a._updateScrollLeftForScrollToColumn(a.props)}}),this._recomputeScrollTopFlag?(this._recomputeScrollTopFlag=!1,this._updateScrollTopForScrollToRow(this.props)):on({cellSizeAndPositionManager:f.rowSizeAndPositionManager,previousCellsCount:e.rowCount,previousCellSize:e.rowHeight,previousScrollToAlignment:e.scrollToAlignment,previousScrollToIndex:e.scrollToRow,previousSize:e.height,scrollOffset:b,scrollToAlignment:u,scrollToIndex:g,size:r,sizeJustIncreasedFromZero:w,updateScrollIndexCallback:function(){return a._updateScrollTopForScrollToRow(a.props)}}),this._invokeOnGridRenderedHelper(),h!==t.scrollLeft||b!==t.scrollTop){var y=f.rowSizeAndPositionManager.getTotalSize(),x=f.columnSizeAndPositionManager.getTotalSize();this._invokeOnScrollMemoizer({scrollLeft:h,scrollTop:b,totalColumnsWidth:x,totalRowsHeight:y})}this._maybeCallOnScrollbarPresenceChange()}},{key:"componentWillUnmount",value:function(){this._disablePointerEventsTimeoutId&&gn(this._disablePointerEventsTimeoutId)}},{key:"render",value:function(){var e=this.props,t=e.autoContainerWidth,a=e.autoHeight,i=e.autoWidth,l=e.className,n=e.containerProps,o=e.containerRole,r=e.containerStyle,s=e.height,u=e.id,c=e.noContentRenderer,g=e.role,d=e.style,p=e.tabIndex,h=e.width,m=this.state,b=m.instanceProps,f=m.needToResetStyleCache,v=this._isScrolling(),y={boxSizing:"border-box",direction:"ltr",height:a?"auto":s,position:"relative",width:i?"auto":h,WebkitOverflowScrolling:"touch",willChange:"transform"};f&&(this._styleCache={}),this.state.isScrolling||this._resetStyleCache(),this._calculateChildrenToRender(this.props,this.state);var x=b.columnSizeAndPositionManager.getTotalSize(),_=b.rowSizeAndPositionManager.getTotalSize(),k=_>s?b.scrollbarSize:0,S=x>h?b.scrollbarSize:0;S===this._horizontalScrollBarSize&&k===this._verticalScrollBarSize||(this._horizontalScrollBarSize=S,this._verticalScrollBarSize=k,this._scrollbarPresenceChanged=!0),y.overflowX=x+k<=h?"hidden":"auto",y.overflowY=_+S<=s?"hidden":"auto";var C=this._childrenToDisplay,M=0===C.length&&s>0&&h>0;return w.createElement("div",Bl({ref:this._setScrollingContainerRef},n,{"aria-label":this.props["aria-label"],"aria-readonly":this.props["aria-readonly"],className:Al("ReactVirtualized__Grid",l),id:u,onScroll:this._onScroll,role:g,style:hn(hn({},y),d),tabIndex:p}),C.length>0&&w.createElement("div",{className:"ReactVirtualized__Grid__innerScrollContainer",role:o,style:hn({width:t?"auto":x,height:_,maxWidth:x,maxHeight:_,overflow:"hidden",pointerEvents:v?"none":"",position:"relative"},r)},C),M&&c())}},{key:"_calculateChildrenToRender",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.state,a=e.cellRenderer,i=e.cellRangeRenderer,l=e.columnCount,n=e.deferredMeasurementCache,o=e.height,r=e.overscanColumnCount,s=e.overscanIndicesGetter,u=e.overscanRowCount,c=e.rowCount,g=e.width,d=e.isScrollingOptOut,p=t.scrollDirectionHorizontal,h=t.scrollDirectionVertical,m=t.instanceProps,b=this._initialScrollTop>0?this._initialScrollTop:t.scrollTop,f=this._initialScrollLeft>0?this._initialScrollLeft:t.scrollLeft,v=this._isScrolling(e,t);if(this._childrenToDisplay=[],o>0&&g>0){var w=m.columnSizeAndPositionManager.getVisibleCellRange({containerSize:g,offset:f}),y=m.rowSizeAndPositionManager.getVisibleCellRange({containerSize:o,offset:b}),x=m.columnSizeAndPositionManager.getOffsetAdjustment({containerSize:g,offset:f}),_=m.rowSizeAndPositionManager.getOffsetAdjustment({containerSize:o,offset:b});this._renderedColumnStartIndex=w.start,this._renderedColumnStopIndex=w.stop,this._renderedRowStartIndex=y.start,this._renderedRowStopIndex=y.stop;var k=s({direction:"horizontal",cellCount:l,overscanCellsCount:r,scrollDirection:p,startIndex:"number"==typeof w.start?w.start:0,stopIndex:"number"==typeof w.stop?w.stop:-1}),S=s({direction:"vertical",cellCount:c,overscanCellsCount:u,scrollDirection:h,startIndex:"number"==typeof y.start?y.start:0,stopIndex:"number"==typeof y.stop?y.stop:-1}),C=k.overscanStartIndex,M=k.overscanStopIndex,T=S.overscanStartIndex,E=S.overscanStopIndex;if(n){if(!n.hasFixedHeight())for(var D=T;D<=E;D++)if(!n.has(D,0)){C=0,M=l-1;break}if(!n.hasFixedWidth())for(var L=C;L<=M;L++)if(!n.has(0,L)){T=0,E=c-1;break}}this._childrenToDisplay=i({cellCache:this._cellCache,cellRenderer:a,columnSizeAndPositionManager:m.columnSizeAndPositionManager,columnStartIndex:C,columnStopIndex:M,deferredMeasurementCache:n,horizontalOffsetAdjustment:x,isScrolling:v,isScrollingOptOut:d,parent:this,rowSizeAndPositionManager:m.rowSizeAndPositionManager,rowStartIndex:T,rowStopIndex:E,scrollLeft:f,scrollTop:b,styleCache:this._styleCache,verticalOffsetAdjustment:_,visibleColumnIndices:w,visibleRowIndices:y}),this._columnStartIndex=C,this._columnStopIndex=M,this._rowStartIndex=T,this._rowStopIndex=E}}},{key:"_debounceScrollEnded",value:function(){var e=this.props.scrollingResetTimeInterval;this._disablePointerEventsTimeoutId&&gn(this._disablePointerEventsTimeoutId),this._disablePointerEventsTimeoutId=dn(this._debounceScrollEndedCallback,e)}},{key:"_handleInvalidatedGridSize",value:function(){if("number"==typeof this._deferredInvalidateColumnIndex&&"number"==typeof this._deferredInvalidateRowIndex){var e=this._deferredInvalidateColumnIndex,t=this._deferredInvalidateRowIndex;this._deferredInvalidateColumnIndex=null,this._deferredInvalidateRowIndex=null,this.recomputeGridSize({columnIndex:e,rowIndex:t})}}},{key:"_invokeOnScrollMemoizer",value:function(e){var t=this,a=e.scrollLeft,i=e.scrollTop,l=e.totalColumnsWidth,n=e.totalRowsHeight;this._onScrollMemoizer({callback:function(e){var a=e.scrollLeft,i=e.scrollTop,o=t.props,r=o.height;(0,o.onScroll)({clientHeight:r,clientWidth:o.width,scrollHeight:n,scrollLeft:a,scrollTop:i,scrollWidth:l})},indices:{scrollLeft:a,scrollTop:i}})}},{key:"_isScrolling",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.state;return Object.hasOwnProperty.call(e,"isScrolling")?Boolean(e.isScrolling):Boolean(t.isScrolling)}},{key:"_maybeCallOnScrollbarPresenceChange",value:function(){if(this._scrollbarPresenceChanged){var e=this.props.onScrollbarPresenceChange;this._scrollbarPresenceChanged=!1,e({horizontal:this._horizontalScrollBarSize>0,size:this.state.instanceProps.scrollbarSize,vertical:this._verticalScrollBarSize>0})}}},{key:"scrollToPosition",value:function(e){var a=e.scrollLeft,i=e.scrollTop,l=t._getScrollToPositionStateUpdate({prevState:this.state,scrollLeft:a,scrollTop:i});l&&(l.needToResetStyleCache=!1,this.setState(l))}},{key:"_getCalculatedScrollLeft",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.state;return t._getCalculatedScrollLeft(e,a)}},{key:"_updateScrollLeftForScrollToColumn",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.state,i=t._getScrollLeftForScrollToColumnStateUpdate(e,a);i&&(i.needToResetStyleCache=!1,this.setState(i))}},{key:"_getCalculatedScrollTop",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.state;return t._getCalculatedScrollTop(e,a)}},{key:"_resetStyleCache",value:function(){var e=this._styleCache,t=this._cellCache,a=this.props.isScrollingOptOut;this._cellCache={},this._styleCache={};for(var i=this._rowStartIndex;i<=this._rowStopIndex;i++)for(var l=this._columnStartIndex;l<=this._columnStopIndex;l++){var n="".concat(i,"-").concat(l);this._styleCache[n]=e[n],a&&(this._cellCache[n]=t[n])}}},{key:"_updateScrollTopForScrollToRow",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props,a=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.state,i=t._getScrollTopForScrollToRowStateUpdate(e,a);i&&(i.needToResetStyleCache=!1,this.setState(i))}}],[{key:"getDerivedStateFromProps",value:function(e,a){var i={};0===e.columnCount&&0!==a.scrollLeft||0===e.rowCount&&0!==a.scrollTop?(i.scrollLeft=0,i.scrollTop=0):(e.scrollLeft!==a.scrollLeft&&e.scrollToColumn<0||e.scrollTop!==a.scrollTop&&e.scrollToRow<0)&&Object.assign(i,t._getScrollToPositionStateUpdate({prevState:a,scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}));var l,n,o=a.instanceProps;return i.needToResetStyleCache=!1,e.columnWidth===o.prevColumnWidth&&e.rowHeight===o.prevRowHeight||(i.needToResetStyleCache=!0),o.columnSizeAndPositionManager.configure({cellCount:e.columnCount,estimatedCellSize:t._getEstimatedColumnSize(e),cellSizeGetter:t._wrapSizeGetter(e.columnWidth)}),o.rowSizeAndPositionManager.configure({cellCount:e.rowCount,estimatedCellSize:t._getEstimatedRowSize(e),cellSizeGetter:t._wrapSizeGetter(e.rowHeight)}),0!==o.prevColumnCount&&0!==o.prevRowCount||(o.prevColumnCount=0,o.prevRowCount=0),e.autoHeight&&!1===e.isScrolling&&!0===o.prevIsScrolling&&Object.assign(i,{isScrolling:!1}),Ql({cellCount:o.prevColumnCount,cellSize:"number"==typeof o.prevColumnWidth?o.prevColumnWidth:null,computeMetadataCallback:function(){return o.columnSizeAndPositionManager.resetCell(0)},computeMetadataCallbackProps:e,nextCellsCount:e.columnCount,nextCellSize:"number"==typeof e.columnWidth?e.columnWidth:null,nextScrollToIndex:e.scrollToColumn,scrollToIndex:o.prevScrollToColumn,updateScrollOffsetForScrollToIndex:function(){l=t._getScrollLeftForScrollToColumnStateUpdate(e,a)}}),Ql({cellCount:o.prevRowCount,cellSize:"number"==typeof o.prevRowHeight?o.prevRowHeight:null,computeMetadataCallback:function(){return o.rowSizeAndPositionManager.resetCell(0)},computeMetadataCallbackProps:e,nextCellsCount:e.rowCount,nextCellSize:"number"==typeof e.rowHeight?e.rowHeight:null,nextScrollToIndex:e.scrollToRow,scrollToIndex:o.prevScrollToRow,updateScrollOffsetForScrollToIndex:function(){n=t._getScrollTopForScrollToRowStateUpdate(e,a)}}),o.prevColumnCount=e.columnCount,o.prevColumnWidth=e.columnWidth,o.prevIsScrolling=!0===e.isScrolling,o.prevRowCount=e.rowCount,o.prevRowHeight=e.rowHeight,o.prevScrollToColumn=e.scrollToColumn,o.prevScrollToRow=e.scrollToRow,o.scrollbarSize=e.getScrollbarSize(),void 0===o.scrollbarSize?(o.scrollbarSizeMeasured=!1,o.scrollbarSize=0):o.scrollbarSizeMeasured=!0,i.instanceProps=o,hn(hn(hn({},i),l),n)}},{key:"_getEstimatedColumnSize",value:function(e){return"number"==typeof e.columnWidth?e.columnWidth:e.estimatedColumnSize}},{key:"_getEstimatedRowSize",value:function(e){return"number"==typeof e.rowHeight?e.rowHeight:e.estimatedRowSize}},{key:"_getScrollToPositionStateUpdate",value:function(e){var t=e.prevState,a=e.scrollLeft,i=e.scrollTop,l={scrollPositionChangeReason:fn};return"number"==typeof a&&a>=0&&(l.scrollDirectionHorizontal=a>t.scrollLeft?1:-1,l.scrollLeft=a),"number"==typeof i&&i>=0&&(l.scrollDirectionVertical=i>t.scrollTop?1:-1,l.scrollTop=i),"number"==typeof a&&a>=0&&a!==t.scrollLeft||"number"==typeof i&&i>=0&&i!==t.scrollTop?l:{}}},{key:"_wrapSizeGetter",value:function(e){return"function"==typeof e?e:function(){return e}}},{key:"_getCalculatedScrollLeft",value:function(e,t){var a=e.columnCount,i=e.height,l=e.scrollToAlignment,n=e.scrollToColumn,o=e.width,r=t.scrollLeft,s=t.instanceProps;if(a>0){var u=a-1,c=n<0?u:Math.min(u,n),g=s.rowSizeAndPositionManager.getTotalSize(),d=s.scrollbarSizeMeasured&&g>i?s.scrollbarSize:0;return s.columnSizeAndPositionManager.getUpdatedOffsetForIndex({align:l,containerSize:o-d,currentOffset:r,targetIndex:c})}return 0}},{key:"_getScrollLeftForScrollToColumnStateUpdate",value:function(e,a){var i=a.scrollLeft,l=t._getCalculatedScrollLeft(e,a);return"number"==typeof l&&l>=0&&i!==l?t._getScrollToPositionStateUpdate({prevState:a,scrollLeft:l,scrollTop:-1}):{}}},{key:"_getCalculatedScrollTop",value:function(e,t){var a=e.height,i=e.rowCount,l=e.scrollToAlignment,n=e.scrollToRow,o=e.width,r=t.scrollTop,s=t.instanceProps;if(i>0){var u=i-1,c=n<0?u:Math.min(u,n),g=s.columnSizeAndPositionManager.getTotalSize(),d=s.scrollbarSizeMeasured&&g>o?s.scrollbarSize:0;return s.rowSizeAndPositionManager.getUpdatedOffsetForIndex({align:l,containerSize:a-d,currentOffset:r,targetIndex:c})}return 0}},{key:"_getScrollTopForScrollToRowStateUpdate",value:function(e,a){var i=a.scrollTop,l=t._getCalculatedScrollTop(e,a);return"number"==typeof l&&l>=0&&i!==l?t._getScrollToPositionStateUpdate({prevState:a,scrollLeft:-1,scrollTop:l}):{}}}])}(w.PureComponent);ml(vn,"defaultProps",{"aria-label":"grid","aria-readonly":!0,autoContainerWidth:!1,autoHeight:!1,autoWidth:!1,cellRangeRenderer:function(e){for(var t=e.cellCache,a=e.cellRenderer,i=e.columnSizeAndPositionManager,l=e.columnStartIndex,n=e.columnStopIndex,o=e.deferredMeasurementCache,r=e.horizontalOffsetAdjustment,s=e.isScrolling,u=e.isScrollingOptOut,c=e.parent,g=e.rowSizeAndPositionManager,d=e.rowStartIndex,p=e.rowStopIndex,h=e.styleCache,m=e.verticalOffsetAdjustment,b=e.visibleColumnIndices,f=e.visibleRowIndices,v=[],w=i.areOffsetsAdjusted()||g.areOffsetsAdjusted(),x=!s&&!w,_=d;_<=p;_++)for(var k=g.getSizeAndPositionOfCell(_),S=l;S<=n;S++){var C=i.getSizeAndPositionOfCell(S),M=S>=b.start&&S<=b.stop&&_>=f.start&&_<=f.stop,T="".concat(_,"-").concat(S),E=void 0;x&&h[T]?E=h[T]:o&&!o.has(_,S)?E={height:"auto",left:0,position:"absolute",top:0,width:"auto"}:(E={height:k.size,left:C.offset+r,position:"absolute",top:k.offset+m,width:C.size},h[T]=E);var D={columnIndex:S,isScrolling:s,isVisible:M,key:T,parent:c,rowIndex:_,style:E},L=void 0;!u&&!s||r||m?L=a(D):(t[T]||(t[T]=a(D)),L=t[T]),null!=L&&!1!==L&&(L.props.role||(L=y().cloneElement(L,{role:"gridcell"})),v.push(L))}return v},containerRole:"row",containerStyle:{},estimatedColumnSize:100,estimatedRowSize:30,getScrollbarSize:Ol,noContentRenderer:function(){return null},onScroll:function(){},onScrollbarPresenceChange:function(){},onSectionRendered:function(){},overscanColumnCount:0,overscanIndicesGetter:function(e){var t=e.cellCount,a=e.overscanCellsCount,i=e.scrollDirection,l=e.startIndex,n=e.stopIndex;return 1===i?{overscanStartIndex:Math.max(0,l),overscanStopIndex:Math.min(t-1,n+a)}:{overscanStartIndex:Math.max(0,l-a),overscanStopIndex:Math.min(t-1,n)}},overscanRowCount:10,role:"grid",scrollingResetTimeInterval:150,scrollToAlignment:"auto",scrollToColumn:-1,scrollToRow:-1,style:{},tabIndex:0,isScrollingOptOut:!1}),(0,bl.polyfill)(vn);const wn=vn;function yn(e){var t=e.cellCount,a=e.overscanCellsCount,i=e.scrollDirection,l=e.startIndex,n=e.stopIndex;return a=Math.max(1,a),1===i?{overscanStartIndex:Math.max(0,l-1),overscanStopIndex:Math.min(t-1,n+a)}:{overscanStartIndex:Math.max(0,l-a),overscanStopIndex:Math.min(t-1,n+1)}}function xn(e,t){(null==t||t>e.length)&&(t=e.length);for(var a=0,i=Array(t);a<t;a++)i[a]=e[a];return i}function kn(e,t){if(e){if("string"==typeof e)return xn(e,t);var a={}.toString.call(e).slice(8,-1);return"Object"===a&&e.constructor&&(a=e.constructor.name),"Map"===a||"Set"===a?Array.from(e):"Arguments"===a||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(a)?xn(e,t):void 0}}function Sn(e,t,a){return t=dl(t),gl(e,Cn()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Cn(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Cn=function(){return!!e})()}var Mn=function(e){function t(e,a){var i;return ol(this,t),(i=Sn(this,t,[e,a]))._loadMoreRowsMemoizer=Rl(),i._onRowsRendered=i._onRowsRendered.bind(i),i._registerChild=i._registerChild.bind(i),i}return hl(t,e),cl(t,[{key:"resetLoadMoreRowsCache",value:function(e){this._loadMoreRowsMemoizer=Rl(),e&&this._doStuff(this._lastRenderedStartIndex,this._lastRenderedStopIndex)}},{key:"render",value:function(){return(0,this.props.children)({onRowsRendered:this._onRowsRendered,registerChild:this._registerChild})}},{key:"_loadUnloadedRanges",value:function(e){var t=this,a=this.props.loadMoreRows;e.forEach(function(e){var i=a(e);i&&i.then(function(){var a;(a={lastRenderedStartIndex:t._lastRenderedStartIndex,lastRenderedStopIndex:t._lastRenderedStopIndex,startIndex:e.startIndex,stopIndex:e.stopIndex}).startIndex>a.lastRenderedStopIndex||a.stopIndex<a.lastRenderedStartIndex||t._registeredChild&&function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,a="function"==typeof e.recomputeGridSize?e.recomputeGridSize:e.recomputeRowHeights;a?a.call(e,t):e.forceUpdate()}(t._registeredChild,t._lastRenderedStartIndex)})})}},{key:"_onRowsRendered",value:function(e){var t=e.startIndex,a=e.stopIndex;this._lastRenderedStartIndex=t,this._lastRenderedStopIndex=a,this._doStuff(t,a)}},{key:"_doStuff",value:function(e,t){var a,i=this,l=this.props,n=l.isRowLoaded,o=l.minimumBatchSize,r=l.rowCount,s=l.threshold,u=function(e){for(var t=e.isRowLoaded,a=e.minimumBatchSize,i=e.rowCount,l=e.stopIndex,n=[],o=null,r=null,s=e.startIndex;s<=l;s++)t({index:s})?null!==r&&(n.push({startIndex:o,stopIndex:r}),o=r=null):(r=s,null===o&&(o=s));if(null!==r){for(var u=Math.min(Math.max(r,o+a-1),i-1),c=r+1;c<=u&&!t({index:c});c++)r=c;n.push({startIndex:o,stopIndex:r})}if(n.length)for(var g=n[0];g.stopIndex-g.startIndex+1<a&&g.startIndex>0;){var d=g.startIndex-1;if(t({index:d}))break;g.startIndex=d}return n}({isRowLoaded:n,minimumBatchSize:o,rowCount:r,startIndex:Math.max(0,e-s),stopIndex:Math.min(r-1,t+s)}),c=(a=[]).concat.apply(a,function(e){return function(e){if(Array.isArray(e))return xn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||kn(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}(u.map(function(e){return[e.startIndex,e.stopIndex]})));this._loadMoreRowsMemoizer({callback:function(){i._loadUnloadedRanges(u)},indices:{squashedUnloadedRanges:c}})}},{key:"_registerChild",value:function(e){this._registeredChild=e}}])}(w.PureComponent);function Tn(e,t,a){return t=dl(t),gl(e,En()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function En(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(En=function(){return!!e})()}ml(Mn,"defaultProps",{minimumBatchSize:10,rowCount:0,threshold:15}),Mn.propTypes={};var Dn=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=Tn(this,t,[].concat(i)),"Grid",void 0),ml(e,"_cellRenderer",function(t){var a=t.parent,i=t.rowIndex,l=t.style,n=t.isScrolling,o=t.isVisible,r=t.key,s=e.props.rowRenderer,u=Object.getOwnPropertyDescriptor(l,"width");return u&&u.writable&&(l.width="100%"),s({index:i,style:l,isScrolling:n,isVisible:o,key:r,parent:a})}),ml(e,"_setRef",function(t){e.Grid=t}),ml(e,"_onScroll",function(t){var a=t.clientHeight,i=t.scrollHeight,l=t.scrollTop;(0,e.props.onScroll)({clientHeight:a,scrollHeight:i,scrollTop:l})}),ml(e,"_onSectionRendered",function(t){var a=t.rowOverscanStartIndex,i=t.rowOverscanStopIndex,l=t.rowStartIndex,n=t.rowStopIndex;(0,e.props.onRowsRendered)({overscanStartIndex:a,overscanStopIndex:i,startIndex:l,stopIndex:n})}),e}return hl(t,e),cl(t,[{key:"forceUpdateGrid",value:function(){this.Grid&&this.Grid.forceUpdate()}},{key:"getOffsetForRow",value:function(e){var t=e.alignment,a=e.index;return this.Grid?this.Grid.getOffsetForCell({alignment:t,rowIndex:a,columnIndex:0}).scrollTop:0}},{key:"invalidateCellSizeAfterRender",value:function(e){var t=e.columnIndex,a=e.rowIndex;this.Grid&&this.Grid.invalidateCellSizeAfterRender({rowIndex:a,columnIndex:t})}},{key:"measureAllRows",value:function(){this.Grid&&this.Grid.measureAllCells()}},{key:"recomputeGridSize",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.columnIndex,a=void 0===t?0:t,i=e.rowIndex,l=void 0===i?0:i;this.Grid&&this.Grid.recomputeGridSize({rowIndex:l,columnIndex:a})}},{key:"recomputeRowHeights",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.Grid&&this.Grid.recomputeGridSize({rowIndex:e,columnIndex:0})}},{key:"scrollToPosition",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.Grid&&this.Grid.scrollToPosition({scrollTop:e})}},{key:"scrollToRow",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.Grid&&this.Grid.scrollToCell({columnIndex:0,rowIndex:e})}},{key:"render",value:function(){var e=this.props,t=e.className,a=e.noRowsRenderer,i=e.scrollToIndex,l=e.width,n=Al("ReactVirtualized__List",t);return w.createElement(wn,Bl({},this.props,{autoContainerWidth:!0,cellRenderer:this._cellRenderer,className:n,columnWidth:l,columnCount:1,noContentRenderer:a,onScroll:this._onScroll,onSectionRendered:this._onSectionRendered,ref:this._setRef,scrollToRow:i}))}}])}(w.PureComponent);ml(Dn,"defaultProps",{autoHeight:!1,estimatedRowSize:30,onScroll:function(){},noRowsRenderer:function(){return null},onRowsRendered:function(){},overscanIndicesGetter:yn,overscanRowCount:10,scrollToAlignment:"auto",scrollToIndex:-1,style:{}});const Ln=function(e,t,a,i,l){return"function"==typeof a?function(e,t,a,i,l){for(var n=a+1;t<=a;){var o=t+a>>>1;l(e[o],i)>=0?(n=o,a=o-1):t=o+1}return n}(e,void 0===i?0:0|i,void 0===l?e.length-1:0|l,t,a):function(e,t,a,i){for(var l=a+1;t<=a;){var n=t+a>>>1;e[n]>=i?(l=n,a=n-1):t=n+1}return l}(e,void 0===a?0:0|a,void 0===i?e.length-1:0|i,t)};function Bn(e,t,a,i,l){this.mid=e,this.left=t,this.right=a,this.leftPoints=i,this.rightPoints=l,this.count=(t?t.count:0)+(a?a.count:0)+i.length}var Hn=Bn.prototype;function An(e,t){e.mid=t.mid,e.left=t.left,e.right=t.right,e.leftPoints=t.leftPoints,e.rightPoints=t.rightPoints,e.count=t.count}function Rn(e,t){var a=Wn(t);e.mid=a.mid,e.left=a.left,e.right=a.right,e.leftPoints=a.leftPoints,e.rightPoints=a.rightPoints,e.count=a.count}function Pn(e,t){var a=e.intervals([]);a.push(t),Rn(e,a)}function zn(e,t){var a=e.intervals([]),i=a.indexOf(t);return i<0?0:(a.splice(i,1),Rn(e,a),1)}function On(e,t,a){for(var i=0;i<e.length&&e[i][0]<=t;++i){var l=a(e[i]);if(l)return l}}function Fn(e,t,a){for(var i=e.length-1;i>=0&&e[i][1]>=t;--i){var l=a(e[i]);if(l)return l}}function In(e,t){for(var a=0;a<e.length;++a){var i=t(e[a]);if(i)return i}}function Nn(e,t){return e-t}function Vn(e,t){return e[0]-t[0]||e[1]-t[1]}function Gn(e,t){return e[1]-t[1]||e[0]-t[0]}function Wn(e){if(0===e.length)return null;for(var t=[],a=0;a<e.length;++a)t.push(e[a][0],e[a][1]);t.sort(Nn);var i=t[t.length>>1],l=[],n=[],o=[];for(a=0;a<e.length;++a){var r=e[a];r[1]<i?l.push(r):i<r[0]?n.push(r):o.push(r)}var s=o,u=o.slice();return s.sort(Vn),u.sort(Gn),new Bn(i,Wn(l),Wn(n),s,u)}function Un(e){this.root=e}Hn.intervals=function(e){return e.push.apply(e,this.leftPoints),this.left&&this.left.intervals(e),this.right&&this.right.intervals(e),e},Hn.insert=function(e){var t=this.count-this.leftPoints.length;if(this.count+=1,e[1]<this.mid)this.left?4*(this.left.count+1)>3*(t+1)?Pn(this,e):this.left.insert(e):this.left=Wn([e]);else if(e[0]>this.mid)this.right?4*(this.right.count+1)>3*(t+1)?Pn(this,e):this.right.insert(e):this.right=Wn([e]);else{var a=Ln(this.leftPoints,e,Vn),i=Ln(this.rightPoints,e,Gn);this.leftPoints.splice(a,0,e),this.rightPoints.splice(i,0,e)}},Hn.remove=function(e){var t=this.count-this.leftPoints;if(e[1]<this.mid)return this.left?4*(this.right?this.right.count:0)>3*(t-1)?zn(this,e):2===(n=this.left.remove(e))?(this.left=null,this.count-=1,1):(1===n&&(this.count-=1),n):0;if(e[0]>this.mid)return this.right?4*(this.left?this.left.count:0)>3*(t-1)?zn(this,e):2===(n=this.right.remove(e))?(this.right=null,this.count-=1,1):(1===n&&(this.count-=1),n):0;if(1===this.count)return this.leftPoints[0]===e?2:0;if(1===this.leftPoints.length&&this.leftPoints[0]===e){if(this.left&&this.right){for(var a=this,i=this.left;i.right;)a=i,i=i.right;if(a===this)i.right=this.right;else{var l=this.left,n=this.right;a.count-=i.count,a.right=i.left,i.left=l,i.right=n}An(this,i),this.count=(this.left?this.left.count:0)+(this.right?this.right.count:0)+this.leftPoints.length}else this.left?An(this,this.left):An(this,this.right);return 1}for(l=Ln(this.leftPoints,e,Vn);l<this.leftPoints.length&&this.leftPoints[l][0]===e[0];++l)if(this.leftPoints[l]===e)for(this.count-=1,this.leftPoints.splice(l,1),n=Ln(this.rightPoints,e,Gn);n<this.rightPoints.length&&this.rightPoints[n][1]===e[1];++n)if(this.rightPoints[n]===e)return this.rightPoints.splice(n,1),1;return 0},Hn.queryPoint=function(e,t){return e<this.mid?this.left&&(a=this.left.queryPoint(e,t))?a:On(this.leftPoints,e,t):e>this.mid?this.right&&(a=this.right.queryPoint(e,t))?a:Fn(this.rightPoints,e,t):In(this.leftPoints,t);var a},Hn.queryInterval=function(e,t,a){var i;return e<this.mid&&this.left&&(i=this.left.queryInterval(e,t,a))||t>this.mid&&this.right&&(i=this.right.queryInterval(e,t,a))?i:t<this.mid?On(this.leftPoints,t,a):e>this.mid?Fn(this.rightPoints,e,a):In(this.leftPoints,a)};var jn=Un.prototype;jn.insert=function(e){this.root?this.root.insert(e):this.root=new Bn(e[0],null,null,[e],[e])},jn.remove=function(e){if(this.root){var t=this.root.remove(e);return 2===t&&(this.root=null),0!==t}return!1},jn.queryPoint=function(e,t){if(this.root)return this.root.queryPoint(e,t)},jn.queryInterval=function(e,t,a){if(e<=t&&this.root)return this.root.queryInterval(e,t,a)},Object.defineProperty(jn,"count",{get:function(){return this.root?this.root.count:0}}),Object.defineProperty(jn,"intervals",{get:function(){return this.root?this.root.intervals([]):[]}});var qn=function(){return cl(function e(){ol(this,e),ml(this,"_columnSizeMap",{}),ml(this,"_intervalTree",new Un(null)),ml(this,"_leftMap",{})},[{key:"estimateTotalHeight",value:function(e,t,a){var i=e-this.count;return this.tallestColumnSize+Math.ceil(i/t)*a}},{key:"range",value:function(e,t,a){var i=this;this._intervalTree.queryInterval(e,e+t,function(e){var t=function(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var a=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=a){var i,l,n,o,r=[],s=!0,u=!1;try{if(n=(a=a.call(e)).next,0===t){if(Object(a)!==a)return;s=!1}else for(;!(s=(i=n.call(a)).done)&&(r.push(i.value),r.length!==t);s=!0);}catch(e){u=!0,l=e}finally{try{if(!s&&null!=a.return&&(o=a.return(),Object(o)!==o))return}finally{if(u)throw l}}return r}}(e,t)||kn(e,t)||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.")}()}(e,3),l=t[0],n=(t[1],t[2]);return a(n,i._leftMap[n],l)})}},{key:"setPosition",value:function(e,t,a,i){this._intervalTree.insert([a,a+i,e]),this._leftMap[e]=t;var l=this._columnSizeMap,n=l[t];l[t]=void 0===n?a+i:Math.max(n,a+i)}},{key:"count",get:function(){return this._intervalTree.count}},{key:"shortestColumnSize",get:function(){var e=this._columnSizeMap,t=0;for(var a in e){var i=e[a];t=0===t?i:Math.min(t,i)}return t}},{key:"tallestColumnSize",get:function(){var e=this._columnSizeMap,t=0;for(var a in e){var i=e[a];t=Math.max(t,i)}return t}}])}();function $n(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function Zn(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?$n(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):$n(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function Kn(e,t,a){return t=dl(t),gl(e,Yn()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Yn(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Yn=function(){return!!e})()}var Jn=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=Kn(this,t,[].concat(i)),"state",{isScrolling:!1,scrollTop:0}),ml(e,"_debounceResetIsScrollingId",void 0),ml(e,"_invalidateOnUpdateStartIndex",null),ml(e,"_invalidateOnUpdateStopIndex",null),ml(e,"_positionCache",new qn),ml(e,"_startIndex",null),ml(e,"_startIndexMemoized",null),ml(e,"_stopIndex",null),ml(e,"_stopIndexMemoized",null),ml(e,"_debounceResetIsScrollingCallback",function(){e.setState({isScrolling:!1})}),ml(e,"_setScrollingContainerRef",function(t){e._scrollingContainer=t}),ml(e,"_onScroll",function(t){var a=e.props.height,i=t.currentTarget.scrollTop,l=Math.min(Math.max(0,e._getEstimatedTotalHeight()-a),i);i===l&&(e._debounceResetIsScrolling(),e.state.scrollTop!==l&&e.setState({isScrolling:!0,scrollTop:l}))}),e}return hl(t,e),cl(t,[{key:"clearCellPositions",value:function(){this._positionCache=new qn,this.forceUpdate()}},{key:"invalidateCellSizeAfterRender",value:function(e){var t=e.rowIndex;null===this._invalidateOnUpdateStartIndex?(this._invalidateOnUpdateStartIndex=t,this._invalidateOnUpdateStopIndex=t):(this._invalidateOnUpdateStartIndex=Math.min(this._invalidateOnUpdateStartIndex,t),this._invalidateOnUpdateStopIndex=Math.max(this._invalidateOnUpdateStopIndex,t))}},{key:"recomputeCellPositions",value:function(){var e=this._positionCache.count-1;this._positionCache=new qn,this._populatePositionCache(0,e),this.forceUpdate()}},{key:"componentDidMount",value:function(){this._checkInvalidateOnUpdate(),this._invokeOnScrollCallback(),this._invokeOnCellsRenderedCallback()}},{key:"componentDidUpdate",value:function(e,t){this._checkInvalidateOnUpdate(),this._invokeOnScrollCallback(),this._invokeOnCellsRenderedCallback(),this.props.scrollTop!==e.scrollTop&&this._debounceResetIsScrolling()}},{key:"componentWillUnmount",value:function(){this._debounceResetIsScrollingId&&gn(this._debounceResetIsScrollingId)}},{key:"render",value:function(){var e,t=this,a=this.props,i=a.autoHeight,l=a.cellCount,n=a.cellMeasurerCache,o=a.cellRenderer,r=a.className,s=a.height,u=a.id,c=a.keyMapper,g=a.overscanByPixels,d=a.role,p=a.style,h=a.tabIndex,m=a.width,b=a.rowDirection,f=this.state,v=f.isScrolling,y=f.scrollTop,x=[],_=this._getEstimatedTotalHeight(),k=this._positionCache.shortestColumnSize,S=this._positionCache.count,C=0;if(this._positionCache.range(Math.max(0,y-g),s+2*g,function(a,i,l){void 0===e?(C=a,e=a):(C=Math.min(C,a),e=Math.max(e,a)),x.push(o({index:a,isScrolling:v,key:c(a),parent:t,style:ml(ml(ml(ml({height:n.getHeight(a)},"ltr"===b?"left":"right",i),"position","absolute"),"top",l),"width",n.getWidth(a))}))}),k<y+s+g&&S<l)for(var M=Math.min(l-S,Math.ceil((y+s+g-k)/n.defaultHeight*m/n.defaultWidth)),T=S;T<S+M;T++)e=T,x.push(o({index:T,isScrolling:v,key:c(T),parent:this,style:{width:n.getWidth(T)}}));return this._startIndex=C,this._stopIndex=e,w.createElement("div",{ref:this._setScrollingContainerRef,"aria-label":this.props["aria-label"],className:Al("ReactVirtualized__Masonry",r),id:u,onScroll:this._onScroll,role:d,style:Zn({boxSizing:"border-box",direction:"ltr",height:i?"auto":s,overflowX:"hidden",overflowY:_<s?"hidden":"auto",position:"relative",width:m,WebkitOverflowScrolling:"touch",willChange:"transform"},p),tabIndex:h},w.createElement("div",{className:"ReactVirtualized__Masonry__innerScrollContainer",style:{width:"100%",height:_,maxWidth:"100%",maxHeight:_,overflow:"hidden",pointerEvents:v?"none":"",position:"relative"}},x))}},{key:"_checkInvalidateOnUpdate",value:function(){if("number"==typeof this._invalidateOnUpdateStartIndex){var e=this._invalidateOnUpdateStartIndex,t=this._invalidateOnUpdateStopIndex;this._invalidateOnUpdateStartIndex=null,this._invalidateOnUpdateStopIndex=null,this._populatePositionCache(e,t),this.forceUpdate()}}},{key:"_debounceResetIsScrolling",value:function(){var e=this.props.scrollingResetTimeInterval;this._debounceResetIsScrollingId&&gn(this._debounceResetIsScrollingId),this._debounceResetIsScrollingId=dn(this._debounceResetIsScrollingCallback,e)}},{key:"_getEstimatedTotalHeight",value:function(){var e=this.props,t=e.cellCount,a=e.cellMeasurerCache,i=e.width,l=Math.max(1,Math.floor(i/a.defaultWidth));return this._positionCache.estimateTotalHeight(t,l,a.defaultHeight)}},{key:"_invokeOnScrollCallback",value:function(){var e=this.props,t=e.height,a=e.onScroll,i=this.state.scrollTop;this._onScrollMemoized!==i&&(a({clientHeight:t,scrollHeight:this._getEstimatedTotalHeight(),scrollTop:i}),this._onScrollMemoized=i)}},{key:"_invokeOnCellsRenderedCallback",value:function(){this._startIndexMemoized===this._startIndex&&this._stopIndexMemoized===this._stopIndex||((0,this.props.onCellsRendered)({startIndex:this._startIndex,stopIndex:this._stopIndex}),this._startIndexMemoized=this._startIndex,this._stopIndexMemoized=this._stopIndex)}},{key:"_populatePositionCache",value:function(e,t){for(var a=this.props,i=a.cellMeasurerCache,l=a.cellPositioner,n=e;n<=t;n++){var o=l(n),r=o.left,s=o.top;this._positionCache.setPosition(n,r,s,i.getHeight(n))}}}],[{key:"getDerivedStateFromProps",value:function(e,t){return void 0!==e.scrollTop&&t.scrollTop!==e.scrollTop?{isScrolling:!0,scrollTop:e.scrollTop}:null}}])}(w.PureComponent);function Xn(){}ml(Jn,"defaultProps",{autoHeight:!1,keyMapper:function(e){return e},onCellsRendered:Xn,onScroll:Xn,overscanByPixels:20,role:"grid",scrollingResetTimeInterval:150,style:{},tabIndex:0,rowDirection:"ltr"}),(0,bl.polyfill)(Jn);var Qn=function(){return cl(function e(){var t=this,a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};ol(this,e),ml(this,"_cellMeasurerCache",void 0),ml(this,"_columnIndexOffset",void 0),ml(this,"_rowIndexOffset",void 0),ml(this,"columnWidth",function(e){var a=e.index;t._cellMeasurerCache.columnWidth({index:a+t._columnIndexOffset})}),ml(this,"rowHeight",function(e){var a=e.index;t._cellMeasurerCache.rowHeight({index:a+t._rowIndexOffset})});var i=a.cellMeasurerCache,l=a.columnIndexOffset,n=void 0===l?0:l,o=a.rowIndexOffset,r=void 0===o?0:o;this._cellMeasurerCache=i,this._columnIndexOffset=n,this._rowIndexOffset=r},[{key:"clear",value:function(e,t){this._cellMeasurerCache.clear(e+this._rowIndexOffset,t+this._columnIndexOffset)}},{key:"clearAll",value:function(){this._cellMeasurerCache.clearAll()}},{key:"defaultHeight",get:function(){return this._cellMeasurerCache.defaultHeight}},{key:"defaultWidth",get:function(){return this._cellMeasurerCache.defaultWidth}},{key:"hasFixedHeight",value:function(){return this._cellMeasurerCache.hasFixedHeight()}},{key:"hasFixedWidth",value:function(){return this._cellMeasurerCache.hasFixedWidth()}},{key:"getHeight",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return this._cellMeasurerCache.getHeight(e+this._rowIndexOffset,t+this._columnIndexOffset)}},{key:"getWidth",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return this._cellMeasurerCache.getWidth(e+this._rowIndexOffset,t+this._columnIndexOffset)}},{key:"has",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return this._cellMeasurerCache.has(e+this._rowIndexOffset,t+this._columnIndexOffset)}},{key:"set",value:function(e,t,a,i){this._cellMeasurerCache.set(e+this._rowIndexOffset,t+this._columnIndexOffset,a,i)}}])}(),eo=["rowIndex"],to=["columnIndex","rowIndex"],ao=["columnIndex"],io=["onScroll","onSectionRendered","onScrollbarPresenceChange","scrollLeft","scrollToColumn","scrollTop","scrollToRow"];function lo(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function no(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?lo(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):lo(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function oo(e,t,a){return t=dl(t),gl(e,ro()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function ro(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(ro=function(){return!!e})()}var so=function(e){function t(e,a){var i;ol(this,t),ml(i=oo(this,t,[e,a]),"state",{scrollLeft:0,scrollTop:0,scrollbarSize:0,showHorizontalScrollbar:!1,showVerticalScrollbar:!1}),ml(i,"_deferredInvalidateColumnIndex",null),ml(i,"_deferredInvalidateRowIndex",null),ml(i,"_bottomLeftGridRef",function(e){i._bottomLeftGrid=e}),ml(i,"_bottomRightGridRef",function(e){i._bottomRightGrid=e}),ml(i,"_cellRendererBottomLeftGrid",function(e){var t=e.rowIndex,a=en(e,eo),l=i.props,n=l.cellRenderer,o=l.fixedRowCount;return t===l.rowCount-o?w.createElement("div",{key:a.key,style:no(no({},a.style),{},{height:20})}):n(no(no({},a),{},{parent:i,rowIndex:t+o}))}),ml(i,"_cellRendererBottomRightGrid",function(e){var t=e.columnIndex,a=e.rowIndex,l=en(e,to),n=i.props,o=n.cellRenderer,r=n.fixedColumnCount,s=n.fixedRowCount;return o(no(no({},l),{},{columnIndex:t+r,parent:i,rowIndex:a+s}))}),ml(i,"_cellRendererTopRightGrid",function(e){var t=e.columnIndex,a=en(e,ao),l=i.props,n=l.cellRenderer,o=l.columnCount,r=l.fixedColumnCount;return t===o-r?w.createElement("div",{key:a.key,style:no(no({},a.style),{},{width:20})}):n(no(no({},a),{},{columnIndex:t+r,parent:i}))}),ml(i,"_columnWidthRightGrid",function(e){var t=e.index,a=i.props,l=a.columnCount,n=a.fixedColumnCount,o=a.columnWidth,r=i.state,s=r.scrollbarSize;return r.showHorizontalScrollbar&&t===l-n?s:"function"==typeof o?o({index:t+n}):o}),ml(i,"_onScroll",function(e){var t=e.scrollLeft,a=e.scrollTop;i.setState({scrollLeft:t,scrollTop:a});var l=i.props.onScroll;l&&l(e)}),ml(i,"_onScrollbarPresenceChange",function(e){var t=e.horizontal,a=e.size,l=e.vertical,n=i.state,o=n.showHorizontalScrollbar,r=n.showVerticalScrollbar;if(t!==o||l!==r){i.setState({scrollbarSize:a,showHorizontalScrollbar:t,showVerticalScrollbar:l});var s=i.props.onScrollbarPresenceChange;"function"==typeof s&&s({horizontal:t,size:a,vertical:l})}}),ml(i,"_onScrollLeft",function(e){var t=e.scrollLeft;i._onScroll({scrollLeft:t,scrollTop:i.state.scrollTop})}),ml(i,"_onScrollTop",function(e){var t=e.scrollTop;i._onScroll({scrollTop:t,scrollLeft:i.state.scrollLeft})}),ml(i,"_rowHeightBottomGrid",function(e){var t=e.index,a=i.props,l=a.fixedRowCount,n=a.rowCount,o=a.rowHeight,r=i.state,s=r.scrollbarSize;return r.showVerticalScrollbar&&t===n-l?s:"function"==typeof o?o({index:t+l}):o}),ml(i,"_topLeftGridRef",function(e){i._topLeftGrid=e}),ml(i,"_topRightGridRef",function(e){i._topRightGrid=e});var l=e.deferredMeasurementCache,n=e.fixedColumnCount,o=e.fixedRowCount;return i._maybeCalculateCachedStyles(!0),l&&(i._deferredMeasurementCacheBottomLeftGrid=o>0?new Qn({cellMeasurerCache:l,columnIndexOffset:0,rowIndexOffset:o}):l,i._deferredMeasurementCacheBottomRightGrid=n>0||o>0?new Qn({cellMeasurerCache:l,columnIndexOffset:n,rowIndexOffset:o}):l,i._deferredMeasurementCacheTopRightGrid=n>0?new Qn({cellMeasurerCache:l,columnIndexOffset:n,rowIndexOffset:0}):l),i}return hl(t,e),cl(t,[{key:"forceUpdateGrids",value:function(){this._bottomLeftGrid&&this._bottomLeftGrid.forceUpdate(),this._bottomRightGrid&&this._bottomRightGrid.forceUpdate(),this._topLeftGrid&&this._topLeftGrid.forceUpdate(),this._topRightGrid&&this._topRightGrid.forceUpdate()}},{key:"invalidateCellSizeAfterRender",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.columnIndex,a=void 0===t?0:t,i=e.rowIndex,l=void 0===i?0:i;this._deferredInvalidateColumnIndex="number"==typeof this._deferredInvalidateColumnIndex?Math.min(this._deferredInvalidateColumnIndex,a):a,this._deferredInvalidateRowIndex="number"==typeof this._deferredInvalidateRowIndex?Math.min(this._deferredInvalidateRowIndex,l):l}},{key:"measureAllCells",value:function(){this._bottomLeftGrid&&this._bottomLeftGrid.measureAllCells(),this._bottomRightGrid&&this._bottomRightGrid.measureAllCells(),this._topLeftGrid&&this._topLeftGrid.measureAllCells(),this._topRightGrid&&this._topRightGrid.measureAllCells()}},{key:"recomputeGridSize",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.columnIndex,a=void 0===t?0:t,i=e.rowIndex,l=void 0===i?0:i,n=this.props,o=n.fixedColumnCount,r=n.fixedRowCount,s=Math.max(0,a-o),u=Math.max(0,l-r);this._bottomLeftGrid&&this._bottomLeftGrid.recomputeGridSize({columnIndex:a,rowIndex:u}),this._bottomRightGrid&&this._bottomRightGrid.recomputeGridSize({columnIndex:s,rowIndex:u}),this._topLeftGrid&&this._topLeftGrid.recomputeGridSize({columnIndex:a,rowIndex:l}),this._topRightGrid&&this._topRightGrid.recomputeGridSize({columnIndex:s,rowIndex:l}),this._leftGridWidth=null,this._topGridHeight=null,this._maybeCalculateCachedStyles(!0)}},{key:"componentDidMount",value:function(){var e=this.props,t=e.scrollLeft,a=e.scrollTop;if(t>0||a>0){var i={};t>0&&(i.scrollLeft=t),a>0&&(i.scrollTop=a),this.setState(i)}this._handleInvalidatedGridSize()}},{key:"componentDidUpdate",value:function(){this._handleInvalidatedGridSize()}},{key:"render",value:function(){var e=this.props,t=e.onScroll,a=e.onSectionRendered,i=(e.onScrollbarPresenceChange,e.scrollLeft,e.scrollToColumn),l=(e.scrollTop,e.scrollToRow),n=en(e,io);if(this._prepareForRender(),0===this.props.width||0===this.props.height)return null;var o=this.state,r=o.scrollLeft,s=o.scrollTop;return w.createElement("div",{style:this._containerOuterStyle},w.createElement("div",{style:this._containerTopStyle},this._renderTopLeftGrid(n),this._renderTopRightGrid(no(no({},n),{},{onScroll:t,scrollLeft:r}))),w.createElement("div",{style:this._containerBottomStyle},this._renderBottomLeftGrid(no(no({},n),{},{onScroll:t,scrollTop:s})),this._renderBottomRightGrid(no(no({},n),{},{onScroll:t,onSectionRendered:a,scrollLeft:r,scrollToColumn:i,scrollToRow:l,scrollTop:s}))))}},{key:"_getBottomGridHeight",value:function(e){return e.height-this._getTopGridHeight(e)}},{key:"_getLeftGridWidth",value:function(e){var t=e.fixedColumnCount,a=e.columnWidth;if(null==this._leftGridWidth)if("function"==typeof a){for(var i=0,l=0;l<t;l++)i+=a({index:l});this._leftGridWidth=i}else this._leftGridWidth=a*t;return this._leftGridWidth}},{key:"_getRightGridWidth",value:function(e){return e.width-this._getLeftGridWidth(e)}},{key:"_getTopGridHeight",value:function(e){var t=e.fixedRowCount,a=e.rowHeight;if(null==this._topGridHeight)if("function"==typeof a){for(var i=0,l=0;l<t;l++)i+=a({index:l});this._topGridHeight=i}else this._topGridHeight=a*t;return this._topGridHeight}},{key:"_handleInvalidatedGridSize",value:function(){if("number"==typeof this._deferredInvalidateColumnIndex){var e=this._deferredInvalidateColumnIndex,t=this._deferredInvalidateRowIndex;this._deferredInvalidateColumnIndex=null,this._deferredInvalidateRowIndex=null,this.recomputeGridSize({columnIndex:e,rowIndex:t}),this.forceUpdate()}}},{key:"_maybeCalculateCachedStyles",value:function(e){var t=this.props,a=t.columnWidth,i=t.enableFixedColumnScroll,l=t.enableFixedRowScroll,n=t.height,o=t.fixedColumnCount,r=t.fixedRowCount,s=t.rowHeight,u=t.style,c=t.styleBottomLeftGrid,g=t.styleBottomRightGrid,d=t.styleTopLeftGrid,p=t.styleTopRightGrid,h=t.width,m=e||n!==this._lastRenderedHeight||h!==this._lastRenderedWidth,b=e||a!==this._lastRenderedColumnWidth||o!==this._lastRenderedFixedColumnCount,f=e||r!==this._lastRenderedFixedRowCount||s!==this._lastRenderedRowHeight;(e||m||u!==this._lastRenderedStyle)&&(this._containerOuterStyle=no({height:n,overflow:"visible",width:h},u)),(e||m||f)&&(this._containerTopStyle={height:this._getTopGridHeight(this.props),position:"relative",width:h},this._containerBottomStyle={height:n-this._getTopGridHeight(this.props),overflow:"visible",position:"relative",width:h}),(e||c!==this._lastRenderedStyleBottomLeftGrid)&&(this._bottomLeftGridStyle=no({left:0,overflowX:"hidden",overflowY:i?"auto":"hidden",position:"absolute"},c)),(e||b||g!==this._lastRenderedStyleBottomRightGrid)&&(this._bottomRightGridStyle=no({left:this._getLeftGridWidth(this.props),position:"absolute"},g)),(e||d!==this._lastRenderedStyleTopLeftGrid)&&(this._topLeftGridStyle=no({left:0,overflowX:"hidden",overflowY:"hidden",position:"absolute",top:0},d)),(e||b||p!==this._lastRenderedStyleTopRightGrid)&&(this._topRightGridStyle=no({left:this._getLeftGridWidth(this.props),overflowX:l?"auto":"hidden",overflowY:"hidden",position:"absolute",top:0},p)),this._lastRenderedColumnWidth=a,this._lastRenderedFixedColumnCount=o,this._lastRenderedFixedRowCount=r,this._lastRenderedHeight=n,this._lastRenderedRowHeight=s,this._lastRenderedStyle=u,this._lastRenderedStyleBottomLeftGrid=c,this._lastRenderedStyleBottomRightGrid=g,this._lastRenderedStyleTopLeftGrid=d,this._lastRenderedStyleTopRightGrid=p,this._lastRenderedWidth=h}},{key:"_prepareForRender",value:function(){this._lastRenderedColumnWidth===this.props.columnWidth&&this._lastRenderedFixedColumnCount===this.props.fixedColumnCount||(this._leftGridWidth=null),this._lastRenderedFixedRowCount===this.props.fixedRowCount&&this._lastRenderedRowHeight===this.props.rowHeight||(this._topGridHeight=null),this._maybeCalculateCachedStyles(),this._lastRenderedColumnWidth=this.props.columnWidth,this._lastRenderedFixedColumnCount=this.props.fixedColumnCount,this._lastRenderedFixedRowCount=this.props.fixedRowCount,this._lastRenderedRowHeight=this.props.rowHeight}},{key:"_renderBottomLeftGrid",value:function(e){var t=e.enableFixedColumnScroll,a=e.fixedColumnCount,i=e.fixedRowCount,l=e.rowCount,n=e.hideBottomLeftGridScrollbar,o=this.state.showVerticalScrollbar;if(!a)return null;var r=o?1:0,s=this._getBottomGridHeight(e),u=this._getLeftGridWidth(e),c=this.state.showVerticalScrollbar?this.state.scrollbarSize:0,g=n?u+c:u,d=w.createElement(wn,Bl({},e,{cellRenderer:this._cellRendererBottomLeftGrid,className:this.props.classNameBottomLeftGrid,columnCount:a,deferredMeasurementCache:this._deferredMeasurementCacheBottomLeftGrid,height:s,onScroll:t?this._onScrollTop:void 0,ref:this._bottomLeftGridRef,rowCount:Math.max(0,l-i)+r,rowHeight:this._rowHeightBottomGrid,style:this._bottomLeftGridStyle,tabIndex:null,width:g}));return n?w.createElement("div",{className:"BottomLeftGrid_ScrollWrapper",style:no(no({},this._bottomLeftGridStyle),{},{height:s,width:u,overflowY:"hidden"})},d):d}},{key:"_renderBottomRightGrid",value:function(e){var t=e.columnCount,a=e.fixedColumnCount,i=e.fixedRowCount,l=e.rowCount,n=e.scrollToColumn,o=e.scrollToRow;return w.createElement(wn,Bl({},e,{cellRenderer:this._cellRendererBottomRightGrid,className:this.props.classNameBottomRightGrid,columnCount:Math.max(0,t-a),columnWidth:this._columnWidthRightGrid,deferredMeasurementCache:this._deferredMeasurementCacheBottomRightGrid,height:this._getBottomGridHeight(e),onScroll:this._onScroll,onScrollbarPresenceChange:this._onScrollbarPresenceChange,ref:this._bottomRightGridRef,rowCount:Math.max(0,l-i),rowHeight:this._rowHeightBottomGrid,scrollToColumn:n-a,scrollToRow:o-i,style:this._bottomRightGridStyle,width:this._getRightGridWidth(e)}))}},{key:"_renderTopLeftGrid",value:function(e){var t=e.fixedColumnCount,a=e.fixedRowCount;return t&&a?w.createElement(wn,Bl({},e,{className:this.props.classNameTopLeftGrid,columnCount:t,height:this._getTopGridHeight(e),ref:this._topLeftGridRef,rowCount:a,style:this._topLeftGridStyle,tabIndex:null,width:this._getLeftGridWidth(e)})):null}},{key:"_renderTopRightGrid",value:function(e){var t=e.columnCount,a=e.enableFixedRowScroll,i=e.fixedColumnCount,l=e.fixedRowCount,n=e.scrollLeft,o=e.hideTopRightGridScrollbar,r=this.state,s=r.showHorizontalScrollbar,u=r.scrollbarSize;if(!l)return null;var c=s?1:0,g=this._getTopGridHeight(e),d=this._getRightGridWidth(e),p=s?u:0,h=g,m=this._topRightGridStyle;o&&(h=g+p,m=no(no({},this._topRightGridStyle),{},{left:0}));var b=w.createElement(wn,Bl({},e,{cellRenderer:this._cellRendererTopRightGrid,className:this.props.classNameTopRightGrid,columnCount:Math.max(0,t-i)+c,columnWidth:this._columnWidthRightGrid,deferredMeasurementCache:this._deferredMeasurementCacheTopRightGrid,height:h,onScroll:a?this._onScrollLeft:void 0,ref:this._topRightGridRef,rowCount:l,scrollLeft:n,style:m,tabIndex:null,width:d}));return o?w.createElement("div",{className:"TopRightGrid_ScrollWrapper",style:no(no({},this._topRightGridStyle),{},{height:g,width:d,overflowX:"hidden"})},b):b}}],[{key:"getDerivedStateFromProps",value:function(e,t){return e.scrollLeft!==t.scrollLeft||e.scrollTop!==t.scrollTop?{scrollLeft:null!=e.scrollLeft&&e.scrollLeft>=0?e.scrollLeft:t.scrollLeft,scrollTop:null!=e.scrollTop&&e.scrollTop>=0?e.scrollTop:t.scrollTop}:null}}])}(w.PureComponent);function uo(e,t,a){return t=dl(t),gl(e,co()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function co(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(co=function(){return!!e})()}ml(so,"defaultProps",{classNameBottomLeftGrid:"",classNameBottomRightGrid:"",classNameTopLeftGrid:"",classNameTopRightGrid:"",enableFixedColumnScroll:!1,enableFixedRowScroll:!1,fixedColumnCount:0,fixedRowCount:0,scrollToColumn:-1,scrollToRow:-1,style:{},styleBottomLeftGrid:{},styleBottomRightGrid:{},styleTopLeftGrid:{},styleTopRightGrid:{},hideTopRightGridScrollbar:!1,hideBottomLeftGridScrollbar:!1}),so.propTypes={},(0,bl.polyfill)(so),(function(e){function t(e,a){var i;return ol(this,t),(i=uo(this,t,[e,a])).state={clientHeight:0,clientWidth:0,scrollHeight:0,scrollLeft:0,scrollTop:0,scrollWidth:0},i._onScroll=i._onScroll.bind(i),i}return hl(t,e),cl(t,[{key:"render",value:function(){var e=this.props.children,t=this.state,a=t.clientHeight,i=t.clientWidth,l=t.scrollHeight,n=t.scrollLeft,o=t.scrollTop,r=t.scrollWidth;return e({clientHeight:a,clientWidth:i,onScroll:this._onScroll,scrollHeight:l,scrollLeft:n,scrollTop:o,scrollWidth:r})}},{key:"_onScroll",value:function(e){var t=e.clientHeight,a=e.clientWidth,i=e.scrollHeight,l=e.scrollLeft,n=e.scrollTop,o=e.scrollWidth;this.setState({clientHeight:t,clientWidth:a,scrollHeight:i,scrollLeft:l,scrollTop:n,scrollWidth:o})}}])}(w.PureComponent)).propTypes={};const go="ASC",po="DESC";function ho(e){var t=e.sortDirection,a=Al("ReactVirtualized__Table__sortableHeaderIcon",{"ReactVirtualized__Table__sortableHeaderIcon--ASC":t===go,"ReactVirtualized__Table__sortableHeaderIcon--DESC":t===po});return w.createElement("svg",{className:a,width:18,height:18,viewBox:"0 0 24 24"},t===go?w.createElement("path",{d:"M7 14l5-5 5 5z"}):w.createElement("path",{d:"M7 10l5 5 5-5z"}),w.createElement("path",{d:"M0 0h24v24H0z",fill:"none"}))}function mo(e,t,a){return t=dl(t),gl(e,bo()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function bo(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(bo=function(){return!!e})()}ho.propTypes={};var fo=function(e){function t(){return ol(this,t),mo(this,t,arguments)}return hl(t,e),cl(t)}(w.Component);function vo(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function wo(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?vo(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):vo(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function yo(e,t,a){return t=dl(t),gl(e,xo()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function xo(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(xo=function(){return!!e})()}ml(fo,"defaultProps",{cellDataGetter:function(e){var t=e.dataKey,a=e.rowData;return"function"==typeof a.get?a.get(t):a[t]},cellRenderer:function(e){var t=e.cellData;return null==t?"":String(t)},defaultSortDirection:go,flexGrow:0,flexShrink:1,headerRenderer:function(e){var t=e.dataKey,a=e.label,i=e.sortBy,l=e.sortDirection,n=i===t,o=[w.createElement("span",{className:"ReactVirtualized__Table__headerTruncatedText",key:"label",title:"string"==typeof a?a:null},a)];return n&&o.push(w.createElement(ho,{key:"SortIndicator",sortDirection:l})),o},style:{}}),fo.propTypes={};var _o=function(e){function t(e){var a;return ol(this,t),(a=yo(this,t,[e])).state={scrollbarWidth:0},a._createColumn=a._createColumn.bind(a),a._createRow=a._createRow.bind(a),a._onScroll=a._onScroll.bind(a),a._onSectionRendered=a._onSectionRendered.bind(a),a._setRef=a._setRef.bind(a),a._setGridElementRef=a._setGridElementRef.bind(a),a}return hl(t,e),cl(t,[{key:"forceUpdateGrid",value:function(){this.Grid&&this.Grid.forceUpdate()}},{key:"getOffsetForRow",value:function(e){var t=e.alignment,a=e.index;return this.Grid?this.Grid.getOffsetForCell({alignment:t,rowIndex:a}).scrollTop:0}},{key:"invalidateCellSizeAfterRender",value:function(e){var t=e.columnIndex,a=e.rowIndex;this.Grid&&this.Grid.invalidateCellSizeAfterRender({rowIndex:a,columnIndex:t})}},{key:"measureAllRows",value:function(){this.Grid&&this.Grid.measureAllCells()}},{key:"recomputeGridSize",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.columnIndex,a=void 0===t?0:t,i=e.rowIndex,l=void 0===i?0:i;this.Grid&&this.Grid.recomputeGridSize({rowIndex:l,columnIndex:a})}},{key:"recomputeRowHeights",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.Grid&&this.Grid.recomputeGridSize({rowIndex:e})}},{key:"scrollToPosition",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.Grid&&this.Grid.scrollToPosition({scrollTop:e})}},{key:"scrollToRow",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0;this.Grid&&this.Grid.scrollToCell({columnIndex:0,rowIndex:e})}},{key:"getScrollbarWidth",value:function(){if(this.GridElement){var e=this.GridElement,t=e.clientWidth||0;return(e.offsetWidth||0)-t}return 0}},{key:"componentDidMount",value:function(){this._setScrollbarWidth()}},{key:"componentDidUpdate",value:function(){this._setScrollbarWidth()}},{key:"render",value:function(){var e=this,t=this.props,a=t.children,i=t.className,l=t.disableHeader,n=t.gridClassName,o=t.gridStyle,r=t.headerHeight,s=t.headerRowRenderer,u=t.height,c=t.id,g=t.noRowsRenderer,d=t.rowClassName,p=t.rowStyle,h=t.scrollToIndex,m=t.style,b=t.width,f=this.state.scrollbarWidth,v=l?u:u-r,y="function"==typeof d?d({index:-1}):d,x="function"==typeof p?p({index:-1}):p;return this._cachedColumnStyles=[],w.Children.toArray(a).forEach(function(t,a){var i=e._getFlexStyleForColumn(t,t.props.style||fo.defaultProps.style);e._cachedColumnStyles[a]=wo({overflow:"hidden"},i)}),w.createElement("div",{"aria-label":this.props["aria-label"],"aria-labelledby":this.props["aria-labelledby"],"aria-colcount":w.Children.toArray(a).length,"aria-rowcount":this.props.rowCount,className:Al("ReactVirtualized__Table",i),id:c,role:"grid",style:m},!l&&s({className:Al("ReactVirtualized__Table__headerRow",y),columns:this._getHeaderColumns(),style:wo({height:r,overflow:"hidden",paddingRight:f,width:b},x)}),w.createElement(wn,Bl({},this.props,{elementRef:this._setGridElementRef,"aria-readonly":null,autoContainerWidth:!0,className:Al("ReactVirtualized__Table__Grid",n),cellRenderer:this._createRow,columnWidth:b,columnCount:1,height:v,id:void 0,noContentRenderer:g,onScroll:this._onScroll,onSectionRendered:this._onSectionRendered,ref:this._setRef,role:"rowgroup",scrollbarWidth:f,scrollToRow:h,style:wo(wo({},o),{},{overflowX:"hidden"})})))}},{key:"_createColumn",value:function(e){var t=e.column,a=e.columnIndex,i=e.isScrolling,l=e.parent,n=e.rowData,o=e.rowIndex,r=this.props.onColumnClick,s=t.props,u=s.cellDataGetter,c=s.cellRenderer,g=s.className,d=s.columnData,p=s.dataKey,h=s.id,m=c({cellData:u({columnData:d,dataKey:p,rowData:n}),columnData:d,columnIndex:a,dataKey:p,isScrolling:i,parent:l,rowData:n,rowIndex:o}),b=this._cachedColumnStyles[a],f="string"==typeof m?m:null;return w.createElement("div",{"aria-colindex":a+1,"aria-describedby":h,className:Al("ReactVirtualized__Table__rowColumn",g),key:"Row"+o+"-Col"+a,onClick:function(e){r&&r({columnData:d,dataKey:p,event:e})},role:"gridcell",style:b,title:f},m)}},{key:"_createHeader",value:function(e){var t,a,i,l,n,o=e.column,r=e.index,s=this.props,u=s.headerClassName,c=s.headerStyle,g=s.onHeaderClick,d=s.sort,p=s.sortBy,h=s.sortDirection,m=o.props,b=m.columnData,f=m.dataKey,v=m.defaultSortDirection,y=m.disableSort,x=m.headerRenderer,_=m.id,k=m.label,S=!y&&d,C=Al("ReactVirtualized__Table__headerColumn",u,o.props.headerClassName,{ReactVirtualized__Table__sortableHeaderColumn:S}),M=this._getFlexStyleForColumn(o,wo(wo({},c),o.props.headerStyle)),T=x({columnData:b,dataKey:f,disableSort:y,label:k,sortBy:p,sortDirection:h});if(S||g){var E=p!==f?v:h===po?go:po,D=function(e){S&&d({defaultSortDirection:v,event:e,sortBy:f,sortDirection:E}),g&&g({columnData:b,dataKey:f,event:e})};n=o.props["aria-label"]||k||f,l="none",i=0,t=D,a=function(e){"Enter"!==e.key&&" "!==e.key||D(e)}}return p===f&&(l=h===go?"ascending":"descending"),w.createElement("div",{"aria-label":n,"aria-sort":l,className:C,id:_,key:"Header-Col"+r,onClick:t,onKeyDown:a,role:"columnheader",style:M,tabIndex:i},T)}},{key:"_createRow",value:function(e){var t=this,a=e.rowIndex,i=e.isScrolling,l=e.key,n=e.parent,o=e.style,r=this.props,s=r.children,u=r.onRowClick,c=r.onRowDoubleClick,g=r.onRowRightClick,d=r.onRowMouseOver,p=r.onRowMouseOut,h=r.rowClassName,m=r.rowGetter,b=r.rowRenderer,f=r.rowStyle,v=this.state.scrollbarWidth,y="function"==typeof h?h({index:a}):h,x="function"==typeof f?f({index:a}):f,_=m({index:a}),k=w.Children.toArray(s).map(function(e,l){return t._createColumn({column:e,columnIndex:l,isScrolling:i,parent:n,rowData:_,rowIndex:a,scrollbarWidth:v})}),S=Al("ReactVirtualized__Table__row",y),C=wo(wo({},o),{},{height:this._getRowHeight(a),overflow:"hidden",paddingRight:v},x);return b({className:S,columns:k,index:a,isScrolling:i,key:l,onRowClick:u,onRowDoubleClick:c,onRowRightClick:g,onRowMouseOver:d,onRowMouseOut:p,rowData:_,style:C})}},{key:"_getFlexStyleForColumn",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a="".concat(e.props.flexGrow," ").concat(e.props.flexShrink," ").concat(e.props.width,"px"),i=wo(wo({},t),{},{flex:a,msFlex:a,WebkitFlex:a});return e.props.maxWidth&&(i.maxWidth=e.props.maxWidth),e.props.minWidth&&(i.minWidth=e.props.minWidth),i}},{key:"_getHeaderColumns",value:function(){var e=this,t=this.props,a=t.children;return(t.disableHeader?[]:w.Children.toArray(a)).map(function(t,a){return e._createHeader({column:t,index:a})})}},{key:"_getRowHeight",value:function(e){var t=this.props.rowHeight;return"function"==typeof t?t({index:e}):t}},{key:"_onScroll",value:function(e){var t=e.clientHeight,a=e.scrollHeight,i=e.scrollTop;(0,this.props.onScroll)({clientHeight:t,scrollHeight:a,scrollTop:i})}},{key:"_onSectionRendered",value:function(e){var t=e.rowOverscanStartIndex,a=e.rowOverscanStopIndex,i=e.rowStartIndex,l=e.rowStopIndex;(0,this.props.onRowsRendered)({overscanStartIndex:t,overscanStopIndex:a,startIndex:i,stopIndex:l})}},{key:"_setRef",value:function(e){this.Grid=e}},{key:"_setGridElementRef",value:function(e){this.GridElement=e}},{key:"_setScrollbarWidth",value:function(){var e=this.getScrollbarWidth();this.setState({scrollbarWidth:e})}}])}(w.PureComponent);ml(_o,"defaultProps",{disableHeader:!1,estimatedRowSize:30,headerHeight:0,headerStyle:{},noRowsRenderer:function(){return null},onRowsRendered:function(){return null},onScroll:function(){return null},overscanIndicesGetter:yn,overscanRowCount:10,rowRenderer:function(e){var t=e.className,a=e.columns,i=e.index,l=e.key,n=e.onRowClick,o=e.onRowDoubleClick,r=e.onRowMouseOut,s=e.onRowMouseOver,u=e.onRowRightClick,c=e.rowData,g=e.style,d={"aria-rowindex":i+1};return(n||o||r||s||u)&&(d["aria-label"]="row",d.tabIndex=0,n&&(d.onClick=function(e){return n({event:e,index:i,rowData:c})}),o&&(d.onDoubleClick=function(e){return o({event:e,index:i,rowData:c})}),r&&(d.onMouseOut=function(e){return r({event:e,index:i,rowData:c})}),s&&(d.onMouseOver=function(e){return s({event:e,index:i,rowData:c})}),u&&(d.onContextMenu=function(e){return u({event:e,index:i,rowData:c})})),w.createElement("div",Bl({},d,{className:t,key:l,role:"row",style:g}),a)},headerRowRenderer:function(e){var t=e.className,a=e.columns,i=e.style;return w.createElement("div",{className:t,role:"row",style:i},a)},rowStyle:{},scrollToAlignment:"auto",scrollToIndex:-1,style:{}}),_o.propTypes={};var ko=[],So=null,Co=null;function Mo(){Co&&(Co=null,document.body&&null!=So&&(document.body.style.pointerEvents=So),So=null)}function To(){Mo(),ko.forEach(function(e){return e.__resetIsScrolling()})}function Eo(e){e.currentTarget===window&&null==So&&document.body&&(So=document.body.style.pointerEvents,document.body.style.pointerEvents="none"),function(){Co&&gn(Co);var e=0;ko.forEach(function(t){e=Math.max(e,t.props.scrollingResetTimeInterval)}),Co=dn(To,e)}(),ko.forEach(function(t){t.props.scrollElement===e.currentTarget&&t.__handleWindowScrollEvent()})}function Do(e,t){ko.some(function(e){return e.props.scrollElement===t})||t.addEventListener("scroll",Eo),ko.push(e)}function Lo(e,t){(ko=ko.filter(function(t){return t!==e})).length||(t.removeEventListener("scroll",Eo),Co&&(gn(Co),Mo()))}var Bo=function(e){return e===window},Ho=function(e){return e.getBoundingClientRect()};function Ao(e,t){if(e){if(Bo(e)){var a=window,i=a.innerHeight,l=a.innerWidth;return{height:"number"==typeof i?i:0,width:"number"==typeof l?l:0}}return Ho(e)}return{height:t.serverHeight,width:t.serverWidth}}function Ro(e){return Bo(e)&&document.documentElement?{top:"scrollY"in window?window.scrollY:document.documentElement.scrollTop,left:"scrollX"in window?window.scrollX:document.documentElement.scrollLeft}:{top:e.scrollTop,left:e.scrollLeft}}function Po(e,t){var a=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),a.push.apply(a,i)}return a}function zo(e){for(var t=1;t<arguments.length;t++){var a=null!=arguments[t]?arguments[t]:{};t%2?Po(Object(a),!0).forEach(function(t){ml(e,t,a[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(a)):Po(Object(a)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(a,t))})}return e}function Oo(e,t,a){return t=dl(t),gl(e,Fo()?Reflect.construct(t,a||[],dl(e).constructor):t.apply(e,a))}function Fo(){try{var e=!Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){}))}catch(e){}return(Fo=function(){return!!e})()}var Io=function(){return"undefined"!=typeof window?window:void 0},No=function(e){function t(){var e;ol(this,t);for(var a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return ml(e=Oo(this,t,[].concat(i)),"_window",Io()),ml(e,"_isMounted",!1),ml(e,"_positionFromTop",0),ml(e,"_positionFromLeft",0),ml(e,"_detectElementResize",void 0),ml(e,"_child",void 0),ml(e,"_windowScrollerRef",w.createRef()),ml(e,"state",zo(zo({},Ao(e.props.scrollElement,e.props)),{},{isScrolling:!1,scrollLeft:0,scrollTop:0})),ml(e,"_registerChild",function(t){!t||t instanceof Element||console.warn("WindowScroller registerChild expects to be passed Element or null"),e._child=t,e.updatePosition()}),ml(e,"_onChildScroll",function(t){var a=t.scrollTop;if(e.state.scrollTop!==a){var i=e.props.scrollElement;i&&("function"==typeof i.scrollTo?i.scrollTo(0,a+e._positionFromTop):i.scrollTop=a+e._positionFromTop)}}),ml(e,"_registerResizeListener",function(t){t===window?window.addEventListener("resize",e._onResize,!1):e._detectElementResize.addResizeListener(t,e._onResize)}),ml(e,"_unregisterResizeListener",function(t){t===window?window.removeEventListener("resize",e._onResize,!1):t&&e._detectElementResize.removeResizeListener(t,e._onResize)}),ml(e,"_onResize",function(){e.updatePosition()}),ml(e,"__handleWindowScrollEvent",function(){if(e._isMounted){var t=e.props.onScroll,a=e.props.scrollElement;if(a){var i=Ro(a),l=Math.max(0,i.left-e._positionFromLeft),n=Math.max(0,i.top-e._positionFromTop);e.setState({isScrolling:!0,scrollLeft:l,scrollTop:n}),t({scrollLeft:l,scrollTop:n})}}}),ml(e,"__resetIsScrolling",function(){e.setState({isScrolling:!1})}),e}return hl(t,e),cl(t,[{key:"updatePosition",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props.scrollElement,t=this.props.onResize,a=this.state,i=a.height,l=a.width,n=this._child||this._windowScrollerRef.current;if(n instanceof Element&&e){var o=function(e,t){if(Bo(t)&&document.documentElement){var a=document.documentElement,i=Ho(e),l=Ho(a);return{top:i.top-l.top,left:i.left-l.left}}var n=Ro(t),o=Ho(e),r=Ho(t);return{top:o.top+n.top-r.top,left:o.left+n.left-r.left}}(n,e);this._positionFromTop=o.top,this._positionFromLeft=o.left}var r=Ao(e,this.props);i===r.height&&l===r.width||(this.setState({height:r.height,width:r.width}),t({height:r.height,width:r.width})),!0===this.props.updateScrollTopOnUpdatePosition&&(this.__handleWindowScrollEvent(),this.__resetIsScrolling())}},{key:"componentDidMount",value:function(){var e=this.props.scrollElement;this._detectElementResize=_l(),this.updatePosition(e),e&&(Do(this,e),this._registerResizeListener(e)),this._isMounted=!0}},{key:"componentDidUpdate",value:function(e,t){var a=this.props.scrollElement,i=e.scrollElement;i!==a&&null!=i&&null!=a&&(this.updatePosition(a),Lo(this,i),Do(this,a),this._unregisterResizeListener(i),this._registerResizeListener(a))}},{key:"componentWillUnmount",value:function(){var e=this.props.scrollElement;e&&(Lo(this,e),this._unregisterResizeListener(e)),this._isMounted=!1}},{key:"render",value:function(){var e=this.props.children,t=this.state,a=t.isScrolling,i=t.scrollTop,l=t.scrollLeft,n=t.height,o=t.width;return w.createElement("div",{ref:this._windowScrollerRef},e({onChildScroll:this._onChildScroll,registerChild:this._registerChild,height:n,isScrolling:a,scrollLeft:l,scrollTop:i,width:o}))}}])}(w.PureComponent);ml(No,"defaultProps",{onResize:function(){},onScroll:function(){},scrollingResetTimeInterval:150,scrollElement:Io(),serverHeight:0,serverWidth:0});const Vo=e=>{const{searchIconInputValue:t,onClickRemoveSearch:a,searchIcon:i,inputElement:l}=e;return(0,w.createElement)("section",{className:"uagb-ip-header"},(0,w.createElement)("h2",null,(0,M.__)("Icon Library","sureforms")),(0,w.createElement)("div",{className:"uagb-ip-search-container"},(0,w.createElement)("div",{className:"uagb-ip-search-bar"},""===t?zi("sistrix"):(0,w.createElement)("span",{onClick:a,className:"dashicons dashicons-no-alt"}),(0,w.createElement)("input",{type:"text",placeholder:(0,M.__)("Search","sureforms"),value:t,onChange:i,ref:l}))))},Go=e=>{const{value:t,onChange:a,closeModal:i,defaultIcons:l,iconCategoryList:n}=e,o={...srfm_spec_blocks_info.uagb_svg_icons},r=e=>((e,t)=>Array.from({length:Math.ceil(e.length/t)},(a,i)=>e.slice(i*t,i*t+t)))(e,8),[s,u]=(0,x.useState)(""),[c,g]=(0,x.useState)(r(l)),[d,p]=(0,x.useState)("all"),[h,m]=(0,x.useState)(l),[b,f]=(0,x.useState)(""),v=(0,x.useRef)(),y=(0,x.useRef)(),[_,k]=(0,x.useState)(null),[S,C]=(0,x.useState)(null),[T,E]=(0,x.useState)(null),D=e=>{const t=y?.current;return t?"w"===e?t.offsetWidth:t.offsetHeight:null};(0,x.useEffect)(()=>{v.current.focus(),k(D("h")),C(D("w"));const e=c.findIndex(e=>e.includes(t));E(e)},[]);const L=e=>{let t=[];if("all"===e)t=l;else if("no-category"===e)for(const e in o)0===o[e].custom_categories.length&&t.push(e);else for(const a in o)o[a].custom_categories.includes(e)&&t.push(a);p(e),m(t),E(null),g(r(t)),u("")};return(0,w.createElement)(te.Modal,{className:"uagb-ip-modal-wrapper",onRequestClose:i,overlayClassName:"uagb-ip-modal-wrapper-overlay",shouldCloseOnClickOutside:!1,closeButtonLabel:(0,M.__)("Close","sureforms")},(0,w.createElement)(Vo,{searchIconInputValue:s,onClickRemoveSearch:()=>{L(d),u("")},searchIcon:e=>{const t=e.target.value.toLowerCase();if(""!==t){const e=[...h].filter(e=>!!o[e]?.label&&-1!==o[e].label.toLowerCase().indexOf(t));g(r(e))}else L(d);u(t)},inputElement:v}),(0,w.createElement)("section",{className:"uagb-ip-lr-container"},(0,w.createElement)("div",{className:"uagb-ip-left"},(0,w.createElement)("div",{className:"uagb-ip-categories-list"},(0,w.createElement)("div",{key:"all",className:"all"===d?"selected":null,onClick:()=>L("all")},(0,M.__)("All Icons","sureforms")),n.map((e,t)=>(0,w.createElement)("div",{key:t,className:e.slug===d?"selected":null,onClick:()=>L(e.slug)},e.title)),(0,w.createElement)("div",{key:"no-category",className:"no-category"===d?"selected":null,onClick:()=>L("no-category")},(0,M.__)("Other","sureforms")))),(0,w.createElement)("div",{className:"uagb-ip-right"},(0,w.createElement)("div",{className:"uagb-ip-modal-container",ref:y},(()=>{if(!c.length)return(0,w.createElement)("div",{className:"uagb-ip-icons icon-not-found"},(0,w.createElement)("div",{className:"uagb-icon-not-available"},(0,w.createElement)("span",null,(0,M.__)("No Icons Found","sureforms"))));const e=S/8;return(0,w.createElement)("div",{className:"uagb-ip-icons"},(0,w.createElement)(wn,{cellRenderer:function(e){const{columnIndex:a,key:i,rowIndex:l,style:n}=e,r=c[l][a];if(!r)return null;const s=ue(["uagb-icon-item",t===r&&"default",r===b&&"selected"]),u=o[r]?.label?o[r].label:"";return(0,w.createElement)("div",{key:i,style:n},(0,w.createElement)("div",{className:s,onClick:()=>{t!==r&&f(r)}},zi(r),(0,w.createElement)(te.Tooltip,{text:u},(0,w.createElement)("span",null,(e=>e?e.length<11?e:e.slice(0,10)+"..":"")(u)))))},columnCount:c[0].length,columnWidth:8===c[0].length?e-2:100,height:_,rowCount:c.length,rowHeight:8===c[0].length?e:100,width:S,scrollToRow:T,autoContainerWidth:!0}))})()))),(0,w.createElement)("section",{className:"uagb-ip-footer"},(0,w.createElement)("button",{className:""===b?"disable":null,onClick:""!==b?()=>{a(b),i()}:null},(0,M.__)("Insert Icon","sureforms"))))},Wo=e=>{(0,x.useLayoutEffect)(()=>(nl.use(),()=>{nl.unuse()}),[]);const{label:t,value:a,onChange:i,help:l=!1}=e,n=[...wp.UAGBSvgIcons],o=[...wp.uagb_icon_category_list],[r,s]=(0,x.useState)(!1),u=()=>s(!0),c=a&&""!==a,g=(0,w.createElement)("div",{className:"uag-ip-placeholder-wrap"},c&&(0,w.createElement)("div",{className:"uag-ip-remove-icon",onClick:()=>{i("")}},zi("xmark")),(0,w.createElement)("div",{className:"uag-ip-selected-icon",onClick:u},(0,w.createElement)("div",{className:"uag-ip-selected-icon-overlay"},!c&&zi("plus")),c&&(0,w.createElement)("div",{className:"uag-ip-selected-icon-value"},zi(a))),(0,w.createElement)("div",{className:"uag-ip-actions"},(0,w.createElement)("span",{onClick:u},c?(0,M.__)("Change Icon","sureforms"):(0,M.__)("Choose Icon","sureforms"))));return(0,w.createElement)("div",{className:"uag-custom-ip components-base-control"},(0,w.createElement)("span",{className:"uag-control-label"},t||(0,M.__)("Icon","sureforms")),g,r&&(0,w.createElement)(Go,{...e,closeModal:()=>s(!1),defaultIcons:n,iconCategoryList:o}),(0,w.createElement)(pe,{text:l}))};var Uo=a(420),jo={};Uo.A&&Uo.A.locals&&(jo.locals=Uo.A.locals);var qo,$o=0,Zo={attributes:{id:"uagb-editor-styles"}};Zo.setAttributes=g(),Zo.insert=u().bind(null,"head"),Zo.domAPI=r(),Zo.insertStyleElement=p(),jo.use=function(e){return Zo.options=e||{},$o++||(qo=n()(Uo.A,Zo)),jo},jo.unuse=function(){$o>0&&! --$o&&(qo(),qo=null)};const Ko=jo,Yo=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Ko.use(),()=>{Ko.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const o=Q(),{label:r,unit:s,mUnit:u,tUnit:c,disableUnits:g,valueBottom:d,valueLeft:p,valueRight:h,valueTop:m,valueBottomTablet:b,valueLeftTablet:f,valueRightTablet:v,valueTopTablet:y,valueBottomMobile:_,valueLeftMobile:k,valueRightMobile:S,valueTopMobile:C,link:T,setAttributes:E,help:D=!1,min:L=-50}=e,B=(e,t)=>{switch(t){case"desktop":E({[m.label]:e}),E({[h.label]:e}),E({[d.label]:e}),E({[p.label]:e});break;case"tablet":E({[y.label]:e}),E({[v.label]:e}),E({[b.label]:e}),E({[f.label]:e});break;case"mobile":E({[C.label]:e}),E({[S.label]:e}),E({[_.label]:e}),E({[k.label]:e})}},H=(e,t,a="",i=!1)=>{let l=a;switch(""===a&&""!==e&&(l=""===e.target.value?0:Number(e.target.value)),i||(T.value?B(l,t):A(t)),t){case"desktop":E({[m.label]:l});break;case"tablet":E({[y.label]:l});break;case"mobile":E({[C.label]:l})}},A=e=>{switch(e){case"desktop":E({[m.label]:""===m.value||void 0===m.value?0:m.value}),E({[h.label]:""===h.value||void 0===h.value?0:h.value}),E({[d.label]:""===d.value||void 0===d.value?0:d.value}),E({[p.label]:""===p.value||void 0===p.value?0:p.value});break;case"tablet":E({[y.label]:void 0===y.value||""===y.value?0:y.value}),E({[v.label]:void 0===v.value||""===v.value?0:v.value}),E({[b.label]:void 0===b.value||""===b.value?0:b.value}),E({[f.label]:void 0===f.value||""===f.value?0:f.value});break;case"mobile":E({[C.label]:""===C.value||void 0===C.value?0:C.value}),E({[S.label]:""===S.value||void 0===S.value?0:S.value}),E({[_.label]:""===_.value||void 0===_.value?0:_.value}),E({[k.label]:""===k.value||void 0===k.value?0:k.value})}},R=(e,t,a="",i=!1)=>{let l=a;switch(""===a&&""!==e&&(l=""===e.target.value?0:Number(e.target.value)),i||(T.value?B(l,t):A(t)),t){case"desktop":E({[h.label]:l});break;case"tablet":E({[v.label]:l});break;case"mobile":E({[S.label]:l})}},P=(e,t,a="",i=!1)=>{let l=a;switch(""===a&&""!==e&&(l=""===e.target.value?0:Number(e.target.value)),i||(T.value?B(l,t):A(o)),t){case"desktop":E({[d.label]:l});break;case"tablet":E({[b.label]:l});break;case"mobile":E({[_.label]:l})}},z=(e,t,a="",i=!1)=>{let l=a;switch(""===a&&""!==e&&(l=""===e.target.value?0:Number(e.target.value)),i||(T.value&&!i?B(l,t):A(o)),t){case"desktop":E({[p.label]:l});break;case"tablet":E({[f.label]:l});break;case"mobile":E({[k.label]:l})}};let F=[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("Em","sureforms"),unitValue:"em"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}];e.units&&(F=e.units);let I="";T&&(I=(0,w.createElement)("span",{className:"uagb-spacing-control__link uagb-spacing-control-connected dashicons dashicons-admin-links ",onClick:()=>{A(o.toLowerCase()),E({[T.label]:!1})}}),T.value||(I=(0,w.createElement)("span",{className:"uagb-spacing-control__link uagb-spacing-control-disconnected dashicons dashicons-editor-unlink",onClick:()=>{N(),E({[T.label]:!0})}})));const N=()=>{let e;const t=o.toLowerCase();switch(t){case"desktop":e=m.value;break;case"tablet":e=y.value;break;case"mobile":e=C.value}B(e,t)},G={};G.Desktop=(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"uagb-spacing-control__inputs"},(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>H(e,"desktop"),value:void 0!==m.value?m.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>R(e,"desktop"),value:void 0!==h.value?h.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>P(e,"desktop"),value:void 0!==d.value?d.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>z(e,"desktop"),value:void 0!==p.value?p.value:""}),I)),G.Tablet=(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"uagb-spacing-control__inputs"},(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>H(e,"tablet"),value:void 0!==y.value?y.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>R(e,"tablet"),value:void 0!==v.value?v.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>P(e,"tablet"),value:void 0!==b.value?b.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>z(e,"tablet"),value:void 0!==f.value?f.value:""}),I)),G.Mobile=(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"uagb-spacing-control__inputs"},(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>H(e,"mobile"),value:void 0!==C.value?C.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>R(e,"mobile"),value:void 0!==S.value?S.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>P(e,"mobile"),value:void 0!==_.value?_.value:""}),(0,w.createElement)("input",{className:"uagb-spacing-control__number",type:"number",min:L,onChange:e=>z(e,"mobile"),value:void 0!==k.value?k.value:""}),I));const W=ce(e.label),U=(0,O.applyFilters)(`spectra.${n}.${t}.${W}.before`,"",n),j=(0,O.applyFilters)(`spectra.${n}.${t}.${W}`,"",n);return(0,w.createElement)("div",{ref:i,className:"components-base-control"},U,(0,w.createElement)("div",{className:"uagb-spacing-control"},(0,w.createElement)("div",{className:"uagb-size-type-field-tabs"},(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)(he,{label:r,responsive:!0}),(0,w.createElement)("div",{className:"uagb-control__actions"},(0,w.createElement)(ke,{onReset:e=>{switch(o.toLowerCase()){case"desktop":H("","desktop",e[m.label],!0),R("","desktop",e[h.label],!0),P("","desktop",e[d.label],!0),z("","desktop",e[p.label],!0),E({[s?.label]:e[s?.label]});break;case"tablet":H("","tablet",e[y.label],!0),R("","tablet",e[v.label],!0),P("","tablet",e[b.label],!0),z("","tablet",e[f.label],!0),E({[c?.label]:e[c?.label]});break;case"mobile":H("","mobile",e[C.label],!0),R("","mobile",e[S.label],!0),P("","mobile",e[_.label],!0),z("","mobile",e[k.label],!0),E({[u?.label]:e[u?.label]})}},attributeNames:[m?.label,h?.label,d?.label,p?.label,y?.label,v?.label,b?.label,f?.label,C?.label,S?.label,_?.label,k?.label,s?.label,c?.label,u?.label]}),(0,w.createElement)(te.ButtonGroup,{className:"uagb-control__units","aria-label":(0,M.__)("Select Units","sureforms")},!g&&(e=>{const t=[];return e.map(e=>t.push((0,w.createElement)(te.Tooltip,{text:(0,M.sprintf)(/* translators: abbreviation for units */ /* translators: abbreviation for units */ (0,M.__)("%s units","sureforms"),e.name)},(0,w.createElement)(te.Button,{key:e.unitValue,className:"uagb-range-control__units--"+e.name,isSmall:!0,isPrimary:"Desktop"===o&&s.value===e.unitValue||"Mobile"===o&&u.value===e.unitValue||"Tablet"===o&&c.value===e.unitValue,isSecondary:s.value!==e.unitValue||u.value!==e.unitValue||c.value!==e.unitValue,"aria-pressed":"Desktop"===o&&s.value===e.unitValue||"Mobile"===o&&u.value===e.unitValue||"Tablet"===o&&c.value===e.unitValue,"data-device-type":o,"aria-label":(0,M.sprintf)(/* translators: abbreviation for units */ /* translators: abbreviation for units */ -(0,M.__)("%s units","sureforms"),e.name),onClick:()=>{return t=e,void E("Mobile"===o?{[u.label]:t.unitValue}:"Tablet"===o?{[c.label]:t.unitValue}:{[s.label]:t.unitValue});var t}},e.unitValue)))),t})(F)))),G[o]?G[o]:G.Desktop,(0,w.createElement)("div",{className:"uagb-spacing-control__input-labels"},(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Top","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Right","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Bottom","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Left","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label uagb-spacing-control__link-label"}))),(0,w.createElement)(pe,{text:D})),j)},Jo=(0,x.memo)(e=>{const{children:t}=e,a=(0,x.useRef)(null),{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name,o=i("uagSettingState"),[r,s]=(0,x.useState)("style");(0,x.useEffect)(()=>{s((()=>{let e="style";return a?.current?.parentElement?.classList.contains("uagb-tab-content-general")&&(e="general"),a?.current?.parentElement?.classList.contains("uagb-tab-content-advance")&&(e="advance"),e})())},[a]);const u=e?.title?e?.title.toLowerCase().replace(/[^a-zA-Z ]/g,"").replace(/\s+/g,"-"):"",c=n.split("/").pop(),g=(0,O.applyFilters)(`spectra.${c}.${r}.${u}.before`,"",n),d=(0,O.applyFilters)(`spectra.${c}.${r}.${u}`,"",n);return(0,w.createElement)(te.PanelBody,{...e,onToggle:()=>{"enabled"===srfm_spec_blocks_info.collapse_panels&&function(e){const t=[];let a=e.parentNode.firstChild;for(;a;)1===a.nodeType&&a!==e&&a.classList.contains("is-opened")&&t.push(a),a=a.nextSibling;return t}(a.current).forEach(e=>{e.querySelector(".components-button").click()});let e=!1;a?.current?.classList.forEach(function(t){t.includes("uag-advance-panel-body")&&(e=t)});let t="style";a?.current?.parentElement?.classList.contains("uagb-tab-content-general")&&(t="general"),a?.current?.parentElement?.classList.contains("uagb-tab-content-advance")&&(t="advance");const l={...o,[n]:{...o?.[n],selectedPanel:e,selectedTab:t}},r=i();r&&r.setItem("uagSettingState",JSON.stringify(l))},ref:a,className:`uag-advance-panel-body-${u}`},g,t,d)}),Xo=(0,x.memo)(e=>{const{attributes:t,setAttributes:a,deviceType:i}=e,{separatorStyle:l,separatorAlign:n,separatorAlignTablet:o,separatorAlignMobile:r,separatorWidth:s,separatorWidthTablet:u,separatorWidthMobile:c,separatorWidthType:g,separatorColor:d,separatorBorderHeight:p,separatorBorderHeightMobile:h,separatorBorderHeightTablet:m,separatorBorderHeightUnit:b,separatorSize:f,separatorSizeMobile:v,separatorSizeTablet:y,separatorSizeType:x,elementType:_,separatorText:k,separatorTextTag:S,separatorIcon:C,elementPosition:T,elementSpacing:E,elementSpacingTablet:D,elementSpacingMobile:L,elementSpacingUnit:B,elementTextLoadGoogleFonts:H,elementTextFontFamily:A,elementTextFontWeight:R,elementTextFontSize:P,elementTextFontSizeType:z,elementTextFontSizeTablet:O,elementTextFontSizeMobile:F,elementTextLineHeightType:I,elementTextLineHeight:N,elementTextLineHeightTablet:V,elementTextLineHeightMobile:G,elementTextFontStyle:W,elementTextLetterSpacing:U,elementTextLetterSpacingTablet:j,elementTextLetterSpacingMobile:q,elementTextLetterSpacingType:$,elementTextDecoration:Z,elementTextTransform:K,elementColor:Y,elementIconWidth:J,elementIconWidthTablet:X,elementIconWidthMobile:Q,elementIconWidthType:ee,blockTopPadding:ae,blockRightPadding:ie,blockLeftPadding:le,blockBottomPadding:ne,blockTopPaddingTablet:oe,blockRightPaddingTablet:re,blockLeftPaddingTablet:se,blockBottomPaddingTablet:ue,blockTopPaddingMobile:ce,blockRightPaddingMobile:ge,blockLeftPaddingMobile:pe,blockBottomPaddingMobile:he,blockPaddingUnit:me,blockPaddingUnitTablet:be,blockPaddingUnitMobile:fe,blockPaddingLink:ve,blockTopMargin:we,blockRightMargin:ye,blockLeftMargin:xe,blockBottomMargin:_e,blockTopMarginTablet:ke,blockRightMarginTablet:Se,blockLeftMarginTablet:Ce,blockBottomMarginTablet:Me,blockTopMarginMobile:Te,blockRightMarginMobile:Ee,blockLeftMarginMobile:De,blockBottomMarginMobile:Le,blockMarginUnit:Be,blockMarginUnitTablet:He,blockMarginUnitMobile:Ae,blockMarginLink:Re}=t;return(0,w.createElement)("div",null,(0,w.createElement)(Pi.InspectorControls,null,(0,w.createElement)(di,null,(0,w.createElement)(pi,{...hi},(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!0},(0,w.createElement)(de,{label:(0,M.__)("Style","sureforms"),data:{value:l,label:"separatorStyle"},help:"none"!==l&&"dotted"!==l&&"dashed"!==l&&"double"!==l&&"solid"!==l&&(0,M.__)("Note: Please set Separator Height for proper thickness.","sureforms"),setAttributes:a,options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"rectangles",label:(0,M.__)("Rectangles","sureforms")},{value:"parallelogram",label:(0,M.__)("Parallelogram","sureforms")},{value:"slash",label:(0,M.__)("Slash","sureforms")},{value:"leaves",label:(0,M.__)("Leaves","sureforms")}]}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Add Element","sureforms"),data:{value:_,label:"elementType"},options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"text",label:(0,M.__)("Text","sureforms")},{value:"icon",label:(0,M.__)("Icon","sureforms")}],showIcons:!1,responsive:!1}),"text"===_&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Xi,{label:(0,M.__)("Text","sureforms"),data:{value:k,label:"separatorText"},setAttributes:a,value:k}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Heading Tag","sureforms"),data:{value:S,label:"separatorTextTag"},options:[{value:"h1",label:(0,M.__)("H1","sureforms")},{value:"h2",label:(0,M.__)("H2","sureforms")},{value:"h3",label:(0,M.__)("H3","sureforms")},{value:"h4",label:(0,M.__)("H4","sureforms")},{value:"h5",label:(0,M.__)("H5","sureforms")},{value:"h6",label:(0,M.__)("H6","sureforms")},{value:"span",label:(0,M.__)("Span","sureforms")},{value:"p",label:(0,M.__)("P","sureforms")}]})),"icon"===_&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Wo,{label:(0,M.__)("Icon","sureforms"),value:C,onChange:e=>a({separatorIcon:e})}))))),(0,w.createElement)(pi,{...mi},(0,w.createElement)(Jo,{title:"Separator",initialOpen:!0},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),data:{desktop:{value:n,label:"separatorAlign"},tablet:{value:o,label:"separatorAlignTablet"},mobile:{value:r,label:"separatorAlignMobile"}},className:"uagb-multi-button-alignment-control",options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0,responsive:!0}),(0,w.createElement)(Qi,{label:(0,M.__)("Width","sureforms"),data:{desktop:{value:s,label:"separatorWidth"},tablet:{value:u,label:"separatorWidthTablet"},mobile:{value:c,label:"separatorWidthMobile"}},min:0,max:"%"===g?100:500,unit:{value:g,label:"separatorWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:a}),"solid"!==l&&"double"!==l&&"dotted"!==l&&"dashed"!==l&&"none"!==l&&(0,w.createElement)(Qi,{label:(0,M.__)("Size","sureforms"),data:{desktop:{value:f,label:"separatorSize"},tablet:{value:y,label:"separatorSizeTablet"},mobile:{value:v,label:"separatorSizeMobile"}},min:0,max:"%"===x?100:500,unit:{value:x,label:"separatorSizeType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:a}),"none"!==l&&(0,w.createElement)(Qi,{label:(0,M.__)("Separator Height","sureforms"),data:{desktop:{value:p,label:"separatorBorderHeight"},tablet:{value:m,label:"separatorBorderHeightTablet"},mobile:{value:h,label:"separatorBorderHeightMobile"}},min:0,max:"%"===x?100:500,unit:{value:b,label:"separatorBorderHeightUnit"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:a}),"none"!==l&&(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:d||"",data:{value:d,label:"separatorColor"},setAttributes:a})),"none"!==_&&(0,w.createElement)(Jo,{title:"text"===_?(0,M.__)("Text","sureforms"):(0,M.__)("Icon","sureforms"),initialOpen:!1},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),responsive:!0,data:{desktop:{value:T,label:"elementPosition"},tablet:{value:T,label:"elementPosition"},mobile:{value:T,label:"elementPosition"}},className:"uagb-multi-button-alignment-control",options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:Y||"",data:{value:Y,label:"elementColor"},setAttributes:a}),"text"===_&&(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:a,loadGoogleFonts:{value:H,label:"elementTextLoadGoogleFonts"},fontFamily:{value:A,label:"elementTextFontFamily"},fontWeight:{value:R,label:"elementTextFontWeight"},fontStyle:{value:W,label:"elementTextFontStyle"},fontSizeType:{value:z,label:"elementTextFontSizeType"},fontSize:{value:P,label:"elementTextFontSize"},fontSizeMobile:{value:F,label:"elementTextFontSizeMobile"},fontSizeTablet:{value:O,label:"elementTextFontSizeTablet"},lineHeightType:{value:I,label:"elementTextLineHeightType"},lineHeight:{value:N,label:"elementTextLineHeight"},lineHeightMobile:{value:G,label:"elementTextLineHeightMobile"},lineHeightTablet:{value:V,label:"elementTextLineHeightTablet"},letterSpacing:{value:U,label:"elementTextLetterSpacing"},letterSpacingTablet:{value:j,label:"elementTextLetterSpacingTablet"},letterSpacingMobile:{value:q,label:"elementTextLetterSpacingMobile"},letterSpacingType:{value:$,label:"elementTextLetterSpacingType"},transform:{value:K,label:"elementTextTransform"},decoration:{value:Z,label:"elementTextDecoration"}}),"icon"===_&&(0,w.createElement)(Qi,{label:(0,M.__)("Icon Size","sureforms"),data:{desktop:{value:J,label:"elementIconWidth"},tablet:{value:X,label:"elementIconWidthTablet"},mobile:{value:Q,label:"elementIconWidthMobile"}},min:0,max:100,unit:{value:ee,label:"elementIconWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("EM","sureforms"),unitValue:"em"}],setAttributes:a}),(0,w.createElement)(Qi,{label:(0,M.__)("Spacing","sureforms"),data:{desktop:{value:E,label:"elementSpacing"},tablet:{value:D,label:"elementSpacingTablet"},mobile:{value:L,label:"elementSpacingMobile"}},min:0,max:500,unit:{value:B,label:"elementSpacingUnit"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:a})),(0,w.createElement)(Jo,{title:(0,M.__)("Spacing","sureforms"),initialOpen:!1},(0,w.createElement)(Yo,{label:(0,M.__)("Padding","sureforms"),valueTop:{value:ae,label:"blockTopPadding"},valueRight:{value:ie,label:"blockRightPadding"},valueBottom:{value:ne,label:"blockBottomPadding"},valueLeft:{value:le,label:"blockLeftPadding"},valueTopTablet:{value:oe,label:"blockTopPaddingTablet"},valueRightTablet:{value:re,label:"blockRightPaddingTablet"},valueBottomTablet:{value:ue,label:"blockBottomPaddingTablet"},valueLeftTablet:{value:se,label:"blockLeftPaddingTablet"},valueTopMobile:{value:ce,label:"blockTopPaddingMobile"},valueRightMobile:{value:ge,label:"blockRightPaddingMobile"},valueBottomMobile:{value:he,label:"blockBottomPaddingMobile"},valueLeftMobile:{value:pe,label:"blockLeftPaddingMobile"},unit:{value:me,label:"blockPaddingUnit"},mUnit:{value:fe,label:"blockPaddingUnitMobile"},tUnit:{value:be,label:"blockPaddingUnitTablet"},deviceType:i,attributes:t,setAttributes:a,link:{value:ve,label:"blockPaddingLink"}}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:we,label:"blockTopMargin"},valueRight:{value:ye,label:"blockRightMargin"},valueBottom:{value:_e,label:"blockBottomMargin"},valueLeft:{value:xe,label:"blockLeftMargin"},valueTopTablet:{value:ke,label:"blockTopMarginTablet"},valueRightTablet:{value:Se,label:"blockRightMarginTablet"},valueBottomTablet:{value:Me,label:"blockBottomMarginTablet"},valueLeftTablet:{value:Ce,label:"blockLeftMarginTablet"},valueTopMobile:{value:Te,label:"blockTopMarginMobile"},valueRightMobile:{value:Ee,label:"blockRightMarginMobile"},valueBottomMobile:{value:Le,label:"blockBottomMarginMobile"},valueLeftMobile:{value:De,label:"blockLeftMarginMobile"},unit:{value:Be,label:"blockMarginUnit"},mUnit:{value:Ae,label:"blockMarginUnitMobile"},tUnit:{value:He,label:"blockMarginUnitTablet"},deviceType:i,attributes:t,setAttributes:a,link:{value:Re,label:"blockMarginLink"}}))))))}),Qo=(0,x.memo)(e=>{const{attributes:{block_id:t,elementType:a,separatorText:i,separatorTextTag:l,separatorStyle:n,separatorIcon:o},className:r,deviceType:s}=e,u=function(e){const t={rectangles:"url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.4 0H16L9.6 16H0L6.4 0Z' fill='black'/%3E%3C/svg%3E\")",parallelogram:"url(\"data:image/svg+xml,%3Csvg width='8' height='16' viewBox='0 0 8 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='8' height='16' fill='black'/%3E%3C/svg%3E\")",slash:"url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.29312 16.9999L17 6.29302M14.2931 16.9999L17 14.293M-0.707031 15.9999L16.0002 -0.707153M8.00017 -0.707153L-0.706882 7.9999' stroke='black'/%3E%3C/svg%3E\")",leaves:"url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0_2356_5631)'%3E%3Cpath d='M15 1C10.5 1 9 2.5 9 7C13.5 7 15 5.5 15 1Z' stroke='black'/%3E%3Cpath d='M1 1C5.5 1 7 2.5 7 7C2.5 7 1 5.5 1 1Z' stroke='black'/%3E%3Cpath d='M15 15C10.5 15 9 13.5 9 9C13.5 9 15 10.5 15 15Z' stroke='black'/%3E%3Cpath d='M1 15C5.5 15 7 13.5 7 9C2.5 9 1 10.5 1 15Z' stroke='black'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_2356_5631'%3E%3Crect width='16' height='16' fill='white'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E\")"};return e in t?t[e]:""}(n),c=`${l}`,g="none"!==a?"wp-block-uagb-separator--"+a:"",d=(0,Pi.useBlockProps)({className:ue([r,`uagb-editor-preview-mode-${s.toLowerCase()}`,`uagb-block-${t}`,g])});return(0,w.createElement)("div",{...d},(0,w.createElement)("div",{className:ue([`uagb-editor-preview-mode-${s.toLowerCase()}`,`uagb-block-${t}`,"wp-block-uagb-separator","none"!==a?"wp-block-uagb-separator--"+a:""])},(0,w.createElement)("div",{className:"wp-block-uagb-separator__inner",style:{"--my-background-image":`${u}`}},"none"!==a&&(0,w.createElement)("div",{className:"wp-block-uagb-separator-element"},"icon"===a?zi(o):(0,w.createElement)(c,{className:"uagb-html-tag"},i)))))}),er=e=>e.reduce((e,t)=>{if(t?.attributes?.block_id&&t.name.includes("srfm")&&(e.blockIds.push(t.attributes.block_id),e.clientIds.push(t.clientId)),t.innerBlocks){const{blockIds:a,clientIds:i}=er(t.innerBlocks);e.blockIds=[...e.blockIds,...a],e.clientIds=[...e.clientIds,...i]}return e},{blockIds:[],clientIds:[]}),tr=e=>t=>{const{name:a,setAttributes:i,clientId:l,attributes:{block_id:n}}=t,o=["uagb/faq","uagb/buttons","uagb/icon-list","uagb/restaurant-menu","uagb/social-share","uagb/content-timeline","uagb/tabs","uagb/how-to"];return(0,x.useEffect)(()=>{srfm_spec_blocks_info.is_customize_preview&&("0"===n||void 0===n)&&o.includes(a)&&document.addEventListener(`UAG-${a}-${l.substr(0,8)}-BlockCustomizeWidgetEditor`,function(e){i({block_id:e.detail.id,classMigrate:e.detail.classMigrate,childMigrate:e.detail.childMigrate})})},[]),(0,x.useEffect)(()=>{if(srfm_spec_blocks_info.is_customize_preview&&("0"===n||void 0===n)&&o.includes(a)){const e=new CustomEvent(`UAG-${a}-${l.substr(0,8)}-BlockCustomizeWidgetEditor`,{detail:{id:l.substr(0,8),classMigrate:!0,childMigrate:!0}});document.dispatchEvent(e)}},[t.attributes]),(0,x.useEffect)(()=>{const e={block_id:l.substr(0,8)};if(["uagb/post-carousel","uagb/post-grid","uagb/post-masonry"].includes(a)&&(e.allTaxonomyStore=void 0),["uagb/countdown"].includes(a)&&(e.editorInnerblocksPreview=!1),["uagb/cf7-styler","uagb/gf-styler"].includes(a)&&(e.isHtml=!1),["uagb/buttons","uagb/icon-list","uagb/restaurant-menu","uagb/social-share","uagb/content-timeline","uagb/instagram-feed"].includes(a)&&(e.childMigrate=!0),["uagb/advanced-heading","uagb/blockquote","uagb/buttons","uagb/call-to-action","uagb/column","uagb/columns","uagb/icon-list","uagb/marketing-button","uagb/image-gallery","uagb/info-box","uagb/lottie","uagb/restaurant-menu","uagb/section","uagb/social-share","uagb/content-timeline","uagb/table-of-contents","uagb/team","uagb/testimonial","uagb/instagram-feed","uagb/login","uagb/register"].includes(a)&&(e.classMigrate=!0),["uagb/image-gallery","srfm/separator","srfm/icon","srfm/image"].includes(a))i(e);else{const t=(0,V.select)("core/editor")?.getBlocks(),{blockIds:a,clientIds:o}=t?er(t):{blockIds:[],clientIds:[]};"not_set"!==n&&"0"!==n&&n&&!((e,t,a)=>e.filter(e=>e===t).length>1&&a===e.lastIndexOf(t))(a,n,o.indexOf(l))||i(e)}},[l]),(0,w.createElement)(e,{...t})},ar=(0,X.compose)(ee,tr)(e=>{const{isSelected:t,attributes:a,attributes:{UAGHideDesktop:i,UAGHideTab:l,UAGHideMob:n},name:o,clientId:r,deviceType:s}=e;(0,x.useEffect)(()=>{N(e)},[i,l,n,s]),(0,x.useEffect)(()=>{G()},[s]);const u=(0,x.useMemo)(()=>function(e,t,a,i){const l=a.replace("srfm/",""),n=i.toLowerCase(),{block_id:o,separatorAlign:r,separatorAlignTablet:s,separatorAlignMobile:u,separatorStyle:c,separatorColor:g,separatorWidth:d,separatorWidthTablet:p,separatorWidthMobile:h,separatorWidthType:m,separatorBorderHeight:b,separatorBorderHeightMobile:f,separatorBorderHeightTablet:v,separatorBorderHeightUnit:w,separatorSize:y,separatorSizeTablet:x,separatorSizeMobile:_,separatorSizeType:k,elementType:S,elementPosition:C,elementSpacing:M,elementSpacingTablet:T,elementSpacingMobile:L,elementSpacingUnit:B,elementTextFontFamily:H,elementTextFontWeight:A,elementTextFontSize:R,elementTextFontSizeType:P,elementTextFontSizeTablet:z,elementTextFontSizeMobile:O,elementTextLineHeightType:N,elementTextLineHeight:V,elementTextLineHeightTablet:G,elementTextLineHeightMobile:W,elementTextFontStyle:U,elementTextLetterSpacing:j,elementTextLetterSpacingTablet:q,elementTextLetterSpacingMobile:$,elementTextLetterSpacingType:Z,elementTextDecoration:K,elementTextTransform:Y,elementColor:J,elementIconWidth:X,elementIconWidthTablet:Q,elementIconWidthMobile:ee,elementIconWidthType:te,blockTopPadding:ae,blockRightPadding:ie,blockLeftPadding:le,blockBottomPadding:ne,blockTopPaddingTablet:oe,blockRightPaddingTablet:re,blockLeftPaddingTablet:se,blockBottomPaddingTablet:ue,blockTopPaddingMobile:ce,blockRightPaddingMobile:ge,blockLeftPaddingMobile:de,blockBottomPaddingMobile:pe,blockPaddingUnit:he,blockPaddingUnitTablet:me,blockPaddingUnitMobile:be,blockTopMargin:fe,blockRightMargin:ve,blockLeftMargin:we,blockBottomMargin:ye,blockTopMarginTablet:xe,blockRightMarginTablet:_e,blockLeftMarginTablet:ke,blockBottomMarginTablet:Se,blockTopMarginMobile:Ce,blockRightMarginMobile:Me,blockLeftMarginMobile:Te,blockBottomMarginMobile:Ee,blockMarginUnit:De,blockMarginUnitTablet:Le,blockMarginUnitMobile:Be}=e,He=F(d,"separatorWidth",l),Ae=F(p,"separatorWidthTablet",l),Re=F(h,"separatorWidthMobile",l),Pe=F(b,"separatorBorderHeight",l),ze=F(f,"separatorBorderHeightMobile",l),Oe=F(v,"separatorBorderHeightTablet",l),Fe=F(y,"separatorSize",l),Ie=F(x,"separatorSizeTablet",l),Ne=F(_,"separatorSizeMobile",l),Ve={"border-top-width":D(Pe,w),"-webkit-mask-size":`${D(Fe,k)} 100%`,width:D(He,m),"border-top-color":g,"border-top-style":c};let Ge={};const We={};if("none"===S)Ge={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{"margin-top":"5px","margin-bottom":"5px",...Ve}};else{const e=I(r);Ge={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{width:D(He,m),...e},".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before":Ve,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before":Ve,".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after":Ve,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after":Ve},"left"===C&&(We[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(M,B)},Ge[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before"]={display:"none"},Ge[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before"]={display:"none"}),"right"===C&&(We[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(M,B)},Ge[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after"]={display:"none"},Ge[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after"]={display:"none"}),"center"===C&&(We[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(M,B),"margin-left":D(M,B)})}const Ue={...Ge,...We,".wp-block-uagb-separator--text .wp-block-uagb-separator-element .uagb-html-tag":{"font-family":H,"font-style":U,"text-decoration":K,"text-transform":Y,"font-weight":A,"font-size":D(R,P),"line-height":D(V,N),"letter-spacing":D(j,Z),color:J,margin:0},".wp-block-uagb-separator--icon .wp-block-uagb-separator-element svg":{"font-size":D(X,te),width:D(X,te),height:D(X,te),"line-height":D(X,te),color:J,fill:J},".wp-block-srfm-separator":{"margin-top":D(fe,De||"px"),"margin-right":D(ve,De||"px"),"margin-bottom":D(ye,De||"px"),"margin-left":D(we,De||"px")},".wp-block-uagb-separator":{"padding-top":D(ae,he||"px"),"padding-right":D(ie,he||"px"),"padding-bottom":D(ne,he||"px"),"padding-left":D(le,he||"px"),"text-align":r}},je={"border-top-width":D(Oe,w),"-webkit-mask-size":`${D(Ie,k)} 100%`,width:D(Ae,m),"border-top-color":g,"border-top-style":c};let qe={};const $e={};if("none"===S)qe={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{"margin-top":"5px","margin-bottom":"5px",...je}};else{const e=I(s);qe={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{width:D(Ae,m),...e},".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before":je,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before":je,".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after":je,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after":je},"left"===C&&($e[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(T,B)},qe[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before"]={display:"none"},qe[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before"]={display:"none"}),"center"===C&&($e[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(T,B),"margin-right":D(T,B)}),"right"===C&&($e[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(T,B)},qe[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after"]={display:"none"},qe[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after"]={display:"none"})}const Ze={...qe,...$e,".wp-block-uagb-separator--text .wp-block-uagb-separator-element .uagb-html-tag":{"font-family":H,"font-style":U,"text-decoration":K,"text-transform":Y,"font-weight":A,"font-size":D(z,P),"line-height":D(G,N),"letter-spacing":D(q,Z),color:J,margin:0},".wp-block-uagb-separator--icon .wp-block-uagb-separator-element svg":{"font-size":D(Q,te),width:D(Q,te),height:D(Q,te),"line-height":D(Q,te),color:J,fill:J},".wp-block-srfm-separator":{"margin-top":D(xe,Le||"px"),"margin-right":D(_e,Le||"px"),"margin-bottom":D(Se,Le||"px"),"margin-left":D(ke,Le||"px")},".wp-block-uagb-separator":{"padding-top":D(oe,me||"px"),"padding-right":D(re,me||"px"),"padding-bottom":D(ue,me||"px"),"padding-left":D(se,me||"px"),"text-align":s}},Ke={"border-top-width":D(ze,w),"-webkit-mask-size":`${D(Ne,k)} 100%`,width:D(Re,m),"border-top-color":g,"border-top-style":c};let Ye={};const Je={};if("none"===S)Ye={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{"margin-top":"5px","margin-bottom":"5px",...Ke}};else{const e=I(u);Ye={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{width:D(Re,m),...e},".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before":Ke,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before":Ke,".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after":Ke,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after":Ke},"left"===C&&(Je[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(L,B)},Ye[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before"]={display:"none"},Ye[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before"]={display:"none"}),"center"===C&&(Je[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(L,B),"margin-right":D(L,B)}),"right"===C&&(Je[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(L,B)},Ye[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after"]={display:"none"},Ye[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after"]={display:"none"})}const Xe={...Ye,...Je,".wp-block-uagb-separator--text .wp-block-uagb-separator-element .uagb-html-tag":{"font-family":H,"font-style":U,"text-decoration":K,"text-transform":Y,"font-weight":A,"font-size":D(O,P),"line-height":D(W,N),"letter-spacing":D($,Z),color:J,margin:0},".wp-block-uagb-separator--icon .wp-block-uagb-separator-element svg":{"font-size":D(ee,te),width:D(ee,te),height:D(ee,te),"line-height":D(ee,te),color:J,fill:J},".wp-block-srfm-separator":{"margin-top":D(Ce,Be||"px"),"margin-right":D(Me,Be||"px"),"margin-bottom":D(Ee,Be||"px"),"margin-left":D(Te,Be||"px")},".wp-block-uagb-separator":{"padding-top":D(ce,be||"px"),"padding-right":D(ge,be||"px"),"padding-bottom":D(pe,be||"px"),"padding-left":D(de,be||"px"),"text-align":u}},Qe=`.editor-styles-wrapper .uagb-block-${o}`;let et=E(Ue,Qe);return"tablet"!==n&&"mobile"!==n||(et+=E(Ze,`${Qe}`,!0,"tablet"),"mobile"===n&&(et+=E(Xe,`${Qe}`,!0,"mobile"))),et}(a,0,o,s),[a,s]);return(0,w.createElement)(w.Fragment,null,(0,w.createElement)(W,{blockStyling:u}),(0,w.createElement)(J,{attributes:a}),t&&(0,w.createElement)(Xo,{...e}),(0,w.createElement)(Qo,{...e}))}),ir=window.wp.blocks,lr=({image:e,isChildren:t=!1})=>{e||console.error(__("Please add preview image.","sureforms"));let a=srfm_spec_blocks_info.srfm_url;return a+="/images/field-previews/",t&&(a+="children/"),a+=e+".svg",(0,w.createElement)("img",{width:"100%",src:a,alt:""})},nr=function(e={}){let t={example:{attributes:{isPreview:!0}},usesContext:["postId","postType"]};return"site-editor"===srfm_spec_blocks_info.is_site_editor&&(t={}),(0,O.applyFilters)("addCommonDataToSpectraBlocks",{...e,...t})},or=(0,O.applyFilters)("srfm/separator",nr({}));(0,ir.registerBlockType)("srfm/separator",{...or,apiVersion:3,title:(0,M.__)("Separator","sureforms"),description:(0,M.__)("Add a modern separator to divide your page content with icon/text.","sureforms"),supports:{html:!1},icon:C.separator,category:srfm_spec_blocks_info.category,keywords:[(0,M.__)("divider","sureforms"),(0,M.__)("separator","sureforms")],attributes:T,edit:e=>e.attributes.isPreview?(0,w.createElement)(lr,{image:"separator"}):(0,w.createElement)(ar,{...e}),save:()=>null});var rr=a(6323),sr={};rr.A&&rr.A.locals&&(sr.locals=rr.A.locals);var ur,cr=0,gr={attributes:{id:"uagb-editor-styles"}};gr.setAttributes=g(),gr.insert=u().bind(null,"head"),gr.domAPI=r(),gr.insertStyleElement=p(),sr.use=function(e){return gr.options=e||{},cr++||(ur=n()(rr.A,gr)),sr},sr.unuse=function(){cr>0&&! --cr&&(ur(),ur=null)};const dr=sr,pr=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null),{getSelectedBlock:l}=(0,V.select)("core/block-editor");(0,x.useLayoutEffect)(()=>(dr.use(),()=>{dr.unuse()}),[]);const{setAttributes:n,gradientType:o,backgroundGradient:r,backgroundGradientColor2:s,backgroundGradientColor1:u,backgroundGradientType:c,backgroundGradientLocation1:g,backgroundGradientLocation2:d,backgroundGradientAngle:p}=e,h=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[h]);const m="gradient-settings",b=(0,O.applyFilters)(`spectra.${h}.${t}.${m}.before`,"",h),f=(0,O.applyFilters)(`spectra.${h}.${t}.${m}`,"",h),v=void 0!==o?o.value:"basic";return(0,w.createElement)(w.Fragment,null,void 0!==o&&(0,w.createElement)(Ri,{setAttributes:n,label:"Select Gradient",data:{value:o.value,label:o.label},options:[{value:"basic",label:(0,M.__)("Basic","sureforms")},{value:"advanced",label:(0,M.__)("Advanced","sureforms")}],showIcons:!1}),(0,w.createElement)("div",{ref:i},b,"basic"===v&&(0,w.createElement)(te.GradientPicker,{__nextHasNoMargin:!0,value:r?.value||null,onChange:e=>{n({[r.label]:e})},className:"uagb-gradient-picker",gradients:[]}),f),"advanced"===v&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:(0,M.__)("Color 1","sureforms"),colorValue:u.value?u.value:"",data:{value:u.value,label:u.label},setAttributes:n}),(0,w.createElement)(Ti,{label:(0,M.__)("Color 2","sureforms"),colorValue:s.value?s.value:"",data:{value:s.value,label:s.label},setAttributes:n}),(0,w.createElement)(Ri,{setAttributes:n,label:(0,M.__)("Type","sureforms"),data:{value:c.value,label:c.label},className:"uagb-multi-button-alignment-control",options:[{value:"linear",label:(0,M.__)("Linear","sureforms")},{value:"radial",label:(0,M.__)("Radial","sureforms")}]}),(0,w.createElement)(Me,{label:(0,M.__)("Location 1","sureforms"),setAttributes:n,value:g.value,data:{value:g.value,label:g.label},min:0,max:100,displayUnit:!1}),(0,w.createElement)(Me,{label:(0,M.__)("Location 2","sureforms"),setAttributes:n,value:d.value,data:{value:d.value,label:d.label},min:0,max:100,displayUnit:!1}),"linear"===c.value&&(0,w.createElement)(Me,{label:(0,M.__)("Angle","sureforms"),setAttributes:n,value:p.value,data:{value:p.value,label:p.label},min:0,max:360,displayUnit:!1})))};var hr=a(5001),mr={};hr.A&&hr.A.locals&&(mr.locals=hr.A.locals);var br,fr=0,vr={attributes:{id:"uagb-editor-styles"}};vr.setAttributes=g(),vr.insert=u().bind(null,"head"),vr.domAPI=r(),vr.insertStyleElement=p(),mr.use=function(e){return vr.options=e||{},fr++||(br=n()(hr.A,vr)),mr},mr.unuse=function(){fr>0&&! --fr&&(br(),br=null)};const wr=mr;function yr({label:e,type:t,classic:a,gradient:i,setAttributes:l}){const[n,o]=(0,x.useState)(null),r=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(wr.use(),()=>{wr.unuse()}),[]);const{getSelectedBlock:s}=(0,V.select)("core/block-editor"),u=s()?.name.split("/").pop();(0,x.useEffect)(()=>{o(se(r))},[u]);const c=ce(e),g=(0,O.applyFilters)(`spectra.${u}.${n}.${c}.before`,"",u),d=(0,O.applyFilters)(`spectra.${u}.${n}.${c}`,"",u);return(0,w.createElement)("div",{ref:r,className:"components-base-control"},g,(0,w.createElement)("div",{className:"uagb-color-switch-control-container"},(0,w.createElement)(Ri,{setAttributes:l,label:e,data:t,className:"uagb-multi-button-alignment-control",options:[{value:"classic",label:(0,M.__)("Classic","sureforms")},{value:"gradient",label:(0,M.__)("Gradient","sureforms")}],showIcons:!1}),"classic"===t.value?(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:a.value,data:{value:a.value,label:a.label},setAttributes:l}):(0,w.createElement)(pr,{backgroundGradient:i,setAttributes:l})),d)}const xr=e=>{const[t,a]=(0,x.useState)(!1),[l,n]=(0,x.useState)(null),o=(0,x.useRef)(null),{setAttributes:r,textShadowColor:s,textShadowHOffset:u,textShadowVOffset:c,textShadowBlur:g,label:d=(0,M.__)("Text Shadow","sureforms"),popup:p=!1,blockId:h,help:m=!1}=e;let b;const f=t?"active":"";(0,x.useLayoutEffect)(()=>{window.addEventListener("click",function(e){const t=document.querySelector(`.active.popup-${h} .spectra-control-popup__options--action-button`),l=document.querySelector(`.active.popup-${h} .spectra-control-popup`);if(t&&!t?.contains(e.target)&&!e.target?.classList?.contains("uagb-advanced-color-indicate")&&!e.target?.parentElement?.closest(".uagb-popover-color")&&l&&!l?.contains(e.target)&&!e.target?.parentElement?.closest(".uagb-reset")){a(!1);const e=y()?.name,t=i("uagSettingState"),l={...t,[e]:{...t?.[e],selectedSetting:!1}},n=i();n&&n.setItem("uagSettingState",JSON.stringify(l))}})},[]);const v=[s.label,u.label,c.label,g.label],{getSelectedBlock:y}=(0,V.select)("core/block-editor"),_=y()?.name.split("/").pop();(0,x.useEffect)(()=>{n(se(o))},[_]);const k=p&&(()=>{const e=(()=>{const e=y()?.name.split("/").pop();let t=!1;return void 0!==z[e]&&v.forEach(a=>{if(a){const i=void 0!==z[e][a]?.default?z[e][a]?.default:"";t={...t,[a]:i}}}),t})(),t=y()?.attributes;let a=!1;return v.forEach(i=>{t?.[i]&&t?.[i]!==e?.[i]&&(a=!0)}),a})(),S=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:s.title,colorValue:s.value,data:{value:s.value,label:s.label},setAttributes:r}),(0,w.createElement)(Me,{label:u.title,value:u.value,min:-100,max:100,displayUnit:!1,setAttributes:r,data:{value:u.value,label:u.label}}),(0,w.createElement)(Me,{label:c.title,value:c.value,min:-100,max:100,displayUnit:!1,setAttributes:r,data:{value:c.value,label:c.label}}),(0,w.createElement)(Me,{label:g.title,value:g.value,min:0,max:100,displayUnit:!1,setAttributes:r,data:{value:g.value,label:g.label}}));t&&(b=(0,w.createElement)("div",{className:"uagb-text-shadow-advanced spectra-control-popup"},S));const C=(0,w.createElement)("div",{className:"spectra-control-popup__options--action-wrapper"},(0,w.createElement)("span",{className:"uag-control-label"},d,k&&(0,w.createElement)("div",{className:"spectra__change-indicator--dot-right"})),(0,w.createElement)(te.Button,{className:"uag-text-shadow-button spectra-control-popup__options--action-button","aria-pressed":t,onClick:()=>{const e=document.querySelectorAll(".spectra-control-popup__options");if(e&&0<e.length)for(let t=0;t<e.length;t++){const a=e[t]?.querySelector(".spectra-control-popup__options.active .spectra-control-popup__options--action-button");a?.click()}a(!t);const l=y()?.name,n=i("uagSettingState");let o={...n,[l]:{...n?.[l],selectedSetting:".uag-text-shadow-options"}};t&&(o={...n,[l]:{...n?.[l],selectedSetting:!1}});const r=i();r&&r.setItem("uagSettingState",JSON.stringify(o))}},(0,w.createElement)(te.Dashicon,{icon:"edit"}))),T=ce(e.label),E=(0,O.applyFilters)(`spectra.${_}.${l}.${T}.before`,"",_),D=(0,O.applyFilters)(`spectra.${_}.${l}.${T}`,"",_);return(0,w.createElement)("div",{ref:o,className:p?"components-base-control":""},E,p?(0,w.createElement)("div",{className:` uag-text-shadow-options spectra-control-popup__options popup-${h} ${f}`},C,t&&b):(0,w.createElement)(w.Fragment,null,S),(0,w.createElement)(pe,{text:m}),D)};var _r=a(8619),kr={};_r.A&&_r.A.locals&&(kr.locals=_r.A.locals);var Sr,Cr=0,Mr={attributes:{id:"uagb-editor-styles"}};Mr.setAttributes=g(),Mr.insert=u().bind(null,"head"),Mr.domAPI=r(),Mr.insertStyleElement=p(),kr.use=function(e){return Mr.options=e||{},Cr++||(Sr=n()(_r.A,Mr)),kr},kr.unuse=function(){Cr>0&&! --Cr&&(Sr(),Sr=null)};const Tr=kr,Er=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Tr.use(),()=>{Tr.unuse()}),[]);const{getSelectedBlock:n}=(0,V.select)("core/block-editor"),o=n()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[o]);const r=(0,x.useRef)(null),s=3===e.tabs.length?"uag-control-tabs-three-tabs ":"",u=e.tabs.map((e,t)=>({...e,className:`uagb-tab-${t+1} ${e?.name}`})),c="tabs",g=(0,O.applyFilters)(`spectra.${o}.${t}.${c}.before`,"",o),d=(0,O.applyFilters)(`spectra.${o}.${t}.${c}`,"",o);return(0,w.createElement)("div",{ref:l},g,(0,w.createElement)(te.TabPanel,{className:`uag-control-tabs ${s}`,activeClass:"active-tab",tabs:u,ref:r,onSelect:e=>{const t=document.getElementsByClassName("uag-control-tabs")[0]?.querySelector(`.${e}`);let a=!1;t&&t?.classList&&t?.classList.forEach(e=>{e.includes("uagb-tab")&&(a=`.${e}`)});const l=n()?.name,o=i("uagSettingState"),r={...o,[l]:{...o?.[l],selectedInnerTab:a}},s=i();s&&s.setItem("uagSettingState",JSON.stringify(r))}},t=>(0,w.createElement)("div",{className:"uag-control-tabs-output"},e[t.name])),!e?.disableBottomSeparator&&(0,w.createElement)(Ui,null),(0,w.createElement)(pe,{text:e.help}),d)},Dr={prefix:j().string,borderStyleLabel:j().string,borderWidthLabel:j().string,borderRadiusLabel:j().string,borderColorLabel:j().string},Lr={borderStyleLabel:(0,M.__)("Style","sureforms"),borderWidthLabel:(0,M.__)("Width","sureforms"),borderRadiusLabel:(0,M.__)("Radius","sureforms"),borderColorLabel:(0,M.__)("Color","sureforms"),borderHoverColorLabel:(0,M.__)("Color","sureforms")},Br=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null),{attributes:l,setAttributes:n,disabledBorderTitle:o,disableBottomSeparator:r,deviceType:s,prefix:u,borderStyleLabel:c,borderWidthLabel:g,borderRadiusLabel:d,borderColorLabel:p,borderHoverColorLabel:h,showWidth:m,label:b=(0,M.__)("Border","sureforms"),normalTabLabel:f=(0,M.__)("Normal","sureforms"),hoverTabLabel:v=(0,M.__)("Hover","sureforms"),borderRadiusHelp:y,help:_=!1}=e,{getSelectedBlock:k}=(0,V.select)("core/block-editor"),S=k()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[S]);const C=[{name:"normal",title:f}];C.push({name:"hover",title:v});const T=l[u+"BorderStyle"],E=(0,w.createElement)(Ti,{label:p,colorValue:l[u+"BorderColor"]?l[u+"BorderColor"]:"",data:{value:l[u+"BorderColor"],label:u+"BorderColor"},setAttributes:n}),D=(0,w.createElement)(Ti,{label:h,colorValue:l[u+"BorderHColor"]?l[u+"BorderHColor"]:"",data:{value:l[u+"BorderHColor"],label:u+"BorderHColor"},setAttributes:n}),L=(0,w.createElement)(w.Fragment,null,!o&&(0,w.createElement)("p",{className:"spectra-panel__body-sub-heading"},b),(0,w.createElement)(de,{label:c,data:{value:T,label:u+"BorderStyle"},setAttributes:n,options:[{value:"default",label:(0,M.__)("Default","sureforms")},{value:"none",label:(0,M.__)("None","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"groove",label:(0,M.__)("Groove","sureforms")},{value:"inset",label:(0,M.__)("Inset","sureforms")},{value:"outset",label:(0,M.__)("Outset","sureforms")},{value:"ridge",label:(0,M.__)("Ridge","sureforms")}]}),"default"!==T&&"none"!==T&&!1!==m&&(0,w.createElement)(Yo,{label:g,valueTop:{value:l[u+"BorderTopWidth"],label:u+"BorderTopWidth"},valueRight:{value:l[u+"BorderRightWidth"],label:u+"BorderRightWidth"},valueBottom:{value:l[u+"BorderBottomWidth"],label:u+"BorderBottomWidth"},valueLeft:{value:l[u+"BorderLeftWidth"],label:u+"BorderLeftWidth"},valueTopTablet:{value:l[u+"BorderTopWidthTablet"],label:u+"BorderTopWidthTablet"},valueRightTablet:{value:l[u+"BorderRightWidthTablet"],label:u+"BorderRightWidthTablet"},valueBottomTablet:{value:l[u+"BorderBottomWidthTablet"],label:u+"BorderBottomWidthTablet"},valueLeftTablet:{value:l[u+"BorderLeftWidthTablet"],label:u+"BorderLeftWidthTablet"},valueTopMobile:{value:l[u+"BorderTopWidthMobile"],label:u+"BorderTopWidthMobile"},valueRightMobile:{value:l[u+"BorderRightWidthMobile"],label:u+"BorderRightWidthMobile"},valueBottomMobile:{value:l[u+"BorderBottomWidthMobile"],label:u+"BorderBottomWidthMobile"},valueLeftMobile:{value:l[u+"BorderLeftWidthMobile"],label:u+"BorderLeftWidthMobile"},disableUnits:!0,deviceType:s,attributes:l,setAttributes:n,link:{value:l[u+"BorderLink"],label:u+"BorderLink"},min:0}),"default"!==T&&(0,w.createElement)(Yo,{label:d,valueTop:{value:l[u+"BorderTopLeftRadius"],label:u+"BorderTopLeftRadius"},valueRight:{value:l[u+"BorderTopRightRadius"],label:u+"BorderTopRightRadius"},valueBottom:{value:l[u+"BorderBottomRightRadius"],label:u+"BorderBottomRightRadius"},valueLeft:{value:l[u+"BorderBottomLeftRadius"],label:u+"BorderBottomLeftRadius"},valueTopTablet:{value:l[u+"BorderTopLeftRadiusTablet"],label:u+"BorderTopLeftRadiusTablet"},valueRightTablet:{value:l[u+"BorderTopRightRadiusTablet"],label:u+"BorderTopRightRadiusTablet"},valueBottomTablet:{value:l[u+"BorderBottomRightRadiusTablet"],label:u+"BorderBottomRightRadiusTablet"},valueLeftTablet:{value:l[u+"BorderBottomLeftRadiusTablet"],label:u+"BorderBottomLeftRadiusTablet"},valueTopMobile:{value:l[u+"BorderTopLeftRadiusMobile"],label:u+"BorderTopLeftRadiusMobile"},valueRightMobile:{value:l[u+"BorderTopRightRadiusMobile"],label:u+"BorderTopRightRadiusMobile"},valueBottomMobile:{value:l[u+"BorderBottomRightRadiusMobile"],label:u+"BorderBottomRightRadiusMobile"},valueLeftMobile:{value:l[u+"BorderBottomLeftRadiusMobile"],label:u+"BorderBottomLeftRadiusMobile"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],unit:{value:l[u+"BorderRadiusUnit"],label:u+"BorderRadiusUnit"},mUnit:{value:l[u+"BorderRadiusUnitMobile"],label:u+"BorderRadiusUnitMobile"},tUnit:{value:l[u+"BorderRadiusUnitTablet"],label:u+"BorderRadiusUnitTablet"},deviceType:s,attributes:l,setAttributes:n,link:{value:l[u+"BorderRadiusLink"],label:u+"BorderRadiusLink"},help:y||!1,min:0}),"none"!==T&&"default"!==T&&(0,w.createElement)(Er,{tabs:C,normal:E,hover:D,active:"",disableBottomSeparator:!0}),!r&&(0,w.createElement)(Ui,null),(0,w.createElement)(pe,{text:_})),B=ce(e.label),H=(0,O.applyFilters)(`spectra.${S}.${t}.${B}.before`,"",S),A=(0,O.applyFilters)(`spectra.${S}.${t}.${B}`,"",S);return(0,w.createElement)("div",{ref:i},H,L,A)},Hr=Br;Br.propTypes=Dr,Br.defaultProps=Lr;const Ar=(0,x.memo)(e=>{const{attributes:t,deviceType:a,setAttributes:i}=e,{block_id:l,headingTitleToggle:n,headingAlign:o,headingAlignTablet:r,headingAlignMobile:s,headingColorType:u,headingColor:c,headingGradientColor:g,blockBackgroundType:d,blockBackground:p,blockGradientBackground:h,subHeadingColor:m,subHeadSpace:b,subHeadSpaceTablet:f,subHeadSpaceMobile:v,subHeadSpaceType:y,separatorColor:x,headingTag:_,headingWrapper:k,headFontFamily:S,headFontWeight:C,headFontStyle:T,headFontSizeType:E,headFontSizeTypeMobile:D,headFontSizeTypeTablet:L,headFontSize:B,headFontSizeMobile:H,headFontSizeTablet:A,headLineHeightType:R,headLineHeight:P,headLineHeightMobile:z,headLineHeightTablet:F,headLetterSpacing:I,headLetterSpacingTablet:N,headLetterSpacingMobile:V,headLetterSpacingType:G,headShadowColor:W,headShadowHOffset:U,headShadowVOffset:j,headShadowBlur:q,headingDescToggle:$,headingDescPosition:Z,subHeadFontFamily:K,subHeadFontWeight:Y,subHeadFontStyle:J,subHeadFontSize:X,subHeadFontSizeType:Q,subHeadFontSizeTypeMobile:ee,subHeadFontSizeTypeTablet:ae,subHeadFontSizeMobile:ie,subHeadFontSizeTablet:le,subHeadLineHeight:ne,subHeadLineHeightType:oe,subHeadLineHeightMobile:re,subHeadLineHeightTablet:se,headTransform:ue,headDecoration:ce,subHeadTransform:ge,subHeadDecoration:pe,separatorWidth:he,separatorWidthTablet:me,separatorWidthMobile:be,separatorWidthType:fe,separatorStyle:ve,separatorPosition:we,separatorHeight:ye,separatorHeightType:xe,headSpace:_e,headSpaceTablet:ke,headSpaceMobile:Se,headSpaceType:Ce,separatorSpace:Te,separatorSpaceTablet:Ee,separatorSpaceMobile:De,separatorSpaceType:Le,headLoadGoogleFonts:Be,subHeadLoadGoogleFonts:He,subHeadLetterSpacing:Ae,subHeadLetterSpacingTablet:Re,subHeadLetterSpacingMobile:Pe,subHeadLetterSpacingType:ze,blockTopPadding:Oe,blockRightPadding:Fe,blockLeftPadding:Ie,blockBottomPadding:Ne,blockTopPaddingTablet:Ve,blockRightPaddingTablet:Ge,blockLeftPaddingTablet:We,blockBottomPaddingTablet:Ue,blockTopPaddingMobile:je,blockRightPaddingMobile:qe,blockLeftPaddingMobile:$e,blockBottomPaddingMobile:Ze,blockPaddingUnit:Ke,blockPaddingUnitTablet:Ye,blockPaddingUnitMobile:Je,blockPaddingLink:Xe,blockTopMargin:Qe,blockRightMargin:et,blockLeftMargin:tt,blockBottomMargin:at,blockTopMarginTablet:it,blockRightMarginTablet:lt,blockLeftMarginTablet:nt,blockBottomMarginTablet:ot,blockTopMarginMobile:rt,blockRightMarginMobile:st,blockLeftMarginMobile:ut,blockBottomMarginMobile:ct,blockMarginUnit:gt,blockMarginUnitTablet:dt,blockMarginUnitMobile:pt,blockMarginLink:ht,linkColor:mt,linkHColor:bt,highLightColor:ft,highLightBackground:vt,highLightLoadGoogleFonts:wt,highLightFontFamily:yt,highLightFontWeight:xt,highLightFontStyle:_t,highLightTransform:kt,highLightDecoration:St,highLightFontSizeType:Ct,highLightFontSizeTypeMobile:Mt,highLightFontSizeTypeTablet:Tt,highLightLineHeightType:Et,highLightFontSize:Dt,highLightFontSizeTablet:Lt,highLightFontSizeMobile:Bt,highLightLineHeight:Ht,highLightLineHeightTablet:At,highLightLineHeightMobile:Rt,highLightLetterSpacing:Pt,highLightLetterSpacingTablet:zt,highLightLetterSpacingMobile:Ot,highLightLetterSpacingType:Ft,highLightTopPadding:It,highLightRightPadding:Nt,highLightLeftPadding:Vt,highLightBottomPadding:Gt,highLightTopPaddingTablet:Wt,highLightRightPaddingTablet:Ut,highLightLeftPaddingTablet:jt,highLightBottomPaddingTablet:qt,highLightTopPaddingMobile:$t,highLightRightPaddingMobile:Zt,highLightLeftPaddingMobile:Kt,highLightBottomPaddingMobile:Yt,highLightPaddingUnit:Jt,highLightPaddingUnitTablet:Xt,highLightPaddingUnitMobile:Qt,highLightPaddingLink:ea}=t;let ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")},{value:"above-sub-heading",label:(0,M.__)("Above Sub-heading","sureforms")},{value:"below-sub-heading",label:(0,M.__)("Below Sub-heading","sureforms")}];n||(ta=[{value:"above-sub-heading",label:(0,M.__)("Above Sub-heading","sureforms")},{value:"below-sub-heading",label:(0,M.__)("Below Sub-heading","sureforms")}]),$||(ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")}]),$&&"above-heading"===Z&&(ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")},{value:"above-sub-heading",label:(0,M.__)("Above Sub-heading","sureforms")}]),$&&"below-heading"===Z&&(ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")},{value:"below-sub-heading",label:(0,M.__)("Below Sub-heading","sureforms")}]);const aa=[{id:"alignment",component:(0,w.createElement)(Ri,{setAttributes:i,label:(0,M.__)("Alignment","sureforms"),data:{desktop:{value:o,label:"headingAlign"},tablet:{value:r,label:"headingAlignTablet"},mobile:{value:s,label:"headingAlignMobile"}},options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0,responsive:!0})},{id:"heading",component:(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Heading","sureforms"),checked:n,onChange:()=>i({headingTitleToggle:!n})})},{id:"heading-tag",component:n&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ri,{setAttributes:i,label:(0,M.__)("Heading Tag","sureforms"),data:{value:_,label:"headingTag"},options:[{value:"h1",label:(0,M.__)("H1","sureforms")},{value:"h2",label:(0,M.__)("H2","sureforms")},{value:"h3",label:(0,M.__)("H3","sureforms")},{value:"h4",label:(0,M.__)("H4","sureforms")},{value:"h5",label:(0,M.__)("H5","sureforms")},{value:"h6",label:(0,M.__)("H6","sureforms")},{value:"p",label:(0,M.__)("P","sureforms")},{value:"div",label:(0,M.__)("Div","sureforms")}]}),(0,w.createElement)(Ri,{setAttributes:i,label:(0,M.__)("Heading Wrapper","sureforms"),data:{value:k,label:"headingWrapper"},options:[{value:"div",label:(0,M.__)("Div","sureforms")},{value:"header",label:(0,M.__)("Header","sureforms")}]}))}],ia=(0,O.applyFilters)("srfm.block.heading.content",aa,e),la=(0,O.applyFilters)("srfm.advanced-heading.settings.advance",[],e);return(0,w.createElement)("div",null,(0,w.createElement)(Pi.InspectorControls,null,(0,w.createElement)(di,null,(0,w.createElement)(pi,{...hi,parentProps:e},(0,w.createElement)(Jo,{title:(0,M.__)("Content","sureforms"),initialOpen:!0},ia.map(e=>e.component)),(0,w.createElement)(Jo,{title:(0,M.__)("Sub Heading","sureforms"),initialOpen:!1},(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Enable Sub Heading","sureforms"),checked:$,onChange:()=>i({headingDescToggle:!$})}),$&&(0,w.createElement)(de,{label:(0,M.__)("Position","sureforms"),data:{value:Z,label:"headingDescPosition"},setAttributes:i,options:[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")}]})),(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!1},(0,w.createElement)(de,{label:(0,M.__)("Style","sureforms"),data:{value:ve,label:"separatorStyle"},setAttributes:i,options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")}]}),"none"!==ve&&(0,w.createElement)(de,{label:(0,M.__)("Position","sureforms"),data:{value:we,label:"separatorPosition"},setAttributes:i,options:ta}))),(0,w.createElement)(pi,{...mi,parentProps:e},n&&(0,w.createElement)(Jo,{title:(0,M.__)("Heading","sureforms"),initialOpen:!0},(0,w.createElement)(yr,{label:(0,M.__)("Text Color","sureforms"),type:{value:u,label:"headingColorType"},classic:{value:c,label:"headingColor"},gradient:{value:g,label:"headingGradientColor"},setAttributes:i}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:i,loadGoogleFonts:{value:Be,label:"headLoadGoogleFonts"},fontFamily:{value:S,label:"headFontFamily"},fontWeight:{value:C,label:"headFontWeight"},fontStyle:{value:T,label:"headFontStyle"},transform:{value:ue,label:"headTransform"},decoration:{value:ce,label:"headDecoration"},fontSizeType:{value:E,label:"headFontSizeType"},fontSizeTypeMobile:{value:D,label:"headFontSizeTypeMobile"},fontSizeTypeTablet:{value:L,label:"headFontSizeTypeTablet"},fontSize:{value:B,label:"headFontSize"},fontSizeMobile:{value:H,label:"headFontSizeMobile"},fontSizeTablet:{value:A,label:"headFontSizeTablet"},lineHeightType:{value:R,label:"headLineHeightType"},lineHeight:{value:P,label:"headLineHeight"},lineHeightMobile:{value:z,label:"headLineHeightMobile"},lineHeightTablet:{value:F,label:"headLineHeightTablet"},letterSpacing:{value:I,label:"headLetterSpacing"},letterSpacingTablet:{value:N,label:"headLetterSpacingTablet"},letterSpacingMobile:{value:V,label:"headLetterSpacingMobile"},letterSpacingType:{value:G,label:"headLetterSpacingType"}}),(0,w.createElement)(xr,{blockId:l,setAttributes:i,label:(0,M.__)("Text Shadow","sureforms"),textShadowColor:{value:W,label:"headShadowColor",title:(0,M.__)("Color","sureforms")},textShadowHOffset:{value:U,label:"headShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},textShadowVOffset:{value:j,label:"headShadowVOffset",title:(0,M.__)("Vertical","sureforms")},textShadowBlur:{value:q,label:"headShadowBlur",title:(0,M.__)("Blur","sureforms")},popup:!0}),($||"none"!==ve)&&(0,w.createElement)(Qi,{label:(0,M.__)("Bottom Spacing","sureforms"),data:{desktop:{value:_e,label:"headSpace"},tablet:{value:ke,label:"headSpaceTablet"},mobile:{value:Se,label:"headSpaceMobile"}},min:0,max:200,unit:{value:Ce,label:"headSpaceType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:i})),"none"!==ve&&(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!1},(0,w.createElement)(Qi,{label:(0,M.__)("Width","sureforms"),data:{desktop:{value:he,label:"separatorWidth"},tablet:{value:me,label:"separatorWidthTablet"},mobile:{value:be,label:"separatorWidthMobile"}},min:0,max:"%"===fe?100:500,unit:{value:fe,label:"separatorWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:i}),(0,w.createElement)(Me,{label:(0,M.__)("Thickness","sureforms"),setAttributes:i,value:ye,data:{value:ye,label:"separatorHeight"},min:0,max:20,unit:{value:xe,label:"separatorHeightType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}]}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:x||"",data:{value:x,label:"separatorColor"},setAttributes:i}),(0,w.createElement)(Qi,{label:(0,M.__)("Bottom Spacing","sureforms"),data:{desktop:{value:Te,label:"separatorSpace"},tablet:{value:Ee,label:"separatorSpaceTablet"},mobile:{value:De,label:"separatorSpaceMobile"}},min:0,max:200,unit:{value:Le,label:"separatorSpaceType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:i})),$&&(0,w.createElement)(Jo,{title:(0,M.__)("Sub Heading","sureforms"),initialOpen:!1},(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:m||"",data:{value:m,label:"subHeadingColor"},setAttributes:i}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:i,loadGoogleFonts:{value:He,label:"subHeadLoadGoogleFonts"},fontFamily:{value:K,label:"subHeadFontFamily"},fontWeight:{value:Y,label:"subHeadFontWeight"},fontStyle:{value:J,label:"subHeadFontStyle"},transform:{value:ge,label:"subHeadTransform"},decoration:{value:pe,label:"subHeadDecoration"},fontSizeType:{value:Q,label:"subHeadFontSizeType"},fontSizeTypeMobile:{value:ee,label:"subHeadFontSizeTypeMobile"},fontSizeTypeTablet:{value:ae,label:"subHeadFontSizeTypeTablet"},fontSize:{value:X,label:"subHeadFontSize"},fontSizeMobile:{value:ie,label:"subHeadFontSizeMobile"},fontSizeTablet:{value:le,label:"subHeadFontSizeTablet"},lineHeightType:{value:oe,label:"subHeadLineHeightType"},lineHeight:{value:ne,label:"subHeadLineHeight"},lineHeightMobile:{value:re,label:"subHeadLineHeightMobile"},lineHeightTablet:{value:se,label:"subHeadLineHeightTablet"},letterSpacing:{value:Ae,label:"subHeadLetterSpacing"},letterSpacingTablet:{value:Re,label:"subHeadLetterSpacingTablet"},letterSpacingMobile:{value:Pe,label:"subHeadLetterSpacingMobile"},letterSpacingType:{value:ze,label:"subHeadLetterSpacingType"}}),(0,w.createElement)(Qi,{label:(0,M.__)("Bottom Spacing","sureforms"),data:{desktop:{value:b,label:"subHeadSpace"},tablet:{value:f,label:"subHeadSpaceTablet"},mobile:{value:v,label:"subHeadSpaceMobile"}},min:0,max:200,unit:{value:y,label:"subHeadSpaceType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:i})),(0,w.createElement)(Jo,{title:(0,M.__)("Link","sureforms"),initialOpen:!1},(0,w.createElement)("p",{className:"components-base-control__help"},(0,M.__)("Below settings will apply to the heading text to which a link is applied.","sureforms")),(0,w.createElement)(Er,{tabs:[{name:"normal",title:(0,M.__)("Normal","sureforms")},{name:"hover",title:(0,M.__)("Hover","sureforms")}],normal:(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:mt,data:{value:mt,label:"linkColor"},setAttributes:i}),hover:(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:bt,data:{value:bt,label:"linkHColor"},setAttributes:i}),disableBottomSeparator:!0})),(0,w.createElement)(Jo,{title:(0,M.__)("Highlight","sureforms"),initialOpen:!1},(0,w.createElement)("p",{className:"components-base-control__help"},(0,M.__)("Highlight heading text from toolbar to see the below controls working.","sureforms")),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:ft,data:{value:ft,label:"highLightColor"},setAttributes:i}),(0,w.createElement)(Ti,{label:(0,M.__)("Background","sureforms"),colorValue:vt,data:{value:vt,label:"highLightBackground"},setAttributes:i}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:i,loadGoogleFonts:{value:wt,label:"highLightLoadGoogleFonts"},fontFamily:{value:yt,label:"highLightFontFamily"},fontWeight:{value:xt,label:"highLightFontWeight"},fontStyle:{value:_t,label:"highLightFontStyle"},transform:{value:kt,label:"highLightTransform"},decoration:{value:St,label:"highLightDecoration"},fontSizeType:{value:Ct,label:"highLightFontSizeType"},fontSizeTypeMobile:{value:Mt,label:"highLightFontSizeTypeMobile"},fontSizeTypeTablet:{value:Tt,label:"highLightFontSizeTypeTablet"},fontSize:{value:Dt,label:"highLightFontSize"},fontSizeMobile:{value:Bt,label:"highLightFontSizeMobile"},fontSizeTablet:{value:Lt,label:"highLightFontSizeTablet"},lineHeightType:{value:Et,label:"highLightLineHeightType"},lineHeight:{value:Ht,label:"highLightLineHeight"},lineHeightMobile:{value:Rt,label:"highLightLineHeightMobile"},lineHeightTablet:{value:At,label:"highLightLineHeightTablet"},letterSpacing:{value:Pt,label:"highLightLetterSpacing"},letterSpacingTablet:{value:zt,label:"highLightLetterSpacingTablet"},letterSpacingMobile:{value:Ot,label:"highLightLetterSpacingMobile"},letterSpacingType:{value:Ft,label:"highLightLetterSpacingType"}}),(0,w.createElement)(Yo,{label:(0,M.__)("Padding","sureforms"),valueTop:{value:It,label:"highLightTopPadding"},valueRight:{value:Nt,label:"highLightRightPadding"},valueBottom:{value:Gt,label:"highLightBottomPadding"},valueLeft:{value:Vt,label:"highLightLeftPadding"},valueTopTablet:{value:Wt,label:"highLightTopPaddingTablet"},valueRightTablet:{value:Ut,label:"highLightRightPaddingTablet"},valueBottomTablet:{value:qt,label:"highLightBottomPaddingTablet"},valueLeftTablet:{value:jt,label:"highLightLeftPaddingTablet"},valueTopMobile:{value:$t,label:"highLightTopPaddingMobile"},valueRightMobile:{value:Zt,label:"highLightRightPaddingMobile"},valueBottomMobile:{value:Yt,label:"highLightBottomPaddingMobile"},valueLeftMobile:{value:Kt,label:"highLightLeftPaddingMobile"},unit:{value:Jt,label:"highLightPaddingUnit"},mUnit:{value:Qt,label:"highLightPaddingUnitMobile"},tUnit:{value:Xt,label:"highLightPaddingUnitTablet"},deviceType:a,attributes:t,setAttributes:i,link:{value:ea,label:"highLightPaddingLink"}}),(0,w.createElement)(Hr,{setAttributes:i,prefix:"highLight",attributes:t,deviceType:a,disableBottomSeparator:!0})),(0,w.createElement)(Jo,{title:(0,M.__)("Background","sureforms"),initialOpen:!1},(0,w.createElement)(yr,{label:(0,M.__)("Background Color","sureforms"),type:{value:d,label:"blockBackgroundType"},classic:{value:p,label:"blockBackground"},gradient:{value:h,label:"blockGradientBackground"},setAttributes:i})),(0,w.createElement)(Jo,{title:(0,M.__)("Spacing","sureforms"),initialOpen:!1},(0,w.createElement)(Yo,{label:(0,M.__)("Padding","sureforms"),valueTop:{value:Oe,label:"blockTopPadding"},valueRight:{value:Fe,label:"blockRightPadding"},valueBottom:{value:Ne,label:"blockBottomPadding"},valueLeft:{value:Ie,label:"blockLeftPadding"},valueTopTablet:{value:Ve,label:"blockTopPaddingTablet"},valueRightTablet:{value:Ge,label:"blockRightPaddingTablet"},valueBottomTablet:{value:Ue,label:"blockBottomPaddingTablet"},valueLeftTablet:{value:We,label:"blockLeftPaddingTablet"},valueTopMobile:{value:je,label:"blockTopPaddingMobile"},valueRightMobile:{value:qe,label:"blockRightPaddingMobile"},valueBottomMobile:{value:Ze,label:"blockBottomPaddingMobile"},valueLeftMobile:{value:$e,label:"blockLeftPaddingMobile"},unit:{value:Ke,label:"blockPaddingUnit"},mUnit:{value:Je,label:"blockPaddingUnitMobile"},tUnit:{value:Ye,label:"blockPaddingUnitTablet"},deviceType:a,attributes:t,setAttributes:i,link:{value:Xe,label:"blockPaddingLink"}}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:Qe,label:"blockTopMargin"},valueRight:{value:et,label:"blockRightMargin"},valueBottom:{value:at,label:"blockBottomMargin"},valueLeft:{value:tt,label:"blockLeftMargin"},valueTopTablet:{value:it,label:"blockTopMarginTablet"},valueRightTablet:{value:lt,label:"blockRightMarginTablet"},valueBottomTablet:{value:ot,label:"blockBottomMarginTablet"},valueLeftTablet:{value:nt,label:"blockLeftMarginTablet"},valueTopMobile:{value:rt,label:"blockTopMarginMobile"},valueRightMobile:{value:st,label:"blockRightMarginMobile"},valueBottomMobile:{value:ct,label:"blockBottomMarginMobile"},valueLeftMobile:{value:ut,label:"blockLeftMarginMobile"},unit:{value:gt,label:"blockMarginUnit"},mUnit:{value:pt,label:"blockMarginUnitMobile"},tUnit:{value:dt,label:"blockMarginUnitTablet"},deviceType:a,attributes:t,setAttributes:i,link:{value:ht,label:"blockMarginLink"}}))),(0,w.createElement)(pi,{...bi},la.map(e=>e.content)))))}),Rr=e=>{const{setAttributes:t,attributes:a,context:i,onReplace:l,mergeBlocks:n,headingHasDynamicContent:o}=e;let{headingTitle:r,headingTag:s}=a,u=!1;if(o){const e=(0,O.applyFilters)("uag_render_text_loop_data",r,i);""!==e&&(u=["srfm/dynamic-content"],r=e)}return(0,w.createElement)(Pi.RichText,{tagName:s,placeholder:(0,M.__)("Write a Heading","sureforms"),value:r,className:"uagb-heading-text",onChange:e=>{t({headingTitle:e})},allowedFormats:u,onMerge:n,onSplit:e=>e?(0,ir.createBlock)("srfm/advanced-heading",{...a,headingTitle:e}):(0,ir.createBlock)("core/paragraph"),onReplace:l,onRemove:()=>l([])})},Pr=e=>{const{setAttributes:t,attributes:a,context:i,onReplace:l,mergeBlocks:n,descriptionHasDynamicContent:o}=e;let{headingDesc:r}=e.attributes,s=!1;if(o){const e=(0,O.applyFilters)("uag_render_text_loop_data",r,i);""!==e&&(s=["srfm/dynamic-content"],r=e)}return(0,w.createElement)(Pi.RichText,{tagName:"p",placeholder:(0,M.__)("Write a Description","sureforms"),value:r,className:"uagb-desc-text",onChange:e=>t({headingDesc:e}),allowedFormats:s,onMerge:n,onSplit:e=>e?(0,ir.createBlock)("srfm/advanced-heading",{...a,headingDesc:e}):(0,ir.createBlock)("core/paragraph"),onReplace:l,onRemove:()=>l([])})},zr=(0,x.memo)(e=>{const{attributes:{block_id:t,headingTitleToggle:a,headingDescToggle:i,separatorStyle:l,separatorPosition:n,headingDescPosition:o,headingWrapper:r},className:s,deviceType:u}=e,c=r||"div",g="none"!==l&&(0,w.createElement)("div",{className:"uagb-separator-wrap"},(0,w.createElement)("div",{className:"uagb-separator"})),d=(0,w.createElement)(w.Fragment,null,"above-heading"===n?g:"",(0,w.createElement)(Rr,{...e}),"below-heading"===n?g:""),p=(0,w.createElement)(w.Fragment,null,"above-sub-heading"===n?g:"",(0,w.createElement)(Pr,{...e}),"below-sub-heading"===n?g:"");return(0,w.createElement)(c,{className:ue([s,"wp-block-uagb-advanced-heading","uagb-block",`uagb-editor-preview-mode-${u.toLowerCase()}`,`uagb-block-${t}`])},i&&"above-heading"===o?p:"",a&&d,i&&"below-heading"===o?p:"",i||a?"":g)}),Or=(e,t,a="desktop")=>{if("default"!==e[t+"BorderStyle"]){switch(a){case"tablet":a="Tablet";break;case"mobile":a="Mobile";break;default:a=""}const i={},l=e[t+"BorderStyle"],n=e[t+"BorderColor"],o=D(e[t+"BorderTopWidth"+a],"px"),r=D(e[t+"BorderRightWidth"+a],"px"),s=D(e[t+"BorderBottomWidth"+a],"px"),u=D(e[t+"BorderLeftWidth"+a],"px"),c=e[t+"BorderRadiusUnit"+a]||"px",g=D(e[t+"BorderTopLeftRadius"+a],c),d=D(e[t+"BorderTopRightRadius"+a],c),p=D(e[t+"BorderBottomRightRadius"+a],c),h=D(e[t+"BorderBottomLeftRadius"+a],c);return"none"!==e[t+"BorderStyle"]&&""!==e[t+"BorderStyle"]&&(i["border-top-width"]=o,i["border-right-width"]=r,i["border-bottom-width"]=s,i["border-left-width"]=u,i["border-color"]=n),i["border-style"]=l,i["border-top-left-radius"]=g,i["border-top-right-radius"]=d,i["border-bottom-right-radius"]=p,i["border-bottom-left-radius"]=h,i}return{}},Fr=(0,x.memo)(({attributes:e})=>{const{headLoadGoogleFonts:t,headFontFamily:a,headFontWeight:i,subHeadLoadGoogleFonts:l,subHeadFontFamily:n,subHeadFontWeight:o,highLightLoadGoogleFonts:r,highLightFontFamily:s,highLightFontWeight:u}=e;let c,g,d;if(!0===t){const e={google:{families:[a+(i?":"+i:"")]}};c=(0,w.createElement)(Y,{config:e})}if(!0===l){const e={google:{families:[n+(o?":"+o:"")]}};g=(0,w.createElement)(Y,{config:e})}if(!0===r){const e={google:{families:[s+(u?":"+u:"")]}};d=(0,w.createElement)(Y,{config:e})}return(0,w.createElement)(w.Fragment,null,c,g,d)}),Ir=(0,X.compose)(tr,ee)(e=>{const{attributes:t,attributes:{UAGHideDesktop:a,UAGHideTab:i,UAGHideMob:l,headingTitle:n,headingDesc:o,formId:r},isSelected:s,clientId:u,name:c,deviceType:g,context:d,setAttributes:p}=e,h=-1!==n.indexOf('<span data-spectra-dc-field="'),m=o&&-1!==o.indexOf('<span data-spectra-dc-field="'),b=(e=>(0,V.useSelect)(t=>{const a=t(Pi.store).getBlockParents(e),i=t(Pi.store).getBlocksByClientId(a?.[0]),l=t("core/editor").getCurrentPostId();return i?.[0]?.attributes?.id||l}))(u);e={...e,headingHasDynamicContent:h,descriptionHasDynamicContent:m};const f=(0,Pi.useBlockProps)();(0,x.useEffect)(()=>{N(e)},[a,i,l,g]),(0,x.useEffect)(()=>{!h&&!m||t?.context||p({context:d})},[d]),(0,x.useEffect)(()=>{G()},[g]),(0,x.useEffect)(()=>{r!==b&&p({formId:b})},[r,b]);const v=(0,x.useMemo)(()=>function(e,t,a,i,l=!1){const n=i.toLowerCase(),o=a.replace("srfm/",""),{block_id:r,headingAlign:s,headingAlignTablet:u,headingAlignMobile:c,headingTag:g,headingColor:d,headingColorType:p,headingGradientColor:h,blockBackgroundType:m,blockBackground:b,blockGradientBackground:f,headSpace:v,headSpaceTablet:w,headSpaceMobile:y,separatorStyle:x,separatorHeight:_,separatorHeightType:k,separatorWidth:S,separatorWidthTablet:C,separatorWidthMobile:M,separatorWidthType:T,separatorColor:L,separatorSpace:B,separatorSpaceTablet:H,separatorSpaceMobile:A,separatorSpaceType:R,subHeadingColor:P,headFontFamily:z,headFontStyle:I,headFontWeight:N,headFontSize:V,headFontSizeType:G,headFontSizeTypeMobile:W,headFontSizeTypeTablet:U,headFontSizeMobile:j,headFontSizeTablet:q,headLineHeight:$,headLineHeightType:Z,headLineHeightMobile:K,headLineHeightTablet:Y,headLetterSpacing:J,headLetterSpacingTablet:X,headLetterSpacingMobile:Q,headLetterSpacingType:ee,headShadowColor:te,headShadowHOffset:ae,headShadowVOffset:ie,headShadowBlur:le,subHeadFontFamily:ne,subHeadFontStyle:oe,subHeadFontWeight:re,subHeadFontSize:se,subHeadFontSizeType:ue,subHeadFontSizeTypeMobile:ce,subHeadFontSizeTypeTablet:ge,subHeadFontSizeMobile:de,subHeadFontSizeTablet:pe,subHeadLineHeight:he,subHeadLineHeightType:me,subHeadLineHeightMobile:be,subHeadLineHeightTablet:fe,headTransform:ve,headDecoration:we,subHeadTransform:ye,subHeadDecoration:xe,subHeadLetterSpacing:_e,subHeadLetterSpacingTablet:ke,subHeadLetterSpacingMobile:Se,subHeadLetterSpacingType:Ce,blockTopPadding:Me,blockRightPadding:Te,blockLeftPadding:Ee,blockBottomPadding:De,blockTopPaddingTablet:Le,blockRightPaddingTablet:Be,blockLeftPaddingTablet:He,blockBottomPaddingTablet:Ae,blockTopPaddingMobile:Re,blockRightPaddingMobile:Pe,blockLeftPaddingMobile:ze,blockBottomPaddingMobile:Oe,blockPaddingUnit:Fe,blockPaddingUnitTablet:Ie,blockPaddingUnitMobile:Ne,blockTopMargin:Ve,blockRightMargin:Ge,blockLeftMargin:We,blockBottomMargin:Ue,blockTopMarginTablet:je,blockRightMarginTablet:qe,blockLeftMarginTablet:$e,blockBottomMarginTablet:Ze,blockTopMarginMobile:Ke,blockRightMarginMobile:Ye,blockLeftMarginMobile:Je,blockBottomMarginMobile:Xe,blockMarginUnit:Qe,blockMarginUnitTablet:et,blockMarginUnitMobile:tt,linkColor:at,linkHColor:it,highLightBorderHColor:lt,highLightColor:nt,highLightBackground:ot,highLightFontFamily:rt,highLightFontWeight:st,highLightFontStyle:ut,highLightTransform:ct,highLightDecoration:gt,highLightFontSizeType:dt,highLightFontSizeTypeTablet:pt,highLightFontSizeTypeMobile:ht,highLightLineHeightType:mt,highLightFontSize:bt,highLightFontSizeTablet:ft,highLightFontSizeMobile:vt,highLightLineHeight:wt,highLightLineHeightTablet:yt,highLightLineHeightMobile:xt,highLightLetterSpacing:_t,highLightLetterSpacingTablet:kt,highLightLetterSpacingMobile:St,highLightLetterSpacingType:Ct,highLightTopPadding:Mt,highLightRightPadding:Tt,highLightLeftPadding:Et,highLightBottomPadding:Dt,highLightTopPaddingTablet:Lt,highLightRightPaddingTablet:Bt,highLightLeftPaddingTablet:Ht,highLightBottomPaddingTablet:At,highLightTopPaddingMobile:Rt,highLightRightPaddingMobile:Pt,highLightLeftPaddingMobile:zt,highLightBottomPaddingMobile:Ot,highLightPaddingUnit:Ft,highLightPaddingUnitTablet:It,highLightPaddingUnitMobile:Nt,subHeadSpace:Vt,subHeadSpaceTablet:Gt,subHeadSpaceMobile:Wt,headingDescToggle:Ut}=e;let jt={},qt={},$t={},Zt={};"gradient"===p&&($t={"-webkit-text-fill-color":at},Zt={"-webkit-text-fill-color":it});const Kt=Or(e,"highLight"),Yt=Or(e,"highLight","tablet"),Jt=Or(e,"highLight","mobile");let Xt={".wp-block-uagb-advanced-heading ":{background:"classic"===m?b:f,"text-align":s,"margin-top":D(Ve,Qe),"margin-right":D(Ge,Qe),"margin-bottom":D(Ue,Qe),"margin-left":D(We,Qe),"padding-top":D(Me,Fe),"padding-right":D(Te,Fe),"padding-bottom":D(De,Fe),"padding-left":D(Ee,Fe)}," p.uagb-desc-text":{"font-family":ne,"font-style":oe,"text-decoration":xe,"text-transform":ye,"font-weight":re,"font-size":D(se,ue),"line-height":D(he,me),"letter-spacing":D(_e,Ce),color:P,"margin-bottom":D(F(Vt,"subHeadSpace",o),"px")},".wp-block-uagb-advanced-heading a":{color:at,...$t},".wp-block-uagb-advanced-heading a:hover":{color:it,...Zt},".wp-block-uagb-advanced-heading .srfm-highlight":{background:ot,color:nt,"-webkit-text-fill-color":nt,"font-family":rt,"font-style":ut,"text-decoration":gt,"text-transform":ct,"font-weight":st,"font-size":D(bt,dt),"line-height":D(wt,mt),"letter-spacing":D(_t,Ct),"padding-top":D(Mt,Ft),"padding-right":D(Tt,Ft),"padding-bottom":D(Dt,Ft),"padding-left":D(Et,Ft),...Kt},".wp-block-uagb-advanced-heading .srfm-highlight:hover":{"border-color":lt}},Qt={};"gradient"===p&&(Qt={background:h,"-webkit-background-clip":"text","-webkit-text-fill-color":"transparent"});const ea={color:nt,background:ot,"-webkit-text-fill-color":nt};Xt[".wp-block-uagb-advanced-heading .srfm-highlight::-moz-selection"]=ea,Xt[".wp-block-uagb-advanced-heading .srfm-highlight::selection"]=ea,Xt[" "+g+".uagb-heading-text"]={"font-family":z,"font-style":I,"text-decoration":we,"text-transform":ve,"font-weight":N,"font-size":D(V,G),"line-height":D($,Z),color:d,"letter-spacing":D(J,ee),...Qt};const ta=te&&D(ae,"px")+" "+D(ie,"px")+" "+D(le,"px")+" "+te;"gradient"===p?Xt[" "+g+".uagb-heading-text"].filter=`drop-shadow(${ta})`:Xt[" "+g+".uagb-heading-text"]["text-shadow"]=ta,"none"!==x&&(Xt[" .uagb-separator"]={"border-top-style":x,"border-top-width":D(F(_,"separatorHeight",o),k),width:D(F(S,"separatorWidth",o),T),"border-color":L,"margin-bottom":D(F(B,"separatorSpace",o),R)}),jt[".wp-block-uagb-advanced-heading "]={"text-align":u,"margin-top":D(je,et),"margin-right":D(qe,et),"margin-bottom":D(Ze,et),"margin-left":D($e,et),"padding-top":D(Le,Ie),"padding-right":D(Be,Ie),"padding-bottom":D(Ae,Ie),"padding-left":D(He,Ie)},jt[" "+g+".uagb-heading-text"]={"font-size":D(q,U),"line-height":D(Y,Z),"letter-spacing":D(X,ee)},jt[" p.uagb-desc-text"]={"font-size":D(pe,ge),"line-height":D(fe,me),"letter-spacing":D(ke,Ce),"margin-bottom":D(F(Gt,"subHeadSpaceTablet",o),"px")},jt[".wp-block-uagb-advanced-heading .srfm-highlight"]={"font-size":D(ft,pt),"line-height":D(yt,mt),"letter-spacing":D(kt,Ct),"padding-top":D(Lt,It),"padding-right":D(Bt,It),"padding-bottom":D(At,It),"padding-left":D(Ht,It),...Yt},qt[".wp-block-uagb-advanced-heading "]={"text-align":c,"margin-top":D(Ke,tt),"margin-right":D(Ye,tt),"margin-bottom":D(Xe,tt),"margin-left":D(Je,tt),"padding-top":D(Re,Ne),"padding-right":D(Pe,Ne),"padding-bottom":D(Oe,Ne),"padding-left":D(ze,Ne)},jt[" .uagb-separator"]={width:D(F(C,"separatorWidthTablet",o),T),"margin-bottom":D(F(H,"separatorSpaceTablet",o),R)},qt[" "+g+".uagb-heading-text"]={"font-size":D(j,W),"line-height":D(K,Z),"letter-spacing":D(Q,ee)},qt[" p.uagb-desc-text"]={"font-size":D(de,ce),"line-height":D(be,me),"letter-spacing":D(Se,Ce),"margin-bottom":D(F(Wt,"subHeadSpaceMobile",o),"px")},qt[".wp-block-uagb-advanced-heading .srfm-highlight"]={"font-size":D(vt,ht),"line-height":D(xt,mt),"letter-spacing":D(St,Ct),"padding-top":D(Rt,Nt),"padding-right":D(Pt,Nt),"padding-bottom":D(Ot,Nt),"padding-left":D(zt,Nt),...Jt},qt[" .uagb-separator"]={width:D(F(M,"separatorWidthMobile",o),T),"margin-bottom":D(F(A,"separatorSpaceMobile",o),R)},(Ut||"none"!==x)&&(Xt[" .uagb-heading-text"]={"margin-bottom":D(F(v,"headSpace",o),"px")},jt[" .uagb-heading-text"]={"margin-bottom":D(F(w,"headSpaceTablet",o),"px")},qt[" .uagb-heading-text"]={"margin-bottom":D(F(y,"headSpaceMobile",o),"px")});const aa=".editor-styles-wrapper "+(l?l+" ":`#block-${t} .uagb-block-${r}`);Xt=(0,O.applyFilters)(`spectra.${o}.styling`,Xt,e),jt=(0,O.applyFilters)(`spectra.${o}.tabletStyling`,jt,e),qt=(0,O.applyFilters)(`spectra.${o}.mobileStyling`,qt,e);let ia=E(Xt,aa);return("tablet"===n||"mobile"===n||l)&&(ia+=E(jt,`${aa}`,!0,"tablet"),("mobile"===n||l)&&(ia+=E(qt,`${aa}`,!0,"mobile"))),ia}(t,u,c,g),[t,g]);return(0,w.createElement)("div",{...f},(0,w.createElement)(W,{blockStyling:v}),(0,w.createElement)(Fr,{attributes:t}),s&&(0,w.createElement)(Ar,{...e}),(0,w.createElement)(zr,{...e}))}),Nr=window.wp.richText,Vr="srfm/advanced-heading-highlight";(0,Nr.registerFormatType)(Vr,{title:"Spectra Highlight",tagName:"mark",className:"srfm-highlight",edit:function({isActive:e,onChange:t,value:a}){const i=(0,V.useSelect)(e=>e("core/block-editor").getSelectedBlock(),[]);return(0,w.createElement)(Pi.BlockControls,null,i&&"srfm/advanced-heading"===i.name&&(0,w.createElement)(te.ToolbarGroup,{className:"uag-highlight-toolbar",label:"Options"},(0,w.createElement)(te.Tooltip,{text:(0,M.__)("Highlight Text","sureforms")},(0,w.createElement)(te.Button,{isPrimary:e,onClick:()=>{t((0,Nr.toggleFormat)(a,{type:Vr}))}},(0,w.createElement)("span",{className:"dashicons dashicons-admin-customizer"})))))}});const Gr=function(e){let t;const a={black:"#000000","cyan-bluish-gray":"#abb8c3",white:"#ffffff","pale-pink":"#f78da7","luminous-vivid-orange":"#ff6900","luminous-vivid-amber":"#fcb900","light-green-cyan":"#7bdcb5","vivid-green-cyan":"#00d084","pale-cyan-blue":"#8ed1fc","vivid-cyan-blue":"#0693e3","vivid-purple":"#9b51e0","vivid-red":"#cf2e2e"};return t=void 0!==a[e?.toLowerCase()]?a[e?.toLowerCase()]:wi(`var(--wp--preset--color--${e})`),t};let Wr={};Wr=(0,O.applyFilters)("srfm/advanced-heading",nr(Wr)),(0,ir.registerBlockType)("srfm/advanced-heading",{...Wr,apiVersion:3,title:(0,M.__)("Heading","sureforms"),description:(0,M.__)("Add heading, sub heading and a separator using one block.","sureforms"),icon:C.advanced_heading,keywords:[(0,M.__)("creative heading","sureforms"),(0,M.__)("uag","sureforms"),(0,M.__)("heading","sureforms")],supports:{anchor:!0,html:!1},attributes:P,category:srfm_spec_blocks_info.category,edit:e=>e.attributes.isPreview?(0,w.createElement)(lr,{image:"advanced-heading"}):(0,w.createElement)(Ir,{...e}),save:()=>null,__experimentalLabel:e=>(0,O.applyFilters)("uag_loop_data_source_label",(0,M.__)("Heading","sureforms"),e),usesContext:["postId","postType"],transforms:{from:[{type:"block",blocks:["core/heading"],transform:e=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:e.content,headingAlign:e.textAlign,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)})},{type:"block",blocks:["core/quote"],transform:e=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:e.value,headingDesc:e.citation,headingAlign:e.align,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)})},{type:"block",blocks:["core/paragraph"],transform:e=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:e.content,headingAlign:e.align,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)})},{type:"block",blocks:["core/list"],transform:(e,t)=>{const a=[];return t.forEach((e,i)=>{a.push({text:t[i].attributes.content})}),a.map(t=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:t.text,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)}))}}],to:[{type:"block",blocks:["core/heading"],transform:e=>(0,ir.createBlock)("core/heading",{content:e.headingTitle,align:e.headingAlign})},{type:"block",blocks:["core/quote"],transform:e=>(0,ir.createBlock)("core/quote",{value:e.headingTitle,citation:e.headingDesc})},{type:"block",blocks:["core/paragraph"],transform:e=>(0,ir.createBlock)("core/paragraph",{content:e.headingTitle})}]}});const Ur=e=>{let{horizontal:t,vertical:a,blur:i,spread:l,horizontalUnit:n="px",verticalUnit:o="px",blurUnit:r="px",spreadUnit:s="px",color:u,position:c="outset",altColor:g=""}=e;return u||g?(t=D(t,n),""===t&&(t=0),a=D(a,o),""===a&&(a=0),i=D(i,r),""===i&&(i=0),l=D(l,s),""===l&&(l=0),0===t&&0===a&&0===i&&0===l?"":`${t} ${a} ${i}${l?` ${l}`:""} ${u||g}${"outset"===c?"":` ${c}`}`):""};var jr=a(1388),qr={};jr.A&&jr.A.locals&&(qr.locals=jr.A.locals);var $r,Zr=0,Kr={attributes:{id:"uagb-editor-styles"}};Kr.setAttributes=g(),Kr.insert=u().bind(null,"head"),Kr.domAPI=r(),Kr.insertStyleElement=p(),qr.use=function(e){return Kr.options=e||{},Zr++||($r=n()(jr.A,Kr)),qr},qr.unuse=function(){Zr>0&&! --Zr&&($r(),$r=null)};const Yr=qr,Jr=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Yr.use(),()=>{Yr.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const{label:o,data:r,setAttributes:s,options:u,help:c=!1}=e,g=Q(),d={};d.Desktop=(0,w.createElement)(te.SelectControl,{value:r.desktop.value,onChange:e=>s({[r.desktop.label]:e}),options:u.desktop}),d.Tablet=(0,w.createElement)(te.SelectControl,{value:r.tablet.value,onChange:e=>s({[r.tablet.label]:e}),options:u.tablet||u.desktop}),d.Mobile=(0,w.createElement)(te.SelectControl,{value:r.mobile.value,onChange:e=>s({[r.mobile.label]:e}),options:u.mobile||u.desktop});const p=ce(e.label),h=(0,O.applyFilters)(`spectra.${n}.${t}.${p}.before`,"",n),m=(0,O.applyFilters)(`spectra.${n}.${t}.${p}`,"",n);return(0,w.createElement)("div",{ref:i,className:"uagb-responsive-select-control components-base-control"},h,(0,w.createElement)("div",{className:"uagb-size-type-field-tabs"},(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)(he,{label:o,responsive:!0})),d[g]?d[g]:d.Desktop),(0,w.createElement)(pe,{text:c}),m)};var Xr=a(9194),Qr={};Xr.A&&Xr.A.locals&&(Qr.locals=Xr.A.locals);var es,ts=0,as={attributes:{id:"uagb-editor-styles"}};as.setAttributes=g(),as.insert=u().bind(null,"head"),as.domAPI=r(),as.insertStyleElement=p(),Qr.use=function(e){return as.options=e||{},ts++||(es=n()(Xr.A,as)),Qr},Qr.unuse=function(){ts>0&&! --ts&&(es(),es=null)};const is=Qr,ls=e=>{const{isOpen:t,setOpen:a,onConfirm:i,title:l,description:n,confirmLabel:o=(0,M.__)("Confirm","sureforms"),cancelLabel:r=(0,M.__)("Cancel","sureforms"),processingLabel:s=(0,M.__)("Processing…","sureforms"),icon:u="",executable:c=!1}=e;(0,x.useLayoutEffect)(()=>(is.use(),()=>{is.unuse()}),[]);const[g,d]=(0,x.useState)(!1),p=()=>{a(!1),d(!1)};return(0,w.createElement)(w.Fragment,null,t&&(0,w.createElement)(te.Modal,{onRequestClose:p,className:"uag-confirm-popup-wrapper",overlayClassName:"uag-confirm-popup-overlay"},(0,w.createElement)("div",{className:"uag-confirm-popup-icon"},""!==u?zi(u):(0,w.createElement)("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:"1.5",stroke:"currentColor"},(0,w.createElement)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"}))),(0,w.createElement)("div",{className:"uag-confirm-popup-content"},(0,w.createElement)("div",{className:"uag-confirm-popup-text"},(0,w.createElement)("span",{className:"uag-confirm-popup-title"},l),(0,w.createElement)("span",{className:"uag-confirm-popup-description"},n)),(0,w.createElement)("div",{className:"uag-confirm-popup-controls"},!1===g?(0,w.createElement)(w.Fragment,null,(0,w.createElement)(te.Button,{className:"uag-confirm-popup-buttons uag-popup-confirmation-button",onClick:()=>{d(!0),c?i(c):i()}},o),(0,w.createElement)(te.Button,{className:"uag-confirm-popup-buttons uag-popup-cancellation-button",onClick:p},r)):(0,w.createElement)(te.Button,{isBusy:!0,className:"uag-confirm-popup-buttons uag-popup-confirmation-button"},s)))))};ls.defaultProps={};const ns=ls,os=window.wp.apiFetch;var rs=a.n(os);const ss=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null),n=(0,V.useSelect)(e=>e("core/block-editor").getSelectedBlock(),[]),o=i(),r=n?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[r]);const[s,u]=(0,x.useState)(!1),{onSelectImage:c,backgroundImage:g,onRemoveImage:d,slug:p="image",label:h=(0,M.__)("Image","sureforms"),disableLabel:m=!1,disableRemove:b=!1,allow:f=["image"],disableDynamicContent:v=!1,help:y=!1}=e;let _,k,S;switch(p){case"video":k=(0,M.__)("Select Video","sureforms"),S=(0,M.__)("Change Video","sureforms"),_=C.video_placeholder;break;case"lottie":k=(0,M.__)("Select Lottie Animation","sureforms"),S=(0,M.__)("Change Lottie Animation","sureforms"),_=C.lottie;break;case"svg":k=(0,M.__)("Upload SVG","sureforms"),S=(0,M.__)("Change SVG","sureforms");break;default:k=(0,M.__)("Select Image","sureforms"),S=(0,M.__)("Change Image","sureforms")}const T=v?null:(0,O.applyFilters)("uagb.registerImageExtender","",n?.name,c),E=v?null:(0,O.applyFilters)("uagb.registerImageLinkExtender","",n?.name,"bgImageLink","url"),D=e=>{const t={svg_nonce:srfm_spec_blocks_info.uagb_svg_confirmation_nonce,confirmation:"yes"};(async({url:e,action:t,data:a})=>{if(!((i=a)&&Object.keys(i).length>0&&Object.getPrototypeOf(i)===Object.prototype))return Promise.reject(new Error((0,M.__)("data object is empty","sureforms")));var i;const l=new window.FormData;l.append("action",t);for(const e in a){const t=a[e];l.append(e,t)}return await rs()({url:e,method:"POST",body:l})})({url:srfm_spec_blocks_info.ajax_url,action:"uagb_svg_confirmation",data:t}).then(t=>{t.success&&(o.setItem("uagSvgConfirmation",JSON.stringify("yes")),e())})},L=e=>{const t=i("uagSvgConfirmation");"svg"===p&&"yes"!==t?u(!0):e()},B=e=>(0,w.createElement)("div",{className:`spectra-media-control__button spectra-media-control__button--${e}`},C[e]),H=ce(e?.label),A=(0,O.applyFilters)(`spectra.${r}.${t}.${H}.before`,"",r),R=(0,O.applyFilters)(`spectra.${r}.${t}.${H}`,"",r);return(0,w.createElement)("div",{ref:l,className:"components-base-control"},A,(0,w.createElement)(te.BaseControl,{className:"spectra-media-control",id:`uagb-option-selector-${p}`,label:h,hideLabelFromVision:m},(()=>{if(v)return!0;const e=n?.attributes?.dynamicContent;return!e||!0!==e?.bgImage?.enable})()?(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"spectra-media-control__wrapper",style:{backgroundImage:!_&&g?.url&&!g?.svg&&`url("${(e=>{let t=e;switch(/(?:\.([^.]+))?$/.exec(String(t))[1]){case"json":case"avi":case"mpg":case"mp4":case"m4v":case"mov":case"ogv":case"vtt":case"wmv":case"3gp":case"3g2":t=""}return t})(g?.url)}")`}},_&&g?.url&&(0,w.createElement)("div",{className:"spectra-media-control__icon spectra-media-control__icon--stroke"},_),g?.svg&&(0,w.createElement)("div",{className:"spectra-media-control__icon spectra-media-control__icon--stroke",dangerouslySetInnerHTML:{__html:g.svg}}),(0,w.createElement)(Pi.MediaUpload,{title:k,onSelect:c,allowedTypes:f,value:g,render:({open:e})=>(e=>{const t=g?.url?"replace":"add";return(0,w.createElement)(w.Fragment,null,"add"===t&&(0,w.createElement)("button",{className:`spectra-media-control__clickable spectra-media-control__clickable--${t}`,onClick:()=>L(e)},B(t)),(0,w.createElement)("div",{className:"spectra-media-control__footer"},(0,w.createElement)("button",{className:"uag-control-label",onClick:()=>L(e)},S),T),"svg"===p&&(0,w.createElement)(ns,{isOpen:s,setOpen:u,onConfirm:D,title:(0,M.__)("Upload SVG?","sureforms"),description:(0,M.__)("Upload SVG can be potentially risky. Are you sure?","sureforms"),confirmLabel:(0,M.__)("Upload Anyway","sureforms"),cancelLabel:(0,M.__)("Cancel","sureforms"),executable:e}))})(e)}),!b&&g?.url&&(0,w.createElement)("button",{className:"spectra-media-control__clickable spectra-media-control__clickable--close",onClick:d},B("close"))),(0,w.createElement)(pe,{text:y})):T),E,R)},us=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null),[n,o]=(0,x.useState)(!1),r=(0,O.applyFilters)("uagb.blocksAttributes",z),{getSelectedBlock:s}=(0,V.select)("core/block-editor");(0,x.useLayoutEffect)(()=>{window.addEventListener("click",function(e){const t=document.querySelector(`.active.popup-${y} .spectra-control-popup__options--action-button`),a=document.querySelector(`.active.popup-${y} .spectra-control-popup`);if(t&&!t?.contains(e.target)&&a&&!a?.contains(e.target)&&!e.target?.classList?.contains("uagb-advanced-color-indicate")&&!e.target?.parentElement?.closest(".uagb-popover-color")&&!e.target?.parentElement?.closest(".uagb-reset")){o(!1);const e=s()?.name,t=i("uagSettingState"),a={...t,[e]:{...t?.[e],selectedSetting:!1}},l=i();l&&l.setItem("uagSettingState",JSON.stringify(a))}})},[]);const u=s()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[u]);const{setAttributes:c,boxShadowColor:g,boxShadowHOffset:d,boxShadowVOffset:p,boxShadowBlur:h,boxShadowSpread:m,boxShadowPosition:b,label:f=(0,M.__)("Box Shadow","sureforms"),popup:v=!1,blockId:y,help:_=!1}=e;let k;const S=n?"active":"",C=[g.label,d.label,p.label,h.label,m.label,b.label],T=v&&(()=>{const e=(()=>{const e=s()?.name.split("/").pop();let t=!1;return void 0!==r[e]&&C.forEach(a=>{if(a){const i=void 0!==r[e][a]?.default?r[e][a]?.default:"";t={...t,[a]:i}}}),t})(),t=s()?.attributes;let a=!1;return C.forEach(i=>{t?.[i]&&t?.[i]!==e?.[i]&&(a=!0)}),a})(),E=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:g.title,colorValue:g.value,data:{value:g.value,label:g.label},setAttributes:c}),(0,w.createElement)(Me,{label:d.title,value:d.value,min:-100,max:100,displayUnit:!1,setAttributes:c,data:{value:d.value,label:d.label}}),(0,w.createElement)(Me,{label:p.title,value:p.value,min:-100,max:100,displayUnit:!1,setAttributes:c,data:{value:p.value,label:p.label}}),(0,w.createElement)(Me,{label:h.title,value:h.value,min:0,max:100,displayUnit:!1,setAttributes:c,data:{value:h.value,label:h.label}}),(0,w.createElement)(Me,{label:m.title,value:m.value,min:-100,max:100,displayUnit:!1,setAttributes:c,data:{value:m.value,label:m.label}}),(0,w.createElement)(Ri,{setAttributes:c,label:b.title,data:{value:b.value,label:b.label},options:[{value:"outset",label:(0,M.__)("Outset","sureforms"),tooltip:(0,M.__)("Outset","sureforms")},{value:"inset",label:(0,M.__)("Inset","sureforms"),tooltip:(0,M.__)("Inset (10px)","sureforms")}],showIcons:!1}));n&&(k=(0,w.createElement)("div",{className:"uagb-box-shadow-advanced spectra-control-popup"},E));const D=(0,w.createElement)("div",{className:"spectra-control-popup__options--action-wrapper"},(0,w.createElement)("span",{className:"uag-control-label"},f,T&&(0,w.createElement)("div",{className:"spectra__change-indicator--dot-right"})),(0,w.createElement)(te.Button,{className:"uag-box-shadow-button spectra-control-popup__options--action-button","aria-pressed":n,onClick:()=>{const e=document.querySelectorAll(".spectra-control-popup__options");if(e&&0<e.length)for(let t=0;t<e.length;t++){const a=e[t]?.querySelector(".spectra-control-popup__options.active .spectra-control-popup__options--action-button");a?.click()}o(!n);const t=s()?.name,a=i("uagSettingState");let l={...a,[t]:{...a?.[t],selectedSetting:".uag-box-shadow-options"}};n&&(l={...a,[t]:{...a?.[t],selectedSetting:!1}});const r=i();r&&r.setItem("uagSettingState",JSON.stringify(l))}},(0,w.createElement)(te.Dashicon,{icon:"edit"}))),L=ce(e.label),B=(0,O.applyFilters)(`spectra.${u}.${t}.${L}.before`,"",u),H=(0,O.applyFilters)(`spectra.${u}.${t}.${L}`,"",u);return(0,w.createElement)("div",{ref:l},B,v?(0,w.createElement)("div",{className:` components-base-control uag-box-shadow-options spectra-control-popup__options popup-${y} ${S}`},D,n&&k,(0,w.createElement)(pe,{text:_})):(0,w.createElement)(w.Fragment,null,E),H)};var cs=a(8542),gs={};cs.A&&cs.A.locals&&(gs.locals=cs.A.locals);var ds,ps=0,hs={attributes:{id:"uagb-editor-styles"}};hs.setAttributes=g(),hs.insert=u().bind(null,"head"),hs.domAPI=r(),hs.insertStyleElement=p(),gs.use=function(e){return hs.options=e||{},ps++||(ds=n()(cs.A,hs)),gs},gs.unuse=function(){ps>0&&! --ps&&(ds(),ds=null)};const ms=gs;var bs=a(9810),fs={};bs.A&&bs.A.locals&&(fs.locals=bs.A.locals);var vs,ws=0,ys={attributes:{id:"uagb-editor-styles"}};ys.setAttributes=g(),ys.insert=u().bind(null,"head"),ys.domAPI=r(),ys.insertStyleElement=p(),fs.use=function(e){return ys.options=e||{},ws++||(vs=n()(bs.A,ys)),fs},fs.unuse=function(){ws>0&&! --ws&&(vs(),vs=null)};const xs=fs,_s=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(xs.use(),()=>{xs.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const o=(0,V.useSelect)(()=>(0,V.select)("core/block-editor").getSelectedBlock(),[]),r=e.enableDynamicContent&&e.name?wp.hooks.applyFilters("uagb.registerTextExtender","",o?.name,e.name,e.dynamicContentType):null,s=()=>{if(!e.enableDynamicContent||!e.name)return!1;const t=o?.attributes?.dynamicContent;return!(!t||!0!==t?.[e.name]?.enable)},{isShiftStepEnabled:u}=e;let c=xe(e.unit?.value,e),g=_e(e.unit?.value,e);const d=isNaN(e?.value)?"":e?.value;let p=[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("Em","sureforms"),unitValue:"em"}];e.units&&(p=e.units);const h=t=>{const a=parseFloat(t);e.setAttributes&&e.setAttributes({[e.data.label]:a}),e?.onChange&&e.onChange(a)},m=t=>{e?.onChange&&e?.onChange(t[e?.data?.label]),e.displayUnit&&b(t[e?.unit?.label])},b=t=>{e.setAttributes({[e.unit.label]:t}),c=xe(t,e),g=_e(t,e),e.value>c&&h(c),e.value<g&&h(g)},f=e.inlineControl?"inline":"full-width",v=ce(e?.label),y=(0,O.applyFilters)(`spectra.${n}.${t}.${v}.before`,"",n),_=(0,O.applyFilters)(`spectra.${n}.${t}.${v}`,"",n);return(0,w.createElement)("div",{ref:i,className:"components-base-control uag-number-control uagb-size-type-field-tabs"+(s()?" uagb-text-control--open-dynamic-content":"")},y,e.showControlHeader&&(0,w.createElement)(()=>(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)("div",{className:"uagb-number-control__actions uagb-control__actions"},(0,w.createElement)(ke,{onReset:m,attributeNames:[e.data.label,!!e.displayUnit&&e.unit.label],setAttributes:e.setAttributes}),e.displayUnit&&(0,w.createElement)(te.ButtonGroup,{className:"uagb-control__units","aria-label":(0,M.__)("Select Units","sureforms")},(t=>{const a=[];return t.map(t=>a.push((0,w.createElement)(te.Tooltip,{text:(0,M.sprintf)(/* translators: abbreviation for units */ /* translators: abbreviation for units */ +(0,M.__)("%s units","sureforms"),e.name),onClick:()=>{return t=e,void E("Mobile"===o?{[u.label]:t.unitValue}:"Tablet"===o?{[c.label]:t.unitValue}:{[s.label]:t.unitValue});var t}},e.unitValue)))),t})(F)))),G[o]?G[o]:G.Desktop,(0,w.createElement)("div",{className:"uagb-spacing-control__input-labels"},(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Top","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Right","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Bottom","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label"},(0,M.__)("Left","sureforms")),(0,w.createElement)("span",{className:"uagb-spacing-control__number-label uagb-spacing-control__link-label"}))),(0,w.createElement)(pe,{text:D})),j)},Jo=(0,x.memo)(e=>{const{children:t}=e,a=(0,x.useRef)(null),{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name,o=i("uagSettingState"),[r,s]=(0,x.useState)("style");(0,x.useEffect)(()=>{s((()=>{let e="style";return a?.current?.parentElement?.classList.contains("uagb-tab-content-general")&&(e="general"),a?.current?.parentElement?.classList.contains("uagb-tab-content-advance")&&(e="advance"),e})())},[a]);const u=e?.title?e?.title.toLowerCase().replace(/[^a-zA-Z ]/g,"").replace(/\s+/g,"-"):"",c=n.split("/").pop(),g=(0,O.applyFilters)(`spectra.${c}.${r}.${u}.before`,"",n),d=(0,O.applyFilters)(`spectra.${c}.${r}.${u}`,"",n);return(0,w.createElement)(te.PanelBody,{...e,onToggle:()=>{"enabled"===srfm_spec_blocks_info.collapse_panels&&function(e){const t=[];let a=e.parentNode.firstChild;for(;a;)1===a.nodeType&&a!==e&&a.classList.contains("is-opened")&&t.push(a),a=a.nextSibling;return t}(a.current).forEach(e=>{e.querySelector(".components-button").click()});let e=!1;a?.current?.classList.forEach(function(t){t.includes("uag-advance-panel-body")&&(e=t)});let t="style";a?.current?.parentElement?.classList.contains("uagb-tab-content-general")&&(t="general"),a?.current?.parentElement?.classList.contains("uagb-tab-content-advance")&&(t="advance");const l={...o,[n]:{...o?.[n],selectedPanel:e,selectedTab:t}},r=i();r&&r.setItem("uagSettingState",JSON.stringify(l))},ref:a,className:`uag-advance-panel-body-${u}`},g,t,d)}),Xo=(0,x.memo)(e=>{const{attributes:t,setAttributes:a,deviceType:i}=e,{separatorStyle:l,separatorAlign:n,separatorAlignTablet:o,separatorAlignMobile:r,separatorWidth:s,separatorWidthTablet:u,separatorWidthMobile:c,separatorWidthType:g,separatorColor:d,separatorBorderHeight:p,separatorBorderHeightMobile:h,separatorBorderHeightTablet:m,separatorBorderHeightUnit:b,separatorSize:f,separatorSizeMobile:v,separatorSizeTablet:y,separatorSizeType:x,elementType:_,separatorText:k,separatorTextTag:S,separatorIcon:C,elementPosition:T,elementSpacing:E,elementSpacingTablet:D,elementSpacingMobile:L,elementSpacingUnit:B,elementTextLoadGoogleFonts:H,elementTextFontFamily:A,elementTextFontWeight:R,elementTextFontSize:P,elementTextFontSizeType:z,elementTextFontSizeTablet:O,elementTextFontSizeMobile:F,elementTextLineHeightType:I,elementTextLineHeight:N,elementTextLineHeightTablet:V,elementTextLineHeightMobile:G,elementTextFontStyle:W,elementTextLetterSpacing:U,elementTextLetterSpacingTablet:j,elementTextLetterSpacingMobile:q,elementTextLetterSpacingType:$,elementTextDecoration:Z,elementTextTransform:K,elementColor:Y,elementIconWidth:J,elementIconWidthTablet:X,elementIconWidthMobile:Q,elementIconWidthType:ee,blockTopPadding:ae,blockRightPadding:ie,blockLeftPadding:le,blockBottomPadding:ne,blockTopPaddingTablet:oe,blockRightPaddingTablet:re,blockLeftPaddingTablet:se,blockBottomPaddingTablet:ue,blockTopPaddingMobile:ce,blockRightPaddingMobile:ge,blockLeftPaddingMobile:pe,blockBottomPaddingMobile:he,blockPaddingUnit:me,blockPaddingUnitTablet:be,blockPaddingUnitMobile:fe,blockPaddingLink:ve,blockTopMargin:we,blockRightMargin:ye,blockLeftMargin:xe,blockBottomMargin:_e,blockTopMarginTablet:ke,blockRightMarginTablet:Se,blockLeftMarginTablet:Ce,blockBottomMarginTablet:Me,blockTopMarginMobile:Te,blockRightMarginMobile:Ee,blockLeftMarginMobile:De,blockBottomMarginMobile:Le,blockMarginUnit:Be,blockMarginUnitTablet:He,blockMarginUnitMobile:Ae,blockMarginLink:Re}=t;return(0,w.createElement)("div",null,(0,w.createElement)(Pi.InspectorControls,null,(0,w.createElement)(di,null,(0,w.createElement)(pi,{...hi},(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!0},(0,w.createElement)(de,{label:(0,M.__)("Style","sureforms"),data:{value:l,label:"separatorStyle"},help:"none"!==l&&"dotted"!==l&&"dashed"!==l&&"double"!==l&&"solid"!==l&&(0,M.__)("Note: Please set Separator Height for proper thickness.","sureforms"),setAttributes:a,options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"rectangles",label:(0,M.__)("Rectangles","sureforms")},{value:"parallelogram",label:(0,M.__)("Parallelogram","sureforms")},{value:"slash",label:(0,M.__)("Slash","sureforms")},{value:"leaves",label:(0,M.__)("Leaves","sureforms")}]}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Add Element","sureforms"),data:{value:_,label:"elementType"},options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"text",label:(0,M.__)("Text","sureforms")},{value:"icon",label:(0,M.__)("Icon","sureforms")}],showIcons:!1,responsive:!1}),"text"===_&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Xi,{label:(0,M.__)("Text","sureforms"),data:{value:k,label:"separatorText"},setAttributes:a,value:k}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Heading Tag","sureforms"),data:{value:S,label:"separatorTextTag"},options:[{value:"h1",label:(0,M.__)("H1","sureforms")},{value:"h2",label:(0,M.__)("H2","sureforms")},{value:"h3",label:(0,M.__)("H3","sureforms")},{value:"h4",label:(0,M.__)("H4","sureforms")},{value:"h5",label:(0,M.__)("H5","sureforms")},{value:"h6",label:(0,M.__)("H6","sureforms")},{value:"span",label:(0,M.__)("Span","sureforms")},{value:"p",label:(0,M.__)("P","sureforms")}]})),"icon"===_&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Wo,{label:(0,M.__)("Icon","sureforms"),value:C,onChange:e=>a({separatorIcon:e})}))))),(0,w.createElement)(pi,{...mi},(0,w.createElement)(Jo,{title:"Separator",initialOpen:!0},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),data:{desktop:{value:n,label:"separatorAlign"},tablet:{value:o,label:"separatorAlignTablet"},mobile:{value:r,label:"separatorAlignMobile"}},className:"uagb-multi-button-alignment-control",options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0,responsive:!0}),(0,w.createElement)(Qi,{label:(0,M.__)("Width","sureforms"),data:{desktop:{value:s,label:"separatorWidth"},tablet:{value:u,label:"separatorWidthTablet"},mobile:{value:c,label:"separatorWidthMobile"}},min:0,max:"%"===g?100:500,unit:{value:g,label:"separatorWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:a}),"solid"!==l&&"double"!==l&&"dotted"!==l&&"dashed"!==l&&"none"!==l&&(0,w.createElement)(Qi,{label:(0,M.__)("Size","sureforms"),data:{desktop:{value:f,label:"separatorSize"},tablet:{value:y,label:"separatorSizeTablet"},mobile:{value:v,label:"separatorSizeMobile"}},min:0,max:"%"===x?100:500,unit:{value:x,label:"separatorSizeType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:a}),"none"!==l&&(0,w.createElement)(Qi,{label:(0,M.__)("Separator Height","sureforms"),data:{desktop:{value:p,label:"separatorBorderHeight"},tablet:{value:m,label:"separatorBorderHeightTablet"},mobile:{value:h,label:"separatorBorderHeightMobile"}},min:0,max:"%"===x?100:500,unit:{value:b,label:"separatorBorderHeightUnit"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:a}),"none"!==l&&(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:d||"",data:{value:d,label:"separatorColor"},setAttributes:a})),"none"!==_&&(0,w.createElement)(Jo,{title:"text"===_?(0,M.__)("Text","sureforms"):(0,M.__)("Icon","sureforms"),initialOpen:!1},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),responsive:!0,data:{desktop:{value:T,label:"elementPosition"},tablet:{value:T,label:"elementPosition"},mobile:{value:T,label:"elementPosition"}},className:"uagb-multi-button-alignment-control",options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:Y||"",data:{value:Y,label:"elementColor"},setAttributes:a}),"text"===_&&(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:a,loadGoogleFonts:{value:H,label:"elementTextLoadGoogleFonts"},fontFamily:{value:A,label:"elementTextFontFamily"},fontWeight:{value:R,label:"elementTextFontWeight"},fontStyle:{value:W,label:"elementTextFontStyle"},fontSizeType:{value:z,label:"elementTextFontSizeType"},fontSize:{value:P,label:"elementTextFontSize"},fontSizeMobile:{value:F,label:"elementTextFontSizeMobile"},fontSizeTablet:{value:O,label:"elementTextFontSizeTablet"},lineHeightType:{value:I,label:"elementTextLineHeightType"},lineHeight:{value:N,label:"elementTextLineHeight"},lineHeightMobile:{value:G,label:"elementTextLineHeightMobile"},lineHeightTablet:{value:V,label:"elementTextLineHeightTablet"},letterSpacing:{value:U,label:"elementTextLetterSpacing"},letterSpacingTablet:{value:j,label:"elementTextLetterSpacingTablet"},letterSpacingMobile:{value:q,label:"elementTextLetterSpacingMobile"},letterSpacingType:{value:$,label:"elementTextLetterSpacingType"},transform:{value:K,label:"elementTextTransform"},decoration:{value:Z,label:"elementTextDecoration"}}),"icon"===_&&(0,w.createElement)(Qi,{label:(0,M.__)("Icon Size","sureforms"),data:{desktop:{value:J,label:"elementIconWidth"},tablet:{value:X,label:"elementIconWidthTablet"},mobile:{value:Q,label:"elementIconWidthMobile"}},min:0,max:100,unit:{value:ee,label:"elementIconWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("EM","sureforms"),unitValue:"em"}],setAttributes:a}),(0,w.createElement)(Qi,{label:(0,M.__)("Spacing","sureforms"),data:{desktop:{value:E,label:"elementSpacing"},tablet:{value:D,label:"elementSpacingTablet"},mobile:{value:L,label:"elementSpacingMobile"}},min:0,max:500,unit:{value:B,label:"elementSpacingUnit"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:a})),(0,w.createElement)(Jo,{title:(0,M.__)("Spacing","sureforms"),initialOpen:!1},(0,w.createElement)(Yo,{label:(0,M.__)("Padding","sureforms"),valueTop:{value:ae,label:"blockTopPadding"},valueRight:{value:ie,label:"blockRightPadding"},valueBottom:{value:ne,label:"blockBottomPadding"},valueLeft:{value:le,label:"blockLeftPadding"},valueTopTablet:{value:oe,label:"blockTopPaddingTablet"},valueRightTablet:{value:re,label:"blockRightPaddingTablet"},valueBottomTablet:{value:ue,label:"blockBottomPaddingTablet"},valueLeftTablet:{value:se,label:"blockLeftPaddingTablet"},valueTopMobile:{value:ce,label:"blockTopPaddingMobile"},valueRightMobile:{value:ge,label:"blockRightPaddingMobile"},valueBottomMobile:{value:he,label:"blockBottomPaddingMobile"},valueLeftMobile:{value:pe,label:"blockLeftPaddingMobile"},unit:{value:me,label:"blockPaddingUnit"},mUnit:{value:fe,label:"blockPaddingUnitMobile"},tUnit:{value:be,label:"blockPaddingUnitTablet"},deviceType:i,attributes:t,setAttributes:a,link:{value:ve,label:"blockPaddingLink"}}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:we,label:"blockTopMargin"},valueRight:{value:ye,label:"blockRightMargin"},valueBottom:{value:_e,label:"blockBottomMargin"},valueLeft:{value:xe,label:"blockLeftMargin"},valueTopTablet:{value:ke,label:"blockTopMarginTablet"},valueRightTablet:{value:Se,label:"blockRightMarginTablet"},valueBottomTablet:{value:Me,label:"blockBottomMarginTablet"},valueLeftTablet:{value:Ce,label:"blockLeftMarginTablet"},valueTopMobile:{value:Te,label:"blockTopMarginMobile"},valueRightMobile:{value:Ee,label:"blockRightMarginMobile"},valueBottomMobile:{value:Le,label:"blockBottomMarginMobile"},valueLeftMobile:{value:De,label:"blockLeftMarginMobile"},unit:{value:Be,label:"blockMarginUnit"},mUnit:{value:Ae,label:"blockMarginUnitMobile"},tUnit:{value:He,label:"blockMarginUnitTablet"},deviceType:i,attributes:t,setAttributes:a,link:{value:Re,label:"blockMarginLink"}}))))))}),Qo=(0,x.memo)(e=>{const{attributes:{block_id:t,elementType:a,separatorText:i,separatorTextTag:l,separatorStyle:n,separatorIcon:o},className:r,deviceType:s}=e,u=function(e){const t={rectangles:"url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.4 0H16L9.6 16H0L6.4 0Z' fill='black'/%3E%3C/svg%3E\")",parallelogram:"url(\"data:image/svg+xml,%3Csvg width='8' height='16' viewBox='0 0 8 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Crect width='8' height='16' fill='black'/%3E%3C/svg%3E\")",slash:"url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.29312 16.9999L17 6.29302M14.2931 16.9999L17 14.293M-0.707031 15.9999L16.0002 -0.707153M8.00017 -0.707153L-0.706882 7.9999' stroke='black'/%3E%3C/svg%3E\")",leaves:"url(\"data:image/svg+xml,%3Csvg width='16' height='16' viewBox='0 0 16 16' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg clip-path='url(%23clip0_2356_5631)'%3E%3Cpath d='M15 1C10.5 1 9 2.5 9 7C13.5 7 15 5.5 15 1Z' stroke='black'/%3E%3Cpath d='M1 1C5.5 1 7 2.5 7 7C2.5 7 1 5.5 1 1Z' stroke='black'/%3E%3Cpath d='M15 15C10.5 15 9 13.5 9 9C13.5 9 15 10.5 15 15Z' stroke='black'/%3E%3Cpath d='M1 15C5.5 15 7 13.5 7 9C2.5 9 1 10.5 1 15Z' stroke='black'/%3E%3C/g%3E%3Cdefs%3E%3CclipPath id='clip0_2356_5631'%3E%3Crect width='16' height='16' fill='white'/%3E%3C/clipPath%3E%3C/defs%3E%3C/svg%3E\")"};return e in t?t[e]:""}(n),c=`${l}`,g="none"!==a?"wp-block-uagb-separator--"+a:"",d=(0,Pi.useBlockProps)({className:ue([r,`uagb-editor-preview-mode-${s.toLowerCase()}`,`uagb-block-${t}`,g])});return(0,w.createElement)("div",{...d},(0,w.createElement)("div",{className:ue([`uagb-editor-preview-mode-${s.toLowerCase()}`,`uagb-block-${t}`,"wp-block-uagb-separator","none"!==a?"wp-block-uagb-separator--"+a:""])},(0,w.createElement)("div",{className:"wp-block-uagb-separator__inner",style:{"--my-background-image":`${u}`}},"none"!==a&&(0,w.createElement)("div",{className:"wp-block-uagb-separator-element"},"icon"===a?zi(o):(0,w.createElement)(c,{className:"uagb-html-tag"},i)))))}),er=e=>e.reduce((e,t)=>{if(t?.attributes?.block_id&&t.name.includes("srfm")&&(e.blockIds.push(t.attributes.block_id),e.clientIds.push(t.clientId)),t.innerBlocks){const{blockIds:a,clientIds:i}=er(t.innerBlocks);e.blockIds=[...e.blockIds,...a],e.clientIds=[...e.clientIds,...i]}return e},{blockIds:[],clientIds:[]}),tr=e=>t=>{const{name:a,setAttributes:i,clientId:l,attributes:{block_id:n}}=t,o=["uagb/faq","uagb/buttons","uagb/icon-list","uagb/restaurant-menu","uagb/social-share","uagb/content-timeline","uagb/tabs","uagb/how-to"];return(0,x.useEffect)(()=>{srfm_spec_blocks_info.is_customize_preview&&("0"===n||void 0===n)&&o.includes(a)&&document.addEventListener(`UAG-${a}-${l.substr(0,8)}-BlockCustomizeWidgetEditor`,function(e){i({block_id:e.detail.id,classMigrate:e.detail.classMigrate,childMigrate:e.detail.childMigrate})})},[]),(0,x.useEffect)(()=>{if(srfm_spec_blocks_info.is_customize_preview&&("0"===n||void 0===n)&&o.includes(a)){const e=new CustomEvent(`UAG-${a}-${l.substr(0,8)}-BlockCustomizeWidgetEditor`,{detail:{id:l.substr(0,8),classMigrate:!0,childMigrate:!0}});document.dispatchEvent(e)}},[t.attributes]),(0,x.useEffect)(()=>{const e={block_id:l.substr(0,8)};if(["uagb/post-carousel","uagb/post-grid","uagb/post-masonry"].includes(a)&&(e.allTaxonomyStore=void 0),["uagb/countdown"].includes(a)&&(e.editorInnerblocksPreview=!1),["uagb/cf7-styler","uagb/gf-styler"].includes(a)&&(e.isHtml=!1),["uagb/buttons","uagb/icon-list","uagb/restaurant-menu","uagb/social-share","uagb/content-timeline","uagb/instagram-feed"].includes(a)&&(e.childMigrate=!0),["uagb/advanced-heading","uagb/blockquote","uagb/buttons","uagb/call-to-action","uagb/column","uagb/columns","uagb/icon-list","uagb/marketing-button","uagb/image-gallery","uagb/info-box","uagb/lottie","uagb/restaurant-menu","uagb/section","uagb/social-share","uagb/content-timeline","uagb/table-of-contents","uagb/team","uagb/testimonial","uagb/instagram-feed","uagb/login","uagb/register"].includes(a)&&(e.classMigrate=!0),["uagb/image-gallery","srfm/separator","srfm/icon","srfm/image"].includes(a))i(e);else{const t=(0,V.select)("core/block-editor")?.getBlocks(),{blockIds:a,clientIds:o}=t?er(t):{blockIds:[],clientIds:[]};"not_set"!==n&&"0"!==n&&n&&!((e,t,a)=>e.filter(e=>e===t).length>1&&a===e.lastIndexOf(t))(a,n,o.indexOf(l))||i(e)}},[l]),(0,w.createElement)(e,{...t})},ar=(0,X.compose)(ee,tr)(e=>{const{isSelected:t,attributes:a,attributes:{UAGHideDesktop:i,UAGHideTab:l,UAGHideMob:n},name:o,clientId:r,deviceType:s}=e;(0,x.useEffect)(()=>{N(e)},[i,l,n,s]),(0,x.useEffect)(()=>{G()},[s]);const u=(0,x.useMemo)(()=>function(e,t,a,i){const l=a.replace("srfm/",""),n=i.toLowerCase(),{block_id:o,separatorAlign:r,separatorAlignTablet:s,separatorAlignMobile:u,separatorStyle:c,separatorColor:g,separatorWidth:d,separatorWidthTablet:p,separatorWidthMobile:h,separatorWidthType:m,separatorBorderHeight:b,separatorBorderHeightMobile:f,separatorBorderHeightTablet:v,separatorBorderHeightUnit:w,separatorSize:y,separatorSizeTablet:x,separatorSizeMobile:_,separatorSizeType:k,elementType:S,elementPosition:C,elementSpacing:M,elementSpacingTablet:T,elementSpacingMobile:L,elementSpacingUnit:B,elementTextFontFamily:H,elementTextFontWeight:A,elementTextFontSize:R,elementTextFontSizeType:P,elementTextFontSizeTablet:z,elementTextFontSizeMobile:O,elementTextLineHeightType:N,elementTextLineHeight:V,elementTextLineHeightTablet:G,elementTextLineHeightMobile:W,elementTextFontStyle:U,elementTextLetterSpacing:j,elementTextLetterSpacingTablet:q,elementTextLetterSpacingMobile:$,elementTextLetterSpacingType:Z,elementTextDecoration:K,elementTextTransform:Y,elementColor:J,elementIconWidth:X,elementIconWidthTablet:Q,elementIconWidthMobile:ee,elementIconWidthType:te,blockTopPadding:ae,blockRightPadding:ie,blockLeftPadding:le,blockBottomPadding:ne,blockTopPaddingTablet:oe,blockRightPaddingTablet:re,blockLeftPaddingTablet:se,blockBottomPaddingTablet:ue,blockTopPaddingMobile:ce,blockRightPaddingMobile:ge,blockLeftPaddingMobile:de,blockBottomPaddingMobile:pe,blockPaddingUnit:he,blockPaddingUnitTablet:me,blockPaddingUnitMobile:be,blockTopMargin:fe,blockRightMargin:ve,blockLeftMargin:we,blockBottomMargin:ye,blockTopMarginTablet:xe,blockRightMarginTablet:_e,blockLeftMarginTablet:ke,blockBottomMarginTablet:Se,blockTopMarginMobile:Ce,blockRightMarginMobile:Me,blockLeftMarginMobile:Te,blockBottomMarginMobile:Ee,blockMarginUnit:De,blockMarginUnitTablet:Le,blockMarginUnitMobile:Be}=e,He=F(d,"separatorWidth",l),Ae=F(p,"separatorWidthTablet",l),Re=F(h,"separatorWidthMobile",l),Pe=F(b,"separatorBorderHeight",l),ze=F(f,"separatorBorderHeightMobile",l),Oe=F(v,"separatorBorderHeightTablet",l),Fe=F(y,"separatorSize",l),Ie=F(x,"separatorSizeTablet",l),Ne=F(_,"separatorSizeMobile",l),Ve={"border-top-width":D(Pe,w),"-webkit-mask-size":`${D(Fe,k)} 100%`,width:D(He,m),"border-top-color":g,"border-top-style":c};let Ge={};const We={};if("none"===S)Ge={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{"margin-top":"5px","margin-bottom":"5px",...Ve}};else{const e=I(r);Ge={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{width:D(He,m),...e},".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before":Ve,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before":Ve,".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after":Ve,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after":Ve},"left"===C&&(We[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(M,B)},Ge[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before"]={display:"none"},Ge[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before"]={display:"none"}),"right"===C&&(We[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(M,B)},Ge[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after"]={display:"none"},Ge[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after"]={display:"none"}),"center"===C&&(We[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(M,B),"margin-left":D(M,B)})}const Ue={...Ge,...We,".wp-block-uagb-separator--text .wp-block-uagb-separator-element .uagb-html-tag":{"font-family":H,"font-style":U,"text-decoration":K,"text-transform":Y,"font-weight":A,"font-size":D(R,P),"line-height":D(V,N),"letter-spacing":D(j,Z),color:J,margin:0},".wp-block-uagb-separator--icon .wp-block-uagb-separator-element svg":{"font-size":D(X,te),width:D(X,te),height:D(X,te),"line-height":D(X,te),color:J,fill:J},".wp-block-srfm-separator":{"margin-top":D(fe,De||"px"),"margin-right":D(ve,De||"px"),"margin-bottom":D(ye,De||"px"),"margin-left":D(we,De||"px")},".wp-block-uagb-separator":{"padding-top":D(ae,he||"px"),"padding-right":D(ie,he||"px"),"padding-bottom":D(ne,he||"px"),"padding-left":D(le,he||"px"),"text-align":r}},je={"border-top-width":D(Oe,w),"-webkit-mask-size":`${D(Ie,k)} 100%`,width:D(Ae,m),"border-top-color":g,"border-top-style":c};let qe={};const $e={};if("none"===S)qe={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{"margin-top":"5px","margin-bottom":"5px",...je}};else{const e=I(s);qe={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{width:D(Ae,m),...e},".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before":je,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before":je,".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after":je,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after":je},"left"===C&&($e[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(T,B)},qe[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before"]={display:"none"},qe[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before"]={display:"none"}),"center"===C&&($e[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(T,B),"margin-right":D(T,B)}),"right"===C&&($e[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(T,B)},qe[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after"]={display:"none"},qe[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after"]={display:"none"})}const Ze={...qe,...$e,".wp-block-uagb-separator--text .wp-block-uagb-separator-element .uagb-html-tag":{"font-family":H,"font-style":U,"text-decoration":K,"text-transform":Y,"font-weight":A,"font-size":D(z,P),"line-height":D(G,N),"letter-spacing":D(q,Z),color:J,margin:0},".wp-block-uagb-separator--icon .wp-block-uagb-separator-element svg":{"font-size":D(Q,te),width:D(Q,te),height:D(Q,te),"line-height":D(Q,te),color:J,fill:J},".wp-block-srfm-separator":{"margin-top":D(xe,Le||"px"),"margin-right":D(_e,Le||"px"),"margin-bottom":D(Se,Le||"px"),"margin-left":D(ke,Le||"px")},".wp-block-uagb-separator":{"padding-top":D(oe,me||"px"),"padding-right":D(re,me||"px"),"padding-bottom":D(ue,me||"px"),"padding-left":D(se,me||"px"),"text-align":s}},Ke={"border-top-width":D(ze,w),"-webkit-mask-size":`${D(Ne,k)} 100%`,width:D(Re,m),"border-top-color":g,"border-top-style":c};let Ye={};const Je={};if("none"===S)Ye={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{"margin-top":"5px","margin-bottom":"5px",...Ke}};else{const e=I(u);Ye={".wp-block-uagb-separator .wp-block-uagb-separator__inner":{width:D(Re,m),...e},".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before":Ke,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before":Ke,".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after":Ke,".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after":Ke},"left"===C&&(Je[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-right":D(L,B)},Ye[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::before"]={display:"none"},Ye[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::before"]={display:"none"}),"center"===C&&(Je[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(L,B),"margin-right":D(L,B)}),"right"===C&&(Je[".wp-block-uagb-separator .wp-block-uagb-separator__inner .wp-block-uagb-separator-element"]={"margin-left":D(L,B)},Ye[".wp-block-uagb-separator--text .wp-block-uagb-separator__inner::after"]={display:"none"},Ye[".wp-block-uagb-separator--icon .wp-block-uagb-separator__inner::after"]={display:"none"})}const Xe={...Ye,...Je,".wp-block-uagb-separator--text .wp-block-uagb-separator-element .uagb-html-tag":{"font-family":H,"font-style":U,"text-decoration":K,"text-transform":Y,"font-weight":A,"font-size":D(O,P),"line-height":D(W,N),"letter-spacing":D($,Z),color:J,margin:0},".wp-block-uagb-separator--icon .wp-block-uagb-separator-element svg":{"font-size":D(ee,te),width:D(ee,te),height:D(ee,te),"line-height":D(ee,te),color:J,fill:J},".wp-block-srfm-separator":{"margin-top":D(Ce,Be||"px"),"margin-right":D(Me,Be||"px"),"margin-bottom":D(Ee,Be||"px"),"margin-left":D(Te,Be||"px")},".wp-block-uagb-separator":{"padding-top":D(ce,be||"px"),"padding-right":D(ge,be||"px"),"padding-bottom":D(pe,be||"px"),"padding-left":D(de,be||"px"),"text-align":u}},Qe=`.editor-styles-wrapper .uagb-block-${o}`;let et=E(Ue,Qe);return"tablet"!==n&&"mobile"!==n||(et+=E(Ze,`${Qe}`,!0,"tablet"),"mobile"===n&&(et+=E(Xe,`${Qe}`,!0,"mobile"))),et}(a,0,o,s),[a,s]);return(0,w.createElement)(w.Fragment,null,(0,w.createElement)(W,{blockStyling:u}),(0,w.createElement)(J,{attributes:a}),t&&(0,w.createElement)(Xo,{...e}),(0,w.createElement)(Qo,{...e}))}),ir=window.wp.blocks,lr=({image:e,isChildren:t=!1})=>{e||console.error(__("Please add preview image.","sureforms"));let a=srfm_spec_blocks_info.srfm_url;return a+="/images/field-previews/",t&&(a+="children/"),a+=e+".svg",(0,w.createElement)("img",{width:"100%",src:a,alt:""})},nr=function(e={}){let t={example:{attributes:{isPreview:!0}},usesContext:["postId","postType"]};return"site-editor"===srfm_spec_blocks_info.is_site_editor&&(t={}),(0,O.applyFilters)("addCommonDataToSpectraBlocks",{...e,...t})},or=(0,O.applyFilters)("srfm/separator",nr({}));(0,ir.registerBlockType)("srfm/separator",{...or,apiVersion:3,title:(0,M.__)("Separator","sureforms"),description:(0,M.__)("Add a modern separator to divide your page content with icon/text.","sureforms"),supports:{html:!1},icon:C.separator,category:srfm_spec_blocks_info.category,keywords:[(0,M.__)("divider","sureforms"),(0,M.__)("separator","sureforms")],attributes:T,edit:e=>e.attributes.isPreview?(0,w.createElement)(lr,{image:"separator"}):(0,w.createElement)(ar,{...e}),save:()=>null});var rr=a(6323),sr={};rr.A&&rr.A.locals&&(sr.locals=rr.A.locals);var ur,cr=0,gr={attributes:{id:"uagb-editor-styles"}};gr.setAttributes=g(),gr.insert=u().bind(null,"head"),gr.domAPI=r(),gr.insertStyleElement=p(),sr.use=function(e){return gr.options=e||{},cr++||(ur=n()(rr.A,gr)),sr},sr.unuse=function(){cr>0&&! --cr&&(ur(),ur=null)};const dr=sr,pr=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null),{getSelectedBlock:l}=(0,V.select)("core/block-editor");(0,x.useLayoutEffect)(()=>(dr.use(),()=>{dr.unuse()}),[]);const{setAttributes:n,gradientType:o,backgroundGradient:r,backgroundGradientColor2:s,backgroundGradientColor1:u,backgroundGradientType:c,backgroundGradientLocation1:g,backgroundGradientLocation2:d,backgroundGradientAngle:p}=e,h=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[h]);const m="gradient-settings",b=(0,O.applyFilters)(`spectra.${h}.${t}.${m}.before`,"",h),f=(0,O.applyFilters)(`spectra.${h}.${t}.${m}`,"",h),v=void 0!==o?o.value:"basic";return(0,w.createElement)(w.Fragment,null,void 0!==o&&(0,w.createElement)(Ri,{setAttributes:n,label:"Select Gradient",data:{value:o.value,label:o.label},options:[{value:"basic",label:(0,M.__)("Basic","sureforms")},{value:"advanced",label:(0,M.__)("Advanced","sureforms")}],showIcons:!1}),(0,w.createElement)("div",{ref:i},b,"basic"===v&&(0,w.createElement)(te.GradientPicker,{__nextHasNoMargin:!0,value:r?.value||null,onChange:e=>{n({[r.label]:e})},className:"uagb-gradient-picker",gradients:[]}),f),"advanced"===v&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:(0,M.__)("Color 1","sureforms"),colorValue:u.value?u.value:"",data:{value:u.value,label:u.label},setAttributes:n}),(0,w.createElement)(Ti,{label:(0,M.__)("Color 2","sureforms"),colorValue:s.value?s.value:"",data:{value:s.value,label:s.label},setAttributes:n}),(0,w.createElement)(Ri,{setAttributes:n,label:(0,M.__)("Type","sureforms"),data:{value:c.value,label:c.label},className:"uagb-multi-button-alignment-control",options:[{value:"linear",label:(0,M.__)("Linear","sureforms")},{value:"radial",label:(0,M.__)("Radial","sureforms")}]}),(0,w.createElement)(Me,{label:(0,M.__)("Location 1","sureforms"),setAttributes:n,value:g.value,data:{value:g.value,label:g.label},min:0,max:100,displayUnit:!1}),(0,w.createElement)(Me,{label:(0,M.__)("Location 2","sureforms"),setAttributes:n,value:d.value,data:{value:d.value,label:d.label},min:0,max:100,displayUnit:!1}),"linear"===c.value&&(0,w.createElement)(Me,{label:(0,M.__)("Angle","sureforms"),setAttributes:n,value:p.value,data:{value:p.value,label:p.label},min:0,max:360,displayUnit:!1})))};var hr=a(5001),mr={};hr.A&&hr.A.locals&&(mr.locals=hr.A.locals);var br,fr=0,vr={attributes:{id:"uagb-editor-styles"}};vr.setAttributes=g(),vr.insert=u().bind(null,"head"),vr.domAPI=r(),vr.insertStyleElement=p(),mr.use=function(e){return vr.options=e||{},fr++||(br=n()(hr.A,vr)),mr},mr.unuse=function(){fr>0&&! --fr&&(br(),br=null)};const wr=mr;function yr({label:e,type:t,classic:a,gradient:i,setAttributes:l}){const[n,o]=(0,x.useState)(null),r=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(wr.use(),()=>{wr.unuse()}),[]);const{getSelectedBlock:s}=(0,V.select)("core/block-editor"),u=s()?.name.split("/").pop();(0,x.useEffect)(()=>{o(se(r))},[u]);const c=ce(e),g=(0,O.applyFilters)(`spectra.${u}.${n}.${c}.before`,"",u),d=(0,O.applyFilters)(`spectra.${u}.${n}.${c}`,"",u);return(0,w.createElement)("div",{ref:r,className:"components-base-control"},g,(0,w.createElement)("div",{className:"uagb-color-switch-control-container"},(0,w.createElement)(Ri,{setAttributes:l,label:e,data:t,className:"uagb-multi-button-alignment-control",options:[{value:"classic",label:(0,M.__)("Classic","sureforms")},{value:"gradient",label:(0,M.__)("Gradient","sureforms")}],showIcons:!1}),"classic"===t.value?(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:a.value,data:{value:a.value,label:a.label},setAttributes:l}):(0,w.createElement)(pr,{backgroundGradient:i,setAttributes:l})),d)}const xr=e=>{const[t,a]=(0,x.useState)(!1),[l,n]=(0,x.useState)(null),o=(0,x.useRef)(null),{setAttributes:r,textShadowColor:s,textShadowHOffset:u,textShadowVOffset:c,textShadowBlur:g,label:d=(0,M.__)("Text Shadow","sureforms"),popup:p=!1,blockId:h,help:m=!1}=e;let b;const f=t?"active":"";(0,x.useLayoutEffect)(()=>{window.addEventListener("click",function(e){const t=document.querySelector(`.active.popup-${h} .spectra-control-popup__options--action-button`),l=document.querySelector(`.active.popup-${h} .spectra-control-popup`);if(t&&!t?.contains(e.target)&&!e.target?.classList?.contains("uagb-advanced-color-indicate")&&!e.target?.parentElement?.closest(".uagb-popover-color")&&l&&!l?.contains(e.target)&&!e.target?.parentElement?.closest(".uagb-reset")){a(!1);const e=y()?.name,t=i("uagSettingState"),l={...t,[e]:{...t?.[e],selectedSetting:!1}},n=i();n&&n.setItem("uagSettingState",JSON.stringify(l))}})},[]);const v=[s.label,u.label,c.label,g.label],{getSelectedBlock:y}=(0,V.select)("core/block-editor"),_=y()?.name.split("/").pop();(0,x.useEffect)(()=>{n(se(o))},[_]);const k=p&&(()=>{const e=(()=>{const e=y()?.name.split("/").pop();let t=!1;return void 0!==z[e]&&v.forEach(a=>{if(a){const i=void 0!==z[e][a]?.default?z[e][a]?.default:"";t={...t,[a]:i}}}),t})(),t=y()?.attributes;let a=!1;return v.forEach(i=>{t?.[i]&&t?.[i]!==e?.[i]&&(a=!0)}),a})(),S=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:s.title,colorValue:s.value,data:{value:s.value,label:s.label},setAttributes:r}),(0,w.createElement)(Me,{label:u.title,value:u.value,min:-100,max:100,displayUnit:!1,setAttributes:r,data:{value:u.value,label:u.label}}),(0,w.createElement)(Me,{label:c.title,value:c.value,min:-100,max:100,displayUnit:!1,setAttributes:r,data:{value:c.value,label:c.label}}),(0,w.createElement)(Me,{label:g.title,value:g.value,min:0,max:100,displayUnit:!1,setAttributes:r,data:{value:g.value,label:g.label}}));t&&(b=(0,w.createElement)("div",{className:"uagb-text-shadow-advanced spectra-control-popup"},S));const C=(0,w.createElement)("div",{className:"spectra-control-popup__options--action-wrapper"},(0,w.createElement)("span",{className:"uag-control-label"},d,k&&(0,w.createElement)("div",{className:"spectra__change-indicator--dot-right"})),(0,w.createElement)(te.Button,{className:"uag-text-shadow-button spectra-control-popup__options--action-button","aria-pressed":t,onClick:()=>{const e=document.querySelectorAll(".spectra-control-popup__options");if(e&&0<e.length)for(let t=0;t<e.length;t++){const a=e[t]?.querySelector(".spectra-control-popup__options.active .spectra-control-popup__options--action-button");a?.click()}a(!t);const l=y()?.name,n=i("uagSettingState");let o={...n,[l]:{...n?.[l],selectedSetting:".uag-text-shadow-options"}};t&&(o={...n,[l]:{...n?.[l],selectedSetting:!1}});const r=i();r&&r.setItem("uagSettingState",JSON.stringify(o))}},(0,w.createElement)(te.Dashicon,{icon:"edit"}))),T=ce(e.label),E=(0,O.applyFilters)(`spectra.${_}.${l}.${T}.before`,"",_),D=(0,O.applyFilters)(`spectra.${_}.${l}.${T}`,"",_);return(0,w.createElement)("div",{ref:o,className:p?"components-base-control":""},E,p?(0,w.createElement)("div",{className:` uag-text-shadow-options spectra-control-popup__options popup-${h} ${f}`},C,t&&b):(0,w.createElement)(w.Fragment,null,S),(0,w.createElement)(pe,{text:m}),D)};var _r=a(8619),kr={};_r.A&&_r.A.locals&&(kr.locals=_r.A.locals);var Sr,Cr=0,Mr={attributes:{id:"uagb-editor-styles"}};Mr.setAttributes=g(),Mr.insert=u().bind(null,"head"),Mr.domAPI=r(),Mr.insertStyleElement=p(),kr.use=function(e){return Mr.options=e||{},Cr++||(Sr=n()(_r.A,Mr)),kr},kr.unuse=function(){Cr>0&&! --Cr&&(Sr(),Sr=null)};const Tr=kr,Er=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Tr.use(),()=>{Tr.unuse()}),[]);const{getSelectedBlock:n}=(0,V.select)("core/block-editor"),o=n()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[o]);const r=(0,x.useRef)(null),s=3===e.tabs.length?"uag-control-tabs-three-tabs ":"",u=e.tabs.map((e,t)=>({...e,className:`uagb-tab-${t+1} ${e?.name}`})),c="tabs",g=(0,O.applyFilters)(`spectra.${o}.${t}.${c}.before`,"",o),d=(0,O.applyFilters)(`spectra.${o}.${t}.${c}`,"",o);return(0,w.createElement)("div",{ref:l},g,(0,w.createElement)(te.TabPanel,{className:`uag-control-tabs ${s}`,activeClass:"active-tab",tabs:u,ref:r,onSelect:e=>{const t=document.getElementsByClassName("uag-control-tabs")[0]?.querySelector(`.${e}`);let a=!1;t&&t?.classList&&t?.classList.forEach(e=>{e.includes("uagb-tab")&&(a=`.${e}`)});const l=n()?.name,o=i("uagSettingState"),r={...o,[l]:{...o?.[l],selectedInnerTab:a}},s=i();s&&s.setItem("uagSettingState",JSON.stringify(r))}},t=>(0,w.createElement)("div",{className:"uag-control-tabs-output"},e[t.name])),!e?.disableBottomSeparator&&(0,w.createElement)(Ui,null),(0,w.createElement)(pe,{text:e.help}),d)},Dr={prefix:j().string,borderStyleLabel:j().string,borderWidthLabel:j().string,borderRadiusLabel:j().string,borderColorLabel:j().string},Lr={borderStyleLabel:(0,M.__)("Style","sureforms"),borderWidthLabel:(0,M.__)("Width","sureforms"),borderRadiusLabel:(0,M.__)("Radius","sureforms"),borderColorLabel:(0,M.__)("Color","sureforms"),borderHoverColorLabel:(0,M.__)("Color","sureforms")},Br=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null),{attributes:l,setAttributes:n,disabledBorderTitle:o,disableBottomSeparator:r,deviceType:s,prefix:u,borderStyleLabel:c,borderWidthLabel:g,borderRadiusLabel:d,borderColorLabel:p,borderHoverColorLabel:h,showWidth:m,label:b=(0,M.__)("Border","sureforms"),normalTabLabel:f=(0,M.__)("Normal","sureforms"),hoverTabLabel:v=(0,M.__)("Hover","sureforms"),borderRadiusHelp:y,help:_=!1}=e,{getSelectedBlock:k}=(0,V.select)("core/block-editor"),S=k()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[S]);const C=[{name:"normal",title:f}];C.push({name:"hover",title:v});const T=l[u+"BorderStyle"],E=(0,w.createElement)(Ti,{label:p,colorValue:l[u+"BorderColor"]?l[u+"BorderColor"]:"",data:{value:l[u+"BorderColor"],label:u+"BorderColor"},setAttributes:n}),D=(0,w.createElement)(Ti,{label:h,colorValue:l[u+"BorderHColor"]?l[u+"BorderHColor"]:"",data:{value:l[u+"BorderHColor"],label:u+"BorderHColor"},setAttributes:n}),L=(0,w.createElement)(w.Fragment,null,!o&&(0,w.createElement)("p",{className:"spectra-panel__body-sub-heading"},b),(0,w.createElement)(de,{label:c,data:{value:T,label:u+"BorderStyle"},setAttributes:n,options:[{value:"default",label:(0,M.__)("Default","sureforms")},{value:"none",label:(0,M.__)("None","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"groove",label:(0,M.__)("Groove","sureforms")},{value:"inset",label:(0,M.__)("Inset","sureforms")},{value:"outset",label:(0,M.__)("Outset","sureforms")},{value:"ridge",label:(0,M.__)("Ridge","sureforms")}]}),"default"!==T&&"none"!==T&&!1!==m&&(0,w.createElement)(Yo,{label:g,valueTop:{value:l[u+"BorderTopWidth"],label:u+"BorderTopWidth"},valueRight:{value:l[u+"BorderRightWidth"],label:u+"BorderRightWidth"},valueBottom:{value:l[u+"BorderBottomWidth"],label:u+"BorderBottomWidth"},valueLeft:{value:l[u+"BorderLeftWidth"],label:u+"BorderLeftWidth"},valueTopTablet:{value:l[u+"BorderTopWidthTablet"],label:u+"BorderTopWidthTablet"},valueRightTablet:{value:l[u+"BorderRightWidthTablet"],label:u+"BorderRightWidthTablet"},valueBottomTablet:{value:l[u+"BorderBottomWidthTablet"],label:u+"BorderBottomWidthTablet"},valueLeftTablet:{value:l[u+"BorderLeftWidthTablet"],label:u+"BorderLeftWidthTablet"},valueTopMobile:{value:l[u+"BorderTopWidthMobile"],label:u+"BorderTopWidthMobile"},valueRightMobile:{value:l[u+"BorderRightWidthMobile"],label:u+"BorderRightWidthMobile"},valueBottomMobile:{value:l[u+"BorderBottomWidthMobile"],label:u+"BorderBottomWidthMobile"},valueLeftMobile:{value:l[u+"BorderLeftWidthMobile"],label:u+"BorderLeftWidthMobile"},disableUnits:!0,deviceType:s,attributes:l,setAttributes:n,link:{value:l[u+"BorderLink"],label:u+"BorderLink"},min:0}),"default"!==T&&(0,w.createElement)(Yo,{label:d,valueTop:{value:l[u+"BorderTopLeftRadius"],label:u+"BorderTopLeftRadius"},valueRight:{value:l[u+"BorderTopRightRadius"],label:u+"BorderTopRightRadius"},valueBottom:{value:l[u+"BorderBottomRightRadius"],label:u+"BorderBottomRightRadius"},valueLeft:{value:l[u+"BorderBottomLeftRadius"],label:u+"BorderBottomLeftRadius"},valueTopTablet:{value:l[u+"BorderTopLeftRadiusTablet"],label:u+"BorderTopLeftRadiusTablet"},valueRightTablet:{value:l[u+"BorderTopRightRadiusTablet"],label:u+"BorderTopRightRadiusTablet"},valueBottomTablet:{value:l[u+"BorderBottomRightRadiusTablet"],label:u+"BorderBottomRightRadiusTablet"},valueLeftTablet:{value:l[u+"BorderBottomLeftRadiusTablet"],label:u+"BorderBottomLeftRadiusTablet"},valueTopMobile:{value:l[u+"BorderTopLeftRadiusMobile"],label:u+"BorderTopLeftRadiusMobile"},valueRightMobile:{value:l[u+"BorderTopRightRadiusMobile"],label:u+"BorderTopRightRadiusMobile"},valueBottomMobile:{value:l[u+"BorderBottomRightRadiusMobile"],label:u+"BorderBottomRightRadiusMobile"},valueLeftMobile:{value:l[u+"BorderBottomLeftRadiusMobile"],label:u+"BorderBottomLeftRadiusMobile"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],unit:{value:l[u+"BorderRadiusUnit"],label:u+"BorderRadiusUnit"},mUnit:{value:l[u+"BorderRadiusUnitMobile"],label:u+"BorderRadiusUnitMobile"},tUnit:{value:l[u+"BorderRadiusUnitTablet"],label:u+"BorderRadiusUnitTablet"},deviceType:s,attributes:l,setAttributes:n,link:{value:l[u+"BorderRadiusLink"],label:u+"BorderRadiusLink"},help:y||!1,min:0}),"none"!==T&&"default"!==T&&(0,w.createElement)(Er,{tabs:C,normal:E,hover:D,active:"",disableBottomSeparator:!0}),!r&&(0,w.createElement)(Ui,null),(0,w.createElement)(pe,{text:_})),B=ce(e.label),H=(0,O.applyFilters)(`spectra.${S}.${t}.${B}.before`,"",S),A=(0,O.applyFilters)(`spectra.${S}.${t}.${B}`,"",S);return(0,w.createElement)("div",{ref:i},H,L,A)},Hr=Br;Br.propTypes=Dr,Br.defaultProps=Lr;const Ar=(0,x.memo)(e=>{const{attributes:t,deviceType:a,setAttributes:i}=e,{block_id:l,headingTitleToggle:n,headingAlign:o,headingAlignTablet:r,headingAlignMobile:s,headingColorType:u,headingColor:c,headingGradientColor:g,blockBackgroundType:d,blockBackground:p,blockGradientBackground:h,subHeadingColor:m,subHeadSpace:b,subHeadSpaceTablet:f,subHeadSpaceMobile:v,subHeadSpaceType:y,separatorColor:x,headingTag:_,headingWrapper:k,headFontFamily:S,headFontWeight:C,headFontStyle:T,headFontSizeType:E,headFontSizeTypeMobile:D,headFontSizeTypeTablet:L,headFontSize:B,headFontSizeMobile:H,headFontSizeTablet:A,headLineHeightType:R,headLineHeight:P,headLineHeightMobile:z,headLineHeightTablet:F,headLetterSpacing:I,headLetterSpacingTablet:N,headLetterSpacingMobile:V,headLetterSpacingType:G,headShadowColor:W,headShadowHOffset:U,headShadowVOffset:j,headShadowBlur:q,headingDescToggle:$,headingDescPosition:Z,subHeadFontFamily:K,subHeadFontWeight:Y,subHeadFontStyle:J,subHeadFontSize:X,subHeadFontSizeType:Q,subHeadFontSizeTypeMobile:ee,subHeadFontSizeTypeTablet:ae,subHeadFontSizeMobile:ie,subHeadFontSizeTablet:le,subHeadLineHeight:ne,subHeadLineHeightType:oe,subHeadLineHeightMobile:re,subHeadLineHeightTablet:se,headTransform:ue,headDecoration:ce,subHeadTransform:ge,subHeadDecoration:pe,separatorWidth:he,separatorWidthTablet:me,separatorWidthMobile:be,separatorWidthType:fe,separatorStyle:ve,separatorPosition:we,separatorHeight:ye,separatorHeightType:xe,headSpace:_e,headSpaceTablet:ke,headSpaceMobile:Se,headSpaceType:Ce,separatorSpace:Te,separatorSpaceTablet:Ee,separatorSpaceMobile:De,separatorSpaceType:Le,headLoadGoogleFonts:Be,subHeadLoadGoogleFonts:He,subHeadLetterSpacing:Ae,subHeadLetterSpacingTablet:Re,subHeadLetterSpacingMobile:Pe,subHeadLetterSpacingType:ze,blockTopPadding:Oe,blockRightPadding:Fe,blockLeftPadding:Ie,blockBottomPadding:Ne,blockTopPaddingTablet:Ve,blockRightPaddingTablet:Ge,blockLeftPaddingTablet:We,blockBottomPaddingTablet:Ue,blockTopPaddingMobile:je,blockRightPaddingMobile:qe,blockLeftPaddingMobile:$e,blockBottomPaddingMobile:Ze,blockPaddingUnit:Ke,blockPaddingUnitTablet:Ye,blockPaddingUnitMobile:Je,blockPaddingLink:Xe,blockTopMargin:Qe,blockRightMargin:et,blockLeftMargin:tt,blockBottomMargin:at,blockTopMarginTablet:it,blockRightMarginTablet:lt,blockLeftMarginTablet:nt,blockBottomMarginTablet:ot,blockTopMarginMobile:rt,blockRightMarginMobile:st,blockLeftMarginMobile:ut,blockBottomMarginMobile:ct,blockMarginUnit:gt,blockMarginUnitTablet:dt,blockMarginUnitMobile:pt,blockMarginLink:ht,linkColor:mt,linkHColor:bt,highLightColor:ft,highLightBackground:vt,highLightLoadGoogleFonts:wt,highLightFontFamily:yt,highLightFontWeight:xt,highLightFontStyle:_t,highLightTransform:kt,highLightDecoration:St,highLightFontSizeType:Ct,highLightFontSizeTypeMobile:Mt,highLightFontSizeTypeTablet:Tt,highLightLineHeightType:Et,highLightFontSize:Dt,highLightFontSizeTablet:Lt,highLightFontSizeMobile:Bt,highLightLineHeight:Ht,highLightLineHeightTablet:At,highLightLineHeightMobile:Rt,highLightLetterSpacing:Pt,highLightLetterSpacingTablet:zt,highLightLetterSpacingMobile:Ot,highLightLetterSpacingType:Ft,highLightTopPadding:It,highLightRightPadding:Nt,highLightLeftPadding:Vt,highLightBottomPadding:Gt,highLightTopPaddingTablet:Wt,highLightRightPaddingTablet:Ut,highLightLeftPaddingTablet:jt,highLightBottomPaddingTablet:qt,highLightTopPaddingMobile:$t,highLightRightPaddingMobile:Zt,highLightLeftPaddingMobile:Kt,highLightBottomPaddingMobile:Yt,highLightPaddingUnit:Jt,highLightPaddingUnitTablet:Xt,highLightPaddingUnitMobile:Qt,highLightPaddingLink:ea}=t;let ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")},{value:"above-sub-heading",label:(0,M.__)("Above Sub-heading","sureforms")},{value:"below-sub-heading",label:(0,M.__)("Below Sub-heading","sureforms")}];n||(ta=[{value:"above-sub-heading",label:(0,M.__)("Above Sub-heading","sureforms")},{value:"below-sub-heading",label:(0,M.__)("Below Sub-heading","sureforms")}]),$||(ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")}]),$&&"above-heading"===Z&&(ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")},{value:"above-sub-heading",label:(0,M.__)("Above Sub-heading","sureforms")}]),$&&"below-heading"===Z&&(ta=[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")},{value:"below-sub-heading",label:(0,M.__)("Below Sub-heading","sureforms")}]);const aa=[{id:"alignment",component:(0,w.createElement)(Ri,{setAttributes:i,label:(0,M.__)("Alignment","sureforms"),data:{desktop:{value:o,label:"headingAlign"},tablet:{value:r,label:"headingAlignTablet"},mobile:{value:s,label:"headingAlignMobile"}},options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0,responsive:!0})},{id:"heading",component:(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Heading","sureforms"),checked:n,onChange:()=>i({headingTitleToggle:!n})})},{id:"heading-tag",component:n&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ri,{setAttributes:i,label:(0,M.__)("Heading Tag","sureforms"),data:{value:_,label:"headingTag"},options:[{value:"h1",label:(0,M.__)("H1","sureforms")},{value:"h2",label:(0,M.__)("H2","sureforms")},{value:"h3",label:(0,M.__)("H3","sureforms")},{value:"h4",label:(0,M.__)("H4","sureforms")},{value:"h5",label:(0,M.__)("H5","sureforms")},{value:"h6",label:(0,M.__)("H6","sureforms")},{value:"p",label:(0,M.__)("P","sureforms")},{value:"div",label:(0,M.__)("Div","sureforms")}]}),(0,w.createElement)(Ri,{setAttributes:i,label:(0,M.__)("Heading Wrapper","sureforms"),data:{value:k,label:"headingWrapper"},options:[{value:"div",label:(0,M.__)("Div","sureforms")},{value:"header",label:(0,M.__)("Header","sureforms")}]}))}],ia=(0,O.applyFilters)("srfm.block.heading.content",aa,e),la=(0,O.applyFilters)("srfm.advanced-heading.settings.advance",[],e);return(0,w.createElement)("div",null,(0,w.createElement)(Pi.InspectorControls,null,(0,w.createElement)(di,null,(0,w.createElement)(pi,{...hi,parentProps:e},(0,w.createElement)(Jo,{title:(0,M.__)("Content","sureforms"),initialOpen:!0},ia.map(e=>e.component)),(0,w.createElement)(Jo,{title:(0,M.__)("Sub Heading","sureforms"),initialOpen:!1},(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Enable Sub Heading","sureforms"),checked:$,onChange:()=>i({headingDescToggle:!$})}),$&&(0,w.createElement)(de,{label:(0,M.__)("Position","sureforms"),data:{value:Z,label:"headingDescPosition"},setAttributes:i,options:[{value:"above-heading",label:(0,M.__)("Above Heading","sureforms")},{value:"below-heading",label:(0,M.__)("Below Heading","sureforms")}]})),(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!1},(0,w.createElement)(de,{label:(0,M.__)("Style","sureforms"),data:{value:ve,label:"separatorStyle"},setAttributes:i,options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")}]}),"none"!==ve&&(0,w.createElement)(de,{label:(0,M.__)("Position","sureforms"),data:{value:we,label:"separatorPosition"},setAttributes:i,options:ta}))),(0,w.createElement)(pi,{...mi,parentProps:e},n&&(0,w.createElement)(Jo,{title:(0,M.__)("Heading","sureforms"),initialOpen:!0},(0,w.createElement)(yr,{label:(0,M.__)("Text Color","sureforms"),type:{value:u,label:"headingColorType"},classic:{value:c,label:"headingColor"},gradient:{value:g,label:"headingGradientColor"},setAttributes:i}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:i,loadGoogleFonts:{value:Be,label:"headLoadGoogleFonts"},fontFamily:{value:S,label:"headFontFamily"},fontWeight:{value:C,label:"headFontWeight"},fontStyle:{value:T,label:"headFontStyle"},transform:{value:ue,label:"headTransform"},decoration:{value:ce,label:"headDecoration"},fontSizeType:{value:E,label:"headFontSizeType"},fontSizeTypeMobile:{value:D,label:"headFontSizeTypeMobile"},fontSizeTypeTablet:{value:L,label:"headFontSizeTypeTablet"},fontSize:{value:B,label:"headFontSize"},fontSizeMobile:{value:H,label:"headFontSizeMobile"},fontSizeTablet:{value:A,label:"headFontSizeTablet"},lineHeightType:{value:R,label:"headLineHeightType"},lineHeight:{value:P,label:"headLineHeight"},lineHeightMobile:{value:z,label:"headLineHeightMobile"},lineHeightTablet:{value:F,label:"headLineHeightTablet"},letterSpacing:{value:I,label:"headLetterSpacing"},letterSpacingTablet:{value:N,label:"headLetterSpacingTablet"},letterSpacingMobile:{value:V,label:"headLetterSpacingMobile"},letterSpacingType:{value:G,label:"headLetterSpacingType"}}),(0,w.createElement)(xr,{blockId:l,setAttributes:i,label:(0,M.__)("Text Shadow","sureforms"),textShadowColor:{value:W,label:"headShadowColor",title:(0,M.__)("Color","sureforms")},textShadowHOffset:{value:U,label:"headShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},textShadowVOffset:{value:j,label:"headShadowVOffset",title:(0,M.__)("Vertical","sureforms")},textShadowBlur:{value:q,label:"headShadowBlur",title:(0,M.__)("Blur","sureforms")},popup:!0}),($||"none"!==ve)&&(0,w.createElement)(Qi,{label:(0,M.__)("Bottom Spacing","sureforms"),data:{desktop:{value:_e,label:"headSpace"},tablet:{value:ke,label:"headSpaceTablet"},mobile:{value:Se,label:"headSpaceMobile"}},min:0,max:200,unit:{value:Ce,label:"headSpaceType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:i})),"none"!==ve&&(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!1},(0,w.createElement)(Qi,{label:(0,M.__)("Width","sureforms"),data:{desktop:{value:he,label:"separatorWidth"},tablet:{value:me,label:"separatorWidthTablet"},mobile:{value:be,label:"separatorWidthMobile"}},min:0,max:"%"===fe?100:500,unit:{value:fe,label:"separatorWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}],setAttributes:i}),(0,w.createElement)(Me,{label:(0,M.__)("Thickness","sureforms"),setAttributes:i,value:ye,data:{value:ye,label:"separatorHeight"},min:0,max:20,unit:{value:xe,label:"separatorHeightType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}]}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:x||"",data:{value:x,label:"separatorColor"},setAttributes:i}),(0,w.createElement)(Qi,{label:(0,M.__)("Bottom Spacing","sureforms"),data:{desktop:{value:Te,label:"separatorSpace"},tablet:{value:Ee,label:"separatorSpaceTablet"},mobile:{value:De,label:"separatorSpaceMobile"}},min:0,max:200,unit:{value:Le,label:"separatorSpaceType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:i})),$&&(0,w.createElement)(Jo,{title:(0,M.__)("Sub Heading","sureforms"),initialOpen:!1},(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:m||"",data:{value:m,label:"subHeadingColor"},setAttributes:i}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:i,loadGoogleFonts:{value:He,label:"subHeadLoadGoogleFonts"},fontFamily:{value:K,label:"subHeadFontFamily"},fontWeight:{value:Y,label:"subHeadFontWeight"},fontStyle:{value:J,label:"subHeadFontStyle"},transform:{value:ge,label:"subHeadTransform"},decoration:{value:pe,label:"subHeadDecoration"},fontSizeType:{value:Q,label:"subHeadFontSizeType"},fontSizeTypeMobile:{value:ee,label:"subHeadFontSizeTypeMobile"},fontSizeTypeTablet:{value:ae,label:"subHeadFontSizeTypeTablet"},fontSize:{value:X,label:"subHeadFontSize"},fontSizeMobile:{value:ie,label:"subHeadFontSizeMobile"},fontSizeTablet:{value:le,label:"subHeadFontSizeTablet"},lineHeightType:{value:oe,label:"subHeadLineHeightType"},lineHeight:{value:ne,label:"subHeadLineHeight"},lineHeightMobile:{value:re,label:"subHeadLineHeightMobile"},lineHeightTablet:{value:se,label:"subHeadLineHeightTablet"},letterSpacing:{value:Ae,label:"subHeadLetterSpacing"},letterSpacingTablet:{value:Re,label:"subHeadLetterSpacingTablet"},letterSpacingMobile:{value:Pe,label:"subHeadLetterSpacingMobile"},letterSpacingType:{value:ze,label:"subHeadLetterSpacingType"}}),(0,w.createElement)(Qi,{label:(0,M.__)("Bottom Spacing","sureforms"),data:{desktop:{value:b,label:"subHeadSpace"},tablet:{value:f,label:"subHeadSpaceTablet"},mobile:{value:v,label:"subHeadSpaceMobile"}},min:0,max:200,unit:{value:y,label:"subHeadSpaceType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"}],setAttributes:i})),(0,w.createElement)(Jo,{title:(0,M.__)("Link","sureforms"),initialOpen:!1},(0,w.createElement)("p",{className:"components-base-control__help"},(0,M.__)("Below settings will apply to the heading text to which a link is applied.","sureforms")),(0,w.createElement)(Er,{tabs:[{name:"normal",title:(0,M.__)("Normal","sureforms")},{name:"hover",title:(0,M.__)("Hover","sureforms")}],normal:(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:mt,data:{value:mt,label:"linkColor"},setAttributes:i}),hover:(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:bt,data:{value:bt,label:"linkHColor"},setAttributes:i}),disableBottomSeparator:!0})),(0,w.createElement)(Jo,{title:(0,M.__)("Highlight","sureforms"),initialOpen:!1},(0,w.createElement)("p",{className:"components-base-control__help"},(0,M.__)("Highlight heading text from toolbar to see the below controls working.","sureforms")),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:ft,data:{value:ft,label:"highLightColor"},setAttributes:i}),(0,w.createElement)(Ti,{label:(0,M.__)("Background","sureforms"),colorValue:vt,data:{value:vt,label:"highLightBackground"},setAttributes:i}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),attributes:t,setAttributes:i,loadGoogleFonts:{value:wt,label:"highLightLoadGoogleFonts"},fontFamily:{value:yt,label:"highLightFontFamily"},fontWeight:{value:xt,label:"highLightFontWeight"},fontStyle:{value:_t,label:"highLightFontStyle"},transform:{value:kt,label:"highLightTransform"},decoration:{value:St,label:"highLightDecoration"},fontSizeType:{value:Ct,label:"highLightFontSizeType"},fontSizeTypeMobile:{value:Mt,label:"highLightFontSizeTypeMobile"},fontSizeTypeTablet:{value:Tt,label:"highLightFontSizeTypeTablet"},fontSize:{value:Dt,label:"highLightFontSize"},fontSizeMobile:{value:Bt,label:"highLightFontSizeMobile"},fontSizeTablet:{value:Lt,label:"highLightFontSizeTablet"},lineHeightType:{value:Et,label:"highLightLineHeightType"},lineHeight:{value:Ht,label:"highLightLineHeight"},lineHeightMobile:{value:Rt,label:"highLightLineHeightMobile"},lineHeightTablet:{value:At,label:"highLightLineHeightTablet"},letterSpacing:{value:Pt,label:"highLightLetterSpacing"},letterSpacingTablet:{value:zt,label:"highLightLetterSpacingTablet"},letterSpacingMobile:{value:Ot,label:"highLightLetterSpacingMobile"},letterSpacingType:{value:Ft,label:"highLightLetterSpacingType"}}),(0,w.createElement)(Yo,{label:(0,M.__)("Padding","sureforms"),valueTop:{value:It,label:"highLightTopPadding"},valueRight:{value:Nt,label:"highLightRightPadding"},valueBottom:{value:Gt,label:"highLightBottomPadding"},valueLeft:{value:Vt,label:"highLightLeftPadding"},valueTopTablet:{value:Wt,label:"highLightTopPaddingTablet"},valueRightTablet:{value:Ut,label:"highLightRightPaddingTablet"},valueBottomTablet:{value:qt,label:"highLightBottomPaddingTablet"},valueLeftTablet:{value:jt,label:"highLightLeftPaddingTablet"},valueTopMobile:{value:$t,label:"highLightTopPaddingMobile"},valueRightMobile:{value:Zt,label:"highLightRightPaddingMobile"},valueBottomMobile:{value:Yt,label:"highLightBottomPaddingMobile"},valueLeftMobile:{value:Kt,label:"highLightLeftPaddingMobile"},unit:{value:Jt,label:"highLightPaddingUnit"},mUnit:{value:Qt,label:"highLightPaddingUnitMobile"},tUnit:{value:Xt,label:"highLightPaddingUnitTablet"},deviceType:a,attributes:t,setAttributes:i,link:{value:ea,label:"highLightPaddingLink"}}),(0,w.createElement)(Hr,{setAttributes:i,prefix:"highLight",attributes:t,deviceType:a,disableBottomSeparator:!0})),(0,w.createElement)(Jo,{title:(0,M.__)("Background","sureforms"),initialOpen:!1},(0,w.createElement)(yr,{label:(0,M.__)("Background Color","sureforms"),type:{value:d,label:"blockBackgroundType"},classic:{value:p,label:"blockBackground"},gradient:{value:h,label:"blockGradientBackground"},setAttributes:i})),(0,w.createElement)(Jo,{title:(0,M.__)("Spacing","sureforms"),initialOpen:!1},(0,w.createElement)(Yo,{label:(0,M.__)("Padding","sureforms"),valueTop:{value:Oe,label:"blockTopPadding"},valueRight:{value:Fe,label:"blockRightPadding"},valueBottom:{value:Ne,label:"blockBottomPadding"},valueLeft:{value:Ie,label:"blockLeftPadding"},valueTopTablet:{value:Ve,label:"blockTopPaddingTablet"},valueRightTablet:{value:Ge,label:"blockRightPaddingTablet"},valueBottomTablet:{value:Ue,label:"blockBottomPaddingTablet"},valueLeftTablet:{value:We,label:"blockLeftPaddingTablet"},valueTopMobile:{value:je,label:"blockTopPaddingMobile"},valueRightMobile:{value:qe,label:"blockRightPaddingMobile"},valueBottomMobile:{value:Ze,label:"blockBottomPaddingMobile"},valueLeftMobile:{value:$e,label:"blockLeftPaddingMobile"},unit:{value:Ke,label:"blockPaddingUnit"},mUnit:{value:Je,label:"blockPaddingUnitMobile"},tUnit:{value:Ye,label:"blockPaddingUnitTablet"},deviceType:a,attributes:t,setAttributes:i,link:{value:Xe,label:"blockPaddingLink"}}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:Qe,label:"blockTopMargin"},valueRight:{value:et,label:"blockRightMargin"},valueBottom:{value:at,label:"blockBottomMargin"},valueLeft:{value:tt,label:"blockLeftMargin"},valueTopTablet:{value:it,label:"blockTopMarginTablet"},valueRightTablet:{value:lt,label:"blockRightMarginTablet"},valueBottomTablet:{value:ot,label:"blockBottomMarginTablet"},valueLeftTablet:{value:nt,label:"blockLeftMarginTablet"},valueTopMobile:{value:rt,label:"blockTopMarginMobile"},valueRightMobile:{value:st,label:"blockRightMarginMobile"},valueBottomMobile:{value:ct,label:"blockBottomMarginMobile"},valueLeftMobile:{value:ut,label:"blockLeftMarginMobile"},unit:{value:gt,label:"blockMarginUnit"},mUnit:{value:pt,label:"blockMarginUnitMobile"},tUnit:{value:dt,label:"blockMarginUnitTablet"},deviceType:a,attributes:t,setAttributes:i,link:{value:ht,label:"blockMarginLink"}}))),(0,w.createElement)(pi,{...bi},la.map(e=>e.content)))))}),Rr=e=>{const{setAttributes:t,attributes:a,context:i,onReplace:l,mergeBlocks:n,headingHasDynamicContent:o}=e;let{headingTitle:r,headingTag:s}=a,u=!1;if(o){const e=(0,O.applyFilters)("uag_render_text_loop_data",r,i);""!==e&&(u=["srfm/dynamic-content"],r=e)}return(0,w.createElement)(Pi.RichText,{tagName:s,placeholder:(0,M.__)("Write a Heading","sureforms"),value:r,className:"uagb-heading-text",onChange:e=>{t({headingTitle:e})},allowedFormats:u,onMerge:n,onSplit:e=>e?(0,ir.createBlock)("srfm/advanced-heading",{...a,headingTitle:e}):(0,ir.createBlock)("core/paragraph"),onReplace:l,onRemove:()=>l([])})},Pr=e=>{const{setAttributes:t,attributes:a,context:i,onReplace:l,mergeBlocks:n,descriptionHasDynamicContent:o}=e;let{headingDesc:r}=e.attributes,s=!1;if(o){const e=(0,O.applyFilters)("uag_render_text_loop_data",r,i);""!==e&&(s=["srfm/dynamic-content"],r=e)}return(0,w.createElement)(Pi.RichText,{tagName:"p",placeholder:(0,M.__)("Write a Description","sureforms"),value:r,className:"uagb-desc-text",onChange:e=>t({headingDesc:e}),allowedFormats:s,onMerge:n,onSplit:e=>e?(0,ir.createBlock)("srfm/advanced-heading",{...a,headingDesc:e}):(0,ir.createBlock)("core/paragraph"),onReplace:l,onRemove:()=>l([])})},zr=(0,x.memo)(e=>{const{attributes:{block_id:t,headingTitleToggle:a,headingDescToggle:i,separatorStyle:l,separatorPosition:n,headingDescPosition:o,headingWrapper:r},className:s,deviceType:u}=e,c=r||"div",g="none"!==l&&(0,w.createElement)("div",{className:"uagb-separator-wrap"},(0,w.createElement)("div",{className:"uagb-separator"})),d=(0,w.createElement)(w.Fragment,null,"above-heading"===n?g:"",(0,w.createElement)(Rr,{...e}),"below-heading"===n?g:""),p=(0,w.createElement)(w.Fragment,null,"above-sub-heading"===n?g:"",(0,w.createElement)(Pr,{...e}),"below-sub-heading"===n?g:"");return(0,w.createElement)(c,{className:ue([s,"wp-block-uagb-advanced-heading","uagb-block",`uagb-editor-preview-mode-${u.toLowerCase()}`,`uagb-block-${t}`])},i&&"above-heading"===o?p:"",a&&d,i&&"below-heading"===o?p:"",i||a?"":g)}),Or=(e,t,a="desktop")=>{if("default"!==e[t+"BorderStyle"]){switch(a){case"tablet":a="Tablet";break;case"mobile":a="Mobile";break;default:a=""}const i={},l=e[t+"BorderStyle"],n=e[t+"BorderColor"],o=D(e[t+"BorderTopWidth"+a],"px"),r=D(e[t+"BorderRightWidth"+a],"px"),s=D(e[t+"BorderBottomWidth"+a],"px"),u=D(e[t+"BorderLeftWidth"+a],"px"),c=e[t+"BorderRadiusUnit"+a]||"px",g=D(e[t+"BorderTopLeftRadius"+a],c),d=D(e[t+"BorderTopRightRadius"+a],c),p=D(e[t+"BorderBottomRightRadius"+a],c),h=D(e[t+"BorderBottomLeftRadius"+a],c);return"none"!==e[t+"BorderStyle"]&&""!==e[t+"BorderStyle"]&&(i["border-top-width"]=o,i["border-right-width"]=r,i["border-bottom-width"]=s,i["border-left-width"]=u,i["border-color"]=n),i["border-style"]=l,i["border-top-left-radius"]=g,i["border-top-right-radius"]=d,i["border-bottom-right-radius"]=p,i["border-bottom-left-radius"]=h,i}return{}},Fr=(0,x.memo)(({attributes:e})=>{const{headLoadGoogleFonts:t,headFontFamily:a,headFontWeight:i,subHeadLoadGoogleFonts:l,subHeadFontFamily:n,subHeadFontWeight:o,highLightLoadGoogleFonts:r,highLightFontFamily:s,highLightFontWeight:u}=e;let c,g,d;if(!0===t){const e={google:{families:[a+(i?":"+i:"")]}};c=(0,w.createElement)(Y,{config:e})}if(!0===l){const e={google:{families:[n+(o?":"+o:"")]}};g=(0,w.createElement)(Y,{config:e})}if(!0===r){const e={google:{families:[s+(u?":"+u:"")]}};d=(0,w.createElement)(Y,{config:e})}return(0,w.createElement)(w.Fragment,null,c,g,d)}),Ir=(0,X.compose)(tr,ee)(e=>{const{attributes:t,attributes:{UAGHideDesktop:a,UAGHideTab:i,UAGHideMob:l,headingTitle:n,headingDesc:o,formId:r},isSelected:s,clientId:u,name:c,deviceType:g,context:d,setAttributes:p}=e,h=-1!==n.indexOf('<span data-spectra-dc-field="'),m=o&&-1!==o.indexOf('<span data-spectra-dc-field="'),b=(e=>(0,V.useSelect)(t=>{const a=t(Pi.store).getBlockParents(e),i=t(Pi.store).getBlocksByClientId(a?.[0]),l=t("core/editor").getCurrentPostId();return i?.[0]?.attributes?.id||l}))(u);e={...e,headingHasDynamicContent:h,descriptionHasDynamicContent:m};const f=(0,Pi.useBlockProps)();(0,x.useEffect)(()=>{N(e)},[a,i,l,g]),(0,x.useEffect)(()=>{!h&&!m||t?.context||p({context:d})},[d]),(0,x.useEffect)(()=>{G()},[g]),(0,x.useEffect)(()=>{r!==b&&p({formId:b})},[r,b]);const v=(0,x.useMemo)(()=>function(e,t,a,i,l=!1){const n=i.toLowerCase(),o=a.replace("srfm/",""),{block_id:r,headingAlign:s,headingAlignTablet:u,headingAlignMobile:c,headingTag:g,headingColor:d,headingColorType:p,headingGradientColor:h,blockBackgroundType:m,blockBackground:b,blockGradientBackground:f,headSpace:v,headSpaceTablet:w,headSpaceMobile:y,separatorStyle:x,separatorHeight:_,separatorHeightType:k,separatorWidth:S,separatorWidthTablet:C,separatorWidthMobile:M,separatorWidthType:T,separatorColor:L,separatorSpace:B,separatorSpaceTablet:H,separatorSpaceMobile:A,separatorSpaceType:R,subHeadingColor:P,headFontFamily:z,headFontStyle:I,headFontWeight:N,headFontSize:V,headFontSizeType:G,headFontSizeTypeMobile:W,headFontSizeTypeTablet:U,headFontSizeMobile:j,headFontSizeTablet:q,headLineHeight:$,headLineHeightType:Z,headLineHeightMobile:K,headLineHeightTablet:Y,headLetterSpacing:J,headLetterSpacingTablet:X,headLetterSpacingMobile:Q,headLetterSpacingType:ee,headShadowColor:te,headShadowHOffset:ae,headShadowVOffset:ie,headShadowBlur:le,subHeadFontFamily:ne,subHeadFontStyle:oe,subHeadFontWeight:re,subHeadFontSize:se,subHeadFontSizeType:ue,subHeadFontSizeTypeMobile:ce,subHeadFontSizeTypeTablet:ge,subHeadFontSizeMobile:de,subHeadFontSizeTablet:pe,subHeadLineHeight:he,subHeadLineHeightType:me,subHeadLineHeightMobile:be,subHeadLineHeightTablet:fe,headTransform:ve,headDecoration:we,subHeadTransform:ye,subHeadDecoration:xe,subHeadLetterSpacing:_e,subHeadLetterSpacingTablet:ke,subHeadLetterSpacingMobile:Se,subHeadLetterSpacingType:Ce,blockTopPadding:Me,blockRightPadding:Te,blockLeftPadding:Ee,blockBottomPadding:De,blockTopPaddingTablet:Le,blockRightPaddingTablet:Be,blockLeftPaddingTablet:He,blockBottomPaddingTablet:Ae,blockTopPaddingMobile:Re,blockRightPaddingMobile:Pe,blockLeftPaddingMobile:ze,blockBottomPaddingMobile:Oe,blockPaddingUnit:Fe,blockPaddingUnitTablet:Ie,blockPaddingUnitMobile:Ne,blockTopMargin:Ve,blockRightMargin:Ge,blockLeftMargin:We,blockBottomMargin:Ue,blockTopMarginTablet:je,blockRightMarginTablet:qe,blockLeftMarginTablet:$e,blockBottomMarginTablet:Ze,blockTopMarginMobile:Ke,blockRightMarginMobile:Ye,blockLeftMarginMobile:Je,blockBottomMarginMobile:Xe,blockMarginUnit:Qe,blockMarginUnitTablet:et,blockMarginUnitMobile:tt,linkColor:at,linkHColor:it,highLightBorderHColor:lt,highLightColor:nt,highLightBackground:ot,highLightFontFamily:rt,highLightFontWeight:st,highLightFontStyle:ut,highLightTransform:ct,highLightDecoration:gt,highLightFontSizeType:dt,highLightFontSizeTypeTablet:pt,highLightFontSizeTypeMobile:ht,highLightLineHeightType:mt,highLightFontSize:bt,highLightFontSizeTablet:ft,highLightFontSizeMobile:vt,highLightLineHeight:wt,highLightLineHeightTablet:yt,highLightLineHeightMobile:xt,highLightLetterSpacing:_t,highLightLetterSpacingTablet:kt,highLightLetterSpacingMobile:St,highLightLetterSpacingType:Ct,highLightTopPadding:Mt,highLightRightPadding:Tt,highLightLeftPadding:Et,highLightBottomPadding:Dt,highLightTopPaddingTablet:Lt,highLightRightPaddingTablet:Bt,highLightLeftPaddingTablet:Ht,highLightBottomPaddingTablet:At,highLightTopPaddingMobile:Rt,highLightRightPaddingMobile:Pt,highLightLeftPaddingMobile:zt,highLightBottomPaddingMobile:Ot,highLightPaddingUnit:Ft,highLightPaddingUnitTablet:It,highLightPaddingUnitMobile:Nt,subHeadSpace:Vt,subHeadSpaceTablet:Gt,subHeadSpaceMobile:Wt,headingDescToggle:Ut}=e;let jt={},qt={},$t={},Zt={};"gradient"===p&&($t={"-webkit-text-fill-color":at},Zt={"-webkit-text-fill-color":it});const Kt=Or(e,"highLight"),Yt=Or(e,"highLight","tablet"),Jt=Or(e,"highLight","mobile");let Xt={".wp-block-uagb-advanced-heading ":{background:"classic"===m?b:f,"text-align":s,"margin-top":D(Ve,Qe),"margin-right":D(Ge,Qe),"margin-bottom":D(Ue,Qe),"margin-left":D(We,Qe),"padding-top":D(Me,Fe),"padding-right":D(Te,Fe),"padding-bottom":D(De,Fe),"padding-left":D(Ee,Fe)}," p.uagb-desc-text":{"font-family":ne,"font-style":oe,"text-decoration":xe,"text-transform":ye,"font-weight":re,"font-size":D(se,ue),"line-height":D(he,me),"letter-spacing":D(_e,Ce),color:P,"margin-bottom":D(F(Vt,"subHeadSpace",o),"px")},".wp-block-uagb-advanced-heading a":{color:at,...$t},".wp-block-uagb-advanced-heading a:hover":{color:it,...Zt},".wp-block-uagb-advanced-heading .srfm-highlight":{background:ot,color:nt,"-webkit-text-fill-color":nt,"font-family":rt,"font-style":ut,"text-decoration":gt,"text-transform":ct,"font-weight":st,"font-size":D(bt,dt),"line-height":D(wt,mt),"letter-spacing":D(_t,Ct),"padding-top":D(Mt,Ft),"padding-right":D(Tt,Ft),"padding-bottom":D(Dt,Ft),"padding-left":D(Et,Ft),...Kt},".wp-block-uagb-advanced-heading .srfm-highlight:hover":{"border-color":lt}},Qt={};"gradient"===p&&(Qt={background:h,"-webkit-background-clip":"text","-webkit-text-fill-color":"transparent"});const ea={color:nt,background:ot,"-webkit-text-fill-color":nt};Xt[".wp-block-uagb-advanced-heading .srfm-highlight::-moz-selection"]=ea,Xt[".wp-block-uagb-advanced-heading .srfm-highlight::selection"]=ea,Xt[" "+g+".uagb-heading-text"]={"font-family":z,"font-style":I,"text-decoration":we,"text-transform":ve,"font-weight":N,"font-size":D(V,G),"line-height":D($,Z),color:d,"letter-spacing":D(J,ee),...Qt};const ta=te&&D(ae,"px")+" "+D(ie,"px")+" "+D(le,"px")+" "+te;"gradient"===p?Xt[" "+g+".uagb-heading-text"].filter=`drop-shadow(${ta})`:Xt[" "+g+".uagb-heading-text"]["text-shadow"]=ta,"none"!==x&&(Xt[" .uagb-separator"]={"border-top-style":x,"border-top-width":D(F(_,"separatorHeight",o),k),width:D(F(S,"separatorWidth",o),T),"border-color":L,"margin-bottom":D(F(B,"separatorSpace",o),R)}),jt[".wp-block-uagb-advanced-heading "]={"text-align":u,"margin-top":D(je,et),"margin-right":D(qe,et),"margin-bottom":D(Ze,et),"margin-left":D($e,et),"padding-top":D(Le,Ie),"padding-right":D(Be,Ie),"padding-bottom":D(Ae,Ie),"padding-left":D(He,Ie)},jt[" "+g+".uagb-heading-text"]={"font-size":D(q,U),"line-height":D(Y,Z),"letter-spacing":D(X,ee)},jt[" p.uagb-desc-text"]={"font-size":D(pe,ge),"line-height":D(fe,me),"letter-spacing":D(ke,Ce),"margin-bottom":D(F(Gt,"subHeadSpaceTablet",o),"px")},jt[".wp-block-uagb-advanced-heading .srfm-highlight"]={"font-size":D(ft,pt),"line-height":D(yt,mt),"letter-spacing":D(kt,Ct),"padding-top":D(Lt,It),"padding-right":D(Bt,It),"padding-bottom":D(At,It),"padding-left":D(Ht,It),...Yt},qt[".wp-block-uagb-advanced-heading "]={"text-align":c,"margin-top":D(Ke,tt),"margin-right":D(Ye,tt),"margin-bottom":D(Xe,tt),"margin-left":D(Je,tt),"padding-top":D(Re,Ne),"padding-right":D(Pe,Ne),"padding-bottom":D(Oe,Ne),"padding-left":D(ze,Ne)},jt[" .uagb-separator"]={width:D(F(C,"separatorWidthTablet",o),T),"margin-bottom":D(F(H,"separatorSpaceTablet",o),R)},qt[" "+g+".uagb-heading-text"]={"font-size":D(j,W),"line-height":D(K,Z),"letter-spacing":D(Q,ee)},qt[" p.uagb-desc-text"]={"font-size":D(de,ce),"line-height":D(be,me),"letter-spacing":D(Se,Ce),"margin-bottom":D(F(Wt,"subHeadSpaceMobile",o),"px")},qt[".wp-block-uagb-advanced-heading .srfm-highlight"]={"font-size":D(vt,ht),"line-height":D(xt,mt),"letter-spacing":D(St,Ct),"padding-top":D(Rt,Nt),"padding-right":D(Pt,Nt),"padding-bottom":D(Ot,Nt),"padding-left":D(zt,Nt),...Jt},qt[" .uagb-separator"]={width:D(F(M,"separatorWidthMobile",o),T),"margin-bottom":D(F(A,"separatorSpaceMobile",o),R)},(Ut||"none"!==x)&&(Xt[" .uagb-heading-text"]={"margin-bottom":D(F(v,"headSpace",o),"px")},jt[" .uagb-heading-text"]={"margin-bottom":D(F(w,"headSpaceTablet",o),"px")},qt[" .uagb-heading-text"]={"margin-bottom":D(F(y,"headSpaceMobile",o),"px")});const aa=".editor-styles-wrapper "+(l?l+" ":`#block-${t} .uagb-block-${r}`);Xt=(0,O.applyFilters)(`spectra.${o}.styling`,Xt,e),jt=(0,O.applyFilters)(`spectra.${o}.tabletStyling`,jt,e),qt=(0,O.applyFilters)(`spectra.${o}.mobileStyling`,qt,e);let ia=E(Xt,aa);return("tablet"===n||"mobile"===n||l)&&(ia+=E(jt,`${aa}`,!0,"tablet"),("mobile"===n||l)&&(ia+=E(qt,`${aa}`,!0,"mobile"))),ia}(t,u,c,g),[t,g]);return(0,w.createElement)("div",{...f},(0,w.createElement)(W,{blockStyling:v}),(0,w.createElement)(Fr,{attributes:t}),s&&(0,w.createElement)(Ar,{...e}),(0,w.createElement)(zr,{...e}))}),Nr=window.wp.richText,Vr="srfm/advanced-heading-highlight";(0,Nr.registerFormatType)(Vr,{title:"Spectra Highlight",tagName:"mark",className:"srfm-highlight",edit:function({isActive:e,onChange:t,value:a}){const i=(0,V.useSelect)(e=>e("core/block-editor").getSelectedBlock(),[]);return(0,w.createElement)(Pi.BlockControls,null,i&&"srfm/advanced-heading"===i.name&&(0,w.createElement)(te.ToolbarGroup,{className:"uag-highlight-toolbar",label:"Options"},(0,w.createElement)(te.Tooltip,{text:(0,M.__)("Highlight Text","sureforms")},(0,w.createElement)(te.Button,{isPrimary:e,onClick:()=>{t((0,Nr.toggleFormat)(a,{type:Vr}))}},(0,w.createElement)("span",{className:"dashicons dashicons-admin-customizer"})))))}});const Gr=function(e){let t;const a={black:"#000000","cyan-bluish-gray":"#abb8c3",white:"#ffffff","pale-pink":"#f78da7","luminous-vivid-orange":"#ff6900","luminous-vivid-amber":"#fcb900","light-green-cyan":"#7bdcb5","vivid-green-cyan":"#00d084","pale-cyan-blue":"#8ed1fc","vivid-cyan-blue":"#0693e3","vivid-purple":"#9b51e0","vivid-red":"#cf2e2e"};return t=void 0!==a[e?.toLowerCase()]?a[e?.toLowerCase()]:wi(`var(--wp--preset--color--${e})`),t};let Wr={};Wr=(0,O.applyFilters)("srfm/advanced-heading",nr(Wr)),(0,ir.registerBlockType)("srfm/advanced-heading",{...Wr,apiVersion:3,title:(0,M.__)("Heading","sureforms"),description:(0,M.__)("Add heading, sub heading and a separator using one block.","sureforms"),icon:C.advanced_heading,keywords:[(0,M.__)("creative heading","sureforms"),(0,M.__)("uag","sureforms"),(0,M.__)("heading","sureforms")],supports:{anchor:!0,html:!1},attributes:P,category:srfm_spec_blocks_info.category,edit:e=>e.attributes.isPreview?(0,w.createElement)(lr,{image:"advanced-heading"}):(0,w.createElement)(Ir,{...e}),save:()=>null,__experimentalLabel:e=>(0,O.applyFilters)("uag_loop_data_source_label",(0,M.__)("Heading","sureforms"),e),usesContext:["postId","postType"],transforms:{from:[{type:"block",blocks:["core/heading"],transform:e=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:e.content,headingAlign:e.textAlign,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)})},{type:"block",blocks:["core/quote"],transform:e=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:e.value,headingDesc:e.citation,headingAlign:e.align,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)})},{type:"block",blocks:["core/paragraph"],transform:e=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:e.content,headingAlign:e.align,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)})},{type:"block",blocks:["core/list"],transform:(e,t)=>{const a=[];return t.forEach((e,i)=>{a.push({text:t[i].attributes.content})}),a.map(t=>(0,ir.createBlock)("srfm/advanced-heading",{headingTitle:t.text,headingColor:Gr(e.textColor),blockBackground:Gr(e.backgroundColor)}))}}],to:[{type:"block",blocks:["core/heading"],transform:e=>(0,ir.createBlock)("core/heading",{content:e.headingTitle,align:e.headingAlign})},{type:"block",blocks:["core/quote"],transform:e=>(0,ir.createBlock)("core/quote",{value:e.headingTitle,citation:e.headingDesc})},{type:"block",blocks:["core/paragraph"],transform:e=>(0,ir.createBlock)("core/paragraph",{content:e.headingTitle})}]}});const Ur=e=>{let{horizontal:t,vertical:a,blur:i,spread:l,horizontalUnit:n="px",verticalUnit:o="px",blurUnit:r="px",spreadUnit:s="px",color:u,position:c="outset",altColor:g=""}=e;return u||g?(t=D(t,n),""===t&&(t=0),a=D(a,o),""===a&&(a=0),i=D(i,r),""===i&&(i=0),l=D(l,s),""===l&&(l=0),0===t&&0===a&&0===i&&0===l?"":`${t} ${a} ${i}${l?` ${l}`:""} ${u||g}${"outset"===c?"":` ${c}`}`):""};var jr=a(1388),qr={};jr.A&&jr.A.locals&&(qr.locals=jr.A.locals);var $r,Zr=0,Kr={attributes:{id:"uagb-editor-styles"}};Kr.setAttributes=g(),Kr.insert=u().bind(null,"head"),Kr.domAPI=r(),Kr.insertStyleElement=p(),qr.use=function(e){return Kr.options=e||{},Zr++||($r=n()(jr.A,Kr)),qr},qr.unuse=function(){Zr>0&&! --Zr&&($r(),$r=null)};const Yr=qr,Jr=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Yr.use(),()=>{Yr.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const{label:o,data:r,setAttributes:s,options:u,help:c=!1}=e,g=Q(),d={};d.Desktop=(0,w.createElement)(te.SelectControl,{value:r.desktop.value,onChange:e=>s({[r.desktop.label]:e}),options:u.desktop}),d.Tablet=(0,w.createElement)(te.SelectControl,{value:r.tablet.value,onChange:e=>s({[r.tablet.label]:e}),options:u.tablet||u.desktop}),d.Mobile=(0,w.createElement)(te.SelectControl,{value:r.mobile.value,onChange:e=>s({[r.mobile.label]:e}),options:u.mobile||u.desktop});const p=ce(e.label),h=(0,O.applyFilters)(`spectra.${n}.${t}.${p}.before`,"",n),m=(0,O.applyFilters)(`spectra.${n}.${t}.${p}`,"",n);return(0,w.createElement)("div",{ref:i,className:"uagb-responsive-select-control components-base-control"},h,(0,w.createElement)("div",{className:"uagb-size-type-field-tabs"},(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)(he,{label:o,responsive:!0})),d[g]?d[g]:d.Desktop),(0,w.createElement)(pe,{text:c}),m)};var Xr=a(9194),Qr={};Xr.A&&Xr.A.locals&&(Qr.locals=Xr.A.locals);var es,ts=0,as={attributes:{id:"uagb-editor-styles"}};as.setAttributes=g(),as.insert=u().bind(null,"head"),as.domAPI=r(),as.insertStyleElement=p(),Qr.use=function(e){return as.options=e||{},ts++||(es=n()(Xr.A,as)),Qr},Qr.unuse=function(){ts>0&&! --ts&&(es(),es=null)};const is=Qr,ls=e=>{const{isOpen:t,setOpen:a,onConfirm:i,title:l,description:n,confirmLabel:o=(0,M.__)("Confirm","sureforms"),cancelLabel:r=(0,M.__)("Cancel","sureforms"),processingLabel:s=(0,M.__)("Processing…","sureforms"),icon:u="",executable:c=!1}=e;(0,x.useLayoutEffect)(()=>(is.use(),()=>{is.unuse()}),[]);const[g,d]=(0,x.useState)(!1),p=()=>{a(!1),d(!1)};return(0,w.createElement)(w.Fragment,null,t&&(0,w.createElement)(te.Modal,{onRequestClose:p,className:"uag-confirm-popup-wrapper",overlayClassName:"uag-confirm-popup-overlay"},(0,w.createElement)("div",{className:"uag-confirm-popup-icon"},""!==u?zi(u):(0,w.createElement)("svg",{xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",strokeWidth:"1.5",stroke:"currentColor"},(0,w.createElement)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M12 9v3.75m9-.75a9 9 0 11-18 0 9 9 0 0118 0zm-9 3.75h.008v.008H12v-.008z"}))),(0,w.createElement)("div",{className:"uag-confirm-popup-content"},(0,w.createElement)("div",{className:"uag-confirm-popup-text"},(0,w.createElement)("span",{className:"uag-confirm-popup-title"},l),(0,w.createElement)("span",{className:"uag-confirm-popup-description"},n)),(0,w.createElement)("div",{className:"uag-confirm-popup-controls"},!1===g?(0,w.createElement)(w.Fragment,null,(0,w.createElement)(te.Button,{className:"uag-confirm-popup-buttons uag-popup-confirmation-button",onClick:()=>{d(!0),c?i(c):i()}},o),(0,w.createElement)(te.Button,{className:"uag-confirm-popup-buttons uag-popup-cancellation-button",onClick:p},r)):(0,w.createElement)(te.Button,{isBusy:!0,className:"uag-confirm-popup-buttons uag-popup-confirmation-button"},s)))))};ls.defaultProps={};const ns=ls,os=window.wp.apiFetch;var rs=a.n(os);const ss=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null),n=(0,V.useSelect)(e=>e("core/block-editor").getSelectedBlock(),[]),o=i(),r=n?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[r]);const[s,u]=(0,x.useState)(!1),{onSelectImage:c,backgroundImage:g,onRemoveImage:d,slug:p="image",label:h=(0,M.__)("Image","sureforms"),disableLabel:m=!1,disableRemove:b=!1,allow:f=["image"],disableDynamicContent:v=!1,help:y=!1}=e;let _,k,S;switch(p){case"video":k=(0,M.__)("Select Video","sureforms"),S=(0,M.__)("Change Video","sureforms"),_=C.video_placeholder;break;case"lottie":k=(0,M.__)("Select Lottie Animation","sureforms"),S=(0,M.__)("Change Lottie Animation","sureforms"),_=C.lottie;break;case"svg":k=(0,M.__)("Upload SVG","sureforms"),S=(0,M.__)("Change SVG","sureforms");break;default:k=(0,M.__)("Select Image","sureforms"),S=(0,M.__)("Change Image","sureforms")}const T=v?null:(0,O.applyFilters)("uagb.registerImageExtender","",n?.name,c),E=v?null:(0,O.applyFilters)("uagb.registerImageLinkExtender","",n?.name,"bgImageLink","url"),D=e=>{const t={svg_nonce:srfm_spec_blocks_info.uagb_svg_confirmation_nonce,confirmation:"yes"};(async({url:e,action:t,data:a})=>{if(!((i=a)&&Object.keys(i).length>0&&Object.getPrototypeOf(i)===Object.prototype))return Promise.reject(new Error((0,M.__)("data object is empty","sureforms")));var i;const l=new window.FormData;l.append("action",t);for(const e in a){const t=a[e];l.append(e,t)}return await rs()({url:e,method:"POST",body:l})})({url:srfm_spec_blocks_info.ajax_url,action:"uagb_svg_confirmation",data:t}).then(t=>{t.success&&(o.setItem("uagSvgConfirmation",JSON.stringify("yes")),e())})},L=e=>{const t=i("uagSvgConfirmation");"svg"===p&&"yes"!==t?u(!0):e()},B=e=>(0,w.createElement)("div",{className:`spectra-media-control__button spectra-media-control__button--${e}`},C[e]),H=ce(e?.label),A=(0,O.applyFilters)(`spectra.${r}.${t}.${H}.before`,"",r),R=(0,O.applyFilters)(`spectra.${r}.${t}.${H}`,"",r);return(0,w.createElement)("div",{ref:l,className:"components-base-control"},A,(0,w.createElement)(te.BaseControl,{className:"spectra-media-control",id:`uagb-option-selector-${p}`,label:h,hideLabelFromVision:m},(()=>{if(v)return!0;const e=n?.attributes?.dynamicContent;return!e||!0!==e?.bgImage?.enable})()?(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"spectra-media-control__wrapper",style:{backgroundImage:!_&&g?.url&&!g?.svg&&`url("${(e=>{let t=e;switch(/(?:\.([^.]+))?$/.exec(String(t))[1]){case"json":case"avi":case"mpg":case"mp4":case"m4v":case"mov":case"ogv":case"vtt":case"wmv":case"3gp":case"3g2":t=""}return t})(g?.url)}")`}},_&&g?.url&&(0,w.createElement)("div",{className:"spectra-media-control__icon spectra-media-control__icon--stroke"},_),g?.svg&&(0,w.createElement)("div",{className:"spectra-media-control__icon spectra-media-control__icon--stroke",dangerouslySetInnerHTML:{__html:g.svg}}),(0,w.createElement)(Pi.MediaUpload,{title:k,onSelect:c,allowedTypes:f,value:g,render:({open:e})=>(e=>{const t=g?.url?"replace":"add";return(0,w.createElement)(w.Fragment,null,"add"===t&&(0,w.createElement)("button",{className:`spectra-media-control__clickable spectra-media-control__clickable--${t}`,onClick:()=>L(e)},B(t)),(0,w.createElement)("div",{className:"spectra-media-control__footer"},(0,w.createElement)("button",{className:"uag-control-label",onClick:()=>L(e)},S),T),"svg"===p&&(0,w.createElement)(ns,{isOpen:s,setOpen:u,onConfirm:D,title:(0,M.__)("Upload SVG?","sureforms"),description:(0,M.__)("Upload SVG can be potentially risky. Are you sure?","sureforms"),confirmLabel:(0,M.__)("Upload Anyway","sureforms"),cancelLabel:(0,M.__)("Cancel","sureforms"),executable:e}))})(e)}),!b&&g?.url&&(0,w.createElement)("button",{className:"spectra-media-control__clickable spectra-media-control__clickable--close",onClick:d},B("close"))),(0,w.createElement)(pe,{text:y})):T),E,R)},us=e=>{const[t,a]=(0,x.useState)(null),l=(0,x.useRef)(null),[n,o]=(0,x.useState)(!1),r=(0,O.applyFilters)("uagb.blocksAttributes",z),{getSelectedBlock:s}=(0,V.select)("core/block-editor");(0,x.useLayoutEffect)(()=>{window.addEventListener("click",function(e){const t=document.querySelector(`.active.popup-${y} .spectra-control-popup__options--action-button`),a=document.querySelector(`.active.popup-${y} .spectra-control-popup`);if(t&&!t?.contains(e.target)&&a&&!a?.contains(e.target)&&!e.target?.classList?.contains("uagb-advanced-color-indicate")&&!e.target?.parentElement?.closest(".uagb-popover-color")&&!e.target?.parentElement?.closest(".uagb-reset")){o(!1);const e=s()?.name,t=i("uagSettingState"),a={...t,[e]:{...t?.[e],selectedSetting:!1}},l=i();l&&l.setItem("uagSettingState",JSON.stringify(a))}})},[]);const u=s()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(l))},[u]);const{setAttributes:c,boxShadowColor:g,boxShadowHOffset:d,boxShadowVOffset:p,boxShadowBlur:h,boxShadowSpread:m,boxShadowPosition:b,label:f=(0,M.__)("Box Shadow","sureforms"),popup:v=!1,blockId:y,help:_=!1}=e;let k;const S=n?"active":"",C=[g.label,d.label,p.label,h.label,m.label,b.label],T=v&&(()=>{const e=(()=>{const e=s()?.name.split("/").pop();let t=!1;return void 0!==r[e]&&C.forEach(a=>{if(a){const i=void 0!==r[e][a]?.default?r[e][a]?.default:"";t={...t,[a]:i}}}),t})(),t=s()?.attributes;let a=!1;return C.forEach(i=>{t?.[i]&&t?.[i]!==e?.[i]&&(a=!0)}),a})(),E=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:g.title,colorValue:g.value,data:{value:g.value,label:g.label},setAttributes:c}),(0,w.createElement)(Me,{label:d.title,value:d.value,min:-100,max:100,displayUnit:!1,setAttributes:c,data:{value:d.value,label:d.label}}),(0,w.createElement)(Me,{label:p.title,value:p.value,min:-100,max:100,displayUnit:!1,setAttributes:c,data:{value:p.value,label:p.label}}),(0,w.createElement)(Me,{label:h.title,value:h.value,min:0,max:100,displayUnit:!1,setAttributes:c,data:{value:h.value,label:h.label}}),(0,w.createElement)(Me,{label:m.title,value:m.value,min:-100,max:100,displayUnit:!1,setAttributes:c,data:{value:m.value,label:m.label}}),(0,w.createElement)(Ri,{setAttributes:c,label:b.title,data:{value:b.value,label:b.label},options:[{value:"outset",label:(0,M.__)("Outset","sureforms"),tooltip:(0,M.__)("Outset","sureforms")},{value:"inset",label:(0,M.__)("Inset","sureforms"),tooltip:(0,M.__)("Inset (10px)","sureforms")}],showIcons:!1}));n&&(k=(0,w.createElement)("div",{className:"uagb-box-shadow-advanced spectra-control-popup"},E));const D=(0,w.createElement)("div",{className:"spectra-control-popup__options--action-wrapper"},(0,w.createElement)("span",{className:"uag-control-label"},f,T&&(0,w.createElement)("div",{className:"spectra__change-indicator--dot-right"})),(0,w.createElement)(te.Button,{className:"uag-box-shadow-button spectra-control-popup__options--action-button","aria-pressed":n,onClick:()=>{const e=document.querySelectorAll(".spectra-control-popup__options");if(e&&0<e.length)for(let t=0;t<e.length;t++){const a=e[t]?.querySelector(".spectra-control-popup__options.active .spectra-control-popup__options--action-button");a?.click()}o(!n);const t=s()?.name,a=i("uagSettingState");let l={...a,[t]:{...a?.[t],selectedSetting:".uag-box-shadow-options"}};n&&(l={...a,[t]:{...a?.[t],selectedSetting:!1}});const r=i();r&&r.setItem("uagSettingState",JSON.stringify(l))}},(0,w.createElement)(te.Dashicon,{icon:"edit"}))),L=ce(e.label),B=(0,O.applyFilters)(`spectra.${u}.${t}.${L}.before`,"",u),H=(0,O.applyFilters)(`spectra.${u}.${t}.${L}`,"",u);return(0,w.createElement)("div",{ref:l},B,v?(0,w.createElement)("div",{className:` components-base-control uag-box-shadow-options spectra-control-popup__options popup-${y} ${S}`},D,n&&k,(0,w.createElement)(pe,{text:_})):(0,w.createElement)(w.Fragment,null,E),H)};var cs=a(8542),gs={};cs.A&&cs.A.locals&&(gs.locals=cs.A.locals);var ds,ps=0,hs={attributes:{id:"uagb-editor-styles"}};hs.setAttributes=g(),hs.insert=u().bind(null,"head"),hs.domAPI=r(),hs.insertStyleElement=p(),gs.use=function(e){return hs.options=e||{},ps++||(ds=n()(cs.A,hs)),gs},gs.unuse=function(){ps>0&&! --ps&&(ds(),ds=null)};const ms=gs;var bs=a(9810),fs={};bs.A&&bs.A.locals&&(fs.locals=bs.A.locals);var vs,ws=0,ys={attributes:{id:"uagb-editor-styles"}};ys.setAttributes=g(),ys.insert=u().bind(null,"head"),ys.domAPI=r(),ys.insertStyleElement=p(),fs.use=function(e){return ys.options=e||{},ws++||(vs=n()(bs.A,ys)),fs},fs.unuse=function(){ws>0&&! --ws&&(vs(),vs=null)};const xs=fs,_s=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(xs.use(),()=>{xs.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const o=(0,V.useSelect)(()=>(0,V.select)("core/block-editor").getSelectedBlock(),[]),r=e.enableDynamicContent&&e.name?wp.hooks.applyFilters("uagb.registerTextExtender","",o?.name,e.name,e.dynamicContentType):null,s=()=>{if(!e.enableDynamicContent||!e.name)return!1;const t=o?.attributes?.dynamicContent;return!(!t||!0!==t?.[e.name]?.enable)},{isShiftStepEnabled:u}=e;let c=xe(e.unit?.value,e),g=_e(e.unit?.value,e);const d=isNaN(e?.value)?"":e?.value;let p=[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("Em","sureforms"),unitValue:"em"}];e.units&&(p=e.units);const h=t=>{const a=parseFloat(t);e.setAttributes&&e.setAttributes({[e.data.label]:a}),e?.onChange&&e.onChange(a)},m=t=>{e?.onChange&&e?.onChange(t[e?.data?.label]),e.displayUnit&&b(t[e?.unit?.label])},b=t=>{e.setAttributes({[e.unit.label]:t}),c=xe(t,e),g=_e(t,e),e.value>c&&h(c),e.value<g&&h(g)},f=e.inlineControl?"inline":"full-width",v=ce(e?.label),y=(0,O.applyFilters)(`spectra.${n}.${t}.${v}.before`,"",n),_=(0,O.applyFilters)(`spectra.${n}.${t}.${v}`,"",n);return(0,w.createElement)("div",{ref:i,className:"components-base-control uag-number-control uagb-size-type-field-tabs"+(s()?" uagb-text-control--open-dynamic-content":"")},y,e.showControlHeader&&(0,w.createElement)(()=>(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)("div",{className:"uagb-number-control__actions uagb-control__actions"},(0,w.createElement)(ke,{onReset:m,attributeNames:[e.data.label,!!e.displayUnit&&e.unit.label],setAttributes:e.setAttributes}),e.displayUnit&&(0,w.createElement)(te.ButtonGroup,{className:"uagb-control__units","aria-label":(0,M.__)("Select Units","sureforms")},(t=>{const a=[];return t.map(t=>a.push((0,w.createElement)(te.Tooltip,{text:(0,M.sprintf)(/* translators: abbreviation for units */ /* translators: abbreviation for units */ (0,M.__)("%s units","sureforms"),t.name),key:t.name},(0,w.createElement)(te.Button,{key:t.unitValue,className:"uagb-number-control__units--"+t.name,isSmall:!0,isPrimary:e.unit.value===t.unitValue,isSecondary:e.unit.value!==t.unitValue,"aria-pressed":e.unit.value===t.unitValue,"aria-label":(0,M.sprintf)(/* translators: abbreviation for units */ /* translators: abbreviation for units */ (0,M.__)("%s units","sureforms"),t.name),onClick:()=>b(t.unitValue)},t.unitValue)))),a})(p)))),null),(0,w.createElement)("div",{className:ri()("uagb-number-control__mobile-controls","uag-number-control__"+f)},(0,w.createElement)(he,{label:e.label,responsive:e.responsive}),!s()&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(te.__experimentalNumberControl,{labelPosition:"edge",disabled:e.disabled,isShiftStepEnabled:u,max:c,min:g,onChange:h,value:d,step:e?.step||1,required:e?.required,readOnly:s()})),r),(0,w.createElement)(pe,{text:e.help}),s()&&(0,w.createElement)(Ui,null),_)};_s.defaultProps={label:(0,M.__)("Margin","sureforms"),className:"",allowReset:!0,isShiftStepEnabled:!0,max:1/0,min:-1/0,resetFallbackValue:"",placeholder:null,unit:["px","em"],displayUnit:!0,responsive:!1,showControlHeader:!0,inlineControl:!0,dynamicContentType:"text",enableDynamicContent:!1,help:!1};const ks=_s;function Ss({imageWidth:e,imageHeight:t,imageSizeOptions:a=[],isResizable:i=!0,data:l,width:n,widthTablet:o,widthMobile:r,height:s,heightTablet:u,heightMobile:c,setAttributes:g,onChange:d,help:p}){const[h,m]=(0,x.useState)(null),b=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(ms.use(),()=>{ms.unuse()}),[]);const{getSelectedBlock:f}=(0,V.select)("core/block-editor"),v=f()?.name.split("/").pop();(0,x.useEffect)(()=>{m(se(b))},[v]);const y=Q();let _,k;switch(y){case"Tablet":_=u,k=o;break;case"Mobile":_=c,k=r;break;default:_=s,k=n}const{currentHeight:S,currentWidth:C,updateDimension:T}=function(e,t,a,i,l){const[n,o]=(0,x.useState)(t||i||""),[r,s]=(0,x.useState)(e||a||"");return(0,x.useEffect)(()=>{void 0===t&&void 0!==i&&o(i),void 0===e&&void 0!==a&&s(a)},[i,a]),(0,x.useEffect)(()=>{void 0!==t&&Number.parseInt(t)!==Number.parseInt(n)&&o(t),void 0!==e&&Number.parseInt(e)!==Number.parseInt(r)&&s(e)},[t,e]),{currentHeight:r,currentWidth:n,updateDimension:(e,t)=>{"width"===e?o(t):s(t),l({[e]:""===t?void 0:parseInt(t,10)})},updateDimensions:(e,t)=>{s(e||a||""),s(t||i||""),l({height:e,width:t})}}}(_,k,t,e,d),E={};E.Desktop=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(ks,{label:(0,M.__)("Width","sureforms"),value:C,data:{value:n,label:"width"},displayUnit:!1,setAttributes:g,min:1/0,step:1,max:-1/0,showControlHeader:!1,onChange:e=>T("width",e)}),(0,w.createElement)(ks,{label:(0,M.__)("Height","sureforms"),value:S,data:{value:s,label:"height"},displayUnit:!1,setAttributes:g,min:1/0,step:1,max:-1/0,showControlHeader:!1,onChange:e=>{T("height",e),isNaN(e)||""===e?g({customHeightSetDesktop:!1}):g({customHeightSetDesktop:!0})}})),E.Tablet=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(ks,{label:(0,M.__)("Width","sureforms"),value:C,data:{value:o,label:"widthTablet"},displayUnit:!1,setAttributes:g,min:1/0,step:1,max:-1/0,showControlHeader:!1,onChange:e=>T("widthTablet",e)}),(0,w.createElement)(ks,{label:(0,M.__)("Height","sureforms"),value:S,data:{value:u,label:"heightTablet"},displayUnit:!1,setAttributes:g,min:1/0,step:1,max:-1/0,showControlHeader:!1,onChange:e=>{T("heightTablet",e),isNaN(e)||""===e?g({customHeightSetTablet:!1}):g({customHeightSetTablet:!0})}})),E.Mobile=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(ks,{label:(0,M.__)("Width","sureforms"),value:C,data:{value:r,label:"widthMobile"},displayUnit:!1,setAttributes:g,min:1/0,step:1,max:-1/0,showControlHeader:!1,onChange:e=>T("widthMobile",e)}),(0,w.createElement)(ks,{label:(0,M.__)("Height","sureforms"),value:S,data:{value:c,label:"heightMobile"},displayUnit:!1,setAttributes:g,min:1/0,step:1,max:-1/0,showControlHeader:!1,onChange:e=>{T("heightMobile",e),isNaN(e)||""===e?g({customHeightSetMobile:!1}):g({customHeightSetMobile:!0})}}));const D="image-size",L=(0,O.applyFilters)(`spectra.${v}.${h}.${D}.before`,"",v),B=(0,O.applyFilters)(`spectra.${v}.${h}.${D}`,"",v);return(0,w.createElement)("div",{ref:b,className:"components-base-control"},L,0!==a.length&&(0,w.createElement)(Jr,{label:(0,M.__)("Image Size","sureforms"),options:{desktop:a,tablet:a,mobile:a},data:{desktop:{label:l.sizeSlug.label,value:l.sizeSlug.value},tablet:{label:l.sizeSlugTablet.label,value:l.sizeSlugTablet.value},mobile:{label:l.sizeSlugMobile.label,value:l.sizeSlugMobile.value}},setAttributes:g}),i&&(0,w.createElement)("div",{className:"block-editor-image-size-control"},(0,w.createElement)("div",{className:"uagb-size-type-field-tabs"},(0,w.createElement)("div",{className:"uagb-control__header"},(0,w.createElement)(he,{label:(0,M.__)("Image Dimensions","sureforms"),responsive:!0})),(0,w.createElement)("div",{className:"block-editor-image-size-control__row"},E[y])),p&&(0,w.createElement)("p",{className:"components-base-control__help"},p)),B)}var Cs=a(3790),Ms={};Cs.A&&Cs.A.locals&&(Ms.locals=Cs.A.locals);var Ts,Es=0,Ds={attributes:{id:"uagb-editor-styles"}};Ds.setAttributes=g(),Ds.insert=u().bind(null,"head"),Ds.domAPI=r(),Ds.insertStyleElement=p(),Ms.use=function(e){return Ds.options=e||{},Es++||(Ts=n()(Cs.A,Ds)),Ms},Ms.unuse=function(){Es>0&&! --Es&&(Ts(),Ts=null)};const Ls=Ms,Bs={label:j().string,data:j().object,onChange:j().func,setAttributes:j().func},Hs={label:(0,M.__)("Alignment","sureforms")},As=e=>{(0,x.useLayoutEffect)(()=>(Ls.use(),()=>{Ls.unuse()}),[]);const{label:t,data:a,onChange:i,setAttributes:l,help:n=!1}=e;return(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"components-base-control spectra__matrix-control"},(0,w.createElement)("div",{className:"uag-control-label"},t),(0,w.createElement)(te.__experimentalAlignmentMatrixControl,{className:"spectra__matrix-control--box",label:t,value:a?.value,onChange:!(!i&&!l)&&(e=>(e=>{l?l({[a?.label]:e}):i&&i(e)})(e))})),(0,w.createElement)(pe,{text:n}))};As.propTypes=Bs,As.defaultProps=Hs;const Rs=As,Ps=window.wp.coreData,zs=[{defaultAttributes:H},{value:"preset-1",label:(0,M.__)("Preset 1","sureforms"),attributes:[{label:"imageBoxShadowHOffset",value:3},{label:"imageBoxShadowVOffset",value:8},{label:"imageBoxShadowBlur",value:12},{label:"imageBoxShadowSpread",value:0},{label:"imageBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_451)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_451" x="55" y="75" width="218" height="127" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="2"/> <feGaussianBlur stdDeviation="2"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_451"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_451" result="shape"/> </filter> </defs> </svg>'},{value:"preset-2",label:(0,M.__)("Preset 2","sureforms"),attributes:[{label:"imageBoxShadowHOffset",value:0},{label:"imageBoxShadowVOffset",value:18},{label:"imageBoxShadowBlur",value:40},{label:"imageBoxShadowSpread",value:-10},{label:"imageBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_459)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_459" x="48" y="71" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_459"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_459" result="shape"/> </filter> </defs> </svg>'},{value:"preset-3",label:(0,M.__)("Preset 3","sureforms"),attributes:[{label:"imageBoxShadowHOffset",value:0},{label:"imageBoxShadowVOffset",value:4},{label:"imageBoxShadowBlur",value:12},{label:"imageBoxShadowSpread",value:0},{label:"imageBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_463)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_463" x="48" y="67" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_463"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_463" result="shape"/> </filter> </defs> </svg>'},{value:"preset-4",label:(0,M.__)("Preset 4","sureforms"),attributes:[{label:"imageBoxShadowHOffset",value:0},{label:"imageBoxShadowVOffset",value:2},{label:"imageBoxShadowBlur",value:5},{label:"imageBoxShadowSpread",value:-1},{label:"imageBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_467)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_467" x="53" y="71" width="222" height="131" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="3"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_467"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_467" result="shape"/> </filter> </defs> </svg>'},{value:"preset-5",label:(0,M.__)("Preset 5","sureforms"),attributes:[{label:"imageBoxShadowHOffset",value:0},{label:"imageBoxShadowVOffset",value:50},{label:"imageBoxShadowBlur",value:50},{label:"imageBoxShadowSpread",value:-30},{label:"imageBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_471)"> <ellipse cx="169" cy="174.5" rx="100" ry="16.5" fill="#FAFAFA"/> </g> <path d="M275 189.388C275 192.493 272.493 195 269.4 195H70.5995C67.5034 195 65 192.486 65 189.388V81.615C65 78.5136 67.5067 76 70.5995 76H269.4C272.497 76 274.997 78.5136 274.997 81.615L275 189.388Z" fill="#FBFBFB"/> <defs> <filter id="filter0_d_103_471" x="60" y="154" width="220" height="53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="6"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_471"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_471" result="shape"/> </filter> </defs> </svg>'},{value:"preset-6",label:(0,M.__)("Preset 6","sureforms"),attributes:[{label:"imageBoxShadowHOffset",value:0},{label:"imageBoxShadowVOffset",value:20},{label:"imageBoxShadowBlur",value:30},{label:"imageBoxShadowSpread",value:0},{label:"imageBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_476)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_476" x="52" y="74" width="224" height="133" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="3.5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_476"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_476" result="shape"/> </filter> </defs> </svg>'}],Os=[{defaultAttributes:H},{value:"preset-1",label:(0,M.__)("Preset 1","sureforms"),attributes:[{label:"imageBoxShadowHOffsetHover",value:3},{label:"imageBoxShadowVOffsetHover",value:8},{label:"imageBoxShadowBlurHover",value:12},{label:"imageBoxShadowSpreadHover",value:0},{label:"imageBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_451)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_451" x="55" y="75" width="218" height="127" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="2"/> <feGaussianBlur stdDeviation="2"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_451"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_451" result="shape"/> </filter> </defs> </svg>'},{value:"preset-2",label:(0,M.__)("Preset 2","sureforms"),attributes:[{label:"imageBoxShadowHOffsetHover",value:0},{label:"imageBoxShadowVOffsetHover",value:18},{label:"imageBoxShadowBlurHover",value:40},{label:"imageBoxShadowSpreadHover",value:-10},{label:"imageBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_459)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_459" x="48" y="71" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_459"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_459" result="shape"/> </filter> </defs> </svg>'},{value:"preset-3",label:(0,M.__)("Preset 3","sureforms"),attributes:[{label:"imageBoxShadowHOffsetHover",value:0},{label:"imageBoxShadowVOffsetHover",value:4},{label:"imageBoxShadowBlurHover",value:12},{label:"imageBoxShadowSpreadHover",value:0},{label:"imageBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_463)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_463" x="48" y="67" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_463"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_463" result="shape"/> </filter> </defs> </svg>'},{value:"preset-4",label:(0,M.__)("Preset 4","sureforms"),attributes:[{label:"imageBoxShadowHOffsetHover",value:0},{label:"imageBoxShadowVOffsetHover",value:2},{label:"imageBoxShadowBlurHover",value:5},{label:"imageBoxShadowSpreadHover",value:-1},{label:"imageBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_467)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_467" x="53" y="71" width="222" height="131" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="3"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_467"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_467" result="shape"/> </filter> </defs> </svg>'},{value:"preset-5",label:(0,M.__)("Preset 5","sureforms"),attributes:[{label:"imageBoxShadowHOffsetHover",value:0},{label:"imageBoxShadowVOffsetHover",value:50},{label:"imageBoxShadowBlurHover",value:50},{label:"imageBoxShadowSpreadHover",value:-30},{label:"imageBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_471)"> <ellipse cx="169" cy="174.5" rx="100" ry="16.5" fill="#FAFAFA"/> </g> <path d="M275 189.388C275 192.493 272.493 195 269.4 195H70.5995C67.5034 195 65 192.486 65 189.388V81.615C65 78.5136 67.5067 76 70.5995 76H269.4C272.497 76 274.997 78.5136 274.997 81.615L275 189.388Z" fill="#FBFBFB"/> <defs> <filter id="filter0_d_103_471" x="60" y="154" width="220" height="53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="6"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_471"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_471" result="shape"/> </filter> </defs> </svg>'},{value:"preset-6",label:(0,M.__)("Preset 6","sureforms"),attributes:[{label:"imageBoxShadowHOffsetHover",value:0},{label:"imageBoxShadowVOffsetHover",value:20},{label:"imageBoxShadowBlurHover",value:30},{label:"imageBoxShadowSpreadHover",value:0},{label:"imageBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_476)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_476" x="52" y="74" width="224" height="133" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="3.5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_476"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_476" result="shape"/> </filter> </defs> </svg>'}],Fs=(0,O.applyFilters)("uag_image_presets",zs);var Is=a(5621),Ns={};Is.A&&Is.A.locals&&(Ns.locals=Is.A.locals);var Vs,Gs=0,Ws={attributes:{id:"uagb-editor-styles"}};Ws.setAttributes=g(),Ws.insert=u().bind(null,"head"),Ws.domAPI=r(),Ws.insertStyleElement=p(),Ns.use=function(e){return Ws.options=e||{},Gs++||(Vs=n()(Is.A,Ws)),Ns},Ns.unuse=function(){Gs>0&&! --Gs&&(Vs(),Vs=null)};const Us=Ns,js=e=>{const[t,a]=(0,x.useState)(null),i=(0,x.useRef)(null);(0,x.useLayoutEffect)(()=>(Us.use(),()=>{Us.unuse()}),[]);const{getSelectedBlock:l}=(0,V.select)("core/block-editor"),n=l()?.name.split("/").pop();(0,x.useEffect)(()=>{a(se(i))},[n]);const{setAttributes:o,presets:r,presetInputType:s,label:u,className:c,help:g=!1}=e,d=[];r&&r.map(e=>{if(e?.attributes)for(const t of e?.attributes)d.includes(t?.label)||d.push(t?.label);return e});const[p,h]=(0,x.useState)(""),m=e=>{h(e),r&&r.map(t=>(t.value&&("default"!==e&&"default"===t.value&&t.attributes&&t.attributes.map(e=>(o({[e.label]:e.value}),e)),t.value&&t.value===e&&t.attributes&&(r[1]?.defaultPresetAttributes?.map(e=>(o({[e.label]:r[0]?.defaultAttributes[e.label]?.default}),e)),t.attributes.map(e=>(o({[e.label]:e.value}),e)),t.childAttributes&&b(t))),t))},b=e=>{let t=[];l().innerBlocks&&(t=l().innerBlocks);const a=[];t.map(e=>(e.clientId&&a.push(e.clientId),e));const i={};e.childAttributes.map(e=>(i[e.label]=e.value,e)),a.map(e=>((0,V.dispatch)("core/block-editor").updateBlockAttributes(e,i),e))},f=r.map(e=>{if(!e.value)return"";const t=e.value,a=p===t;return(0,w.createElement)(w.Fragment,null,(0,w.createElement)("input",{key:t,className:"uag-presets-radio-input",type:"radio",value:t,checked:a,onChange:()=>m(t),onClick:()=>m(t)}),(0,w.createElement)("label",{htmlFor:t,className:"uag-presets-radio-input-label",dangerouslySetInnerHTML:{__html:e.icon},onClick:()=>m(t)}))}),v=(0,w.createElement)(te.SelectControl,{className:"uagb-presets-dropdown",onChange:m,options:r,label:u}),y=(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"uagb-presets-radio-image-wrap"},f)),_=ce(u),k=(0,O.applyFilters)(`spectra.${n}.${t}.${_}.before`,"",n),S=(0,O.applyFilters)(`spectra.${n}.${t}.${_}`,"",n);return(0,w.createElement)("div",{ref:i,className:"components-base-control"},k,(0,w.createElement)("div",{className:ri()(c,"uagb-presets-main-wrap")},(0,w.createElement)("div",{className:"uagb-presets-label-reset-wrap"},(0,w.createElement)("label",{htmlFor:"uag-presets-label",className:"uag-presets-label"},u),(0,w.createElement)(ke,{attributeNames:d,setAttributes:o,onReset:()=>{h(""),(()=>{let e=[];l().innerBlocks&&(e=l().innerBlocks);const t=[];e.map(e=>(e.clientId&&t.push(e.clientId),e));const a={};r.map(e=>(e?.childAttributes&&e?.childAttributes.map(e=>(r[1]?.defaultChildAttributes&&r[1]?.defaultChildAttributes[e.label]&&void 0!==r[1]?.defaultChildAttributes[e.label].default&&(a[e.label]=r[1]?.defaultChildAttributes[e.label].default),e)),e)),t.map(e=>((0,V.dispatch)("core/block-editor").updateBlockAttributes(e,a),e))})()}})),"dropdown"===s&&v,"radioImage"===s&&y,(0,w.createElement)(pe,{text:g})),S)};js.defaultProps={presetInputType:"dropdown",label:(0,M.__)("Select Preset","sureforms")};const qs=(0,x.memo)(js),$s=window.wp.blob,Zs=(e,t)=>{const{alt:a,id:i,link:l,caption:n}=e,o={alt:a,id:i,link:l,caption:n};return e?.sizes&&e?.sizes[t]?{...o,width:e?.sizes[t]?.width,height:e?.sizes[t]?.height,url:e?.sizes[t]?.url}:e?.media_details&&e?.media_details?.sizes[t]?{...o,width:e?.media_details?.sizes[t]?.width,height:e?.media_details?.sizes[t]?.height,url:e?.media_details?.sizes[t]?.source_url}:{...o,url:e?.url}},Ks=(e,t)=>t&&!e&&!(0,$s.isBlobURL)(t),Ys=(e,t)=>!(!e?.sizes?.[t]&&!e?.media_details?.sizes?.[t]),Js=e=>(wp?.media?.attachment(e)||{}).destroyed,Xs=(e,t)=>{const a="url"+t,i="height"+t,l="width"+t,n="sizeSlug"+t,o=Zs(e,n),r={};return o.url&&(r[a]=o.url),"custom"!==n?(o.height&&(r[i]=o.height),o.width&&(r[l]=o.width)):(r[i]=void 0,r[l]=void 0),r};function Qs(e){const{attributes:t,setAttributes:a,context:i,isSelected:l,clientId:n,deviceType:o}=e,{block_id:r,objectFit:s,objectFitTablet:u,objectFitMobile:c,layout:g,id:d,url:p,urlTablet:h,urlMobile:m,width:b,widthTablet:f,widthMobile:v,height:y,heightTablet:_,heightMobile:k,align:S,alignTablet:C,alignMobile:T,alt:E,sizeSlug:D,sizeSlugTablet:L,sizeSlugMobile:B,enableCaption:H,naturalWidth:A,naturalHeight:R,imageTopMargin:P,imageRightMargin:z,imageLeftMargin:O,imageBottomMargin:F,imageTopMarginTablet:I,imageRightMarginTablet:N,imageLeftMarginTablet:G,imageBottomMarginTablet:W,imageTopMarginMobile:U,imageRightMarginMobile:j,imageLeftMarginMobile:q,imageBottomMarginMobile:$,imageMarginUnit:Z,imageMarginUnitTablet:K,imageMarginUnitMobile:Y,imageMarginLink:J,captionShowOn:Q,captionLoadGoogleFonts:ee,captionAlign:ae,captionFontFamily:ie,captionFontWeight:le,captionFontStyle:ne,captionFontSize:oe,captionColor:re,captionTransform:se,captionDecoration:ue,captionFontSizeType:ce,captionFontSizeTypeMobile:ge,captionFontSizeTypeTablet:pe,captionFontSizeMobile:he,captionFontSizeTablet:me,captionLineHeight:be,captionLineHeightType:fe,captionLineHeightMobile:ve,captionLineHeightTablet:we,captionTopMargin:ye,captionRightMargin:xe,captionLeftMargin:_e,captionBottomMargin:ke,captionTopMarginTablet:Se,captionRightMarginTablet:Ce,captionLeftMarginTablet:Te,captionBottomMarginTablet:Ee,captionTopMarginMobile:De,captionRightMarginMobile:Le,captionLeftMarginMobile:Be,captionBottomMarginMobile:He,captionMarginUnit:Ae,captionMarginUnitTablet:Re,captionMarginUnitMobile:Pe,captionMarginLink:ze,headingTag:Oe,headingShowOn:Fe,headingLoadGoogleFonts:Ie,headingFontFamily:Ne,headingFontWeight:Ve,headingFontStyle:Ge,headingFontSize:We,headingColor:Ue,headingTransform:je,headingDecoration:qe,headingFontSizeType:$e,headingFontSizeTypeMobile:Ze,headingFontSizeTypeTablet:Ke,headingFontSizeMobile:Ye,headingFontSizeTablet:Je,headingLineHeight:Xe,headingLineHeightType:Qe,headingLineHeightMobile:et,headingLineHeightTablet:tt,headingTopMargin:at,headingRightMargin:it,headingLeftMargin:lt,headingBottomMargin:nt,headingTopMarginTablet:ot,headingRightMarginTablet:rt,headingLeftMarginTablet:st,headingBottomMarginTablet:ut,headingTopMarginMobile:ct,headingRightMarginMobile:gt,headingLeftMarginMobile:dt,headingBottomMarginMobile:pt,headingMarginUnit:ht,headingMarginUnitTablet:mt,headingMarginUnitMobile:bt,headingMarginLink:ft,overlayPositionFromEdge:vt,overlayPositionFromEdgeUnit:wt,overlayContentPosition:yt,overlayBackground:xt,overlayOpacity:_t,overlayHoverOpacity:kt,separatorShowOn:St,separatorStyle:Ct,separatorWidth:Mt,separatorWidthType:Tt,separatorThickness:Et,separatorThicknessUnit:Dt,separatorPosition:Lt,separatorColor:Bt,separatorTopMargin:Ht,separatorRightMargin:At,separatorLeftMargin:Rt,separatorBottomMargin:Pt,separatorTopMarginTablet:zt,separatorRightMarginTablet:Ot,separatorLeftMarginTablet:Ft,separatorBottomMarginTablet:It,separatorTopMarginMobile:Nt,separatorRightMarginMobile:Vt,separatorLeftMarginMobile:Gt,separatorBottomMarginMobile:Wt,separatorMarginUnit:Ut,separatorMarginUnitTablet:jt,separatorMarginUnitMobile:qt,separatorMarginLink:$t,imageHoverEffect:Zt,useSeparateBoxShadows:Kt,imageBoxShadowColor:Yt,imageBoxShadowHOffset:Jt,imageBoxShadowVOffset:Xt,imageBoxShadowBlur:Qt,imageBoxShadowSpread:ea,imageBoxShadowPosition:ta,imageBoxShadowColorHover:aa,imageBoxShadowHOffsetHover:ia,imageBoxShadowVOffsetHover:la,imageBoxShadowBlurHover:na,imageBoxShadowSpreadHover:oa,imageBoxShadowPositionHover:ra,maskShape:sa,maskCustomShape:ua,maskSize:ca,maskPosition:ga,maskRepeat:da,headingLetterSpacing:pa,headingLetterSpacingTablet:ha,headingLetterSpacingMobile:ma,headingLetterSpacingType:ba,captionLetterSpacing:fa,captionLetterSpacingTablet:va,captionLetterSpacingMobile:wa,captionLetterSpacingType:ya,disableLazyLoad:xa}=t,{imageSizes:_a}=(0,V.useSelect)(e=>{const{getSettings:t}=e(Pi.store),{imageSizes:a}=t();return{imageSizes:a}},[n]),{image:ka}=(0,V.useSelect)(e=>{const{getMedia:t}=e(Ps.store);return{image:d&&l?t(d):null}},[d,l]),{imageDefaultSize:Sa}=(0,V.useSelect)(e=>{const{getSettings:t}=e(Pi.store),{imageDefaultSize:a}=t();return{imageDefaultSize:a}},[]),[Ca,Ma]=(0,x.useState)({desktop:D,tablet:L,mobile:B});(0,x.useEffect)(()=>{if(D)switch(o){case"Mobile":"custom"===B&&Ca.mobile!==B?a({objectFitMobile:"cover"}):"custom"!==B&&Ra(B),Ma({...Ca,mobile:B});break;case"Tablet":"custom"===L&&Ca.tablet!==L?a({objectFitTablet:"cover"}):"custom"!==L&&Aa(L),Ma({...Ca,tablet:L});break;default:"custom"===D&&Ca.desktop!==D?a({objectFit:"cover"}):"custom"!==D&&Ha(D),Ma({...Ca,desktop:D})}},[D,L,B]);const{allowResize:Ta=!0}=i,Ea=(0,X.useViewportMatch)("medium"),Da=["wide","full"].includes(S),La=Ta&&!(Da&&Ea),Ba=ka?.media_details&&_a.reduce((e,t)=>{if(ka?.media_details?.sizes[t.slug]){const a=e.pop();e.push({value:t.slug,label:t.name},a)}return e},[{value:"custom",label:"Custom"}]),Ha=e=>{const t=ka?.media_details?.sizes[e];if(!t||t?.source_url===p)return null;a({url:t?.source_url,width:t?.width,height:t?.height,sizeSlug:e})},Aa=e=>{const t=ka?.media_details?.sizes[e];if(!t||t?.source_url===h)return null;a({urlTablet:t?.source_url,widthTablet:t?.width,heightTablet:t?.height,sizeSlugTablet:e})},Ra=e=>{const t=ka?.media_details?.sizes[e];if(!t||t?.source_url===m)return null;a({urlMobile:t?.source_url,widthMobile:t?.width,heightMobile:t?.height,sizeSlugMobile:e})},Pa={desktop:[{value:"",label:(0,M.__)("Default","sureforms")},{value:"fill",label:(0,M.__)("Fill","sureforms")},{value:"cover",label:(0,M.__)("Cover","sureforms")},{value:"contain",label:(0,M.__)("Contain","sureforms")}],tablet:[{value:"",label:(0,M.__)("Default","sureforms")},{value:"fill",label:(0,M.__)("Fill","sureforms")},{value:"cover",label:(0,M.__)("Cover","sureforms")},{value:"contain",label:(0,M.__)("Contain","sureforms")}],mobile:[{value:"",label:(0,M.__)("Default","sureforms")},{value:"fill",label:(0,M.__)("Fill","sureforms")},{value:"cover",label:(0,M.__)("Cover","sureforms")},{value:"contain",label:(0,M.__)("Contain","sureforms")}]},za=(0,w.createElement)(Jo,{title:(0,M.__)("Image","sureforms"),initialOpen:!0},(0,w.createElement)(ss,{onSelectImage:e=>{if(!e||!e.url)return void a({url:void 0,alt:void 0,id:void 0,title:void 0,caption:void 0});let t=Zs(e,Sa);t={...t,...Xs(e,"Tablet"),...Xs(e,"Mobile")},"custom"===D&&(delete t.width,delete t.height),a(t)},backgroundImage:{url:p},onRemoveImage:()=>{a({url:void 0,urlTablet:void 0,urlMobile:void 0,alt:void 0,id:void 0,title:void 0,caption:void 0,width:void 0,widthTablet:void 0,widthMobile:void 0,height:void 0,heightTablet:void 0,heightMobile:void 0})},disableLabel:!0}),(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Disable Lazy Loading","sureforms"),checked:xa,onChange:()=>{a({disableLazyLoad:!xa})}}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),data:{desktop:{value:S,label:"align"},tablet:{value:C,label:"alignTablet"},mobile:{value:T,label:"alignMobile"}},className:"uagb-multi-button-alignment-control",options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0,responsive:!0}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Layout","sureforms"),data:{value:g,label:"layout"},className:"uagb-multi-button-alignment-control",options:[{value:"default",label:(0,M.__)("Normal","sureforms")},{value:"overlay",label:(0,M.__)("Overlay","sureforms")}],showIcons:!1}),"overlay"===g&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Rs,{label:(0,M.__)("Content Position","sureforms"),data:{label:"overlayContentPosition",value:yt},setAttributes:a}),(0,w.createElement)(Hr,{setAttributes:a,prefix:"overlay",attributes:t,deviceType:o}),(0,w.createElement)(Me,{label:(0,M.__)("Border Distance From EDGE","sureforms"),setAttributes:a,value:vt,data:{value:vt,label:"overlayPositionFromEdge"},min:-100,max:100,unit:{value:wt,label:"overlayPositionFromEdgeUnit"}})),l&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ss,{onChange:e=>a(e),data:{sizeSlug:{label:"sizeSlug",value:D},sizeSlugTablet:{label:"sizeSlugTablet",value:L},sizeSlugMobile:{label:"sizeSlugMobile",value:B}},width:b||A,widthTablet:f,widthMobile:v,height:y||R,heightTablet:_,heightMobile:k,setAttributes:a,imageSizeOptions:Ba,isResizable:La,imageWidth:A,imageHeight:R}),(0,w.createElement)(Xi,{label:(0,M.__)("Alt Text","sureforms"),enableDynamicContent:!0,dynamicContentType:"text",value:E,name:"alt",setAttributes:a,data:{value:E,label:"alt"}})),(0,w.createElement)(Jr,{label:(0,M.__)("Object Fit","sureforms"),data:{desktop:{value:s,label:"objectFit"},tablet:{value:u,label:"objectFitTablet"},mobile:{value:c,label:"objectFitMobile"}},options:Pa,setAttributes:a}),(0,w.createElement)(de,{label:(0,M.__)("On Hover Image","sureforms"),data:{value:Zt,label:"imageHoverEffect"},setAttributes:a,options:[{value:"static",label:(0,M.__)("Static","sureforms")},{value:"zoomin",label:(0,M.__)("Zoom In","sureforms")},{value:"slide",label:(0,M.__)("Slide","sureforms")},{value:"grayscale",label:(0,M.__)("Gray Scale","sureforms")},{value:"blur",label:(0,M.__)("Blur","sureforms")}]}),"overlay"!==g&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Enable Caption","sureforms"),checked:H,onChange:()=>{a({enableCaption:!H})}}),H&&(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),data:{value:ae,label:"captionAlign"},className:"uagb-multi-button-alignment-control",options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0}))),Oa=(0,w.createElement)(Jo,{title:(0,M.__)("Mask","sureforms"),initialOpen:!1},(0,w.createElement)(de,{label:(0,M.__)("Mask Shape","sureforms"),data:{value:sa,label:"maskShape"},setAttributes:a,options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"circle",label:(0,M.__)("Circle","sureforms")},{value:"diamond",label:(0,M.__)("Diamond","sureforms")},{value:"hexagon",label:(0,M.__)("Hexagon","sureforms")},{value:"rounded",label:(0,M.__)("Rounded","sureforms")},{value:"blob1",label:(0,M.__)("Blob 1","sureforms")},{value:"blob2",label:(0,M.__)("Blob 2","sureforms")},{value:"blob3",label:(0,M.__)("Blob 3","sureforms")},{value:"blob4",label:(0,M.__)("Blob 4","sureforms")},{value:"custom",label:(0,M.__)("Custom","sureforms")}]}),"custom"===sa&&(0,w.createElement)(ss,{onSelectImage:e=>{e&&e.url?e.type&&"image"===e.type&&a({maskCustomShape:e}):a({maskCustomShape:null})},backgroundImage:ua,onRemoveImage:()=>{a({maskCustomShape:null})},label:(0,M.__)("Custom Mask Image","sureforms"),slug:"custom-mask-image"}),"none"!==sa&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(de,{label:(0,M.__)("Mask Size","sureforms"),data:{value:ca,label:"maskSize"},setAttributes:a,options:[{value:"auto",label:(0,M.__)("Auto","sureforms")},{value:"contain",label:(0,M.__)("Contain","sureforms")},{value:"cover",label:(0,M.__)("Cover","sureforms")}]}),(0,w.createElement)(de,{label:(0,M.__)("Mask Position","sureforms"),data:{value:ga,label:"maskPosition"},setAttributes:a,options:[{value:"center top",label:(0,M.__)("Center Top","sureforms")},{value:"center center",label:(0,M.__)("Center Center","sureforms")},{value:"center bottom",label:(0,M.__)("Center Bottom","sureforms")},{value:"left top",label:(0,M.__)("Left Top","sureforms")},{value:"left center",label:(0,M.__)("Left Center","sureforms")},{value:"left bottom",label:(0,M.__)("Left Bottom","sureforms")},{value:"right top",label:(0,M.__)("Right Top","sureforms")},{value:"right center",label:(0,M.__)("Right Center","sureforms")},{value:"right bottom",label:(0,M.__)("Right Bottom","sureforms")}]}),(0,w.createElement)(de,{label:(0,M.__)("Mask Repeat","sureforms"),data:{value:da,label:"maskRepeat"},setAttributes:a,options:[{value:"no-repeat",label:(0,M.__)("No Repeat","sureforms")},{value:"repeat",label:(0,M.__)("Repeat","sureforms")},{value:"repeat-x",label:(0,M.__)("Repeat-X","sureforms")},{value:"repeat-y",label:(0,M.__)("Repeat-Y","sureforms")}]}))),Fa=(0,w.createElement)(Jo,{title:(0,M.__)("Separator","sureforms"),initialOpen:!1},"none"!==Ct&&(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Show On","sureforms"),data:{value:St,label:"separatorShowOn"},className:"uagb-multi-button-alignment-control",options:[{value:"always",label:(0,M.__)("Always","sureforms")},{value:"hover",label:(0,M.__)("Hover","sureforms")}],showIcons:!1}),(0,w.createElement)(de,{label:(0,M.__)("Style","sureforms"),data:{value:Ct,label:"separatorStyle"},setAttributes:a,options:[{value:"none",label:(0,M.__)("None","sureforms")},{value:"solid",label:(0,M.__)("Solid","sureforms")},{value:"double",label:(0,M.__)("Double","sureforms")},{value:"dashed",label:(0,M.__)("Dashed","sureforms")},{value:"dotted",label:(0,M.__)("Dotted","sureforms")}]}),"none"!==Ct&&(0,w.createElement)(de,{label:(0,M.__)("Position","sureforms"),data:{value:Lt,label:"separatorPosition"},setAttributes:a,options:[{value:"before_title",label:(0,M.__)("Before Title","sureforms")},{value:"after_title",label:(0,M.__)("After Title","sureforms")},{value:"after_sub_title",label:(0,M.__)("After Sub Title","sureforms")}]})),Ia=(0,w.createElement)(Jo,{title:(0,M.__)("Heading","sureforms"),initialOpen:!1},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Show On","sureforms"),data:{value:Fe,label:"headingShowOn"},className:"uagb-multi-button-alignment-control",options:[{value:"always",label:(0,M.__)("Always","sureforms")},{value:"hover",label:(0,M.__)("Hover","sureforms")}],showIcons:!1})),Na=(0,w.createElement)(Jo,{title:(0,M.__)("Description","sureforms"),initialOpen:!1},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Show On","sureforms"),data:{value:Q,label:"captionShowOn"},className:"uagb-multi-button-alignment-control",options:[{value:"always",label:(0,M.__)("Always","sureforms")},{value:"hover",label:(0,M.__)("Hover","sureforms")}],showIcons:!1})),Va=(0,w.createElement)(Jo,{title:(0,M.__)("Heading","sureforms"),initialOpen:!1},(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Heading Tag","sureforms"),data:{value:Oe,label:"headingTag"},options:[{value:"h1",label:(0,M.__)("H1","sureforms")},{value:"h2",label:(0,M.__)("H2","sureforms")},{value:"h3",label:(0,M.__)("H3","sureforms")},{value:"h4",label:(0,M.__)("H4","sureforms")},{value:"h5",label:(0,M.__)("H5","sureforms")},{value:"h6",label:(0,M.__)("H6","sureforms")}]}),(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),setAttributes:a,loadGoogleFonts:{value:Ie,label:"headingLoadGoogleFonts"},fontFamily:{value:Ne,label:"headingFontFamily"},fontWeight:{value:Ve,label:"headingFontWeight"},fontStyle:{value:Ge,label:"headingFontStyle"},transform:{value:je,label:"headingTransform"},decoration:{value:qe,label:"headingDecoration"},fontSizeType:{value:$e,label:"headingFontSizeType"},fontSizeTypeTablet:{value:Ke,label:"headingFontSizeTypeTablet"},fontSizeTypeMobile:{value:Ze,label:"headingFontSizeTypeMobile"},fontSize:{value:We,label:"headingFontSize"},fontSizeMobile:{value:Ye,label:"headingFontSizeMobile"},fontSizeTablet:{value:Je,label:"headingFontSizeTablet"},lineHeightType:{value:Qe,label:"headingLineHeightType"},lineHeight:{value:Xe,label:"headingLineHeight"},lineHeightMobile:{value:et,label:"headingLineHeightMobile"},lineHeightTablet:{value:tt,label:"headingLineHeightTablet"},letterSpacing:{value:pa,label:"headingLetterSpacing"},letterSpacingTablet:{value:ha,label:"headingLetterSpacingTablet"},letterSpacingMobile:{value:ma,label:"headingLetterSpacingMobile"},letterSpacingType:{value:ba,label:"headingLetterSpacingType"}}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:Ue||"",data:{value:Ue,label:"headingColor"},setAttributes:a}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:at,label:"headingTopMargin"},valueRight:{value:it,label:"headingRightMargin"},valueBottom:{value:nt,label:"headingBottomMargin"},valueLeft:{value:lt,label:"headingLeftMargin"},valueTopTablet:{value:ot,label:"headingTopMarginTablet"},valueRightTablet:{value:rt,label:"headingRightMarginTablet"},valueBottomTablet:{value:ut,label:"headingBottomMarginTablet"},valueLeftTablet:{value:st,label:"headingLeftMarginTablet"},valueTopMobile:{value:ct,label:"headingTopMarginMobile"},valueRightMobile:{value:gt,label:"headingRightMarginMobile"},valueBottomMobile:{value:pt,label:"headingBottomMarginMobile"},valueLeftMobile:{value:dt,label:"headingLeftMarginMobile"},unit:{value:ht,label:"headingMarginUnit"},mUnit:{value:bt,label:"headingMarginUnitMobile"},tUnit:{value:mt,label:"headingMarginUnitTablet"},deviceType:o,attributes:t,setAttributes:a,link:{value:ft,label:"headingMarginLink"}})),Ga=(0,w.createElement)(Jo,{title:"overlay"===g?(0,M.__)("Description","sureforms"):(0,M.__)("Caption","sureforms"),initialOpen:!1},(0,w.createElement)(Qa,{label:(0,M.__)("Typography","sureforms"),setAttributes:a,loadGoogleFonts:{value:ee,label:"captionLoadGoogleFonts"},fontFamily:{value:ie,label:"captionFontFamily"},fontWeight:{value:le,label:"captionFontWeight"},fontStyle:{value:ne,label:"captionFontStyle"},transform:{value:se,label:"captionTransform"},decoration:{value:ue,label:"captionDecoration"},fontSizeType:{value:ce,label:"captionFontSizeType"},fontSizeTypeTablet:{value:pe,label:"captionFontSizeTypeTablet"},fontSizeTypeMobile:{value:ge,label:"captionFontSizeTypeMobile"},fontSize:{value:oe,label:"captionFontSize"},fontSizeMobile:{value:he,label:"captionFontSizeMobile"},fontSizeTablet:{value:me,label:"captionFontSizeTablet"},lineHeightType:{value:fe,label:"captionLineHeightType"},lineHeight:{value:be,label:"captionLineHeight"},lineHeightMobile:{value:ve,label:"captionLineHeightMobile"},lineHeightTablet:{value:we,label:"captionLineHeightTablet"},letterSpacing:{value:fa,label:"captionLetterSpacing"},letterSpacingTablet:{value:va,label:"captionLetterSpacingTablet"},letterSpacingMobile:{value:wa,label:"captionLetterSpacingMobile"},letterSpacingType:{value:ya,label:"captionLetterSpacingType"}}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:re||"",data:{value:re,label:"captionColor"},setAttributes:a}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:ye,label:"captionTopMargin"},valueRight:{value:xe,label:"captionRightMargin"},valueBottom:{value:ke,label:"captionBottomMargin"},valueLeft:{value:_e,label:"captionLeftMargin"},valueTopTablet:{value:Se,label:"captionTopMarginTablet"},valueRightTablet:{value:Ce,label:"captionRightMarginTablet"},valueBottomTablet:{value:Ee,label:"captionBottomMarginTablet"},valueLeftTablet:{value:Te,label:"captionLeftMarginTablet"},valueTopMobile:{value:De,label:"captionTopMarginMobile"},valueRightMobile:{value:Le,label:"captionRightMarginMobile"},valueBottomMobile:{value:He,label:"captionBottomMarginMobile"},valueLeftMobile:{value:Be,label:"captionLeftMarginMobile"},unit:{value:Ae,label:"captionMarginUnit"},mUnit:{value:Pe,label:"captionMarginUnitMobile"},tUnit:{value:Re,label:"captionMarginUnitTablet"},deviceType:o,attributes:t,setAttributes:a,link:{value:ze,label:"captionMarginLink"}})),Wa=(0,w.createElement)(Jo,{title:(0,M.__)("Image","sureforms"),initialOpen:!0},(0,w.createElement)(Hr,{setAttributes:a,prefix:"image",attributes:t,deviceType:o}),(0,w.createElement)(Yo,{label:(0,M.__)("Margin","sureforms"),valueTop:{value:P,label:"imageTopMargin"},valueRight:{value:z,label:"imageRightMargin"},valueBottom:{value:F,label:"imageBottomMargin"},valueLeft:{value:O,label:"imageLeftMargin"},valueTopTablet:{value:I,label:"imageTopMarginTablet"},valueRightTablet:{value:N,label:"imageRightMarginTablet"},valueBottomTablet:{value:W,label:"imageBottomMarginTablet"},valueLeftTablet:{value:G,label:"imageLeftMarginTablet"},valueTopMobile:{value:U,label:"imageTopMarginMobile"},valueRightMobile:{value:j,label:"imageRightMarginMobile"},valueBottomMobile:{value:$,label:"imageBottomMarginMobile"},valueLeftMobile:{value:q,label:"imageLeftMarginMobile"},unit:{value:Z,label:"imageMarginUnit"},mUnit:{value:Y,label:"imageMarginUnitMobile"},tUnit:{value:K,label:"imageMarginUnitTablet"},deviceType:o,attributes:t,setAttributes:a,link:{value:J,label:"imageMarginLink"}})),Ua=(0,w.createElement)(Jo,{title:(0,M.__)("Box Shadow","sureforms"),initialOpen:!1},(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Separate Hover Shadow","sureforms"),checked:Kt,onChange:()=>a({useSeparateBoxShadows:!Kt})}),Kt?(0,w.createElement)(Er,{tabs:[{name:"normal",title:(0,M.__)("Normal","sureforms")},{name:"hover",title:(0,M.__)("Hover","sureforms")}],normal:(0,w.createElement)(w.Fragment,null,(0,w.createElement)(qs,{setAttributes:a,presets:Fs,presetInputType:"radioImage"}),(0,w.createElement)(us,{blockId:r,setAttributes:a,label:(0,M.__)("Box Shadow","sureforms"),boxShadowColor:{value:Yt,label:"imageBoxShadowColor",title:(0,M.__)("Color","sureforms")},boxShadowHOffset:{value:Jt,label:"imageBoxShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},boxShadowVOffset:{value:Xt,label:"imageBoxShadowVOffset",title:(0,M.__)("Vertical","sureforms")},boxShadowBlur:{value:Qt,label:"imageBoxShadowBlur",title:(0,M.__)("Blur","sureforms")},boxShadowSpread:{value:ea,label:"imageBoxShadowSpread",title:(0,M.__)("Spread","sureforms")},boxShadowPosition:{value:ta,label:"imageBoxShadowPosition",title:(0,M.__)("Position","sureforms")},popup:!1})),hover:(0,w.createElement)(w.Fragment,null,(0,w.createElement)(qs,{setAttributes:a,presets:Os,presetInputType:"radioImage"}),(0,w.createElement)(us,{blockId:r,setAttributes:a,label:(0,M.__)("Box Shadow","sureforms"),boxShadowColor:{value:aa,label:"imageBoxShadowColorHover",title:(0,M.__)("Color","sureforms")},boxShadowHOffset:{value:ia,label:"imageBoxShadowHOffsetHover",title:(0,M.__)("Horizontal","sureforms")},boxShadowVOffset:{value:la,label:"imageBoxShadowVOffsetHover",title:(0,M.__)("Vertical","sureforms")},boxShadowBlur:{value:na,label:"imageBoxShadowBlurHover",title:(0,M.__)("Blur","sureforms")},boxShadowSpread:{value:oa,label:"imageBoxShadowSpreadHover",title:(0,M.__)("Spread","sureforms")},boxShadowPosition:{value:ra,label:"imageBoxShadowPositionHover",title:(0,M.__)("Position","sureforms")},popup:!1})),disableBottomSeparator:!0}):(0,w.createElement)(w.Fragment,null,(0,w.createElement)(qs,{setAttributes:a,presets:Fs,presetInputType:"radioImage"}),(0,w.createElement)(us,{blockId:r,setAttributes:a,label:(0,M.__)("Box Shadow","sureforms"),boxShadowColor:{value:Yt,label:"imageBoxShadowColor",title:(0,M.__)("Color","sureforms")},boxShadowHOffset:{value:Jt,label:"imageBoxShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},boxShadowVOffset:{value:Xt,label:"imageBoxShadowVOffset",title:(0,M.__)("Vertical","sureforms")},boxShadowBlur:{value:Qt,label:"imageBoxShadowBlur",title:(0,M.__)("Blur","sureforms")},boxShadowSpread:{value:ea,label:"imageBoxShadowSpread",title:(0,M.__)("Spread","sureforms")},boxShadowPosition:{value:ta,label:"imageBoxShadowPosition",title:(0,M.__)("Position","sureforms")},popup:!1}))),ja=(0,w.createElement)(Jo,{title:(0,M.__)("Overlay","sureforms"),initialOpen:!1},(0,w.createElement)(Ti,{label:(0,M.__)("Background","sureforms"),colorValue:xt||"",data:{value:xt,label:"overlayBackground"},setAttributes:a}),(0,w.createElement)(Me,{label:(0,M.__)("Overlay Opacity","sureforms"),setAttributes:a,value:_t,data:{value:_t,label:"overlayOpacity"},min:0,max:1,step:.1,displayUnit:!1}),(0,w.createElement)(Me,{label:(0,M.__)("Overlay Hover Opacity","sureforms"),setAttributes:a,value:kt,data:{value:kt,label:"overlayHoverOpacity"},min:0,max:1,step:.1,displayUnit:!1})),qa=(0,w.createElement)(Jo,{title:"Separator",initialOpen:!1},(0,w.createElement)(Me,{label:(0,M.__)("Width","sureforms"),setAttributes:a,value:Mt,data:{value:Mt,label:"separatorWidth"},min:0,max:"%"===Tt?100:500,unit:{value:Tt,label:"separatorWidthType"},units:[{name:(0,M.__)("Pixel","sureforms"),unitValue:"px"},{name:(0,M.__)("Em","sureforms"),unitValue:"em"},{name:(0,M.__)("%","sureforms"),unitValue:"%"}]}),(0,w.createElement)(Me,{label:(0,M.__)("Thickness","sureforms"),setAttributes:a,value:Et,data:{value:Et,label:"separatorThickness"},min:0,max:10,unit:{value:Dt,label:"separatorThicknessUnit"}}),(0,w.createElement)(Ti,{label:(0,M.__)("Color","sureforms"),colorValue:Bt||"",data:{value:Bt,label:"separatorColor"},setAttributes:a}),(0,w.createElement)(Yo,{...e,label:(0,M.__)("Margin","sureforms"),valueTop:{value:Ht,label:"separatorTopMargin"},valueRight:{value:At,label:"separatorRightMargin"},valueBottom:{value:Pt,label:"separatorBottomMargin"},valueLeft:{value:Rt,label:"separatorLeftMargin"},valueTopTablet:{value:zt,label:"separatorTopMarginTablet"},valueRightTablet:{value:Ot,label:"separatorRightMarginTablet"},valueBottomTablet:{value:It,label:"separatorBottomMarginTablet"},valueLeftTablet:{value:Ft,label:"separatorLeftMarginTablet"},valueTopMobile:{value:Nt,label:"separatorTopMarginMobile"},valueRightMobile:{value:Vt,label:"separatorRightMarginMobile"},valueBottomMobile:{value:Wt,label:"separatorBottomMarginMobile"},valueLeftMobile:{value:Gt,label:"separatorLeftMarginMobile"},unit:{value:Ut,label:"separatorMarginUnit"},mUnit:{value:qt,label:"separatorMarginUnitMobile"},tUnit:{value:jt,label:"separatorMarginUnitTablet"},deviceType:o,attributes:t,setAttributes:a,link:{value:$t,label:"separatorMarginLink"}}));return(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Pi.InspectorControls,null,(0,w.createElement)(di,null,(0,w.createElement)(pi,{...hi,parentProps:e},za,Oa,"overlay"===g&&(0,w.createElement)(w.Fragment,null,Ia,Na,Fa)),(0,w.createElement)(pi,{...mi,parentProps:e},Wa,"static"===Zt&&Ua,"overlay"===g&&(0,w.createElement)(w.Fragment,null,ja,Va,Ga),H&&"overlay"!==g&&Ga,"none"!==Ct&&"overlay"===g&&qa))))}const eu=window.wp.primitives,tu=(0,x.createElement)(eu.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,x.createElement)(eu.Path,{d:"M18.5 15v3.5H13V6.7l4.5 4.1 1-1.1-6.2-5.8-5.8 5.8 1 1.1 4-4v11.7h-6V15H4v5h16v-5z"})),au=window.wp.url,iu=(0,x.createElement)(eu.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,x.createElement)(eu.Path,{d:"M16.5 7.8v7H18v-7c0-1-.8-1.8-1.8-1.8h-7v1.5h7c.2 0 .3.1.3.3zm-8.7 8.7c-.1 0-.2-.1-.2-.2V2H6v4H2v1.5h4v8.8c0 1 .8 1.8 1.8 1.8h8.8v4H18v-4h4v-1.5H7.8z"})),lu="none",nu="media",ou="attachment",ru="custom",su=["image"];function uu({temporaryURL:e,attributes:t,attributes:{url:a="",urlTablet:i="",urlMobile:l="",alt:n,align:o,id:r,width:s,widthTablet:u,widthMobile:c,height:g,heightTablet:d,heightMobile:p,disableLazyLoad:h},setAttributes:m,isSelected:b,onCloseModal:f,onSelectImage:v,onSelectURL:y,onUploadError:_,containerRef:k,context:S,clientId:C,onImageLoadError:T}){const E=(0,x.useRef)(),{allowResize:D=!0}=S,{toggleSelection:L}=(0,V.useDispatch)(Pi.store),B=Q(),{multiImageSelection:H}=(0,V.useSelect)(e=>{const{getMultiSelectedBlockClientIds:t,getBlockName:a}=e(Pi.store),i=t();return{multiImageSelection:i.length&&i.every(e=>"srfm/image"===a(e))}},[r,b]),{imageEditing:A,maxWidth:R}=(0,V.useSelect)(e=>{const{getSettings:t}=e(Pi.store),{imageEditing:a,maxWidth:i}=t();return{imageEditing:a,maxWidth:i}},[C]),P=(0,X.useViewportMatch)("medium"),z=["wide","full"].includes(o),[{loadedNaturalWidth:O,loadedNaturalHeight:F},I]=(0,x.useState)({}),[N,G]=(0,x.useState)(!1),W=function(e,t){const[a,i]=(0,x.useState)();function l(){i(e.current.clientWidth)}return(0,x.useEffect)(l,t),(0,x.useEffect)(()=>{const{defaultView:t}=e.current.ownerDocument;return t.addEventListener("resize",l),()=>{t.removeEventListener("resize",l)}},[]),a}(k,[o]),U=D&&!(z&&P),{naturalWidth:j,naturalHeight:q}=(0,x.useMemo)(()=>{const e=E.current?.naturalWidth||O||void 0,a=E.current?.naturalHeight||F||void 0;return t.naturalWidth&&t.naturalHeight||m({naturalWidth:e,naturalHeight:a}),{naturalWidth:e,naturalHeight:a}},[O,F,E.current?.complete]),$=(0,au.getFilename)(a);let Z;Z=n||($?(0,M.sprintf)(/* translators: %s: file name */ /* translators: %s: file name */ (0,M.__)("This image has an empty alt attribute; its file name is %s","sureforms"),$):(0,M.__)("This image has an empty alt attribute","sureforms"));let K,Y,J=(0,w.createElement)(w.Fragment,null,(0,w.createElement)("img",{srcSet:`${e||a} ${i?","+i+" 780w":""}${l?", "+l+" 360w":""}`,src:e||a,alt:Z,onLoad:e=>{I({loadedNaturalWidth:e.target?.naturalWidth,loadedNaturalHeight:e.target?.naturalHeight})},ref:E,loading:h?"eager":"lazy"}),e&&(0,w.createElement)(te.Spinner,null));if(W&&j&&q){const e=j>W;K=e?W:j,Y=e?W*(q/j):q}(0,x.useEffect)(()=>{b||G(!1),b&&Js(r)&&T()},[b]);const ee=r&&j&&q&&A,ae=!H&&ee&&!N;if(ee&&N)J=(0,w.createElement)(Pi.__experimentalImageEditor,{id:r,url:a,width:s,height:g,clientWidth:W,naturalHeight:q,naturalWidth:j,onSaveImage:e=>m(e),onFinishEditing:()=>{G(!1)}});else if(U&&K){const e=s||K,t=g||Y,a=j/q,i=j<q?20:20*a,l=q<j?20:20/a,n=2.5*R;let r=!1,h=!1;"center"===o?(r=!0,h=!0):(0,M.isRTL)()?"left"===o?r=!0:h=!0:"right"===o?h=!0:r=!0;let f="",v="";"Tablet"===B?(f=u||s,v=d||g):"Mobile"===B?(f=c||u||s,v=p||d||g):(f=s,v=g),J=(0,w.createElement)(te.ResizableBox,{size:{width:f||"auto",height:v||"auto"},showHandle:b,minWidth:i,maxWidth:n,minHeight:l,maxHeight:n/a,lockAspectRatio:!0,enable:{top:!1,right:r,bottom:!0,left:h},onResizeStart:function(){L(!1)},onResizeStop:(a,i,l,n)=>{if(L(!0),"Tablet"===B){const e=u||780;m({widthTablet:Math.abs(parseInt(e+n.width,10)),heightTablet:Math.abs(parseInt(d+n.height,10))})}else if("Mobile"===B){const e=c||320;m({widthMobile:Math.abs(parseInt(e+n.width,10)),heightMobile:Math.abs(parseInt(p+n.height,10))})}else m({width:Math.abs(parseInt(e+n.width,10)),height:Math.abs(parseInt(t+n.height,10))})}},J)}else"full"!==o&&(J=(0,w.createElement)("div",null,J));const ie=(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Pi.BlockControls,{group:"block"},ae&&(0,w.createElement)(te.ToolbarButton,{onClick:()=>G(!0),icon:iu,label:(0,M.__)("Crop","sureforms")})),!H&&!N&&(0,w.createElement)(Pi.BlockControls,{group:"other"},(0,w.createElement)(Pi.MediaReplaceFlow,{mediaId:r,mediaURL:a,allowedTypes:su,accept:"image/*",onSelect:v,onSelectURL:y,onError:_,onCloseModal:f})));return(0,w.createElement)(w.Fragment,null,!e&&ie,J)}function cu({attributes:e,isSelected:t,setAttributes:a,captionRef:i}){const{caption:l,enableCaption:n,heading:o,headingTag:r,layout:s,overlayContentPosition:u,separatorStyle:c,separatorPosition:g}=e,d=(0,x.useRef)();(0,x.useEffect)(()=>{d.current=o},[l]);const p=(0,w.createElement)(w.Fragment,null,(!Pi.RichText.isEmpty(o)||t)&&(0,w.createElement)(Pi.RichText,{ref:d,tagName:r,className:"uagb-image-heading","aria-label":(0,M.__)("Image overlay heading text","sureforms"),placeholder:(0,M.__)("Add Heading","sureforms"),value:o,onChange:e=>a({heading:e})})),h=(0,w.createElement)(w.Fragment,null,(!Pi.RichText.isEmpty(l)||t)&&(0,w.createElement)(Pi.RichText,{ref:i,tagName:"figcaption",className:"uagb-image-caption","aria-label":(0,M.__)("Image caption text","sureforms"),placeholder:(0,M.__)("Add caption","sureforms"),value:l,onChange:e=>a({caption:e})})),m="none"!==c&&(0,w.createElement)("div",{className:"uagb-image-separator"});return(0,w.createElement)(w.Fragment,null,"overlay"===s?(0,w.createElement)(w.Fragment,null,(0,w.createElement)("div",{className:"wp-block-uagb-image--layout-overlay__color-wrapper"}),(0,w.createElement)("div",{className:`wp-block-uagb-image--layout-overlay__inner ${u.replace(" ","-")}`},"before_title"===g&&m,p,"after_title"===g&&m,h,"after_sub_title"===g&&m)):(0,w.createElement)(w.Fragment,null,n&&h))}var gu=a(4486),du={};gu.A&&gu.A.locals&&(du.locals=gu.A.locals);var pu,hu=0,mu={attributes:{id:"uagb-editor-styles"}};mu.setAttributes=g(),mu.insert=u().bind(null,"head"),mu.domAPI=r(),mu.insertStyleElement=p(),du.use=function(e){return mu.options=e||{},hu++||(pu=n()(gu.A,mu)),du},du.unuse=function(){hu>0&&! --hu&&(pu(),pu=null)};const bu=du,fu=e=>{let{attributes:t}=e;const{setAttributes:a,className:i,isSelected:l,insertBlocksAfter:n,onReplace:o,context:r,clientId:s,deviceType:u}=e;e?.loopUrl&&(t={...t,url:e.loopUrl}),e?.loopAlt&&(t={...t,alt:e.loopAlt}),e?.loopWidth&&(t={...t,width:e.loopWidth});const{block_id:c,layout:g,url:d,alt:p,caption:h,align:m,id:b,linkTarget:f,linkClass:v,rel:y,imageHoverEffect:_,href:k,linkDestination:S,sizeSlug:T,sizeSlugTablet:E,sizeSlugMobile:D}=t;(0,x.useLayoutEffect)(()=>(bu.use(),()=>{bu.unuse()}),[]);const{createNotice:L}=(0,V.useDispatch)("core/notices"),[B,H]=(0,x.useState)(),[A,R]=(0,x.useState)(),P=(0,x.useRef)();(0,x.useEffect)(()=>{P.current=p},[p]);const z=(0,x.useRef)();(0,x.useEffect)(()=>{z.current=h},[h]);const O=(0,x.useRef)(),{imageDefaultSize:F,mediaUpload:I}=(0,V.useSelect)(e=>{const{getSettings:t}=e(Pi.store),{imageDefaultSize:a,mediaUpload:i}=t();return{imageDefaultSize:a,mediaUpload:i}},[]),{image:N}=(0,V.useSelect)(e=>{const{getMedia:t}=e(Ps.store);return{image:b&&l?t(b):null}},[b,l]);function G(){Js(t?.id)&&a({url:void 0,id:void 0})}function W(e){L("error",e,{type:"snackbar"})}function U(e){if(!e||!e.url)return void a({url:void 0,alt:void 0,id:void 0,title:void 0,caption:void 0});if((0,$s.isBlobURL)(e.url))return void H(e.url);H();let i=Zs(e,F);"custom"===T&&(delete i.width,delete i.height),z.current&&!i.caption&&(i={...i,alt:i.alt,id:i.id,link:i.link});let l={};e.id&&e.id===b?l={url:d}:("custom"!==T&&(l={width:void 0,height:void 0,sizeSlug:Ys(e,F)?F:"full",...l}),"custom"!==E&&(l={...l,sizeSlugTablet:Ys(e,F)?F:"full"}),"custom"!==D&&(l={...l,sizeSlugMobile:Ys(e,F)?F:"full"}));let n,o=t.linkDestination;if(!o)switch(wp?.media?.view?.settings?.defaultProps?.link||lu){case"file":case nu:o=nu;break;case"post":case ou:o=ou;break;case ru:o=ru;break;case lu:o=lu}switch(o){case nu:n=e.url;break;case ou:n=e.link}i.href=n,i={...i,...Xs(e,"Tablet"),...Xs(e,"Mobile")};const r={...i,...l,linkDestination:o};a(r)}function j(e){if(e!==d){let t={url:e,urlTablet:e,urlMobile:e,id:void 0};"custom"!==T&&(t={...t,width:void 0,height:void 0,sizeSlug:F}),"custom"!==E&&(t={...t,widthTablet:void 0,heightTablet:void 0,sizeSlugTablet:F}),"custom"!==D&&(t={...t,heightMobile:void 0,widthMobile:void 0,sizeSlugMobile:F}),a(t)}}let q=((e,t)=>!e&&(0,$s.isBlobURL)(t))(b,d);(0,x.useEffect)(()=>{if(!q)return;const e=(0,$s.getBlobByURL)(d);e&&I({filesList:[e],onFileChange:([e])=>{U(e)},allowedTypes:su,onError:e=>{q=!1,L("error",e,{type:"snackbar"}),a({src:void 0,id:void 0,url:void 0})}})},[]),(0,x.useEffect)(()=>{q?H(d):(0,$s.revokeBlobURL)(B)},[q,d]);const $=Ks(b,d)?d:void 0,Z=!!d&&(0,w.createElement)("img",{alt:(0,M.__)("Edit image","sureforms"),title:(0,M.__)("Edit image","sureforms"),className:"edit-image-preview",src:d});return(0,x.useEffect)(()=>{Ks(b,d)&&l&&!A&&window.fetch(d).then(e=>e.blob()).then(e=>R(e)).catch(()=>{})},[b,d,l,A]),(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Pi.BlockControls,{group:"block"},(0,w.createElement)(Pi.__experimentalImageURLInputUI,{url:k||"",onChangeUrl:function(e){a(e)},linkDestination:S,mediaUrl:N&&N.source_url||d,mediaLink:N&&N.link,linkTarget:f,linkClass:v,rel:y}),A&&(0,w.createElement)(te.ToolbarButton,{onClick:function(){I({filesList:[A],onFileChange([e]){U(e),(0,$s.isBlobURL)(e?.url)||(R(),L("success",(0,M.__)("Image uploaded.","sureforms"),{type:"snackbar"}))},allowedTypes:su,onError(e){L("error",e,{type:"snackbar"})}})},icon:tu,label:(0,M.__)("Upload external image","sureforms")})),(0,w.createElement)("div",{ref:O,className:ri()(i,"wp-block-uagb-image","uagb-block",`uagb-editor-preview-mode-${u.toLowerCase()}`,`uagb-block-${c}`,`wp-block-uagb-image--layout-${g}`,`wp-block-uagb-image--effect-${_}`,`wp-block-uagb-image--align-${m||"none"}`)},(B||d)&&(0,w.createElement)("figure",{className:"wp-block-uagb-image__figure"},(0,w.createElement)(uu,{temporaryURL:B,attributes:t,setAttributes:a,isSelected:l,insertBlocksAfter:n,onReplace:o,onSelectImage:U,onSelectURL:j,onUploadError:W,containerRef:O,context:r,clientId:s,onCloseModal:G,onImageLoadError:function(e=!1){e||a({url:void 0,id:void 0})}}),(0,w.createElement)(cu,{captionRef:z,attributes:t,setAttributes:a,isSelected:l})),(0,w.createElement)(Pi.MediaPlaceholder,{icon:(0,w.createElement)(Pi.BlockIcon,{icon:C.image}),labels:{title:(0,M.__)("Image","sureforms"),instructions:(0,M.__)("Upload an image file, pick one from your media library, or add one with a URL.","sureforms")},onSelect:U,onSelectURL:j,onError:W,onClose:G,accept:"image/*",allowedTypes:su,value:{id:b,src:$},mediaPreview:Z,disableMediaButtons:B||d})))};fu.propTypes={},fu.defaultProps={};const vu=(0,x.memo)(fu),wu=(0,X.compose)(function(e){return t=>{const{attributes:a,context:i}=t,l=a?.dynamicContent?.bgImage?.enable;if(t={...t,hasDynamicContent:l},!l)return(0,w.createElement)(e,{...t});const n=(0,O.applyFilters)("spectra_filter_dc_image",a,i);return t={...t,attributes:n},(0,w.createElement)(e,{...t})}},tr,ee)(function(e){const{isSelected:t,attributes:a,name:i,attributes:{UAGHideDesktop:l,UAGHideTab:n,UAGHideMob:o},deviceType:r,context:s,setAttributes:u,clientId:c,hasDynamicContent:g}=e,d=(0,Pi.useBlockProps)();(0,x.useEffect)(()=>{g&&!a?.context&&u({context:s})},[s]),(0,x.useEffect)(()=>{G()},[r]);const p=(0,x.useMemo)(()=>function(e,t,a,i,l=!1){const n=a.replace("srfm/",""),o=i.toLowerCase(),{block_id:r,width:s,widthTablet:u,widthMobile:c,height:g,heightTablet:d,heightMobile:p,align:h,alignTablet:m,alignMobile:b,imageTopMargin:f,imageRightMargin:v,imageLeftMargin:w,imageBottomMargin:y,imageTopMarginTablet:x,imageRightMarginTablet:_,imageLeftMarginTablet:k,imageBottomMarginTablet:S,imageTopMarginMobile:C,imageRightMarginMobile:M,imageLeftMarginMobile:T,imageBottomMarginMobile:L,imageMarginUnit:B,imageMarginUnitTablet:H,imageMarginUnitMobile:A,captionShowOn:R,captionAlign:P,captionFontFamily:z,captionFontWeight:O,captionFontStyle:I,captionFontSize:N,captionColor:V,captionTransform:G,captionDecoration:W,captionFontSizeType:U,captionFontSizeTypeMobile:j,captionFontSizeTypeTablet:q,captionFontSizeMobile:$,captionFontSizeTablet:Z,captionLineHeight:K,captionLineHeightType:Y,captionLineHeightMobile:J,captionLineHeightTablet:X,captionTopMargin:Q,captionRightMargin:ee,captionLeftMargin:te,captionBottomMargin:ae,captionTopMarginTablet:ie,captionRightMarginTablet:le,captionLeftMarginTablet:ne,captionBottomMarginTablet:oe,captionTopMarginMobile:re,captionRightMarginMobile:se,captionLeftMarginMobile:ue,captionBottomMarginMobile:ce,captionMarginUnit:ge,captionMarginUnitTablet:de,captionMarginUnitMobile:pe,headingShowOn:he,headingFontFamily:me,headingFontWeight:be,headingFontStyle:fe,headingFontSize:ve,headingColor:we,headingTransform:ye,headingDecoration:xe,headingFontSizeType:_e,headingFontSizeTypeMobile:ke,headingFontSizeTypeTablet:Se,headingFontSizeMobile:Ce,headingFontSizeTablet:Me,headingLineHeight:Te,headingLineHeightType:Ee,headingLineHeightMobile:De,headingLineHeightTablet:Le,headingTopMargin:Be,headingRightMargin:He,headingLeftMargin:Ae,headingBottomMargin:Re,headingTopMarginTablet:Pe,headingRightMarginTablet:ze,headingLeftMarginTablet:Oe,headingBottomMarginTablet:Fe,headingTopMarginMobile:Ie,headingRightMarginMobile:Ne,headingLeftMarginMobile:Ve,headingBottomMarginMobile:Ge,headingMarginUnit:We,headingMarginUnitTablet:Ue,headingMarginUnitMobile:je,objectFit:qe,objectFitTablet:$e,objectFitMobile:Ze,overlayOpacity:Ke,overlayHoverOpacity:Ye,overlayPositionFromEdge:Je,overlayPositionFromEdgeUnit:Xe,overlayBackground:Qe,overlayBorderHColor:et,separatorShowOn:tt,separatorStyle:at,separatorWidth:it,separatorWidthType:lt,separatorThickness:nt,separatorThicknessUnit:ot,separatorColor:rt,separatorTopMargin:st,separatorRightMargin:ut,separatorLeftMargin:ct,separatorBottomMargin:gt,separatorTopMarginTablet:dt,separatorRightMarginTablet:pt,separatorLeftMarginTablet:ht,separatorBottomMarginTablet:mt,separatorTopMarginMobile:bt,separatorRightMarginMobile:ft,separatorLeftMarginMobile:vt,separatorBottomMarginMobile:wt,separatorMarginUnit:yt,separatorMarginUnitTablet:xt,separatorMarginUnitMobile:_t,imageBorderHColor:kt,useSeparateBoxShadows:St,imageBoxShadowColor:Ct,imageBoxShadowHOffset:Mt,imageBoxShadowVOffset:Tt,imageBoxShadowBlur:Et,imageBoxShadowSpread:Dt,imageBoxShadowPosition:Lt,imageBoxShadowColorHover:Bt,imageBoxShadowHOffsetHover:Ht,imageBoxShadowVOffsetHover:At,imageBoxShadowBlurHover:Rt,imageBoxShadowSpreadHover:Pt,imageBoxShadowPositionHover:zt,maskShape:Ot,maskCustomShape:Ft,maskSize:It,maskPosition:Nt,maskRepeat:Vt,headingLetterSpacing:Gt,headingLetterSpacingTablet:Wt,headingLetterSpacingMobile:Ut,headingLetterSpacingType:jt,captionLetterSpacing:qt,captionLetterSpacingTablet:$t,captionLetterSpacingMobile:Zt,captionLetterSpacingType:Kt,customHeightSetDesktop:Yt,customHeightSetTablet:Jt,customHeightSetMobile:Xt}=e,Qt=F(it,"separatorWidth",n),ea=F(Je,"overlayPositionFromEdge",n),ta=F(nt,"separatorThickness",n),aa=F(Ke,"overlayOpacity",n),ia=F(Ye,"overlayHoverOpacity",n),la=Or(e,"overlay"),na=Or(e,"overlay","tablet"),oa=Or(e,"overlay","mobile"),ra=Or(e,"image"),sa=Or(e,"image","tablet"),ua=Or(e,"image","mobile"),ca=""!==u?u:s,ga=""!==c?c:ca,da=""!==d?d:g,pa=""!==p?p:da,ha=Ur({horizontal:Mt,vertical:Tt,blur:Et,spread:Dt,color:Ct,position:Lt}),ma=Ur({horizontal:Ht,vertical:At,blur:Rt,spread:Pt,color:Bt,position:zt,altColor:Ct});function ba(e){switch(e){case"center":return"center";case"left":return"flex-start";case"right":return"flex-end";default:return""}}const fa=ba(h),va=ba(m),wa=ba(b),ya={".wp-block-uagb-image":{"margin-top":D(f,B),"margin-right":D(v,B),"margin-bottom":D(y,B),"margin-left":D(w,B),"text-align":h,"justify-content":fa}," .wp-block-uagb-image__figure":{"align-items":fa},".wp-block-uagb-image--layout-default figure img":{width:"inherit",height:"inherit","box-shadow":ha,...ra},".wp-block-uagb-image .wp-block-uagb-image__figure img:hover":{"border-color":kt},".wp-block-uagb-image .wp-block-uagb-image__figure figcaption":{"font-family":z,"font-style":I,"text-decoration":W,"text-transform":G,"font-weight":O,"font-size":D(N,U),"line-height":D(K,Y),"letter-spacing":D(qt,Kt),color:V,"margin-top":D(Q,ge),"margin-right":D(ee,ge),"margin-bottom":D(ae,ge),"margin-left":D(te,ge),"text-align":P},".wp-block-uagb-image .wp-block-uagb-image__figure figcaption a":{color:V},".wp-block-uagb-image--layout-overlay figure img":{width:"inherit",height:"inherit","box-shadow":ha,...ra},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__color-wrapper":{background:Qe,opacity:aa,...ra},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__color-wrapper:hover":{"border-color":kt},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__inner":{left:D(ea,Xe),right:D(ea,Xe),top:D(ea,Xe),bottom:D(ea,Xe),...la},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__inner .uagb-image-heading":{"font-family":me,"font-style":fe,"text-decoration":xe,"text-transform":ye,"font-weight":be,"font-size":D(ve,_e),"line-height":D(Te,Ee),"letter-spacing":D(Gt,jt),color:we,"margin-top":D(Be,We),"margin-right":D(He,We),"margin-bottom":D(Re,We),"margin-left":D(Ae,We),opacity:"always"===he?1:0},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__inner .uagb-image-heading a":{color:we},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__inner .uagb-image-caption":{opacity:"always"===R?1:0},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image__figure:hover .wp-block-uagb-image--layout-overlay__inner":{"border-color":et},".wp-block-uagb-image--layout-overlay .wp-block-uagb-image__figure:hover .wp-block-uagb-image--layout-overlay__color-wrapper":{opacity:ia},".wp-block-uagb-image .wp-block-uagb-image--layout-overlay__inner .uagb-image-separator":{width:D(Qt,lt),"border-top-width":D(ta,ot),"border-top-color":rt,"border-top-style":at,"margin-bottom":D(gt,yt),"margin-top":D(st,yt),"margin-left":D(ct,yt),"margin-right":D(ut,yt),opacity:"always"===tt?1:0}};if(ya[".wp-block-uagb-image .wp-block-uagb-image__figure img"]={"object-fit":qe,width:s+"px",height:"auto"},Yt&&(ya[".wp-block-uagb-image .wp-block-uagb-image__figure img"].height=g+"px"),"hover"===he&&(ya[".wp-block-uagb-image .wp-block-uagb-image__figure:hover .wp-block-uagb-image--layout-overlay__inner .uagb-image-heading"]={opacity:1}),"hover"===R&&(ya[".wp-block-uagb-image .wp-block-uagb-image__figure:hover .wp-block-uagb-image--layout-overlay__inner .uagb-image-caption"]={opacity:1}),"hover"===tt&&(ya[".wp-block-uagb-image .wp-block-uagb-image__figure:hover .wp-block-uagb-image--layout-overlay__inner .uagb-image-separator"]={opacity:1}),St&&(ya[".wp-block-uagb-image--layout-default figure img:hover"]={"box-shadow":ma},ya[".wp-block-uagb-image--layout-overlay figure img:hover"]={"box-shadow":ma}),"none"!==Ot){let e=`${window?.srfm_spec_blocks_info?.uagb_url}assets/images/masks/${Ot}.svg`;"custom"===Ot&&(e=`${Ft?.url}`),void 0!==e&&e&&(ya[`.wp-block-uagb-image .wp-block-uagb-image__figure img, .uagb-block-${r} .wp-block-uagb-image--layout-overlay__color-wrapper`]={"mask-image":`url(${e})`,"-webkit-mask-image":`url(${e})`,"mask-size":It,"-webkit-mask-size":It,"mask-repeat":Vt,"-webkit-mask-repeat":Vt,"mask-position":Nt,"-webkit-mask-position":Nt})}const xa={},_a={};xa[".wp-block-uagb-image .components-resizable-box__container"]={width:D(u,"px"),height:D(d,"px")},xa[".wp-block-uagb-image--layout-default figure img"]=sa,xa[".wp-block-uagb-image--layout-overlay figure img"]=sa,xa[".wp-block-uagb-image"]={"margin-top":D(x,H),"margin-right":D(_,H),"margin-bottom":D(S,H),"margin-left":D(k,H),"text-align":m,"justify-content":va},xa[" .wp-block-uagb-image__figure"]={"align-items":va},xa[".wp-block-uagb-image .wp-block-uagb-image__figure figcaption"]={"font-size":D(Z,q),"line-height":D(X,Y),"letter-spacing":D($t,Kt),"margin-top":D(ie,de),"margin-right":D(le,de),"margin-bottom":D(oe,de),"margin-left":D(ne,de)},xa[".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__inner"]=na,xa[".wp-block-uagb-image .wp-block-uagb-image--layout-overlay__inner .uagb-image-heading"]={"font-size":D(Me,Se),"line-height":D(Le,Ee),"letter-spacing":D(Wt,jt),"margin-top":D(Pe,Ue),"margin-right":D(ze,Ue),"margin-bottom":D(Fe,Ue),"margin-left":D(Oe,Ue)},xa[".wp-block-uagb-image .wp-block-uagb-image--layout-overlay__inner .uagb-image-separator"]={"margin-bottom":D(mt,xt),"margin-top":D(dt,xt),"margin-left":D(ht,xt),"margin-right":D(pt,xt)},xa[".wp-block-uagb-image .wp-block-uagb-image__figure img"]={"object-fit":$e,width:ca+"px",height:"auto"},Jt&&(xa[".wp-block-uagb-image .wp-block-uagb-image__figure img"].height=da+"px"),_a[".wp-block-uagb-image .components-resizable-box__container"]={width:D(c,"px"),height:D(p,"px")},_a[".wp-block-uagb-image--layout-default figure img"]=ua,_a[".wp-block-uagb-image--layout-overlay figure img"]=ua,_a[".wp-block-uagb-image"]={"margin-top":D(C,A),"margin-right":D(M,A),"margin-bottom":D(L,A),"margin-left":D(T,A),"text-align":b,"justify-content":wa},_a[" .wp-block-uagb-image__figure"]={"align-items":wa},_a[".wp-block-uagb-image .wp-block-uagb-image__figure figcaption"]={"font-size":D($,j),"line-height":D(J,Y),"letter-spacing":D(Zt,Kt),"margin-top":D(re,pe),"margin-right":D(se,pe),"margin-bottom":D(ce,pe),"margin-left":D(ue,pe)},_a[".wp-block-uagb-image--layout-overlay .wp-block-uagb-image--layout-overlay__inner"]=oa,_a[".wp-block-uagb-image .wp-block-uagb-image--layout-overlay__inner .uagb-image-heading"]={"font-size":D(Ce,ke),"line-height":D(De,Ee),"letter-spacing":D(Ut,jt),"margin-top":D(Ie,je),"margin-right":D(Ne,je),"margin-bottom":D(Ge,je),"margin-left":D(Ve,je)},_a[".wp-block-uagb-image .wp-block-uagb-image--layout-overlay__inner .uagb-image-separator"]={"margin-bottom":D(wt,_t),"margin-top":D(bt,_t),"margin-left":D(vt,_t),"margin-right":D(ft,_t)},_a[".wp-block-uagb-image .wp-block-uagb-image__figure img"]={"object-fit":Ze,width:ga+"px",height:"auto"},Xt&&(_a[".wp-block-uagb-image .wp-block-uagb-image__figure img"].height=pa+"px");const ka=l?`.editor-styles-wrapper ${l} `:`.editor-styles-wrapper .uagb-block-${r}`;let Sa=E(ya,ka);return("tablet"===o||"mobile"===o||l)&&(Sa+=E(xa,`${ka}`,!0,"tablet"),("mobile"===o||l)&&(Sa+=E(_a,`${ka}`,!0,"mobile"))),Sa}(a,0,i,r),[a,r]);return(0,x.useEffect)(()=>{N(e)},[l,n,o,r]),(0,w.createElement)("div",{...d},(0,w.createElement)(W,{blockStyling:p}),t&&(0,w.createElement)(Qs,{...e}),(0,w.createElement)(vu,{...e}))});let yu={};yu=(0,O.applyFilters)("srfm/image",nr(yu)),(0,ir.registerBlockType)("srfm/image",{...yu,apiVersion:3,title:(0,M.__)("Image","sureforms"),description:(0,M.__)("Add images on your webpage with multiple customization options.","sureforms"),icon:C.image,keywords:[(0,M.__)("image","sureforms"),(0,M.__)("advance image","sureforms"),(0,M.__)("caption","sureforms"),(0,M.__)("overlay image","sureforms")],supports:{anchor:!0,color:{__experimentalDuotone:"img",text:!1,background:!1},align:!0,html:!1},attributes:H,category:srfm_spec_blocks_info.category,edit:e=>e.attributes.isPreview?(0,w.createElement)(lr,{image:"image"}):(0,w.createElement)(wu,{...e}),save:()=>null,__experimentalLabel:e=>(0,O.applyFilters)("uag_loop_data_source_label",(0,M.__)("Image","sureforms"),e),usesContext:["postId","postType"],transforms:{from:[{type:"block",blocks:["core/image"],transform:({url:e,sizeSlug:t})=>(0,ir.createBlock)("srfm/image",{url:e,sizeSlug:t})},{type:"block",blocks:["core/post-featured-image"],transform:({sizeSlug:e})=>(0,ir.createBlock)("srfm/image",{useDynamicData:!0,dynamicContentType:"featured-image",sizeSlug:e})}],to:[{type:"block",blocks:["core/image"],transform:({url:e,sizeSlug:t})=>(0,ir.createBlock)("core/image",{url:e,sizeSlug:t})}]}});const xu=[{defaultAttributes:A},{value:"preset-1",label:(0,M.__)("Preset 1","sureforms"),attributes:[{label:"iconShadowHOffset",value:2},{label:"iconShadowVOffset",value:4},{label:"iconShadowBlur",value:3}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_451)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_451" x="55" y="75" width="218" height="127" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="2"/> <feGaussianBlur stdDeviation="2"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_451"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_451" result="shape"/> </filter> </defs> </svg>'},{value:"preset-2",label:(0,M.__)("Preset 2","sureforms"),attributes:[{label:"iconShadowHOffset",value:0},{label:"iconShadowVOffset",value:5},{label:"iconShadowBlur",value:5}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_459)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_459" x="48" y="71" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_459"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_459" result="shape"/> </filter> </defs> </svg>'},{value:"preset-3",label:(0,M.__)("Preset 3","sureforms"),attributes:[{label:"iconShadowHOffset",value:0},{label:"iconShadowVOffset",value:2},{label:"iconShadowBlur",value:3}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_463)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_463" x="48" y="67" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_463"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_463" result="shape"/> </filter> </defs> </svg>'},{value:"preset-4",label:(0,M.__)("Preset 4","sureforms"),attributes:[{label:"iconShadowHOffset",value:0},{label:"iconShadowVOffset",value:1},{label:"iconShadowBlur",value:3}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_467)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_467" x="53" y="71" width="222" height="131" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="3"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_467"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_467" result="shape"/> </filter> </defs> </svg>'},{value:"preset-5",label:(0,M.__)("Preset 5","sureforms"),attributes:[{label:"iconShadowHOffset",value:0},{label:"iconShadowVOffset",value:5},{label:"iconShadowBlur",value:5}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_471)"> <ellipse cx="169" cy="174.5" rx="100" ry="16.5" fill="#FAFAFA"/> </g> <path d="M275 189.388C275 192.493 272.493 195 269.4 195H70.5995C67.5034 195 65 192.486 65 189.388V81.615C65 78.5136 67.5067 76 70.5995 76H269.4C272.497 76 274.997 78.5136 274.997 81.615L275 189.388Z" fill="#FBFBFB"/> <defs> <filter id="filter0_d_103_471" x="60" y="154" width="220" height="53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="6"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_471"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_471" result="shape"/> </filter> </defs> </svg>'},{value:"preset-6",label:(0,M.__)("Preset 6","sureforms"),attributes:[{label:"iconShadowHOffset",value:0},{label:"iconShadowVOffset",value:5},{label:"iconShadowBlur",value:8}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_476)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_476" x="52" y="74" width="224" height="133" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="3.5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_476"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_476" result="shape"/> </filter> </defs> </svg>'}],_u=[{defaultAttributes:A},{value:"preset-1",label:(0,M.__)("Preset 1","sureforms"),attributes:[{label:"iconBoxShadowHOffset",value:3},{label:"iconBoxShadowVOffset",value:8},{label:"iconBoxShadowBlur",value:12},{label:"iconBoxShadowSpread",value:0},{label:"iconBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_451)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_451" x="55" y="75" width="218" height="127" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="2"/> <feGaussianBlur stdDeviation="2"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_451"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_451" result="shape"/> </filter> </defs> </svg>'},{value:"preset-2",label:(0,M.__)("Preset 2","sureforms"),attributes:[{label:"iconBoxShadowHOffset",value:0},{label:"iconBoxShadowVOffset",value:18},{label:"iconBoxShadowBlur",value:40},{label:"iconBoxShadowSpread",value:-10},{label:"iconBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_459)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_459" x="48" y="71" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_459"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_459" result="shape"/> </filter> </defs> </svg>'},{value:"preset-3",label:(0,M.__)("Preset 3","sureforms"),attributes:[{label:"iconBoxShadowHOffset",value:0},{label:"iconBoxShadowVOffset",value:4},{label:"iconBoxShadowBlur",value:12},{label:"iconBoxShadowSpread",value:0},{label:"iconBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_463)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_463" x="48" y="67" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_463"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_463" result="shape"/> </filter> </defs> </svg>'},{value:"preset-4",label:(0,M.__)("Preset 4","sureforms"),attributes:[{label:"iconBoxShadowHOffset",value:0},{label:"iconBoxShadowVOffset",value:2},{label:"iconBoxShadowBlur",value:5},{label:"iconBoxShadowSpread",value:-1},{label:"iconBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_467)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_467" x="53" y="71" width="222" height="131" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="3"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_467"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_467" result="shape"/> </filter> </defs> </svg>'},{value:"preset-5",label:(0,M.__)("Preset 5","sureforms"),attributes:[{label:"iconBoxShadowHOffset",value:0},{label:"iconBoxShadowVOffset",value:50},{label:"iconBoxShadowBlur",value:50},{label:"iconBoxShadowSpread",value:-30},{label:"iconBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_471)"> <ellipse cx="169" cy="174.5" rx="100" ry="16.5" fill="#FAFAFA"/> </g> <path d="M275 189.388C275 192.493 272.493 195 269.4 195H70.5995C67.5034 195 65 192.486 65 189.388V81.615C65 78.5136 67.5067 76 70.5995 76H269.4C272.497 76 274.997 78.5136 274.997 81.615L275 189.388Z" fill="#FBFBFB"/> <defs> <filter id="filter0_d_103_471" x="60" y="154" width="220" height="53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="6"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_471"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_471" result="shape"/> </filter> </defs> </svg>'},{value:"preset-6",label:(0,M.__)("Preset 6","sureforms"),attributes:[{label:"iconBoxShadowHOffset",value:0},{label:"iconBoxShadowVOffset",value:20},{label:"iconBoxShadowBlur",value:30},{label:"iconBoxShadowSpread",value:0},{label:"iconBoxShadowPosition",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_476)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_476" x="52" y="74" width="224" height="133" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="3.5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_476"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_476" result="shape"/> </filter> </defs> </svg>'}],ku=[{defaultAttributes:A},{value:"preset-1",label:(0,M.__)("Preset 1","sureforms"),attributes:[{label:"iconBoxShadowHOffsetHover",value:3},{label:"iconBoxShadowVOffsetHover",value:8},{label:"iconBoxShadowBlurHover",value:12},{label:"iconBoxShadowSpreadHover",value:0},{label:"iconBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_451)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_451" x="55" y="75" width="218" height="127" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="2"/> <feGaussianBlur stdDeviation="2"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_451"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_451" result="shape"/> </filter> </defs> </svg>'},{value:"preset-2",label:(0,M.__)("Preset 2","sureforms"),attributes:[{label:"iconBoxShadowHOffsetHover",value:0},{label:"iconBoxShadowVOffsetHover",value:18},{label:"iconBoxShadowBlurHover",value:40},{label:"iconBoxShadowSpreadHover",value:-10},{label:"iconBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_459)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_459" x="48" y="71" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_459"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_459" result="shape"/> </filter> </defs> </svg>'},{value:"preset-3",label:(0,M.__)("Preset 3","sureforms"),attributes:[{label:"iconBoxShadowHOffsetHover",value:0},{label:"iconBoxShadowVOffsetHover",value:4},{label:"iconBoxShadowBlurHover",value:12},{label:"iconBoxShadowSpreadHover",value:0},{label:"iconBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_463)"> <path d="M268 190.388C268 193.493 265.493 196 262.4 196H63.5995C60.5034 196 58 193.486 58 190.388V82.615C58 79.5136 60.5067 77 63.5995 77H262.4C265.497 77 267.997 79.5136 267.997 82.615L268 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_463" x="48" y="67" width="230" height="139" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_463"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_463" result="shape"/> </filter> </defs> </svg>'},{value:"preset-4",label:(0,M.__)("Preset 4","sureforms"),attributes:[{label:"iconBoxShadowHOffsetHover",value:0},{label:"iconBoxShadowVOffsetHover",value:2},{label:"iconBoxShadowBlurHover",value:5},{label:"iconBoxShadowSpreadHover",value:-1},{label:"iconBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_467)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_467" x="53" y="71" width="222" height="131" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset/> <feGaussianBlur stdDeviation="3"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_467"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_467" result="shape"/> </filter> </defs> </svg>'},{value:"preset-5",label:(0,M.__)("Preset 5","sureforms"),attributes:[{label:"iconBoxShadowHOffsetHover",value:0},{label:"iconBoxShadowVOffsetHover",value:50},{label:"iconBoxShadowBlurHover",value:50},{label:"iconBoxShadowSpreadHover",value:-30},{label:"iconBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_471)"> <ellipse cx="169" cy="174.5" rx="100" ry="16.5" fill="#FAFAFA"/> </g> <path d="M275 189.388C275 192.493 272.493 195 269.4 195H70.5995C67.5034 195 65 192.486 65 189.388V81.615C65 78.5136 67.5067 76 70.5995 76H269.4C272.497 76 274.997 78.5136 274.997 81.615L275 189.388Z" fill="#FBFBFB"/> <defs> <filter id="filter0_d_103_471" x="60" y="154" width="220" height="53" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dx="1" dy="6"/> <feGaussianBlur stdDeviation="5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_471"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_471" result="shape"/> </filter> </defs> </svg>'},{value:"preset-6",label:(0,M.__)("Preset 6","sureforms"),attributes:[{label:"iconBoxShadowHOffsetHover",value:0},{label:"iconBoxShadowVOffsetHover",value:20},{label:"iconBoxShadowBlurHover",value:30},{label:"iconBoxShadowSpreadHover",value:0},{label:"iconBoxShadowPositionHover",value:"outset"}],icon:'<svg xmlns="http://www.w3.org/2000/svg" width="325" height="245" viewBox="0 0 325 245" fill="none"> <path d="M28 31.7987C28 29.1485 30.1527 27 32.8081 27H295.192C297.847 27 300 29.1485 300 31.7987V245H28V31.7987Z" fill="white"/> <g filter="url(#filter0_d_103_476)"> <path d="M269 190.388C269 193.493 266.493 196 263.4 196H64.5995C61.5034 196 59 193.486 59 190.388V82.615C59 79.5136 61.5067 77 64.5995 77H263.4C266.497 77 268.997 79.5136 268.997 82.615L269 190.388Z" fill="#FBFBFB"/> </g> <defs> <filter id="filter0_d_103_476" x="52" y="74" width="224" height="133" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB"> <feFlood flood-opacity="0" result="BackgroundImageFix"/> <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/> <feOffset dy="4"/> <feGaussianBlur stdDeviation="3.5"/> <feComposite in2="hardAlpha" operator="out"/> <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.35 0"/> <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_103_476"/> <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_103_476" result="shape"/> </filter> </defs> </svg>'}],Su=[{defaultAttributes:A},{defaultPresetAttributes:[{label:"iconBackgroundColor"},{label:"iconBorderTopLeftRadius"},{label:"iconBorderTopRightRadius"},{label:"iconBorderBottomRightRadius"},{label:"iconBorderBottomLeftRadius"},{label:"iconBorderTopWidth"},{label:"iconBorderRightWidth"},{label:"iconBorderBottomWidth"},{label:"iconBorderLeftWidth"},{label:"iconBorderStyle"}]},{value:"preset-1",label:(0,M.__)("Preset 1","sureforms"),attributes:[{label:"iconBackgroundColor",value:"#DCF1FF"},{label:"iconBorderStyle",value:""},{label:"iconBorderTopLeftRadius",value:50},{label:"iconBorderTopRightRadius",value:50},{label:"iconBorderBottomRightRadius",value:50},{label:"iconBorderBottomLeftRadius",value:50},{label:"iconTopPadding",value:12},{label:"iconRightPadding",value:12},{label:"iconBottomPadding",value:12},{label:"iconLeftPadding",value:12}],icon:'<svg width="325" height="245" viewBox="0 0 325 245" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/><circle cx="162.619" cy="136.119" r="30" fill="#B6B6B6"/><path d="M161.512 118.9C161.922 117.917 163.316 117.917 163.726 118.9L167.605 128.193C167.778 128.608 168.168 128.891 168.615 128.927L178.652 129.744C179.715 129.831 180.145 131.156 179.336 131.851L171.697 138.412C171.356 138.704 171.207 139.162 171.311 139.599L173.635 149.397C173.881 150.434 172.754 151.254 171.844 150.699L163.243 145.461C162.86 145.227 162.378 145.227 161.995 145.461L153.394 150.699C152.484 151.254 151.356 150.434 151.602 149.397L153.927 139.599C154.031 139.162 153.882 138.704 153.541 138.412L145.901 131.851C145.093 131.156 145.523 129.831 146.586 129.744L156.623 128.927C157.07 128.891 157.46 128.608 157.633 128.193L161.512 118.9Z" fill="white"/></svg>'},{value:"preset-2",label:(0,M.__)("Preset 2","sureforms"),attributes:[{label:"iconBackgroundColor",value:""},{label:"iconBorderStyle",value:"solid"},{label:"iconBorderTopLeftRadius",value:50},{label:"iconBorderTopRightRadius",value:50},{label:"iconBorderBottomRightRadius",value:50},{label:"iconBorderBottomLeftRadius",value:50},{label:"iconBorderTopWidth",value:2},{label:"iconBorderRightWidth",value:2},{label:"iconBorderBottomWidth",value:2},{label:"iconBorderLeftWidth",value:2},{label:"iconTopPadding",value:12},{label:"iconRightPadding",value:12},{label:"iconBottomPadding",value:12},{label:"iconLeftPadding",value:12}],icon:'<svg width="325" height="245" viewBox="0 0 325 245" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/><path d="M192.119 136C192.119 152.225 178.913 165.381 162.619 165.381C146.325 165.381 133.119 152.225 133.119 136C133.119 119.775 146.325 106.619 162.619 106.619C178.913 106.619 192.119 119.775 192.119 136Z" stroke="#959595" fill="none"/><path d="M161.512 118.848C161.924 117.867 163.314 117.867 163.726 118.848L167.604 128.105C167.778 128.518 168.167 128.801 168.614 128.837L178.643 129.65C179.707 129.736 180.137 131.064 179.326 131.758L171.699 138.281C171.357 138.574 171.208 139.033 171.312 139.471L173.634 149.219C173.881 150.255 172.755 151.075 171.844 150.523L163.241 145.304C162.859 145.072 162.379 145.072 161.996 145.304L153.394 150.523C152.483 151.075 151.357 150.255 151.604 149.219L153.926 139.471C154.03 139.033 153.88 138.574 153.538 138.281L145.912 131.758C145.101 131.064 145.531 129.736 146.595 129.65L156.624 128.837C157.071 128.801 157.46 128.518 157.633 128.105L161.512 118.848Z" fill="#B6B6B6"/></svg>'},{value:"preset-3",label:(0,M.__)("Preset 3","sureforms"),attributes:[{label:"iconBackgroundColor",value:"#DCF1FF"},{label:"iconBorderStyle",value:""},{label:"iconBorderTopLeftRadius",value:6},{label:"iconBorderTopRightRadius",value:6},{label:"iconBorderBottomRightRadius",value:6},{label:"iconBorderBottomLeftRadius",value:6},{label:"iconTopPadding",value:12},{label:"iconRightPadding",value:12},{label:"iconBottomPadding",value:12},{label:"iconLeftPadding",value:12}],icon:'<svg width="325" height="245" viewBox="0 0 325 245" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/><rect x="132.902" y="106" width="60.1963" height="60" rx="5" fill="#B6B6B6"/><path d="M161.893 118.849C162.305 117.867 163.695 117.867 164.107 118.849L167.986 128.105C168.159 128.519 168.548 128.801 168.995 128.837L179.024 129.651C180.088 129.737 180.518 131.065 179.707 131.759L172.081 138.282C171.738 138.574 171.589 139.034 171.693 139.472L174.015 149.219C174.262 150.256 173.136 151.076 172.225 150.523L163.622 145.304C163.24 145.072 162.76 145.072 162.378 145.304L153.775 150.523C152.864 151.076 151.738 150.256 151.985 149.219L154.307 139.472C154.411 139.034 154.261 138.574 153.919 138.282L146.293 131.759C145.482 131.065 145.912 129.737 146.976 129.651L157.005 128.837C157.452 128.801 157.841 128.519 158.014 128.105L161.893 118.849Z" fill="white"/></svg>'},{value:"preset-4",label:(0,M.__)("Preset 4","sureforms"),attributes:[{label:"iconBackgroundColor",value:""},{label:"iconBorderStyle",value:"solid"},{label:"iconBorderTopWidth",value:2},{label:"iconBorderRightWidth",value:2},{label:"iconBorderBottomWidth",value:2},{label:"iconBorderLeftWidth",value:2},{label:"iconTopPadding",value:12},{label:"iconRightPadding",value:12},{label:"iconBottomPadding",value:12},{label:"iconLeftPadding",value:12}],icon:'<svg width="325" height="245" viewBox="0 0 325 245" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M27 31.7987C27 29.1485 29.1527 27 31.8081 27H294.192C296.847 27 299 29.1485 299 31.7987V245H27V31.7987Z" fill="white"/><rect x="133.402" y="106.5" width="59.1963" height="59" rx="4.5" stroke="#959595" fill="none"/><path d="M161.893 118.849C162.305 117.867 163.695 117.867 164.107 118.849L167.986 128.105C168.159 128.519 168.548 128.801 168.995 128.837L179.024 129.651C180.088 129.737 180.518 131.065 179.707 131.759L172.081 138.282C171.738 138.574 171.589 139.034 171.693 139.472L174.015 149.219C174.262 150.256 173.136 151.076 172.225 150.523L163.622 145.304C163.24 145.072 162.76 145.072 162.378 145.304L153.775 150.523C152.864 151.076 151.738 150.256 151.985 149.219L154.307 139.472C154.411 139.034 154.261 138.574 153.919 138.282L146.293 131.759C145.482 131.065 145.912 129.737 146.976 129.651L157.005 128.837C157.452 128.801 157.841 128.519 158.014 128.105L161.893 118.849Z" fill="#B6B6B6"/></svg>'}],Cu=(0,x.memo)(e=>{const{attributes:t,setAttributes:a}=e,{icon:i,iconSize:l,iconSizeTablet:n,iconSizeMobile:o,iconSizeUnit:r,align:s,alignTablet:u,alignMobile:c,rotation:g,rotationUnit:d,link:p,target:h,disableLink:m,iconAccessabilityMode:b,iconAccessabilityDesc:f}=t;return(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Jo,{title:(0,M.__)("Icon","sureforms"),initialOpen:!0},(0,w.createElement)(Wo,{label:(0,M.__)("Icon","sureforms"),value:i,onChange:e=>a({icon:e})}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Accessibility Mode","sureforms"),data:{value:b,label:"iconAccessabilityMode"},options:[{value:"svg",label:(0,M.__)("SVG","sureforms")},{value:"image",label:(0,M.__)("Image","sureforms")},{value:"presentation",label:(0,M.__)("Decorative","sureforms")}]}),"presentation"!==b&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Xi,{label:(0,M.__)("Accessibility Label","sureforms"),data:{value:f,label:"iconAccessabilityDesc"},value:f,setAttributes:a,onChange:e=>a({iconAccessabilityDesc:e})})),(0,w.createElement)(Qi,{label:(0,M.__)("Size","sureforms"),data:{desktop:{value:l,label:"iconSize"},tablet:{value:n,label:"iconSizeTablet"},mobile:{value:o,label:"iconSizeMobile"}},min:0,max:200,unit:{value:r,label:"iconSizeUnit"},setAttributes:a}),(0,w.createElement)(Ri,{setAttributes:a,label:(0,M.__)("Alignment","sureforms"),data:{desktop:{value:s,label:"align"},tablet:{value:u,label:"alignTablet"},mobile:{value:c,label:"alignMobile"}},options:[{value:"left",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-left")}),tooltip:(0,M.__)("Left","sureforms")},{value:"center",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-center")}),tooltip:(0,M.__)("Center","sureforms")},{value:"right",icon:(0,w.createElement)(te.Icon,{icon:zi("fa fa-align-right")}),tooltip:(0,M.__)("Right","sureforms")}],showIcons:!0,responsive:!0}),(0,w.createElement)(Me,{label:(0,M.__)("Rotation","sureforms"),setAttributes:a,value:g,data:{value:g,label:"rotation"},min:-180,max:180,unit:{value:d,label:"rotationUnit"},units:[{name:(0,M.__)("Degree","sureforms"),unitValue:"deg"}]}),(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Link","sureforms"),checked:m,onChange:()=>a({disableLink:!m})}),m&&(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Xi,{label:(0,M.__)("URL","sureforms"),value:p,data:{value:p,label:"link"},setAttributes:a,onChange:e=>a({link:e}),placeholder:(0,M.__)("Enter URL","sureforms")}),(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Open in New Tab","sureforms"),checked:h,onChange:()=>a({target:!h})}))),(0,w.createElement)(Jo,{title:(0,M.__)("Presets","sureforms"),initialOpen:!1},(0,w.createElement)(qs,{setAttributes:a,presets:Su,presetInputType:"radioImage"})))}),Mu=(0,x.memo)(e=>{const{attributes:t,setAttributes:a,deviceType:i}=e,{block_id:l,iconColor:n,iconBackgroundColorType:o,iconBackgroundColor:r,iconBackgroundGradientColor:s,iconHoverColor:u,iconHoverBackgroundColorType:c,iconHoverBackgroundColor:g,iconHoverBackgroundGradientColor:d,iconTopPadding:p,iconRightPadding:h,iconBottomPadding:m,iconLeftPadding:b,iconTopTabletPadding:f,iconRightTabletPadding:v,iconBottomTabletPadding:y,iconLeftTabletPadding:x,iconTopMobilePadding:_,iconRightMobilePadding:k,iconBottomMobilePadding:S,iconLeftMobilePadding:C,iconPaddingUnit:T,iconMobilePaddingUnit:E,iconTabletPaddingUnit:D,iconPaddingLink:L,iconTopMargin:B,iconRightMargin:H,iconBottomMargin:A,iconLeftMargin:R,iconTopTabletMargin:P,iconRightTabletMargin:z,iconBottomTabletMargin:O,iconLeftTabletMargin:F,iconTopMobileMargin:I,iconRightMobileMargin:N,iconBottomMobileMargin:V,iconLeftMobileMargin:G,iconMarginUnit:W,iconMobileMarginUnit:U,iconTabletMarginUnit:j,iconMarginLink:q,iconShadowColor:$,iconShadowHOffset:Z,iconShadowVOffset:K,iconShadowBlur:Y,useSeparateBoxShadows:J,iconBoxShadowColor:X,iconBoxShadowHOffset:Q,iconBoxShadowVOffset:ee,iconBoxShadowBlur:ae,iconBoxShadowSpread:ie,iconBoxShadowPosition:le,iconBoxShadowColorHover:ne,iconBoxShadowHOffsetHover:oe,iconBoxShadowVOffsetHover:re,iconBoxShadowBlurHover:se,iconBoxShadowSpreadHover:ue,iconBoxShadowPositionHover:ce}=t;return(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Jo,{title:(0,M.__)("Icon","sureforms"),initialOpen:!0},(0,w.createElement)(Er,{tabs:[{name:"normal",title:(0,M.__)("Normal","sureforms")},{name:"hover",title:(0,M.__)("Hover","sureforms")}],normal:(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:(0,M.__)("Icon Color","sureforms"),colorValue:n||"",data:{value:n,label:"iconColor"},setAttributes:a}),(0,w.createElement)(yr,{label:(0,M.__)("Background Type","sureforms"),type:{value:o,label:"iconBackgroundColorType"},classic:{value:r,label:"iconBackgroundColor"},gradient:{value:s,label:"iconBackgroundGradientColor"},setAttributes:a})),hover:(0,w.createElement)(w.Fragment,null,(0,w.createElement)(Ti,{label:(0,M.__)("Icon Color","sureforms"),colorValue:u||"",data:{value:u,label:"iconHoverColor"},setAttributes:a}),(0,w.createElement)(yr,{label:(0,M.__)("Background Type","sureforms"),type:{value:c,label:"iconHoverBackgroundColorType"},classic:{value:g,label:"iconHoverBackgroundColor"},gradient:{value:d,label:"iconHoverBackgroundGradientColor"},setAttributes:a})),disableBottomSeparator:!1}),(0,w.createElement)(Hr,{setAttributes:a,prefix:"icon",attributes:t,deviceType:i,disableBottomSeparator:!0})),(0,w.createElement)(Jo,{title:(0,M.__)("Drop Shadow","sureforms"),initialOpen:!1},(0,w.createElement)(qs,{setAttributes:a,presets:xu,presetInputType:"radioImage"}),(0,w.createElement)(xr,{blockId:l,setAttributes:a,textShadowColor:{value:$,label:"iconShadowColor",title:(0,M.__)("Color","sureforms")},textShadowHOffset:{value:Z,label:"iconShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},textShadowVOffset:{value:K,label:"iconShadowVOffset",title:(0,M.__)("Vertical","sureforms")},textShadowBlur:{value:Y,label:"iconShadowBlur",title:(0,M.__)("Blur","sureforms")},popup:!1})),(0,w.createElement)(Jo,{title:(0,M.__)("Box Shadow","sureforms"),initialOpen:!1},(0,w.createElement)(te.ToggleControl,{label:(0,M.__)("Separate Hover Shadow","sureforms"),checked:J,onChange:()=>a({useSeparateBoxShadows:!J})}),J?(0,w.createElement)(Er,{tabs:[{name:"normal",title:(0,M.__)("Normal","sureforms")},{name:"hover",title:(0,M.__)("Hover","sureforms")}],normal:(0,w.createElement)(w.Fragment,null,(0,w.createElement)(qs,{setAttributes:a,presets:_u,presetInputType:"radioImage"}),(0,w.createElement)(us,{blockId:l,setAttributes:a,boxShadowColor:{value:X,label:"iconBoxShadowColor",title:(0,M.__)("Color","sureforms")},boxShadowHOffset:{value:Q,label:"iconBoxShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},boxShadowVOffset:{value:ee,label:"iconBoxShadowVOffset",title:(0,M.__)("Vertical","sureforms")},boxShadowBlur:{value:ae,label:"iconBoxShadowBlur",title:(0,M.__)("Blur","sureforms")},boxShadowSpread:{value:ie,label:"iconBoxShadowSpread",title:(0,M.__)("Spread","sureforms")},boxShadowPosition:{value:le,label:"iconBoxShadowPosition",title:(0,M.__)("Position","sureforms")}})),hover:(0,w.createElement)(w.Fragment,null,(0,w.createElement)(qs,{setAttributes:a,presets:ku,presetInputType:"radioImage"}),(0,w.createElement)(us,{blockId:l,setAttributes:a,boxShadowColor:{value:ne,label:"iconBoxShadowColorHover",title:(0,M.__)("Color","sureforms")},boxShadowHOffset:{value:oe,label:"iconBoxShadowHOffsetHover",title:(0,M.__)("Horizontal","sureforms")},boxShadowVOffset:{value:re,label:"iconBoxShadowVOffsetHover",title:(0,M.__)("Vertical","sureforms")},boxShadowBlur:{value:se,label:"iconBoxShadowBlurHover",title:(0,M.__)("Blur","sureforms")},boxShadowSpread:{value:ue,label:"iconBoxShadowSpreadHover",title:(0,M.__)("Spread","sureforms")},boxShadowPosition:{value:ce,label:"iconBoxShadowPositionHover",title:(0,M.__)("Position","sureforms")}})),disableBottomSeparator:!0}):(0,w.createElement)(w.Fragment,null,(0,w.createElement)(qs,{setAttributes:a,presets:_u,presetInputType:"radioImage"}),(0,w.createElement)(us,{blockId:l,setAttributes:a,boxShadowColor:{value:X,label:"iconBoxShadowColor",title:(0,M.__)("Color","sureforms")},boxShadowHOffset:{value:Q,label:"iconBoxShadowHOffset",title:(0,M.__)("Horizontal","sureforms")},boxShadowVOffset:{value:ee,label:"iconBoxShadowVOffset",title:(0,M.__)("Vertical","sureforms")},boxShadowBlur:{value:ae,label:"iconBoxShadowBlur",title:(0,M.__)("Blur","sureforms")},boxShadowSpread:{value:ie,label:"iconBoxShadowSpread",title:(0,M.__)("Spread","sureforms")},boxShadowPosition:{value:le,label:"iconBoxShadowPosition",title:(0,M.__)("Position","sureforms")}}))),(0,w.createElement)(Jo,{title:(0,M.__)("Spacing","sureforms"),initialOpen:!1},(0,w.createElement)(Yo,{...e,label:(0,M.__)("Padding","sureforms"),valueTop:{value:p,label:"iconTopPadding"},valueRight:{value:h,label:"iconRightPadding"},valueBottom:{value:m,label:"iconBottomPadding"},valueLeft:{value:b,label:"iconLeftPadding"},valueTopTablet:{value:f,label:"iconTopTabletPadding"},valueRightTablet:{value:v,label:"iconRightTabletPadding"},valueBottomTablet:{value:y,label:"iconBottomTabletPadding"},valueLeftTablet:{value:x,label:"iconLeftTabletPadding"},valueTopMobile:{value:_,label:"iconTopMobilePadding"},valueRightMobile:{value:k,label:"iconRightMobilePadding"},valueBottomMobile:{value:S,label:"iconBottomMobilePadding"},valueLeftMobile:{value:C,label:"iconLeftMobilePadding"},unit:{value:T,label:"iconPaddingUnit"},mUnit:{value:E,label:"iconMobilePaddingUnit"},tUnit:{value:D,label:"iconTabletPaddingUnit"},attributes:t,setAttributes:a,link:{value:L,label:"iconPaddingLink"}}),(0,w.createElement)(Yo,{...e,label:(0,M.__)("Margin","sureforms"),valueTop:{value:B,label:"iconTopMargin"},valueRight:{value:H,label:"iconRightMargin"},valueBottom:{value:A,label:"iconBottomMargin"},valueLeft:{value:R,label:"iconLeftMargin"},valueTopTablet:{value:P,label:"iconTopTabletMargin"},valueRightTablet:{value:z,label:"iconRightTabletMargin"},valueBottomTablet:{value:O,label:"iconBottomTabletMargin"},valueLeftTablet:{value:F,label:"iconLeftTabletMargin"},valueTopMobile:{value:I,label:"iconTopMobileMargin"},valueRightMobile:{value:N,label:"iconRightMobileMargin"},valueBottomMobile:{value:V,label:"iconBottomMobileMargin"},valueLeftMobile:{value:G,label:"iconLeftMobileMargin"},unit:{value:W,label:"iconMarginUnit"},mUnit:{value:U,label:"iconMobileMarginUnit"},tUnit:{value:j,label:"iconTabletMarginUnit"},attributes:t,setAttributes:a,link:{value:q,label:"iconMarginLink"}})))}),Tu=(0,x.memo)(e=>(0,w.createElement)(Pi.InspectorControls,null,(0,w.createElement)(di,null,(0,w.createElement)(pi,{...hi,parentProps:e},(0,w.createElement)(Cu,{...e})),(0,w.createElement)(pi,{...mi,parentProps:e},(0,w.createElement)(Mu,{...e}))))),Eu=(0,x.memo)(e=>{const{attributes:t,setAttributes:a,deviceType:i}=e,{icon:l,block_id:n,iconAccessabilityMode:o,iconAccessabilityDesc:r}=t,s=zi(l||"circle-check",a),u=(0,Pi.useBlockProps)({className:`uagb-block-${n} uagb-icon-wrapper uagb-editor-preview-mode-${i.toLowerCase()}`});return(0,w.createElement)("div",{...u},(0,w.createElement)("span",{className:"uagb-svg-wrapper"},s))}),Du=(0,X.compose)(tr,ee)(e=>{const{attributes:t,attributes:{UAGHideDesktop:a,UAGHideTab:i,UAGHideMob:l},isSelected:n,name:o,deviceType:r,clientId:s}=e,u=(0,x.useMemo)(()=>function(e,t,a,i,l=!1){const n=a.replace("srfm/",""),o=i.toLowerCase(),{block_id:r,iconSize:s,iconSizeTablet:u,iconSizeMobile:c,iconSizeUnit:g,align:d,alignTablet:p,alignMobile:h,rotation:m,rotationUnit:b,iconColor:f,iconBackgroundColorType:v,iconBackgroundColor:w,iconBackgroundGradientColor:y,iconHoverColor:x,iconHoverBackgroundColorType:_,iconHoverBackgroundColor:k,iconHoverBackgroundGradientColor:S,iconTopPadding:C,iconRightPadding:M,iconBottomPadding:T,iconLeftPadding:L,iconTopTabletPadding:B,iconRightTabletPadding:H,iconBottomTabletPadding:A,iconLeftTabletPadding:R,iconTopMobilePadding:P,iconRightMobilePadding:z,iconBottomMobilePadding:O,iconLeftMobilePadding:I,iconPaddingUnit:N,iconMobilePaddingUnit:V,iconTabletPaddingUnit:G,iconTopMargin:W,iconRightMargin:U,iconBottomMargin:j,iconLeftMargin:q,iconTopTabletMargin:$,iconRightTabletMargin:Z,iconBottomTabletMargin:K,iconLeftTabletMargin:Y,iconTopMobileMargin:J,iconRightMobileMargin:X,iconBottomMobileMargin:Q,iconLeftMobileMargin:ee,iconMarginUnit:te,iconMobileMarginUnit:ae,iconTabletMarginUnit:ie,iconBorderStyle:le,iconBorderColor:ne,iconBorderHColor:oe,iconShadowColor:re,iconShadowHOffset:se,iconShadowVOffset:ue,iconShadowBlur:ce,useSeparateBoxShadows:ge,iconBoxShadowColor:de,iconBoxShadowHOffset:pe,iconBoxShadowVOffset:he,iconBoxShadowBlur:me,iconBoxShadowSpread:be,iconBoxShadowPosition:fe,iconBoxShadowColorHover:ve,iconBoxShadowHOffsetHover:we,iconBoxShadowVOffsetHover:ye,iconBoxShadowBlurHover:xe,iconBoxShadowSpreadHover:_e,iconBoxShadowPositionHover:ke}=e,Se=F(s,"iconSize",n),Ce=D(F(m,"rotation",n),b),Me="classic"===v?w:y,Te="classic"===_?k:S,Ee=Ur({horizontal:se,vertical:ue,blur:ce,color:re}),De=Ur({horizontal:pe,vertical:he,blur:me,spread:be,color:de,position:fe}),Le=Ur({horizontal:we,vertical:ye,blur:xe,spread:_e,color:ve,position:ke,altColor:de}),Be={".uagb-icon-wrapper":{"text-align":d},".uagb-icon-wrapper svg":{width:D(Se,g),height:D(Se,g),"box-sizing":"content-box",transform:`rotate(${Ce})`,fill:f,filter:Ee?`drop-shadow( ${Ee} )`:""},".uagb-icon-wrapper .uagb-svg-wrapper":{display:"inline-flex",background:Me,"padding-top":D(C,N),"padding-right":D(M,N),"padding-bottom":D(T,N),"padding-left":D(L,N),"margin-top":D(W,te),"margin-right":D(U,te),"margin-bottom":D(j,te),"margin-left":D(q,te),"border-style":le,"border-color":ne,...Or(e,"icon"),"box-shadow":De},".uagb-icon-wrapper .uagb-svg-wrapper:hover":{"border-color":oe,background:Te},".uagb-icon-wrapper .uagb-svg-wrapper:hover svg":{fill:x}};ge&&(Be[".uagb-icon-wrapper .uagb-svg-wrapper:hover"]={"box-shadow":Le,background:Te,"border-color":oe});const He={".uagb-icon-wrapper":{"text-align":p},".uagb-icon-wrapper .uagb-svg-wrapper":{"padding-top":D(B,G),"padding-right":D(H,G),"padding-bottom":D(A,G),"padding-left":D(R,G),"margin-top":D($,ie),"margin-right":D(Z,ie),"margin-bottom":D(K,ie),"margin-left":D(Y,ie),...Or(e,"icon","tablet")},".uagb-icon-wrapper .uagb-svg-wrapper svg":{width:D(u,g),height:D(u,g)}},Ae={".uagb-icon-wrapper":{"text-align":h},".uagb-icon-wrapper .uagb-svg-wrapper":{"padding-top":D(P,V),"padding-right":D(z,V),"padding-bottom":D(O,V),"padding-left":D(I,V),"margin-top":D(J,ae),"margin-right":D(X,ae),"margin-bottom":D(Q,ae),"margin-left":D(ee,ae),...Or(e,"icon","mobile")},".uagb-icon-wrapper .uagb-svg-wrapper svg":{width:D(c,g),height:D(c,g)}};let Re="";const Pe=l||`.uagb-block-${r}`;return Re=E(Be,Pe),("tablet"===o||"mobile"===o||l)&&(Re+=E(He,`${Pe}`,!0,"tablet"),("mobile"===o||l)&&(Re+=E(Ae,`${Pe}`,!0,"mobile"))),Re}(t,0,o,r),[t,r]);return(0,x.useEffect)(()=>{G()},[r]),(0,x.useEffect)(()=>{N(e)},[a,i,l,r]),(0,w.createElement)(w.Fragment,null,(0,w.createElement)(W,{blockStyling:u}),n&&(0,w.createElement)(Tu,{...e}),(0,w.createElement)(Eu,{...e}))});let Lu={};Lu=(0,O.applyFilters)("srfm/icon",nr(Lu)),(0,ir.registerBlockType)("srfm/icon",{...Lu,apiVersion:3,title:(0,M.__)("Icon","sureforms"),description:(0,M.__)("Add stunning customizable icons to your website.","sureforms"),icon:C.icon,keywords:[(0,M.__)("icon","sureforms"),(0,M.__)("uag","sureforms")],supports:{anchor:!0,html:!1},attributes:A,category:srfm_spec_blocks_info.category,edit:e=>e.attributes.isPreview?(0,w.createElement)(lr,{image:"icon"}):(0,w.createElement)(Du,{...e}),save:()=>null});const Bu=i();if(Bu&&(Bu.removeItem("uagSettingState"),Bu.removeItem("isSpectraFontAwesomeAPILoading")),a.p=srfm_spec_blocks_info.uagb_url+"dist/",srfm_spec_blocks_info.uagb_svg_icons={},srfm_spec_blocks_info?.number_of_icon_chunks)for(let e=0;e<srfm_spec_blocks_info.number_of_icon_chunks;e++)srfm_spec_blocks_info.uagb_svg_icons={...srfm_spec_blocks_info.uagb_svg_icons,...window["uagb_svg_icons_"+e]};srfm_spec_blocks_info.font_awesome_5_polyfill={ad:"rectangle-ad","rectangle-ad":"rectangle-ad",adjust:"circle-half-stroke","circle-half-stroke":"circle-half-stroke","air-freshener":"spray-can-sparkles","spray-can-sparkles":"spray-can-sparkles","alien-monster":"alien-8bit","alien-8bit":"alien-8bit",allergies:"hand-dots","hand-dots":"hand-dots",ambulance:"truck-medical","truck-medical":"truck-medical","american-sign-language-interpreting":"hands-asl-interpreting","hands-asl-interpreting":"hands-asl-interpreting",analytics:"chart-mixed","chart-mixed":"chart-mixed","angle-double-down":"angles-down","angles-down":"angles-down","angle-double-left":"angles-left","angles-left":"angles-left","angle-double-right":"angles-right","angles-right":"angles-right","angle-double-up":"angles-up","angles-up":"angles-up",angry:"face-angry","face-angry":"face-angry","apple-alt":"apple-whole","apple-whole":"apple-whole","apple-crate":"crate-apple","crate-apple":"crate-apple",archive:"box-archive","box-archive":"box-archive","arrow-alt-circle-down":"circle-down","circle-down":"circle-down","arrow-alt-circle-left":"circle-left","circle-left":"circle-left","arrow-alt-circle-right":"circle-right","circle-right":"circle-right","arrow-alt-circle-up":"circle-up","circle-up":"circle-up","arrow-alt-down":"down",down:"down","arrow-alt-from-bottom":"up-from-line","up-from-line":"up-from-line","arrow-alt-from-left":"right-from-line","right-from-line":"right-from-line","arrow-alt-from-right":"left-from-line","left-from-line":"left-from-line","arrow-alt-from-top":"down-from-line","down-from-line":"down-from-line","arrow-alt-left":"left",left:"left","arrow-alt-right":"right",right:"right","arrow-alt-square-down":"square-down","square-down":"square-down","arrow-alt-square-left":"square-left","square-left":"square-left","arrow-alt-square-right":"square-right","square-right":"square-right","arrow-alt-square-up":"square-up","square-up":"square-up","arrow-alt-to-bottom":"down-to-line","down-to-line":"down-to-line","arrow-alt-to-left":"left-to-line","left-to-line":"left-to-line","arrow-alt-to-right":"right-to-line","right-to-line":"right-to-line","arrow-alt-to-top":"up-to-line","up-to-line":"up-to-line","arrow-alt-up":"up",up:"up","arrow-circle-down":"circle-arrow-down","circle-arrow-down":"circle-arrow-down","arrow-circle-left":"circle-arrow-left","circle-arrow-left":"circle-arrow-left","arrow-circle-right":"circle-arrow-right","circle-arrow-right":"circle-arrow-right","arrow-circle-up":"circle-arrow-up","circle-arrow-up":"circle-arrow-up","arrow-from-bottom":"arrow-up-from-line","arrow-up-from-line":"arrow-up-from-line","arrow-from-left":"arrow-right-from-line","arrow-right-from-line":"arrow-right-from-line","arrow-from-right":"arrow-left-from-line","arrow-left-from-line":"arrow-left-from-line","arrow-from-top":"arrow-down-from-line","arrow-down-from-line":"arrow-down-from-line","arrow-square-down":"square-arrow-down","square-arrow-down":"square-arrow-down","arrow-square-left":"square-arrow-left","square-arrow-left":"square-arrow-left","arrow-square-right":"square-arrow-right","square-arrow-right":"square-arrow-right","arrow-square-up":"square-arrow-up","square-arrow-up":"square-arrow-up","arrow-to-bottom":"arrow-down-to-line","arrow-down-to-line":"arrow-down-to-line","arrow-to-left":"arrow-left-to-line","arrow-left-to-line":"arrow-left-to-line","arrow-to-right":"arrow-right-to-line","arrow-right-to-line":"arrow-right-to-line","arrow-to-top":"arrow-up-to-line","arrow-up-to-line":"arrow-up-to-line",arrows:"arrows-up-down-left-right","arrows-up-down-left-right":"arrows-up-down-left-right","arrows-alt":"up-down-left-right","up-down-left-right":"up-down-left-right","arrows-alt-h":"left-right","left-right":"left-right","arrows-alt-v":"up-down","up-down":"up-down","arrows-h":"arrows-left-right","arrows-left-right":"arrows-left-right","arrows-v":"arrows-up-down","arrows-up-down":"arrows-up-down","assistive-listening-systems":"ear-listen","ear-listen":"ear-listen",atlas:"book-atlas","book-atlas":"book-atlas","atom-alt":"atom-simple","atom-simple":"atom-simple",backspace:"delete-left","delete-left":"delete-left","balance-scale":"scale-balanced","scale-balanced":"scale-balanced","balance-scale-left":"scale-unbalanced","scale-unbalanced":"scale-unbalanced","balance-scale-right":"scale-unbalanced-flip","scale-unbalanced-flip":"scale-unbalanced-flip","band-aid":"bandage",bandage:"bandage","barcode-alt":"rectangle-barcode","rectangle-barcode":"rectangle-barcode","baseball-ball":"baseball",baseball:"baseball","basketball-ball":"basketball",basketball:"basketball","bed-alt":"bed-front","bed-front":"bed-front",beer:"beer-mug-empty","beer-mug-empty":"beer-mug-empty",betamax:"cassette-betamax","cassette-betamax":"cassette-betamax",bible:"book-bible","book-bible":"book-bible",biking:"person-biking","person-biking":"person-biking","biking-mountain":"person-biking-mountain","person-biking-mountain":"person-biking-mountain","birthday-cake":"cake-candles","cake-candles":"cake-candles",blind:"person-walking-with-cane","person-walking-with-cane":"person-walking-with-cane","book-alt":"book-blank","book-blank":"book-blank","book-dead":"book-skull","book-skull":"book-skull","book-reader":"book-open-reader","book-open-reader":"book-open-reader","book-spells":"book-sparkles","book-sparkles":"book-sparkles","border-style":"border-top-left","border-top-left":"border-top-left","border-style-alt":"border-bottom-right","border-bottom-right":"border-bottom-right","box-alt":"box-taped","box-taped":"box-taped","box-fragile":"square-fragile","square-fragile":"square-fragile","box-full":"box-open-full","box-open-full":"box-open-full","box-up":"square-this-way-up","square-this-way-up":"square-this-way-up","box-usd":"box-dollar","box-dollar":"box-dollar",boxes:"boxes-stacked","boxes-stacked":"boxes-stacked","boxes-alt":"boxes-stacked",brackets:"brackets-square","brackets-square":"brackets-square","broadcast-tower":"tower-broadcast","tower-broadcast":"tower-broadcast",burn:"fire-flame-simple","fire-flame-simple":"fire-flame-simple","bus-alt":"bus-simple","bus-simple":"bus-simple","calculator-alt":"calculator-simple","calculator-simple":"calculator-simple","calendar-alt":"calendar-days","calendar-days":"calendar-days","calendar-edit":"calendar-pen","calendar-pen":"calendar-pen","calendar-times":"calendar-xmark","calendar-xmark":"calendar-xmark","camera-alt":"camera",camera:"camera","camera-home":"camera-security","camera-security":"camera-security","car-alt":"car-rear","car-rear":"car-rear","car-crash":"car-burst","car-burst":"car-burst","car-mechanic":"car-wrench","car-wrench":"car-wrench","caravan-alt":"caravan-simple","caravan-simple":"caravan-simple","caret-circle-down":"circle-caret-down","circle-caret-down":"circle-caret-down","caret-circle-left":"circle-caret-left","circle-caret-left":"circle-caret-left","caret-circle-right":"circle-caret-right","circle-caret-right":"circle-caret-right","caret-circle-up":"circle-caret-up","circle-caret-up":"circle-caret-up","caret-square-down":"square-caret-down","square-caret-down":"square-caret-down","caret-square-left":"square-caret-left","square-caret-left":"square-caret-left","caret-square-right":"square-caret-right","square-caret-right":"square-caret-right","caret-square-up":"square-caret-up","square-caret-up":"square-caret-up",cctv:"camera-cctv","camera-cctv":"camera-cctv","chalkboard-teacher":"chalkboard-user","chalkboard-user":"chalkboard-user","chart-pie-alt":"chart-pie-simple","chart-pie-simple":"chart-pie-simple","check-circle":"circle-check","circle-check":"circle-check","check-square":"square-check","square-check":"square-check",cheeseburger:"burger-cheese","burger-cheese":"burger-cheese","chess-bishop-alt":"chess-bishop-piece","chess-bishop-piece":"chess-bishop-piece","chess-clock-alt":"chess-clock-flip","chess-clock-flip":"chess-clock-flip","chess-king-alt":"chess-king-piece","chess-king-piece":"chess-king-piece","chess-knight-alt":"chess-knight-piece","chess-knight-piece":"chess-knight-piece","chess-pawn-alt":"chess-pawn-piece","chess-pawn-piece":"chess-pawn-piece","chess-queen-alt":"chess-queen-piece","chess-queen-piece":"chess-queen-piece","chess-rook-alt":"chess-rook-piece","chess-rook-piece":"chess-rook-piece","chevron-circle-down":"circle-chevron-down","circle-chevron-down":"circle-chevron-down","chevron-circle-left":"circle-chevron-left","circle-chevron-left":"circle-chevron-left","chevron-circle-right":"circle-chevron-right","circle-chevron-right":"circle-chevron-right","chevron-circle-up":"circle-chevron-up","circle-chevron-up":"circle-chevron-up","chevron-double-down":"chevrons-down","chevrons-down":"chevrons-down","chevron-double-left":"chevrons-left","chevrons-left":"chevrons-left","chevron-double-right":"chevrons-right","chevrons-right":"chevrons-right","chevron-double-up":"chevrons-up","chevrons-up":"chevrons-up","chevron-square-down":"square-chevron-down","square-chevron-down":"square-chevron-down","chevron-square-left":"square-chevron-left","square-chevron-left":"square-chevron-left","chevron-square-right":"square-chevron-right","square-chevron-right":"square-chevron-right","chevron-square-up":"square-chevron-up","square-chevron-up":"square-chevron-up","clinic-medical":"house-chimney-medical","house-chimney-medical":"house-chimney-medical","cloud-download":"cloud-arrow-down","cloud-arrow-down":"cloud-arrow-down","cloud-download-alt":"cloud-arrow-down","cloud-upload":"cloud-arrow-up","cloud-arrow-up":"cloud-arrow-up","cloud-upload-alt":"cloud-arrow-up",cocktail:"martini-glass-citrus","martini-glass-citrus":"martini-glass-citrus",coffee:"mug-saucer","mug-saucer":"mug-saucer","coffee-togo":"cup-togo","cup-togo":"cup-togo",cog:"gear",gear:"gear",cogs:"gears",gears:"gears",columns:"table-columns","table-columns":"table-columns","comment-alt":"message",message:"message","comment-alt-check":"message-check","message-check":"message-check","comment-alt-dollar":"message-dollar","message-dollar":"message-dollar","comment-alt-dots":"message-dots","message-dots":"message-dots","comment-alt-edit":"message-pen","message-pen":"message-pen","comment-alt-exclamation":"message-exclamation","message-exclamation":"message-exclamation","comment-alt-lines":"message-lines","message-lines":"message-lines","comment-alt-medical":"message-medical","message-medical":"message-medical","comment-alt-minus":"message-minus","message-minus":"message-minus","comment-alt-music":"message-music","message-music":"message-music","comment-alt-plus":"message-plus","message-plus":"message-plus","comment-alt-slash":"message-slash","message-slash":"message-slash","comment-alt-smile":"message-smile","message-smile":"message-smile","comment-alt-times":"message-xmark","message-xmark":"message-xmark","comment-edit":"comment-pen","comment-pen":"comment-pen","comment-times":"comment-xmark","comment-xmark":"comment-xmark","comments-alt":"messages",messages:"messages","comments-alt-dollar":"messages-dollar","messages-dollar":"messages-dollar","compress-alt":"down-left-and-up-right-to-center","down-left-and-up-right-to-center":"down-left-and-up-right-to-center","compress-arrows-alt":"minimize",minimize:"minimize","concierge-bell":"bell-concierge","bell-concierge":"bell-concierge",construction:"triangle-person-digging","triangle-person-digging":"triangle-person-digging","conveyor-belt-alt":"conveyor-belt-boxes","conveyor-belt-boxes":"conveyor-belt-boxes","cowbell-more":"cowbell-circle-plus","cowbell-circle-plus":"cowbell-circle-plus",cricket:"cricket-bat-ball","cricket-bat-ball":"cricket-bat-ball","crop-alt":"crop-simple","crop-simple":"crop-simple",curling:"curling-stone","curling-stone":"curling-stone",cut:"scissors",scissors:"scissors",deaf:"ear-deaf","ear-deaf":"ear-deaf",debug:"ban-bug","ban-bug":"ban-bug","desktop-alt":"desktop",desktop:"desktop",dewpoint:"droplet-degree","droplet-degree":"droplet-degree",diagnoses:"person-dots-from-line","person-dots-from-line":"person-dots-from-line",digging:"person-digging","person-digging":"person-digging","digital-tachograph":"tachograph-digital","tachograph-digital":"tachograph-digital",directions:"diamond-turn-right","diamond-turn-right":"diamond-turn-right",dizzy:"face-dizzy","face-dizzy":"face-dizzy","dolly-flatbed":"cart-flatbed","cart-flatbed":"cart-flatbed","dolly-flatbed-alt":"cart-flatbed-boxes","cart-flatbed-boxes":"cart-flatbed-boxes","dolly-flatbed-empty":"cart-flatbed-empty","cart-flatbed-empty":"cart-flatbed-empty",donate:"circle-dollar-to-slot","circle-dollar-to-slot":"circle-dollar-to-slot","dot-circle":"circle-dot","circle-dot":"circle-dot","drafting-compass":"compass-drafting","compass-drafting":"compass-drafting","drone-alt":"drone-front","drone-front":"drone-front","dryer-alt":"dryer-heat","dryer-heat":"dryer-heat","eclipse-alt":"moon-over-sun","moon-over-sun":"moon-over-sun",edit:"pen-to-square","pen-to-square":"pen-to-square","ellipsis-h":"ellipsis",ellipsis:"ellipsis","ellipsis-h-alt":"ellipsis-stroke","ellipsis-stroke":"ellipsis-stroke","ellipsis-v":"ellipsis-vertical","ellipsis-vertical":"ellipsis-vertical","ellipsis-v-alt":"ellipsis-stroke-vertical","ellipsis-stroke-vertical":"ellipsis-stroke-vertical","envelope-square":"square-envelope","square-envelope":"square-envelope",exchange:"arrow-right-arrow-left","arrow-right-arrow-left":"arrow-right-arrow-left","exchange-alt":"right-left","right-left":"right-left","exclamation-circle":"circle-exclamation","circle-exclamation":"circle-exclamation","exclamation-square":"square-exclamation","square-exclamation":"square-exclamation","exclamation-triangle":"triangle-exclamation","triangle-exclamation":"triangle-exclamation","expand-alt":"up-right-and-down-left-from-center","up-right-and-down-left-from-center":"up-right-and-down-left-from-center","expand-arrows":"arrows-maximize","arrows-maximize":"arrows-maximize","expand-arrows-alt":"maximize",maximize:"maximize","external-link":"arrow-up-right-from-square","arrow-up-right-from-square":"arrow-up-right-from-square","external-link-alt":"up-right-from-square","up-right-from-square":"up-right-from-square","external-link-square":"square-arrow-up-right","square-arrow-up-right":"square-arrow-up-right","external-link-square-alt":"square-up-right","square-up-right":"square-up-right","fast-backward":"backward-fast","backward-fast":"backward-fast","fast-forward":"forward-fast","forward-fast":"forward-fast","feather-alt":"feather-pointed","feather-pointed":"feather-pointed",female:"person-dress","person-dress":"person-dress","field-hockey":"field-hockey-stick-ball","field-hockey-stick-ball":"field-hockey-stick-ball","fighter-jet":"jet-fighter","jet-fighter":"jet-fighter","file-alt":"file-lines","file-lines":"file-lines","file-archive":"file-zipper","file-zipper":"file-zipper","file-chart-line":"file-chart-column","file-chart-column":"file-chart-column","file-download":"file-arrow-down","file-arrow-down":"file-arrow-down","file-edit":"file-pen","file-pen":"file-pen","file-medical-alt":"file-waveform","file-waveform":"file-waveform","file-search":"file-magnifying-glass","file-magnifying-glass":"file-magnifying-glass","file-times":"file-xmark","file-xmark":"file-xmark","file-upload":"file-arrow-up","file-arrow-up":"file-arrow-up","film-alt":"film-simple","film-simple":"film-simple","fire-alt":"fire-flame-curved","fire-flame-curved":"fire-flame-curved","first-aid":"kit-medical","kit-medical":"kit-medical","fist-raised":"hand-fist","hand-fist":"hand-fist","flag-alt":"flag-swallowtail","flag-swallowtail":"flag-swallowtail",flame:"fire-flame","fire-flame":"fire-flame","flask-poison":"flask-round-poison","flask-round-poison":"flask-round-poison","flask-potion":"flask-round-potion","flask-round-potion":"flask-round-potion",flushed:"face-flushed","face-flushed":"face-flushed",fog:"cloud-fog","cloud-fog":"cloud-fog","folder-download":"folder-arrow-down","folder-arrow-down":"folder-arrow-down","folder-times":"folder-xmark","folder-xmark":"folder-xmark","folder-upload":"folder-arrow-up","folder-arrow-up":"folder-arrow-up","font-awesome-alt":"square-font-awesome-stroke","square-font-awesome-stroke":"square-font-awesome-stroke","font-awesome-flag":"font-awesome","font-awesome":"font-awesome","font-awesome-logo-full":"font-awesome","football-ball":"football",football:"football",fragile:"wine-glass-crack","wine-glass-crack":"wine-glass-crack","frosty-head":"snowman-head","snowman-head":"snowman-head",frown:"face-frown","face-frown":"face-frown","frown-open":"face-frown-open","face-frown-open":"face-frown-open","funnel-dollar":"filter-circle-dollar","filter-circle-dollar":"filter-circle-dollar","game-board-alt":"game-board-simple","game-board-simple":"game-board-simple","gamepad-alt":"gamepad-modern","gamepad-modern":"gamepad-modern","glass-champagne":"champagne-glass","champagne-glass":"champagne-glass","glass-cheers":"champagne-glasses","champagne-glasses":"champagne-glasses","glass-martini":"martini-glass-empty","martini-glass-empty":"martini-glass-empty","glass-martini-alt":"martini-glass","martini-glass":"martini-glass","glass-whiskey":"whiskey-glass","whiskey-glass":"whiskey-glass","glass-whiskey-rocks":"whiskey-glass-ice","whiskey-glass-ice":"whiskey-glass-ice","glasses-alt":"glasses-round","glasses-round":"glasses-round","globe-africa":"earth-africa","earth-africa":"earth-africa","globe-americas":"earth-americas","earth-americas":"earth-americas","globe-asia":"earth-asia","earth-asia":"earth-asia","globe-europe":"earth-europa","earth-europa":"earth-europa","golf-ball":"golf-ball-tee","golf-ball-tee":"golf-ball-tee",grimace:"face-grimace","face-grimace":"face-grimace",grin:"face-grin","face-grin":"face-grin","grin-alt":"face-grin-wide","face-grin-wide":"face-grin-wide","grin-beam":"face-grin-beam","face-grin-beam":"face-grin-beam","grin-beam-sweat":"face-grin-beam-sweat","face-grin-beam-sweat":"face-grin-beam-sweat","grin-hearts":"face-grin-hearts","face-grin-hearts":"face-grin-hearts","grin-squint":"face-grin-squint","face-grin-squint":"face-grin-squint","grin-squint-tears":"face-grin-squint-tears","face-grin-squint-tears":"face-grin-squint-tears","grin-stars":"face-grin-stars","face-grin-stars":"face-grin-stars","grin-tears":"face-grin-tears","face-grin-tears":"face-grin-tears","grin-tongue":"face-grin-tongue","face-grin-tongue":"face-grin-tongue","grin-tongue-squint":"face-grin-tongue-squint","face-grin-tongue-squint":"face-grin-tongue-squint","grin-tongue-wink":"face-grin-tongue-wink","face-grin-tongue-wink":"face-grin-tongue-wink","grin-wink":"face-grin-wink","face-grin-wink":"face-grin-wink","grip-horizontal":"grip",grip:"grip","h-square":"square-h","square-h":"square-h",hamburger:"burger",burger:"burger","hand-holding-usd":"hand-holding-dollar","hand-holding-dollar":"hand-holding-dollar","hand-holding-water":"hand-holding-droplet","hand-holding-droplet":"hand-holding-droplet","hand-paper":"hand",hand:"hand","hand-receiving":"hands-holding-diamond","hands-holding-diamond":"hands-holding-diamond","hand-rock":"hand-back-fist","hand-back-fist":"hand-back-fist","hands-heart":"hands-holding-heart","hands-holding-heart":"hands-holding-heart","hands-helping":"handshake-angle","handshake-angle":"handshake-angle","hands-usd":"hands-holding-dollar","hands-holding-dollar":"hands-holding-dollar","hands-wash":"hands-bubbles","hands-bubbles":"hands-bubbles","handshake-alt":"handshake-simple","handshake-simple":"handshake-simple","handshake-alt-slash":"handshake-simple-slash","handshake-simple-slash":"handshake-simple-slash","hard-hat":"helmet-safety","helmet-safety":"helmet-safety",hdd:"hard-drive","hard-drive":"hard-drive","head-vr":"head-side-goggles","head-side-goggles":"head-side-goggles","headphones-alt":"headphones-simple","headphones-simple":"headphones-simple","heart-broken":"heart-crack","heart-crack":"heart-crack","heart-circle":"circle-heart","circle-heart":"circle-heart","heart-rate":"wave-pulse","wave-pulse":"wave-pulse","heart-square":"square-heart","square-heart":"square-heart",heartbeat:"heart-pulse","heart-pulse":"heart-pulse",hiking:"person-hiking","person-hiking":"person-hiking",history:"clock-rotate-left","clock-rotate-left":"clock-rotate-left",home:"house",house:"house","home-alt":"house","home-heart":"house-heart","house-heart":"house-heart","home-lg":"house-chimney","house-chimney":"house-chimney","home-lg-alt":"house","hospital-alt":"hospital",hospital:"hospital","hospital-symbol":"circle-h","circle-h":"circle-h","hot-tub":"hot-tub-person","hot-tub-person":"hot-tub-person","hourglass-half":"hourglass",hourglass:"hourglass","house-damage":"house-chimney-crack","house-chimney-crack":"house-chimney-crack","house-leave":"house-person-leave","house-person-leave":"house-person-leave","house-return":"house-person-return","house-person-return":"house-person-return",hryvnia:"hryvnia-sign","hryvnia-sign":"hryvnia-sign",humidity:"droplet-percent","droplet-percent":"droplet-percent","icons-alt":"symbols",symbols:"symbols","id-card-alt":"id-card-clip","id-card-clip":"id-card-clip","industry-alt":"industry-windows","industry-windows":"industry-windows","info-circle":"circle-info","circle-info":"circle-info","info-square":"square-info","square-info":"square-info",innosoft:"42-group","42-group":"42-group",inventory:"shelves",shelves:"shelves","journal-whills":"book-journal-whills","book-journal-whills":"book-journal-whills",kiss:"face-kiss","face-kiss":"face-kiss","kiss-beam":"face-kiss-beam","face-kiss-beam":"face-kiss-beam","kiss-wink-heart":"face-kiss-wink-heart","face-kiss-wink-heart":"face-kiss-wink-heart","landmark-alt":"landmark-dome","landmark-dome":"landmark-dome","laptop-house":"house-laptop","house-laptop":"house-laptop",laugh:"face-laugh","face-laugh":"face-laugh","laugh-beam":"face-laugh-beam","face-laugh-beam":"face-laugh-beam","laugh-squint":"face-laugh-squint","face-laugh-squint":"face-laugh-squint","laugh-wink":"face-laugh-wink","face-laugh-wink":"face-laugh-wink","level-down":"arrow-turn-down","arrow-turn-down":"arrow-turn-down","level-down-alt":"turn-down","turn-down":"turn-down","level-up":"arrow-turn-up","arrow-turn-up":"arrow-turn-up","level-up-alt":"turn-up","turn-up":"turn-up","list-alt":"rectangle-list","rectangle-list":"rectangle-list",location:"location-crosshairs","location-crosshairs":"location-crosshairs","location-circle":"circle-location-arrow","circle-location-arrow":"circle-location-arrow","location-slash":"location-crosshairs-slash","location-crosshairs-slash":"location-crosshairs-slash","lock-alt":"lock-keyhole","lock-keyhole":"lock-keyhole","lock-open-alt":"lock-keyhole-open","lock-keyhole-open":"lock-keyhole-open","long-arrow-alt-down":"down-long","down-long":"down-long","long-arrow-alt-left":"left-long","left-long":"left-long","long-arrow-alt-right":"right-long","right-long":"right-long","long-arrow-alt-up":"up-long","up-long":"up-long","long-arrow-down":"arrow-down-long","arrow-down-long":"arrow-down-long","long-arrow-left":"arrow-left-long","arrow-left-long":"arrow-left-long","long-arrow-right":"arrow-right-long","arrow-right-long":"arrow-right-long","long-arrow-up":"arrow-up-long","arrow-up-long":"arrow-up-long","low-vision":"eye-low-vision","eye-low-vision":"eye-low-vision",luchador:"luchador-mask","luchador-mask":"luchador-mask","luggage-cart":"cart-flatbed-suitcase","cart-flatbed-suitcase":"cart-flatbed-suitcase",magic:"wand-magic","wand-magic":"wand-magic","mail-bulk":"envelopes-bulk","envelopes-bulk":"envelopes-bulk",male:"person",person:"person","map-marked":"map-location","map-location":"map-location","map-marked-alt":"map-location-dot","map-location-dot":"map-location-dot","map-marker":"location-pin","location-pin":"location-pin","map-marker-alt":"location-dot","location-dot":"location-dot","map-marker-alt-slash":"location-dot-slash","location-dot-slash":"location-dot-slash","map-marker-check":"location-check","location-check":"location-check","map-marker-edit":"location-pen","location-pen":"location-pen","map-marker-exclamation":"location-exclamation","location-exclamation":"location-exclamation","map-marker-minus":"location-minus","location-minus":"location-minus","map-marker-plus":"location-plus","location-plus":"location-plus","map-marker-question":"location-question","location-question":"location-question","map-marker-slash":"location-pin-slash","location-pin-slash":"location-pin-slash","map-marker-smile":"location-smile","location-smile":"location-smile","map-marker-times":"location-xmark","location-xmark":"location-xmark","map-signs":"signs-post","signs-post":"signs-post","mars-stroke-h":"mars-stroke-right","mars-stroke-right":"mars-stroke-right","mars-stroke-v":"mars-stroke-up","mars-stroke-up":"mars-stroke-up","medium-m":"medium",medium:"medium",medkit:"suitcase-medical","suitcase-medical":"suitcase-medical",meh:"face-meh","face-meh":"face-meh","meh-blank":"face-meh-blank","face-meh-blank":"face-meh-blank","meh-rolling-eyes":"face-rolling-eyes","face-rolling-eyes":"face-rolling-eyes","microphone-alt":"microphone-lines","microphone-lines":"microphone-lines","microphone-alt-slash":"microphone-lines-slash","microphone-lines-slash":"microphone-lines-slash","mind-share":"brain-arrow-curved-right","brain-arrow-curved-right":"brain-arrow-curved-right","minus-circle":"circle-minus","circle-minus":"circle-minus","minus-hexagon":"hexagon-minus","hexagon-minus":"hexagon-minus","minus-octagon":"octagon-minus","octagon-minus":"octagon-minus","minus-square":"square-minus","square-minus":"square-minus","mobile-alt":"mobile-screen-button","mobile-screen-button":"mobile-screen-button","mobile-android":"mobile",mobile:"mobile","mobile-android-alt":"mobile-screen","mobile-screen":"mobile-screen","money-bill-alt":"money-bill-1","money-bill-1":"money-bill-1","money-bill-wave-alt":"money-bill-1-wave","money-bill-1-wave":"money-bill-1-wave","money-check-alt":"money-check-dollar","money-check-dollar":"money-check-dollar","money-check-edit":"money-check-pen","money-check-pen":"money-check-pen","money-check-edit-alt":"money-check-dollar-pen","money-check-dollar-pen":"money-check-dollar-pen","monitor-heart-rate":"monitor-waveform","monitor-waveform":"monitor-waveform",mouse:"computer-mouse","computer-mouse":"computer-mouse","mouse-alt":"computer-mouse-scrollwheel","computer-mouse-scrollwheel":"computer-mouse-scrollwheel","mouse-pointer":"arrow-pointer","arrow-pointer":"arrow-pointer","music-alt":"music-note","music-note":"music-note","music-alt-slash":"music-note-slash","music-note-slash":"music-note-slash","oil-temp":"oil-temperature","oil-temperature":"oil-temperature","page-break":"file-dashed-line","file-dashed-line":"file-dashed-line","paint-brush-alt":"paint-brush-fine","paint-brush-fine":"paint-brush-fine","pallet-alt":"pallet-boxes","pallet-boxes":"pallet-boxes","paragraph-rtl":"paragraph-left","paragraph-left":"paragraph-left",parking:"square-parking","square-parking":"square-parking","parking-circle":"circle-parking","circle-parking":"circle-parking","parking-circle-slash":"ban-parking","ban-parking":"ban-parking","parking-slash":"square-parking-slash","square-parking-slash":"square-parking-slash",pastafarianism:"spaghetti-monster-flying","spaghetti-monster-flying":"spaghetti-monster-flying","pause-circle":"circle-pause","circle-pause":"circle-pause","paw-alt":"paw-simple","paw-simple":"paw-simple","pen-alt":"pen-clip","pen-clip":"pen-clip","pen-square":"square-pen","square-pen":"square-pen","pencil-alt":"pencil",pencil:"pencil","pencil-paintbrush":"pen-paintbrush","pen-paintbrush":"pen-paintbrush","pencil-ruler":"pen-ruler","pen-ruler":"pen-ruler",pennant:"flag-pennant","flag-pennant":"flag-pennant","people-arrows":"people-arrows-left-right","people-arrows-left-right":"people-arrows-left-right","people-carry":"people-carry-box","people-carry-box":"people-carry-box",percentage:"percent",percent:"percent","person-carry":"person-carry-box","person-carry-box":"person-carry-box","phone-alt":"phone-flip","phone-flip":"phone-flip","phone-laptop":"laptop-mobile","laptop-mobile":"laptop-mobile","phone-square":"square-phone","square-phone":"square-phone","phone-square-alt":"square-phone-flip","square-phone-flip":"square-phone-flip","photo-video":"photo-film","photo-film":"photo-film","plane-alt":"plane-engines","plane-engines":"plane-engines","play-circle":"circle-play","circle-play":"circle-play","plus-circle":"circle-plus","circle-plus":"circle-plus","plus-hexagon":"hexagon-plus","hexagon-plus":"hexagon-plus","plus-octagon":"octagon-plus","octagon-plus":"octagon-plus","plus-square":"square-plus","square-plus":"square-plus",poll:"square-poll-vertical","square-poll-vertical":"square-poll-vertical","poll-h":"square-poll-horizontal","square-poll-horizontal":"square-poll-horizontal","portal-enter":"person-to-portal","person-to-portal":"person-to-portal","portal-exit":"person-from-portal","person-from-portal":"person-from-portal",portrait:"image-portrait","image-portrait":"image-portrait","pound-sign":"sterling-sign","sterling-sign":"sterling-sign",pray:"person-praying","person-praying":"person-praying","praying-hands":"hands-praying","hands-praying":"hands-praying","prescription-bottle-alt":"prescription-bottle-medical","prescription-bottle-medical":"prescription-bottle-medical",presentation:"presentation-screen","presentation-screen":"presentation-screen","print-search":"print-magnifying-glass","print-magnifying-glass":"print-magnifying-glass",procedures:"bed-pulse","bed-pulse":"bed-pulse","project-diagram":"diagram-project","diagram-project":"diagram-project","question-circle":"circle-question","circle-question":"circle-question","question-square":"square-question","square-question":"square-question",quran:"book-quran","book-quran":"book-quran","rabbit-fast":"rabbit-running","rabbit-running":"rabbit-running","radiation-alt":"circle-radiation","circle-radiation":"circle-radiation","radio-alt":"radio-tuner","radio-tuner":"radio-tuner",random:"shuffle",shuffle:"shuffle","rectangle-landscape":"rectangle",rectangle:"rectangle","rectangle-portrait":"rectangle-vertical","rectangle-vertical":"rectangle-vertical",redo:"arrow-rotate-right","arrow-rotate-right":"arrow-rotate-right","redo-alt":"rotate-right","rotate-right":"rotate-right","remove-format":"text-slash","text-slash":"text-slash","repeat-1-alt":"arrows-repeat-1","arrows-repeat-1":"arrows-repeat-1","repeat-alt":"arrows-repeat","arrows-repeat":"arrows-repeat","retweet-alt":"arrows-retweet","arrows-retweet":"arrows-retweet","rss-square":"square-rss","square-rss":"square-rss",running:"person-running","person-running":"person-running","sad-cry":"face-sad-cry","face-sad-cry":"face-sad-cry","sad-tear":"face-sad-tear","face-sad-tear":"face-sad-tear",save:"floppy-disk","floppy-disk":"floppy-disk","sax-hot":"saxophone-fire","saxophone-fire":"saxophone-fire","scalpel-path":"scalpel-line-dashed","scalpel-line-dashed":"scalpel-line-dashed","scanner-image":"scanner",scanner:"scanner",search:"magnifying-glass","magnifying-glass":"magnifying-glass","search-dollar":"magnifying-glass-dollar","magnifying-glass-dollar":"magnifying-glass-dollar","search-location":"magnifying-glass-location","magnifying-glass-location":"magnifying-glass-location","search-minus":"magnifying-glass-minus","magnifying-glass-minus":"magnifying-glass-minus","search-plus":"magnifying-glass-plus","magnifying-glass-plus":"magnifying-glass-plus","sensor-alert":"sensor-triangle-exclamation","sensor-triangle-exclamation":"sensor-triangle-exclamation","sensor-smoke":"sensor-cloud","sensor-cloud":"sensor-cloud","share-alt":"share-nodes","share-nodes":"share-nodes","share-alt-square":"square-share-nodes","square-share-nodes":"square-share-nodes","share-square":"share-from-square","share-from-square":"share-from-square","shield-alt":"shield-blank","shield-blank":"shield-blank","shipping-fast":"truck-fast","truck-fast":"truck-fast","shipping-timed":"truck-clock","truck-clock":"truck-clock","shopping-bag":"bag-shopping","bag-shopping":"bag-shopping","shopping-basket":"basket-shopping","basket-shopping":"basket-shopping","shopping-cart":"cart-shopping","cart-shopping":"cart-shopping","shuttle-van":"van-shuttle","van-shuttle":"van-shuttle",sign:"sign-hanging","sign-hanging":"sign-hanging","sign-in":"arrow-right-to-bracket","arrow-right-to-bracket":"arrow-right-to-bracket","sign-in-alt":"right-to-bracket","right-to-bracket":"right-to-bracket","sign-language":"hands",hands:"hands","sign-out":"arrow-right-from-bracket","arrow-right-from-bracket":"arrow-right-from-bracket","sign-out-alt":"right-from-bracket","right-from-bracket":"right-from-bracket","signal-1":"signal-weak","signal-weak":"signal-weak","signal-2":"signal-fair","signal-fair":"signal-fair","signal-3":"signal-good","signal-good":"signal-good","signal-4":"signal-strong","signal-strong":"signal-strong","signal-alt":"signal-bars","signal-bars":"signal-bars","signal-alt-1":"signal-bars-weak","signal-bars-weak":"signal-bars-weak","signal-alt-2":"signal-bars-fair","signal-bars-fair":"signal-bars-fair","signal-alt-3":"signal-bars-good","signal-bars-good":"signal-bars-good","signal-alt-slash":"signal-bars-slash","signal-bars-slash":"signal-bars-slash",skating:"person-skating","person-skating":"person-skating","ski-jump":"person-ski-jumping","person-ski-jumping":"person-ski-jumping","ski-lift":"person-ski-lift","person-ski-lift":"person-ski-lift",skiing:"person-skiing","person-skiing":"person-skiing","skiing-nordic":"person-skiing-nordic","person-skiing-nordic":"person-skiing-nordic","slack-hash":"slack",slack:"slack",sledding:"person-sledding","person-sledding":"person-sledding","sliders-h":"sliders",sliders:"sliders","sliders-h-square":"square-sliders","square-sliders":"square-sliders","sliders-v":"sliders-up","sliders-up":"sliders-up","sliders-v-square":"square-sliders-vertical","square-sliders-vertical":"square-sliders-vertical",smile:"face-smile","face-smile":"face-smile","smile-beam":"face-smile-beam","face-smile-beam":"face-smile-beam","smile-plus":"face-smile-plus","face-smile-plus":"face-smile-plus","smile-wink":"face-smile-wink","face-smile-wink":"face-smile-wink","smoking-ban":"ban-smoking","ban-smoking":"ban-smoking",sms:"comment-sms","comment-sms":"comment-sms","snapchat-ghost":"snapchat",snapchat:"snapchat",snowboarding:"person-snowboarding","person-snowboarding":"person-snowboarding",snowmobile:"person-snowmobiling","person-snowmobiling":"person-snowmobiling","sort-alpha-down":"arrow-down-a-z","arrow-down-a-z":"arrow-down-a-z","sort-alpha-down-alt":"arrow-down-z-a","arrow-down-z-a":"arrow-down-z-a","sort-alpha-up":"arrow-up-a-z","arrow-up-a-z":"arrow-up-a-z","sort-alpha-up-alt":"arrow-up-z-a","arrow-up-z-a":"arrow-up-z-a","sort-alt":"arrow-down-arrow-up","arrow-down-arrow-up":"arrow-down-arrow-up","sort-amount-down":"arrow-down-wide-short","arrow-down-wide-short":"arrow-down-wide-short","sort-amount-down-alt":"arrow-down-short-wide","arrow-down-short-wide":"arrow-down-short-wide","sort-amount-up":"arrow-up-wide-short","arrow-up-wide-short":"arrow-up-wide-short","sort-amount-up-alt":"arrow-up-short-wide","arrow-up-short-wide":"arrow-up-short-wide","sort-circle":"circle-sort","circle-sort":"circle-sort","sort-circle-down":"circle-sort-down","circle-sort-down":"circle-sort-down","sort-circle-up":"circle-sort-up","circle-sort-up":"circle-sort-up","sort-numeric-down":"arrow-down-1-9","arrow-down-1-9":"arrow-down-1-9","sort-numeric-down-alt":"arrow-down-9-1","arrow-down-9-1":"arrow-down-9-1","sort-numeric-up":"arrow-up-1-9","arrow-up-1-9":"arrow-up-1-9","sort-numeric-up-alt":"arrow-up-9-1","arrow-up-9-1":"arrow-up-9-1","sort-shapes-down":"arrow-down-triangle-square","arrow-down-triangle-square":"arrow-down-triangle-square","sort-shapes-down-alt":"arrow-down-square-triangle","arrow-down-square-triangle":"arrow-down-square-triangle","sort-shapes-up":"arrow-up-triangle-square","arrow-up-triangle-square":"arrow-up-triangle-square","sort-shapes-up-alt":"arrow-up-square-triangle","arrow-up-square-triangle":"arrow-up-square-triangle","sort-size-down":"arrow-down-big-small","arrow-down-big-small":"arrow-down-big-small","sort-size-down-alt":"arrow-down-small-big","arrow-down-small-big":"arrow-down-small-big","sort-size-up":"arrow-up-big-small","arrow-up-big-small":"arrow-up-big-small","sort-size-up-alt":"arrow-up-small-big","arrow-up-small-big":"arrow-up-small-big",soup:"bowl-hot","bowl-hot":"bowl-hot","space-shuttle":"shuttle-space","shuttle-space":"shuttle-space","space-station-moon-alt":"space-station-moon-construction","space-station-moon-construction":"space-station-moon-construction","square-root-alt":"square-root-variable","square-root-variable":"square-root-variable","star-half-alt":"star-half-stroke","star-half-stroke":"star-half-stroke","starfighter-alt":"starfighter-twin-ion-engine","starfighter-twin-ion-engine":"starfighter-twin-ion-engine","step-backward":"backward-step","backward-step":"backward-step","step-forward":"forward-step","forward-step":"forward-step","sticky-note":"note-sticky","note-sticky":"note-sticky","stop-circle":"circle-stop","circle-stop":"circle-stop","store-alt":"shop",shop:"shop","store-alt-slash":"shop-slash","shop-slash":"shop-slash",stream:"bars-staggered","bars-staggered":"bars-staggered",subway:"train-subway","train-subway":"train-subway",surprise:"face-surprise","face-surprise":"face-surprise",swimmer:"person-swimming","person-swimming":"person-swimming","swimming-pool":"water-ladder","water-ladder":"water-ladder",sync:"arrows-rotate","arrows-rotate":"arrows-rotate","sync-alt":"rotate",rotate:"rotate","table-tennis":"table-tennis-paddle-ball","table-tennis-paddle-ball":"table-tennis-paddle-ball","tablet-alt":"tablet-screen-button","tablet-screen-button":"tablet-screen-button","tablet-android":"tablet",tablet:"tablet","tablet-android-alt":"tablet-screen","tablet-screen":"tablet-screen",tachometer:"gauge-simple","gauge-simple":"gauge-simple","tachometer-alt":"gauge",gauge:"gauge","tachometer-alt-average":"gauge-med","gauge-med":"gauge-med","tachometer-alt-fast":"gauge","tachometer-alt-fastest":"gauge-max","gauge-max":"gauge-max","tachometer-alt-slow":"gauge-low","gauge-low":"gauge-low","tachometer-alt-slowest":"gauge-min","gauge-min":"gauge-min","tachometer-average":"gauge-simple-med","gauge-simple-med":"gauge-simple-med","tachometer-fast":"gauge-simple","tachometer-fastest":"gauge-simple-max","gauge-simple-max":"gauge-simple-max","tachometer-slow":"gauge-simple-low","gauge-simple-low":"gauge-simple-low","tachometer-slowest":"gauge-simple-min","gauge-simple-min":"gauge-simple-min",tanakh:"book-tanakh","book-tanakh":"book-tanakh",tasks:"list-check","list-check":"list-check","tasks-alt":"bars-progress","bars-progress":"bars-progress","telegram-plane":"telegram",telegram:"telegram","temperature-down":"temperature-arrow-down","temperature-arrow-down":"temperature-arrow-down","temperature-frigid":"temperature-snow","temperature-snow":"temperature-snow","temperature-hot":"temperature-sun","temperature-sun":"temperature-sun","temperature-up":"temperature-arrow-up","temperature-arrow-up":"temperature-arrow-up",tenge:"tenge-sign","tenge-sign":"tenge-sign",th:"table-cells","table-cells":"table-cells","th-large":"table-cells-large","table-cells-large":"table-cells-large","th-list":"table-list","table-list":"table-list","theater-masks":"masks-theater","masks-theater":"masks-theater","thermometer-empty":"temperature-empty","temperature-empty":"temperature-empty","thermometer-full":"temperature-full","temperature-full":"temperature-full","thermometer-half":"temperature-half","temperature-half":"temperature-half","thermometer-quarter":"temperature-quarter","temperature-quarter":"temperature-quarter","thermometer-three-quarters":"temperature-three-quarters","temperature-three-quarters":"temperature-three-quarters",thunderstorm:"cloud-bolt","cloud-bolt":"cloud-bolt","thunderstorm-moon":"cloud-bolt-moon","cloud-bolt-moon":"cloud-bolt-moon","thunderstorm-sun":"cloud-bolt-sun","cloud-bolt-sun":"cloud-bolt-sun","ticket-alt":"ticket-simple","ticket-simple":"ticket-simple",times:"xmark",xmark:"xmark","times-circle":"circle-xmark","circle-xmark":"circle-xmark","times-hexagon":"hexagon-xmark","hexagon-xmark":"hexagon-xmark","times-octagon":"octagon-xmark","octagon-xmark":"octagon-xmark","times-square":"square-xmark","square-xmark":"square-xmark",tint:"droplet",droplet:"droplet","tint-slash":"droplet-slash","droplet-slash":"droplet-slash",tired:"face-tired","face-tired":"face-tired","toilet-paper-alt":"toilet-paper-blank","toilet-paper-blank":"toilet-paper-blank","tombstone-alt":"tombstone-blank","tombstone-blank":"tombstone-blank",tools:"screwdriver-wrench","screwdriver-wrench":"screwdriver-wrench",torah:"scroll-torah","scroll-torah":"scroll-torah",tram:"train-tram","train-tram":"train-tram","transgender-alt":"transgender",transgender:"transgender","trash-alt":"trash-can","trash-can":"trash-can","trash-restore":"trash-arrow-up","trash-arrow-up":"trash-arrow-up","trash-restore-alt":"trash-can-arrow-up","trash-can-arrow-up":"trash-can-arrow-up","trash-undo-alt":"trash-can-undo","trash-can-undo":"trash-can-undo","tree-alt":"tree-deciduous","tree-deciduous":"tree-deciduous","triangle-music":"triangle-instrument","triangle-instrument":"triangle-instrument","trophy-alt":"trophy-star","trophy-star":"trophy-star","truck-couch":"truck-ramp-couch","truck-ramp-couch":"truck-ramp-couch","truck-loading":"truck-ramp-box","truck-ramp-box":"truck-ramp-box",tshirt:"shirt",shirt:"shirt","tv-alt":"tv",tv:"tv",undo:"arrow-rotate-left","arrow-rotate-left":"arrow-rotate-left","undo-alt":"rotate-left","rotate-left":"rotate-left",university:"building-columns","building-columns":"building-columns",unlink:"link-slash","link-slash":"link-slash","unlock-alt":"unlock-keyhole","unlock-keyhole":"unlock-keyhole","usd-circle":"circle-dollar","circle-dollar":"circle-dollar","usd-square":"square-dollar","square-dollar":"square-dollar","user-alt":"user-large","user-large":"user-large","user-alt-slash":"user-large-slash","user-large-slash":"user-large-slash","user-chart":"chart-user","chart-user":"chart-user","user-circle":"circle-user","circle-user":"circle-user","user-cog":"user-gear","user-gear":"user-gear","user-edit":"user-pen","user-pen":"user-pen","user-friends":"user-group","user-group":"user-group","user-hard-hat":"user-helmet-safety","user-helmet-safety":"user-helmet-safety","user-md":"user-doctor","user-doctor":"user-doctor","user-md-chat":"user-doctor-message","user-doctor-message":"user-doctor-message","user-times":"user-xmark","user-xmark":"user-xmark","users-class":"screen-users","screen-users":"screen-users","users-cog":"users-gear","users-gear":"users-gear","users-crown":"user-group-crown","user-group-crown":"user-group-crown","utensil-fork":"fork",fork:"fork","utensil-knife":"knife",knife:"knife","utensil-spoon":"spoon",spoon:"spoon","utensils-alt":"fork-knife","fork-knife":"fork-knife",vhs:"cassette-vhs","cassette-vhs":"cassette-vhs","volleyball-ball":"volleyball",volleyball:"volleyball","volume-down":"volume-low","volume-low":"volume-low","volume-mute":"volume-xmark","volume-xmark":"volume-xmark","volume-up":"volume-high","volume-high":"volume-high","vote-nay":"xmark-to-slot","xmark-to-slot":"xmark-to-slot","vote-yea":"check-to-slot","check-to-slot":"check-to-slot",walking:"person-walking","person-walking":"person-walking","warehouse-alt":"warehouse-full","warehouse-full":"warehouse-full",washer:"washing-machine","washing-machine":"washing-machine","water-lower":"water-arrow-down","water-arrow-down":"water-arrow-down","water-rise":"water-arrow-up","water-arrow-up":"water-arrow-up","waveform-path":"waveform-lines","waveform-lines":"waveform-lines",webcam:"camera-web","camera-web":"camera-web","webcam-slash":"camera-web-slash","camera-web-slash":"camera-web-slash",weight:"weight-scale","weight-scale":"weight-scale","wifi-1":"wifi-weak","wifi-weak":"wifi-weak","wifi-2":"wifi-fair","wifi-fair":"wifi-fair","window-alt":"window-flip","window-flip":"window-flip","window-close":"rectangle-xmark","rectangle-xmark":"rectangle-xmark","wine-glass-alt":"wine-glass-empty","wine-glass-empty":"wine-glass-empty"},Bu.setItem("uagSvgConfirmation",JSON.stringify(srfm_spec_blocks_info?.svg_confirmation||!1)),srfm_spec_blocks_info.uagb_svg_icons?.uagb_category_list&&(wp.uagb_icon_category_list=[...srfm_spec_blocks_info.uagb_svg_icons.uagb_category_list],delete srfm_spec_blocks_info.uagb_svg_icons.uagb_category_list),wp.UAGBSvgIcons=Object.keys(srfm_spec_blocks_info.uagb_svg_icons),wp.hooks.addFilter("uag_reponsive_conditions_compatible_blocks","enable_reponsive_condition_for_cf_blocks",function(e){return e.push("wcfb/"),e})},3307(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uag-custom-ip .uag-control-label{padding-bottom:4px;display:block}.uag-custom-ip .uag-ip-placeholder-wrap{width:256px;max-width:100%;min-height:96px;display:flex;background-color:#fff;border:1px solid #e6e7e9;border-radius:3px;position:relative;overflow:hidden}.uag-custom-ip .uag-ip-placeholder-wrap:hover .uag-ip-actions{transform:translate(0, 0)}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-remove-icon>svg,.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-selected-icon-overlay>svg{fill:#fff;width:18px;height:18px;background-color:#ccc;padding:2.4px;border-radius:50%}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-remove-icon{position:absolute;right:5px;top:5px;line-height:0;cursor:pointer;z-index:6}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-remove-icon>svg{transition:.3s background-color linear}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-remove-icon>svg:hover{background-color:#959494}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-selected-icon{width:100%;display:flex;cursor:pointer}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-selected-icon-overlay{display:flex;width:100%;justify-content:center;align-items:center}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-selected-icon-value{position:absolute;z-index:1;width:100%;height:100%;display:flex;align-items:center;justify-content:center}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-selected-icon-value>svg{height:30px;width:30px;fill:#50575e}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-actions{position:absolute;bottom:0;width:100%;display:flex;z-index:2;transform:translate(0, 24px);transition:.2s all ease-in-out}.uag-custom-ip .uag-ip-placeholder-wrap .uag-ip-actions>span{background-color:#f0f0f1;flex:1;font-size:13px;font-weight:400;text-align:center;line-height:24px;color:#50575e;cursor:pointer}.components-modal__screen-overlay.uagb-ip-modal-wrapper-overlay{background-color:rgba(0,0,0,.7)}.components-modal__frame.uagb-ip-modal-wrapper{width:1080px;height:796px;max-height:80%;max-width:80%;overflow:unset;box-sizing:border-box}.components-modal__frame.uagb-ip-modal-wrapper *{box-sizing:border-box}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content{padding:30px 24px;margin:0;background-color:#fff;overflow:unset;border-radius:2px}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content>div:not(.components-modal__header){height:100%}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .components-modal__header{height:0}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .components-modal__header .components-modal__header-heading-container{display:none !important}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .components-modal__header .components-button{color:#aaa;position:absolute;width:12px;height:12px;top:4px;right:-32px;transition:.2s color linear;left:auto}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .components-modal__header .components-button:hover{color:#fff}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .uagb-ip-header{display:flex;align-items:baseline;height:64px}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .uagb-ip-header>h2{width:156px;margin:0;font-size:20px;font-weight:400;color:#1e1e1e}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .uagb-ip-footer{height:68px;text-align:right;display:flex;align-items:flex-end;justify-content:flex-end}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .uagb-ip-footer>button{font-size:13px;color:#fff;border:none;background-color:#007cba;border-radius:2px;width:89px;height:36px;cursor:pointer}.components-modal__frame.uagb-ip-modal-wrapper .components-modal__content .uagb-ip-footer>button.disable{opacity:.7;cursor:not-allowed}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-lr-container{display:flex;height:calc(100% - 134px);grid-gap:24px}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-lr-container .uagb-ip-left{width:156px;overflow:auto}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-lr-container .uagb-ip-right{flex:1;padding:14px;padding-right:0;border:1px solid #e6e7e9;border-radius:2px}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-lr-container .uagb-ip-right .uagb-ip-modal-container{height:100%}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-lr-container .uagb-ip-right .uagb-ip-modal-container .ReactVirtualized__Grid__innerScrollContainer>div{display:flex;justify-content:center;align-items:center}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-categories-list>div{padding:9px 10px;cursor:pointer;border-radius:2px;color:#1d2327;display:flex;justify-content:space-between;font-size:13px}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-categories-list>div.selected{background-color:#dcf2ff;color:#0063a1}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container{flex:1;padding-left:24px}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar{position:relative}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar>svg,.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar>span{width:14px;height:14px;position:absolute;top:11px;color:#555d66;fill:#555d66;transform:rotateZ(90deg);left:12px}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar>span{width:unset;cursor:pointer}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar input{height:36px;width:100%;padding:7px 12px 7px 38px;border:1px solid #e6e7e9;margin:0;border-radius:2px;color:#1d2327}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar input::placeholder{color:#50575e}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-search-container .uagb-ip-search-bar input:focus{border:1.5px solid #007cba}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .ReactVirtualized__Grid__innerScrollContainer{overflow-x:hidden !important;max-width:inherit !important}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons.icon-not-found{display:flex;align-items:center;justify-content:center}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .uagb-icon-item{width:80px;height:80px;background-color:#fff;border:1px solid #e6e7e9;border-radius:3px;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:.2s transform ease;flex-direction:column;grid-gap:6px;max-width:90%;max-height:90%}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .uagb-icon-item.default{border-color:#007cba;box-shadow:0 0 0 2px #007cba;pointer-events:none}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .uagb-icon-item.selected{border-color:#007cba;box-shadow:0 0 0 2px #dcf2ff;pointer-events:none}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .uagb-icon-item>svg{width:20.9px;height:20.27px}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .uagb-icon-item>span{font-size:11px;text-align:center}.components-modal__frame.uagb-ip-modal-wrapper .uagb-ip-icons .uagb-icon-item:hover{border-color:#e6e7e9;box-shadow:0 0 0 4px #f0f0f1}",""]);const r=o},3491(e){(function(){var t,a,i,l,n,o;"undefined"!=typeof performance&&null!==performance&&performance.now?e.exports=function(){return performance.now()}:"undefined"!=typeof process&&null!==process&&process.hrtime?(e.exports=function(){return(t()-n)/1e6},a=process.hrtime,l=(t=function(){var e;return 1e9*(e=a())[0]+e[1]})(),o=1e9*process.uptime(),n=l-o):Date.now?(e.exports=function(){return Date.now()-i},i=Date.now()):(e.exports=function(){return(new Date).getTime()-i},i=(new Date).getTime())}).call(this)},3578(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-advanced-color-settings-container{display:flex;align-items:center}.uagb-advanced-color-settings-container .uagb-beside-color-click{display:flex;align-items:center}.uagb-advanced-color-settings-container .uagb-color-icon-indicate{height:auto;position:relative;transform:scale(1);transition:transform .1s ease;border-radius:50%;padding:0}.uagb-advanced-color-settings-container .uagb-has-alpha{background-image:linear-gradient(45deg, #ddd 25%, transparent 0),linear-gradient(-45deg, #ddd 25%, transparent 0),linear-gradient(45deg, transparent 75%, #ddd 0),linear-gradient(-45deg, transparent 75%, #ddd 0);background-size:10px 10px;background-position:0 0,0 5px,5px -5px,-5px 0}.uagb-advanced-color-settings-container .uagb-beside-color-label{flex-grow:1;margin:0}.uagb-advanced-color-settings-container .uagb-color-icon-indicate .component-color-indicator.uagb-advanced-color-indicate{width:28px;height:28px;border-radius:50%;margin:0;background:none;display:flex;justify-content:center;align-items:center}.uagb-advanced-color-settings-container .uagb-color-icon-indicate .component-color-indicator.uagb-advanced-color-indicate>svg{fill:rgba(0,0,0,0)}.uagb-advanced-color-settings-container .uag-global-icon-black{color:#000}.uagb-advanced-color-settings-container .uag-global-icon-white{color:#fff}.uagb-popover-color .components-popover__content{overflow-x:hidden;overflow-y:auto}.uagb-popover-color .components-circular-option-picker{padding:2px 0 10px 5px}.uagb-popover-color .components-circular-option-picker .components-circular-option-picker__swatches{margin-right:0;text-align:left;padding-left:10px}.uagb-popover-color .uagb-clear-btn-inside-picker{margin:5px 20px 20px 15px;padding:0 8px;border:1px solid #ccc;box-shadow:none}",""]);const r=o},3790(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-inspector-tab .spectra__matrix-control{display:flex;justify-content:space-between;align-items:flex-start}.uagb-inspector-tab .spectra__matrix-control--box{border:1px solid #e6e7e9;border-radius:3px}.uagb-inspector-tab .spectra__matrix-control .uag-control-label{margin:0}",""]);const r=o},3942(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".spectra-separator{width:100%;height:1px;margin:25px 0;background-color:#e6e7e9}.spectra-separator--removed-top-space{margin-top:0 !important}.uagb-inspector-tab .components-panel__body .spectra-separator{width:auto;margin:25px -16px}",""]);const r=o},4180(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-multi-button-button-group{display:flex !important;width:100%}.uagb-multi-button-button-group .uagb-multi-button{width:100%;justify-content:center;height:unset;padding:6px;line-height:16px;min-height:30px}.uagb-multi-button-button-group .uagb-multi-button:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.uagb-multi-button-button-group .uagb-multi-button:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.uagb-multi-button-button-group button.uagb-multi-button.is-secondary{color:#50575e;box-shadow:inset 0 0 0 1px #e6e7e9}.uagb-multi-button-button-group .uagb-multi-button.is-secondary:hover:not(:disabled),.uagb-multi-button-button-group .uagb-multi-button-grou[aria-label=Gap] .uagb-multi-button.is-tertiary:hover:not(:disabled){color:#1d2327;box-shadow:inset 0 0 0 1px #e6e7e9}.uagb-multi-button-button-group .uagb-multi-button.is-secondary,.uagb-multi-button-button-group .uagb-multi-button.is-tertiary{color:#50575e}.uagb-multi-button-button-group .uagb-multi-button.is-secondary:active:not(:disabled),.uagb-multi-button-button-group .uagb-multi-button-grou[aria-label=Gap] .uagb-multi-button.is-tertiary:active:not(:disabled){background:#fff;box-shadow:inset 0 0 0 1px #e6e7e9}.uagb-multi-button-button-group button.uagb-multi-button{font-size:13px;font-weight:400}.uagb-multi-button-button-group svg{width:18px;fill:#50575e}.uagb-multi-button-button-group svg path{fill:inherit}.uagb-multi-buttons-control.uag-multibutton-icons .uagb-multi-button{padding:3px}.spectra-multi-buttons__color-scheme--primary button.uagb-multi-button.is-primary.is-primary{color:#007cba;background-color:#dcf2ff;border-color:#cde9f9;box-shadow:inset 0 0 0 1px #cde9f9}.spectra-multi-buttons__color-scheme--primary button.uagb-multi-button.is-primary.is-primary svg{fill:#007cba}.spectra-multi-buttons__color-scheme--secondary button.uagb-multi-button.is-primary.is-primary{color:#fff;background-color:#959595;border-color:#959595;box-shadow:inset 0 0 0 1px #959595}.spectra-multi-buttons__color-scheme--secondary button.uagb-multi-button.is-primary.is-primary svg{fill:#fff}.spectra-multi-buttons__layout--inline{align-items:center;display:grid;grid-template-columns:50% 50%}.spectra-multi-buttons__layout--inline .uagb-control__header,.spectra-multi-buttons__layout--inline .uag-control-label{margin-bottom:0}",""]);const r=o},4284(e){"use strict";var t,a=(t=[],function(e,a){return t[e]=a,t.filter(Boolean).join("\n")});function i(e,t,i,l){var n;if(i)n="";else{n="",l.supports&&(n+="@supports (".concat(l.supports,") {")),l.media&&(n+="@media ".concat(l.media," {"));var o=void 0!==l.layer;o&&(n+="@layer".concat(l.layer.length>0?" ".concat(l.layer):""," {")),n+=l.css,o&&(n+="}"),l.media&&(n+="}"),l.supports&&(n+="}")}if(e.styleSheet)e.styleSheet.cssText=a(t,n);else{var r=document.createTextNode(n),s=e.childNodes;s[t]&&e.removeChild(s[t]),s.length?e.insertBefore(r,s[t]):e.appendChild(r)}}var l={singleton:null,singletonCounter:0};e.exports=function(e){if("undefined"==typeof document)return{update:function(){},remove:function(){}};var t=l.singletonCounter++,a=l.singleton||(l.singleton=e.insertStyleElement(e));return{update:function(e){i(a,t,!1,e)},remove:function(e){i(a,t,!0,e)}}}},4486(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,'.uagb-inspector-tab.uagb-tab-content-general .uag-advance-panel-body-image .editor-bg-image-control{margin-top:-35px}.uagb-inspector-tab .block-editor-image-size-control .block-editor-image-size-control__row{text-transform:capitalize}.uagb-inspector-tab .components-base-control label.components-input-control__label{text-transform:capitalize}.uagb-inspector-tab .block-editor-image-size-control__row .components-button-group .components-button{border:1px solid #8f9395;box-shadow:none;font-size:13px;font-weight:400;height:26px}.uagb-inspector-tab .block-editor-image-size-control__row .components-button-group .components-button.is-pressed{background:#0085ba;border-color:#0085ba}.uagb-inspector-tab .block-editor-image-size-control__row .components-button span.dashicons-image-rotate{font-size:9px;display:flex;justify-content:center;align-items:center;color:#2e92c4}.block-editor-block-list__block.wp-block[data-type="srfm/image"]{width:inherit}.wp-block-uagb-image--effect-slide .wp-block-uagb-image__figure img,.wp-block-uagb-image--effect-slide .wp-block-uagb-image__figure .wp-block-uagb-image--layout-overlay__color-wrapper{width:calc(100% + 40px) !important;max-width:none !important;transform:translate3d(-40px, 0, 0);transition:transform .35s ease-in-out}.wp-block-uagb-image--effect-slide .wp-block-uagb-image__figure:hover img,.wp-block-uagb-image--effect-slide .wp-block-uagb-image__figure:hover .wp-block-uagb-image--layout-overlay__color-wrapper{transform:translate3d(0, 0, 0)}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder{box-shadow:none;border:1px dashed #555d66}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder .components-placeholder__label{margin-left:auto;margin-right:auto;margin-bottom:8px}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder .components-placeholder__label .block-editor-block-icon svg.uagb-editor-icons path{stroke:#0063a1}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder .components-placeholder__fieldset{justify-content:center}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder .components-placeholder__fieldset .components-placeholder__instructions{width:100%;text-align:center;margin-bottom:32px}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder .components-button.is-tertiary{box-shadow:inset 0 0 0 1px var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba));color:var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba));padding:6px 12px}.wp-block-uagb-image .components-placeholder.block-editor-media-placeholder .components-button.is-tertiary:hover{box-shadow:inset 0 0 0 1px var(--wp-components-color-accent-darker-10, var(--wp-admin-theme-color-darker-10, #006ba1));color:var(--wp-components-color-accent-darker-10, var(--wp-admin-theme-color-darker-10, #006ba1))}.wp-block-uagb-image .components-resizable-box__container{max-width:100% !important;height:auto !important}.wp-block-uagb-image .components-resizable-box__container img{max-width:100% !important}.wp-block-uagb-image .components-placeholder.is-medium .components-placeholder__instructions{display:block !important}.wp-block-uagb-image .components-placeholder.is-medium .components-placeholder__fieldset{flex-direction:row}.wp-block-uagb-image .components-placeholder.is-medium .components-placeholder__fieldset .components-button{margin-right:10px}',""]);const r=o},4676(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uag-range-control .uagb-range-control__mobile-controls{display:flex;width:100%;align-items:center}.uag-range-control .uagb-range-control__mobile-controls .components-base-control.components-range-control{-webkit-tap-highlight-color:rgba(0,0,0,0);box-sizing:border-box;align-items:flex-start;-webkit-box-pack:start;justify-content:flex-start;margin-right:20px;position:relative;width:100%;margin-bottom:0;max-height:30px}.uag-range-control .uagb-range-control__mobile-controls .components-base-control.components-range-control .components-range-control__tooltip{left:45%}.uag-range-control .uagb-range-control__mobile-controls .components-input-control__container{flex:0 0 0%;width:100%}.uag-range-control .uagb-range-control__mobile-controls .components-number-control{width:35%;margin-left:10px}.uag-range-control .uagb-range-control__mobile-controls .components-number-control .components-input-control__input{padding:0 1px 0 8px !important;text-align:left;font-size:14px}.uag-range-control .uagb-range-control__mobile-controls .components-range-control__marks{top:13px}",""]);const r=o},4868(e){"use strict";e.exports=function(e,t){Object.keys(t).forEach(function(a){e.setAttribute(a,t[a])})}},4994(e){e.exports=function(e){return e&&e.__esModule?e:{default:e}},e.exports.__esModule=!0,e.exports.default=e.exports},5001(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-color-switch-control-container .components-flex.components-angle-picker-control{margin-bottom:0}.uagb-color-switch-control-container .uagb-multi-buttons-control{margin-bottom:5px}.uagb-color-switch-control-container .uagb-color-popover-container{margin-top:25px}.uagb-color-switch-control-container .components-custom-gradient-picker{margin-top:25px}.uagb-color-switch-control-container .uagb-advanced-color-settings-container{justify-content:flex-end}",""]);const r=o},5072(e){"use strict";var t=[];function a(e){for(var a=-1,i=0;i<t.length;i++)if(t[i].identifier===e){a=i;break}return a}function i(e,i){for(var n={},o=[],r=0;r<e.length;r++){var s=e[r],u=i.base?s[0]+i.base:s[0],c=n[u]||0,g="".concat(u," ").concat(c);n[u]=c+1;var d=a(g),p={css:s[1],media:s[2],sourceMap:s[3],supports:s[4],layer:s[5]};if(-1!==d)t[d].references++,t[d].updater(p);else{var h=l(p,i);i.byIndex=r,t.splice(r,0,{identifier:g,updater:h,references:1})}o.push(g)}return o}function l(e,t){var a=t.domAPI(t);return a.update(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap&&t.supports===e.supports&&t.layer===e.layer)return;a.update(e=t)}else a.remove()}}e.exports=function(e,l){var n=i(e=e||[],l=l||{});return function(e){e=e||[];for(var o=0;o<n.length;o++){var r=a(n[o]);t[r].references--}for(var s=i(e,l),u=0;u<n.length;u++){var c=a(n[u]);0===t[c].references&&(t[c].updater(),t.splice(c,1))}n=s}}},5371(e,t,a){var i;!function(){function l(e,t,a){return e.call.apply(e.bind,arguments)}function n(e,t,a){if(!e)throw Error();if(2<arguments.length){var i=Array.prototype.slice.call(arguments,2);return function(){var a=Array.prototype.slice.call(arguments);return Array.prototype.unshift.apply(a,i),e.apply(t,a)}}return function(){return e.apply(t,arguments)}}function o(e,t,a){return(o=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?l:n).apply(null,arguments)}var r=Date.now||function(){return+new Date};function s(e,t){this.a=e,this.o=t||e,this.c=this.o.document}var u=!!window.FontFace;function c(e,t,a,i){if(t=e.c.createElement(t),a)for(var l in a)a.hasOwnProperty(l)&&("style"==l?t.style.cssText=a[l]:t.setAttribute(l,a[l]));return i&&t.appendChild(e.c.createTextNode(i)),t}function g(e,t,a){(e=e.c.getElementsByTagName(t)[0])||(e=document.documentElement),e.insertBefore(a,e.lastChild)}function d(e){e.parentNode&&e.parentNode.removeChild(e)}function p(e,t,a){t=t||[],a=a||[];for(var i=e.className.split(/\s+/),l=0;l<t.length;l+=1){for(var n=!1,o=0;o<i.length;o+=1)if(t[l]===i[o]){n=!0;break}n||i.push(t[l])}for(t=[],l=0;l<i.length;l+=1){for(n=!1,o=0;o<a.length;o+=1)if(i[l]===a[o]){n=!0;break}n||t.push(i[l])}e.className=t.join(" ").replace(/\s+/g," ").replace(/^\s+|\s+$/,"")}function h(e,t){for(var a=e.className.split(/\s+/),i=0,l=a.length;i<l;i++)if(a[i]==t)return!0;return!1}function m(e,t,a){function i(){r&&l&&n&&(r(o),r=null)}t=c(e,"link",{rel:"stylesheet",href:t,media:"all"});var l=!1,n=!0,o=null,r=a||null;u?(t.onload=function(){l=!0,i()},t.onerror=function(){l=!0,o=Error("Stylesheet failed to load"),i()}):setTimeout(function(){l=!0,i()},0),g(e,"head",t)}function b(e,t,a,i){var l=e.c.getElementsByTagName("head")[0];if(l){var n=c(e,"script",{src:t}),o=!1;return n.onload=n.onreadystatechange=function(){o||this.readyState&&"loaded"!=this.readyState&&"complete"!=this.readyState||(o=!0,a&&a(null),n.onload=n.onreadystatechange=null,"HEAD"==n.parentNode.tagName&&l.removeChild(n))},l.appendChild(n),setTimeout(function(){o||(o=!0,a&&a(Error("Script load timeout")))},i||5e3),n}return null}function f(){this.a=0,this.c=null}function v(e){return e.a++,function(){e.a--,y(e)}}function w(e,t){e.c=t,y(e)}function y(e){0==e.a&&e.c&&(e.c(),e.c=null)}function x(e){this.a=e||"-"}function _(e,t){this.c=e,this.f=4,this.a="n";var a=(t||"n4").match(/^([nio])([1-9])$/i);a&&(this.a=a[1],this.f=parseInt(a[2],10))}function k(e){var t=[];e=e.split(/,\s*/);for(var a=0;a<e.length;a++){var i=e[a].replace(/['"]/g,"");-1!=i.indexOf(" ")||/^\d/.test(i)?t.push("'"+i+"'"):t.push(i)}return t.join(",")}function S(e){return e.a+e.f}function C(e){var t="normal";return"o"===e.a?t="oblique":"i"===e.a&&(t="italic"),t}function M(e){var t=4,a="n",i=null;return e&&((i=e.match(/(normal|oblique|italic)/i))&&i[1]&&(a=i[1].substr(0,1).toLowerCase()),(i=e.match(/([1-9]00|normal|bold)/i))&&i[1]&&(/bold/i.test(i[1])?t=7:/[1-9]00/.test(i[1])&&(t=parseInt(i[1].substr(0,1),10)))),a+t}function T(e,t){this.c=e,this.f=e.o.document.documentElement,this.h=t,this.a=new x("-"),this.j=!1!==t.events,this.g=!1!==t.classes}function E(e){if(e.g){var t=h(e.f,e.a.c("wf","active")),a=[],i=[e.a.c("wf","loading")];t||a.push(e.a.c("wf","inactive")),p(e.f,a,i)}D(e,"inactive")}function D(e,t,a){e.j&&e.h[t]&&(a?e.h[t](a.c,S(a)):e.h[t]())}function L(){this.c={}}function B(e,t){this.c=e,this.f=t,this.a=c(this.c,"span",{"aria-hidden":"true"},this.f)}function H(e){g(e.c,"body",e.a)}function A(e){return"display:block;position:absolute;top:-9999px;left:-9999px;font-size:300px;width:auto;height:auto;line-height:normal;margin:0;padding:0;font-variant:normal;white-space:nowrap;font-family:"+k(e.c)+";font-style:"+C(e)+";font-weight:"+e.f+"00;"}function R(e,t,a,i,l,n){this.g=e,this.j=t,this.a=i,this.c=a,this.f=l||3e3,this.h=n||void 0}function P(e,t,a,i,l,n,o){this.v=e,this.B=t,this.c=a,this.a=i,this.s=o||"BESbswy",this.f={},this.w=l||3e3,this.u=n||null,this.m=this.j=this.h=this.g=null,this.g=new B(this.c,this.s),this.h=new B(this.c,this.s),this.j=new B(this.c,this.s),this.m=new B(this.c,this.s),e=A(e=new _(this.a.c+",serif",S(this.a))),this.g.a.style.cssText=e,e=A(e=new _(this.a.c+",sans-serif",S(this.a))),this.h.a.style.cssText=e,e=A(e=new _("serif",S(this.a))),this.j.a.style.cssText=e,e=A(e=new _("sans-serif",S(this.a))),this.m.a.style.cssText=e,H(this.g),H(this.h),H(this.j),H(this.m)}x.prototype.c=function(e){for(var t=[],a=0;a<arguments.length;a++)t.push(arguments[a].replace(/[\W_]+/g,"").toLowerCase());return t.join(this.a)},R.prototype.start=function(){var e=this.c.o.document,t=this,a=r(),i=new Promise(function(i,l){!function n(){r()-a>=t.f?l():e.fonts.load(function(e){return C(e)+" "+e.f+"00 300px "+k(e.c)}(t.a),t.h).then(function(e){1<=e.length?i():setTimeout(n,25)},function(){l()})}()}),l=null,n=new Promise(function(e,a){l=setTimeout(a,t.f)});Promise.race([n,i]).then(function(){l&&(clearTimeout(l),l=null),t.g(t.a)},function(){t.j(t.a)})};var z={D:"serif",C:"sans-serif"},O=null;function F(){if(null===O){var e=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent);O=!!e&&(536>parseInt(e[1],10)||536===parseInt(e[1],10)&&11>=parseInt(e[2],10))}return O}function I(e,t,a){for(var i in z)if(z.hasOwnProperty(i)&&t===e.f[z[i]]&&a===e.f[z[i]])return!0;return!1}function N(e){var t,a=e.g.a.offsetWidth,i=e.h.a.offsetWidth;(t=a===e.f.serif&&i===e.f["sans-serif"])||(t=F()&&I(e,a,i)),t?r()-e.A>=e.w?F()&&I(e,a,i)&&(null===e.u||e.u.hasOwnProperty(e.a.c))?V(e,e.v):V(e,e.B):function(e){setTimeout(o(function(){N(this)},e),50)}(e):V(e,e.v)}function V(e,t){setTimeout(o(function(){d(this.g.a),d(this.h.a),d(this.j.a),d(this.m.a),t(this.a)},e),0)}function G(e,t,a){this.c=e,this.a=t,this.f=0,this.m=this.j=!1,this.s=a}P.prototype.start=function(){this.f.serif=this.j.a.offsetWidth,this.f["sans-serif"]=this.m.a.offsetWidth,this.A=r(),N(this)};var W=null;function U(e){0==--e.f&&e.j&&(e.m?((e=e.a).g&&p(e.f,[e.a.c("wf","active")],[e.a.c("wf","loading"),e.a.c("wf","inactive")]),D(e,"active")):E(e.a))}function j(e){this.j=e,this.a=new L,this.h=0,this.f=this.g=!0}function q(e,t,a,i,l){var n=0==--e.h;(e.f||e.g)&&setTimeout(function(){var e=l||null,r=i||{};if(0===a.length&&n)E(t.a);else{t.f+=a.length,n&&(t.j=n);var s,u=[];for(s=0;s<a.length;s++){var c=a[s],g=r[c.c],d=t.a,h=c;if(d.g&&p(d.f,[d.a.c("wf",h.c,S(h).toString(),"loading")]),D(d,"fontloading",h),d=null,null===W)if(window.FontFace){h=/Gecko.*Firefox\/(\d+)/.exec(window.navigator.userAgent);var m=/OS X.*Version\/10\..*Safari/.exec(window.navigator.userAgent)&&/Apple/.exec(window.navigator.vendor);W=h?42<parseInt(h[1],10):!m}else W=!1;d=W?new R(o(t.g,t),o(t.h,t),t.c,c,t.s,g):new P(o(t.g,t),o(t.h,t),t.c,c,t.s,e,g),u.push(d)}for(s=0;s<u.length;s++)u[s].start()}},0)}function $(e,t){this.c=e,this.a=t}function Z(e,t){this.c=e,this.a=t}function K(e,t){this.c=e||Y,this.a=[],this.f=[],this.g=t||""}G.prototype.g=function(e){var t=this.a;t.g&&p(t.f,[t.a.c("wf",e.c,S(e).toString(),"active")],[t.a.c("wf",e.c,S(e).toString(),"loading"),t.a.c("wf",e.c,S(e).toString(),"inactive")]),D(t,"fontactive",e),this.m=!0,U(this)},G.prototype.h=function(e){var t=this.a;if(t.g){var a=h(t.f,t.a.c("wf",e.c,S(e).toString(),"active")),i=[],l=[t.a.c("wf",e.c,S(e).toString(),"loading")];a||i.push(t.a.c("wf",e.c,S(e).toString(),"inactive")),p(t.f,i,l)}D(t,"fontinactive",e),U(this)},j.prototype.load=function(e){this.c=new s(this.j,e.context||this.j),this.g=!1!==e.events,this.f=!1!==e.classes,function(e,t,a){var i=[],l=a.timeout;!function(e){e.g&&p(e.f,[e.a.c("wf","loading")]),D(e,"loading")}(t),i=function(e,t,a){var i,l=[];for(i in t)if(t.hasOwnProperty(i)){var n=e.c[i];n&&l.push(n(t[i],a))}return l}(e.a,a,e.c);var n=new G(e.c,t,l);for(e.h=i.length,t=0,a=i.length;t<a;t++)i[t].load(function(t,a,i){q(e,n,t,a,i)})}(this,new T(this.c,e),e)},$.prototype.load=function(e){function t(){if(n["__mti_fntLst"+i]){var a,l=n["__mti_fntLst"+i](),o=[];if(l)for(var r=0;r<l.length;r++){var s=l[r].fontfamily;null!=l[r].fontStyle&&null!=l[r].fontWeight?(a=l[r].fontStyle+l[r].fontWeight,o.push(new _(s,a))):o.push(new _(s))}e(o)}else setTimeout(function(){t()},50)}var a=this,i=a.a.projectId,l=a.a.version;if(i){var n=a.c.o;b(this.c,(a.a.api||"https://fast.fonts.net/jsapi")+"/"+i+".js"+(l?"?v="+l:""),function(l){l?e([]):(n["__MonotypeConfiguration__"+i]=function(){return a.a},t())}).id="__MonotypeAPIScript__"+i}else e([])},Z.prototype.load=function(e){var t,a,i=this.a.urls||[],l=this.a.families||[],n=this.a.testStrings||{},o=new f;for(t=0,a=i.length;t<a;t++)m(this.c,i[t],v(o));var r=[];for(t=0,a=l.length;t<a;t++)if((i=l[t].split(":"))[1])for(var s=i[1].split(","),u=0;u<s.length;u+=1)r.push(new _(i[0],s[u]));else r.push(new _(i[0]));w(o,function(){e(r,n)})};var Y="https://fonts.googleapis.com/css";function J(e){this.f=e,this.a=[],this.c={}}var X={latin:"BESbswy","latin-ext":"çöüğş",cyrillic:"йяЖ",greek:"αβΣ",khmer:"កខគ",Hanuman:"កខគ"},Q={thin:"1",extralight:"2","extra-light":"2",ultralight:"2","ultra-light":"2",light:"3",regular:"4",book:"4",medium:"5","semi-bold":"6",semibold:"6","demi-bold":"6",demibold:"6",bold:"7","extra-bold":"8",extrabold:"8","ultra-bold":"8",ultrabold:"8",black:"9",heavy:"9",l:"3",r:"4",b:"7"},ee={i:"i",italic:"i",n:"n",normal:"n"},te=/^(thin|(?:(?:extra|ultra)-?)?light|regular|book|medium|(?:(?:semi|demi|extra|ultra)-?)?bold|black|heavy|l|r|b|[1-9]00)?(n|i|normal|italic)?$/;function ae(e,t){this.c=e,this.a=t}var ie={Arimo:!0,Cousine:!0,Tinos:!0};function le(e,t){this.c=e,this.a=t}function ne(e,t){this.c=e,this.f=t,this.a=[]}ae.prototype.load=function(e){var t=new f,a=this.c,i=new K(this.a.api,this.a.text),l=this.a.families;!function(e,t){for(var a=t.length,i=0;i<a;i++){var l=t[i].split(":");3==l.length&&e.f.push(l.pop());var n="";2==l.length&&""!=l[1]&&(n=":"),e.a.push(l.join(n))}}(i,l);var n=new J(l);!function(e){for(var t=e.f.length,a=0;a<t;a++){var i=e.f[a].split(":"),l=i[0].replace(/\+/g," "),n=["n4"];if(2<=i.length){var o;if(o=[],r=i[1])for(var r,s=(r=r.split(",")).length,u=0;u<s;u++){var c;if((c=r[u]).match(/^[\w-]+$/))if(null==(g=te.exec(c.toLowerCase())))c="";else{if(c=null==(c=g[2])||""==c?"n":ee[c],null==(g=g[1])||""==g)g="4";else var g=Q[g]||(isNaN(g)?"4":g.substr(0,1));c=[c,g].join("")}else c="";c&&o.push(c)}0<o.length&&(n=o),3==i.length&&(o=[],0<(i=(i=i[2])?i.split(","):o).length&&(i=X[i[0]])&&(e.c[l]=i))}for(e.c[l]||(i=X[l])&&(e.c[l]=i),i=0;i<n.length;i+=1)e.a.push(new _(l,n[i]))}}(n),m(a,function(e){if(0==e.a.length)throw Error("No fonts to load!");if(-1!=e.c.indexOf("kit="))return e.c;for(var t=e.a.length,a=[],i=0;i<t;i++)a.push(e.a[i].replace(/ /g,"+"));return t=e.c+"?family="+a.join("%7C"),0<e.f.length&&(t+="&subset="+e.f.join(",")),0<e.g.length&&(t+="&text="+encodeURIComponent(e.g)),t}(i),v(t)),w(t,function(){e(n.a,n.c,ie)})},le.prototype.load=function(e){var t=this.a.id,a=this.c.o;t?b(this.c,(this.a.api||"https://use.typekit.net")+"/"+t+".js",function(t){if(t)e([]);else if(a.Typekit&&a.Typekit.config&&a.Typekit.config.fn){t=a.Typekit.config.fn;for(var i=[],l=0;l<t.length;l+=2)for(var n=t[l],o=t[l+1],r=0;r<o.length;r++)i.push(new _(n,o[r]));try{a.Typekit.load({events:!1,classes:!1,async:!0})}catch(e){}e(i)}},2e3):e([])},ne.prototype.load=function(e){var t=this.f.id,a=this.c.o,i=this;t?(a.__webfontfontdeckmodule__||(a.__webfontfontdeckmodule__={}),a.__webfontfontdeckmodule__[t]=function(t,a){for(var l=0,n=a.fonts.length;l<n;++l){var o=a.fonts[l];i.a.push(new _(o.name,M("font-weight:"+o.weight+";font-style:"+o.style)))}e(i.a)},b(this.c,(this.f.api||"https://f.fontdeck.com/s/css/js/")+function(e){return e.o.location.hostname||e.a.location.hostname}(this.c)+"/"+t+".js",function(t){t&&e([])})):e([])};var oe=new j(window);oe.a.c.custom=function(e,t){return new Z(t,e)},oe.a.c.fontdeck=function(e,t){return new ne(t,e)},oe.a.c.monotype=function(e,t){return new $(t,e)},oe.a.c.typekit=function(e,t){return new le(t,e)},oe.a.c.google=function(e,t){return new ae(t,e)};var re={load:o(oe.load,oe)};void 0===(i=function(){return re}.call(t,a,t,e))||(e.exports=i)}()},5556(e,t,a){e.exports=a(2694)()},5621(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-presets-radio-image-wrap{display:grid;grid-column-gap:16px;grid-template-columns:repeat(2, 1fr);grid-row-gap:14px}.uagb-presets-radio-image-wrap .uag-presets-radio-input{display:none}.uagb-presets-radio-image-wrap .uag-presets-radio-input-label{position:relative;display:inline-block}.uagb-presets-radio-image-wrap svg{width:100%;height:auto;fill:#898e95;border:1px solid #dadada;color:#898e95;background-color:#f0f0f1;transition:background .08s ease,box-shadow .08s ease;border-radius:5px 5px 3px 3px}.uagb-presets-radio-image-wrap svg>path:first-child{scale:1.129 1.085;transform-origin:center bottom}.uagb-presets-radio-image-wrap .uag-presets-radio-input:checked+.uag-presets-radio-input-label svg{background-color:#007cba;border:1px solid #00608f}.uagb-presets-radio-image-wrap .uag-presets-radio-image-clickable{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%}.uagb-inspector-tab .components-panel__body .uag-presets-label{line-height:2.4}.uagb-presets-label-reset-wrap{display:flex;justify-content:space-between}.uagb-presets-main-wrap.border-none svg{border:none}",""]);const r=o},5795(e){"use strict";e.exports=window.ReactDOM},6314(e){"use strict";e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var a="",i=void 0!==t[5];return t[4]&&(a+="@supports (".concat(t[4],") {")),t[2]&&(a+="@media ".concat(t[2]," {")),i&&(a+="@layer".concat(t[5].length>0?" ".concat(t[5]):""," {")),a+=e(t),i&&(a+="}"),t[2]&&(a+="}"),t[4]&&(a+="}"),a}).join("")},t.i=function(e,a,i,l,n){"string"==typeof e&&(e=[[null,e,void 0]]);var o={};if(i)for(var r=0;r<this.length;r++){var s=this[r][0];null!=s&&(o[s]=!0)}for(var u=0;u<e.length;u++){var c=[].concat(e[u]);i&&o[c[0]]||(void 0!==n&&(void 0===c[5]||(c[1]="@layer".concat(c[5].length>0?" ".concat(c[5]):""," {").concat(c[1],"}")),c[5]=n),a&&(c[2]?(c[1]="@media ".concat(c[2]," {").concat(c[1],"}"),c[2]=a):c[2]=a),l&&(c[4]?(c[1]="@supports (".concat(c[4],") {").concat(c[1],"}"),c[4]=l):c[4]="".concat(l)),t.push(c))}},t}},6323(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-gradient-picker .components-custom-gradient-picker__gradient-bar{border-radius:5px;height:30px}.uagb-gradient-picker .components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__control-point-button{top:9px;width:12px;height:12px}.uagb-gradient-picker .components-custom-gradient-picker__gradient-bar .components-custom-gradient-picker__insert-point{top:7px}.block-editor-block-inspector .uagb-inspector-tab .uag-background-gradient .uagb-color-popover-container,.block-editor-block-inspector .uagb-inspector-tab .uag-background-gradient .uagb-multi-buttons-control,.block-editor-block-inspector .uagb-inspector-tab .uag-background-gradient .uagb-size-type-field-tabs,.block-editor-block-inspector .uagb-inspector-tab .uag-background-gradient .components-button-group,.block-editor-block-inspector .uag-background-image-overlay-gradient .uagb-color-popover-container,.block-editor-block-inspector .uag-background-image-overlay-gradient .uagb-multi-buttons-control,.block-editor-block-inspector .uag-background-image-overlay-gradient .uagb-size-type-field-tabs,.block-editor-block-inspector .uag-background-image-overlay-gradient .components-button-group{margin-bottom:24px}.block-editor-block-inspector .uagb-inspector-tab .uag-background-gradient .uagb-size-type-field-tabs,.block-editor-block-inspector .uag-background-image-overlay-gradient .uagb-size-type-field-tabs{display:block}.block-editor-block-inspector .uagb-inspector-tab .uag-background-gradient .uagb-gradient-advanced-option,.block-editor-block-inspector .uag-background-image-overlay-gradient .uagb-gradient-advanced-option{width:100%;justify-content:right;margin-bottom:5px;padding-right:0}",""]);const r=o},6359(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,'.components-panel[data-uagb-tab]{z-index:99}.components-panel[data-uagb-tab]:not([data-uagb-tab=advance]) .components-panel__body.block-editor-block-inspector__advanced,.components-panel[data-uagb-tab]:not([data-uagb-tab=advance]) .components-panel__body.editor-block-inspector__advanced.block-editor-block-inspector__advanced,.components-panel[data-uagb-tab]:not([data-uagb-tab=advance]) .block-editor-block-inspector>div>.components-panel__body{display:none}.components-panel[data-uagb-tab]:not([data-uagb-tab=advance]) .block-editor-block-inspector>div>.components-panel__body.uagb-dynamic-content-wrap{display:block;border-bottom:1px solid #e0e0e0 !important}.components-panel[data-uagb-tab] .block-editor-block-card{position:relative;z-index:1;overflow:hidden}.components-panel[data-uagb-tab] .block-editor-block-card::before{content:"";position:absolute;top:0;left:-16px;right:-16px;bottom:0;background:#fff;z-index:-1}.components-panel[data-uagb-tab] .components-panel__body.edit-post-settings-sidebar__panel-block .block-editor-block-card{overflow:unset}.components-panel[data-uagb-tab] .components-panel__body.edit-post-settings-sidebar__panel-block .block-editor-block-card::before{top:-16px}.components-panel[data-uagb-tab=advance] .block-editor-block-inspector__advanced{border-color:rgba(0,0,0,0)}[dir=rtl] .uagb-inspector-tabs{direction:rtl}[dir=rtl] .uagb-inspector-tabs>div:first-child.uagb-active::after{border-left:1px solid #d6d9dd;border-right:0}[dir=rtl] .uagb-inspector-tabs>div:last-child.uagb-active::after{border-left:0;border-right:1px solid #d6d9dd}.uagb-inspector-tabs{display:flex;position:relative;background:#fff;z-index:9;height:65px}.uagb-inspector-tabs>div{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;background:#fff;cursor:pointer}.uagb-inspector-tabs>div::after,.uagb-inspector-tabs>div::before{content:"";position:absolute;display:block;top:0;left:0;width:100%}.uagb-inspector-tabs>div::after{border-bottom:1px solid #d6d9dd;height:100%;z-index:1}.uagb-inspector-tabs>div:first-child.uagb-active::after{border-left:0;box-shadow:inset 0 -3px 0 0 #007cba;color:#007cba}.uagb-inspector-tabs>div:last-child.uagb-active::after{border-right:0;box-shadow:inset 0 -3px 0 0 #007cba;color:#007cba}.uagb-inspector-tabs>div.uagb-active::after{border-left:1px solid #d6d9dd;border-right:1px solid #d6d9dd;border-bottom:0;box-shadow:inset 0 -3px 0 0 #007cba;color:#007cba}.uagb-inspector-tabs>div.uagb-active::before{height:0;background-color:rgba(0,0,0,0);z-index:2}.uagb-inspector-tabs>div h5{margin:6px 0 0;font-size:13px;font-weight:400;line-height:1.2}.uagb-inspector-tabs>div h5,.uagb-inspector-tabs>div svg{z-index:2;fill:#585858}.uagb-inspector-tabs>div.uagb-active h5{color:#0085ba}.uagb-inspector-tabs>div.uagb-active path{fill:#0085ba}.components-panel .components-panel__body .uagb-inspector-tabs-container{position:static !important;margin-left:-16px;margin-right:-16px;border-top:0 !important;top:0 !important}.uagb-inspector-tabs-container{position:sticky;top:-3px;z-index:9;border-top:calc(.1em + 1px) solid #f2f4f5;direction:initial}.customize-widgets-layout__inspector .uagb-inspector-tabs-container{top:-12px;margin-left:-12px;margin-right:-12px}.uagb-inspector-tab .components-panel__body:first-child,.edit-post-settings-sidebar__panel-block .uagb-inspector-tab .components-panel__body:first-child{margin-top:0;border-top:none !important}',""]);const r=o},6925(e){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},6942(e,t){var a;!function(){"use strict";var i={}.hasOwnProperty;function l(){for(var e="",t=0;t<arguments.length;t++){var a=arguments[t];a&&(e=o(e,n(a)))}return e}function n(e){if("string"==typeof e||"number"==typeof e)return e;if("object"!=typeof e)return"";if(Array.isArray(e))return l.apply(null,e);if(e.toString!==Object.prototype.toString&&!e.toString.toString().includes("[native code]"))return e.toString();var t="";for(var a in e)i.call(e,a)&&e[a]&&(t=o(t,a));return t}function o(e,t){return t?e?e+" "+t:e+t:e}e.exports?(l.default=l,e.exports=l):void 0===(a=function(){return l}.apply(t,[]))||(e.exports=a)}()},7659(e){"use strict";var t={};e.exports=function(e,a){var i=function(e){if(void 0===t[e]){var a=document.querySelector(e);if(window.HTMLIFrameElement&&a instanceof window.HTMLIFrameElement)try{a=a.contentDocument.head}catch(e){a=null}t[e]=a}return t[e]}(e);if(!i)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");i.appendChild(a)}},8006(e,t,a){"use strict";var i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var i in a)Object.prototype.hasOwnProperty.call(a,i)&&(e[i]=a[i])}return e},l=function(){function e(e,t){for(var a=0;a<t.length;a++){var i=t[a];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,a,i){return a&&e(t.prototype,a),i&&e(t,i),t}}(),n=a(1609),o=s(n),r=s(a(5556));function s(e){return e&&e.__esModule?e:{default:e}}var u={position:"absolute",top:0,left:0,visibility:"hidden",height:0,overflow:"scroll",whiteSpace:"pre"},c=["extraWidth","injectStyles","inputClassName","inputRef","inputStyle","minWidth","onAutosize","placeholderIsMinWidth"],g=function(e,t){t.style.fontSize=e.fontSize,t.style.fontFamily=e.fontFamily,t.style.fontWeight=e.fontWeight,t.style.fontStyle=e.fontStyle,t.style.letterSpacing=e.letterSpacing,t.style.textTransform=e.textTransform},d=!("undefined"==typeof window||!window.navigator)&&/MSIE |Trident\/|Edge\//.test(window.navigator.userAgent),p=function(){return d?"_"+Math.random().toString(36).substr(2,12):void 0},h=function(e){function t(e){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,t);var a=function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return a.inputRef=function(e){a.input=e,"function"==typeof a.props.inputRef&&a.props.inputRef(e)},a.placeHolderSizerRef=function(e){a.placeHolderSizer=e},a.sizerRef=function(e){a.sizer=e},a.state={inputWidth:e.minWidth,inputId:e.id||p()},a}return function(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}(t,e),l(t,[{key:"componentDidMount",value:function(){this.mounted=!0,this.copyInputStyles(),this.updateInputWidth()}},{key:"UNSAFE_componentWillReceiveProps",value:function(e){var t=e.id;t!==this.props.id&&this.setState({inputId:t||p()})}},{key:"componentDidUpdate",value:function(e,t){t.inputWidth!==this.state.inputWidth&&"function"==typeof this.props.onAutosize&&this.props.onAutosize(this.state.inputWidth),this.updateInputWidth()}},{key:"componentWillUnmount",value:function(){this.mounted=!1}},{key:"copyInputStyles",value:function(){if(this.mounted&&window.getComputedStyle){var e=this.input&&window.getComputedStyle(this.input);e&&(g(e,this.sizer),this.placeHolderSizer&&g(e,this.placeHolderSizer))}}},{key:"updateInputWidth",value:function(){if(this.mounted&&this.sizer&&void 0!==this.sizer.scrollWidth){var e=void 0;e=this.props.placeholder&&(!this.props.value||this.props.value&&this.props.placeholderIsMinWidth)?Math.max(this.sizer.scrollWidth,this.placeHolderSizer.scrollWidth)+2:this.sizer.scrollWidth+2,(e+="number"===this.props.type&&void 0===this.props.extraWidth?16:parseInt(this.props.extraWidth)||0)<this.props.minWidth&&(e=this.props.minWidth),e!==this.state.inputWidth&&this.setState({inputWidth:e})}}},{key:"getInput",value:function(){return this.input}},{key:"focus",value:function(){this.input.focus()}},{key:"blur",value:function(){this.input.blur()}},{key:"select",value:function(){this.input.select()}},{key:"renderStyles",value:function(){var e=this.props.injectStyles;return d&&e?o.default.createElement("style",{dangerouslySetInnerHTML:{__html:"input#"+this.state.inputId+"::-ms-clear {display: none;}"}}):null}},{key:"render",value:function(){var e=[this.props.defaultValue,this.props.value,""].reduce(function(e,t){return null!=e?e:t}),t=i({},this.props.style);t.display||(t.display="inline-block");var a=i({boxSizing:"content-box",width:this.state.inputWidth+"px"},this.props.inputStyle),l=function(e,t){var a={};for(var i in e)t.indexOf(i)>=0||Object.prototype.hasOwnProperty.call(e,i)&&(a[i]=e[i]);return a}(this.props,[]);return function(e){c.forEach(function(t){return delete e[t]})}(l),l.className=this.props.inputClassName,l.id=this.state.inputId,l.style=a,o.default.createElement("div",{className:this.props.className,style:t},this.renderStyles(),o.default.createElement("input",i({},l,{ref:this.inputRef})),o.default.createElement("div",{ref:this.sizerRef,style:u},e),this.props.placeholder?o.default.createElement("div",{ref:this.placeHolderSizerRef,style:u},this.props.placeholder):null)}}]),t}(n.Component);h.propTypes={className:r.default.string,defaultValue:r.default.any,extraWidth:r.default.oneOfType([r.default.number,r.default.string]),id:r.default.string,injectStyles:r.default.bool,inputClassName:r.default.string,inputRef:r.default.func,inputStyle:r.default.object,minWidth:r.default.oneOfType([r.default.number,r.default.string]),onAutosize:r.default.func,onChange:r.default.func,placeholder:r.default.string,placeholderIsMinWidth:r.default.bool,style:r.default.object,value:r.default.any},h.defaultProps={minWidth:1,injectStyles:!0},t.A=h},8226(e){e.exports=function(){"use strict";return function(e){var t="/*|*/",a=t+"}";function i(t){if(t)try{e(t+"}")}catch(e){}}return function(l,n,o,r,s,u,c,g,d,p){switch(l){case 1:if(0===d&&64===n.charCodeAt(0))return e(n+";"),"";break;case 2:if(0===g)return n+t;break;case 3:switch(g){case 102:case 112:return e(o[0]+n),"";default:return n+(0===p?t:"")}case-2:n.split(a).forEach(i)}}}}()},8514(e,t,a){"use strict";t.__esModule=!0,t.default=void 0,function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var a in e)if(Object.prototype.hasOwnProperty.call(e,a)){var i=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(e,a):{};i.get||i.set?Object.defineProperty(t,a,i):t[a]=e[a]}t.default=e}(a(5556));var i=r(a(2963)),l=r(a(788)),n=r(a(1609)),o=r(a(495));function r(e){return e&&e.__esModule?e:{default:e}}function s(){return s=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var a=arguments[t];for(var i in a)Object.prototype.hasOwnProperty.call(a,i)&&(e[i]=a[i])}return e},s.apply(this,arguments)}a(554);var u=function(e,t){return e&&t&&t.split(" ").forEach(function(t){return(0,i.default)(e,t)})},c=function(e,t){return e&&t&&t.split(" ").forEach(function(t){return(0,l.default)(e,t)})},g=function(e){var t,a;function i(){for(var t,a=arguments.length,i=new Array(a),l=0;l<a;l++)i[l]=arguments[l];return(t=e.call.apply(e,[this].concat(i))||this).onEnter=function(e,a){var i=t.getClassNames(a?"appear":"enter").className;t.removeClasses(e,"exit"),u(e,i),t.props.onEnter&&t.props.onEnter(e,a)},t.onEntering=function(e,a){var i=t.getClassNames(a?"appear":"enter").activeClassName;t.reflowAndAddClass(e,i),t.props.onEntering&&t.props.onEntering(e,a)},t.onEntered=function(e,a){var i=t.getClassNames("appear").doneClassName,l=t.getClassNames("enter").doneClassName,n=a?i+" "+l:l;t.removeClasses(e,a?"appear":"enter"),u(e,n),t.props.onEntered&&t.props.onEntered(e,a)},t.onExit=function(e){var a=t.getClassNames("exit").className;t.removeClasses(e,"appear"),t.removeClasses(e,"enter"),u(e,a),t.props.onExit&&t.props.onExit(e)},t.onExiting=function(e){var a=t.getClassNames("exit").activeClassName;t.reflowAndAddClass(e,a),t.props.onExiting&&t.props.onExiting(e)},t.onExited=function(e){var a=t.getClassNames("exit").doneClassName;t.removeClasses(e,"exit"),u(e,a),t.props.onExited&&t.props.onExited(e)},t.getClassNames=function(e){var a=t.props.classNames,i="string"==typeof a,l=i?(i&&a?a+"-":"")+e:a[e];return{className:l,activeClassName:i?l+"-active":a[e+"Active"],doneClassName:i?l+"-done":a[e+"Done"]}},t}a=e,(t=i).prototype=Object.create(a.prototype),t.prototype.constructor=t,t.__proto__=a;var l=i.prototype;return l.removeClasses=function(e,t){var a=this.getClassNames(t),i=a.className,l=a.activeClassName,n=a.doneClassName;i&&c(e,i),l&&c(e,l),n&&c(e,n)},l.reflowAndAddClass=function(e,t){t&&(e&&e.scrollTop,u(e,t))},l.render=function(){var e=s({},this.props);return delete e.classNames,n.default.createElement(o.default,s({},e,{onEnter:this.onEnter,onEntered:this.onEntered,onEntering:this.onEntering,onExit:this.onExit,onExiting:this.onExiting,onExited:this.onExited}))},i}(n.default.Component);g.defaultProps={classNames:""},g.propTypes={};var d=g;t.default=d,e.exports=t.default},8542(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".block-editor-image-size-control{margin-bottom:1em}.block-editor-image-size-control .block-editor-image-size-control__row{display:flex;justify-content:space-between;flex-direction:column}.block-editor-image-size-control .block-editor-image-size-control__row .uag-number-control .uag-number-control__inline,.block-editor-image-size-control .block-editor-image-size-control__row .uag-number-control .uag-number-control__full-width{margin-bottom:10px}",""]);const r=o},8619(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uag-control-tabs{margin:0 -16px;padding:0 16px}.uag-control-tabs.uag-control-tabs-three-tabs .components-tab-panel__tabs>.components-button{width:31.3%}.uag-control-tabs>.components-tab-panel__tabs{justify-content:space-between;margin:0 -16px 25px;padding:0 16px;border-bottom:1px solid #e6e7e9}.uag-control-tabs>.components-tab-panel__tabs>.components-button{width:47%;text-align:center;justify-content:center;border:1px solid #e6e7e9;border-radius:3px 3px 0 0;color:#50575e;background-color:#f0f0f1;max-height:30px;font-size:13px;border-bottom:0;margin-bottom:-1px}.uag-control-tabs>.components-tab-panel__tabs>.components-button.active-tab{color:#007cba;background:#fff}.uag-control-tabs>.components-tab-panel__tabs>.components-button:focus:not(:disabled){box-shadow:none}.uag-control-tabs .components-base-control{margin-bottom:25px}.uag-control-tabs .components-base-control .components-base-control,.uag-control-tabs .components-base-control .components-base-control__field{padding-top:0;margin-bottom:0}.uag-control-tabs .components-base-control:last-child{margin-bottom:0}",""]);const r=o},9194(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uag-confirm-popup-wrapper{display:flex;flex-direction:row;align-items:flex-start;padding:24px;width:612px;height:166px;background:#fff;box-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 10px 10px -5px rgba(0,0,0,.04);border-radius:2px}.uag-confirm-popup-wrapper .components-modal__content{margin:0;padding:0;display:flex;flex-direction:row;gap:20px}.uag-confirm-popup-wrapper .components-modal__content .components-modal__header{display:none}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-icon{display:flex;flex-direction:row;align-items:flex-start;padding:12px;gap:8px;width:54px;height:54px;background:#dcf2ff;border-radius:32px;flex:none;order:0;flex-grow:0}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-icon svg{stroke:#007cba}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content{box-sizing:border-box;display:flex;flex-direction:column;gap:24px}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-text{display:flex;flex-direction:column;order:1;gap:4px}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-text .uag-confirm-popup-title{width:480px;height:28px;font-style:normal;font-weight:500;font-size:20px;line-height:28px;color:#1d2327;flex:none;order:0;flex-grow:0}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-text .uag-confirm-popup-description{width:480px;height:20px;font-style:normal;font-weight:400;font-size:13px;line-height:20px;display:flex;align-items:center;color:#50575e;flex:none;order:1;flex-grow:0}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-controls{display:flex;flex-direction:row;align-items:flex-start;gap:12px;flex:none;order:2}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-controls .uag-confirm-popup-buttons{display:flex;flex-direction:row;justify-content:center;align-items:center;padding:9px 17px;box-shadow:0 1px 2px rgba(0,0,0,.05)}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-controls .uag-popup-confirmation-button{background:#007cba;color:#fff;border-radius:2px;flex:none;order:0}.uag-confirm-popup-wrapper .components-modal__content .uag-confirm-popup-content .uag-confirm-popup-controls .uag-popup-cancellation-button{background:#fff;border:1px solid #e6e7e9;border-radius:2px;flex:none;order:1}.uag-confirm-popup-overlay{background-color:rgba(0,0,0,.4392156863)}",""]);const r=o},9380(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uagb-text-control{position:relative}.uagb-text-control--open-dynamic-content{flex-direction:column;align-items:unset}.uagb-text-control .components-base-control__field{margin-bottom:0}.uagb-text-control .components-text-control__input{padding-right:30px;margin-left:0;margin-right:0;color:#50575e;border-color:#e6e7e9}.uagb-text-control .components-text-control__input:focus{border-color:#959595;box-shadow:unset}.uagb-text-control .uagb-control__header .uagb-number-control__actions .uagb-reset{height:fit-content}.uagb-text-control__controls>.components-button{position:absolute;right:0;bottom:0;padding:0 8px;border-radius:2px;height:30px}.uagb-text-control__controls>.components-button svg{width:18px;stroke:#555d66;stroke-width:1.4;fill:none}.uagb-text-control__controls-inline .components-base-control__field{display:flex;align-items:center}.uagb-text-control__controls-inline .components-base-control__field>label{flex:50%;margin-bottom:unset}.uagb-text-control__controls-inline .components-base-control__field>input{flex:50%}.uagb-text-control__controls-textarea{position:relative}.uagb-text-control__controls-textarea>.components-button{top:2px;bottom:auto}.uagb-text-control__controls-textarea textarea{color:#50575e;border-color:#e6e7e9}.uagb-text-control__controls-textarea textarea:focus{border-color:#959595;box-shadow:unset}.uagb-text-control.components-base-control>.components-base-control__help{margin-top:10px}",""]);const r=o},9790(e,t,a){"use strict";var i=r(a(8514)),l=r(a(1369)),n=r(a(2312)),o=r(a(495));function r(e){return e&&e.__esModule?e:{default:e}}e.exports={Transition:o.default,TransitionGroup:n.default,ReplaceTransition:l.default,CSSTransition:i.default}},9810(e,t,a){"use strict";a.d(t,{A:()=>r});var i=a(1601),l=a.n(i),n=a(6314),o=a.n(n)()(l());o.push([e.id,".uag-number-control .uagb-number-control__mobile-controls.uag-number-control__full-width{position:relative;color:#50575e}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__full-width .uag-control-label{margin-bottom:10px}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__full-width .components-number-control .components-input-control__input{padding:0 7px 0 12px !important}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__full-width>.components-button{position:absolute;left:75%;bottom:0%;height:30px;z-index:1}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__inline{align-items:center;display:grid;grid-template-columns:repeat(3, 1fr);color:#50575e}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__inline .uag-control-label{margin-bottom:0}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__inline .components-number-control .components-input-control__input{padding:0 7px 0 12px !important}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__inline .components-input-control__container{width:100%}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__inline .uagb-dynamic-content-wrap{width:245%;margin-top:20px}.uag-number-control .uagb-number-control__mobile-controls.uag-number-control__inline>.components-button{position:absolute;right:34%}.uag-number-control .uagb-number-control__mobile-controls>.components-button svg{width:18px;stroke:#555d66;stroke-width:1.4;fill:none;z-index:1}.uag-number-control .uagb-control__header{display:grid;grid-template-columns:100%;justify-items:end;justify-content:end}.uag-number-control .uag-responsive-label-wrap{grid-column:1/span 2}.uag-number-control .uagb-dynamic-content-wrap{margin-top:20px}.uag-number-control.uagb-text-control--open-dynamic-content .uag-number-control__inline{display:block}.uag-number-control.uagb-text-control--open-dynamic-content .uag-number-control__inline .uagb-dynamic-content-wrap{width:100%;margin-top:20px}.uag-number-control input[type=number]::-webkit-inner-spin-button,.uag-number-control input[type=number]::-webkit-outer-spin-button{opacity:1}",""]);const r=o}},a={};function i(e){var l=a[e];if(void 0!==l)return l.exports;var n=a[e]={id:e,exports:{}};return t[e].call(n.exports,n,n.exports,i),n.exports}i.m=t,e=[],i.O=(t,a,l,n)=>{if(!a){var o=1/0;for(c=0;c<e.length;c++){for(var[a,l,n]=e[c],r=!0,s=0;s<a.length;s++)(!1&n||o>=n)&&Object.keys(i.O).every(e=>i.O[e](a[s]))?a.splice(s--,1):(r=!1,n<o&&(o=n));if(r){e.splice(c--,1);var u=l();void 0!==u&&(t=u)}}return t}n=n||0;for(var c=e.length;c>0&&e[c-1][2]>n;c--)e[c]=e[c-1];e[c]=[a,l,n]},i.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return i.d(t,{a:t}),t},i.d=(e,t)=>{for(var a in t)i.o(t,a)&&!i.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},i.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),i.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;globalThis.importScripts&&(e=globalThis.location+"");var t=globalThis.document;if(!e&&t&&(t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()&&(e=t.currentScript.src),!e)){var a=t.getElementsByTagName("script");if(a.length)for(var l=a.length-1;l>-1&&(!e||!/^http(s?):/.test(e));)e=a[l--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),i.p=e})(),(()=>{var e={617:0,232:0};i.O.j=t=>0===e[t];var t=(t,a)=>{var l,n,[o,r,s]=a,u=0;if(o.some(t=>0!==e[t])){for(l in r)i.o(r,l)&&(i.m[l]=r[l]);if(s)var c=s(i)}for(t&&t(a);u<o.length;u++)n=o[u],i.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return i.O(c)},a=globalThis.webpackChunksureforms=globalThis.webpackChunksureforms||[];a.forEach(t.bind(null,0)),a.push=t.bind(null,a.push.bind(a))})();var l=i.O(void 0,[232],()=>i(3216));l=i.O(l)})(); \ No newline at end of file diff --git a/modules/quick-action-sidebar/components/blocks.js b/modules/quick-action-sidebar/components/blocks.js index d2e63c9af..5c3e389cb 100644 --- a/modules/quick-action-sidebar/components/blocks.js +++ b/modules/quick-action-sidebar/components/blocks.js @@ -26,9 +26,7 @@ const Blocks = ( { const blockEditor = select( 'core/block-editor' ); const { index } = blockEditor.getBlockInsertionPoint(); const clientId = blockEditor.getSelectedBlockClientId(); - const rootClientId = blockEditor.getBlockRootClientId( - getSelectedBlockClientId - ); + const rootClientId = blockEditor.getBlockRootClientId( clientId ); const allowedBlocks = blockEditor.getAllowedBlocks( clientId ); return { blockInsertionPoint: index, @@ -36,7 +34,7 @@ const Blocks = ( { getSelectedBlockClientId: clientId, getSelectedBlockAllowedBlocks: allowedBlocks || EMPTY_ALLOWED_BLOCKS, }; - } ); + }, [] ); const srfmBlocks = blocks.filter( ( block ) => { return defaultAllowedQuickSidebarBlocks.includes( block.name ); } ); diff --git a/src/blocks/textarea/components/default.js b/src/blocks/textarea/components/default.js index 6e41578a1..856f8ba6a 100644 --- a/src/blocks/textarea/components/default.js +++ b/src/blocks/textarea/components/default.js @@ -65,6 +65,7 @@ export const TextareaComponent = ( { attributes, blockID, setAttributes } ) => { formats={ formats } value={ defaultValue } modules={ quillModules } + readOnly={ true } /> ) } </div> @@ -74,6 +75,7 @@ export const TextareaComponent = ( { attributes, blockID, setAttributes } ) => { label={ label } placeholder={ placeholder } value={ defaultValue } + readOnly={ true } rows={ rows } cols={ cols } data-minlength={ minLength || undefined } diff --git a/src/utils/Helpers.js b/src/utils/Helpers.js index 07a8d1003..610ad49d0 100644 --- a/src/utils/Helpers.js +++ b/src/utils/Helpers.js @@ -2,6 +2,7 @@ import apiFetch from '@wordpress/api-fetch'; import { __, sprintf } from '@wordpress/i18n'; import { Toaster, ToastBar } from 'react-hot-toast'; import { store as editorStore } from '@wordpress/editor'; +import { store as blockEditorStore } from '@wordpress/block-editor'; import { select, useSelect } from '@wordpress/data'; import { addQueryArgs, cleanForSlug } from '@wordpress/url'; import clsx from 'clsx'; @@ -440,7 +441,11 @@ export const flattenBlocks = ( blocks, { excludeChildrenOf = [] } = {} ) => }, [] ); export const setFormSpecificSmartTags = ( updateBlockAttributes ) => { - const { getBlocks } = select( editorStore ); + // Read the block list from core/block-editor rather than core/editor: WP 7.1 + // deprecates the getBlocks() forwarder on core/editor (TC-004), and this call + // destructures it without optional chaining, so a removed forwarder would be a + // hard TypeError. core/block-editor returns the same list here. + const { getBlocks } = select( blockEditorStore ); let savedBlocks = getBlocks(); const blockSlugs = prepareBlockSlugs( updateBlockAttributes, savedBlocks ); From 3b3b72788200cb3c144eb0e741c5346b612f0b9f Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 08:51:37 +0530 Subject: [PATCH 53/65] =?UTF-8?q?fix:=20defaultProps=20review=20=E2=80=94?= =?UTF-8?q?=20useMemo=20defaults=20in=20text-control=20&=20fontloader=20(r?= =?UTF-8?q?ender=20identity),=20move=20DEFAULTS=20above=20(TDZ),=20onStatu?= =?UTF-8?q?s=20optional?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/number-control/index.js | 43 +++++++++++----------- src/components/presets/index.js | 10 +++--- src/components/range/Range.js | 41 +++++++++++---------- src/components/text-control/index.js | 47 +++++++++++++++---------- src/components/typography/fontloader.js | 24 +++++++++---- 5 files changed, 96 insertions(+), 69 deletions(-) diff --git a/src/components/number-control/index.js b/src/components/number-control/index.js index c9c6cf6d9..91210882e 100644 --- a/src/components/number-control/index.js +++ b/src/components/number-control/index.js @@ -22,6 +22,29 @@ import Separator from '@Components/separator'; import { applyFilters } from '@wordpress/hooks'; import SRFMHelpText from '@Components/help-text'; +const SRFM_NUMBER_CONTROL_DEFAULTS = { + label: __( 'Margin', 'sureforms' ), + className: '', + allowReset: true, + isShiftStepEnabled: true, + max: Infinity, + min: -Infinity, + resetFallbackValue: '', + placeholder: null, + unit: [ 'px', 'em' ], + displayUnit: true, + responsive: false, + showControlHeader: true, + inlineControl: true, + dynamicContentType: 'text', + enableDynamicContent: false, + // name: attribute name as a string, // a prop used when dynamic content support needs to be added to an instance of this control. + help: false, +}; + +// Reads `props.*` throughout and forwards the whole object, so the defaults-merge +// idiom is kept deliberately rather than destructuring every reference. No call +// site passes an explicit `undefined` for a defaulted key. const SRFMNumberControl = ( rawProps ) => { const props = { ...SRFM_NUMBER_CONTROL_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); @@ -260,24 +283,4 @@ const SRFMNumberControl = ( rawProps ) => { ); }; -const SRFM_NUMBER_CONTROL_DEFAULTS = { - label: __( 'Margin', 'sureforms' ), - className: '', - allowReset: true, - isShiftStepEnabled: true, - max: Infinity, - min: -Infinity, - resetFallbackValue: '', - placeholder: null, - unit: [ 'px', 'em' ], - displayUnit: true, - responsive: false, - showControlHeader: true, - inlineControl: true, - dynamicContentType: 'text', - enableDynamicContent: false, - // name: attribute name as a string, // a prop used when dynamic content support needs to be added to an instance of this control. - help: false, -}; - export default SRFMNumberControl; diff --git a/src/components/presets/index.js b/src/components/presets/index.js index a07ad7188..f5aadc14c 100644 --- a/src/components/presets/index.js +++ b/src/components/presets/index.js @@ -15,6 +15,11 @@ import { getIdFromString, getPanelIdFromRef } from '@Utils/Helpers'; import SRFMReset from '../reset'; import SRFMHelpText from '@Components/help-text'; +const SRFM_PRESETS_DEFAULTS = { + presetInputType: 'dropdown', + label: __( 'Select Preset', 'sureforms' ), +}; + const SRFMPresets = ( rawProps ) => { const props = { ...SRFM_PRESETS_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); @@ -287,9 +292,4 @@ const SRFMPresets = ( rawProps ) => { ); }; -const SRFM_PRESETS_DEFAULTS = { - presetInputType: 'dropdown', - label: __( 'Select Preset', 'sureforms' ), -}; - export default memo( SRFMPresets ); diff --git a/src/components/range/Range.js b/src/components/range/Range.js index f0f622998..25d440a1e 100644 --- a/src/components/range/Range.js +++ b/src/components/range/Range.js @@ -23,6 +23,29 @@ import SRFMHelpText from '@Components/help-text'; const isNumberControlSupported = !! NumberControl; +const RANGE_DEFAULTS = { + label: __( 'Margin', 'sureforms' ), + className: '', + allowReset: true, + withInputField: true, + isShiftStepEnabled: true, + max: Infinity, + min: -Infinity, + resetFallbackValue: '', + placeholder: null, + unit: [ 'px', 'em' ], + displayUnit: true, + responsive: false, + help: false, + marks: false, + isFormSpecific: false, +}; + +// This component reads `props.*` throughout and forwards the whole object, so +// the defaults-merge idiom is kept deliberately rather than destructuring ~30 +// references. No call site passes an explicit `undefined` for a defaulted key +// (verified across responsive-slider and range-typography), so the +// spread-vs-destructure difference for `undefined` is not reachable here. const Range = ( rawProps ) => { const props = { ...RANGE_DEFAULTS, ...rawProps }; const [ panelNameForHook, setPanelNameForHook ] = useState( null ); @@ -244,22 +267,4 @@ const Range = ( rawProps ) => { ); }; -const RANGE_DEFAULTS = { - label: __( 'Margin', 'sureforms' ), - className: '', - allowReset: true, - withInputField: true, - isShiftStepEnabled: true, - max: Infinity, - min: -Infinity, - resetFallbackValue: '', - placeholder: null, - unit: [ 'px', 'em' ], - displayUnit: true, - responsive: false, - help: false, - marks: false, - isFormSpecific: false, -}; - export default Range; diff --git a/src/components/text-control/index.js b/src/components/text-control/index.js index b9c18b23e..b4eca087a 100644 --- a/src/components/text-control/index.js +++ b/src/components/text-control/index.js @@ -2,6 +2,7 @@ import { useLayoutEffect, useEffect, + useMemo, useState, useRef, } from '@wordpress/element'; @@ -17,8 +18,34 @@ import SRFMHelpText from '@Components/help-text'; import { applyFilters } from '@wordpress/hooks'; import EditorSmartTagList from '@Components/misc/EditorSmartTagList'; +const SRFM_TEXT_CONTROL_DEFAULTS = { + label: '', + type: 'text', + className: '', + allowReset: true, + resetFallbackValue: '', + placeholder: null, + variant: 'full-width', + autoComplete: 'off', + showHeaderControls: true, + dynamicContentType: 'url', // url | text + enableDynamicContent: false, + help: false, + isFormSpecific: false, + withSmartTagDropdown: false, + disabled: false, +}; + const SRFMTextControl = ( rawProps ) => { - const props = { ...SRFM_TEXT_CONTROL_DEFAULTS, ...rawProps }; + // Memoize the defaults-merged props on rawProps identity so `props` keeps a + // stable reference across the component's own re-renders — matching how React + // reused the single defaultProps-merged object before this refactor. Without + // this, a fresh object every render makes the [ props ] effect below fire on + // self-renders and overwrite in-progress input (e.g. the Slug field). + const props = useMemo( + () => ( { ...SRFM_TEXT_CONTROL_DEFAULTS, ...rawProps } ), + [ rawProps ] + ); const [ panelNameForHook, setPanelNameForHook ] = useState( null ); const panelRef = useRef( null ); const [ inputData, setInputData ] = useState( props?.value ); @@ -226,22 +253,4 @@ const SRFMTextControl = ( rawProps ) => { ); }; -const SRFM_TEXT_CONTROL_DEFAULTS = { - label: '', - type: 'text', - className: '', - allowReset: true, - resetFallbackValue: '', - placeholder: null, - variant: 'full-width', - autoComplete: 'off', - showHeaderControls: true, - dynamicContentType: 'url', // url | text - enableDynamicContent: false, - help: false, - isFormSpecific: false, - withSmartTagDropdown: false, - disabled: false, -}; - export default SRFMTextControl; diff --git a/src/components/typography/fontloader.js b/src/components/typography/fontloader.js index 618855d0c..1afde76b1 100644 --- a/src/components/typography/fontloader.js +++ b/src/components/typography/fontloader.js @@ -3,7 +3,7 @@ if ( googlefonts === undefined ) { } import PropTypes from 'prop-types'; import WebFont from 'webfontloader'; -import { useState, useEffect } from '@wordpress/element'; +import { useState, useEffect, useMemo } from '@wordpress/element'; const statuses = { inactive: 'inactive', active: 'active', @@ -11,8 +11,20 @@ const statuses = { }; const noop = () => {}; +const WEBFONT_LOADER_DEFAULTS = { + onStatus: noop, +}; + const WebfontLoader = ( rawProps ) => { - const props = { ...WEBFONT_LOADER_DEFAULTS, ...rawProps }; + // Memoize on rawProps identity so `props` is stable across this component's + // own re-renders. The [ props ] effect below calls loadFonts(), whose WebFont + // callbacks setValue({ status }) and re-render; a fresh props object each + // render would make that effect re-fire every time, an unbounded + // render→loadFonts→setValue loop in the same-origin iframe path. + const props = useMemo( + () => ( { ...WEBFONT_LOADER_DEFAULTS, ...rawProps } ), + [ rawProps ] + ); const [ value, setValue ] = useState( [] ); const status = undefined; @@ -97,11 +109,9 @@ const WebfontLoader = ( rawProps ) => { WebfontLoader.propTypes = { config: PropTypes.object?.isRequired, children: PropTypes.element, - onStatus: PropTypes.func?.isRequired, -}; - -const WEBFONT_LOADER_DEFAULTS = { - onStatus: noop, + // Optional: the component falls back to a noop via WEBFONT_LOADER_DEFAULTS, + // so callers may omit it without a "required but undefined" dev warning. + onStatus: PropTypes.func, }; export default WebfontLoader; From 883defa17b8214ec29179724d210d51e50d6e2a1 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 10:21:11 +0530 Subject: [PATCH 54/65] Restore widget hooks and remove the 'Remind me in two weeks' snooze (#3031) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two changes: 1. Hook registration lost in the dev merge. The merge rebuilt admin.php from dev's copy plus #3041's members, but the two constructor lines that wire the widget were only in #3041's constructor diff, so register_form_setup_widget() and enqueue_form_setup_widget_assets() were defined and never attached — the widget never rendered on the dashboard. Re-added next to the AI widget's hooks. 2. Snooze removed. The widget now shows only the fixed optional next-step CTAs; the per-user 14-day snooze that hid the whole widget is gone. Drops the button markup, its CSS and JS (including removeWidget), the SETUP_WIDGET_SNOOZE_USER_META const and its meta write, the compute_form_setup_card() snooze gate, and the 'snooze' REST enum value. Tests and docblocks updated to match. Verified: php -l, PHPCS, PHPStan level 9, PHP Insights 100/100/100, 13 unit tests (46 assertions), and a live render (3 CTAs, no snooze markup). --- admin/admin.php | 74 +++++++-------------------------- inc/rest-api.php | 6 +-- tests/unit/admin/test-admin.php | 29 ++++--------- 3 files changed, 26 insertions(+), 83 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index f5f736f83..f968082d7 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -50,15 +50,6 @@ class Admin { */ public const ASTRA_SITES_IMPORT_META = '_astra_sites_imported_post'; - /** - * User meta: unix time until which the "Finish setting up" widget is snoozed - * for this user across every form ("Remind me in two weeks"). Per-user rather - * than per-form so the reminder hides the whole widget, not just one form. - * - * @since x.x.x - */ - public const SETUP_WIDGET_SNOOZE_USER_META = 'srfm_setup_widget_snooze_until'; - /** * Inline CSS for Quill 1.x (react-quill) list markers. * @@ -112,7 +103,7 @@ class Admin { * A static property (not a function-local static) so tests can reset it via * reset_form_setup_card_cache() and exercise the populated path — a * function-local static pins the first result for the whole process. Keyed by - * user id since the payload derives from that user's caps and snooze meta. + * user id since the payload derives from that user's capabilities. * `false` means "not computed yet"; `null`/array is a computed result. * * @var array<int,array<string,mixed>|null> @@ -184,6 +175,10 @@ public function __construct() { // Enqueue the AI quick draft widget script on the dashboard screen. add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_ai_dashboard_widget_assets' ] ); + // "Finish setting up" checklist widget on the main WP dashboard (#3031). + add_action( 'wp_dashboard_setup', [ $this, 'register_form_setup_widget' ] ); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_form_setup_widget_assets' ] ); + // Save first form creation time stamp. add_action( 'admin_init', [ $this, 'save_first_form_creation_time_stamp' ] ); add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] ); @@ -424,7 +419,7 @@ public static function reset_thankyou_prompt_cache() { * Setup-checklist data for the newest starter-template form (#3031). * * Picks the most recent form the current user can edit that was created from an - * Astra Sites starter template and which the user has not snoozed. The widget + * Astra Sites starter template. The widget * lists a fixed set of optional next-steps for it — their completion is not * computed — so the payload carries only the form and the CTA targets. Memoized * for the request so the widget register/enqueue/render passes share one query. @@ -436,7 +431,7 @@ public static function get_form_setup_card() { $user_id = get_current_user_id(); // Request memo, keyed per user — the payload derives from that user's - // capabilities and snooze meta. Reset via reset_form_setup_card_cache(). + // capabilities. Reset via reset_form_setup_card_cache(). if ( array_key_exists( $user_id, self::$setup_card_cache ) ) { return self::$setup_card_cache[ $user_id ]; } @@ -450,7 +445,7 @@ public static function get_form_setup_card() { * Clear the setup-card request memo (#3031). * * Lets tests exercise the populated path, and is a safe hook for anything that - * changes which form qualifies (e.g. a form save or snooze). + * changes which form qualifies (e.g. a form save). * * @since x.x.x * @return void @@ -462,11 +457,10 @@ public static function reset_form_setup_card_cache() { /** * REST handler: record a "Finish setting up" widget interaction (#3031). * - * Tracks the clicked action as an analytics event and, for "snooze", stores a - * per-user 14-day snooze so "Remind me in two weeks" hides the whole widget - * rather than only the form currently shown. The request carries the displayed - * form id: capability is re-checked against it here — beyond the route's generic - * permission callback — so only a genuine editor of that form can act. + * Records the clicked CTA/view action as an analytics event. The request + * carries the displayed form id: capability is re-checked against it here — + * beyond the route's generic permission callback — so only a genuine editor of + * that form can act. * * @param \WP_REST_Request<array<string,mixed>> $request Request. * @@ -490,18 +484,12 @@ public function dismiss_form_setup_card( $request ) { 'edit_thankyou' => 'form_setup_widget_edit_thankyou', 'set_up_email' => 'form_setup_widget_set_up_email', 'view_form' => 'form_setup_widget_view_form', - 'snooze' => 'form_setup_widget_snooze', ]; if ( isset( $events[ $action ] ) ) { Analytics::events()->track( $events[ $action ], (string) $form_id ); } - // "Remind me in two weeks" hides the whole widget per-user for 14 days. - if ( 'snooze' === $action ) { - update_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, time() + ( 14 * DAY_IN_SECONDS ) ); - } - return new \WP_REST_Response( [ 'success' => true ], 200 ); } @@ -541,8 +529,8 @@ public function register_form_setup_widget() { * A heading (with a link to view the form), a subtitle, and a fixed list of * optional next-steps — each always shown with its CTA; completion is not * computed. Each CTA deep-links into the editor (edit form / Thank You message / - * email notification). The "Remind me in two weeks" snooze is wired in the - * enqueued inline script against the REST endpoint. + * email notification) and records an analytics event via the REST endpoint + * wired in the enqueued inline script. * * @since x.x.x * @return void @@ -605,8 +593,6 @@ public function render_form_setup_widget() { </li> <?php } ?> </ul> - - <button type="button" class="srfm-setup-checklist__snooze" id="srfm-setup-checklist-snooze"><?php esc_html_e( 'Remind me in two weeks', 'sureforms' ); ?></button> </div> <?php } @@ -615,7 +601,7 @@ public function render_form_setup_widget() { * Enqueue the setup-checklist widget's styles and behavior on the dashboard (#3031). * * Mirrors the AI widget convention: an inline-only handle carries the CSS and the - * behavior (dismiss / snooze / reveal-and-copy embed code), with server values — + * behavior (CTA click analytics), with server values — * the REST URL, nonce and form id — passed through wp_localize_script rather than * printed into the markup, so it stays Plugin-Check clean. * @@ -655,8 +641,6 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { /* Drop WP's blue focus ring on the widget's links; keep an accessible, on-brand keyboard outline. */ .srfm-setup-checklist a:focus { outline: none; box-shadow: none; } .srfm-setup-checklist a:focus-visible { outline: 2px solid #d54e21; outline-offset: 2px; box-shadow: none; } -.srfm-setup-checklist__snooze { display: inline-block; margin-top: 14px; border: 0; background: transparent; padding: 0; font-size: 13px; color: #646970; text-decoration: underline; cursor: pointer; } -.srfm-setup-checklist__snooze:hover { color: #1e1e1e; } CSS; wp_register_style( 'srfm-setup-checklist-widget', false, [], SRFM_VER ); @@ -694,15 +678,6 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { } ).catch( function () {} ); }; - const removeWidget = function () { - // Remove the whole postbox; removing only the inner node would leave an - // empty box with its title still showing. - const box = document.getElementById( 'srfm_form_setup_checklist' ); - if ( box ) { - box.remove(); - } - }; - // Beacon the CTA / view-form clicks for analytics. keepalive on the fetch lets // the request finish even though the CTA immediately navigates away. widget.addEventListener( 'click', function ( e ) { @@ -711,20 +686,6 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { persist( target.getAttribute( 'data-srfm-event' ) ); } } ); - - const snoozeBtn = document.getElementById( 'srfm-setup-checklist-snooze' ); - if ( snoozeBtn ) { - snoozeBtn.addEventListener( 'click', function () { - // Only hide the widget once the snooze actually persisted — the - // render-time wp_rest nonce can expire on a long-open dashboard, and - // hiding on a 403 would make the widget silently reappear next load. - persist( 'snooze' ).then( function ( res ) { - if ( res && res.ok ) { - removeWidget(); - } - } ); - } ); - } }() ); JS; @@ -2901,11 +2862,6 @@ private static function compute_form_setup_card() { return null; } - // "Remind me in two weeks" — a per-user snooze that hides the whole widget. - if ( (int) get_user_meta( get_current_user_id(), self::SETUP_WIDGET_SNOOZE_USER_META, true ) > time() ) { - return null; - } - // Only forms created from an Astra Sites starter template — those carry the // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. // Prime post + meta caches (the loop reads title, permalink and edit link diff --git a/inc/rest-api.php b/inc/rest-api.php index 038c1c25e..abde3c72c 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1413,8 +1413,8 @@ private function get_endpoints() { 'callback' => [ Field_Mapping::get_instance(), 'generate_gutenberg_fields_from_questions' ], 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], ], - // Dismiss/snooze the dashboard "Finish setting up" card for a form - // (#3031). Per-form capability is re-checked in the handler. + // Record a "Finish setting up" card CTA click for a form (#3031). + // Per-form capability is re-checked in the handler. 'dismiss-form-setup-card' => [ 'methods' => 'POST', 'callback' => [ \SRFM\Admin\Admin::get_instance(), 'dismiss_form_setup_card' ], @@ -1427,7 +1427,7 @@ private function get_endpoints() { 'action' => [ 'required' => true, 'type' => 'string', - 'enum' => [ 'edit_form', 'edit_thankyou', 'set_up_email', 'view_form', 'snooze' ], + 'enum' => [ 'edit_form', 'edit_thankyou', 'set_up_email', 'view_form' ], // Core only enforces `enum` via the default arg sanitizer, which // is skipped once a sanitize_callback is set — so pair it with an // explicit validate_callback, matching this file's other routes. diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 133d29c45..f3bc79d75 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -1019,10 +1019,10 @@ public function test_reset_form_setup_card_cache() { } /** - * The setup-card REST handler snoozes only on the "snooze" action (#3031). + * The setup-card REST handler records a CTA click without error (#3031). * - * A CTA/analytics action ("edit_form") records telemetry but must not hide the - * widget; only "snooze" writes the per-user snooze meta. + * A CTA/analytics action ("edit_form") records telemetry and returns success; + * the handler no longer writes any per-user state. */ public function test_dismiss_form_setup_card() { $admin = Admin::get_instance(); @@ -1043,25 +1043,13 @@ public function test_dismiss_form_setup_card() { ); wp_set_current_user( is_wp_error( $user ) ? 0 : (int) $user ); - $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Widget form' ] ); - $meta_key = Admin::SETUP_WIDGET_SNOOZE_USER_META; + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Widget form' ] ); - $call = static function ( $action ) use ( $admin, $form_id ) { - $req = new \WP_REST_Request( 'POST', '/sureforms/v1/dismiss-form-setup-card' ); - $req->set_param( 'form_id', $form_id ); - $req->set_param( 'action', $action ); - return $admin->dismiss_form_setup_card( $req ); - }; - - // A CTA action succeeds but does NOT snooze the widget. - delete_user_meta( (int) $user, $meta_key ); - $res = $call( 'edit_form' ); + $req = new \WP_REST_Request( 'POST', '/sureforms/v1/dismiss-form-setup-card' ); + $req->set_param( 'form_id', $form_id ); + $req->set_param( 'action', 'edit_form' ); + $res = $admin->dismiss_form_setup_card( $req ); $this->assertFalse( is_wp_error( $res ), 'A valid CTA action should not error.' ); - $this->assertSame( '', (string) get_user_meta( (int) $user, $meta_key, true ), 'A CTA action must not set the snooze meta.' ); - - // The snooze action stores a future snooze timestamp. - $call( 'snooze' ); - $this->assertGreaterThan( time(), (int) get_user_meta( (int) $user, $meta_key, true ), 'Snooze must store a future timestamp.' ); wp_delete_post( $form_id, true ); wp_set_current_user( 0 ); @@ -1110,7 +1098,6 @@ public function test_render_form_setup_widget() { $this->assertStringContainsString( 'srfm-setup-checklist', $output ); $this->assertStringContainsString( 'srfm-setup-checklist__cta', $output ); - $this->assertStringContainsString( 'srfm-setup-checklist-snooze', $output ); $this->assertStringContainsString( 'Render Form', $output ); // Negative: no card → nothing rendered. From 7febd1734227c0df42b6fcc506f7d0f655d7ac7c Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 10:57:35 +0530 Subject: [PATCH 55/65] Version Bump 2.12.4 --- README.md | 18 +- admin/admin.php | 42 ++-- inc/generate-form-markup.php | 8 +- inc/post-types.php | 2 +- languages/sureforms.pot | 394 +++++++++++++++++++++-------------- package-lock.json | 4 +- package.json | 2 +- readme.txt | 18 +- sureforms.php | 6 +- 9 files changed, 287 insertions(+), 207 deletions(-) diff --git a/README.md b/README.md index 52214697c..890650ed9 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ **Contributors:** [brainstormforce](https://profiles.wordpress.org/brainstormforce/) **Tags:** forms, ai forms, contact form, form builder, payment form **Requires at least:** 6.4 -**Tested up to:** 7.0.2 +**Tested up to:** 7.0.4 **Requires PHP:** 7.4 -**Stable tag:** 2.12.3 +**Stable tag:** 2.12.4 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -426,6 +426,14 @@ Visit the [SureForms features page](https://sureforms.com/features/?utm_source=w You can report security issues through our [Bug Bounty Program](https://brainstormforce.com/bug-bounty-program/). We collaborate with Patchstack to validate, triage, and handle security reports. ## Changelog ## +### 2.12.4 - 19th August 2026 ### +* New: Added a "Finish setting up" card on the dashboard that guides a newly created form through its remaining setup steps. +* New: Added a dashboard prompt to help you personalise a new form's Thank You message. +* New: Added a Form shortcut to the admin bar "+ New" menu so you can start a form from anywhere in the admin. +* New: Added an Edit Form shortcut on embedded forms, visible only to administrators, for quicker edits from the front end. +* Fix: Email body images are now uploaded to the Media Library instead of being embedded as base64, keeping notification emails lighter. +* Fix: Replaced a deprecated defaultProps usage so the block editor no longer logs warnings. +* Fix: Resolved block editor compatibility issues on WordPress 7.1. ### 2.12.3 - 6th August 2026 ### * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) @@ -440,12 +448,6 @@ You can report security issues through our [Bug Bounty Program](https://brainsto ### 2.12.2 - 20th July 2026 ### * New: Added a Payment History widget for Elementor and Bricks. * Fix: Custom CSS now applies correctly on the single form view. -### 2.12.1 - 8th July 2026 ### -* New: Added an AI-powered quick draft flow on the dashboard to generate forms faster, with built-in usage tracking. -* Improvement: Email fields now enforce standard RFC 5321 length limits (a 64-character local part and 255-character domain) to prevent oversized submissions, with a filter to customize the limits. -* Fix: Reset form option not working for some fields. -* Fix: Resolved a Stripe one-time payment error that could cause card payments to fail with an HTTP 400 response. -* Fix: Restored bullet point visibility in the rich text admin editor so formatted lists display correctly. The full changelog is available [here](https://sureforms.com/whats-new/?utm_source=wordpress.org&utm_medium=whats_new). ## Upgrade Notice ## \ No newline at end of file diff --git a/admin/admin.php b/admin/admin.php index f968082d7..619afb932 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -46,7 +46,7 @@ class Admin { * forms only. Owned by a plugin that is NOT a SureForms dependency: on installs * without Starter Templates nothing carries this meta and the prompt never shows. * - * @since x.x.x + * @since 2.12.4 */ public const ASTRA_SITES_IMPORT_META = '_astra_sites_imported_post'; @@ -93,7 +93,7 @@ class Admin { * the value for the whole process and the feature is untestable. * * @var array<int,array<string,mixed>>|null - * @since x.x.x + * @since 2.12.4 */ private static $thankyou_prompt_cache = null; @@ -107,7 +107,7 @@ class Admin { * `false` means "not computed yet"; `null`/array is a computed result. * * @var array<int,array<string,mixed>|null> - * @since x.x.x + * @since 2.12.4 */ private static $setup_card_cache = []; @@ -308,7 +308,7 @@ public static function is_first_form_created() { * * @param int $form_id Form post ID. * - * @since x.x.x + * @since 2.12.4 * @return bool */ public static function is_default_confirmation_message( $form_id ) { @@ -349,7 +349,7 @@ public static function is_default_confirmation_message( $form_id ) { * * @param int $form_id Form post ID. * - * @since x.x.x + * @since 2.12.4 * @return bool */ public static function form_has_reply_destination( $form_id ) { @@ -378,7 +378,7 @@ public static function form_has_reply_destination( $form_id ) { * message, or no reply destination). Dismissal is enforced by the caller, * before this query runs. * - * @since x.x.x + * @since 2.12.4 * @return array<int,array<string,mixed>> One entry, or none. */ public static function get_thankyou_prompt_forms() { @@ -394,7 +394,7 @@ public static function get_thankyou_prompt_forms() { * * @param array<int,array<string,mixed>> $prompts Candidate prompt payloads. * - * @since x.x.x + * @since 2.12.4 */ $filtered = apply_filters( 'srfm_thankyou_prompt_forms', self::compute_thankyou_prompt_forms() ); self::$thankyou_prompt_cache = is_array( $filtered ) ? $filtered : []; @@ -408,7 +408,7 @@ public static function get_thankyou_prompt_forms() { * Lets tests exercise the memoized public path, and is a safe hook for anything * that changes which form qualifies (e.g. a form save). * - * @since x.x.x + * @since 2.12.4 * @return void */ public static function reset_thankyou_prompt_cache() { @@ -424,7 +424,7 @@ public static function reset_thankyou_prompt_cache() { * computed — so the payload carries only the form and the CTA targets. Memoized * for the request so the widget register/enqueue/render passes share one query. * - * @since x.x.x + * @since 2.12.4 * @return array<string,mixed>|null Card payload, or null when there is no candidate form. */ public static function get_form_setup_card() { @@ -447,7 +447,7 @@ public static function get_form_setup_card() { * Lets tests exercise the populated path, and is a safe hook for anything that * changes which form qualifies (e.g. a form save). * - * @since x.x.x + * @since 2.12.4 * @return void */ public static function reset_form_setup_card_cache() { @@ -464,7 +464,7 @@ public static function reset_form_setup_card_cache() { * * @param \WP_REST_Request<array<string,mixed>> $request Request. * - * @since x.x.x + * @since 2.12.4 * @return \WP_REST_Response|\WP_Error */ public function dismiss_form_setup_card( $request ) { @@ -500,7 +500,7 @@ public function dismiss_form_setup_card( $request ) { * so the widget never appears empty. The data is memoized in get_form_setup_card() * and reused by the enqueue and render passes. * - * @since x.x.x + * @since 2.12.4 * @return void */ public function register_form_setup_widget() { @@ -532,7 +532,7 @@ public function register_form_setup_widget() { * email notification) and records an analytics event via the REST endpoint * wired in the enqueued inline script. * - * @since x.x.x + * @since 2.12.4 * @return void */ public function render_form_setup_widget() { @@ -607,7 +607,7 @@ public function render_form_setup_widget() { * * @param string $hook_suffix Current admin page hook suffix. * - * @since x.x.x + * @since 2.12.4 * @return void */ public function enqueue_form_setup_widget_assets( $hook_suffix ) { @@ -702,7 +702,7 @@ public function enqueue_form_setup_widget_assets( $hook_suffix ) { * stable notice id so the library's built-in ✕ dismissal is one persistent * choice ("stop nudging me"), not a per-form row. * - * @since x.x.x + * @since 2.12.4 * @return void */ public function render_thankyou_prompt_notice() { @@ -715,7 +715,7 @@ public function render_thankyou_prompt_notice() { * * @param bool $show Whether to show the notice. Default true. * - * @since x.x.x + * @since 2.12.4 */ if ( ! apply_filters( 'srfm_show_thankyou_prompt', true ) ) { return; @@ -790,7 +790,7 @@ public function render_thankyou_prompt_notice() { * when a CTA or the dismiss ✕ is clicked. Uses `keepalive` so the beacon * survives the navigation the CTA links trigger. * - * @since x.x.x + * @since 2.12.4 * @return void */ public function enqueue_thankyou_notice_tracking() { @@ -865,7 +865,7 @@ public function enqueue_thankyou_notice_tracking() { * Fired via astra_notice_before_markup_{id} so it lands right before the notice * and only when the notice actually renders. * - * @since x.x.x + * @since 2.12.4 * @return void */ public function print_thankyou_notice_styles() { @@ -2854,7 +2854,7 @@ public function render_dashboard_widget() { /** * Build the setup-card payload (uncached). See get_form_setup_card(). * - * @since x.x.x + * @since 2.12.4 * @return array<string,mixed>|null Card payload, or null when there is no candidate. */ private static function compute_form_setup_card() { @@ -2922,7 +2922,7 @@ private static function compute_form_setup_card() { /** * Build the Thank You prompt payload (uncached). See get_thankyou_prompt_forms(). * - * @since x.x.x + * @since 2.12.4 * @return array<int,array<string,mixed>> One entry, or none. */ private static function compute_thankyou_prompt_forms() { @@ -3010,7 +3010,7 @@ private static function compute_thankyou_prompt_forms() { * * @param array<string,mixed> $form Prompt payload from get_thankyou_prompt_forms(). * - * @since x.x.x + * @since 2.12.4 * @return string */ private static function build_thankyou_notice_markup( $form ) { diff --git a/inc/generate-form-markup.php b/inc/generate-form-markup.php index c3ad6627c..f0f55cc5a 100644 --- a/inc/generate-form-markup.php +++ b/inc/generate-form-markup.php @@ -1351,7 +1351,7 @@ public static function get_redirect_url( $form_data = [], $submission_data = [] * @param int $form_id Form post ID. * * @return void - * @since x.x.x + * @since 2.12.4 */ public static function render_edit_form_button( $form_id ) { $form_id = absint( $form_id ); @@ -1403,7 +1403,7 @@ public static function render_edit_form_button( $form_id ) { * @param bool $show Whether to render the shortcut. Default true. * @param int $form_id Form post ID. * - * @since x.x.x + * @since 2.12.4 */ if ( ! apply_filters( 'srfm_show_edit_form_button', true, $form_id ) ) { return; @@ -1421,7 +1421,7 @@ public static function render_edit_form_button( $form_id ) { * @param string $edit_link Editor URL for the form. * @param int $form_id Form post ID. * - * @since x.x.x + * @since 2.12.4 */ $edit_link = Helper::get_string_value( apply_filters( 'srfm_edit_form_button_link', $edit_link, $form_id ) ); @@ -1457,7 +1457,7 @@ public static function render_edit_form_button( $form_id ) { * inside the box — no mobile horizontal overflow — and is RTL-correct. * * @return string - * @since x.x.x + * @since 2.12.4 */ private static function get_edit_form_button_css() { return ' diff --git a/inc/post-types.php b/inc/post-types.php index 96b131ab0..d3af48d85 100644 --- a/inc/post-types.php +++ b/inc/post-types.php @@ -113,7 +113,7 @@ public function add_edit_form_to_admin_bar_menu( $wp_admin_bar ) { * so it only shows for users who can actually create a form. * * @param WP_Admin_Bar $wp_admin_bar WP_Admin_Bar instance. - * @since x.x.x + * @since 2.12.4 * @return void */ public function add_new_form_to_admin_bar_menu( $wp_admin_bar ) { diff --git a/languages/sureforms.pot b/languages/sureforms.pot index 460060efb..efb834837 100644 --- a/languages/sureforms.pot +++ b/languages/sureforms.pot @@ -2,14 +2,14 @@ # This file is distributed under the GPLv2 or later. msgid "" msgstr "" -"Project-Id-Version: SureForms 2.12.3\n" +"Project-Id-Version: SureForms 2.12.4\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/sureforms\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-08-05T10:06:17+00:00\n" +"POT-Creation-Date: 2026-08-19T05:26:36+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: sureforms\n" @@ -17,9 +17,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -46,12 +46,65 @@ msgstr "" msgid "https://sureforms.com/" msgstr "" -#: admin/admin.php:329 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "" + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "" + +#: admin/admin.php:570 +msgid "your form" +msgstr "" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "" + +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -66,9 +119,9 @@ msgstr "" msgid "Dashboard" msgstr "" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -86,9 +139,9 @@ msgstr "" msgid "Settings" msgstr "" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -96,42 +149,42 @@ msgstr "" msgid "Upgrade" msgstr "" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "" -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "" -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "" -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "" -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -145,9 +198,9 @@ msgstr "" msgid "Learn" msgstr "" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -161,15 +214,15 @@ msgstr "" msgid "Forms" msgstr "" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -186,8 +239,8 @@ msgstr "" msgid "Entries" msgstr "" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -202,16 +255,16 @@ msgid "Payments" msgstr "" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "" -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -226,84 +279,84 @@ msgstr "" msgid "Activated" msgstr "" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "" -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "" -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "" #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "" -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "" -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "" -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -311,118 +364,136 @@ msgstr "" msgid "Invalid nonce." msgstr "" -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "" #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "" -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "" -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" msgstr "" -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "" -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 msgid "Form Name" msgstr "" -#: admin/admin.php:2344 +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "" + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "" + +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "" -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "" @@ -1349,7 +1420,7 @@ msgstr "" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "" @@ -1695,33 +1766,33 @@ msgstr "" msgid "Unable to import form." msgstr "" -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "" #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." msgstr "" #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "" #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." msgstr "" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "" @@ -1850,8 +1921,8 @@ msgstr "" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "" @@ -1952,41 +2023,41 @@ msgstr "" msgid "Too many requests. Please try again shortly." msgstr "" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "" -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" msgstr "" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" msgstr "" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "" -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "" #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "" @@ -2101,10 +2172,22 @@ msgstr "" msgid "Sorry, you are not allowed to render this form." msgstr "" -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "" +#: inc/generate-form-markup.php:1444 +#: inc/page-builders/elementor/form-widget.php:332 +#: inc/post-types.php:95 +#: inc/post-types.php:271 +#: assets/build/blocks.js:172 +msgid "Edit Form" +msgstr "" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "" + #: inc/global-settings/email-summary.php:70 msgid "Invalid email address." msgstr "" @@ -2215,7 +2298,7 @@ msgstr "" #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "" @@ -2223,7 +2306,7 @@ msgstr "" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -2256,14 +2339,14 @@ msgstr "" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "" @@ -2276,7 +2359,7 @@ msgstr "" msgid "Advanced Fields" msgstr "" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "" @@ -3066,13 +3149,6 @@ msgstr "" msgid "Hide" msgstr "" -#: inc/page-builders/elementor/form-widget.php:332 -#: inc/post-types.php:95 -#: inc/post-types.php:232 -#: assets/build/blocks.js:172 -msgid "Edit Form" -msgstr "" - #: inc/page-builders/elementor/form-widget.php:335 #: assets/build/formEditor.js:172 #: assets/build/forms.js:172 @@ -3333,7 +3409,7 @@ msgstr "" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "" @@ -3365,7 +3441,7 @@ msgstr "" #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "" @@ -3478,7 +3554,7 @@ msgstr "" #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "" @@ -3512,7 +3588,7 @@ msgstr "" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -3557,7 +3633,7 @@ msgstr "" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -3567,7 +3643,7 @@ msgstr "" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "" @@ -3576,24 +3652,24 @@ msgstr "" msgid "Failed to verify subscription." msgstr "" -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "" -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "" -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -3601,18 +3677,18 @@ msgstr "" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "" -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "" @@ -4936,75 +5012,75 @@ msgstr "" msgid "Edit this form" msgstr "" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "" -#: inc/post-types.php:226 +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "" -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "" -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "" -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "" -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "" @@ -5086,7 +5162,7 @@ msgstr "" msgid "Failed to %s this form. Please try again." msgstr "" -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "" diff --git a/package-lock.json b/package-lock.json index 261dce2cb..8df6b1197 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sureforms", - "version": "2.12.3", + "version": "2.12.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sureforms", - "version": "2.12.3", + "version": "2.12.4", "license": "GPL", "dependencies": { "@bsf/force-ui": "git+https://github.com/brainstormforce/bsf-admin-ui#v1.7.7", diff --git a/package.json b/package.json index f126f825e..6ec8dc47f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sureforms", - "version": "2.12.3", + "version": "2.12.4", "description": "A simple yet powerful way to add forms to your website.", "main": "index.js", "scripts": { diff --git a/readme.txt b/readme.txt index 2c493bedd..50e9c5604 100644 --- a/readme.txt +++ b/readme.txt @@ -2,9 +2,9 @@ Contributors: brainstormforce Tags: forms, ai forms, contact form, form builder, payment form Requires at least: 6.4 -Tested up to: 7.0.2 +Tested up to: 7.0.4 Requires PHP: 7.4 -Stable tag: 2.12.3 +Stable tag: 2.12.4 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -426,6 +426,14 @@ Visit the [SureForms features page](https://sureforms.com/features/?utm_source=w You can report security issues through our [Bug Bounty Program](https://brainstormforce.com/bug-bounty-program/). We collaborate with Patchstack to validate, triage, and handle security reports. == Changelog == += 2.12.4 - 19th August 2026 = +* New: Added a "Finish setting up" card on the dashboard that guides a newly created form through its remaining setup steps. +* New: Added a dashboard prompt to help you personalise a new form's Thank You message. +* New: Added a Form shortcut to the admin bar "+ New" menu so you can start a form from anywhere in the admin. +* New: Added an Edit Form shortcut on embedded forms, visible only to administrators, for quicker edits from the front end. +* Fix: Email body images are now uploaded to the Media Library instead of being embedded as base64, keeping notification emails lighter. +* Fix: Replaced a deprecated defaultProps usage so the block editor no longer logs warnings. +* Fix: Resolved block editor compatibility issues on WordPress 7.1. = 2.12.3 - 6th August 2026 = * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) @@ -440,12 +448,6 @@ You can report security issues through our [Bug Bounty Program](https://brainsto = 2.12.2 - 20th July 2026 = * New: Added a Payment History widget for Elementor and Bricks. * Fix: Custom CSS now applies correctly on the single form view. -= 2.12.1 - 8th July 2026 = -* New: Added an AI-powered quick draft flow on the dashboard to generate forms faster, with built-in usage tracking. -* Improvement: Email fields now enforce standard RFC 5321 length limits (a 64-character local part and 255-character domain) to prevent oversized submissions, with a filter to customize the limits. -* Fix: Reset form option not working for some fields. -* Fix: Resolved a Stripe one-time payment error that could cause card payments to fail with an HTTP 400 response. -* Fix: Restored bullet point visibility in the rich text admin editor so formatted lists display correctly. The full changelog is available [here](https://sureforms.com/whats-new/?utm_source=wordpress.org&utm_medium=whats_new). == Upgrade Notice == \ No newline at end of file diff --git a/sureforms.php b/sureforms.php index 50eb202f2..d52728b8b 100644 --- a/sureforms.php +++ b/sureforms.php @@ -7,7 +7,7 @@ * Requires PHP: 7.4 * Author: SureForms * Author URI: https://sureforms.com/ - * Version: 2.12.3 + * Version: 2.12.4 * License: GPLv2 or later * Text Domain: sureforms * @@ -25,7 +25,7 @@ define( 'SRFM_BASENAME', plugin_basename( SRFM_FILE ) ); define( 'SRFM_DIR', plugin_dir_path( SRFM_FILE ) ); define( 'SRFM_URL', plugins_url( '/', SRFM_FILE ) ); -define( 'SRFM_VER', '2.12.3' ); +define( 'SRFM_VER', '2.12.4' ); define( 'SRFM_SLUG', 'srfm' ); // ------ ADDITIONAL CONSTANTS ------- // define( 'SRFM_FORMS_POST_TYPE', 'sureforms_form' ); @@ -35,7 +35,7 @@ define( 'SRFM_AI_MIDDLEWARE', 'https://credits.startertemplates.com/sureforms/' ); define( 'SRFM_MIDDLEWARE_BASE_URL', 'https://api.sureforms.com/' ); define( 'SRFM_BILLING_PORTAL', 'https://billing.sureforms.com/' ); -define( 'SRFM_PRO_RECOMMENDED_VER', '2.12.3' ); +define( 'SRFM_PRO_RECOMMENDED_VER', '2.12.4' ); define( 'SRFM_SURETRIGGERS_INTEGRATION_BASE_URL', 'https://app.ottokit.com/' ); From a720e8c59230d98c6e32d87b9857ac2245bc1044 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 11:14:58 +0530 Subject: [PATCH 56/65] Update 2.12.4 changelog entry --- README.md | 14 +++++++------- readme.txt | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 890650ed9..c68022cfd 100644 --- a/README.md +++ b/README.md @@ -427,13 +427,13 @@ You can report security issues through our [Bug Bounty Program](https://brainsto ## Changelog ## ### 2.12.4 - 19th August 2026 ### -* New: Added a "Finish setting up" card on the dashboard that guides a newly created form through its remaining setup steps. -* New: Added a dashboard prompt to help you personalise a new form's Thank You message. -* New: Added a Form shortcut to the admin bar "+ New" menu so you can start a form from anywhere in the admin. -* New: Added an Edit Form shortcut on embedded forms, visible only to administrators, for quicker edits from the front end. -* Fix: Email body images are now uploaded to the Media Library instead of being embedded as base64, keeping notification emails lighter. -* Fix: Replaced a deprecated defaultProps usage so the block editor no longer logs warnings. -* Fix: Resolved block editor compatibility issues on WordPress 7.1. +* New: Added a "Finish setting up" card on the dashboard that guides new forms to completion. +* New: Added a "Form" option to the WordPress admin bar's "+ New" menu so you can start a new form from anywhere in wp-admin. +* New: Added a dashboard prompt that helps you personalise a new form's Thank You message. +* New: Added an admin-only "Edit Form" shortcut on embedded forms to jump straight from the page to the form editor. +* Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. +* Fix: Compatibility with the WordPress 7.1 iframed block editor. +* Fix: Resolved React deprecation warnings on WordPress 7.1. ### 2.12.3 - 6th August 2026 ### * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) diff --git a/readme.txt b/readme.txt index 50e9c5604..74c01a5c6 100644 --- a/readme.txt +++ b/readme.txt @@ -427,13 +427,13 @@ You can report security issues through our [Bug Bounty Program](https://brainsto == Changelog == = 2.12.4 - 19th August 2026 = -* New: Added a "Finish setting up" card on the dashboard that guides a newly created form through its remaining setup steps. -* New: Added a dashboard prompt to help you personalise a new form's Thank You message. -* New: Added a Form shortcut to the admin bar "+ New" menu so you can start a form from anywhere in the admin. -* New: Added an Edit Form shortcut on embedded forms, visible only to administrators, for quicker edits from the front end. -* Fix: Email body images are now uploaded to the Media Library instead of being embedded as base64, keeping notification emails lighter. -* Fix: Replaced a deprecated defaultProps usage so the block editor no longer logs warnings. -* Fix: Resolved block editor compatibility issues on WordPress 7.1. +* New: Added a "Finish setting up" card on the dashboard that guides new forms to completion. +* New: Added a "Form" option to the WordPress admin bar's "+ New" menu so you can start a new form from anywhere in wp-admin. +* New: Added a dashboard prompt that helps you personalise a new form's Thank You message. +* New: Added an admin-only "Edit Form" shortcut on embedded forms to jump straight from the page to the form editor. +* Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. +* Fix: Compatibility with the WordPress 7.1 iframed block editor. +* Fix: Resolved React deprecation warnings on WordPress 7.1. = 2.12.3 - 6th August 2026 = * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) From c841491055b1383ff33fdae5be3e2871ba51a5bb Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 11:21:08 +0530 Subject: [PATCH 57/65] updated readme --- README.md | 5 ++--- readme.txt | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c68022cfd..ea6ba2726 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Contributors:** [brainstormforce](https://profiles.wordpress.org/brainstormforce/) **Tags:** forms, ai forms, contact form, form builder, payment form **Requires at least:** 6.4 -**Tested up to:** 7.0.4 +**Tested up to:** 7.1 **Requires PHP:** 7.4 **Stable tag:** 2.12.4 **License:** GPLv2 or later @@ -432,8 +432,7 @@ You can report security issues through our [Bug Bounty Program](https://brainsto * New: Added a dashboard prompt that helps you personalise a new form's Thank You message. * New: Added an admin-only "Edit Form" shortcut on embedded forms to jump straight from the page to the form editor. * Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. -* Fix: Compatibility with the WordPress 7.1 iframed block editor. -* Fix: Resolved React deprecation warnings on WordPress 7.1. +* Fix: Compatibility with the WordPress 7.1. ### 2.12.3 - 6th August 2026 ### * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) diff --git a/readme.txt b/readme.txt index 74c01a5c6..9ec178851 100644 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: brainstormforce Tags: forms, ai forms, contact form, form builder, payment form Requires at least: 6.4 -Tested up to: 7.0.4 +Tested up to: 7.1 Requires PHP: 7.4 Stable tag: 2.12.4 License: GPLv2 or later @@ -432,8 +432,7 @@ You can report security issues through our [Bug Bounty Program](https://brainsto * New: Added a dashboard prompt that helps you personalise a new form's Thank You message. * New: Added an admin-only "Edit Form" shortcut on embedded forms to jump straight from the page to the form editor. * Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. -* Fix: Compatibility with the WordPress 7.1 iframed block editor. -* Fix: Resolved React deprecation warnings on WordPress 7.1. +* Fix: Compatibility with the WordPress 7.1. = 2.12.3 - 6th August 2026 = * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) From 80d7fd49651ef1de625830e872fd549f60ad8ec5 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 11:25:17 +0530 Subject: [PATCH 58/65] updated readme --- README.md | 4 ---- readme.txt | 4 ---- 2 files changed, 8 deletions(-) diff --git a/README.md b/README.md index ea6ba2726..ac2472e3f 100644 --- a/README.md +++ b/README.md @@ -427,10 +427,6 @@ You can report security issues through our [Bug Bounty Program](https://brainsto ## Changelog ## ### 2.12.4 - 19th August 2026 ### -* New: Added a "Finish setting up" card on the dashboard that guides new forms to completion. -* New: Added a "Form" option to the WordPress admin bar's "+ New" menu so you can start a new form from anywhere in wp-admin. -* New: Added a dashboard prompt that helps you personalise a new form's Thank You message. -* New: Added an admin-only "Edit Form" shortcut on embedded forms to jump straight from the page to the form editor. * Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. * Fix: Compatibility with the WordPress 7.1. ### 2.12.3 - 6th August 2026 ### diff --git a/readme.txt b/readme.txt index 9ec178851..a182ab923 100644 --- a/readme.txt +++ b/readme.txt @@ -427,10 +427,6 @@ You can report security issues through our [Bug Bounty Program](https://brainsto == Changelog == = 2.12.4 - 19th August 2026 = -* New: Added a "Finish setting up" card on the dashboard that guides new forms to completion. -* New: Added a "Form" option to the WordPress admin bar's "+ New" menu so you can start a new form from anywhere in wp-admin. -* New: Added a dashboard prompt that helps you personalise a new form's Thank You message. -* New: Added an admin-only "Edit Form" shortcut on embedded forms to jump straight from the page to the form editor. * Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. * Fix: Compatibility with the WordPress 7.1. = 2.12.3 - 6th August 2026 = From 14933578506ec9fa30cea4d220c6a8cdac874e2b Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 11:26:21 +0530 Subject: [PATCH 59/65] updated chage log --- README.md | 2 +- readme.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac2472e3f..c961f08c8 100644 --- a/README.md +++ b/README.md @@ -428,7 +428,7 @@ You can report security issues through our [Bug Bounty Program](https://brainsto ## Changelog ## ### 2.12.4 - 19th August 2026 ### * Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. -* Fix: Compatibility with the WordPress 7.1. +* Fix: Compatibility with WordPress 7.1. ### 2.12.3 - 6th August 2026 ### * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) diff --git a/readme.txt b/readme.txt index a182ab923..ce8fe7c3c 100644 --- a/readme.txt +++ b/readme.txt @@ -428,7 +428,7 @@ You can report security issues through our [Bug Bounty Program](https://brainsto == Changelog == = 2.12.4 - 19th August 2026 = * Improvement: Email notification images are now saved to the Media Library instead of being embedded as base64, improving email deliverability and reducing message size. -* Fix: Compatibility with the WordPress 7.1. +* Fix: Compatibility with WordPress 7.1. = 2.12.3 - 6th August 2026 = * New: Added an "Entries" shortcut in the Instant Form admin bar to open a form's entries in one click. * Improvement: Enhanced WPML compatibility. [https://wpml.org/plugin/sureforms/](https://wpml.org/plugin/sureforms/) From 509b5c9123a5e0eaace5beb0c5df0562b7b1cd8d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 19 Aug 2026 06:21:05 +0000 Subject: [PATCH 60/65] chore: update i18n translations Auto-generated by /i18n command on PR #3050 --- languages/sureforms-de_DE.mo | Bin 324802 -> 326290 bytes languages/sureforms-de_DE.po | 378 +++++++++++++++++++++-------------- languages/sureforms-es_ES.mo | Bin 326622 -> 328095 bytes languages/sureforms-es_ES.po | 378 +++++++++++++++++++++-------------- languages/sureforms-fr_FR.mo | Bin 330912 -> 332462 bytes languages/sureforms-fr_FR.po | 378 +++++++++++++++++++++-------------- languages/sureforms-it_IT.mo | Bin 320140 -> 321625 bytes languages/sureforms-it_IT.po | 378 +++++++++++++++++++++-------------- languages/sureforms-nl_NL.mo | Bin 313376 -> 314816 bytes languages/sureforms-nl_NL.po | 378 +++++++++++++++++++++-------------- languages/sureforms-pl_PL.mo | Bin 321345 -> 322839 bytes languages/sureforms-pl_PL.po | 378 +++++++++++++++++++++-------------- languages/sureforms-pt_PT.mo | Bin 323606 -> 325083 bytes languages/sureforms-pt_PT.po | 378 +++++++++++++++++++++-------------- 14 files changed, 1589 insertions(+), 1057 deletions(-) diff --git a/languages/sureforms-de_DE.mo b/languages/sureforms-de_DE.mo index 0bc827de49da3e2d48b363cc78b6322b06006bb1..0bad4a95acf16429b69082d44b85e96d5634a397 100644 GIT binary patch delta 72337 zcmX`!dAyBP+raUC&M8tNk|E?E<1r7J=gc#anGzK;luX4oG$0kCBvXS-Aw$wcB`KjK zNkxT6X+)If_xIatectDv@4eQ2-)mj#TEpJwpy%yVSI#|uW%6j=i{>ZzU)4N`L=k*$ zhNVQJ!j)<NZ+5OKQtpa1F&ECj`nUiu!-MD>-(Uwkj#p!~d}*n6+haA#Lof#}M(!sQ zE5b$MZ7j}>BiIK2LmO&yRa)Y5d=iV|3M_^@@oxMdHpJff(-Kv2A=bb>Xh&%U(h^tV zWtbC-VLPmV`RG3}o(o6#2-?Bpcm;08Yj7tPz!PYO{zd~TR4^?;(h_CRk=BXj8}M4n zgRu@i6w5o&j=x9yt5qm1aVh;L8gY?{ZP3&XMN>Kfjr;-3iwn`f)}jGyL!aA&2KX5| zfYWGTxvmZw%|r*%6feP>(C3C=vMv|XxhRD@us@!{w%EFGTH<D$kA3k1IyK#kg!-q^ z)L&FIG~5guQErD<;VjIJ&!7X_7<~)Pz(+;Xl8J0wd`88k_!Z{E@6i|kLr0wZnlQpl zwBg#Z+yQ-VFjm4b*c6weBmFMcpF!KtES8q2f?4Q*`V>os2VbSa2X>$--xtfrqCcSx zUWnzi%(TSClyjo1J})l8d{_)Op@AGg=RAM$v_vx;hy!p1X5b~s5@D6*L`RYzTVrW- z&PQTFoQC;v5jyvq&^dk!pTz@M8ON3kt9%7+ro0(lgtuRtmT;<{MF)5kZ9jRI3p>8J zR2bn^=#*T8K3EE!t2*(16LgB&pi|Kwd*I!eiTluP_Y1l!{y+oHS2|b%ZNCbVfn=f< z7mlzV`r-|-+z(ydW24j1KpsW+@e}BxdJdhMP3T&A9bMgf(LjGd14xt!?dL+LrXZGa z|M%u%EEUtx5&ea3r#xlDwke0EwiO!CxLAK5cB1?&n&NZl>aSETEpa;z$LjbQy6AG2 z4+mNUwEbClEBz;)<Kj9W$O=blGjybr(UDG%&PPY`Of0{McKik!*zf3^W>g3n&5vCv zS4J~54V~&)Xl52+(nYj^3sbiPeee@B6GzY&enmUTsF;>$g}KqAx(7O!6VQOCpaIW7 z1AQFbRnMXCuSci&HT1om71{rGxQ7Y@I2a!|89j|Q_$Ri<?3F@>x}l3}E;==9(d~Ey zT@%N#8lJ@#SgLYbVmuDRl6Vr$z@=4^VZ_C%gw<Xa%W|VWnt?&+wz~%na4x#PpG8No z16}>QW4UD2Fyiv)do{5TwnINV2BYsyi_T1PVQS`}yI?Vv#x3Z`kD#mhdo+Mcs)c=D z2pwS-W@10Ah)FDmYq1O-LQls3Fts?VrzK`k9*&li7r5}#s&<W#(!SV%@;EfoUFbQm z4;{&|SpFLg{EC_(up;OhsEE#SO>{~cp=+Rdv=jPXZ)EC|iCbgE$mqS8TJ>l{^U*n7 zigvILFTyQoV6UOieHiZ_Mi=cjXvWT<fuvs-p1TB{+Prv~`@bv~K2QU%$GT`oNt}%j z;vg(oD=o1WCt+=@P&+NL4hP{P%vUEZF&Z~u7c5;jY`^i?jq+Z+0ZY~kyJH-dqyNMM zT)607MCbZ2dT{)XnV3~Stp0XrDi@*|SsvXS-GPq$V|0Ya&?&oso(p*!g!)qG`}Hts zgKfC*#ct@n9fZ!&UFa%KqKor!G^Oif{hR0%974~LAJC5eL7%&#Vd$th+I|(Z{l@6F z@6eF_?_A$Vh29b!g^pkny3gmK0jx(Gcn|IP(|G^;SiZPXs4s-JS233BqV07+1HA>! z%$P>W(BNz;9Ptvgqt)mLcAy=85<P}Ca2gFDy>S>}ezd_-=>0}$W;<gg?1PT@A++6j zn2yVnT$JEqCAtkiKv(l=bd~>!HuPWg(k5YXUWIm46dh^hSgwz$kz!TqZ$aC69G%Li z@H*UxekV+x;-V!NmoyD0TPMt<JQ8c*9IT1&Vm<sjTDw^|dPk!t+jCe8-$L8_17~29 z>(dhR@B=i%1Dc0`hau-nGBKVDx8Gz;!w1l>M$^$u%!=j5(UB}fr(|g?uSHY3F}efI z*e9|46}tFNqf?M*5#G;{lKoeJ3j-*HK9GfWTmwyQ!+5`KtnZ8l*c%;DfAqW<ioSmr zIyLvk`bRJ|1!&+;q1$g2UgG}W%7rhyg$8l}jrcG+l2d2{=g<cJKm*I(GMEp2zBoF^ zRnhlap@DWq2XrIa@lELaBQa^@6XT8h(T?WD@{?#oE76WOVJc8;P5A)!!=kN1gZHBC z%|J6T2YqiL8sJKFs<xtQ<^5Lde>+HP9U{yb&5t&eiAGu$4Xh^meBEgCXeadf-e`vd z(GRat(Q(ma^Z_)}54TQ+h99HC1{R>HS{7Z6cDy<IN^~2V${n%%ar991%jh>~z$c?; z&;b8N&yP!!ZNdnzK|9VuQ&bauu|>2qn$kX49tYt<oQ>}DthV9(zUatrMc*He9!%rW z#rhZ;z*2Ndl54rJ<2TTe?!vOTCzj8nBmEPdiX81i2l>(ZqUie-qSv9%HAWX-d$i-u z=m7enfej8O6Qj5=qI;t=F*OzF94$jf^gP<(S~PX9qYZzAQ}9dlxqj`#{Xv)-c`QGM zKEDDDa1-Y6^Z!jQT-CeLqxefKga4s{mFW-ysfk8j4{e|YI#pfKk==p@d<PoHUC{|> zCZ?d7x*yH-qgdSiKaUGXv<02p-Dn`^(X+f@$MD^*5_)F$!6tYQR>n85IsSwbv3jR) zRBu4PPyB=icv<JPL}AQ_wp#_0R<wu}H=`pOhmL$k^a*st%h5%%5l!XW@%}z^YQ99< z`vL7RdzaAO73j!|qX$$LdcSFx`2D{v6{hS4G=;s<j&4FzHwsPt-RO&xF%=;C-V<ox zOVGg9M_)tV+l6NIWAroTJf`FCUD*Fd_Gf(XqOM`2xzROIB$g{-YVOevTA+b+K}X&j z&Cn1uu(7fJ{#c$DeJ0kwhz7nr$%QYz8y`4;cJvLJfgjPe@i+Ry6*q(c3ZV5R(Licp zacqpfcXRYkwEd~*51o&qNAC)(fXT18FatTeg$MITOQL~PK|832*W>lr7-z)$yW{<X z=vTF)=np1;pxd}Y_wcQ^20E29&<s9|^qWjP$%P|(7VT(tbQ2oD>u5u}V)?`9=V(L! zL*F}tw(}>NfwUXLfbyWL{Tg(jHP9()n3Db1jte8}6(8sqy$x;fPV|NG(Ff7M=0}&I z&#gfZoQ-H;d(g%F8T$NDG_X_X+WG@8bN^q~BfL-movV`QTvb6|Y!&Of;;WPgpaB)` z8CHEc^trm|2%DqrbVLK`6Yt*^@81>gPsF4V&Wsha(S{eJDP4oE?#<};`W?|v(Gj0Q z-#?9Z_#4_`Mz0W1ZnXaDST2L!uNKP<d&Tent>c5;(EtX<2S%YC+>5?A6%FW-SYC_< zx(e-RV{|(j;2w0B96;ay7E9u<vA#fW_J1WRvU-PKCig;L_y}FaCvY$p=#!Qhj+4;O zhM&+5uId{`S_CbZiB>}AxMs8^n!%pv8W@HKd~cEqJDd?+jQJ>UKpS`$UA>>7bNn+p zl0VP}FYXsIP!KH_NAK5&Hby&Y7ws7x98KQEg)dBw&O#$xfF7wU(FR_L_uoYq*~hW` zWxW3#`l)t4mjA>LDQE8=w(lXdpRdp<`~jKTWa3XQj65+QbaW-U1~Sq5N@#|fpc&|f zRdE3NVKWy!c-EnTy^jvy0NT-Uw4JlDeDO_TP36Npe*Rw_D=I{*rEc&WkyvhnW}*|? z;7w>CBV+lVSe}V?JU^C~qk+E|eFqKjGqjy!n9u!xh6@|ac5|5fJlKJ9X)K3#V-_w& zpZfq^Y@bGtps7EBrubC!JUVr014GBT(Dw_XYpW!tzW>*Z4>UlxTT3jB?Qso`##=G- zmbAoBoR06{IUInm3<@7AR}T&ybV1wciyqwr(M3HpmM6#Z^ug?ZBVJ5}k*-2VwgsKr zH_!|mMjOhwHKgt`^!cmNl$Sx*Of9s%=IFW5Io|IT?+-y!KMsBW!CRA|;dxXz$BWRT zcP*B}o#>qXfX?N4wBa1L1@oc}7Dmth^5|l_9{oMSjcBSzqU}t@+Bgf%$j&4eExGs{ zZJ@;M;d8t`HlW-O9r+@(<LA&hT#E+06&?Bev3v+U;l4vV$T=hgP#paRR2_Z3JK9e2 z7B1{y1e(gRSRNllQ@Ih%$TsYTpQ7L4Dhy3a^ucE62$!MHZNxIT8x7zrw#Dqj(h@IY zS9}&PyCe1GHJMn?g{k@qjqC#2V7B2QWd+dyOP~Rk$A(xp){jTm%#>K3j%H>ynz5&` zIj%;h>NFbIe|VMqKi`N@Q67Du5gJGbwBbHzCI+I5W<;#N7Y%G0y8RwP-=B?s6<dl9 z<SlgW51`K-LEAru7rXyYb5Rd}L$_VEkzw)m#7dNt=yqC%8Mql;j9bwF_n;jfz$$ni zZKw385O{lZu6v>xyak=A(U|nZWfm8%_Gi!^Fy2E)@+}(aZ}<dWbZ1)PJ6wd0?EbsL zVtWGXQ+^G{;00`nBSweS{xVuVjSjT--Qjmjqwi+_PoZKJ6-JyjCN1$Uc0t!fp|Rlr zs)kO%QFLy<M}O(`7dn>($A#aXRYV8S1zp6W(DP$atbZ3>y#GUY+u!5Z{~k2?$A=r$ z(1u&19S%k_a3?x<lVkn;=#<PsQ~N}`|4gi3flkd@^!?58{@d~Xu2{b}$%PSpfzI7o zbc7`*ga&Fv>!I~c(GI&t`^Ea((Tq(%1Ah#iqNV8b8_+3z9gE=y=s}hIfeT;w7oCDj z?+J^fDjIncG^HJ*!_kHx#tOI;vv3c39$dh#*zMl5#8bEm4XpXZ@P}3X(0~?TnxFsA z#){?W>V7f08BOt4H1*ril<q+H^=?dUt5|;|)}KJ1{|Oz~Sv25(qgPA{^(F9f_kSfW z9ASMlvfk0bXosWFeLfD|K9kV~XQLT<Ci)_}cDAAKeGxr|o*SpofPRanv-Wbi|8sF+ z!$r|KsfcdN#^@^Tjy5n74R9jb(DdlMcz+q1k+o=sUPiauo9LYXjn`t4$zj_z!K57y z;=%^Up^@K*F3N{+0X~D3vEG!BiJ{TE(C6=o<*8_(Gow$S2i0@v0Jox<dk@X%=Tq4K z25^iDBR-GL-M_J%F*Q7x6CGK;=r!o`WusNm%+!tL=IHYs&?)MH_A?k=jN{RBWA0Q^ z;*Awl7}=}nHrs<Xcm$n-?_z!Wv=GphXa|MShDycyy3wX+M{QzxAU38v6rG9}unz7? za^b4ac3(*4rD$sMpn()Z@0XAFD@ALfBdZ_pw?U_{1G;N^q2G!JU?;o>&FmgD@croX z$uDBXx9D7+iC#co_zyGjqWi;(rO?z@Mn_&7{qSjznK%LsY&P2767-i)%VT*5x<+;* z?IaV2xNvcNjYf1Dec^936IVYFIxK;nU|HyqT{qeteeO=Q;|XZs(_{Hz^u4Fh_E)0= z*pia{x19@Ld=G8tQ*=!nMN@SKoy))QZp`;!2zVyCW)`9&eF5!g6S{rhMozfIXXr1R zK1V-xkDvjZ$JF2d`PU07a!e1Y$%i&n9IdYs>+7L`w!#+J9q+-#=*M@V8R7j#=(cNz zW?}$3kU?mBBVu_1CY_7>xG0Tt;*G87gKwiF+>1W<6}qT?L<7t|Gc=qZU8I@l;=4B1 zm&e+aYoH^(BRU3cH#w92Z-jHGFh!4}4LpgCbSXM#Ytbor1wEMd#PV@;q`#qS=+cM6 zL3K46XdA48gU~heIC|7?L=Uw653&C<xk#H8{)n{%W>FrA-Ea}s#ItB1WgiX=*TANf zJEC(v7hNMO(E+@Lvv3!d#~U6A+c}AzC$rH-zS;^?`5xN9A#{<PMn`(dqoIRh=!-Sc z`i{}TSc39Ibi~Whc3#8k_z9ZoOJ;{mU5%D2q5UQsb75*bVmZ7S?O+yqQay_Xv;#}x z7uW^=i}$<C38}vmU4&E7j#uI`{1T_*#JS-+Vz$S^nrVi#pG>sp!T|0-KRzd;bF~;V z@s)W0b97`sp()QcFC0Kc&}~~4T?=*4Ic|>)aTq#<YtX6r25tXaO#S{pV}5wyax}#i zFcVv#yWm!I_1=kgd{3;O6J3NJ)hp0*U@Q9kcJ%r8(8YWd9q5l}>i<*DpG2<5!{RE6 zHc&2FC0Yw@pdmW4cIZflqKhaQ?=MC(xCRa2z36^)mwg`n3Ox@_V6r0@KXc&=4WFO_ zTVh+>g|7N57lcJqELs%}v>Cb<+Mwsd;^=BLlP{y&azC1(Z=z?T8BenRy^-(95K$?# z;mT<0uR|MXg0Aw;n2Dp&17|)O;FD-dm!l)wjA^(HZRgGC2WX(5#`5te+5dL%bG-2{ z+Q4NCLxWeLpK{ltf!2w(L3c@S^!+=dQ{(-)=&pGdT?4P70q&1}jrQ|PGFJS7c67;8 zA>yKF!)4L^T0558pi|WgZE#?`e<wP!`_Q#A2OarRw4K$_SL6NN@qY3%E^P34toRXK zrN5(7ap|J)o6kI0j`C!5@vTPp`!;k@p1>-Yu{fTP=wj@M#c>#x!ACF)w_v9G{}>ll zsmNFo8mft&WH+FTXaw5840PYFiS9xhJdRGqWlO^!T$aEJl-r{1jKgd3G0eoRcpV<b zaxV8PmW30mE_!1)R>tLMLkH1_)1MAgR0$2F8M-L@V<t|GK8tS4cd$GjLl3UYp9upg zjlSOsE4tlo;ld2eMN|1s^f<c8)1M6;XG5o?FuLkXp!X}GCtx*nuIr*FT^scIPS^); zMAyjXc>gU-{r-O!7cQ2)=;HYdo#T_}9R3;W3p^J_TncTt71~ip^nmGx2G9#_X9(Kv zICK$DLwCjeSYG>F-2dCDaP@x_Z~PD49>1dvr7aJOG&kB{K{Nv;W4UrH*F{Iz0v$lt zc>mT|e<!-wlhNtRlOf_cR2bpYXv3S(?X?|ka39+77id5y(E!h(&;N^#{L<$`Cay;B z7mMX`XvQj`1FeY$*e1zEMK1bbEu4j}`ghRnbrgN!q7|W|LTE#!(E1AKVrqh}_P*#; zj6(yPhz@K<^r`4tbj>8Ub7ADW&=(G&BRw9=Kcgq#pXl6OwlZ{35*=Y#oR8JeweTLM zGKL271)9mP(bWHfK6e4>Cz<${3rCb=RcP=EG?1&KrO{Ph4Snu9bP5`v9koTD?-9Kv zIuZ@wUi7&s=sEF7bUBuH|G&<K4Sb7^=-22!=!@A`hsg7x4HiZBeTi7#JlX-x+>K~} zH=`%%NKCE%cz-^6J}kp4-T<a4tVa1Nav0_)PR)bP6t86B;UlPFW?iqlRdT+oA9E zj^*3XfW}6rqVGM76>u@8{{G)?F6vWp5L;v37s9^pg9bDno%?C%N%j<$!_8=eN70Uc z#w`3J)|XlvS3CM#8}$8NvHq^L?EmUiOsB$#UdO6<3O#rVuL}*=MgwSuj<`3vh;Bzm zJ_0M@q*z{yzW+L!k;CZXJBhCPUt<05>)8K3aMAkEQJ!cKbgs*wA2Jot7jHlpVV`(^ zAUg8f&`jNhJ~uJmzdzoeiRG!EkG}sVrs1w67k2bMx(N57i{^7QWj~>d=bu>4{bJ~# z7&@Xdv0MesNNqHrhUmarqwjZ*_isb{8y?HaySQ+BjYnUch>l=7n%dduoGnEc;a0Tc z_hbFX=%?ln@qUR7p~LEE0L^2$3p%h{qGOR0FqxPcE)q-7hBu;tyoP4vUG!x87#+z^ z*Z}{-4%lF0`1?Pza5Uvyo6-{Z;xz1miOu1M(4J_9=As!`kSeqP7IR?+o<&E#0-dAv z=$vke<u{|da6I+<&;VP#6wdM+(D!dcI~p0wW6-Ib6n!M#UxMlG|L3?!bsQg9kFN6V zXa{@Ilj|@V*y(uxcQn9@w}j_%V^_+B(bSKK_4h`nqnVu-%S$n72Wz;n!<VBw(YZc= z26h6Snjd5R`DnJ6!+QnLwNeV5q8ez5Tg3Zq(T;nff!%_xg;6iZpa1WR56nP67U!V> ztwbB%f{uJ=yuSxc@z-dBCu8|nw4*;_{Y6{D0P>*i6++u7g9cb>EBoKMuTF*gu@<Id zooM}NqiEA;^Jpt<&+~232A@PTx&+POYIH!a#rhA?0KY&3Iho|bk^F=<@GCmv3+UWt ze<hd)9cf{-!LsOQMtwBpozavIjP+yCKpu+qPoN#IMi=8t(d14pjPxLyqLXMx=VCeS z)li=sZJ;O`SXngiYUtvujds`(ZKpRnklSN<92)ooXy6M&J%9ekg$=%eMz#wL=n&fQ zcd`CIbP?u$Ed){!Etf<WX@yu{18t{KEO(6MUg(cvL(sq`r|Q{%k8<H$EJYi79t~(+ zbZhkO=$`1O(XY{we~)(j8=9$XuZOA0gSJ-^ZNDO#xtiX0|JUQfxoeLewF6>#ybn;G z70XM|jy6Q!Km>?eHV?`7h8Z_zCU!FZ8{O-w5SA=ogs6nDl{$Tol7r*cxxcs<;vT za(M#%a+=r{Mo=5=urbcSw&?o@(SXjQYv^xuQRmnmI?fd>h)zL??d<;+TvVmP2*<@6 z_eCE=Q}qnm&`R{VwdnVOS7Ld8^a#2pPN8e)Ec$-Nn<3yF=>2?XeNq2t#F3PYH!7j2 ztA$3`939aO=nK7L`6e`Tx1rD9iO&6G^tsuw{&95GKZh>9t>{$mLwCV9$yo6lI`=u= z3J;V(M_LmNut~HXI>$HSwRk(4>PO=Jr_g|&M?W<;V<vtW%cs!*E_*w?m%N4xU&ul` zs)LT;`e+-pgHGt`?Te0l5PD*cKvOyjZD#_Sx#`#)pTGh5Gum;-9bqbOM*8F5|AdRg zooK@o(T*NO=ls!le;yjhQuMhO&_K7K0lbdBw-bGCFW!cqV^?hUPFkWdK7qdXSxWZb zQ7&98C(yY%kB%V6&R{__GiA^bR6|qS9G&w4=o%Rr9gDs{37x`+(SV*r7wz-${x+=R z{@)uP$o_6xqBrGy=p2tk8=8u@;2gA}->@lW><S&UKr_$<9a(QQ;G59EhN17>g|<66 zIv10^_#79edM)~s$wn-VAE6`o9UXbbdtr|AqxILK0aigfZiIH!98&?IQ`H-tnn7qg zcc2-c{2u$?Z7_$5#`rw?!nbIO&!CGc=lh}ItI_&0=yqy~zTX4=thfU!;C<*%(Hn3W zet-sCdv|#5dNk19yV?IndK(p{W>mZ}4efX~+Tjwk!B^02cL4490#?P#KM23NX@qvv z4_!+`(Dx^yYvoBSgR8I{?oV>zzW)myQNBIl$Ssea(Je3&Z$}%PiH>v$n#z~Z_ufMT zJc_3F0(x}k*c*P2PztSYiw>+0`hIc<7tZ-abS|GlJ6esIxD5^Dt5~1DFEpGV4Wt^n zs#{|xya^3xBl?-}UMzoyWhwuQ22ke1)So9L6E(RoMLp3MN23qU#LBn{?cg~2++XN( z`9BJotAN%wM}OuUfTnh0bOmNo-j6<a79Hs2`^^CRuLu{DsHlv$<2rQP6#O_mSPY%h zO6ZAK7oE%c=pt%|euwOdF5bTAZn_nHZdfeei*Cy)X#2A;_4j`t<HCrRqA#w)Mz{&x zR==XZ7yKiZ3mymoU4y2wJQ`SSwBfqwdre}wCAzpfpu1rJ8u(sJy3ar7!V#o>688PY zXhRjyeOn#fCG}$c^=L-gq5<3(?+=Rg!=n?>j68r2a5fs~QZ&G)KVkpZ<YEOCZlfb; zWVsK94vU~2l!{i5^-a(bwLt^zg9bD(Is)zR9&`XR(GKUL0WF9=bCCUCj*1tkD21P* z4gHNae95O_N^+wO<wF}Pg3e_Lw84t8Tnl}_DW+16wle@zYa-qs79E$27x$qJ%|;tu zi0;qjXzI739lwP(v<rQH54y-c#VkCD6*2Fj@GG6hSc&pPtbi|IJ3NdAm@NHSNL6k0 zz-Wm!JTQ6(+VR*}o``1RL9B+4q5-{)j(it7g$K})e~nJzx9D@{(E<L697xH;#fQTP z^P>$ELto57JFbQXR2yxeDcV3wbOc?{fNnvL<Y71+r^Nb8KMw)qMcc_lGgclib^q5* zU2uS)i>4EL0`^Boa#wUR+Tp{|rD#AK(1y35fxn3cz6%}s-gy6uSpPqCpg$n%pO05A z+<t$cBlrg$Vcsu72Sw5QCD4(UMmws6p6NBwldlDOBo9PS%n9gc!rWN@0(x@pKm$IE z$&y?g=i)xh{$+Sz7Mh}G&=GIMdiV~Sp~R82#3PU!4PXfx@OpG)uc86Ji)L^)`rILO z0N-I2o<73(9Z8X+;enE9hc(dE-vVu*C))8~w4uA>{Rhz9@g&;LGw778LZ4rUX7mj- zu#clh(SE)^%KrDkzo~GpF8eCHPzYTEl`ysF(3G`ApX-b^*dHDF(0G3gnz_m7bF(q^ zag7H068dSo4Snv*Bp0USM|1?|&<Fp*a(L0#ArqC*7n-1R+Bwz_MLU`l>t~_c@_DqQ z!)OM6M+46JP3W&6x=53mT-b5xXhk%D8nN6Umaj(xZ6ECx?Tb#)AgqLUqTd&uM%#TS z-v0p2)MscWkB4$H@e>!$=>;@ZIgW*LCi+5E^o9D-7U<gO6w3qAfbT%3a!kB`e{=zw zp*7eNU%_UWcHDN@f6ck5K}8QVRS%=7c?MkrE730wucO=S5IQyIuoPZ%B8>EUbk(;- z1L}yj(<9#R7afFVY#65g{{MI`jPQ}@BD8_kXbLw)Uqv(W7TUlbbQK>)1N|ZTAG%hq z{9oKv=-k(cHbyhp4pV>szdsjtcq_WvN8+`3HyYSNG?10(bL-Inw&Fb8i3Zl|WEk-v z^tqwv`=in4r{aD1D4OYf-?IOWyxh0p!3O9eYl}A66@9TEx;BQQA5v4%5iUVbv~}pB zdnfuWdIDbhU3jhp8c?-Zu7^%d+wYR$8%bv>oV%{^fg5A_Ry2^IXlBNs0p1hK)6fx4 z$GZ49Iwkwjj2%Zi`W`FbX&it>Plf&_CAl!Nsp!uE5217O9GaPz(Gh<T?|&QbC%z9O zyb}Gcn1$|=p=h9Yqq}MXn!$(Afh<7#dp4GnFK}U`FQbcO8#=<>=z|}l+v*FngYU63 zo<mdI;)gJo{m>5YLIb`JotkCn`&+OU?nDo$e~>knOjP+Xbkq%<!+z)sQ_zgeM!)^8 zLg)NFG{v8xnfe}|!GG`uT=rAgrsvW3^Zp#ZTV|op_eI+oiC4P+Cv)LQ=Ak2aA^HZ| z(LS7oU&rztzl4z`(K(%uZSid^kGW2V0P0{S<?iSJ#-byC9L@0inELyF`?>Id`4XMG z-_aERjZRI6Ga=$`=oAb>r)mWH-aU9dK8|<e7ig+GpAEkOnSmQApG6nr@?XQEU4u#Y z;VWD?@_lHEzKRc=MMsu67XoRAE~c*Nsvm&9KRh}O&Da98oz++p-#|~yZ_vOmJ0Esk zf%EMDQdAV8!pIt-tF$@VQ73dQ^hHxPES5*30ZfbabI`^5B)a&XLEqno>G%QK&c0ZG z1Updv{yh7?3m0{M3;)h<7TVCS$m&e|jjrP2zlV|5Ld)&Y25&~!&L}j4GolOQ{Wa)R zyoxT)v)B+@UI<h7K#~hjwx`kkz7<W?9(0xdh6a@Fk1z$f(dY7`87q&OSOv{UXLOD9 zM^k+}mc_fV6E4AF_zPCRWS>97h-TpJR4he1%<)(FOQw0zj(VbV-9MH`qf;^g9r;vr zt{;o_FQbchdn~_;W^NxkuoK7>B@^eku*0;!!=ktpO>Itebr(jD=IhY8tc!Ns0PUbT zx@+2@Yo{|BP@h=716>p2(Cs-7&Cqtd*!}-L7dG%Ax@bN@8~O(A=ts1pbJ4%hfYbkp zs~K&u06GQ5W4SUqRdr&0`)Kc2e>-NU|HMQtOv(Ldr1R13vjOeso#<Y4Dn7*q_$3<P z)&GY266kwn(SYlr0X0Pj)CtXGZ}huie+>Wq4=!9R_oMrF4jTEhXag_D@=i3+!)Sx2 z(A9q~-p~18nBz<|lh>hB*$jQJORT>cZGXgn?0+MkMup#MACC{bh%UA_upWMlgD@8> z;5r<QrEm>a#r^1Z%}7g6eF-g#nUrrtI~s=uG7DW(Pod9mNlT`u{$1}ERNO&DoAmV5 zFO9ciE6T+)(o-23f_^yNiw3+DJ<~VF@_wvN`2^O$f)|Bydn`kF3Obdm&<t-xr{J9= z7tYl&wBb|e9RH2ZRr<x@#cb#z%Z<)?p;#`CPEi)xPMvtaF}e#{p;OTlo#Mf0Chm+T zr^Fkx(K%g&cCaG49xGFR8O!0fSPAoF3jsC8{*>FGBU_CI@;W-DJEBL>Kz~OAx;T5f zQ_TExVMQ4<!Ww8pjnTR5f;KcbmM5c`nung8D`NdNbYvf+2hBHVyT7B)Uvx=&Y7rJd zpDTl@|NiH7T-ae-G-Z9!NQa|eAnrvQoR0>w25n#`x~e}x13!UwcskzyCz>-yc)l>& zZh3TZ*T&S}|7p*K4c&xxGz#tDL3EKlj;`95urz*zj{J8tz+9K6CyHYkG?3QlTIm+c z{n7S^q657L9q7ZD`ul%NxbVg2&{VyMu7w@3ejhrr&tv_!IG*xZY>vY&OHVYxjp)eE zp&jPP83HVXwpR^Z+zrqGo8{#1KiF}5DqQV7;{$!s`hjSqBVu_n-b{HGdSw5CHh2zA z?VsoXF1b8(To^6aKm%%t267|X{>_)O|J|3v<BhTL##FR}M`HbBv3?1<x>w^E+<;ZE zY_702dSW%ocVT&a9{s%Ek517Qxx;R$hIJ^<O>*Jf?m-vVw^$O>t_TNGDJ(_#F|_^_ z^yE5%&V72G^wbet82#b2I@ZNb=yrVwT|+NnG5iEwW9QHVEqQ6)a8y=A1L=T9dOLb@ zJ%lZB6K3LHXl9CB8K$N<x~Qt5p9R;)a-VpAcq}K;%*{bh$_2;?m`v>9qAC^NqmdTL z7gAOa?PvlzXG!#6nu*T!Ty)JWLl@I?==1B)5pF`K_WgMO<LH-IllqgG&CmZLSB2GG z678T$EZ0U4pyueua!<73yU~Upiq4BJjy@k<AKi+!`&RUQbbIetKmWhx!UlhdH!h$Z zXU`u-S{Sn^mqS;3H?)D?(IGgL@^~~;|3d>kjb<uafnYv#8<&Vy#?-(6tItIyH#(vp zuOrbpU4g6d6&!}Q6bz}}k2ds0EPsd2?b%rWM=WP6l%7bV{&MuITW<8Zyy%n_D#ZSG zf0v}f4AejyZh(G_wn5iK5;Jj0EN@45!BKQqWLzB@EQ79rs%Sgcp}V9RIt6{u4Bmof zYRJ{>e-DDYsW8$hXk^pSNFR>ndFYEvV*PVygKN-^Hbvh=r)Dqu{+H-;$MJ6b0n6e| zg+qHYlUx|UY&7yk=t=c78psB;q1Vta3~!?ye2q5z3;O==u|A_ndg{AjUaU=hCp5qr z*cBg-<?qpUlD~6dhuMmTl;p=sl#8PsbV38@flg6>w8PubpKL~>Q}F`Y;C}3jU!zmo z@S5;`M|3K>qy3FQ7H2Y%<iZCZMi<?Za3k>|HmAG|OW{SuLh8z6CgrZ^fioKIcour} zK83?^9~y9j%+O&AwA>y4#{O8;{oki}SoIUoMX>?P<Ll^$$G2!E{zNm8ULu$SZSaa{ zp=gO{R<uU6L9_)n<-LxW`uG2Hxp1x*pbb8Q2C@dt$QGP}@5TFVN`{elMdx-X`q?oK z{rH`WF4h%jJ8RJlZAJUph3=aDm~^D)xhRd9*M^a{L=TRRXa{}KFC0TK3#Xt{wiXR| z8~S}<7Y@WGrNVi!96jLjmQGLomsIDX_e+)u0X|rU{cma?roz<DM;FPWSbhoZ=yh~N zd!q-?zz#=GMt?=8EKxR${L1Jx=!semZLa~Ei4J9xVcYef!tK`=ZTMz%m5)HD;2w0b zJsiu+(FR^dpL+{a0ipvr5bHlj2Y52p{~YVjqy3~M%Y_u?LLV%EHdGA#I4*@5*chG5 z>tnei`dn9ZZhN95yDgT-<3!5S(Q_kP`SAX=Xuy@xDNfeo!jZR*6&=u%un#(terRBW z(C6+zr|3>Ju!qnFA4LOv3VrW+bZxAS^;<BNDKw*dk;R%!e8q(gpF>mn2RfpRtk7Uy zw4tKtbEVM(Bn$n<QxAQw2m0R4XeLIXpMq0kc>xxuyb2BQ15Ew??_)09J||NZTvP~= z=8I;c8K{5;QUh(E0ow8P=*T*ti?3I_e@ApQI@kB0?M#pLv#ob~Ji*0$d=5=b-HO3> z=(g*Jj`(i0qx;d0=U^)3Xv5EAM_h-#_b)p4S5-<+{jR4vR-`-tug6C)c^el8xNv0k zD~Gvl9_@!lJ{C>weP|$$p@BY&2J}*_e+zwnKf1V%qPynD=tWgReG&AaDqn^DZ$pjZ zjm~HT{m~AG#qvGq3)9ht7h_digT8+x*8hS%DF1`yuzS_87AB)#;pU*bYAsgA_o}l0 zec=KXm9TTQ@ToQ#JsG#6--wQ*AD>rO4`=sq>`8e8`u+a08tJKD*|xzJlow$WJdSo; zs%FS+6Kq4d7rHo?C%JHrUPGtgFuJ&op(8zoeoy}$%i`77g%LGF>u<o`I2P^r0JikG zTIs1jqP-cbQ$B-sSgLkdJN3|Al5Ea}9d<`k-xuw82s(G;ur1C;KVH8?GnKne_z9>X zdjBP?gK2fc4<Plh8Rao(yRTv|+=Z>MM7_BGhlY#9WUS4N`DiBgVd{_D(C>if(7C&^ zetPN`m6g!NxB#7^mFPgeLQlq%=-T)ZU8MhFBfPXh7+@Pr{rA6naN&!$pxbF^bPSq_ zDd-3ujV?kDqE%=|>(Irz8SQ9Cy#FD(O+P`~J&JDAQ|JKCc;Eg1Cl@w&QNz$t4s>Ms z(F~MESAR3KgC1x@x1a~kFf=nsw4;UC0GFewK8~4Kp;3Bb8n(xkxF3^_d_v=}xTfGR z%B#`(0!>0k*Pxjwjb@?-dcO%e!d7S?UC;mqp(7lLJ~ti>d@{P|W}(k7Zo>X|<S$a; z3ooG!ZbKV-FV-JGNBkxF{0X$-Q?YzHme0rX-{{n&H4PnRN6Q7#cCU%$a!uL)HdHxQ zT!)tHqa8LwUucVV+#PMGH<rSia3Ma3nOLG(c&-`xek*ifozQ{xjP(O!{m>*AHar?r zsX{xLjHc{?Se}c1dM&^k@l|xr^Ijjmx>ZDX$qnd%a~GDxM==XGVK4j&%V6E+VQnOD z=E8lw20c=bqDSKuEy9OJW2{U04m8k}=t$P0BYYWMtlQB{eTaVee2y;OGqFBb%P{AK z&^1s2`TmehG~mL9nxF?xYxE1oO=!at(A7UP)-Oc^*^0jR2D&JBVt@P?&0MusA)^h^ z=bB@AY#+<xF!lTY$+6-AbYzd9t8)Q5C2OJ^(IfN~^kDfg`VIR0uV}#8T8Du0qveul zK-JN;&?w$-g{eRP>&Ar#$N(#F1e(GL=*Z@v9WFr|dNJOA9nH*v=y&M*|DXX~(k28@ z7;PsjS{rSrIVSD6GZ(1<&<u>g)MCWcVnkE^02;_c=yQwFxm<ys4_ncW-o;EjfIfc? z%V4&);a4w}&?&j4ZT$QnM#VZRCZQcyY!|G7es8abzR(dJ;f>LoaT(=1(7DgmKHMLU z20k7QC>hJM&_L&+8Ccey{qF-WP~iw)!E13Fx)_h6BmE0~?&1!i;k;-A1<`=7#Zj0Q z>ldRPt%~<w#!SlF&?);0ouYF|E=*zej$v^WL>EnQbPZI+a@Z<*C%QWpp<hT|Lbq9t zPT_ODG#XehG=RZqN2Aex9z-*<0L^4_NxZQNJz!qNYWOAEQ0~ql^@Y)ZN}?mKi{5X7 zcF-OTYyjHvcr<elqM4h62CxMEw!I#CKACu*3%AuVw1W%i36{G{NL3d4LSr;Dz0eU4 zK~KO3(KYf68psy({r6-2|In2GfiA{eT|+;aSim1oYjNQV9np@4qM5iKT?;GFhWDVW z_$zd6WWON<Pz-&(E@ojL^eCQ=W?}`JiI>m;Y)7B}5VQIDe})TFbO9^j#ofYUsev9C z-O$wai;h5!&ctMN+unyx$z$jM7NS$LIr?V2zbBRtp#6P?sek|TBNum4@f!}n+q;Jc zcB6B82+hE0bgD9L4CO*-hAN;V>x>3;6Pogocpcu4rv7zwiua*`{_jTi|2JIxM@4u1 zrbl{WF4pcD4vG)Zk*D=aPi)7$*bF~LzcuIYou2xK%Qdhf<xyzHmZDR-5_{r1vHqGq zVPIv@jMeDF{x{-!RJfSh;Pp5NFT&O6Hd&9(<*VrSc@ItTJ~ShrV|zS}W};!=uxmP? zbKgCd2VffI+t7A~B)PDmk!XtUMLT)~?RXJ71uM{q-;DQnp(#Fyo{Zn4Q*;(x8yEKr z1IQ806}=Lj`+~8YEX9QpmPaG1fp%OMO=WX*&N`qS4nhN+fKJV<=;G))Os#TsTYiXU z_Bgs${zV5^vVW?dWTGk;rn)}5t(u@I?TL0c0`2HNG{E_2U{9feK8LP__2@wM;!r$< zw$p4tXul`=d_T1Qc1(T$Po^&TRErNh5q$>Tr)#k`ei-X7xhahBN;Hs?=o+dJ>+7L` zw2gK{f8W<1Ti`QT2~S~V_kY2g!;em_(63rk(N+FNtWO)5p88YpdRU+OvDg<kV<zUk zC1jvFTJDTZ@J_6No3R*vgJvpiQ1~ub43m?nn81aL;t#Bf*#?I{W~+_8DL;jF_&XYT zw_DQ_tMEQ-i<NE*Kh;jamXvqm&v^Om>8byI;NSQY<@rO>Q~w>&X+zT!7bq7V#{PG) z<hvt1^|#WmMLQUU9uUjWpK@P~^+&KW<($LA=Y4%_PI(cQ!(&*}`y;}iA2da$ZY-MF z7cmomz%0x;G8ukUsy#AvJO<6ca;%4k(7C*FRM=)ku_NVD*ck6dx9=A8y|>YfoWqLP z_|EYDaP+xx=vufBo#I_dE}YZL?h32F75d@;bgmvjGw=dBvJbHXUOYN1&KuAVn=#l1 z=VNF58V#h{-RY@+(m4suz<bySGscAb$pKtA(ihN%zr#{kYixL-FD|FN083)Sabf@8 zj9HXNqp4qpPQ`9?09TBU&!ba%GaA?&tcAysfRc&A6T*i?cQmqxu|0l|J+SsYA$4=m zsaPCcfo{JI=*jphUXE|Y@`vcT@+q47FVN?|#mRUYQ{Vqb-5VCgSoHIK0an2`aU!0< zQ8;2^dg3sCgCF8+lfr@W5NpW59!CRNhVG^n=#jh`UF5sagX|F6{&!fx{a<KuSX?de zV#*!RGyDeh#Oe|64@5^e6iefHwBcpwb1z~Zd<~tdz3A#cgMLPopArJ7h6daWlQ!6% z3m@o>1~3pE!R=_nW6;Q_U@n}C1@UQggs-9v?nOVo4`B@)GBu=rDcbHD^!*L!^KVXN z|J%TBDoouGbk0u12TsNMU(vby6a7rcm=>Nd7%helq%_)54Kx#VV|_bxAidDFFbEA~ z)HLS6iplZ8S<!`P23AI2LZ5pZeQ_T;f+OfueT!!B2Xr96qVNBS29o{0@O&Y3x0S?e zv44^aU%U_9=d-XHuE&9R3`=2)`@{G9Vd$<{h6eBlcEF4W!XL4AK?CT9w%Z5I=q>2; zx1$-l3(ZJ!JQrzP+!rezh!4y`NA^VYDYSv5=v1si7vV;<gTwLuQS@W{JM{g;gJF?g zgg%!K4X_Zhrjm(FE<EX~q7ipQJGc=|^#C*jBd{vY#|pR$8{;`Ff;FdyPrWX9HRXBe z=lpu~y`AW1%J1=ho*8a;_Fn}q%5vidwBd>9gR9Yo-oZ}z75Xt+Wo8Jt6Z*|)IF`Zt z(T>(ezryP%=Xogp2!~me??mgDU={cOK`z`b*=D7u{-cxi(17Nk`}bA!{;%k6Df@7+ z9y%o*&|T33U37P#i**8;nFr8}K8tSS7tl<<fk_XLom{wm4x$YlkLA;7CjLbiOTkCN z+?7P%E02Y-E;{Gkqr=fmJrM6dk50wg=(+J3I<;pWVgLJL;?b~83SuV3^5~bxw&)1@ z<NbJVG<|jmbUM12=A!{ELPz=nI>MJ?`3-b{@1g_zB;NmKHv8X{o{ANJqucPJIU%KG z(1z=y0kuQtd;pq}vFOOA;$64^|HGVf!+SX&3x6_N1f7z{(ZHUG<<&_pJRr8jiucge ze1gvD@p%6N`Z<5;y!6z6a-kgh;j{_cVAc8Qseg)bFPf1&kB1Q#L`Pg24Y)dbzBEJw zN{-^f17spPl0E36I)*O3AF(o)dLkS^-Oybz0}bdo{2q7UNnE!e{JFsVCxbZ`hTSp^ zw{ibzw7&sQrOpHX`yX65;>~D;JEHs0%p67|{UO%>j!sGXq7Z0abZ(2F@0UkYToZk- z0lFqyqnYS}KGz?waQ_eC!T|0;M?Nz?FfY0^x*BchCG@#%Xn^mbyWn%Q!{4Imi$h1b z(Dw>OOP~Q~VL|tQ9WIQh3wk#9jSfT?-R<%I#OU<sV`wIppdGJ6_xG!4haaFv`zM%= zpQ1<dVKnd~nEL(yFI-fj;y0|0rIv(k*b{Ad0(uTS5X;NZRK9?|_X?K9@6Z9{SsF%I z04<k7pU*-ES{n_p*;4ku9}4Z_1D(;i>xZu5!RY-v(1`Cu8@LZ`_|fS6=u>FGPovv< zE&BeO=sB_z4dfU)g}*FKhPnTP3LCy;StwtLK3D>+uZ%WW7hV1B(SUA4r(gm$#hK{# z+KW$N;^{DuMQFg!q5-Xn<#kCejCeEJ;G41hF`9{^=$xKJGx9sOz<<&Anm-dp(iwfe zHyZFj^#1Tzo)Ens9oXz>axoV+yc%6B8_-BMp$)wfeFyE}L!5($&{cf<v*G=*=<}1% zMLPq%zZgg08Z_mFp9=?ADV*Tv|9UQbq5SgDaYHo1>(LQ(MpM=oox_{)E=*!e{1vNU zz2`%K!>}af(O3o-U^#pf{hslCEMKz1GW)L@7ZthD2|dv!;q|x}U8Tpc8UBEkvGU6B ze19BI`C)Wq*;j>3<cStU&y`|mMk~eo8nM0}rvCiD4Hqt=8__fWR`e*o7yYoAi+A8E zbP*O<9a3E$%}`A=V@=RNI-r^AflkTYX#11V?~b$4jGe+{e=e?Glb-kzC*bRN;|uAj z|CCz3wc$f%2AY}d>q1IPV^zu>&^exrj_?t5s^+1AJsHc((EwIQUqv&sdma1VMRk}8 zU-$-%_$PGLU%*M2V|{vJDo)34c-f2TiO29J^h7(4X6_F(fLt5Gnz|C5!ZK)wRnT@D zp$A&04eWnUupw0V;*;oZSb{Ff<!I!upu6LJbfh1k&+m_Z8tcD6r{Wv*`JZF?G&-<< z(DpCc7|fmI!pQTZ4Q9m~RbsgoI)eIWhMLE6XEcyr=&Bxo<#7^b;i_0Zh?$fVo5I0W z94k|-A59M9!qvYBT@<^~2L6imWj2QstsDB{bnJ**u?=4GQhMq?PSX|pS&yBuz?QIh zZ%3zaGCI)z(Dw7aocex|Of=@gH837q;}rBe;Rkp-9!FPg`>o;RdmbB5{s~)Q)+=GV zj>a1)zk+o!&#U1JOuOj)*qHil*d71F9`66{uZ3SYtjFfu_y;{=o4p?Xh-D^rp?nk< zVAVH5hr7{pA@{amS8PK03A`2$qZ#=Z{l4FKdsq|m(5ZVIOZfS}hzm2Y9bKKf&~5b@ zx@u3NYvVk6qWy_JU*gS>((>qHZ4~Vqy%oDse-BQ<53vSzek=Sg=>bey@p`N{gMNCI zc{}`++6(JYejKagN9gkx?Fi4+LC=9<SQD3^Yv>d70K52|U}1DhtHyF`bS?CMhyCxx zXevDEW<-~vBYGJN;s<DhC(!5rM89(7-WlG@LZ5Gn-tQjEL(vm68J&x^vmAZywVlb( z&_`6*z>o34#Ji#4E71nZqc1c-pX(AGjD8=OfIc@LeQqV%(HqeN=zFKo=l+T1E0Vjy z3)e>LL_44<8yLL@eep3gQ_rIvy@3YsG3LRa(2oB@JG|<>@LW0c#A_JKJ<#WqcW~jN zOQH?UMpL^6?Qj>`(C4xKXLL#~eLuWc5)GsVdQ!GVPq?1wA{~G(=G)MdaSZw)H4W)E znRu8BPqrm!L#xp<eLLFF4)o~U9X*IP{585OzC*X$Pw{@<-JzqR(emgCS_}P())+l8 zr(rSo|I=L9;9F>e@1rT)ho<@jx?lf7N0RnIJiF27^P~3*qwN%rmP0$P8q0Oj=bNGf zYiZg2-+>F~x+~hyP_&^@XeP#^FHA%OxDTDXx#;KobJ4fZ_l}||K8bzsG@APMd%}Qv zq2*DS`t!d@v0^$p74y*!pGF&6iH>9=I)c~GK;Fb+xDO5VXLJhBqR(aD8`eZl^vo}U z2G|O{-)S%V-wwJ_Q5^fDi)czL&%x4^H=&F1bDWGnVWBj>-R=twPX91H_1}D*jRto4 zN8v-NFuHbzB9AA=;H@|gOW@ZZvHwePk+DDg8onGF&|q|ABhio5+2{yf!(R9;dbT(H zICS_lUPF03+VDPn63<{yeCR+pN&knnDHr=BWVA<;3m4l>=$wp2KgI4t*Tk3Tl$=8Y zNgNDwn1v-NHpOx{7&CD;nyC$FK<{7$JdSSfD?SbFWML1=$?jbE>9igl*-12IO%4Uy zp;L1s`e8I44QM*r(L8j@R-lXW<yd|neeN*Y@&7P2fX_l;S;%KaGSP+$r{Eqm^-rUz zUxQ}i1FVT94~H+MJ+T|*eRvyQ`+4|+@i5*%Ip-JQpIY36%_$#3Gh6h_@VQ?eJ;0`5 z>i_?9As3G9h3IQ&AiL3B@Cn+$7wC5T4juW$N5aWi5DmBjda$%ZQ$GZq!WrnN;?sCN zevIy>0!LXBNiH(EFjc*<F%HIQxB`7J>#HyoHPEBD5&C@BXn!=|p|N~7dX7v%SN((d zCC)(C%;2xX@0Mp`vM&`sbKybJ?whc^R-qk~KNcFk4qc>;aR7FY<(JVB??p541A1a! zc07!{1inJKF1qT^p=+z+2?8Xt+9%lmZK!DYzwoC~Gtkr>L>oGXc6`~%kcr~xl$1w5 z&8o)wwrImQpzrmM_s5_En~k0$KcSh*_iflM*L<4{`?nDlu7UPw>iVD=xH&#J99`Xy zqTA_dbSn0ti|H8J@n7g_&--1-Kt=Su=IGkF5i8>8SbiqSg(KXKeheSPes~hiO!HIe zssFpo*?2AG8sCSJ^h6t)jGb{E+Ck!nu+56%1d6TD4D7(RnE7LR;$a+y9WePP7frZm z{Zo44CVU9pjz8fTyz=L8GS0-7ly{+Lc<x_9$_t>GDiO<-Vz~}BroK74dmcd7%46sh zZ@@d;{~vMT0n+evNL2^)!2xJ$C!wi+0^JR3(8abHeeV-=>P}!M{1waK^=HCb8HNUY z7rI97K|iD(z|`OWd5R0?XcIb;o#-OlkG}93I=9Esj{ZbPl;do8K0kVLmOxWH5sTyd zSO<SV126S!=%*4|-x!Cv|0i&<3BSck_|&<uCU&D8evJn33zo-h=i};+wnZ~E2>tLG zk1paxI24~j2bAl#Frcf@_A)W)Hmb#ii>EXC;PB|(Xa?@ZviKm@!WYpK@H=!W{z5ZY z`1fE%Y(cpZIu#FKU0jFP;i+im1@^x;ZoCjajppJm%0Hm1cGDl>#Vh^{4YkEF)Zc}U z@Ow0n(|9#z{1pPYCRzo(-xOT~-O&Bt7ai!Wf3g4FcEhP~PLp^!&O+-Kq9a=q@4pf6 z?~eCBi}z2V9sGrUv&r~7ynhMWVIlN>NwmGJc)vlC3rErceeeeKJm`lm#?k2FnT)M* z2KxK~d<hTZL-^=F>4~qg@W0{Q_#3~W-15J01efCr+HA_l@g5wVmXSIilBeUv(DZQQ zB)Y9`&d5mp%Z59#3gr!04v(R8oAaWK)Q3q|yqWS?G-IEm+v|sD;^I)g3LRK^^yiDl zSjzq1hYR=n)OceV+Q92*gZt4JkD(d4fTr-GY#FKZA%C<ox~f~D?e#}HnuvZ3KZ%|v z8_->~8&m)O|1cMJ^fNm0|Dw6GXQZ}Ov1s*ZOSIwM=;|Mfeyl!$2L2ivz(?qI{25)G zc`gZ7K(}j4EbRX8&4n+FjW_1U@+x#O?m}1bK_q2~@6bSV<p^FAt%PplhUiFpqwkGI zkK6~*0G~&<^=p{=`Tt!mTx5TtnYifEj6^zKg%z=2v<13IN29BJ61t71#rm1(DxZgT zya=7T^=QXCF%v&WzX|<yX-4?{f8)zCQlD<k(Hle1k*>#E@F1Gvx;aBY{jd$?S?FRs zgdOpk%QI4+p2M*w<-O?0Gje65&Y2SEdwuaqT$wAGk@|l!Z<;$Ss_a)}q|Sjt=*UXP zaz#v|To*I2KAMTfvD^mDNC$M0c11JMAD#PK(F{zD_n$yB{cMs8SL5b*V+Xo8K12_s z<LG`rjdu83G?6E~cPV<m5c+&EH1G=OE~$<N(j1-Q_UP1fkM+shxiIok==K?dzW6Zu z!qQm35*^ugw4)EuMf4e(k>luM{Wf|&nvpjw(mZGeilgschxD6FG~vRITA&SdjP^w% zABtw^E_7s5V|fPp`~oz^&!gMzExZ*^U|(!^Wq58i+TK>Qzc(@U{r`O~oQp5e2!F&5 zn3gX**a=O2&*(t3p*zrRcsH8C`_YljjP>(lc{w^oFUI;U=s@08_y68l@k#Uxw4q~Y z!#|-No<#%sGkVcg;kjJsbA`}`uR*7(6xwlB^!-}sbB&_cW9t9^r!^OLcmtY={^%kc ziKhNObj}|`7tb>E`Az5)Y(qQTgKoRe@EGRGAGYTiH1OI5LV!)t_F5NU|9e1mr@{w@ zp$(5gQ#%Ent2yXM7Ge!thK}SQ`rPMepx>j<{SoW`Ll<-Ig5iE~wBsu1qHR!+{cp!j zsBi>r;{!LMBfSM}cr2Qk2V(gNG}X^X*P?4@GrAbxM>{%!oA3-e1<MPC6LBqiRPRV~ zVXD7IJ31H5xH<%s7rlQCmd9#X3Hzb}%|b`K7#+y7Xvb^Ok-v&&a1R>5LG<|}=m3(( z<Hh&r2+qWEw!-1_{&MugsTS77Zn1tg`YrcWY=K{587x^OBlX+zw%CaB61)kI;zQWD zXn1}PmUaJMc}<A0KKilR99<JP#qwA*u*cBFwi2E5Ezx(;5r2wi@Hje^XVEGA7tKtb zV&UVuFq)ZqSepJ5?PJAg^xN<QXsVW>4Xs2|wK>+mhBmwdT|}Rvfqjm4^c@<=*;t>J z8NPtzM&B!gPF-D0{rjJ`TzGPIM?Yl7qaVNbpbbt!cg1vcq>rH)Sr*GLp&h;*-H*=s z*JvhBp#%93egCrJ;rW7?`ul%nxNrnD<BewMh`XRK^o;ihqXCUZM=}Zh%$O7FSE5t1 z5e@KdG>}8cTqnLp-^)=VEb1a9*#CA=g$g5WfG(!4SREIl4eUdoI}|+;JrnQ$i??z= zd&%%UU<8_x?dVkQ!&3MuHpaivDQIwQGJJdOaBVnHHlQ7CK}Wg+ZD23j;K5jb0-chd zWBCuX!HiNNlljngN}w63jJDGV-Aygg_68-nFomOI#Y5;+EJXL|%IG?@!OhXPFf}rC zZa+mkI)(;zHu?`bm6wzb--L3b_bZ|8C+ozEMrg;)(e2R{9nl~((lKZN_oH7f=b|02 zLEn2BkK)c)ey&WozYz^=8`{pk=#gMD@go;D@K-cP+0bzTbcAKm2CASZVPiDF8_+c~ z7~Qt_qUXos=*TvrBj1X)za0&DFFKIJnA`n-GT!(NjWE4jcrXu|fuhk$XvdAvfI6ce zLN}oe4@Nt>6YXF!8o<Nod-I~tqXXND`ThKVGu}9auKH8x$cmQFNd4XL>Nth+NOXi} zu`%Y#%1Hesla4r-@(<VmCsha?zmCrJj#%D@X67K8u`e)bWaqi?Q!9JL&~XWLpVmg_ zx-FXeThM(y4*ikp;aFadX5dvcWADcLL+D6<MB6)u?yBsSVumZR|9!D26{fx%+Cc62 zKx;Im-O!N?j1EViACIPbdaR!x%gfM#twr14j*k2Tw4MEU2}kXhmDvAA^uNmC!C%mZ z|3c^X(kdY%xzRZ<6|IS8pgCq?Uo`L;*Z~(}MLdP&ut3$&ZWDC7cS19HYcgKki#9k1 z{ZLtju7R~^AUn{=--{kVM|2cz@C5q&U-5pPYN5Ue`d)Q3z=mi>I-&t2dvoE7Bjb$+ z(A3S14?Kr9@JcMdgTpBw#*)~odiXuTF!Z@KXuw<0)&E*7za8)ILIe012`HI38gKl9 z2J$Dm*siD%7SFZl6jg}j>+m|t4e<lK8(sZPYGx#+;V0<a_P8!1_4kBss+E!Y1?NGu z-2$~k=CUxm`@bp|rlL-&f}i1HxjVY}hN2OVM@Mu&*1}m>72iPv{0&WUqE1*VdC(~> z9<776*BQ-Je@y-Ve+`K@?zMs&GttlgMd<cfiZ03(SO&MC0USje%wIQb(`(V)&;b3^ zY!k~}(Le^Ei+CKmt*2w^-~T?%g$=!ky>J_PKoqK%k@|Om)zO3Jd8~wQV|P4*W~NpB z;0<V?1JL(JpedgbU5phdZ$KCA(faIvQ+A$;EX>v*G*AsqX_IJMbc(v64Gcj?@&ww^ z3cMTN!qk`5h8d~9bk+@hZzp=deU6RrJi69uHe&yG=Avz*jMRS=YB7FHd12#>)Zf#; zqe<AmtI*UQK&R+yG{CdyT>g!Al)Y*A1w#?^{;lYm85JFe2A=%Cy6!x{$Et7q_%Ksh z?kI|qGGyOHSt5JcWfv)f!H5}V?BT1VRFp`Rt&&QV(lRP4ijs;#Nh@uZ773}lJHPk) zd(Lw|_w)Nbzkhn2bFS+;%jYcDcNP=++`T5Il6VLW<pr%n$SR_9)Cdh#H?-m5Xa$qe zZFUzr*Y~2&FGAPMW3hZq^hNXtehvL7_96P6k;I=Q9NC3!LWPylwNNAG8>8Qfy$Y-2 zVyur_u@U}>j<kN;_$3t@iI!-2Z>)#|u@%n5I`|IKp+w3l5;j=$>M-I9F`fKn=$A-6 z@NyiD)$nmN5<Ahz9KgN!hk5q>N7sZkaHw4v=~?YlQwDOqF0RD;Z~!*!;K9ZIUqE6w z1-r2mHtU$0{7J`M_!Rk%umMi(l$!DjuETVEv~z085quMk;My)>|8GD${yrLs!)OFf zV+E|(HJlsQVDk6>Cy{V2o<c{o4PDh=qucIJbpMvRHhem+jn4HrbS>Nx^Y@|KZ7KS0 zcn)1;`RF3t9Lu+%Yh(u|+<u?Lf`iecXoydt9V^l;HTio%)zAj6M=KnS-Zug5=$+^Q zR-zr=fNsa#=-N4kF6xWBhkCE*&i?m-UKF?nMq+uKj8?n^T}02I6|6_^`vx7^ujs!1 z3+-s>9^w4B0<R$77Co@0;61n+M`4qmsmZ^H{$x+~za8k`D>eD;^;|S`8<4e>vKejY zE%dd#Bf1OScAub;_!_<Mhgg0LJqiDbPF0cKVIZZ@`qR;=tDGR=zPuvZ9v$KJXaq)J zU7Uh8@H85c^_ZMfv?JTlMfed~@mDebOY|>viVF7$+q@F`T%tM&*Fb%=!8T~md&lxj zw1eZLccK+7iLQ_3yQ4p#YvfO~o??ANhb~4tUJGrwA$E2Dw;)lQg1P8{@;bWTPodkW z_H|)o9nlf@#d3HfuEzvkg^l`!RXrh^K<~dJ=I=ox^Z**66`1_{U(d&ax040TDY`w5 zpsV;dw8usJhw}5#IW3D$NmX>p>Z1*`jCP6T{bN2WIv$P046k$kq|6~<$QGm9V=cP> z-$57Wfmr?rdZ3iJK6IoCny-U)q)jaE8toIW--tFiHaZQR!daO7``?d|=uW{JtbwPo z1J)Q2R{eN1l#`>kpdp+UuP=(_OQI{#h&+Y9q}Ip$Ms)RWM?X7$IDq}{d;0_hHgMAo zA+)*ZqMU|~>|S&P4`K4{hE}u&E8#k{LwnJN526t~iLQ-vZVcx~SM>U1w7yw4vj49n zF^>W}@B!NJ9(2yXM_2JL=-mE|HL>Wx(2+*y^%iKwUD41Eh)zNWumIg%52FKEht~H> zf`k>kjV`K>(T*I5<%iHYK7~Gbc1GBa=c660ik^V=@LueMezN%--L}Wj`py^>^8Y~B zSUL27OEe<khs`Ev$eN)Q_d$C;5bfYiXa^^wJ-<C(pC8MYVRFv#2ClEi*;smT*xrw! z&+S4N``1YQ{QZ9t&fRIW$Hj+)8!AMvzy_3ei1`G1|9o_Nu0SL7D*AfeiM|VdLnBrq zGYqf{I_DQht6)dp|Mf^1qN(T{-4=ZSU1U$95qbu_?>RIg>(Pk3jfQ*|x~dPM9Xoqy zh-f7=<jt`O_QiCZk5{_?Um#)6kD?Wn92UOrZ-|x2kHt~A7~5ju;o&1$S8PFk4I0v) z(Cu3wD}0Qvg`S|Z(6{PJbUVI{FX4Nb@PQd4LXX#?H@=Nk@en$)5;ujBR7KzCtzv#4 z+TqD)$d{puaU;4d_hKFV8?CSQ$Z%gDbk~g^$^N&(briVxcA^a)Mn{w~DvaPfY)-Zw z+Ta+hi3`x}wi#>VmpB5?&JOSYiRhYIi`Bgkt>-6v6>H@rQd6EIaVRG>`O9XDM~7AV z8~Q-Xm@rp0&`5Pc%O|2ETY+|b7aF;r(2y6;4UwveF1ikAM|z_74Z|LIXM#jK5?`RJ zwQ^n<VQqAgb;oqfKu3Hl*21;ucKQNcgon{co<tiuZ)}KU6?8E+L$`IW=nd$uNem<5 zi8loe{Ty@zE6@(Sfv)-;(T~vvzlixm=)OOSPQl+;4r`4IYoIfFJrC>SEoetx3?@=u zBavK{(f81ieTW0_OZ0)J<5N?XV_VF?@6e82Ga-z;3%V9YV)AUqzU1ej^&LSwatfWY zGbehEB={^w!jacSBXM=i_lfyYXob_zk<UWUiTlw-`Z&54UO}hkFgl<MCWVGCM)!a9 zm~V{*$X|=aX+Nbq2`d_e&fR#lLwBOvX*t@lSJ0DhJ6hpqXsC~)pA*iT9P%}=3i*y` zc^<k3?n3K*6y2WdG2y=bGG6!>T5-vnL(glX9czqsq%*oEhNBftK%bw3Hn1jMe+#{T z7rK^yMmth;O0WVtpvF_!|IS4R3Uo-kVH(=d0(9;l!y@=J8lm;^`gXjJ{66e}Bd3Ou z<zpN2U!dEy!nE-5zB3w`g;)_^pT_=oTYXDGT|Ae3V{C<&;S}_wT8mb61g)Ud^sr5@ zLhl=d)o=m23tq>o@n`gCzx<Z)O{l);5&jT*w11r-;e%)08hTz2+mr8u4e=4Y9zVsw zc*TtH6OM<_iVkBJtb1E%D1mnHQM7?~(E<L7wsXnMunpUx?Ifm<@MPPHjqq5^*SOu+ zBOSpOxB?y7x9BP_c}JL%mgrjO6!U}7-7yMNF@a~`40QM08S@K}?VCthOky+_9!2+Q z$ys4vr=#1b3KqtiXa!fGi>(!U;`KwHn}~*bCQ@<AlW4<hqc5V1@Kv<KA7S$E{~RRY zqB@SQ+OzHqBdCC`(gx_ZYa7dZp&c5AHasTgr=cC36}=x_v=7JpYIHZ{qaE08x%+=V z2}AZ1TJdQwVBxz$2hK;YS4PVlp(k0JX!lq?5bfwlwBae}b9bN(K8R=GTJ*krOc>&~ zNf@&C&`9h;AN(HOMyK#bY<73p?@Q4|wE;bV4xt??JUi4=8m;FNbpO{w&y_Cdlng^7 zH)=Nf-v=jC;M-_cbSc`?b!bmtK}Y^>EdLliAHGDN`w2Zi3eE`)ltmk;fV;5{I?%Lx zVn@*dm%fMnY^W}wK&zn*H;6YjjW>2cr=}ZvAoWK(Fa*6n53TTKbmX_99aw<g_b57m z=VE>%+TME!65jX;x;no_SNA`$3YNS#RB&aq1A6~;(V=LE@}g6)68V|&`s(O<bV|3N z5&s13XyQ8(hVT?x@!503CzLYi4NcK)))l=z3f&cx(W$u`?f7DJj@QNV?dYQW3~l&V z^!e2LLVM>Rk>UUUM#3I7K(|LLY=ynU4Ji*|XYx;?p9fB&`@HA8@Z1EfNPcGYDQr)E z2U_2S^TU0$uo?L)(T+~S^1lD)k#O<6fUf2b&<1|SmU!;{;RNh~z8mhx^4^Db{3zOi zztKosx*)8TCTIlP;N{o{jr1J!`A0GN?|<JS;T(R5E~0&C$o8Y5{taC$X%B?8P#j&1 zmta$@iY~&;=qR+Fap-eX(E9H{7vWrVH!Q(~bMgp@%kUZW#{K9gl*8zL{Skfe7}~MF z(YZZmVHi<mbfj0J9qEEL+&ktoVm=F9Gh@+6+_sSY?~(f;1%~nkv;&*b3bvyo{TSUw zU&s6}Xh;6QbS%0k%xO*Z`L^h1!7kVwN1*pVh3>8mXh(K0V*gw4Ed?%$ztA~6|G`i} zO?36QL#JXW`rrgih7{eVbJ3G-J$A!AI1{Tpl$!h()lcIh@*@_frfkI2CE?d`Hzi28 zs=F@@p?(&v_$74YucNQgZD?rUN9T4=y#9I2e~-@TPq-G3p;PwgvM};z(C6QXzJu1E z*h#_>?nCGF6xu+s<)Om!(Td8T+o>`du_n>(=xQE;J~ta(Q}fXV9!8&k3di9~@p{dN zljVt&#vzf?7M=5MF@Jq@IJ!2*MsG!@VlFzON6?6^LZ@b3bTiuUN9fx55?up7p^-X` zXS@H?9tjPXKzn{Mx;m?)tG_u~QQKJF4Xto!bR2r$ZRi@h3+>p7czre6;45hTucMKE z4-3(L%7J*{2>RfuXv(9Z;zH<lEQST~oM_2tspy5#ve9yw!~GS|4$MObvJj2n3QV|7 zUWgZVqEqlWI+s77Bl{Vx;5a(+KhXOMtq7KkUV?_W8Ya&Jbi`fIsp*gIuA5@{tt;67 z-f%Ak_G}3nnkS>Lp%3gvr{oCQaLQxBqUdv_V!i@eUoCV1P0;6Cq8;dquBG8<1jav> z2nBagV2>A|tNclHq#Mu%x1$eyjCSM)^x*mno%7Nw!)mXK-roe12N61@UE=lLXgveb zj*dx?@PTRQmr{44J$*8|9=-9M=pM9V2co}5QyvfH#iN%*YoQG`MI+l8ZEr9-;6yeF zdwNT}a2Gn)3(yB2Lg#cf`j*@n%RfOoaxmt9NB4W7CqjKC(6w_BI)L(MWNV|(wL&73 zNa+@DxDKsgC|-f1WBv*Bdp^(MDBOeBVCyHt!F4xYMSc|;>VxRqAH_BJI~v)?R)zZC zL<jbMGSB||l7u}wh%TnT;thqK3cpl#AsVt<(8V(wlaWCqw;FBu1@!q1=$d#39qIm9 zeiR+xU+5H{xta*M|4WgufwJfgRlI=pVtGTf;#O!!yPzEygpM>1y?=7dPe(g+2YTPV zXvZH$r}i1No#!$6`#&2=ILABCMX?_p!SPsr_L?yF<<JTnqjTB;t*8$=fDClRBhe|l z8SVJ;=xQ`#`RKXx#v1m26%wCQ;2fnr9WGpoR@fYq4MqE)BOQWPGy)A}9y;O~vHWiI zt$9CM&mwg3u0ZeKh&lNF)9n9gB$_=Fw#NoEL?59Keu75i0NUUQbi{w7p)a&HjIcOb z@kMB;YoHx!9BmnGk4Cy1-j0J4B(g~y#=&^qv!MeUqnpu+-$q}%pP&)>CHfZ{;=<2` zsW~4jlCO+5)Di9I0Q9~gXg#CRsY=Wu;lZ#F)A4Ea$ov2^@Vj{ZnswnfB?q7<-y7(2 zpWzhz6|FG)`PAe;&z*|qccGCxfOg<WEdL$pSR&=j7s8EaqdhB&uJQ(GsN11a(j9AK zAFP45qZO`0JMtPD`rYUvJ%CQ#Z)iPdz8K2SK|53)3;X`BPQs8jKo?0%w8H*a4#!|$ zybo>gF#7euNi<Ryz7z&f7yTsF9F5Qb^fTc^OveS-5??~^JB1UI`#(Qad@s5!7NaA{ zN9S-$^pohJ=s(d0&R!oXtd7;mw?nsY9$t>KF&#IfQ}PYk@ne{%M56G^Ayjp+3Heso z2&ZB?zJylz3A(tBVpTl<mGDibtI!c=MyI0<EJi!H4$I>Xbc%mPBUt!V_J2JRHD3)E zZa_mn9<5+DdXTI@=kjf|f_-R5j$utKy&*i;1}*Q0b|`^H^dTIEFQHR>$;NPBqmAtU z<XlnUqMC@l-yg#|_%a%yL+D6~zZSmxRTG<$?}yIiB6Nf=p=)MuEI);Ipw#Ojl9!>8 z?SVc&J3+!wyo)yQ6S{hfyb*T6MYx1~9lQ<SL-%vHO(7zE(Zzcc7Ql(<c`-S97p9Sa z2%Y=oG5<`wo_IbMyosK8@1PCrLbu62bTNK|R`e^j#FOYz+-P%H3s<4f4MTTHHrlbt zXvgk|*Y8B1n;Y^8{<ut->!tVr7hb^R$@ONKf&pm9=Aesn5hgo`9<lo{dBDW-BWMSX zp&kDlef}SB1xrUOBxV2AB4NlIp*?MnR@@OgV-IYPkDwJFiT;juG<8duiu2Lus-pGP zMLXIOeXboEk)G&OWMK0D|2>+7A(<F&n1+t%ZuG>vA6?aN#_I>sicg@={e?DMaBC<p zf{y%Lw1eehz8<=Znxng_J0@&sJP9jGpgo+4_IMuJ(`9G~pN`kpqpNyLEZ>iI;K%53 z^!dNgqrA}DsmXtuT^5^?ABDZ~skhnxSCc64PWUNUI~-2_KD6h5M*p!b?2=2+4z@%) z)CKMMbuoV<+VBXpq4Dwh^RfJ8ba!k)Be-W<B82L53S8ZX(GdND_PpS`VJb?Y6_-OF ztbsOs8QP&nG2a$_z9Sl;8_)<(Mh~7DxCocV@+%VC!(wTUj_6wS9OxhO6QeWGIlTw% z*pirk7VW@mv3xr^!mrRN`2~IMcXR+}ycarjF51yV84^BF3msWA^u{*mZnzfxDAgT( z2lPfenuA7ca=e~E8=QgGb9cNx4?W5kq8)h#t$zbD#fg-6NLb-M^gaDu^cQSM{tsM> z_1+Ih^?vjn@fUhjm-rxj%cTk$nMt@3=fr&d9iicC(1v@VQ<s6oeE$z4VMXK7j@*q` z;sfZ7AE9%(H+meMqH}hJj?_Y5O0CiR`lHt;pmTpe8j+=F#2!O;)hbN>{{MOs_H0M= zGfaMwiOG@1@)940IlBZsVCtbAY!%Dfp%wQ>ch3lPKvU4r-+?~2Am$&(gmd!(346L7 z{TRL*T@$~dbDH{57(r3A!V*{$FGefufG(!~==0ezKL;Jy!)S!opdU!y!pivPN9=zu zl;0I9XpA=43GGl%G;{-E`H)yX679&in4gZ`cV~1ix|SBA19=3mz~|7{?m@Kv%DdVB z_PoySP+=?d!OrLneb7)2MBnSV=q{Lt-nTmXV)S)%K-<ue??*fOOU(a?o&$yUgvDGT zLBbF<!yB<Z_Q6$X!v#JLM`uZNbq_)3d?LCwreS%!Kl&23BEJ`_;zgf?``e(A?SKxf zdn`}%Ct>I^V!?2<=h^5;ro{aHXeb{=N4^eyZbS4<bfoX12htuivIo#LasvINb>`lX zFOSLne;ElQ&?Xe5T#G(92yJK_+VcdueeOWtUbE3%@@%}m1?|xLXnnhJAAXIF_|;Ft z^|#P^wqx@1|ITEB0|?*Z!nar%SM3Ym+uezN#yf>pT<Wthf(mFv>Z5bo8r}Z`V)-O= z%I-v8<4dsyzK2fTDNO$Szu4zt-(G@VsD;jPYfOG1L66{$XlT2}{PpNm4MazjjYcXj z=5IzLIURf8{Fwg%z3)#<{{COVFT$cJf;n91j5fFtJy15G5!i_?%Ae7>O!+c=s=Wx^ z9Zk_GxgI?S#$aEZi#B)&ouXgS`%itz{&#U)@Kva|8al!&(Z$pbeV_*#>VC0&M9hyv z53rf&NSEL!T#HWO#b1Zr(FWbNL$Mkr&?9=)*NM>MtrWDS;4^HG<@bk|&rN8<E3iI3 zk5=>pRzdz8M)FIps^}W%fv$m3XajfRH~2V?#Jj!;zi03}8qunWZ^NhBtI-N>K|{D0 zT?@~mBiV{J{1bZLncsyeNXKW%Uy0uTBieAm??b)ia1i-^=*hPc?f5^@0VOW|Ar$n% z?iQeP^$|J+`_NVU9l9vbJs7?(P#T?@N$8rGj!xY?beAkg52n@V;(H(O#`1^4Z$><g z37ShePQnn4JscYDdn80)AbJ3ei_SskdL=s78_>nN16}>ie+(UNgUMZj-gkX8CweOy z;RTrd`~OdoFccr5JwNlOu<c5qUz(kVj=Ukd7Mh_AbdLFcXv9XKyCoOhmbah>&%NkD zwg@ZXqw)GXSdb8;d`!Yc^C{Z16PSfXehxny8jDlNe}sm->o4K;+Z&C@40P@viav{u zd@H(UK1HYKSTyZuxLyhqE{bX-2I4U6g72WKv-Gc_fy<+vurcL>(T*-fN4O5{*sJKi z-;7Sleyob$qY){7EJWgBbZu2R#{REI;xY=Z$00ZyH=$F~<+re!Z^c{4FGn9Ne>}V; zYoZO`hDPFUbgCXjr{qaY?jm&6Z$+Q~8GY`L<LrNXmU1HWycoLZYN2bPZL}MD6c0e> z_(n8B+2~0*8w=uGw1N3(1Iy43twh^djV1Brn14S(!bSEOUXFjGi>txOFlQ~%k@P?- z?vGYHG?tHw`EfBn1)Y-H&<5wA^(~J1C(-9$LI;}INWu~AL672ZqbJZ+d*<(<$LC;m z@)cvgD|&q}+Q6uopNs>@--dSl02+bA=$bi-cJPc-$win*DMrEy%A+^d#>&_Lt)M?T z6@$@Lor6|%E4r!|#{4RDd%lL={{cEh`_MIT3LSB=KSDi~G5Py{jY&B2_UMEC&^a24 zHaHpGo^#^$RcM7TVsqS%PhinMQ&U>w^XQ`f9h+gbe}?Tk4E+Yi{a6Wi;Cb%<6C_-{ zMg9t}#qwB}d`p~xxp)_zMDM@lUt#qZ_&Ypz9lFg%qa%C}-G<Mh1KEi!@!M$S)8VV_ z;h3o7jU=4Q{pbTnupFL77fU&IvyrHbPDx{Qs#>DYU4t&RZZUr&I;B}?WXH$yJJ3aZ z9~!|WDg6CY7vDMxtY8y5hda;;zKZ2PqWArYcA#*9;JIjsFT`5d2i-+8(M9$uj>EUm z0W>L?mK;!L^ySpEAiw`qk;Hfk?CD~(p*3hEUPTw#4zz>&(T@FseggUnechH$4fi)d z8)_Hx{i8Xtd<J^|1895CCrB8Ix6qOALmN6A%TGm%rKKfTeMPimjnO&oj6OdSt@u{7 z!^_bIo{Mfq>)jRIj}A2P3kiGtH(JrTXQU+;QI%+Ov}1kHZ8r?vB~!3I&O#gBfUc!a z(fSIX89G`PtB|jYHrN-9;4q|~M9NqaRy-Z;`2w`TC(yahM;m+{?cjE_g8ec7GumL< zSz*pg<5T3*@mlZ4PFS{3XeSG;e;Quke!7Q*4LpIa_UF-6{Yor<3q9j^qN{#)EZ>KQ z`1_du9Ve4dEu6+Or2%vi&OjTSjjov`=)sha$^E~FgrPYc{R4fVP?0ca7ep&Z8=#SC zh2GZz9Y8;{gG2Ft9Er`bK+&}1`Op$OkRO3g-HVvGfy5yab+Fw((vshTorvwo7e719 zU0?J_o{pYuPv9K<6r19(Vrj`QuOGwe<Ud0Xq%(`BrKDpWwEk<+dZ*)MxUD$*-=pv^ z3aq%oIdNZNE%M{h2OmQ_up4XOKhX-RoST;Xdw~7W`#(e@a~hqRvr2?HzW`mNwb0$u zA(r1zg8gqn9tF<*9cYN|K_B=O+v7=0#}*~iQU+rNI>%eE2)>Ipya!#xU!YU*3%Zt0 zplj$fI`^sPg|$&WLBf4m9i78QXo%XN70!v*7sUJuw4<xhj;}*MKWs%8*CBM|Y3B#e zk5-O0jJAs=u8WBgScnI2Mi=94=;E4>c4P&*%~qogyoPSW9as}TNAD|KDxM=~hpM12 zu~z8)ThX`aE~NfM$}b_2ays5nymV-&EIPtE=$yAkBa?%k-Rp51?!!m%u?s?nuemTp zv`;h>oq{~H15?om-h~C+|M!vbv)g=h1P`DiTozr6&gC2E+-^lH*o)5nS7-x=qsP$* z{*6xU*=54@i_kSw3B6t&%h7&HV-i+)9oo=9On$YB_BeqBa5mb|J?Q<5VtzUL+^Sf< z7VX$e=oD^3>-iA<obe@E&k0O^{ePOod<xFGD1>@3dc)i3qWlnT;0tv1eiN@3C>z#H zQFQyBheqz|Sl$O6=|D7cIoJzt!8Z6wS@yp@D|>O+$JNjtKa7U%S+s)J&<?$i$p_KJ zTK19<iArcaHPPoAV=HWrRd6=iu@~?T+=33Ib2;|E58PBPEUKH)FRz!PAEolqknKQM z^Y<}dAU!Sl?Yax_a>^&72huZm74AnHNG~5oeie2me=R<N%g_N`ov09QxE3A3AZ*EG z=isH}pSv_1Kzq=sC|5Bp`2)ln=-Y4zI@goYH8B&tZ#G)rqUcIAqU)k>L=zvx8$L%L zJcJ$a1fGR0DuoEOLo4hX%|u6#i}&G_SYE7h82Lr${f)5_UXAHE679$wB(nVee@LXP zLr1U;ePAcn!jo7TD^>|}*b&_w*P~N44xO5Nu_Zo*9#lV~YveR8$3j)plK)eiCvh(M zi>syaHz3)6&yaYUf_Bx@l7AZYB)V8~YlH~QKs$Cf+M#*qK7IqeZ%fR7j7ID;bkTl; zM&KB_#!jPasd&v$UKx|W|6iYkpMaX9+oY!#a41?~ZgetQ@vUfu_n~Xx5%jZQe$0Q2 z-uEMV-#^iMiq;APDT&r!29x{0a=cI*?ZD+|2(LjO?1wJ0LFhR!3Tt2<`c_+xj&ucj z|FdYs)}!^k9{mvQ&^PD@l;3Kx|ErUjRXZ$-=h2>TLPNU~4fTGsqVLg@@D$p>pJ;;x z>V*3WqidrW+OaC=NNb=2Xox=73SGSI>m<U39u&ALZ-|aWLpmAlz=P;wT86%qo<J*n z745)Qw89V2Io^vE@fS2Q=hY1nEssuh1N3}opCDmKhGAu#fc9`1dH}6NSNTRXBA=im zI*3+$JX)Y$c&-@QvGdUmrK9y%M|VjRwEkY`fD+e}@PW)&FdCiXNoYh8_%_Z#L)+`J zFv4ssPktuau_w?Dtw$T)f<|gb%zuN|k^c#+;x+Y?CQ?R|xRQbgu`TYwVR%u4wB)Zy z%|Lrv<nj=*lITaXdT7I4&=KB<HkgBUbVkfCi9U<o_ZGUAcH>3v|L;jSl7d%+P*;pz zg>J9D=mXj4+)YP!#{#qiPhvTI8IzwGu{HUV=qH^f4MXUA<E`Y!U<*8srD;Fq@<!n; z)fuaiABRR_Ir_kN*c6914xi^&VhhW$8CGtRmi(5>5cIjtn2m+5OiTV%+zFUT{%!1! zwVI|SfBb$YCVa_!O~Rh1HA_qWQ>^l62<M^KSEEy~16@3O(UE_J&gD^Tju&1Prr<iP zNq!XO;X`;W7HgiC{9iQOh?~j3(4776>vBSiu-acjx6=pcV)__u@SB)Fj84VxXvYe- zOiTV_^IGT{nvD(d9lQ@yTBW6Az&z}Q$FT=?XdM>gvexW>D?CMkp)S%UEoCCkL8s!( zwqfq-VoUNJ(OoeIE8}AHB;1Vd_n+}`EO~W!?iFlLeh)g3a@PbaqwUs8kg&q$*abVI zp<RNm)~C@2H=_IgEp)r?jMqPl`6KcAN%a1L?c#}uPGvFlWUYd3&nwVHoM=J93VWcT zzX6@=q0t<)!ikuC06pR6VHI439xNZm>p!B;pGJ2}q4r@HT#R<0F}A^W$W-wE{~=MC zg8jJ32RfuB|8n`eXv1qdhOYsi$EoDMK^w^E6goTt9Y8J`$*JgbccW`)9vXq=Xhhee z5qJlafB)+v5<a*u-f$2-a!;WZmFOHsej(aWO>`<6Mq8ti>x#ZB`k>EUAIk^F{7q;( zx#$3<W4inQP7-I}Q)mOvqBp*Z_H-NCz^+*SS@aNk|L<sp1-pcLilV#WTzn5Z<K<YU zYv|y$Xnnmf`TIWuNEoW2XoY#`2&bVPy9*uB+~`8|zGdi$S7BXz2It^c=-L={ZCdgt zp9|3IZ$(c;D|ci6yD$56OH2N9nWwQ4`TE_{l0O9>iA{VEJtt1b{8c@|KA(i{n&;3+ zrSuGot_XT`mqT~c<!FbmMqj(#&?7&mXMF$PM}ez)3A$>Z$5ea=4b^+-gS*j_@)#PS z;=RJEz6gC?S4Sh&3Vp6U8rg2>Nq7TV|3~P3KO{(a<Im^;b246N)H{?nk6we0pevTd zeledNuTMe`pj*%nE{{jIpo{riw1a=6+qG1mFyKTz685ki8p2-a;=2(Y;V87nlhB6m z!3y{&8saTzg`c7KpG4n=1^b4GRY31+fu4B1(ffxZ+cJ?dgM=Meg7$C~TG1x-z<59U zIoiP^Xv9uL|Aj8nGp-BUv?yBNCFtDOKqJ>Q=C8r}<ojas@BhyxQImp4&?)!;ZRnhS zp@K5_1Nj>0HY?db%w1XZV7V0SP*b#_HfY4U;=gbR-iCv&57&P{JA4e2pZ`yhu;R1< zp~17!iY`G%QVo6J3UpsLMI$v4eQququ?NwPuS6H~T6B?Z#o72idSAaA!bvz3!|(r* zsKJE<I#;XFvwjmA!rf?xzC%ZLG<wF3VJ(!2Hp7d!J`gA16s&^Bu`!k%7&_1!U1Ng= zvj1HaqbabVThRk$K05M6=yqF)c5pLx!k^LSuFMFb?~G1GFSMiCXnm8=eSR0(u{G#B z;2pI7y%~u(G74O5N73zb8Xf5+gF-~=N86+4z>R1JrpEGn(GjggSO4?qeY?>6enlgi zIyiKw6uO%lB}jNfC$s}Mpf`>}J1`xc>jmftpT>H)72SrX(EBeM5+YO^-Cq5$E{?-= zd>pIc+jtrNimru3#mtbXi*}$X8nTY);u(d8YApI0?-sP8P4W5>^toeb1PTldi?uj9 z!t>GHQ4Q^IJ+!`_!9+?1344+qog8nt9bL`yaRDwxw^99Jp@Q}3oNhtqbU(W4e??Ec zLc_y{(+X%uI-(uD5shp%HuLlU3=&Skrg&i&I)?}GG#1KAOa2wiLL<_Wzlwb`x(zS5 zDJ-&{_#OF7?1vpkh7LTAUCF<Jo-5~!3fr|iIz|2QCfZLKA1@q0LvsWT*(r2nDcNBT z&%w@Q>!G_Ofv)!3&;i_wKKDq>uR<5|t9U!^LnD!q6Yd*_$^Aby7Tk^nxZxi3z?qAN z>;W{iE71;ZK<D~BG}QahwQ?Mt%73EwpEWv6;U#FutD<k!W@yJ-j%NQm$DJs!!QN<t z*P|o63B5iVZD2AQp<814J!mKwMW07I_(Al`=+Du=(cMyPOo&+dG3<Z0SA7cH79G)% zO^eP(JMs`3%H`<DUPBk(9`wZg6&=7?xnYjaMk7%Q-AxtHfwVyva~Jer`!+$s1`6bb z8_q;4JSXNWqa&`1_PiMyx@*yj`{PwO6@3?MKu^9cXa_!y`2*-0`3;?lGscDvC(4k> zq#zyh@OE@{|B095730Del_T*Q^6PN0*Rc=YFg|<)dkI~fXG};-xdnTm9o&Nz@pr6( zWhbU3{}f{zZ0-Ah7YR?Q(v!k_xg9279=MwF<LHz;JUMji8JtD_F#081-pyfkpTvgb zr%p*r{vq-g@ka9ZPYqw|9Y^zBrtz7w03TNI4fp>c)<6deo|>MPvXdK5+>(|uocz{X zL+I<=7QS3=ik-MVA3ch{#ya>1`gW@}Gkka*jKj$<!5(<V?O|ZoVGHte(EC5Yj_&_L zcZ3l3#9HK6V14`$yWttL!pQnyP4f3*8{B{{sseY0{ah5MkS~dSaW1+B4q*d4fkUzS zU7^1FFyX4*M#62k1Fy#~(F(4-JAA|7e)Mg26q{hN+2Lqyk5-(ESK|}tn)n&3<JEJ* zt{Q`b$UlZg=B#@{y`%48|2rq|QP34@-W%p}3c4s$=Y|et;SJ=sqKl}~ePPvi#=Ycc zql+zbUf7;@ppjY@-HuMhDKxU3=7*Qj^!dzva|%{aFap29?%3u2Frr7W1^I*MqO7)n zGaDa4^JhO07UxVf)bpdu(QUdKouZe}ZTSXzkbQ`5`@IPgKKKRtz#)7EkE2twc47E# z_>0(x{AcKHId4%~@-LXS#mC8?!b@4S%O7OB;hPVI#d~mZsQ(0dJ``9IPRJryntY-R z2@i(L&;zCow!l8<Ij{&_8@tgSe-k~3j_fD&rSm&_^qxjTUwmn3xG8#HJM?;YtcQc} zI`{wmB&^_Pv;!y6kr!STERI%iKKk+~heqmBG^DlB0W?P&=!TUs154s8^!_Ed6`#PC zn7!N%vj3hXVS^j69BxJ*IDo!feu~!%JscuX4DC=!bS^KB`HJYfp*9-owrIUw@E_O{ z9Y6-!@k~s9{vU6Gf?LrC?}_<^XhSPv{%N$Lm(h`KjrotG-=HVuQFLzqMjI^kNT|0A z+Tlyl=c{AF8=H`Dj=N(Y%)mPMGA0)#y3dcJXMD9s!;jG>p!c1|hFE7s_%YrvwBui5 z4jzp8zK?|t3__<o>oNAfJsd-Ub3YCZ*(|i-dyvJP@?gv_j@KVYpIZ}s7LD8s(T!M* z{8n_)9z{EJ0{y^p8h!r4m5C6Fi&ut*YoQ^kkG_VRU^-rl_IM0BRg=)j&BS)N6kFi; zF<<5Ja88WIij;qjJ+Z(OVLSK6OUX}3kZ4ch;dtRN+VgXs46ofL=xUvgHnbV7u;{9A z1lPr3<gddjxCt-ALs%KhJ{1nK*4T;sUDyFX!7iAnusVFVdJKBQi|9+I;2Pde*b{x= zVH|@;@ERQOba*SSM4$T$&%^f5gsHp%T~lMwNKHp0x(JQnGg!g>{|X7`?hACkevi)8 zpD~}dHdJ^4+CYt%Z-IV<>VZ}`8eKC}V)-3dgZyJ?#CD<|*-oILKlfQ9#{R#YM0E-V zU{#!jE|TZa^I$t(fJg8OOnWX=bR||I-v=MZsnLq-LPxiw1Nj>L?06U*XyNC>S}K8s zX+Nb52}f2D4N+rsL|xI)^+zkpL+5yEEMJL^Xd@blPtlQ`L?c<|g|K*Q<4W>f@gcU; z33PySUt<3+A@LLmkI-xK!vS&~I(Ng+4vdfad(e|>DcaFz(8#=ncI*pWg=ef!Oa3dj zwdh)E_j35w?nCH6u74#=>Cji$|28y<0#B}4*cu-|%lDy+?hqy;@oLzvdDw;W8Q2s* z!nRm^LzwGc$l^+wY@QJ>#fxzB#<Y}$lz;hJ`1!#2*V+HIDJb*?2L(4Y#98E<ZVGd? z1wEKPKu5eEotod#5T|Yq9V#8Ig5K8<z1|spJ_8-lSoHZB=n;Hxf`n)Ka&!vTpf|pT zE}Hkzm&%W^JoU|Ry+pJ;I+u0P2zH3}MLRMSlLrl2|HEkg>(F`=n@HHBy=afVMIStl zZkr-+g$L@Ob9WWGirb-!t{XbiY_tQnqHAPs^bxe7b!h$D@GSfk33wu9KZ$}Ae1oa@ zJ=)X5=u!L^I>)J7!e_n~=!g<%gDcQ&`W(9dKSU$?IX1>a=(fFdYv_1CGy;S14EKL7 z2_Kk<RxlGC;oRg6ynN7}FGqX67VTI*+R@k0&j~xx=Z~NfJ&C@|3cejIgq9aW7jqd* z{`=p{NK~bu3A$JYqZN-wLpLjyFORN6L%apO?_>17gXlIqjdrNYJ7EpA!an3PusObr z&*2}Ka3rg@g&wZMH1g|Xek0oBH_=751C7L?c>NEwBd5{GobzsY%Uys@%_#K#o6&ae zMk6#2ljq30?0*-}Gx5gF=z|}ji|uRl!NbU6N%<8G>2GL7e?-%^hYl3SM=39j*7FK_ z-#ci7yU+vcTQt)D+Rpx;MB<$HLdAFCL*(b;gIMGJup73Z9r+AhD+ka9enBJlFZ3&< zf*+)%Jc;R;joYv$Hrf$7n2B}BkHX7wX(ATvLMuq!89v{aNB4hsY=&d760XIoaSysk z%YGPM!<Dc;`6=kCe->xrVf4PyAB6!-LI*G%Z7(s0gdtsx&f#<DoV^^&x5fMpG<08~ zYvC07@+q+^{MJlu^!ihnTr=q6+<}IEe=I+S9?gFvQ=CXCzdPJm12ehM4BhW5@OJzf z3p4q{_N1l!NPf)6;g?iz_$2%))d_SYOZSEY>s4&&b7)5@d>Tex8=b1l(eftAJp2D@ z5-x_0(Hqc_j6oxE7y7_FG?dHGxqku|<BPZ&yX_0V|NAd|nEb@g;)l%7!wGpY+JSm8 ze+8DH{ge(QJdp;VAsdN?Xc~6FN6-g<M0d-tXz0)QBAk5X(cRG!?O<#4{!Y<u=oI%x zJAOTS{|HR}{lAeU+$NLIReoFaZuEo6JhZ|m&~3RU=3hc1^D0{L+h_;&pbdVB)$m)a zjm5qUpR}5xyI}a2?EmT{7E$0fc@vx9(P)jY!l&7xcopRjqT6OKx<-n99lk2=h*y%o z4Kwf!?1vThhwVKT?;-y?8u8l?gqPQu-z365zx11Mgl@zJ+^`$FVBv4W8t98Is)6XX zd=#hQChU(bz6;-ASb`nNAH`nS^!sr1&cmC?A4bc2{}8^zvL->ID+Om93^(>dNANTb z!s3U5xoAUsurJm-oEH8;Vf1(0K>3g(;ra4ErlkxdKLZEjw>T8r{S@9cYjFhm#9k8D zkZApLSQK}ob2kTT;C%GJcpaVl_t3@qar8U%wS63&(^KfKsrpMOuZsoAH;6Vw*HRN~ z<Nj|>VhjbhVR<}>u7wMZhPiEv70FLScf|^<g<H|Ja~yrH+^^wtK}+<$Oe}}9unImI z^E=T29>wI(|4))|gny&Epy;u%noFTKRz$aD^_XuOZH3<74joYs^uE5Bjw8_Ba5uWE z?nmoejNbo<*IkW|lXx1}q7@GKEj%zB-BvkhNT;F?&O|G|E9U2;6)%eUW%2q7^eA5w z%Qr+f#p_!!`TKu6NZ7z9@rJL^3cp1=bQo>$M9lw<u7$$K!*eCkj$MSF2kGc@HPHby zMAt}Lw4L_RZpYdGhU_{D((xvAam_|Uwis>rQS^vjjgIIww80P13U|fw&(H>s#Or^c z9r_#XK#>!n-eTxW>HHJye;=q!foq@vns15cV^_3-O!OoigI07qCZ_-$>HO$2wBxJL z4nB+Sq8HJD?MDZ26m2ghaWYhNHoD(Sp&t$>p}XKd^v2iF3b&&j+lhYW`yQRDf1w>u z{XKNx+~@`9bLG%TRgBg|2asqG3!0%7wMFN)Bl=)3v_t*k^<1=~iD)FIM{h$zIt!iB z2hn;~qYb@?KKEKI--@@o|96sbggs7$h6bYfiD>9&#{7LTzYGoeQ?dL-w1Lf-j1by^ zomdGEpdBsrM_5DuKnGe5&-I%!l}J>hpds4B478#wv?JN*fpRlCcgwIMK7&<p7rHqA zLPnHQ{LlO{B?@dRQX*$`W_DhBR(5(udUoc7^syO(^7oc4aO|o|IXQWm=@W+Mqz}s+ zo0p!QGd62zR_2iOoT174ax+Jd%*xEmf4hHyPU#Kv#^#L5nw*(FDQ8@6`p}%*QR!oo z&!uOLP0!8D7&6I1QzO&!#tj;km6w;5lbzQj|C}iWD*q$R2Nu?yRp8PJqcZdIGKOWQ zv>n2OV~1y^_Z*&)eN*~%IpfmfrTosb3RJzgeRfvf@btXQv17Bchoz4jon9#~<?5{e zyYSz=`CqObn7*V^-ht^$^K(}gSU2dB+`OFZjFArEe`_^Ay->m47njZ)pGAZiNT%KU zckTIOD-|qJa^a*#1)n^ZfMw=pGSXyp(ud{bU);E0$04OF<)v5se<NKjf6&r`+X^Q# z4@`e>d}eya$PlZ+FqTk{9iEjJqG|MKuXcJI<lu41i03(ax{{Z}f2kuc2Akjy&KWr} zb8s^H|0CwLQ~C_gNOnGbLe|KUPHvO@rcV@nw$Q=_YYUbvF>dq_+73;R&dnJ$dTjpp zYYX-%Q~1A!+w|RncNZ`7=1W6|W@nCd<z!}MXO3c3jLXbU@5%ak>(hcacWu_^&Bun1 zq@+g{BO8}jGkrp4Zu*-W2Jv5SO>db!c0x|>Sne2<nVm6scy89<;bXIgjiq0?L-Mbx zmYQF+{k0i+d9jN2!*kQGW}%E5nUR~GkzF%=+^F<S!t>?^=7T3Q)7xfc=VnsLxa?s( zGd?GG@;DmH%%X`V`NzAZzE!N`zbhD&nUOmvd1+z(z|?9DyZl!N=*)jzNon=(WO5Kg z7)TqIV`kpJyPN;jz|@*m+I6?<v7gK|@ksg4qW{tL|NG*B>C0S*OMEK7$gI@&CRK`y zF)xeWhxq+(P46m@c4eh9Z!TesqjTTfFqB(!h7jEU8o<KQy;9H5FJ2|B;RU7I*6N&* zHPR-MQO*qgTlnF&)bxcTny2lp)+y7NIaNb5^Tsk)Im4M)oBi);8kRXcGdsU!i?pJ* zR%MhK*^@J~e5&gIe<@U3IJb3L+5BOf)1E7u$jVJ0p21vOZ5~tiACuuM#ksT(nYnpm zGe?dbTRZ(f764B;?L#s~vEs>uxlPZqyZ_q)m^>~$FJsiG%#qow`HZ~u{EI$Fd#y;7 yAuJeUmFz@zdb_Ob37KrOY^N|i<EF9WI0lG({?5H=pOq>4A5)jV>bJBD3;Z8#g@%Oy delta 70908 zcmX`!dAyEA|G@G49FjH3UY29u_kG{8?@I`YY{`~N$a2#n6rxfnB}pWOB&9{E6jG@0 zh)SubL@Gu4eLnZh>-YTgo|)^qX1?>Cnd`pKA<v>e^1l01-sI7%GC!K&e;Iiai6U5J zjy1e0?f<=;Qc>zXu?${;ld&<*#vJ%Q`ow401^46CSTb)~s^2D9lX^eQhVzi?$;4x! zkl2VNxUdI1;Aym@hWXMGxo{2^#mBHXZpI1tIX1<P`O^|La4y!yZRkK}FfU%foS3^n zTA~vc!F-IL7)ikyPDclrg;(OUSPVB~K|FwF=w~#bYz5O2BrQ=8ooR(wzZOeV?~M&` zN~~{22R@9BSFTW6B0J+Js!_<mhG=U0qba=wjr>l$3g@DMJ&6Xe9=&fH8sJWJ0$-zn zT|zT@W#KT9nwXV(cl5q~m~2R45`{9j32($h*by6CotC%>@53ALM|5f0Toc+CqNzWJ zc3i7STA~>?#{4)HbK@d(V$Vc3pc#0lNLn(Hg~Co6vg2O#fy3xbPogusfOeR-XsA~} z?`wfou{*ZJ8E7Ey#rEB3zZbANW+@gXQV+fF(PGJP!*Uu-^&0enH={e_jr(K$2wukZ zAJE<Y3ogggSRCgU4}q*l*ZK^$!loH%i9vWbX2Rp>=KLW^!I_-F_Lx>8taV2$M13F@ zz=`OZ&qvqx30#Tmu^RR$8Fu&G_zLv}=;ph&R9eC%o{mm%E4r8VpyMXLreG?5Lzm)j z^u|Q#utxdN>qRghmO+=IA@;>?n1O518GVeNh68B8r=$O({pTnXGH?|#!DONU1s|*y z8WIiAUEL!(5Zx@dpy&5CbTcK<z~-ZS<uP<uKaU3b0UE&n(Efiy_sH*94(papOHB0q z52WCXzCbtI&*-_&TrQ-x6dF)ZwEafxhSSj$??rcgw(@C-k=Pz<;U;v`{eWGtP=(O{ z2pmB@iFFx2@dE{4rNt_Snf6C#IwX24I+JO!{s21g<7i;}&^0}Z?wK>#6SG$e85)SL z^$0XG6VW~NASO-SatfyMB{UPSp$~k54saCP;Ysv`Qmb-U%j?jk8Gr^n6b*DddWw?h z^K;Q9Sd8w0r_u3NSLXa1z{~N5?a^Imho56-{1(kn^(tX=jX`()Z1gz3hVF^C&<~kC z*aj0-(-M=REtbOVXa>GV1Nf&Z=il9)sajg1JQhSV&>TH>z0m;2pyzu!I)mlt?q3z_ zm(UqsRy{m-B^IV$4*kq%fj&1dIt<Os=p+T#Y!a5mh3L#*LwEE0XaL92H9LpSFiVYa z>>6Md>iw_+&PI3lM)b{i7*m_GW?Etn_4a6eKl&k+%v&p@v_85^d!ms(gJxz8I+HhJ z{Yy0RQ)pm+p?e@}?XbpIqDyi$nvslXCG@$vXzE*rdNR>5Ug(3VU5{>-ThTSW3msq% zX2ykRV2jcF*2e3vpqq9Z8rW_$kgw4Dj-yNa3mQnKI$r1e<)&~g4f)Z5`r$)(6Ar`Q z@kPA8Zd#%~US2OPu^yY_6L=c$zz6H6C3;|5gK+$M;dRuX$6j~|Jsmw8hNT*e<rzQm z00r0j6|9B(FaxtR3cJ4?n#u`iMrK48M3<v8e-WMGo9L45N8by-#P&qv@O%NZzcQHg z!Ri!@tT~#RF6i#>hi=aCXiDeC_GRc2Y(zKZ2k1Zt(fdxJfnG%W&(S3Ge+|0!70{)w z*@W|Np;>I`gwEi4^h0DE8o*pMz?JC08{+l%WBu#sIkdm5O~ZZp(f%r+fi^=k(;e+^ zR8!8sGoDO?1Ko$tV0paZrRbYz2fNS!zCves2JJA>EL^`DO>JeYiuKSL4@dhQhv_&2 zOX59A3ZBE~&|SI<-Q}O79UYE-k8aN2&_K?kGtJ&S)C*#2rdWgaW@ta-(WSf->*750 zLu?1O#pH1c#VJ&35jI^%tWAA1*1;9n2)~TxZ5dv@UC}pN66@g;Xom-I4i;&ZmUsl8 zLo?jy+7NJC^!?HcIiATxe+qt;8jOB58iHnGM68cTXEFg@v%6w_Hk#6T(dB5yUW)bC z(apCDU4s9i&wm#^i>dRUXdQ0If)1P;O>JTH1yVM)S4IP@i_WMax+HDT0lJ_|(<io% z#MBa?1K)}6nS0UuAI3bM|0gIo(0VlDSJ0X4Ks(rrc5na<?Az#R^!|(J8s}^io-2h0 zS{0p8O?2SK=<^-X!24p-3xg;)&^WYy2O7XV=)m*QnLUB+aXk*i^Js^C+J+8?qB9$f zJ~sgk@E&xj9!B@dvuOWE+H(Gl@CO?73>w)5wBt<eLSR>-59E(#L@S~9*F^_xif*n> z(Vo$M(ZOh@Z$>9Pwp}uGa61hKFeQ3lykSA~k?0aML(60R#puT9mgqJ#;O)`fXn<d$ z?~m`%3I3g=;J{hhhZJ3jK3F1J8BJ+DtccBVDUL$Vd6o|0`TFS0TcXdmM_)|6(9Jp) z4d5<xNoJ$tCLgC@DxSgexH{H9MQ8ds8tHfF0B2(Rd9;JeI|lQh_g#Z-zVhh6mC*^* zM+0jS?SurBO!Ntb#4vO%Z%5Z?3Oe9SG?3Y7>K;QoegS9V7WBRbox=6zn3{R4k45jl z8x3$i8u&8I<LCb>3cicCU^zUDrYgO22;@pM@&afFCD7em6`ff#G~jk<AYG!@p_v$f z4mb$S^eyPO=y90W^S_XSYr6^!<Wuxr{ySE|Y+b@TyB@Zn-W#jo<JcN^;xxRXYj{;Z zh<=~gi3WHAuffx3zd5>vdI?P0(1e0B>WR*LX!JI8#xu}OGY?JWlkxf*bZNGr1AKrE z_$}JsDRkx+(HB&f?%{gTXxZ-Z=l^Onn8Lc~K#kGVbwX3$4ehu;rUFD$eH%K^WHhk3 z(Z%R<&!8E75&ew$6w`4Z8rbLEIse{xj0R_V5`EMC73<l0#I;8UD1io21)X_a^tsk( zU_D~{pjaOlofg|4Km%WjKDQznZ&;58vJK6^hv;tq5`Ewl8o=4uehCfas-9spU4uT? zB-$Ar;0E-E+FQ_9@7-7#Uq>^L{DFcuo{3&U1If`V3{U{CrCuDH<52Yas(Afn^sCxd z^aqmz=rO+hy6~+xH@cKV(Fxp)4txhPv1DR81!r<!bUr%3V`xXu#QNIkX0)Ss(C2oe z8TuT}z!7vpKck!bZ*;)iy~7d}j+Vnrp8q-&yrDs~7208EbWM9jZ$bmRH97^oZx;H( znTH0p8r{sB(EGQdf$c!|)&cas6YBXtOTmaQp=*_+Pk68t+Fli3$3|#Cf1<lSbKh`Z zeslsE==~MZ0qVu;t>X1A@p@l0z+ss5fl(CfcoLe@S?KOwfPSxE9^HV>cn8|SF7)}& z&;gI4Gd>yH|A_VU>%;Y2==H+rbEU73-~VgSU;s_y4V};d`k)=(fCe-&)+eEX-ivlL zFS-;Ba5Z{*)}znAi>2_B*nSqPQqR(l^FM(?oqpkg7tme&HV((LI2Nz(A3ENN&R}n> zAC7*5uI-P}f6&b391zyNI2vd*G_c0eZb=IHXc&riFd5yo51<3BKxeQH?eH~p=DTA3 zK)n7#^mlZi|Dri>2=&6zvS@#`qRD0y+?^fKP1PUmV064;GP=3$i}eNZ`ZDy>?D<%K z5%*Gm9X+;l2Zn(bp-Z<MUD6lPiEKi~NhUs^;M(tx7rsGLbPmlx)*Hh&oxJFWOl$Oo zGZ+nQDmsB#=s=6n0anHOYv{lqq8Z*3>&H@Z{=SbFPQ?rVqM67vD0G+)4Wv}8SB>>1 z=)mn_y)PR0kmy7-zz5L49z~b>S+u{c);<3_D0IO?SOLoqPD@n69_WqJ(Oo?!`VgA> z$I!KWBKkbKbg!TTZ%3csh0gp7bZLH!*MGyLsriROSxnrNmUscm;RxK1qp;DCw8Rcv zje~IX(C}fh2OZ$DVIjp=q5~8_XId=QYsGpaG~jM%paX`*&;OA$xVE>V8F&!w=v6dz zZ=nzDK~sJh-7_cA4$q^fBJ=QYJr{btDEfRQ^!bKpzirVa?m9dfUb%y4C_}>}G<D0- zwR|4!cw6*+w8Kx(cm7xCX8Q~M{XzB-A=RbOe(GR-Y=&lJ61K&8=<}Z^DfngZG&aFJ zH-`wjq67CqQ#=TbcoaIbsj)s6eX}h?2Y4G@>jUUFpA+c)*+zzb3ZfY(iDoickwQfZ z4bfB%LqCMZ<8?R({qA-Q2jHLR06lLB_YK2x)Tf~Vtiq1?I&Q%%qrx9lyoJ@M-!wX8 zY7r7xGVuZhJKTz<Y!@2g=V*jqVN?7iwpSh#PD5?<zD8(fTA>;1g{|=hbg5RNfo(+J ztRKeuSE=iqzq1rfQQFwhac(pd1<*}XGPYMk2ds-8zozH_t<WXxfllNObRx6R`yN93 ze-u4!E3px-!LpwJ?<u(Xa*hk1N;T0N2V*82fo{f8=zAcE4mb;|<MZh8J%k3HxHYVG zPBeoB(IqX1W}q25-gTJtmqAk~IFqGlq-*do+=4%1*YROy^=}KCtphfueJtLIFJN0N zd3)IHx1jZv=uA&xZ7g?3_>pY@8t~COIR76|xNJh$6ua>S>ffU?S$Jny+b7XqHmyh3 zau=4yuh9uyHZg4C(pZ6dSG0XHx_KW*kK0S=d*-9q{{2MGza3ws!2t_T3K=Mau3as( zy*|1m*P_R<L%e=nZ10CI%^);`BjWW5@%mk{eFhrPe01qnB`LUjzd$?qA^K}<{{tN` z%j94l^!_5~3#SSiU>kJv^+4|*iZ1CmERNIB7u9m~{tf67B;TaqCixDH{2ZFP^t*y3 z(2kp9W$b~KFp0hoUcjE1bxK-d84f@LJC6pEXKMJ-s|Z>zhHmN#!DONe1yfrCO?f>u z6OGaH+zLHTonm|M*nR_g|8R6hqtHMnM(4!#W$46KqZ8YV267-J=kFK=2Rw<M?=xsd z{zf~@HZ62;O|$~KXX>HP^@{dK-xoKb0ga1JL6_owwBN<(Qap$GJ^x!NxI6cv9sGnw z_$S&?+Vo&9^m<`5BW2MHRY#9m19Yt?pr_+e^t0i0biku%e`nCZ|HY)cF*B#&al8hr z;VWn+zKi~hK5#D9FQ9>Bni0GbeL)pPXIKNxTnn_Ho@fC5(SXOIOE+-_=ii2@@y7em znaztnhF)J0U5jRBQ>?#*-v1%G#-E`B9YZ(aS@eC8V`ga2Km)6Vo}$(>nTZ|trokl` z94|~kBYzMb;1RT=<*|KJ^bK^N_hS7BHmCj_x)f#Z4u4eJ8r}6tG?VwB{m-?*NEXE# zR>m7vN7th>+Z?aIhpyp==&9L{ej7f7-S8Zm+Sd1kz&oJ#_losFXaKiFljAA)z$DDT zY3PiXqp5!$o%sgzL+1m`z#q}TvfUdxEQtQnsaUKxM)yc7w4ZM1-nbqOXe4rfGBJUI zsdyN@aT$7Co<-l)o1%Ns`%a+)|BeQpc3-GxL7&Tq4p0j1uUfP|`dkaNpRRb7KmYfk z;EZoU*YXaWfb-CZGtCN{CNG-0GUz~+(T~$cn1<caUoQ1TKW=-Y0gOfW*u?1FXlCZ& z6`ud4@xq#T;T1H}?brtQ;uI`!fB4*9gm&;6dhFguGjRx=$We5_A7lM@^!|UbEM}h_ zuGhe%$DuI=XVeAl;08>6@jy4(sMtOp>r<bC&g_-wn`l2Dpn)7jGw~Jr{MYD&PM}M3 z4n3xcIh=oAKzZkchKlHnnxLugj@585y2}@0bzFz;jjzym`rqh%h31CM*$z8XABmN4 z3torEu?{wPAOte*0nWc2PobeDE=Je%5V{vmqch0*U|QlqyaFrYGW6JffW9}rM0fug zG?TgKh3AW*d!ZgW(XMF!!_nuaCgX+0(HF5K7j~e5{eT9NK0o}~@HJ?vyP}yI9P1O% zf$v9CyBI6r8g$_O=nLs28c_BH;j<xGl0pv}+MqWqK~ujK%iu>?3s2+ISn8p)#BAJw zjj{8>uxI9?&p(0&@Cy1V`60Sg-(dzO7KQ62kclM|wJDgA&ghF~2zovzp);I;uJI$- z6gQ!3coton@(+grs-l~>1A2ciG{v`L2F^oI#d>t}ZpHkb|99hsgVE#Y+Wv~3_y5ob zvOE$3&5iEnGU!Zep{Z{Zy$;>wL(%7NjZTbCN1wkBi!pxUVG7Q4Bf5z`h&OzPrtmBp zK<-C_h0tSGB3c%mc_r+Mb<q3oL;IhP9r23AA+Ubv9vY6R^FN7#k<LZ;!b0?g@m=%` zn#xP)-YE1~$WZxcgJ_3ne>9-cXuo%&sh@^EKO5cTk3Yuw&!F%I4Zd)WpsD*BP3g~Q zM;Fjn>}8LKjxLX0g$7zQ)+?d|)QRn_(dT=h{S83(*eG;~XFSgNx3G`~kI6G=2V0{b z#TyTy$L1uuS<{z<4hu!gp##;8_2%e6UD25jMf)9xral?#3oW=-E6@nn#v8VxGuwr3 zmV;<VC(w@0MAMdr>v_=Y#nJvM#(FJulQu<{qC1YozE}a1A5w7hok7q0Wy`|xsf5+3 zcfiye65Wi8u>@|ya`-v=iv1Teu)-7J*L5AxV>lIkei^!lUPYh(6nQTs6K6vqamACN z!;0uq^uY2s5-Z~(w4=ANG#<tb{15A5#_}+uKIjW;CfdFktKrXRKSiDj0k_B0-~XLJ z!8g=gbXPuy8Te83Bzi1!JRRQs70_35FLWkj(B~Im6?_3};2|^vIaUNKqMN)ux;Hvw z7SHER6x{VA;|&wgH{fJ+t!JWdx`pT(K86EuIl4zK#Oqm~3HM!r?uC5l-YJeQaTRn4 zTg3K(m~_UYDcJD>bfCrP3+4$lfE8#*8_<s5MtAYY=&3jo>*vtZlx1a@VL|l1%IN86 ziuThE-K4!&a{le`MjFh(EolADSf7c`a2`5?rSbau*uE9*=!589G~k2iz(1n>{)3*b zEYF7i@}uLFd^Q;(szQSiHbNh0jds)>&BWk%eR!<jie_vAx|UPX02iWrU=`NG{phaG zu_~OdGU)vs(QyVPDcI3ybfDYgg-PfP?u{;vK9BB=*U<pqMLXJu&gf{Y|Aa2ZALtTg zc`o!{44r5xd=!&aD7fbDp{f1|4de?nW&cA{d=kCycXXh?(ZDmW4jtw|1IZsPf$sJy z=zTTNwXctk(+0Uendlh`i5sJ%&;TZ)H%>+02XmrNV@2v)&;h?iXY_0IJo;Sv^C9ru zXn%#!&0aLNH&4m=Yfr%$^*|%M0exkTLYH8Ay#5gS9$1F1^;UE(_n-lMiw^vA^lwa^ zhBcv|g6NV}K*wo-sqg=7DfnP-8*m63&~4Fa=!3JdGCm&L-^a$(KgIT#Yi&5+eb9jJ zK-Ydc`oda_74RjrzeAXGpr0sI!gKLL#tUI))zKSUqa9oq+s9%p>i3`lZNVD&9r}VP zur5rX78*cPbjH2WJv0=Z=q>9w|5YhWjt$SF9c)1}asb_Y-=MqxWNbeh{STc$&KH9P z(X}p#emIpwpX-Wl!ani(K=ipGFLM4()!2CBq<F)Oc*A{Ik?Rkk9lU{Q_%1ro4s;WK zgzlNo(Tx3w?w#|oo_&1?<Z5(6C1br(l7cCzg+|l>o%ywB2i@cKA?Sc3V|^@oyzW4s zn}p8v9yGNNpi8zC-GrOafp^6AJ?N)n@<hC$=u2V1s%QYsW4$vvvm2wgp}YUS=n}N! z7tugoMKiJ;{kYzPPUJ^yg8yI_tp9TAcfrZT{S@w?A=`$u#8jM)eenX;$6gylhUTFe zcsSM{M>DV-o%u8960Jp-bVIDa5q%dY)BX_}V5?0|g!A8(f*lM&mts_`k4M*Xa&%6- zz68^0e+p9r$Lnj+UH&>cz)tkVbpQ?QRJ?u`4KVQv_xbssokCA6fTsQyFW|)JJ!ond z#QM_cbLfB@qwk<={RtY_F?4Bui0!{c(>90auENyc|I47@8dXD6+#=r41|7H;8rY5K zUKowumyFl%Mfb!4G@zB}CftC|{GE9HLo~zxL;L$?Gw0uiUukflbMeA|=nQhc8am8} zc2p7_xB|NNRng;E6J3(p(R$H_(I(O6(N@@*``f(A`M1MIXfWkV&=jshXY^`p{}>JM z3p9{#(7=C0pZ^t|@$cx`rf&)6L}yw6?XML2nNbhTc&8)<Q#vqS7>@=rE4D8}2VRA4 z#+Re-pn-mhru-XppwqE_F`E6g@O&XOuu^E?RnX0utVO{AJD?r)MrSfK)^A56pNU5P zXl!4LcK8|^*t=*z`_PV$$M%2FO_+Ua2qZ6BFNQ2}GEpvGsD^gbFxET7`gQ1!T*J`7 zro{HS=u#|2_sR-1pf%A=(Kn+XMn8-G4|90_zo+29XV6rqy&l#kC)!~#bb#_`>Z-@< zb<w43hrVk2$NC-d`u(xK1kLce=xb=;J23U%|LvmSX7~bKf*;X=|3n{5yb<a-(QhyX zV!Z(tr``(N;}EQYFQPw?97Df^UO*>MYg?FLBb-CM4JPg2Qwm1(8@h@9LU(oMH^ac$ zqIuCJD2i>cG8*9Ru{{}`k7nvgw4aseeb1xc2VRNw-EVUKy>O5QH^q18Ci(^K;1aqd zncoW6bEEBr(Dq`ny#kuKnrMK{(Ft`$@9!P!1JKM4LGK^)7U$o!pAv6;AYNFA?)s<D z&9@0%>yOY=a3t2xplhG`?Qp#)I-%-lfQ_SV(IxJIrEw^l={d=G!(ud|73jz2OPGNl z$NDKWfGqEX2MeS3mqiDvjn1@Lv^6?FM|AD`qB9?azA<k>GoBnx!Hy=Nsk;Yz<02e{ zKcNG6*dEsM26VuiqGQmGC!qt~jjs9JczppH$Wrva)o7p_kN}d2Efjq49rVVXcr$*E zJ+bM#X^G~z2z_vW^bopNj-gBS8#;l^?*;RsftExkPzB9wb9Bl3V;0Z<s8oTk+h_-q z(KVcn2J{HJYgfeUTd@K4o$-45j<iI7>bcQ19)<QZ4Ts``Xg_DLC0;`NZ}C1EVEja9 z3aMR+MmzxBy(7>E$D$oiiOxgU?kP0Y&!az>yohCS7dpUMbmo`PCC>9fXfKWiSP4^q z|ED1Z2WpOX+!<Y~-ssW{LOZ${P5Bh`6g-H{aRqw+w`hugMhCq7!_aSjw7n#Hnwp@` z_xzCa?}x?BG*reU`s4CC9E~5KGpV&Re5f=-1MQ6lIt0zk=-56T9ryusz$IvZub{{7 z6LjF;u?A-SC>ee?)9|A((DmqM8isZ-8Qm<8U^#piE8uSQ-2aKrDEG(Vm0JdVMYq5V z9E$dLA3D(`XeM7qpL;J!!3Ynbsr?;&cW2%eeqoS-wzolN)(7oi7`o<@(6wBQ4zvn0 za4Q<f;n@B!+HaoSA&@HQrcPc<p&Nw(Xhbifp9$~9`f)5z{ckjYl6%4*98^a$)C+xX z9D3h<SPj>s0~|%~`xCt{&nF>s<&gGdqB#YB=If89c2e{i%%Hv-?cf)5rdjuf3>3ua z)GOjhT!WsPyq|{qu15Dx1@w(q2VKf~=pJf|slWf*i-NniFM6DALT?-q>l4vqITan? zezfEHXh2KR=hk2|T#p{-U(w(Hos0FnpM~cNqnRv&?0<GQ1v{>TKG-<cTcW$WJ$f4Y zqml1K&-v%*x8RGhp4b=qDTf~0s^}@H8{3<qfww^e=z&RZ7!)szj7~r^G83KQ1854D zq5(dEb?_PV7#&0d%f3GhSP&f`BU&}KH%2Ga8l7;T{qggEAPq)#3p(JP=nU>d2b_ln z^l<b^tU!G=mch@^=l?=G&U7FwNp`fK+-N@q(WNYk_E-J@=ii2!G}u8COr;#{s6VFm zM7%yCdV4g9cJu(+&!gz^d>YN{CUoF!Xg}|w_kW1)vCr(F5`}ND3g-Ge{7$D4R;4}( zE8}YHga^<7OMDSBRSP}WEzyn#MsG$3zAe@#p_#ZFYvNoqpyZnrocX)x8h(P#{D0^g zev97t8#=>3&=*qT%P_+{=<`>j&y__7u7U<s3w^!``g}`t0-ce7l8GBB_)Z>yvvF#; zkhtt%2p|{Q(KTqw%Ag(9i8e>~Oh@z$*bkk^*yt2=z}eBIXh7>Qo1gz1C>Z%0Xyosr zGvArIfv@GU{cCilC(zSy7CnCF&<UJJ1Iu+N3{VKYUKCAz33QwaXa=ie5zl`M3Vt{Y zL|>T`(9eW<v3)iA>U;~$!~raYNAX@vKOC;#k7npebjB}YBYYdp&;^{2+5Z;;Sc0kF z|E;Cq%r>JDZ%0%3J{svhbOy(<5}rb5Qt(K)UJM<u8oK*ipwIV02Of;}b8Eal6FnV| z9O3-i(UUZ|CeNY|tU*)y8XDN1=pl5V@6r4ILYFGbSK<DA=pLwmsZEDwtR;G1C$ztQ z=u!>;iu3Oc<7qH;Q{s&eVCwT4jr3*o<8~{0-<N1cen2O18olpNtbqTanW%6y+}{{o z(oSgma5SLF$#~&@^jxk$2ReXe;4B*P<;TK+dC^UJ4LWd%Xn8b%YO!8F)|;V$wu^R) z_C=Q{Ifz143S-bO3{RjPza4M*08Q0?G*d@o{YP|7e@8Qw`Rh=>2ED&BdVjrW3v}ik zV|^eJa58Z-1=n(XykSQ4VKhb0VOx9!Tj9lcz4<rcFO~L0Gc_B{%#-LISc!gb*n)n) z*oQ97X)J?<zjdOVzh)HN^=;4;c0fDonYw|$u@oJIrfdW{;2mgybE1!-&#yu=xIVfW z&B!+N`47=ed;nAb{oe@-H2i~Zt}BkmV}-7LwP+(Wg>BI_?S~F{6S~_+VQIV-4eU`g zkd^3tYtaBU;UoACrq2I$--Q_uLT?<7b}$ZoU>e?wbJ3aS{yqd;8ojSR8c-W_rd`nI zu1ELAaP&iJ8alxx=nHMl_ndz>-P<(ix9A)2vJ>IPqG&)>V!bZ9G;PpVa3^%>y2R@} zV*MsGkl|=%#-jn=8SB&0!0$Pc4F5dNLK<9?-Dt{=q62-8mGKk~!a_fU0Vkt@O+$YU zn1wFQQ|MA|L}&a#y#8&xegU1}6+edWie-}&JSM}@NN+`t)dVz!v(TA5j1IUw)>or} zZbbLUR&<8%qxbDWPt_M_|KDSGJdFm>;-|2b$?GXN;8--`B)T@s&<-|WJ$wg!L7hi8 zS*4R<pl;~WU60;B70t*4=(pcz(KUY$&G3FSQ{Uq=p8xX{deN}#R5+)<p&jJ<IefV+ zi$2g7?PwI5;wk7%7N8SY9eoWQ=p%d({}<~w{}Lv47rLYmVMovZn-nV2knPtHKyA#R z-W{F6ZRpGwqAA{iF3E261@k4kbZ5~N|Aj71`_m!dZs-yWLYL|m^tn6nT0j36QkZ~W zpsDWkTlfvgy||J3FX(1``b^lh&!NZg6?Enwp&2?Hum6G_sb4??X?r&8r7q~M?~gt| z5|b9DQ!r%@qaCfnQurGB$~=Nbp5^y&?5@Hx)bpW%HAFMg9Nn}X(Y??Y&De-oABP4o zJ+?piJLlis`Unkfz9-QRwqiPdfOhmzY(I!ysDF<=u=cs|pXuF?_VX*cIsZa8agjg5 zOlzX`wrGDhpnGTZADn+vcrOk5XuRP$bSXBYoAVcJiY@;PYc~^pvps=s#!YCZK14U^ z88o1@zrqq^NAJsnW~>ZmV5KAlQ_>0DB>m7-55@9$D|W*rI2uo)ySLBzFr#~MB=x1} zfSLaeznaa34%7=>;(oC{4qcK7=!BEgD7e=1<Asgrrg=Tqx1*{12%Xt6bcs%*171X5 z#h3jPQhPbNy9=PN<{Icy)<FlZkM`djIW@^dTMBNTPH04ZV*O@xPuz|k&jo0PUPouP z13h*hqXF$j`#FLR^aDE3>FA$m!2e=uGheVj&firOT!JF027aM{u2t>W-Y(iZwhu)I zn1p6z1{&x?=;>L94)k_(CmQf)*aW{spU;1hcF%uN3O-m0jkqovP!n`U9nn<wM!y^O z!&Ct1OlF|R_dzu9<>>PpWBna8&;w|H-=VwzG$wuE@_)k`UxTKy26{}Iq7QbC?KhzJ z-+~4_9sO3jFkXKF-E6O6Biw_-Fx#c@ht1=#4E5)*2JXJZ`S-kDqM<65`Y#-d9_T=~ zqk-IyZmPxT{TpyBet~1KHCyav+=T70NLqR-Bg4=Sr-^95OVL;Qi?O~tEt#JBn+(Tj zsLh4E>7m{Z%Tb?-uI006ieE&R;B9oNzCt_x4qfBF(53npeJ(9idTP^VN0%&LtQSF- zsBDsg9o3FEG(t~7D|9J(p=&%C&BU1K)Y$$2x~7kz13VL5i`A%aL|;tbq8ZMaIRw-Q zZ={}VO~IM1LIc@?uIXFRgJ`5@(SQ<{rKi?77g{fg23QU4rxChzozZ><$NCgBQwz{H z=QE)_nb=Cfne9PeG)K^m&!P|fhi<~FvV{9eqMNJ+I$#?#V|~#;N21>!CZhd4ga+~) zI?g+2e|s_Y=YPj2IN+&x!};jtmxl)mpdFV%2d;(AupQdb0Cb?y=m2-4n`|MvX<x>& zxC@>6Sv0_GSqZ@NUy_1vwyHK@eYE3i(HZtaXE+?)WE0W*rlA>{gYJPRV*6@zLYrdy zJ2;v8E^Ljhv!y3m-~*WY{NF>t0l!5fJBxOhBYPOI02*Ksbl|e+F0UD{*NyFs(Lme9 z`t^7d^<n6%dM7%8J!nSvXHQS2X7CLS4tx%sQLY>zpbRvS>gd3Y&|}p$ws(u|{m}tN z#P-p#eImN4@4-89E>_31oMBJY%*pw$Nkb<ZDq<4-oL`G2@F(<`<j9qt`ZJ$V=$fuV zH`O~>3J>ELyo6<N^cA6f5&FV<6`kP!&{yv{^oP=%$=vCwf1k4gdQOL;n`b^2#~0Df zwFiBZ9mfpJa%Bjl92#g#^o2DP+v0<mfd|mc{DCgbKj@yyktYO_EK0$KI_M2;W4$k$ zx?8Xojz`~otFQ*XhX(ownz4LWg@JmaOV$^CAq_#-dK9{6CZl_48WI?P|A&Gzd=OpR zXW|VnL^op{+TTV4`UBnF7tsN-<qh>b=&>w@ejL|C`|X1EJ2W~bdS^<`Uotk#jxIzy zUK)J{J=bfaThR`8#`<UIz+a;?J%^PrJzv=ERng~bM_b`2>OC;^=l^d}Fw&3E4vs~C zL1%g)nl*no9r-bX_VQR4+oMZ31J~jr9F0v1gjBCZ`*|hSx1*Wdg{go4V_$4IhG|?l zfqrNEF}9yV*X%61M=qin$W<_OTmb#_EQRigzL<d%WBqaT6l_6H%MrA{L?O<<yEA*C z&{1ymm=r;mpbq-NXo7C4R_J@63mRxYw4(v&jE2Yh81%V`v3(la-@Rxi9*iz2#QAq^ zo{KkbjyG<@3AFFP^4PF&=x_)cz(_Rk3Fw>iE;Nw2XdsWEr)3%1|5h}Bo#^wQ#`Ysg z3QcG@h4rz*)gi*0uqX9#vHl*~(WmHu$Iy(N#;W)aIzWYMLI5?;C901O*aH25rZc(} z_o4kI*HXBF!d7%`3l<3-lt-7M8aiM*baVDa?;DP8x{0xU4z{NL82SeM3e8-mqG2yo zM&Ep$(Se5{Z{B3$4hmywSdB(ppja5NI9jiU7qLE?(mKV%uJ4IvU@lg~N72uYchF4i zN0;J%(QncIeu|z=$@#w!8!~5v8*)VpM2llf9xRV;s!`}#kB`@<pn=?rW@G`*#1-*+ zsS;u4mC?<2E&AEf9aI1Q$0!PRJOk}$7Mh}k=s-`S$7U@$(@(H0{*BHwqhwf`^5_6{ z(JvaUuoCt|muwcAfydDA15aae2!*Rlg%`$jBq51Y_z;dNou2UeMKr)cWx{~N(bSHO zPCy5kirzOb`Y;;MlIU~MO_*A$GMs;Byq^X=ioQyJLOc8y&A=69!*MGVEsAzr65ZX^ z(9}1=)FzAdVd(P{(fej%DnN7s50_1b3rlG*mCwZs>(K``qXTV6Q}+pa-<N1d$I$Ns z-(x0BlnWEdjMj6b_vJ;Gv@klc^0D3^Nnsid?a<x*0h)>L&;U-O$L<39!pT-X)UQC_ zfJM-m6hi|mgWgvKJ-#*3KsuuRbw&H{k3N?iPQjUti5Kp~RI1RF&O^WTK81Gt3YyZb z=#1V&JKTr%^A&pE3G}^j3jL;Y0e!Aeh45TSBooO*4GMnxwG0i3zF30#NHoF+&^@sT zJvPt9`a5W#2clo28Tc6u<Q)3^zv#f3D~9{8KsVpjnEL&Hl~jSxXLPL_p&hl0?cHK~ zAAFSdp=f6QiRP>nj$1Kw#&yuZTB8GZ$5hJEeuraM9E$}!Zf{X=?LWuL_&Zj?jLPY$ ze|oJ8-c0>rbY>UPwY{uLuoxP6J#<N~MFZ)H208={XhLkCiQc~ulWwl%6g)QTqC3#` zBk0<nL_7K~w&$rDIw+0~SUJ`kq4&2#pT7ZX;3)L@Cu93d*q8d7RXP6^C={p`jzx3y zyIXhkSdGDII2(Q7HLQwxs)tXr=2(&XB=nomO7v6nF#5`_S|dGiJ&s4er0&A*n7w9t z>Mt-3sLA<nLBmQK9Qb=QwQ04|Q~yr~SEHMA7`jAL&?Q)cZmwt0nXW;<o^QeOco;qB znQDjjeAu6QJ#2#yV_WY_QkYMnWS#IedjmS)_vq%ifOd3Q-7sJQbnS|w16M?su0D3e zZpg=K;t4cUd(oeKF2(B;>V+R<wqrxulNTtoqENSfdZHiRh3)WjbS;ZD2wzNUp)((i zp63bZcfCdEQf<JIxEtMkbsL5yX@h2J8u})@7u^eUkxiLQJVBuu4bP)9`Y~Kc{E0r8 z-Y6WOY|(t^eZ|pCREai3Up#HmfjXg^vj@8S2gmDU(9GV3+5NbiO2Kn^KRUw&@rK9I z4xd2>T8+-^6*L1o&<uTp4)7=1PkQ6<g2|3%rYL&;>thpag=TmrW_bQTrf?6Q!sl^Z zlQ8o_O~Ym?j-zRBhh}6mI?y&W6FblV_r>eS&>5aU-*msB0c2_xCU^zfPeDu?c`*uZ zvWn;fjnJ8QK{L`5?Qj6v(eT(l9u4F!^!~fij_;54`LX_RtS?2E<|%Z%Rn0j6HoQuM z9dC;_e28|mC)N+d`eAgyZ_xXHLI*yF_VYKE!T)e6mT4Zoe7=L;_YL~|33Ot=Hcy6` z{S_~ywFnoop$}YzsZ^l@6hkvsI@YVBA69j-5B5dZ{ADbQyU<f|7Ja|uX&JuCRl!Qs zyC*61qc9E2;X!nBBwB@Y+#Y>}PDS5@>#;H(#fF&U+7M_Pbcs5mGrSJntT&*U8iRf( zoP=)P1+hK3j)H5x1znSm(Ju`DLpwT#zF>Yp-;DpE9T#dHc7J)ay$PDJ-sp4v(M>r7 zZ^T>C%zcVx^ayfaGI5+jMH)_phD3ojG1X{CrO}yHMgy&jcF;cB4Si$wL0>FmqDl1r zg=oOfq5-`U>)SE)`@hd9xEa2RH=ICI_B;9lxfJWU+J+PsLOZI44%ir-S(kXdANpPx zADxBvw+s#FIW(ZHnA7wBkp=t$?dUi<@agC!Gy}QX#m$JR&4{MFG#W?+^u9*uQnp6l z553X;hhhefNAF*R$#N8)rBDZVqbW~sA8yEw>!}w(Q@$&@5B*AZ2)+LobcTOK6CKhM zPgBo<uKhandd`j^@PcSSMLWjxUy%kQt&V1(X}qBWI>SC#8V8`8aV9#`C1^)0(Tu!| zKL08j@Vhu3KZ@;*I)!oCqSvqM#QD#lFn|WvY#O>oi!k+uLifh2=$gHa9;3Zj0Z&A) z>>N%(L-Y$sPxP3r##*=o4eUHR(ac@KI9DYpI8YgM26fR?HID6V(HBf#tciD_9leOA zek&T#c63Gu<Mm_cL{6c{^Ab96!LA{5Wzftet5Gn3#^~4U&gcUp&|@_N9bhr~273|B z)JN$3N72ljM`xV1TX+MOLH9^=G>~5C^CM#WJxD+N|9??%H?BhmdJA3S&(Q~dK?lm# zJ!GO3x))lb9p8d(;%Vq}tI${Qn`q_^VkP_seHEAO5i-#lQ-A)~lY%q20exT$n#u)e ziWXy4T!|UD58V^LqnW!H&DAr!Ig6pkw<Ow64Riwa(WUDV9q4t>|1Gg$JUZYsba&6i z+wc(_gqQaU*KbCbXabsn`RG!ui1jUKhCW6ob{Y-nKXmD?xGsD(D}||l|DzuTQ$HGw z^d9^MpTypn?46!igkPZViIIK6%%8%yslSYVhrG3K_?G+%Hm1H0t6=WyL&ln*OWFpn z$D6L_{F};cG&uA3(Uk2&BR+(#<&StRX6hH-2kp>P(iz>=ebLi198K|PG$WI+GtNgd zaRfazKcg8w*N^jW!zCKhFiZc?QC760E6~k(H9Ambbl`^Q60}AG9vH6=LsNV^+V5<1 zi5@~fRaatWTpeAPjD-zo240Qz_s|G;qBGlv4tx;J*l~2pentn(G#~_82;Gzwqm81S zFty3iV>t%RY;q<AH_H>~47Z~L?L{L!j2^3FXiEP=2h4Rt7^ox~U@bJT2I%uG(Vv() zqZ1j0qi_P+&o@Z_$;4k2eBffdaQVQH`l8Va==D0$=IAl)i1l$yY<~`&;RZC2?dTr* zIJO@`1NkZXJGNx}#J?2UaH08);hf)()u_LU4e$i|RV!mq*ya7v_NTBB9zu6}{=wll zsXZ`*`pakrK8y9!*n;|%H-)coJ+QdvKS{wGpTd6lCQipfL&BbT3~Nw-7H`5Yus=2! z8U}n6t5W|R*I>zE;b+0!*nxVX;o*nPA^0ox7w~ahI)d~63x!%Yr>FkC&k`fk6X&UK zMN_%)mh{wLI)4`(Aor;7erSsRwA&YLpMqv=E#8QSu{Aav9X=&zpzn>fSR21amoEPp z&cCVcGA5*K4p#C;^hc#H&;jy|4H;;KrhEdrmK)Gx_6Byv_pmwU9T)acFEn$5up=(Q zDtHuqKIg5;aASd6!!Ha<qHnTc=$fuUcmE0W!As~;RURKQ&;gy<80>;8(am`l{jkY* zTUdfx*q!=xG>}iRJr+sc9yZr-96-Yg^oC35Ogr2WI-Z4PsDF-T>;kUBx)b6bsh}^a z#GN67S78OJP0^*e8J)m-EQLqV%q9~PLuA#k9t|_m0k&dYJckBWX;OHV&c?pfzrY+= zZE{FuqiAdN_;p3!jD0Z|-Wcm+(D%w6$n(j>WC}iTAI`w}cp2utE9{B<SdMyKtd0Y5 z8ZN-`m}^RU;t(crFJ3=2ye}$D3xU-}18IuBVOyiG<Q|yY^FNG&ugnSP0JE?%Zb3KK zcW6LAqwnyu=nLu3cs*@;m|-?7OM5}|^fX29>w+%L^=Rrxp}T(pUhetdNx=X<MR(;l zXv$7`1OAN$;9pj82A889=R=<>j#prHEQHO_8TLi{8-;#+Pe6}f))`^xnqca`|7%ad z4!WWb3`9G)8BN_3bj|LL*YA(*3(=)}9Q{mK5!+vlzKKp`2Rea$XeJKE_LDO>|IXw* z4Q{4PGeaP`(RwkogNo7mXa?Fud!qLZLMJd9oxl`ysqRBFI0v1`LiG8^(Lh$sj49ee zgU4+<md1b42TR@^&Ur<wNxd@;!5LTvzeB&@XTK+$il%4)k6{;Ff$8`g8o=*pzyF{a zO;6q%9=IG$Q64lS1u+dv#(L>^y&5{RI?)E`fKAY)Xp3dB8#=(mczr7RBAbOizZ~79 z$!92d<3=>XE$F6t3w_h=MI-(N9pDc%)tAr=<hn1sVr!wNW*9cdMOXy)qn~=e;ni4k zR`~qyj5R#}LnsvH!lUR7FJU?S7|Y{XwBu{;5BIf0@4E@R;WR9cpP&K%iheW7IXm=I z3K=NTF**%>vAu*9JpU&sRHEU^IpIQMtWN!Q^te2W*Wn>FplWl&`R$8dUx=QT52A<A zCHWaW6@Q|eF2@65vlc=#QyNqM{cj5jro021>i+233_*AQ?Pv!xV|_lFu_w^I@+!J? z+tKHC;x%{>UGsC%oDYUfl}4{$i>d$rpFtFSaomZn?E>_{<>)ba6*F)r`sMK_bO!(8 zeR%b};L~WJW#@;0YM}u&ME6bybb>u&z5jg9zcU<4gAd*oZ%Cpky+78MqF*?kK~wrZ z+VNpDpp)pDUqUmIe?iz}8F)MOy7(WiMW0*yQ1}zj*B|2i`vR%GFhtfIt+zvG-YeFJ zqnWu44Pa)xz8L+Se;()Hhv<h>_eJ4ze=j~l{pyE9MqWZE{3<%(9Z3pC{2BU!If4d| z`;qVhxd#2Zd<(j%W}qJ)bFmt}hrWP*M^8n$M?*j@@g()Zcmg{u4u1|%>#^Wk^t2>P zJf5C-i$XK>jdclqA9P+4X50e}aBy@qnwg1cpmSpTqiAZMMgx5ro$2fG`c8E1_oL7K z57`sR#19lq#c$|9|DvZM>(UTFVYI{Y==GY>Cee22=IV*wHvkQAIJ(Oxp#we=eH!g& z9cK0XZ%GvriFeS5KSEE#m*|bZp|9o((X?e@(_M~Uzb0BXS_92QV|3t7=!E*BfsRC9 z?YANOpRYm`d?!ytBcFnv=XqEaA3@jnJ<Pzr(2ff|5#9r((Rx!flO53K`e1pSg-+ll zbb^~>{XI<m{hyC0IFm2X2){x1z)7^j)9Bh=L<7tGWVoIK4fsm*`I6{BRid?`4bT9a zp~t!-+W){OnZE-Jp~1Dg6+LEmp&ibN^+(YAR>t<1(T?6gcl{@5AU~n0zkn?<$MSHh zy5KVEGtmhYeJTW6`YF!8kyMNg)zC=mpdGe|^`2-3Zba8|1lrLgY=cSkxew5Z>_hKA zf==YSc>Q#&Ux;Q&J{@M3Ct3{cxDvWaYN9Evjds*9+8Q088!p7Y=-Qq{pFfY@{~!8> z%)TOAFNWi&S4IO(K0#p)h3D`tto}@R;01Kxx6#zUkIrx(nz5tkXTWjv6`NQYe#pE7 zt5e;E2KWn>!auMa7JfGTVA2A40VNZoV#A!!kl2J(xbZXe)%qV^i^W!j%{c^HQ6G)f z@MZM=uW>S7@m!eMY%~*#qD#=d^)#kVL#mzgw>e(ehR$>sx`_^=@A@CnSMa~+hfLnp zVe?f)Q``j2Ogr@XUTA6uqZt~7-ZvZV_hIadE3vxg|00DOvC8x5i6b}<x8W^o(o_F3 zTDi61L*)rHBUir=QrQ4&P#=u0{ln<YR-j9?8Vzh+tiOf^@Md%mrvCk}uPC@yKcf$v zLnBVC3%flBPN!M~@5W{5H=<%MrY9c8JJ1(c*7YG{Ine-0pqsBO`d(>>E<r2w6!loo z`S+X55E^`AO+z1ChpycQw1d~s$akZs;s`p^qv-wLMSqIzzoJWV4!u9^rBKg=PV7pw z|7%`KhC)diT<Z#GhfU)Rtzx|cI)koghWf_(P&AM+=*Q{pSP>UuCESJ?_#^tF%Jy>D zw56lHk`&y%_oByUBl_U+*q(bsc!M>;YP8>qUGZt`fWP5TY_u^w^?%9wG<K){AG%q) zZwgCyGdjT^(Ecx?-y@RcUkPhJ7~9h@68-MC2}j~Cbhp;o9Nu*Eu?h9hu^r}pH5|_Y z*oXQGY>0oO1JvFU9D~iNKZm{X2c+L*qUmel7YmPJYc70`ZLreT@JA`PVGrsb;Nw{M z^)TQ@^gZxbw9y;k2aP0_rhPjO#1mK-TW<?{VJf<0)3KzV|MyaG_pe5G<xA*sdI#OD zpP+l<EA$QaEqZ_UH$zIVLN{r-XrpLX>`D6&oQYeoHa2)G{LW}B*7p2A8ygOx-vM*K z9ex;Xi4CYv$6ELr+QHB0eI?!r=f4-$p*{;!uU_<p^-DC<_OPUd(e@hXUTBM{zyCjg zf}3T0bT&Gpr?3!iLLc0XKKL#A)#@+wxxDX&`zxZ?o5p%i^kaHN^e(iYdFXvB-{t(< z(Q7m~;DLDKk7&miV*RT3!UJW{`x-{OpvUSabf9Ty#}A<ct%|;ZKKB`V-}kY8{=H;) zAm@%?iD+H)6m*OZK_8rg1~wlZXcZd3>*)7|&(VQ@KnMI6y)V!E;j3C%wB8)O|GFdv zH{A%dqe*B+9!3Xz3GL|J*!~5&Bxlj*a(oavEP}ovYoKqo7U(8zhi>L>=o@h$`r$MR zeLgvXf^W20Xk?4fclm0xqZiOu=EmroXvaIzQ}HQ!+&+)j|3L@3?8D$y=$o@R`jxCa z`lcL(#XbLXDA?f|w8IT(3SUK2y&FBR$I+Smga-B(djF+(J=4z6Pqt_tbl}3VUJ|{( zBKmx_RGsrzmx62E2py;=8qoD<CI+Jq3_}ALjjr8Y=;!-`(KYCEAD}7z1P9<jG$VCB z3KMFH*00BGp8w&o;Z}4hrlAAQ@dkVdoyk&k1}o7(o<~xccohxw3v>w&qxYRg_ry8$ zouB#R5MXumdVNfmpwNVZH{OWW$6;Aqh;G8ya0c$e!fE_OvnzBoe0O^4pKKkA26PJj zaQYkFGwt_;S8gvHLA^JY#J8{vezS-3-<ZPXpM;rSi_WME`Y}2djeH6A!}rm5ddA)` zU=saCG!N}~9WKGWcs-8%G`vCI!}`?!MKf9Vv#`gSea88BEv}=%Pp_NMz3@7^6#LLX zj-s0}+rIE^HUleAzZNraESjkWXh6?kW!#P)>tE4+vh5F_rnRvy^?6AO&TI#ovf>AV z715=rgMJA0K?53&4s;v3WcQ()@zGdcjo!Bf9r!&=O#lrn+vnjkqCC0;$?GY&$&zU5 z=b)KbgLN?Ni|{419$rU%9o~%TUxqIhqp%nClQ;pJ9Sk4io6*c(z}}ekP<V0Ohz2|f znOHJ0Hxv>}&_JF?cmGDTgRSU{KS1AvhtNQOL0=@f4u_dlLYJ-s`YCu5UW*T-Ykm;@ zH2nt6&^7-{=L<=a&ut3#&~P()<Im_){DBUbI1(Pn7tKHetsLuh(f3A6<ZvX~;SubB zrLf#r;djOz@doNIq3?xUM>$oDpSXpB5uHLi{tJBrrX5R948nqFeG)q3`Dg~#Vd@Qu z&ipuT#S7?e-~4r$$gg-Ak^PMwX#ek<@MlaNzUBP8DHc<(qs{0*yU|R1i!Q|}ER1Jk zd(Pvb<NWAz8R+$T=*+sK?~nE9gg(a%Jchm}_|IiioBE3HIRB=uC=F(y6lP#Gbdz*L zkI_x&QY=6}{Z^s_Z$o$ael!EWqR(adKD?R>VHN6iVtoiY!5QeM-{S9+;f1oA22+#e zM0#Q+cE{5A2Rf6he+V75!0yz?VG-PpspExrQP1{c$iThWk@`0{53BqXe!KPtwxFK< zWO`ySc1lw49InSZ@c=f)j;F$p)3ebJl~2)4c@WLi@mN0{>;GVL+Ozx|PEA{Muk=Ef z_%<Aa3(@z+e`uzXxqk^amOxY63{7=kbPtS1H`@gC!AH>-(kkqRuV6X6?ANeYs-OYa zMgwk)ekip?muLVw@EyoRl8IRq++>T;2bQ2~`z$)p8|ZuBV|3<UqHoOOXo{Pj4sXi2 z==olU27Uq^=yYsP`z`z}+D5pE_UEyx=YPPNuqhru2V8*$@G`o#A7X0vM{}MH87hl@ z=rlw(@eMc%hoBSMi%#eZw7+lAe$JzN=c?bi&+}i+0@g(zXoBUj9oEC~=o@eix)j^c znH`D#ifyPT&V{9Diw&uc!@9UO`b}&v^hfv*>WRq@xnUgz&+Q$5h6g`G*EHu}VN=#d zXZQjd$OiP-?LY%L7CjTMXF4DDKmqjp7egml9zAx|&?Rktp7ZYup>w>@AMJ2-ykR<e z{egIWNxZ%m-DKO)Z!$aL^^ed256A1@q5b_FuU|qZlKby)U;e*2|Gp54)8OW+gKnM{ z*d9Be4?KdKaVb84-Tp~We2qu21HO47{Eexs7sD&~BtAs@v;U^2{;%8WTng`p4bjT~ zh4$4+3LdLce1mI>wXizgh81uny0&}J50iXpnG!c)eKeKJ(Bri(x;^>@I<Zse&l73s znNshWqUd{}722L0Ou-JOp&c$lA6$uMWGkA&_tE#mm(kzQU7amc=r9BAuqk@Z`=R&W zhMuYi&~cWc<Gh4SJehbW6cV4JFP^WX=b~9NhmMP&yT3k~iN0uuQ_&eMM33W3=;quP z{RQne>t(SY^#1yo`uG2P$A(+b%{Cj|<%_Wlu0fY*Z}eF7G<uHzLuXnfOL(ph`pRvG z1~>ve)>E-I-jD9FZFr^U|9uMS_ytzML($7G&y?EDb<kbj3_V8I#`ccrDYy;|_y%<8 zZbb*4g&DXE{U)>x?I$g3rqqX97EF4f5(Q^^D-OlQXo@eO0Ts`dDYeTxqnq(@?25;5 zAXdwsDfL}(K05Oq=nLpLdOC{b$dvk8J`#6O&y+Llshv49h2Q@lrooy0fW8=h#WcKt zneboqT&Lv<^&IF-a-*9xADW2_bnVNd8E6%+_eD3|P;@g+i0$|0N`}qx5DgCeEPCEI zpaX7+Zbu*76|Wyg@BbPN{1^0;oI?Z2az$9<E6}AWh_+Wm1Fwmmo_a|NKG+4_6ocZ0 zk?723paVUKZlWb<MxI4C>+{i9qdU;ex)063x9D?!p#!Jq4&z*oKA*fY7K)(}Rz_!9 z8=YCJSnq&7a6Ovh5$JKd8%N+Oya97v8SWc}_BR=w*i3YybJ3-E0tqmgc#%RE8s0^3 z%#$ai{_1FHw4<u%%<7^uX@kzJV{Gpo>%-9{93R^!q7%74IzReoO3vRC6zpgv+VOgH zz)k2Lcq95gdf#63zQbt8$IzuZfew5Yef~UpU*f9ZW$5$Sqxms){xc}}hN^+4zBRh$ zz0l1w7=7>#OsyF@;5@8@OYmFVi*0aY-VpfTXn>jWh5oXm?}viu#HwKG-~X#e!PK@y zm!Jnalm1v62ct7tjNZ2l4fF-{zSm>>JLnpJ8n1tgPUH-_X)mDzr{@n7$eBN$|3Wl4 z(=uqs_0dhzHrD&1GZ_&bi|+0T=w_UY4zvpWZnqI#g5d?ijK`v{>U+^luRzDyT!8a$ zVFwMSbbq|z7*?eIJ66SF1w%lc(HRd!XEGEWcq}^eDQE`gp#dyL?_Z8i;MwR4=ma(< zW5b77frd}ePp9+fE3`nN(B2(OP@jUX@sn5%zr!Awvv8(FGrSS~!Qv@=0Mo7x_s_%f z)DNHm{)?&4|18&p6qQ69>Z6hMLO0t;bj>G5??-3+7@E0f(adc^m+);gGyBkw>mz7p zE@D}{qDZLMLB0+1?|)G+RfExvMxv>j5ZkAs9p8&?qQ}s{mZ1Z!K?B(o+uudMfP9KR z_anNOE}*9<XVLKDDv131SA2h`;Ky%cw8LiTjqTBy_Chl<IM(k(2fQb`2u<k<^mwgB zC-M&Z{BHFALulYXM*p;(@e`Sgg&F5XAGjL5u^bvu9dstm&<~9sv3(@EG`FJx-h&46 zIJ(v=(C0ozcl}pr|7XxZFJaQnl&^TE)E_YPM>|-6-uQTQRdi##{x*)_`cCYM)ic5j zXP`^D0L$QG*c{(Pm*5iKgt<$E_sMM~;`yIQgEPGs?O;Bdvc<7|6}luZ#ro@Lhda<r zeU1iv9L>mYXg`UP;WTAM`zwoPuuiOZDwzx&^ryjdIx;#A?QlZ$ZcNP#UE9adfmWh{ zZHm5yZr+d3Z$h8O_S0zp|3nj|!nj$I6g(dJ&>59QBdv!9&<6c-*%KXjG&<u+cob*F z`moaB`t4|7Nwl8@(dE$>(dV~ClOI!X;DhK4e?mJrgKnC%G9keH=%y)${uJ8;eP8rJ zXLdU}^U3G{GthwNqZ3(*_PaW^Z$Sb~Cf<t;`_Mp+Mo*)eNt6u_UWI-Ll|(x(hYnN= z9iRmoKo|76>!KsjiA_e=er9Zc9BX<0*HUn1N3k)U!<ks4T$te|Y)*YIF2gI!XG;Bb z+I8rF%_@XF&<3q{M>EnF&D20Nph=keutLXMg;#n0-=N?ce}bm`2lPB&K;L9nRt)v> z=**j-nQ9-~`=K)&ho1L|=xLgZ-v3DSX>?DlL!W;GQ~&+%ZVIOIAiA4RM9-iPTtrix zqf)qD2(6bwXI32@s3kh{E@(f!Fe~5VZ$tySxpKJgHniXAl{x>e={y=t$s%-<JRf}x z&A?8qgkPhP=d2RGGZw`v)JJ0lT#9zQ16}L=XeLia|3mxBS2cW=RIbYTci`$Y7)Tp5 z@{ZBo=!^!V9gaZnpB}G265F4O^;gjVx1$-^hX!yIeeU<zo~>HQT>c~lZzzWj+&I?T z;#lefuoUjXrg$2?uWI!Wa07JHHI4Pw==Bb00N0@b4UX-%p@B?8_geB{3T~d&=o-Bg z>szrd_3gL|&*LK8Q6p309_&*ytnL5scIw~N%9Q%eX5ZSO<E3ck)}#Huf=+Z>tbZ2j z$;2TFZoXg9h%cfu%33E=>bGCHu?F?FXn>Q^8Qp{Kl}FGueKxuc?e74ZiEq(O`b%v8 zFV=I_^<$s&SDb<omP9vCMJ$I6upSOZJ6wVu)79wie+T`v+!O0xpn)7m1G|9UpQB#r zw=~*ME$oLau(0R<2@1F2tLQ7WLjCZivo-dneg~SFUC}SmK#!v@n6v0w=4=qmz{=EX zqnmaxnz2b(3Fn~CZ^oo4-9bS=LD%RY+QBdAOs;Mi2C9e?s9%eINqrs1;X(Adc8$Ut z?gnf|eG<CaUc>JA30}mE#+efPuxJy`e<KRNH3{dpa?_C7-sqYQK?9qBu4NJ(XfAfZ zr{eXK=$<(jy?_Ru-Yh(K6;7jG6wTx^G-IoqCBquML4&C}fDU{L?ciVZy^yPUSnL05 z>COXfEdB?MAMPoll;~@zxb}U^lBnz?yRt^MtSLl`#3>@BEFnZC6(tek%9bT5T1cUV zlpiTtR8)lD`+a8qdOb7ed1gK{^O<?hy`(GA2ChbPrcA7_60MCM!41%_V7H^+14g4c zGY@U=4Kx>)reei<>_)|AERRJRgs)`Hu{Pz==uE6ezXfkXXX5=>{}q;`d>9*I&W0K3 zzc17R4QLeF;bb%^=V2zMR&n8vMtiX){)y$VT%#}(x1lrB7x&{MmO0ZqG!8j1xJel4 zQ`nQwSK@1!ziIe=z*_X+D%dO|{pW_AuqEY9*o^-9ui7)x|7u+aticC~<{63KpeANw zsarD=$FV6oh1azR*<23|ye&Et_n<Q{7K`H|tcE+VD*lHqMWvQuKrOM5`@attZoARw z{+)wOaXGry|Dd^$Y!%A+(d5ZQPq-Rra@IkUut}_MiRMUqbo+IU<-4Q9F|Yf76c<MJ z3|@yz&<?&s8~hVZ$}?!7m$nWgD2oPM58aNP(A>EnUE}#^yYHe)xF5}d->?{-!}Ndu zTeM9`u4-rlb<rF9p(7iCesf8o4L*+^An#%={17YS1)PkP+h(NyuxSIXpj@F{2;d+( zW2cZ5N}O%S{<nj3RG8H{+XpX2kJc;D87PF_ml^9TpaIlCm#7iCJKCTfbU~M_2b%pu zqGQp4%|vJPmG-HS9IL3XgQI9eC((}2qJd<;EhJxVwBdrWTsB%0U7CjI{=O4^t`EBQ zgV7F0qk&I}^)IHlFv4ZgEoehuMo-52%We<%Wum!J9c`!?8c;_x@P25=L$M8x#LD;) zdXD^qZu4p#!tP1+=fZ9EI6C5KSQKaD8eD@n<FJk)o8OMELGRxb%iGa*K0^cg77g@7 zEGIgJ@)hW=D2XI*Dp8ROBW@f&Xoaq62Xsk#p=&l6?cm|)6S00qEH8*ILuX=r{QLtn zkT1|(aSVNHX6tNHvj48;!Vj)P50VyWggs+<02;{XSU)j3HGV!D?eMK=7P^F+(RL1C zdpv>_uy&X5^12Jjf7YH0r*dU<Ejoppy#aT}`Y)s3qBC+BO}3M<d>YOEWY_SWF&Fx} zu8g+-Dmt@oqDh&B>EHi-$b}==gXxIThK^t<JdOsG_m0qUF?0&6pt;c;%j3lO`AW3C z%~%(Aq5<US7CO#@E_u;zjNdFSONDEDJyyiVXduJT&qtyoo`_EEbI}#((tL_;udmSO zj-&1Ui9Vm`9!7pS8pzdXeev$>f7iSk6+YM$-Hxr%2z#L?-yocV<I!(4SKS%ztAI9m zb1XMObEz|W!VSahI2@g^2het>qJhszabYB{qHD7fjr_fM!^g3HAEwtF@8t87_%ycd z5%%{1^tnrWhHNi{c2Egjy4vW#Zi%1Y5ls!@!q@IN^u{&lOXWlKtUrX#%ms8LIeLY) z%@xg$EvPSo&cq;eDTYPIp}8~@eSR)_-;2n=Q;FBOaOCfxQ@aUE;9fM4Gw9S^**i>a zMXW=)31;G>Xp+5*zV{EH&nNnXALmPAX^Oq@9-N3x@HBRF|KE65`1yVgdQg0g74TQ| zdwSu%;i$YHeQiFAZo7AIHNK19KeS&6cpiG+J6IO?q652t4&<u-;dNaF)8GGFabd*$ z(J7yVCf#Cm`)$K2cpPo;>H*=t#^}iVpzr^e&<-}B9qvO1^b7h;DcivCwY&)0-<_DM z$i-ML+*Zr5GVa7dcm{pH_Z<|HXC9XKKCFjd<2o#ScSd44?!`_xad1e+L+Jg#U?vv4 zC(P6hXno&%*#C}fDiub)37xvH(TM*;M^@<GkaX9hS=<1<?{>TmAHZ912b!$;hJ+Db zjqa{`n2D{?0T01SIBy91-)*yl3X^aj+TmfeqijRNROUyMu{^qe8%A58=f~~nkvb5a z`iId0Ohp5D3(flV(XD8IJ5sS?FS@@Epi6KZi(=tnAqVQ9pZCP-crO~rg6Nx=PRi)J z=)g8&cif5IU+%t)#7lS`_QKTXTo_r6;bG);(Ol?)p5ganXKzFs+>Zuw1YNQ}(R1Un z5n<%lqBBuFmK(=%SG2vm(UISeoD-?UV_cY})6ra5gs#m#bVL{3A3Dy39<2ppxhiI( zd=nZ#J+z%R=+gB;m*N3*H$9C8wg|m{4Hk6&f5?SX{XP0MIokuFToB7pu8r3BM04Ol zwBae}_IwT9wmW0}&uE~D2Seb6(7;Ngfz&~Bq61z<|B1V}uz`os4(7xgmZJ}BLX+tm zG?0Iymp>FnR2p51>!a<^`|d_N8jG&|G|Yw1qcijxrvLk&HC#-iVmsc7T}FnHy^4(~ z??CtK<qv11|5i*LbY>pMlDGujR=cq(p2r)o%Bb)I%|P^^nuoTtAALUK5%#|)QH4js zjcu?T<+124Sb|OQ8}w{1K05r8sR??9KY^a@pP<kEg)T{vF(J^#cs=FG*bP6xK3IZn z-v*yZabZLIur*%$Xy|A#8sQYQgDiA}2homlKNhxOO>9niAo>niiM8>&SS~m=yd4{3 zed?#81KW)zc_K9~tVv}wscwknHt1`#D`wzeya<P)+vkB;9*b_@i8vIepxZR@c&NV& z-9`EF5-fy1UjogwR242f@tUCz_C=@qKD6PPXvg!S3((|x9S!(Bw81aYr1~CB+P}~N zTs}S|X)$!$U5C~;L;^}BZs)>|?+g`*yU_;kk3NQG?K81F8{JN?q5-Ul^`D{*e~pgx zM65rJ?)&T$!sq$W_DkVq?*D4(3l5O@K`S)UE@;OC(S}E$9ZtX;I1jz=RdkBqL1*k; zbS5^T&+S2X(Gl!{<(~-K{VA;I{(pmuqPQ15T2G@5B`1cd&yCJdUi9-K=u4+!v;i7W zM>L>2(GlJo>mSDSIe<Pl4LvUwV*20z*u;e$e1Koz9&|*nKN&iF3k_%;IwM=6pP(J@ zM*};A-uElI1gFr0=K>l)&Zolt1<?D7KE?ibs!CH~05_mFHbqC!A(nfg9S=qC8-*s} zL^O+ELbq!c`uum%U(x%|MRQFG0Tqa5PGaACV3ec68{0&?p=&n~9oZ-}&?nI;oQK}O z9Q`7)F@Ams-A#YS&+|SVlCKE5G*!^R>!I(6j;Z*;5Hz_g+wn}agGFeE@1P_52n}dI zx(kkCLp&2dzv-Eb^uKu45`FJKk8bCG(C4n69FFXA(Nt?Ln)AVMw80JNjl1zC{0@!u z+9_eAwb110j3(`UXa~<?16+mm@o)4UP<v{4?mo2L8CVh*ATyClZ0EvcIfzd2F|3Ja z(UDi178+=Z&d2~XsqROUXbd`I<I#OS3(b|+(HUEbw!Z~$#E;RWz2sSC|K;Vvh6<q% zW}+QbK$EZrx*O`F0W`tuuswR;c=U_NWb~w*iaz%o8rTAKY2QHyv;!UJcbNY7fBxXY zj?Y+u7flc4%h04Lh(1^rJz8%<r?N8|KtJ^PA?QdSMo0d5EKf%Rc>yzV8M>sqF#Z4k z{)r2}^ZkMKFwczeKx=e+^+W@CD3&Lp4a`Tg`Cat+U1;{7K$jxd%<$aRn4VE|o7O<T z&~%&0{%^;{NGitTPF#=ep36x8x1M=sWh6FGUW8Mz@9dD(r_rgteNJe&D?0K%=-cuh zbS8(POFJ@t{%9;eg)Zr|Iqd&sTs%jGYu5DnF!J_j19wFSqaBPuM>qyu(|KqIE6@ht zMcdhk?xr2+3?7W0M$d~pbHj60Q(Tx-*P|UYMjL32_hZ-i`L0-hAo>%!=BHvgF)uuK zDViGvqovWMsDTcs3Az-m&?QZEj2HdTjvqjiXDpgD)6kK<f;Rj*+VN^M@Xcs)eu^&1 zVYHo}V*M$!y<9H@3!(RwMRF*WsLX|tHH$a2K|8z??Vt}j)kD$9C&c<G=yUU;uc8ev zLAT=y%#QCwv!ZLG8`84>H^qvrID`j2Km(}tVi-wXbPAiHS>8F;k3eVQQ8Wi8p#eOL zK0g~B`3vZMOQKoPEtvlO|0i6e4+M0?f1qn~0o`7gzZB|AN2{Y#Tpyj8meJnm{STo_ zG6n7U)#x(xxwWzU0jB@`kKJ52f`e!SN6-NNL)ZM$`C$eMqvZ-{z&D^--Vz;YPqf1! z=!`v#1~LgfxaOnh#yT|FznIVd_kn{{xVAr`Yx+mL;SAbP^5rlCSE2V8M}K0fga+C& z+6|q-!O@XuU=yM<qpwC+zMKj-Y>5@S(GCxxQ+pEaFvo&0;w#ZWOQH3Z(Y3w-eePy- z*R(<3lD%U6C^V3#V|gw*14~j|*x+h3dEP@uunnEs&(Q~uqBC<Uetr&ZAlED5S2X$2 zatrh)st$M$j>Km8BYJREc{TjXwiVi5>S-=q`x&?d=b}@4%WI**{^-bt#qwA*u&2>v znjb%3g8eCPKxd}Z!jLOfF+DTrK--`lcSfF1C3<pUQVd2%IzD`mn1POHKDx$>(HUBc zcCaaazBAT;8SB4613QWa`Ue`o#f!o~3!v>3NtfCGCAl!73h0g1(JXI_u5EiXkWT2@ z_KFTicfojc0JCHLa&+ytqU{|(m-JV(owMiwE_$5-(|_U$E?l#sXylEeZO|#Z13h@| z!ZP?Mx<s$X`t4|ghcVqz^ej5koNt77@}M(W03C1{OuzrDaN%pSHrmjQ=m?sj5A?zz zI1I<&_vr5Exj4+w1L$+3&>5M420jNJ@d7l*mY@S%iMIRRV)nmN{TUTTbRc>p`U^Vc zr*H!1cr*O1n910O@;P*gdMyd|LmR#ueeI4yXJmSGJ{rJV=+eBqg#BNViyc(h(Qjy^ z+1?5_=0qFHk0xhDbmVn06WgID=6%=;pNyX$$KI5)Ee$8%UFdTud<18r?OmB#mXZF? zYKx&2528~y0gZG@te=Ypwm6oTqk(NgvwS}~)hEyyIgOR^ELOnsZ-@3eqJi{AXFl~1 z7f!_lbnRxL4K0rK@1Ox~i}jzPQ@S6`kt1k>7qBQ^wLJX3uqHZy$>`4q&!aQ70UhWU z$brPa|IdXlhiogtm%?i>lkyGN0K1|m*F1a(*P;zqUm12qJ#-{@pi4L~Ix6~1^d<C5 z=W?{YPq94xCr)tT{w?rM_`#zpW>W5lM*0LA`Eytb-$G|<57xn>SR0G23eR;#+Z%=E z)(k9*?_z2E0UhuqtI_>mk_$Vihep^Di{Wr|jc1}$_!d^fU9moUR+#$2=<`+4bEFv> z;N9r+W6(gJ!-}{LU9w}C@`LkS7*UBeVM=et{*=3-YrF-$?^{eS)w?07u0h}Lw_p|Q zj?U0C=s;FtCESHK;dylGZ(JJ&*mW)Y-=ukjiu4+zC*4}i#J%X${*5+JbzPW=d(jT2 zp~<@x-39OAJluni<IweC*PKFU<UcfdFW(TpBVMzC{qKQMgbJ;UNxT_d`$n<cK7QUQ zmiwb8-e7cFK8Ws;F=#SAfwnUfP2%U#qxf4i7k)sW%bnU7viV9hvLcubE1)-2LLaOV z%XQGTZh+5WXG|Yl=n`amF9cQ%P0kxJ9UywbjzI&R5bIM@xNti?heo~t9ogH_b<q!^ zyU{8C77g?lwBg^d75<IQvB{>;?v&_UG|)xpQoM^imr8uhg$;gzMtTGd=ma_=|Da28 z(dN)meso5zK|e2!j;IP&#@cAI_K%-GjkY@neQrJ)@WOOG`)?^1j(imw;nrCG5{>jQ zx~)#59TnaZ8Y+PXP!0{a78+<nbOzhS&%2>XJuudfM+2Cu?*G|b*uZ==i<e+q+=Mq` z-mT&90k+1blwZSJ@B|LPn(v3eUyQzuo)=rt0FR&n{ejNFxmeEF#{ReCJY3jOVf2Ph zXnl8dR}4g_a3nfYkD}Q<8J(f&Xy6Oc8Cr`zzZHG%Gql~kXh7e_@=x2?|2FU&6;4t1 z4?+V)(1WK8&c+6@{%bT>4x=Ob3q1!e#PT)ULwy-E(Cg5^>c{f!XaK!q{gCacFv4+E zxF*x%jdRfvyn&8r6&mP9bVhcgBl{k`?-;rp{zAV=okrgQXV5_NeHdn}2>N*mw7)Vb zE^MeuyrCAlzw4qSXpeT#6HU&+XoF+W*YuOo>3BWm7jPMVi5}JCKMH64eDtVZjqPwJ zIy0$jcZ9#MR}HP$hjx4%?f74G?Jn9GvO720P+>HXDp(imp!Yq1F6AT9+2|6zgT8cj zqc5c&!{@2Qg?Pi&ABU-~jm}5|G|6s3w^b{2X1bw)4UeWU{X-_&!Teai8eOt2XwH0z z26!~qpTIo6|1WUi)aLmlj3^VGfePq@H^lO-XaJqjoEU<B4SxvDiCO5HE<y*e44t9X zSP?g)?fr@db^(jH|F8TsR8&Jp))<|lwpbGfU}=0Y)^9@_IDmHeI~veGXvf(;3-vkC z`YX^t3dM3s^u9`%@}dS8CR1H>Bu%guc0gadPooX(Ks(-pHh2_$?qvM@EIO0PUE#an z|Il4f3%##Rv`e(lF8048y@v{?d_3Cl^jLloJqMPc+57=IL*HW$`~^E<tKFgF*RU<+ zEHs&Oeje8R8Z<YGV==59?fN<UzabTmP*E1&LzCnfI<>!|BR?JMFQ7Aa(VlSMrD)(+ zq65i{<=W^>HbqC?5q+*_v_Cq~dsAF^B8^0+b^@9tbI=hlj^%CW)b2%R;8-mGg+6!j z7onp<Xy7H#-BSU5c~wPs$?fs;foMRfVO-eYL-;j5j*hs;m*Iv1XhTELk&K9r!S^Xo z#M0PmZ}{PK1g5{rq3y0k2lN3tBm2-L{Si4QQi*K)!Uxx)YgP$;k2k;yI22vGd1wPG z(DPtRtly0;*^ik1LV_N#zo9exXDlc7howrQ1G*B^zyB`~D~h61SrTu<>tlHmI;Ag0 z7os_{6o=qRw8LIsg~0lvGcW>OvS-nyd=)eCJuHfcF#Z4kO?({=lB=*YAJjlQd<I>k zndk%a(5YOHHv9=X!tc;zI)UE*H#$@2V||`)Lb(unfR#fBS|3yQaB&+KuHj~MdmKae zZLV*_pLUl(&+t}g5)Hy8n8N0`4X?+`4}^}IVRg!#&~_$a8GIGX<Hu+Y{C$A^@5>_Z z!O%e^JWTmk9E_E}3xA<tE;^+jV;%e%ZJ^Yl5KuidM{Y+4G6?N>8hYPibP3+axA8ml z{;A)mLdOfg4-Id{-h6N#J^6b55F&pG9ntn!K8x)smpB}j>H%~K#-K_2B$||~uotdF zm*(343rklLUAkH+F5D)K(5Y{OCf_iegxjzwwmZUF;cRq<3LXs||A#I~^2cxh6^d3v z*Sa~n);-Z=9gb%IVKm^>F)q^E1idkFESN7^8tvc)bPZdhGw}c#_+re4tI;o=YtWH@ zgC^nkX!|E)`8=B3d45XomQ><@TzG_*LJywm=s|NMmcpj-^TC*%^22D(j79^Sg9C9X zcE^H0hhMQgfKK_JSP{>lGg9VwSo@pPGN-q5;m8M}Ni!PVUe85ekDsqabK(>1iMdaN zzcVrzP0n>_2VX^h#~Uc;_$36|03BdQG_W3+e*gF5!ZjI>W$`I=MpmLTu^C;fomdU` zVmHkBYxp~$ebFWP1Kp;je+&NsV<YsrZRlHa7us>z-$S5PF#YHMO}TJQT4H(|p=&(| zZQxn-!57fLUPZt8tU%v-yU|?uDS8UciEJmsiI{=T(3R*(SruK%8YkKRc5povcF+(_ zp5|yrZ7?5pkL6)#lBKXFE<lrOKe}W`(1HAowtE3>H`gDbJ}+7>6w8@^u>W0?vQ*e% zHMGHcvD^}Upes7kUg*nbBzhE2jLt!qYB3t{J6Ik+jO9P$=Q;ii?dL`BFOuTItSyU1 zJ^`J9$!K=ZKm&XOP0|%;fZNdfKF89yAASA;x)eG7irW}%r!+c4bz`{|x;<09x$uGe z&@~!^=D<93#4FH_cc2d(Ku7)y`rLVR#JNs|`--63vl{w&E3~~XSPzHbB3y=z=s(fv zbja$tcoQFdg6`Mce}^NvHhK;W$Mk+jx7kwkt+)-V;t?E&|NAE+@f1Ffo|vWn4cY%1 z`rJ8mm*qd>0J-BPF3jc*=txFj1DqJ$fwxe;^lbPQO9yoA#-sO7K?8XO&6TZ~o-uSu z4xmeQ1byx}nro*l8)3$OVNEYXr?xP9V+AyeYob$FA5FfFXajxGB^i$9#JE^L6}|68 zG=R6FtI!$VfR*qprrbv5&V?lFf%j7$fR5lGI--;4%jq91iG|OHK<l9$wMA#52byHV z(E!JzflWtWzw^-pY8`t2{`2gAJ30|7E=2QP2mzEqAE<-QOeb_E2B0G!gLX7I*3XNs zKy&3ow4(#)5}%BpU%`2sJ}DEaWIEzTRM<g>Xg{>!2czTBkxoYgUVsL&3f(0;qleMJ z&Y}V2&X!E?f=sMVxgy$ePppEYQ(V~KTWF-4(2l-9r|vMijebWP{12VtyxBuXCD1jl zj^0-n4XhdZeD_!$g!c0&dY(+j#h9AMMO!YKWhB%8UEXZ8qa)}@&S3hxU@~-20?mmk zXp+{7_4U!Sy(OCMZDV~$bY^?U@^E~Zate9rr4nbjFro`+hdD1wrjw;0dLUIt18RrP zOuy*;=>3nQOEn|9Ao?~sGaJ$SK0s$^FB;$vIK%yajEj0yjJ`OTJ{UIOt(1?VYgR2s zGX0-i^u;Qa-^b_hFZ5iPlrx!rTYiBa#s6V7EOALP{ck^Zz#Aza##)$}E17;bbi%Uk z|FK+T;+tp(AEOQbhu2|~+{yF__z>Fgi|BUTg_ZCR^tsGSLjY~D0_6wM=U>4Ga4&j) ztINX7jKY*_GmZ<Vcm|rCZ=lKeL9G8emVZOnJ|j<<p<L+w9k4mxhnct@```iei%o;e zlj(!3DY_)>&?N41c{2R_pLbJXG7UqMXcW5kDKs};K-YL7x`ywdGqee9@RBRS=Xud` zQ8dsp=s+r?-y0gD2T@;i;E!Ix{`X>9tXL3T8GS$cW%MW-(BEh>Ch~^lx*XFTquZ<u z+HM_m8@9lT*crWVJi1MvNpWFBub^+QjpzdnuS}+2qixXay*oMz{d^MI(QI^tZ=!4d z9y&9}(HyCfFPZoVJK_S&%pcm@iq2?iPrUdZU4q}x4*o@_@ZzhI>F;uvq2JjqM@Mia zI>N%y3h1`F5nbDc=<~OuFR?q&_WMPLA~TpuJj{iWJQ+Wjg(l6*;fBOQEJ}G5+TfRH zN8h3c(+_CCXE7V*{9ouO7kYpGSiTy4u2ihAfVtfN*Ky$#--I^Q3jLzc71K$Hj(8MK z$8qRX7bp-uZ-gdgE3|_yX!7=mpN~d!<_UEBPDN*Ki}mjRJzSVf-=b4@96R7SY>c-R z41vu?_wj3Jz}FNCGglFPz7862b4)*nc03!MiI>p<zK%Y>3R4Za*v3T}%vm@@Ru!M1 z+yEWPN9Y4TqDl2P`eSvWtHax`Iyz%5&}8l%%cHRe<r!EL|3VL>^4BEO|J`8sYuNvG zFpmmHz7|{I$G8X!UmHfW1^xVEbOZ;n0gHVcOHi&<G#o(f(50A*wQ&);%?_bScp9CF zY?<M{oSCW6V16oWxEPv@m7_OCZ;hXKMmy+>z9WXAxv?Idq4&{tzKDL0F3GPr4gZPt zPZbL@J1fP753IscxCJxu7#heW#lzGVh*m~N&;-4|C04@wur$s`lWRM=JNBbXbrM~g z+$ESfERCKYsR3M=B%|;pd>lt$$&$(RU%8xvb10WDl}x;a@8c-EuXO0>S9At0pn>Hm z6Si+2G?09;ToS#n9Ga}vkb$QX^|^5BTA@kQJ$#TDfll>f=*#IDGzS*M`ghO<H$^{0 z8{UPs_Z_<SzoFm#E-D+!B{98QF#Z4kY|e!ZbwNka3+;G7tRE5UA3*~chfdwh`1$K- za=nf2|8-aaH={4JU(h8!iS~0I?dRfhwCDc6%nK}vMqUkPU;`|Vd(m9TRz5_2IXbmP z(37$X`g{#!QzV+A9o&L;*ap3?6Pgp<(7^7;^q>EY<iZh*M<1MuX6>w4|1uiDlIU7= zN<Ty!{t?Zg6X?t66x!Y;6+!^{(e|!Em$)>R#G5Lx|DBrNR5+zW(6t_mo(r?k8Civ; zaT^-o3G{3CpJ;aHt{7&d6uNY^&~_U}+n~>NLj&uB26S&l_P-rGM1|X9V!ZJcbVQ5M z2Uf=NMs$t0qcideZpUxXsePqV7~y&>MtKjqRHx8@F0LFp&WFy_wW(N94ZBcL7t7+z z=titd`A2MmC8{LTe>GzuPN2LS4YYIBFk`*YuVg8-<9X-+-$FawfCjodmQz2+i}UD> zS5^zjR2=;|z6Lsyw&+yf7kwJtUJKFWTaPZ?r|421MgusFMKQ;9A+R#oh;n13{ZwKi z7f$`FI2PZ-`q;2~SmSY6hVoo2hg;E^_yxVcdX4b)dNtOg{3q78zGgE0)9wiDPI(3T z+!eKw>3><NBewDVzm1E&d~ntE$@KqLdlYu0ybpc3RIVK&Z;wMM4?(B!5c>JQ=n`Ce zLrAjH=*TOfOL;RISbua07GXtPhr{VVag2+$*sV@7{l8Lp3%5|tUN^iZx1rgdyfJL2 zYtUpWiDq@RSgwsOMH4izPIxDdLUZVAydM8|Q+OG*##ApV4sp=|8{V8u|MGb@nv5sV zDQ;RXnf|L+AE8Utuzq-nbVql=OIRA;LQlRg(EXigkW4IuQs{FZV{`lw(}6c+|9erp zVTimQ+F(0ujXlt*T#6>=d+7b2q5FI<x;=l0pZ^le=i=u%8-@GxqX*U1=+b4P?|>T` zvHv{?ZlS`gZI3qC7d<+MqHFt5^f5Gmr_lSSp(om_Xp*i&M|wDZeja^3Z{x5#3ZuKK z3K~F*6c>%T=!&=DOIRBJ#LZZ^Niy+0ev5Xzv1#~OZyS!Ld<yMgc(V}jBj^AgM`v;h z`rHd>&b*4wz;bj(Q#-hD2EIl|{D0_!C*lof(0!llme5d1bmSG#j&4SmqIt9f+D<QY z$_JtW+#BofkLA%wKdHpyTsVSfF%#$FMYtaAU<(@1CupGGpdB2E^}j^VqW53YJhYb| zZRc7v`%B=**aK@~#aj)K{nwid8|;q;G6bEfhtLMcqa&P(HaHI*(Sqn3=zVXaBVLD9 zaT7j+C$S8sS|rndu(=5Re6PCybF>T<wb5-j5Xa+tSR0$PN~V8*KL+bi-itS5-qxYq z7TwpA&|R|?ovAC^grvI$J*umryQvu(aA!>Un(f0yF?=k3@CusMOVKlZ8)o3w=u90% zpF4`aY?5um3>8DOx)OR|-H6WA?dWrNpflSChvU$;?0-A>zj))n@y0~EaKPk58@Ls1 zpk1^JI)Yy4kvce*AB~?+!jjZaN5817iS9#_`7|2f746yo?$@&I!-yN95q3qVus@o7 z!_XW^p#e`qJD!il@f~!E_o40mg5IC=w($1LkIq;P^uG4!Q9U5Vg%3Q8?#r2I087yb z*P#vVL8tb+=&xvi=g^tSaeMG`G)W7f+w@wry{hQi--OOw>sU^8;i5VfgV2$^h!t@q zHo!w@N5wmY1}fr@ly5?JOR0`wi7KN5sEG#D8ttef+HNmAhY#T6IHFVf^HkzrE{r(Y zIgB(H+VKC-h>M~PRYgZq7rp-$bYHhdXX+{RxdrHqy@>{%g(mZ6G?(_{)A$|ccK;9V z5{|-$&;}-A1)PSi)dqAb_n-kCMFaX99a;9S!2)P5RE)Mk&-(lDL7a?b@Zvj?=|2~& zjJe(a1Gq5BMxaSC7VT&TdZ4_9j(jn?-LlXCzrdE5=oX%9g-(4BbSe6yfj)}1HwoS5 z^U%OHV#=4m*Id}a&zK$=nrzv-hwYOW9cfi`Mw&$LK(l%n8u*l0|1vtDEG&xK(EE;{ z_hsA}X7s8%+5bjVmI}Ait>_JRq5%wzH>S`4o<-Ms5jw*6uo~`1r#@GY&~PPmhU%lc zYcN*DComJ&U^)D%M=JbABBN(Wnp)9@XaKFz0K22flR{@|0@lOnXhVDA=jYJplD)zV z<U^CS7&^c*=n~aM18$V!!Up?Ahojm1X!Pk=KO4>F*Kj5-L$^_r-r@Nj=$h_Bm-J6G z>ofX<6R$9qrCb9Iq&pgDY8V$z?W1@T&P11BPpm(JuHhNHfQ9c$rvI_Z!hMtJziRyq zx(&<s3rW@wk5GOPyJGkLA%Hd5hVtjw0E-Vu@3vIpE-qZ7d+=_Y7(Ph+h0e@5bjorK z3?sV|GbtCxR@eyLCDYL4eGVPK%jk0}V|g9=F8Bl|;0a9s|38Kg3O7E1?*A#VJR7r7 zo{z5K0(8n=N2fLmo$61~Y(I#;Tuz|5a`D|^DKA6sFN7{(RdmMdU`C3IHe49_ZSjUX z(GCZo9o~zMaCH29EZV`-=nPGd_4Co0TpZno26!m?do(dP)L(%qPqs`hoU-cZ_G*IH zVRv+7Q=>1Ufh<9%aydG(U1;+Ch@KA__k;lyLT9unn$%^{-BbgeiH`TM|IOx}RCuzT zMmxxNZ@8f#+F<cmu8oekAsToabmn@a4c~))Gn#^S{3&|!?Lz}N7R!I31HNbo``@)F zFeF4=5&KfU4u|7xG`lYy8oo5%f=wuo!DjeA_VM#!;VaruY)$z?G&u|0mrOi{ebE4a z#FBW)@bE6EoZ@0K6&<k=9zjp4awEcPxhtk$9{48p7vCS2WCa@7CY*@>;aD91K*;W# z4~FlAQ}7`5+pz~Od?@^Ack#$jPW9xXPBt3CP26zyVSckodHtwlVi)BcqmzjNl=q`k z-+&qGh^?_DzJ?yfe_$2N{b+c*)y3MB@5ceS6mP=<kA;EVjrBQy5-)La10Nj17Fc*} zn8JQoiSjC}j)$=w78n;sHV`XPei<9%r)W~;dpvCCYw;1vrLZ$DKy%<M*1#O&lZk%5 z|8L~tdMaK)x7|1Bw)-Bt;qPbzttN!u4=hCAX4#(zU%xZ4Eaf}Uh9AeK_%3$B#KiDx zyw2#Z8i&1cH4bq97kV-@JQiJ}gXmFt^HX6hC!<Mu)ua&6D7=&Mek_C6KOM5Z2kxi* zBARRuJ`=X*9CW7MjvhdlBG+X0zf*fB7ru?2#d^332jMAfk3FY^5v|1fl+U0^S$AqU zvR9(zqSHch&O)d9wditmn{Ggt=tFc{em;%;?@4x;3itib=!3tZ51hrdc=5AgX*Odi z%G=T8`UTxBrKcy;|IlbBTu3?B41NPb(k{o6_~p!yyl0*Z?dO;k&WC)n$XbucYp5uI z714vCF?zss#QHc8-END~+&GE`d@6bd9oYr+rE|&b&~9FI>WiTRYmMI5HGY0qii>Jg zjKD6q5N#kaCj^iaP0FjI#n1-Ipg)pTLuaZcI;Hi|0klI0)(1=DaLk9#qxUbx4>0vE z7Y(?0^!X6s7PP}pu_%6lKJXX%a=8#cFFZHQKqeYcDRe2T#Bwe4-B2GriaVk0_QXrE zA2NVcVmKE@{vbL<6QeWG2j|D~8)!$XV);F^p`GYR_s8<F=qdE&m3>}V+AGi*D~q;U z5ifTC*W|(mZbWmSCA!9UVJ94pRd6S!lM>zM7rzkB_`3K6<tNem^1c|(lLq(z<&kLM zzvB=*6U&2MA^`eNjNrmGAB9FZ4o$u%&?$Q!?RY+t%!xN+`K|c*8uYo1(Jkl*KZt&Y z<tXn*lQ#SO5Ks<G`Hdwn7dB7<orx-F$Mw)PZGygrTVf{mMgty)F4-h>=4Rn7xD4y# zKe2qn%i)|DizTW56>rCU3)ugqxEQb?{Kj%JHmAG-t^W^=y!b2Owc8R+)@RX<zCati z_SJ9%H^lyw@5VB?2R(AnqPw8-YvCa4fGsJ{^X+vj7e7(a8fz>Jui<g%4cpO|PX0yV z<<t+oe+3T1bJz@rydK_)S?F_l-U#0-?m(AvD4J8_(3yG`ozcZ9E}X(mSR6k_*X}oT zzy5<J&!vk)`G07G<uO0r6wB?=Z%}>F_Qs+)Gdb4J!3vaDqcipc`jst}<IOPjCD18r zhUIYxmc{4M9NCJV2M4eqp2J%Bza^oeR_Kxq#DzE|TI;P4=mB&ff1uwT|3e1K-~V13 zlBpzmLq&9Cwa_VQfsUvbI(7G;_l-vbo)YV`&=Gxx&ctynfjO6jnX8DIl<VVb*bAS} z#{SFkb{OG;<>4oq_2?1WWkonZ?nc*cBpSfPSe}m_T+7fvH=#4L7Y*z;d;<%tOs4-M zw#{fRb$uuNYIg~y|Nh^-tHPQ-gmyFuJ-MF8M)-QHKY=FQSxnEw>abnMqscoHZ^Zw@ zCRi*htaX1hx1P4l0kRCQ#xK^e|7Y>R@9%~`5SX|&{D!jdIt~hMXpR&4y!HB!l>5-+ zJA{t-PjqQ6*$}4qD)js)7rg<!uX+5u2m1VQbf6P9u>WmfCKW#TGJ2*jN0(q@ym1$r zG~b~wmGiOws*RzclF{mDvNl9#uv>Hx8puOvPE1DIU$K$>ZzS(iVZ(dSfPO{;I*mSf z@q1w^uR-r`fF@yEbh~y%ldccCZ68Ggn1SZVg6K-LpZC%Bze#bCgNx(Hj3@rY?05=2 zlK(*?{SQ5g^K1%hd==hIxjj0fX=sP5&~3UE-T#Nt8T}P+z_aMKt+_b_o*K-BBf1|i z!pG4Eo<bX#g^qAR{QONc^5tmYo6*2NLId4}eoy!Tef}IeqdB*P_VY&zBlW37CKqON zMYO@jXp*!<8|;Bj*|1nYF*+BW+NJ1y@1ghYMz`NFG>|K{hTN%uohaXm^>6_$_x=9^ z7mi@Y`ys-)=xg%jSYC*ZU<sOBYtR|^JbwNI8pttp0RN(Iw`|+Ol5|AxzYFbW1UfUL zF#Z4ko4|!hGYh@(O>`~Sp-J`;`rsZkN4`dv>RYs-AELjY0sMmtF!4cX=N0t6<!GSm z(Szy}O#l3Ul#7v6{EId`d^<-Yj>I{b|HH5gmZE{YkLJiuG|>I%j2%UPGCGd0<0T)3 zKWbfp6)6|n5dv(DRVa7d!Tztw#e`U~9&O+RR>fR9!`jtFe>v3^OW|y6iW|}7yy)Zb z`ptvYDfdOQeGZPtJ?MR1J_!TpjSgVoC#lfk15`Nj8R!%~k1oZ6Sid5c*Pv7PA({){ zqc5GavA)2kAy=xRNqHkW<*j3V5A-O$8(rGTDK5NmHulBE=ox;+XW?hRR(OeLHJ+gU z;I8nOPj~JPe?zMG=V1W3_JjkfEH>c2R%p^rL6>YUx<m_N{i0Y-t>nV(wkEn09pOQA zCjLenx`0k$?k~cc=f}B}i{qQP5g*1uUnUdt@d$c=P1qZf`zbVl7i0Mqq~BB`iwh5+ z9q3Gag-+3NycP583lDZdcgdaTl;4M*bd%9tu@nvPZM36zqZ`qs-HImbN9g_g@KX2x zS6sL~j-pd_GWrktMdSk7VE+AK%?hFA66nm7MH{Yx2G9`gumzUGc32rlVR>8}{Swpv z{%7K=@QZ{>(E)fJH@<?N@q5u-a@E%%H(FqA$`i3JZpL1C4!dHHZ^Cw7i<2qW_?CT+ zThW(PqXS`E_r#P(<{2((VBUk_i$qg&?PsFN^a7?|zc_~SdAtKhe;0m{@D;Y8T<K8w z1I&@=QTrL*jb*+M_0zF4<)5$(HvED8?~Tv?5JvDb_NLtOaBvyg(Ut!f9=sO^Q{En} zaU_}k_X1x=XW-7G$wW`wgnh8skN%E_?}}I!Pv9WD>R9;N{^&9Gzsc|+6|UJ1tbn`F z1L8k)pI-7)NYZ@K;%IhPLr=1r=#2G^_4i<Q%EO`~(42V?8{;E53^%8^D8@zgpTiN^ z0bSd%SQ6KvyWtR4!i?h~iK?N`b;A-k2EA_qx+}I}89Wlpmz@X$tb_(y9UWk*E*ED1 zEoc_shR#GUbUXHs<&n`8djEKIL{riGW@08TLU+N3=x*ALwznU>|6u(5FuvvfKf#3! zKL1O2;59UmC1|8;(FeDn4R4R-U1-B!#_~7u^F!#-{Zp*}H+nvPp7CpF_tLcNi~L;J z!8K@u#n6DtpdDTp%XQIQXo?2b7JaTWdJc3)pBsn{U<8^YW6}F3L?@#&_8exqFJI@v z6YwK+%J!oje}^8;$Iua-MLW#>TWIhKw7wwPVOjL^T4+FZ(EysE?Y2N)M(xr2`(XOt z{~H!7#-QJJpGF&4fS!O$(T28SdI`{x?uvecc5oC8;1_fk{ecdw$nPQ0N@&vEgtl|* z@9cl~`)ySC9dI>P#82amXVC_8o(zFqh8|cY(50$_j-);sK<j7+^to>6)c1-GL^~c9 z%MYJq|J%@5DqP!%=!4Iq0nI``Uxqfc3Z01!(aq?TZbR2}FWSyAw4*=J=g!9Zj6cG! z=`TZPVrq&DJ9;5jtU{-LODumH%io|={$s5F1MT1frf2BS5Wr<viu$5xpiR&mYK{)1 z8yaYDEQbw8aAAZmq75xX50W?0<oXm#;z2Bn8GnTaE8<wn_5R8#pD)|yT&s&@`|ake z0^PGU&&+y$bhZ+g&f5NDwrjI4eJWe=YqK6+lx<n>tQNVlx4$-Pb(!o}<eRmpPWHK3 z<LYK_c30MqFJ<3)Nmjwd**E9RO0LY_u5eb5PqIICdDg`TvOm-&YkkFx)n&8RcgWb9 zXV&z)GRn@n^{$NES?BM{$Sjl9|LKgKBeS|*oUC0cYg2_}?Siv%HBSDQRkcYn*VtL9 iTas62joF@Do;&N!J;}|vvgRF3eqK0h)W69B+5R6d=}Mab diff --git a/languages/sureforms-de_DE.po b/languages/sureforms-de_DE.po index e215ff91a..9a699f9e8 100644 --- a/languages/sureforms-de_DE.po +++ b/languages/sureforms-de_DE.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Eine einfache, aber leistungsstarke Möglichkeit, moderne Formulare für msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Armaturenbrett" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Armaturenbrett" msgid "Settings" msgstr "Einstellungen" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Neues Formular" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Einträge" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "%1$s bearbeiten" @@ -126,18 +126,18 @@ msgid "Nonce verification failed." msgstr "Überprüfung des Nonce ist fehlgeschlagen." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Bitte %1$saktivieren%2$s Sie Ihre Kopie von %3$s, um neue Funktionen zu erhalten, Support zu nutzen, Update-Benachrichtigungen zu erhalten und mehr." #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "SureForms %1$s erfordert mindestens %2$s %3$s, um ordnungsgemäß zu funktionieren. Bitte aktualisieren Sie auf die neueste Version von %4$shier%5$s." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -207,7 +207,7 @@ msgstr "Müll" msgid "Published" msgstr "Veröffentlicht" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Ansehen" @@ -299,11 +299,11 @@ msgstr "Kein Plugin angegeben" msgid "Plugin Successfully Activated" msgstr "Plugin erfolgreich aktiviert" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Aktivieren..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -318,17 +318,17 @@ msgstr "Aktivieren..." msgid "Activated" msgstr "Aktiviert" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Aktivieren" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Installation läuft..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Installiert" @@ -336,11 +336,11 @@ msgstr "Installiert" msgid "You do not have permission to access this page." msgstr "Sie haben keine Berechtigung, auf diese Seite zuzugreifen." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -540,7 +540,7 @@ msgid "Dropdown" msgstr "Dropdown-Menü" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Wählen Sie eine Option" @@ -560,7 +560,7 @@ msgstr "Bestätigen" msgid "Confirm %s" msgstr "Bestätigen %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Ich stimme zu, dass diese Website meine übermittelten Informationen speichert, damit sie auf meine Anfrage antworten können." @@ -617,7 +617,7 @@ msgstr "Formulardaten wurden nicht gefunden." msgid "Sorry, you are not allowed to view the form." msgstr "Entschuldigung, Sie dürfen das Formular nicht ansehen." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "Beim Absenden Ihres Formulars ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." @@ -625,7 +625,7 @@ msgstr "Beim Absenden Ihres Formulars ist ein Fehler aufgetreten. Bitte versuche msgid "Test Email Sent Successfully." msgstr "Test-E-Mail erfolgreich gesendet." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "Keine Formulare gefunden." @@ -709,9 +709,10 @@ msgstr "Zeigen" msgid "Hide" msgstr "Verbergen" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Formular bearbeiten" @@ -722,7 +723,7 @@ msgstr "Formular bearbeiten" msgid "Edit" msgstr "Bearbeiten" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -736,32 +737,32 @@ msgstr "Erstellen" msgid "Import Form" msgstr "Importformular" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Neues Formular hinzufügen" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "Keine Einträge gefunden" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "Hier werden Ihre Formulareinträge angezeigt" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Formular anzeigen" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Formulare anzeigen" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -775,30 +776,30 @@ msgstr "Formulare anzeigen" msgid "Forms" msgstr "Formulare" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Suchformulare" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Elternformulare:" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "Keine Formulare im Papierkorb gefunden." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Formular veröffentlicht." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Formular aktualisiert." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Admin-Benachrichtigungs-E-Mail" @@ -806,7 +807,7 @@ msgstr "Admin-Benachrichtigungs-E-Mail" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8331,7 +8332,7 @@ msgstr "Formular ändern" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Dieses Formular wurde gelöscht oder ist nicht verfügbar." @@ -8882,9 +8883,9 @@ msgstr "Blöcke zur Schnellzugriffsleiste hinzufügen" msgid "Re-arrange block inside Quick Action Bar" msgstr "Block im Schnellaktionsbereich neu anordnen" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9256,7 +9257,7 @@ msgstr "Zentrum" msgid "Right" msgstr "Richtig" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9266,7 +9267,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "CloudFlare Turnstile" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9327,7 +9328,7 @@ msgstr "Zurück" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Danke" @@ -9548,7 +9549,7 @@ msgstr "Standortschlüssel" msgid "Secret Key" msgstr "Geheimer Schlüssel" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Cloudflare-Drehkreuz" @@ -10506,7 +10507,7 @@ msgstr "Fügen Sie Ihrer Website atemberaubende anpassbare Symbole hinzu." msgid "icon" msgstr "Symbol" -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Bewerten Sie SureForms" @@ -10616,7 +10617,7 @@ msgstr "Konversationelle Formulare freischalten" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Mit dem SureForms Pro Plan können Sie Ihre Formulare in ansprechende, dialogorientierte Layouts verwandeln, um ein nahtloses Benutzererlebnis zu schaffen." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Holen Sie sich SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Gradient auswählen" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "Captcha-Überprüfung fehlgeschlagen. Kein Fehlercode angegeben." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "Captcha-Überprüfung fehlgeschlagen." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Unbekanntes Captcha" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Ungültiger Captcha-Typ." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "%s-Verifizierung fehlgeschlagen. Bitte wenden Sie sich an Ihren Website-Administrator." @@ -11242,8 +11243,8 @@ msgstr "Beschreiben Sie das Formular, das Sie erstellen möchten" msgid "We are building your form…" msgstr "Wir erstellen Ihr Formular…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Admin-Benachrichtigung aktivieren" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "Admin-Benachrichtigungen halten Sie über neue Formulareinträge seit Ihrem letzten Besuch auf dem Laufenden." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Unbefugter Benutzer." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sBeginnen Sie damit, %2$sIhr erstes Formular zu erstellen%3$s.%4$s%5$sErleben Sie die Leistungsfähigkeit unseres intuitiven KI-Formularerstellers%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "SureForms wartet auf Sie!" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Erstelle mein erstes Formular" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Verwerfen" @@ -11417,51 +11418,51 @@ msgstr "Anmelden" msgid "Register" msgstr "Registrieren" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Neueste Einträge" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( Letzte 7 Tage )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Verwenden Sie bedingte Logik, um nur das Wichtige anzuzeigen" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Teilen Sie Ihr Formular in Schritte auf, um es einfach zu halten." -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Lassen Sie Personen Dateien direkt in Ihr Formular hochladen" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Antworten automatisch in herunterladbare PDFs umwandeln" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Lassen Sie Benutzer mit einem einfachen Unterschriftsfeld unterschreiben" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Verbinden Sie Ihr Formular mit anderen Tools über Webhooks" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Verwenden Sie Konversationsformulare für ein chatähnliches Erlebnis" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Lassen Sie Benutzer sich über Ihr Formular registrieren oder anmelden" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Erstellen Sie Formulare, die WordPress-Benutzerkonten erstellen" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Berechnungen hinzufügen, um die Punktzahlen oder Preise automatisch zu summieren" @@ -11883,7 +11884,7 @@ msgstr "Erkunde SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Etwas ist schiefgelaufen. Wir haben den Fehler zur weiteren Untersuchung protokolliert." -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "Feld ist nicht gültig." @@ -11951,8 +11952,8 @@ msgstr "SureForms Video-Miniaturansicht" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Erwartetes Format für E-Mails - email@sureforms.com oder John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12330,7 +12331,7 @@ msgstr "Unbekannt" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Gastbenutzer" @@ -12356,7 +12357,7 @@ msgstr "Stripe ist nicht verbunden." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Stripe-Geheimschlüssel nicht gefunden." @@ -12465,7 +12466,7 @@ msgstr "Abonnement für die Zahlung nicht gefunden." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "Benutzer-ID: %d" @@ -12499,7 +12500,7 @@ msgstr "Abonnement-ID: %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12544,7 +12545,7 @@ msgstr "Kunden-ID: %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12554,7 +12555,7 @@ msgstr "Betrag: %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Modus: %s" @@ -12563,24 +12564,24 @@ msgstr "Modus: %s" msgid "Failed to verify subscription." msgstr "Überprüfung des Abonnements fehlgeschlagen." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Fehler beim Abrufen des Zahlungsziels." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "Die Zahlung wurde nicht erfolgreich bestätigt." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Zahlungsüberprüfung" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12588,18 +12589,18 @@ msgstr "Transaktions-ID: %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Status: %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Erstellung des Stripe-Kunden fehlgeschlagen." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Erstellung des Stripe-Gastkunden fehlgeschlagen." @@ -13466,7 +13467,7 @@ msgstr "Bearbeiten Sie dieses Formular" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Ihr Formular wurde erfolgreich eingereicht. Wir werden Ihre Angaben prüfen und uns bald bei Ihnen melden." @@ -15163,7 +15164,7 @@ msgstr "Der Wert des variablen Betragsfeldes ist erforderlich." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Zahlungsbetrag unter dem Minimum. Minimum: %1$s, erhalten %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Kopie)" @@ -15362,12 +15363,12 @@ msgid "Stripe Settings" msgstr "Stripe-Einstellungen" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "SureForms %1$s erfordert mindestens %2$s %3$s, um ordnungsgemäß zu funktionieren. Bitte aktualisieren Sie auf die neueste Version." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Jetzt aktualisieren" @@ -15415,8 +15416,8 @@ msgstr "Position des Währungszeichens" msgid "Select the position of the currency symbol relative to the amount." msgstr "Wählen Sie die Position des Währungssymbols relativ zum Betrag aus." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15430,40 +15431,40 @@ msgstr "Wählen Sie die Position des Währungssymbols relativ zum Betrag aus." msgid "Learn" msgstr "Lernen" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "Erstaunlich! SureForms treibt Ihre Formulare und Einsendungen an - lassen Sie uns gemeinsam weiter wachsen!" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Wenn SureForms hilfreich war, würden Sie sich einen Moment Zeit nehmen, um eine 5-Sterne-Bewertung auf WordPress.org zu hinterlassen?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Vielleicht später" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "Ich habe es bereits getan" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms ist bereit, Ihre Formulare zu unterstützen — entdecken Sie, was möglich ist!" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Verwalten Sie Ihre Formulare, verfolgen Sie Einsendungen und entdecken Sie Funktionen wie den AI Form Builder, Zahlungsintegrationen und mehr im SureForms-Dashboard." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Zum Dashboard gehen" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Ich weiß schon" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Ungültige Parameter." @@ -15841,8 +15842,8 @@ msgstr "Textfeld" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Dieses Formular ist noch nicht verfügbar. Schauen Sie nach der geplanten Startzeit wieder vorbei." @@ -16126,8 +16127,8 @@ msgstr "Webhook kann nicht gelöscht werden." msgid "Unable to connect to Stripe." msgstr "Verbindung zu Stripe nicht möglich." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Dieses Formular ist geschlossen. Die Einreichungsfrist ist abgelaufen." @@ -16797,19 +16798,19 @@ msgstr "Webhook-Geheimnis nicht konfiguriert." msgid "Invalid webhook signature." msgstr "Ungültige Webhook-Signatur." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Quizze" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Quiz-Einträge" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Neu" @@ -17327,9 +17328,9 @@ msgstr "Perfekt für Bildung, Schulungen und unterhaltsame Quizfragen" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Wählen Sie dies, um ein Quiz mit bewerteten Fragen und benoteten Ergebnissen zu erstellen." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Umfrageberichte" @@ -17735,7 +17736,7 @@ msgid "Error creating SureForms Form." msgstr "Fehler beim Erstellen des SureForms-Formulars." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17893,9 +17894,9 @@ msgstr "Die KI-Antwort war leer. Bitte verfeinern Sie Ihre Eingabeaufforderung u msgid "Unable to build form fields from the AI response." msgstr "Formularfelder können nicht aus der KI-Antwort erstellt werden." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Teilweise Einträge" @@ -18766,23 +18767,23 @@ msgstr "Der Zahlungsbetrag konnte für dieses Formular nicht verifiziert werden. msgid "Cancellation is not supported for this payment gateway." msgstr "Eine Stornierung wird für dieses Zahlungs-Gateway nicht unterstützt." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Schnellentwurf" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Beschreiben Sie das Formular und lassen Sie SureForms AI es für Sie erstellen." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Beschreiben Sie Ihr Formular" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Beispiel: Erstellen Sie ein Kontaktformular mit Feldern für Name, E-Mail, Telefon und Nachricht." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Weiterleitung..." @@ -18795,14 +18796,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "Die Eingabe ist zu lang. Bitte kürzen Sie sie und versuchen Sie es erneut." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "Der Teil vor dem @ darf %s Zeichen nicht überschreiten." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18889,22 +18890,97 @@ msgstr "Entschuldigung, Sie dürfen dieses Formular nicht rendern." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Dieses Formular erfordert eine Zahlung. Bitte führen Sie die Zahlung durch und senden Sie es erneut." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "Sie dürfen diesen Hinweis nicht aktualisieren." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Richten Sie Ihr Formular ein" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Überprüfen oder bearbeiten Sie Ihr Formular" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Formular bearbeiten" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Personalisieren Sie die Dankesnachricht" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Nachricht bearbeiten" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Wählen Sie aus, wer über neue Antworten benachrichtigt wird" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "E-Mail einrichten" + +#: admin/admin.php:570 +msgid "your form" +msgstr "Ihr Formular" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Richten Sie %s ein" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "%s anzeigen (öffnet in einem neuen Tab)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Passen Sie Ihr Formular an, um es für echte Einreichungen vorzubereiten:" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "Wir haben dieses Formular bereits für Sie erstellt. Passen Sie es an, damit es bereit ist, echte Einreichungen zu sammeln." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Richten Sie „%s“ ein" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Bearbeiten Sie die Dankesnachricht" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Legen Sie fest, wohin die Antworten gehen" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(öffnet in einem neuen Tab)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Formulare" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Formular" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Formulare" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Neu hinzufügen" diff --git a/languages/sureforms-es_ES.mo b/languages/sureforms-es_ES.mo index 0845ca2c91c7b413549ae42af31d30ede777eed2..1d586e695e5c44605e5221f8b758400faeb0b6df 100644 GIT binary patch delta 72240 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 delta 70903 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 bSEA!Z*<-&+bh{`!<8UHbc<t<*m!$t6_IYiB diff --git a/languages/sureforms-es_ES.po b/languages/sureforms-es_ES.po index 99a8d9ffd..06254cf4b 100644 --- a/languages/sureforms-es_ES.po +++ b/languages/sureforms-es_ES.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Una forma simple pero poderosa de crear formularios modernos para tu sit msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Tablero" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Tablero" msgid "Settings" msgstr "Configuraciones" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Nuevo formulario" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Entradas" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "Editar %1$s" @@ -126,18 +126,18 @@ msgid "Nonce verification failed." msgstr "La verificación del nonce falló." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Por favor, %1$sactiva%2$s tu copia de %3$s para obtener nuevas funciones, acceder al soporte, recibir notificaciones de actualizaciones y más." #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "SureForms %1$s requiere un mínimo de %2$s %3$s para funcionar correctamente. Por favor, actualice a la última versión desde %4$saquí%5$s." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -207,7 +207,7 @@ msgstr "Basura" msgid "Published" msgstr "Publicado" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Ver" @@ -299,11 +299,11 @@ msgstr "No se especificó ningún complemento" msgid "Plugin Successfully Activated" msgstr "Plugin activado con éxito" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Activando..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -318,17 +318,17 @@ msgstr "Activando..." msgid "Activated" msgstr "Activado" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Activar" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Instalando..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Instalado" @@ -336,11 +336,11 @@ msgstr "Instalado" msgid "You do not have permission to access this page." msgstr "No tienes permiso para acceder a esta página." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -540,7 +540,7 @@ msgid "Dropdown" msgstr "Desplegable" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Selecciona una opción" @@ -560,7 +560,7 @@ msgstr "Confirmar" msgid "Confirm %s" msgstr "Confirmar %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Doy mi consentimiento para que este sitio web almacene la información que he enviado para que puedan responder a mi consulta." @@ -617,7 +617,7 @@ msgstr "Los datos del formulario no se encuentran." msgid "Sorry, you are not allowed to view the form." msgstr "Lo siento, no tienes permiso para ver el formulario." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "Hubo un error al intentar enviar su formulario. Por favor, inténtelo de nuevo." @@ -625,7 +625,7 @@ msgstr "Hubo un error al intentar enviar su formulario. Por favor, inténtelo de msgid "Test Email Sent Successfully." msgstr "Correo de prueba enviado con éxito." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "No se encontraron formularios." @@ -709,9 +709,10 @@ msgstr "Mostrar" msgid "Hide" msgstr "Ocultar" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Editar formulario" @@ -722,7 +723,7 @@ msgstr "Editar formulario" msgid "Edit" msgstr "Editar" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -736,32 +737,32 @@ msgstr "Crear" msgid "Import Form" msgstr "Formulario de Importación" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Agregar nuevo formulario" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "No se encontraron registros" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "Aquí es donde aparecerán las entradas de su formulario" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Ver formulario" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Ver formularios" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -775,30 +776,30 @@ msgstr "Ver formularios" msgid "Forms" msgstr "Formularios" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Formularios de búsqueda" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Formularios de los padres:" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "No se encontraron formularios en la papelera." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Formulario publicado." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Formulario actualizado." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Correo Electrónico de Notificación del Administrador" @@ -806,7 +807,7 @@ msgstr "Correo Electrónico de Notificación del Administrador" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8331,7 +8332,7 @@ msgstr "Cambiar formulario" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Este formulario ha sido eliminado o no está disponible." @@ -8882,9 +8883,9 @@ msgstr "Agregar bloques a la barra de acción rápida" msgid "Re-arrange block inside Quick Action Bar" msgstr "Reorganizar bloque dentro de la Barra de Acción Rápida" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9256,7 +9257,7 @@ msgstr "Centro" msgid "Right" msgstr "Correcto" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9266,7 +9267,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "CloudFlare Turnstile" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9327,7 +9328,7 @@ msgstr "Anterior" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Gracias" @@ -9548,7 +9549,7 @@ msgstr "Clave del sitio" msgid "Secret Key" msgstr "Clave secreta" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Cloudflare Turnstile" @@ -10506,7 +10507,7 @@ msgstr "Agrega impresionantes iconos personalizables a tu sitio web." msgid "icon" msgstr "icono" -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Califica SureForms" @@ -10616,7 +10617,7 @@ msgstr "Desbloquear formularios conversacionales" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Con el Plan SureForms Pro, puedes transformar tus formularios en diseños conversacionales atractivos para una experiencia de usuario fluida." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Obtén SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Seleccionar degradado" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "La validación del captcha falló. No se proporcionó un código de error." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "La validación del captcha falló." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Captcha desconocido" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Tipo de captcha no válido." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "La verificación de %s falló. Por favor, contacte a su administrador del sitio." @@ -11242,8 +11243,8 @@ msgstr "Describe el formulario que deseas crear" msgid "We are building your form…" msgstr "Estamos construyendo tu formulario…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Habilitar notificación de administrador" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "Las notificaciones de administrador te mantienen informado sobre nuevas entradas de formularios desde tu última visita." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Usuario no autorizado." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sComienza %2$screando tu primer formulario%3$s.%4$s%5$sExperimenta el poder de nuestro intuitivo Creador de Formularios AI%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "¡SureForms te está esperando!" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Construir mi primer formulario" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Descartar" @@ -11417,51 +11418,51 @@ msgstr "Iniciar sesión" msgid "Register" msgstr "Registrar" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Entradas Recientes" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( Últimos 7 días )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Usa lógica condicional para mostrar solo lo que importa" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Divide tu formulario en pasos para mantenerlo sencillo" -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Permite que las personas suban archivos directamente a tu formulario" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Convierte las respuestas en PDFs descargables automáticamente" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Permitir que los usuarios firmen con un campo de firma simple" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Conecta tu formulario a otras herramientas usando webhooks" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Utiliza Formularios Conversacionales para una experiencia similar a un chat" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Permitir a los usuarios registrarse o iniciar sesión a través de su formulario" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Crear formularios que generen cuentas de usuario de WordPress" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Agrega cálculos para totalizar automáticamente las puntuaciones o precios" @@ -11883,7 +11884,7 @@ msgstr "Explora SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Algo salió mal. Hemos registrado el error para una investigación posterior." -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "El campo no es válido." @@ -11951,8 +11952,8 @@ msgstr "Miniatura de video de SureForms" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Formato esperado para correos electrónicos: email@sureforms.com o John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12330,7 +12331,7 @@ msgstr "Desconocido" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Usuario invitado" @@ -12356,7 +12357,7 @@ msgstr "Stripe no está conectado." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Clave secreta de Stripe no encontrada." @@ -12465,7 +12466,7 @@ msgstr "Suscripción no encontrada para el pago." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "ID de usuario: %d" @@ -12499,7 +12500,7 @@ msgstr "ID de suscripción: %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12544,7 +12545,7 @@ msgstr "ID de cliente: %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12554,7 +12555,7 @@ msgstr "Cantidad: %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Modo: %s" @@ -12563,24 +12564,24 @@ msgstr "Modo: %s" msgid "Failed to verify subscription." msgstr "Error al verificar la suscripción." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Error al recuperar la intención de pago." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "El pago no se confirmó con éxito." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Verificación de Pago" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12588,18 +12589,18 @@ msgstr "ID de transacción: %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Estado: %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Error al crear el cliente de Stripe." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Error al crear un cliente invitado de Stripe." @@ -13466,7 +13467,7 @@ msgstr "Edita este formulario" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Su formulario ha sido enviado con éxito. Revisaremos sus detalles y nos pondremos en contacto con usted pronto." @@ -15163,7 +15164,7 @@ msgstr "Se requiere el valor del campo de cantidad variable." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Importe del pago por debajo del mínimo. Mínimo: %1$s, recibido %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Copiar)" @@ -15362,12 +15363,12 @@ msgid "Stripe Settings" msgstr "Configuración de Stripe" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "SureForms %1$s requiere un mínimo de %2$s %3$s para funcionar correctamente. Por favor, actualice a la última versión." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Actualizar ahora" @@ -15415,8 +15416,8 @@ msgstr "Posición del signo de moneda" msgid "Select the position of the currency symbol relative to the amount." msgstr "Seleccione la posición del símbolo de moneda en relación con la cantidad." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15430,40 +15431,40 @@ msgstr "Seleccione la posición del símbolo de moneda en relación con la canti msgid "Learn" msgstr "Aprender" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "¡Increíble! SureForms está impulsando tus formularios y envíos - ¡sigamos creciendo juntos!" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Si SureForms ha sido útil, ¿te importaría tomarte un momento para dejar una reseña de 5 estrellas en WordPress.org?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Quizás más tarde" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "Ya lo hice" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms está listo para potenciar tus formularios — ¡explora lo que es posible!" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Administra tus formularios, realiza un seguimiento de las presentaciones y descubre funciones como el Creador de Formularios con IA, integraciones de pago y más desde el panel de SureForms." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Ir al panel de control" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Ya lo sé" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Parámetros no válidos." @@ -15841,8 +15842,8 @@ msgstr "Campo de texto" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Este formulario aún no está disponible. Vuelve a consultar después de la hora de inicio programada." @@ -16126,8 +16127,8 @@ msgstr "No se puede eliminar el webhook." msgid "Unable to connect to Stripe." msgstr "No se puede conectar a Stripe." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Este formulario está cerrado. El período de presentación ha terminado." @@ -16797,19 +16798,19 @@ msgstr "Secreto del webhook no configurado." msgid "Invalid webhook signature." msgstr "Firma de webhook no válida." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Cuestionarios" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Entradas del cuestionario" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Nuevo" @@ -17327,9 +17328,9 @@ msgstr "Perfecto para educación, formación y trivia divertida" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Selecciona esto para crear un cuestionario con preguntas puntuadas y resultados calificados." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Informes de encuestas" @@ -17735,7 +17736,7 @@ msgid "Error creating SureForms Form." msgstr "Error al crear el formulario de SureForms." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17893,9 +17894,9 @@ msgstr "La respuesta de la IA estaba vacía. Por favor, refine su solicitud y vu msgid "Unable to build form fields from the AI response." msgstr "No se pueden construir los campos del formulario a partir de la respuesta de la IA." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Entradas parciales" @@ -18766,23 +18767,23 @@ msgstr "No se pudo verificar el monto del pago para este formulario. Por favor, msgid "Cancellation is not supported for this payment gateway." msgstr "La cancelación no es compatible con esta pasarela de pago." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Borrador Rápido" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Describe el formulario y deja que SureForms AI lo genere por ti." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Describe tu formulario" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Ejemplo: Crear un formulario de contacto con campos de nombre, correo electrónico, teléfono y mensaje." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Redirigiendo..." @@ -18795,14 +18796,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "El mensaje es demasiado largo. Por favor, acórtalo e inténtalo de nuevo." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "La parte antes de @ no puede exceder %s caracteres." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18889,22 +18890,97 @@ msgstr "Lo siento, no tienes permiso para renderizar este formulario." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Este formulario requiere un pago. Por favor, complete el pago y envíe de nuevo." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "No tienes permiso para actualizar este mensaje." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Termina de configurar tu formulario" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Revisa o edita tu formulario" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Editar formulario" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Personaliza el mensaje de agradecimiento" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Editar mensaje" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Elige quién recibe notificaciones de nuevas respuestas" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "Configurar correo electrónico" + +#: admin/admin.php:570 +msgid "your form" +msgstr "tu formulario" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Termina de configurar %s" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "Ver %s (se abre en una nueva pestaña)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Personaliza tu formulario para que esté listo para envíos reales:" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "Ya hemos creado este formulario para ti. Termina de personalizarlo para que esté listo para recibir envíos reales." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Termina de configurar “%s”" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Edita el mensaje de agradecimiento" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Configura dónde van las respuestas" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(se abre en una nueva pestaña)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Formularios" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Formulario" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Formularios" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Agregar nuevo" diff --git a/languages/sureforms-fr_FR.mo b/languages/sureforms-fr_FR.mo index 1c176557886ce36e31f02e19923f61b274cb60de..a55ba8fee35001322c731b2f11768c327a56fbce 100644 GIT binary patch delta 72255 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 Htn~i{Qdbdy delta 70908 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 C<NdP$ diff --git a/languages/sureforms-fr_FR.po b/languages/sureforms-fr_FR.po index 8e35856e6..9ebc979cd 100644 --- a/languages/sureforms-fr_FR.po +++ b/languages/sureforms-fr_FR.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Un moyen simple mais puissant de créer des formulaires modernes pour vo msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Tableau de bord" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Tableau de bord" msgid "Settings" msgstr "Paramètres" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Nouveau formulaire" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Entrées" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "Modifier %1$s" @@ -126,12 +126,12 @@ msgid "Nonce verification failed." msgstr "La vérification du nonce a échoué." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Veuillez %1$sactiver%2$s votre copie de %3$s pour obtenir de nouvelles fonctionnalités, accéder au support, recevoir des notifications de mise à jour, et plus encore." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -201,7 +201,7 @@ msgstr "Poubelle" msgid "Published" msgstr "Publié" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Voir" @@ -288,11 +288,11 @@ msgstr "Aucun plugin spécifié" msgid "Plugin Successfully Activated" msgstr "Plugin activé avec succès" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Activation..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -307,17 +307,17 @@ msgstr "Activation..." msgid "Activated" msgstr "Activé" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Activer" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Installation en cours..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Installé" @@ -325,11 +325,11 @@ msgstr "Installé" msgid "You do not have permission to access this page." msgstr "Vous n'avez pas la permission d'accéder à cette page." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -529,7 +529,7 @@ msgid "Dropdown" msgstr "Menu déroulant" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Sélectionnez une option" @@ -549,7 +549,7 @@ msgstr "Confirmer" msgid "Confirm %s" msgstr "Confirmer %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Je consens à ce que ce site web stocke les informations que j'ai soumises afin qu'ils puissent répondre à ma demande." @@ -606,7 +606,7 @@ msgstr "Les données du formulaire sont introuvables." msgid "Sorry, you are not allowed to view the form." msgstr "Désolé, vous n'êtes pas autorisé à voir le formulaire." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "Une erreur s'est produite lors de la soumission de votre formulaire. Veuillez réessayer." @@ -614,7 +614,7 @@ msgstr "Une erreur s'est produite lors de la soumission de votre formulaire. Veu msgid "Test Email Sent Successfully." msgstr "E-mail de test envoyé avec succès." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "Aucun formulaire trouvé." @@ -698,9 +698,10 @@ msgstr "Afficher" msgid "Hide" msgstr "Cacher" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Modifier le formulaire" @@ -711,7 +712,7 @@ msgstr "Modifier le formulaire" msgid "Edit" msgstr "Modifier" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -725,32 +726,32 @@ msgstr "Créer" msgid "Import Form" msgstr "Formulaire d'importation" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Ajouter un nouveau formulaire" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "Aucun enregistrement trouvé" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "C'est ici que vos entrées de formulaire apparaîtront" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Voir le formulaire" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Afficher les formulaires" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -764,30 +765,30 @@ msgstr "Afficher les formulaires" msgid "Forms" msgstr "Formulaires" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Formulaires de recherche" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Formulaires parents :" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "Aucun formulaire trouvé dans la corbeille." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Formulaire publié." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Formulaire mis à jour." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Email de notification d'administration" @@ -795,7 +796,7 @@ msgstr "Email de notification d'administration" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8320,7 +8321,7 @@ msgstr "Changer de formulaire" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Ce formulaire a été supprimé ou est indisponible." @@ -8871,9 +8872,9 @@ msgstr "Ajouter des blocs à la barre d'action rapide" msgid "Re-arrange block inside Quick Action Bar" msgstr "Réorganiser le bloc dans la barre d'action rapide" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9245,7 +9246,7 @@ msgstr "Centre" msgid "Right" msgstr "D'accord" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9255,7 +9256,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "Tourniquet CloudFlare" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9316,7 +9317,7 @@ msgstr "Précédent" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Merci" @@ -9533,7 +9534,7 @@ msgstr "Clé du site" msgid "Secret Key" msgstr "Clé secrète" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Tourniquet Cloudflare" @@ -10484,7 +10485,7 @@ msgid "icon" msgstr "icône" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "SureForms %1$s nécessite au minimum %2$s %3$s pour fonctionner correctement. Veuillez mettre à jour vers la dernière version depuis %4$scet endroit%5$s." @@ -10506,7 +10507,7 @@ msgstr "Journalisation IP" msgid "Honeypot" msgstr "Pot de miel" -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Évaluez SureForms" @@ -10616,7 +10617,7 @@ msgstr "Déverrouiller les formulaires conversationnels" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Avec le plan SureForms Pro, vous pouvez transformer vos formulaires en mises en page conversationnelles engageantes pour une expérience utilisateur fluide." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Obtenez SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Sélectionner le dégradé" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "La validation du captcha a échoué. Aucun code d'erreur fourni." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "La validation du captcha a échoué." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Captcha inconnu" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Type de captcha invalide." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "La vérification de %s a échoué. Veuillez contacter votre administrateur de site." @@ -11242,8 +11243,8 @@ msgstr "Décrivez le formulaire que vous souhaitez créer" msgid "We are building your form…" msgstr "Nous construisons votre formulaire…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Activer la notification administrateur" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "Les notifications administratives vous informent des nouvelles entrées de formulaire depuis votre dernière visite." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Utilisateur non autorisé." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sCommencez par %2$scréer votre premier formulaire%3$s.%4$s%5$sDécouvrez la puissance de notre créateur de formulaires intuitif alimenté par l'IA%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "SureForms vous attend !" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Construire mon premier formulaire" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Rejeter" @@ -11417,51 +11418,51 @@ msgstr "Connexion" msgid "Register" msgstr "Inscrire" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Entrées récentes" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( 7 derniers jours )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Utilisez la logique conditionnelle pour montrer uniquement ce qui compte" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Divisez votre formulaire en étapes pour le rendre facile." -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Permettez aux gens de télécharger des fichiers directement sur votre formulaire" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Transformez les réponses en PDF téléchargeables automatiquement" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Permettez aux utilisateurs de signer avec un simple champ de signature" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Connectez votre formulaire à d'autres outils en utilisant des webhooks" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Utilisez des formulaires conversationnels pour une expérience de type chat" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Permettez aux utilisateurs de s'inscrire ou de se connecter via votre formulaire" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Créez des formulaires qui génèrent des comptes utilisateurs WordPress" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Ajoutez des calculs pour totaliser automatiquement les scores ou les prix" @@ -11883,7 +11884,7 @@ msgstr "Explorez SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Un problème est survenu. Nous avons enregistré l'erreur pour une enquête plus approfondie." -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "Le champ n'est pas valide." @@ -11951,8 +11952,8 @@ msgstr "Miniature vidéo SureForms" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Format attendu pour les e-mails - email@sureforms.com ou John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12333,7 +12334,7 @@ msgstr "Inconnu" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Utilisateur Invité" @@ -12359,7 +12360,7 @@ msgstr "Stripe n'est pas connecté." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Clé secrète Stripe introuvable." @@ -12468,7 +12469,7 @@ msgstr "Abonnement non trouvé pour le paiement." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "ID utilisateur : %d" @@ -12502,7 +12503,7 @@ msgstr "ID d'abonnement : %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12547,7 +12548,7 @@ msgstr "ID client : %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12557,7 +12558,7 @@ msgstr "Montant : %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Mode : %s" @@ -12566,24 +12567,24 @@ msgstr "Mode : %s" msgid "Failed to verify subscription." msgstr "Échec de la vérification de l'abonnement." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Échec de la récupération de l'intention de paiement." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "Le paiement n'a pas été confirmé avec succès." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Vérification de paiement" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12591,18 +12592,18 @@ msgstr "ID de transaction : %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Statut : %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Échec de la création du client Stripe." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Échec de la création du client invité Stripe." @@ -13469,7 +13470,7 @@ msgstr "Modifier ce formulaire" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Votre formulaire a été soumis avec succès. Nous examinerons vos informations et vous répondrons bientôt." @@ -15166,7 +15167,7 @@ msgstr "La valeur du champ de montant variable est requise." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Montant du paiement inférieur au minimum. Minimum : %1$s, reçu %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Copie)" @@ -15365,12 +15366,12 @@ msgid "Stripe Settings" msgstr "Paramètres Stripe" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "SureForms %1$s nécessite au minimum %2$s %3$s pour fonctionner correctement. Veuillez mettre à jour vers la dernière version." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Mettez à jour maintenant" @@ -15418,8 +15419,8 @@ msgstr "Position du signe monétaire" msgid "Select the position of the currency symbol relative to the amount." msgstr "Sélectionnez la position du symbole monétaire par rapport au montant." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15433,40 +15434,40 @@ msgstr "Sélectionnez la position du symbole monétaire par rapport au montant." msgid "Learn" msgstr "Apprendre" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "Incroyable ! SureForms alimente vos formulaires et soumissions - continuons à grandir ensemble !" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Si SureForms vous a été utile, pourriez-vous prendre un moment pour laisser un avis 5 étoiles sur WordPress.org ?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Peut-être plus tard" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "Je l'ai déjà fait" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms est prêt à dynamiser vos formulaires — explorez ce qui est possible !" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Gérez vos formulaires, suivez les soumissions et découvrez des fonctionnalités telles que le constructeur de formulaires IA, les intégrations de paiement et bien plus encore depuis le tableau de bord SureForms." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Aller au tableau de bord" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Je sais déjà" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Paramètres invalides." @@ -15844,8 +15845,8 @@ msgstr "Champ de texte" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Ce formulaire n'est pas encore disponible. Revenez après l'heure de début prévue." @@ -16129,8 +16130,8 @@ msgstr "Impossible de supprimer le webhook." msgid "Unable to connect to Stripe." msgstr "Impossible de se connecter à Stripe." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Ce formulaire est fermé. La période de soumission est terminée." @@ -16800,19 +16801,19 @@ msgstr "Secret du webhook non configuré." msgid "Invalid webhook signature." msgstr "Signature de webhook invalide." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Quiz" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Participations au quiz" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Nouveau" @@ -17330,9 +17331,9 @@ msgstr "Parfait pour l'éducation, la formation et les quiz amusants" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Sélectionnez ceci pour créer un quiz avec des questions notées et des résultats évalués." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Rapports d'enquête" @@ -17738,7 +17739,7 @@ msgid "Error creating SureForms Form." msgstr "Erreur lors de la création du formulaire SureForms." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17896,9 +17897,9 @@ msgstr "La réponse de l'IA était vide. Veuillez affiner votre invite et réess msgid "Unable to build form fields from the AI response." msgstr "Impossible de créer les champs de formulaire à partir de la réponse de l'IA." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Entrées partielles" @@ -18769,23 +18770,23 @@ msgstr "Le montant du paiement n'a pas pu être vérifié pour ce formulaire. Ve msgid "Cancellation is not supported for this payment gateway." msgstr "L'annulation n'est pas prise en charge pour cette passerelle de paiement." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Brouillon Rapide" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Décrivez le formulaire et laissez SureForms AI le générer pour vous." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Décrivez votre formulaire" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Exemple : Créez un formulaire de contact avec des champs pour le nom, l'email, le téléphone et le message." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Redirection..." @@ -18798,14 +18799,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "L'invite est trop longue. Veuillez la raccourcir et réessayer." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "La partie avant @ ne peut pas dépasser %s caractères." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18892,22 +18893,97 @@ msgstr "Désolé, vous n'êtes pas autorisé à afficher ce formulaire." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Ce formulaire nécessite un paiement. Veuillez effectuer le paiement et soumettre à nouveau." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "Vous n'êtes pas autorisé à mettre à jour cette invite." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Terminez la configuration de votre formulaire" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Révisez ou modifiez votre formulaire" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Modifier le formulaire" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Personnalisez le message de remerciement" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Modifier le message" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Choisissez qui sera notifié des nouvelles réponses" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "Configurer l'email" + +#: admin/admin.php:570 +msgid "your form" +msgstr "votre formulaire" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Terminez la configuration de %s" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "Voir %s (s'ouvre dans un nouvel onglet)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Personnalisez votre formulaire pour le préparer à recevoir de vraies soumissions :" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "Nous avons déjà créé ce formulaire pour vous. Terminez de le personnaliser pour qu'il soit prêt à collecter de vraies soumissions." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Terminez la configuration de « %s »" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Modifier le message de remerciement" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Définir où vont les réponses" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(s'ouvre dans un nouvel onglet)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Formulaires" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Formulaire" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Formulaires" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Ajouter nouveau" diff --git a/languages/sureforms-it_IT.mo b/languages/sureforms-it_IT.mo index f9106b11842c70c9a043e08522f9e6c9f7b2f0c4..7dc352b07516a3afca6939339fc5ce745ff2b54f 100644 GIT binary patch delta 72242 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 delta 70901 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 Y@$g02`L}0ODl(l4i%jo*B;)M=0des%Z~y=R diff --git a/languages/sureforms-it_IT.po b/languages/sureforms-it_IT.po index d75b0b0f6..514a4fe59 100644 --- a/languages/sureforms-it_IT.po +++ b/languages/sureforms-it_IT.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Un modo semplice ma potente per creare moduli moderni per il tuo sito we msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Cruscotto" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Cruscotto" msgid "Settings" msgstr "Impostazioni" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Nuovo modulo" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Voci" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "Modifica %1$s" @@ -126,18 +126,18 @@ msgid "Nonce verification failed." msgstr "Verifica del nonce fallita." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Per favore %1$sattiva%2$s la tua copia di %3$s per ottenere nuove funzionalità, accedere al supporto, ricevere notifiche di aggiornamento e altro ancora." #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "SureForms %1$s richiede almeno %2$s %3$s per funzionare correttamente. Si prega di aggiornare all'ultima versione da %4$squi%5$s." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -207,7 +207,7 @@ msgstr "Spazzatura" msgid "Published" msgstr "Pubblicato" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Visualizza" @@ -299,11 +299,11 @@ msgstr "Nessun plugin specificato" msgid "Plugin Successfully Activated" msgstr "Plugin attivato con successo" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Attivazione in corso..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -318,17 +318,17 @@ msgstr "Attivazione in corso..." msgid "Activated" msgstr "Attivato" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Attiva" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Installazione in corso..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Installato" @@ -336,11 +336,11 @@ msgstr "Installato" msgid "You do not have permission to access this page." msgstr "Non hai il permesso di accedere a questa pagina." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -540,7 +540,7 @@ msgid "Dropdown" msgstr "Menu a tendina" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Seleziona un'opzione" @@ -560,7 +560,7 @@ msgstr "Conferma" msgid "Confirm %s" msgstr "Conferma %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Acconsento a che questo sito web memorizzi le informazioni che ho inviato in modo che possano rispondere alla mia richiesta." @@ -617,7 +617,7 @@ msgstr "I dati del modulo non sono stati trovati." msgid "Sorry, you are not allowed to view the form." msgstr "Spiacente, non sei autorizzato a visualizzare il modulo." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "C'è stato un errore nel tentativo di inviare il modulo. Per favore riprova." @@ -625,7 +625,7 @@ msgstr "C'è stato un errore nel tentativo di inviare il modulo. Per favore ripr msgid "Test Email Sent Successfully." msgstr "Email di prova inviato con successo." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "Nessun modulo trovato." @@ -666,7 +666,7 @@ msgstr "Il valore deve essere unico." msgid "Sorry, you are not allowed to perform this action." msgstr "Spiacente, non ti è permesso eseguire questa azione." -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Valuta SureForms" @@ -713,9 +713,10 @@ msgstr "Mostra" msgid "Hide" msgstr "Nascondi" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Modifica modulo" @@ -726,7 +727,7 @@ msgstr "Modifica modulo" msgid "Edit" msgstr "Modifica" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -740,32 +741,32 @@ msgstr "Crea" msgid "Import Form" msgstr "Modulo di importazione" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Aggiungi nuovo modulo" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "Nessun record trovato" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "Qui è dove appariranno le voci del tuo modulo" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Visualizza modulo" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Visualizza moduli" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -779,30 +780,30 @@ msgstr "Visualizza moduli" msgid "Forms" msgstr "Moduli" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Moduli di ricerca" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Moduli genitori:" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "Nessun modulo trovato nel Cestino." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Modulo pubblicato." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Modulo aggiornato." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Email di notifica amministrativa" @@ -810,7 +811,7 @@ msgstr "Email di notifica amministrativa" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8335,7 +8336,7 @@ msgstr "Modifica modulo" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Questo modulo è stato eliminato o non è disponibile." @@ -8886,9 +8887,9 @@ msgstr "Aggiungi blocchi alla barra delle azioni rapide" msgid "Re-arrange block inside Quick Action Bar" msgstr "Riorganizza il blocco all'interno della Barra delle Azioni Rapide" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9260,7 +9261,7 @@ msgstr "Centro" msgid "Right" msgstr "Destra" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9270,7 +9271,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "CloudFlare Turnstile" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9331,7 +9332,7 @@ msgstr "Precedente" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Grazie" @@ -9566,7 +9567,7 @@ msgstr "Chiave del sito" msgid "Secret Key" msgstr "Chiave segreta" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Cloudflare Turnstile" @@ -10616,7 +10617,7 @@ msgstr "Sblocca moduli conversazionali" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Con il piano SureForms Pro, puoi trasformare i tuoi moduli in layout conversazionali coinvolgenti per un'esperienza utente senza interruzioni." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Ottieni SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Seleziona sfumatura" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "La validazione del captcha non è riuscita. Nessun codice di errore fornito." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "La validazione del captcha è fallita." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Captcha sconosciuto" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Tipo di captcha non valido." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "La verifica di %s non è riuscita. Si prega di contattare l'amministratore del sito." @@ -11242,8 +11243,8 @@ msgstr "Descrivi il modulo che desideri creare" msgid "We are building your form…" msgstr "Stiamo creando il tuo modulo…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Abilita la Notifica Amministratore" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "Le notifiche dell'amministratore ti tengono informato sui nuovi invii di moduli dalla tua ultima visita." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Utente non autorizzato." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sInizia %2$scostruendo il tuo primo modulo%3$s.%4$s%5$sScopri la potenza del nostro intuitivo Costruttore di Moduli AI%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "SureForms ti sta aspettando!" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Crea il mio primo modulo" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Chiudi" @@ -11417,51 +11418,51 @@ msgstr "Accesso" msgid "Register" msgstr "Registrati" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Voci recenti" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( Ultimi 7 giorni )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Usa la logica condizionale per mostrare solo ciò che conta" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Dividi il tuo modulo in passaggi per mantenerlo semplice" -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Consenti alle persone di caricare file direttamente nel tuo modulo" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Trasforma automaticamente le risposte in PDF scaricabili" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Consenti agli utenti di firmare con un semplice campo firma" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Collega il tuo modulo ad altri strumenti utilizzando i webhook" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Usa moduli conversazionali per un'esperienza simile a una chat" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Consenti agli utenti di registrarsi o accedere tramite il tuo modulo" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Crea moduli che creano account utente WordPress" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Aggiungi calcoli per totalizzare automaticamente i punteggi o i prezzi" @@ -11883,7 +11884,7 @@ msgstr "Esplora SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Qualcosa è andato storto. Abbiamo registrato l'errore per ulteriori indagini." -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "Il campo non è valido." @@ -11951,8 +11952,8 @@ msgstr "Miniatura video di SureForms" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Formato previsto per le email - email@sureforms.com o John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12330,7 +12331,7 @@ msgstr "Sconosciuto" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Utente Ospite" @@ -12356,7 +12357,7 @@ msgstr "Stripe non è connesso." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Chiave segreta di Stripe non trovata." @@ -12465,7 +12466,7 @@ msgstr "Abbonamento non trovato per il pagamento." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "ID utente: %d" @@ -12499,7 +12500,7 @@ msgstr "ID di abbonamento: %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12544,7 +12545,7 @@ msgstr "ID cliente: %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12554,7 +12555,7 @@ msgstr "Importo: %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Modalità: %s" @@ -12563,24 +12564,24 @@ msgstr "Modalità: %s" msgid "Failed to verify subscription." msgstr "Verifica dell'abbonamento non riuscita." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Impossibile recuperare l'intento di pagamento." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "Il pagamento non è stato confermato con successo." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Verifica del pagamento" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12588,18 +12589,18 @@ msgstr "ID transazione: %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Stato: %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Creazione del cliente Stripe non riuscita." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Impossibile creare un cliente ospite di Stripe." @@ -13466,7 +13467,7 @@ msgstr "Modifica questo modulo" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Il tuo modulo è stato inviato con successo. Esamineremo i tuoi dettagli e ti ricontatteremo presto." @@ -15163,7 +15164,7 @@ msgstr "È richiesto il valore del campo importo variabile." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Importo del pagamento inferiore al minimo. Minimo: %1$s, ricevuto %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Copia)" @@ -15362,12 +15363,12 @@ msgid "Stripe Settings" msgstr "Impostazioni di Stripe" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "SureForms %1$s richiede almeno %2$s %3$s per funzionare correttamente. Si prega di aggiornare all'ultima versione." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Aggiorna ora" @@ -15415,8 +15416,8 @@ msgstr "Posizione del simbolo di valuta" msgid "Select the position of the currency symbol relative to the amount." msgstr "Seleziona la posizione del simbolo della valuta rispetto all'importo." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15430,40 +15431,40 @@ msgstr "Seleziona la posizione del simbolo della valuta rispetto all'importo." msgid "Learn" msgstr "Impara" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "Incredibile! SureForms sta alimentando i tuoi moduli e le tue sottomissioni - continuiamo a crescere insieme!" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Se SureForms ti è stato utile, ti dispiacerebbe prendere un momento per lasciare una recensione a 5 stelle su WordPress.org?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Forse più tardi" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "L'ho già fatto" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms è pronto a potenziare i tuoi moduli — scopri cosa è possibile!" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Gestisci i tuoi moduli, traccia le sottomissioni e scopri funzionalità come AI Form Builder, integrazioni di pagamento e altro ancora dalla dashboard di SureForms." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Vai al cruscotto" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Lo so già" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Parametri non validi." @@ -15841,8 +15842,8 @@ msgstr "Campo di testo" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Questo modulo non è ancora disponibile. Ricontrolla dopo l'orario di inizio programmato." @@ -16126,8 +16127,8 @@ msgstr "Impossibile eliminare il webhook." msgid "Unable to connect to Stripe." msgstr "Impossibile connettersi a Stripe." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Questo modulo è chiuso. Il periodo di invio è terminato." @@ -16797,19 +16798,19 @@ msgstr "Segreto del webhook non configurato." msgid "Invalid webhook signature." msgstr "Firma del webhook non valida." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Quiz" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Voci del quiz" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Nuovo" @@ -17327,9 +17328,9 @@ msgstr "Perfetto per l'istruzione, la formazione e i quiz divertenti" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Seleziona questo per creare un quiz con domande a punteggio e risultati valutati." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Rapporti di indagine" @@ -17735,7 +17736,7 @@ msgid "Error creating SureForms Form." msgstr "Errore nella creazione del modulo SureForms." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17893,9 +17894,9 @@ msgstr "La risposta dell'IA era vuota. Per favore, perfeziona il tuo prompt e ri msgid "Unable to build form fields from the AI response." msgstr "Impossibile creare i campi del modulo dalla risposta dell'AI." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Voci parziali" @@ -18766,23 +18767,23 @@ msgstr "L'importo del pagamento non può essere verificato per questo modulo. Mo msgid "Cancellation is not supported for this payment gateway." msgstr "La cancellazione non è supportata per questo gateway di pagamento." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Bozza Rapida" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Descrivi il modulo e lascia che SureForms AI lo generi per te." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Descrivi il tuo modulo" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Esempio: Crea un modulo di contatto con campi per nome, email, telefono e messaggio." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Reindirizzamento in corso..." @@ -18795,14 +18796,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "Il prompt è troppo lungo. Per favore accorcialo e riprova." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "La parte prima di @ non può superare %s caratteri." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18889,22 +18890,97 @@ msgstr "Spiacente, non sei autorizzato a visualizzare questo modulo." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Questo modulo richiede un pagamento. Si prega di completare il pagamento e inviare di nuovo." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "Non sei autorizzato ad aggiornare questo prompt." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Completa la configurazione del tuo modulo" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Rivedi o modifica il tuo modulo" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Modifica modulo" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Personalizza il messaggio di ringraziamento" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Modifica messaggio" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Scegli chi riceve notifiche di nuove risposte" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "Configura email" + +#: admin/admin.php:570 +msgid "your form" +msgstr "il tuo modulo" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Completa la configurazione di %s" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "Visualizza %s (si apre in una nuova scheda)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Personalizza il tuo modulo per prepararlo a ricevere invii reali:" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "Abbiamo già creato questo modulo per te. Completa la personalizzazione in modo che sia pronto a raccogliere invii reali." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Completa la configurazione di “%s”" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Modifica il messaggio di ringraziamento" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Imposta dove vanno le risposte" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(si apre in una nuova scheda)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Moduli" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Modulo" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Moduli" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Aggiungi nuovo" diff --git a/languages/sureforms-nl_NL.mo b/languages/sureforms-nl_NL.mo index 8abb6867fa9ef47cd7a375d712aae7d03fcf5796..d0af99322f4afe39fe85d0f13155f51417a5684b 100644 GIT binary patch delta 72269 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 X}9V8hs26_;K`DZ$_Vg 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 TTzKZm|7{|QO23*}uGs$qn{JA- delta 70903 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 F{{c}3%r*c3 diff --git a/languages/sureforms-nl_NL.po b/languages/sureforms-nl_NL.po index 12734e51e..504d5ed40 100644 --- a/languages/sureforms-nl_NL.po +++ b/languages/sureforms-nl_NL.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Een eenvoudige maar krachtige manier om moderne formulieren voor uw webs msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Dashboard" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Dashboard" msgid "Settings" msgstr "Instellingen" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Nieuw formulier" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Inzendingen" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "Bewerk %1$s" @@ -126,12 +126,12 @@ msgid "Nonce verification failed." msgstr "Verificatie van nonce mislukt." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Gelieve %1$suw exemplaar van %3$s te activeren%2$s om nieuwe functies te krijgen, toegang tot ondersteuning, update-meldingen te ontvangen en meer." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -201,7 +201,7 @@ msgstr "Afval" msgid "Published" msgstr "Gepubliceerd" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Bekijken" @@ -288,11 +288,11 @@ msgstr "Geen plugin opgegeven" msgid "Plugin Successfully Activated" msgstr "Plugin succesvol geactiveerd" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Activeren..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -307,17 +307,17 @@ msgstr "Activeren..." msgid "Activated" msgstr "Geactiveerd" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Activeren" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Installeren..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Geïnstalleerd" @@ -325,11 +325,11 @@ msgstr "Geïnstalleerd" msgid "You do not have permission to access this page." msgstr "U heeft geen toestemming om deze pagina te openen." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -529,7 +529,7 @@ msgid "Dropdown" msgstr "Keuzemenu" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Selecteer een optie" @@ -549,7 +549,7 @@ msgstr "Bevestigen" msgid "Confirm %s" msgstr "Bevestig %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Ik geef toestemming aan deze website om mijn ingediende informatie op te slaan zodat ze op mijn vraag kunnen reageren." @@ -606,7 +606,7 @@ msgstr "Formuliergegevens zijn niet gevonden." msgid "Sorry, you are not allowed to view the form." msgstr "Sorry, je mag het formulier niet bekijken." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "Er is een fout opgetreden bij het indienen van uw formulier. Probeer het alstublieft opnieuw." @@ -614,7 +614,7 @@ msgstr "Er is een fout opgetreden bij het indienen van uw formulier. Probeer het msgid "Test Email Sent Successfully." msgstr "Test-e-mail succesvol verzonden." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "Geen formulieren gevonden." @@ -698,9 +698,10 @@ msgstr "Tonen" msgid "Hide" msgstr "Verbergen" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Formulier bewerken" @@ -711,7 +712,7 @@ msgstr "Formulier bewerken" msgid "Edit" msgstr "Bewerken" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -725,32 +726,32 @@ msgstr "Maken" msgid "Import Form" msgstr "Importformulier" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Nieuw formulier toevoegen" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "Geen records gevonden" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "Hier verschijnen uw formulierinvoeren" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Formulier bekijken" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Formulieren bekijken" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -764,30 +765,30 @@ msgstr "Formulieren bekijken" msgid "Forms" msgstr "Formulieren" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Zoekformulieren" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Ouderformulieren:" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "Geen formulieren gevonden in de prullenbak." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Formulier gepubliceerd." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Formulier bijgewerkt." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Beheerdersmelding E-mail" @@ -795,7 +796,7 @@ msgstr "Beheerdersmelding E-mail" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8320,7 +8321,7 @@ msgstr "Formulier wijzigen" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Dit formulier is verwijderd of is niet beschikbaar." @@ -8871,9 +8872,9 @@ msgstr "Blokken toevoegen aan de Snelle Actiebalk" msgid "Re-arrange block inside Quick Action Bar" msgstr "Blok herschikken in de Snelle Actiebalk" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9245,7 +9246,7 @@ msgstr "Centrum" msgid "Right" msgstr "Rechts" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9255,7 +9256,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "CloudFlare Turnstile" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9316,7 +9317,7 @@ msgstr "Vorige" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Dank je" @@ -9533,7 +9534,7 @@ msgstr "Sitecode" msgid "Secret Key" msgstr "Geheime Sleutel" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Cloudflare Turnstile" @@ -10484,7 +10485,7 @@ msgid "icon" msgstr "icoon" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "SureForms %1$s vereist minimaal %2$s %3$s om goed te functioneren. Werk alstublieft bij naar de nieuwste versie van %4$shier%5$s." @@ -10506,7 +10507,7 @@ msgstr "IP-logboek" msgid "Honeypot" msgstr "Honeypot" -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Beoordeel SureForms" @@ -10616,7 +10617,7 @@ msgstr "Ontgrendel Gespreksformulieren" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Met het SureForms Pro Plan kun je je formulieren omzetten in boeiende, conversatiegerichte lay-outs voor een naadloze gebruikerservaring." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Verkrijg SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Selecteer verloop" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "Captcha-validatie mislukt. Geen foutcode opgegeven." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "Captcha-validatie mislukt." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Onbekende Captcha" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Ongeldig captcha-type." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "%s verificatie mislukt. Neem contact op met uw sitebeheerder." @@ -11242,8 +11243,8 @@ msgstr "Beschrijf het formulier dat je wilt maken" msgid "We are building your form…" msgstr "We zijn uw formulier aan het maken…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Beheerdermelding inschakelen" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "Beheerdersmeldingen houden je op de hoogte van nieuwe formulierinzendingen sinds je laatste bezoek." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Ongeautoriseerde gebruiker." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sBegin met %2$shet bouwen van je eerste formulier%3$s.%4$s%5$sErvaar de kracht van onze intuïtieve AI Form Builder%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "SureForms wacht op je!" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Bouw Mijn Eerste Formulier" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Afwijzen" @@ -11417,51 +11418,51 @@ msgstr "Inloggen" msgid "Register" msgstr "Registreren" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Recente items" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( Laatste 7 dagen )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Gebruik voorwaardelijke logica om alleen te tonen wat ertoe doet" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Verdeel uw formulier in stappen om het eenvoudig te houden" -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Laat mensen bestanden direct naar uw formulier uploaden" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Zet reacties automatisch om in downloadbare PDF's" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Laat gebruikers ondertekenen met een eenvoudig handtekeningveld" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Verbind uw formulier met andere tools via webhooks" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Gebruik Conversational Forms voor een chat-achtige ervaring" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Laat gebruikers zich registreren of inloggen via uw formulier" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Bouw formulieren die WordPress-gebruikersaccounts aanmaken" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Berekeningen toevoegen om scores of prijzen automatisch op te tellen" @@ -11883,7 +11884,7 @@ msgstr "Verken SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Er is iets misgegaan. We hebben de fout geregistreerd voor verder onderzoek." -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "Veld is niet geldig." @@ -11951,8 +11952,8 @@ msgstr "SureForms Video Miniatuur" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Verwacht formaat voor e-mails - email@sureforms.com of John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12330,7 +12331,7 @@ msgstr "Onbekend" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Gastgebruiker" @@ -12356,7 +12357,7 @@ msgstr "Stripe is niet verbonden." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Stripe geheime sleutel niet gevonden." @@ -12465,7 +12466,7 @@ msgstr "Abonnement niet gevonden voor de betaling." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "Gebruikers-ID: %d" @@ -12499,7 +12500,7 @@ msgstr "Abonnement-ID: %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12544,7 +12545,7 @@ msgstr "Klant-ID: %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12554,7 +12555,7 @@ msgstr "Bedrag: %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Modus: %s" @@ -12563,24 +12564,24 @@ msgstr "Modus: %s" msgid "Failed to verify subscription." msgstr "Verificatie van abonnement mislukt." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Het is niet gelukt om de betalingsintentie op te halen." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "Betaling werd niet succesvol bevestigd." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Betalingsverificatie" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12588,18 +12589,18 @@ msgstr "Transactie-ID: %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Status: %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Het is niet gelukt om een Stripe-klant aan te maken." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Het is niet gelukt om een Stripe-gastklant aan te maken." @@ -13466,7 +13467,7 @@ msgstr "Bewerk dit formulier" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Uw formulier is succesvol ingediend. We zullen uw gegevens bekijken en nemen binnenkort contact met u op." @@ -15163,7 +15164,7 @@ msgstr "Waarde van het variabele bedrag veld is vereist." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Betalingsbedrag onder het minimum. Minimum: %1$s, ontvangen %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Kopie)" @@ -15362,12 +15363,12 @@ msgid "Stripe Settings" msgstr "Stripe-instellingen" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "SureForms %1$s vereist minimaal %2$s %3$s om goed te functioneren. Werk alstublieft bij naar de nieuwste versie." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Nu bijwerken" @@ -15415,8 +15416,8 @@ msgstr "Positie van het valutateken" msgid "Select the position of the currency symbol relative to the amount." msgstr "Selecteer de positie van het valutasymbool ten opzichte van het bedrag." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15430,40 +15431,40 @@ msgstr "Selecteer de positie van het valutasymbool ten opzichte van het bedrag." msgid "Learn" msgstr "Leren" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "Geweldig! SureForms ondersteunt je formulieren en inzendingen - laten we samen blijven groeien!" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Als SureForms nuttig is geweest, zou u dan een moment willen nemen om een 5-sterrenbeoordeling achter te laten op WordPress.org?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Misschien later" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "Ik heb het al gedaan" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms is klaar om uw formulieren van stroom te voorzien — ontdek wat er mogelijk is!" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Beheer uw formulieren, volg inzendingen en ontdek functies zoals AI Form Builder, betalingsintegraties en meer vanaf het SureForms-dashboard." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Ga naar Dashboard" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Ik weet het al" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Ongeldige parameters." @@ -15841,8 +15842,8 @@ msgstr "Tekstveld" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Dit formulier is nog niet beschikbaar. Kom terug na de geplande starttijd." @@ -16126,8 +16127,8 @@ msgstr "Kan webhook niet verwijderen." msgid "Unable to connect to Stripe." msgstr "Kan geen verbinding maken met Stripe." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Dit formulier is gesloten. De indieningsperiode is afgelopen." @@ -16797,19 +16798,19 @@ msgstr "Webhook-geheim niet geconfigureerd." msgid "Invalid webhook signature." msgstr "Ongeldige webhook-handtekening." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Quizzen" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Quizinzendingen" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Nieuw" @@ -17327,9 +17328,9 @@ msgstr "Perfect voor educatie, training en leuke trivia" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Selecteer dit om een quiz te maken met gescoorde vragen en beoordeelde resultaten." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Onderzoeksrapporten" @@ -17735,7 +17736,7 @@ msgid "Error creating SureForms Form." msgstr "Fout bij het maken van SureForms-formulier." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17893,9 +17894,9 @@ msgstr "De AI-reactie was leeg. Gelieve uw prompt te verfijnen en het opnieuw te msgid "Unable to build form fields from the AI response." msgstr "Kan formuliervelden niet opbouwen vanuit de AI-reactie." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Gedeeltelijke invoer" @@ -18766,23 +18767,23 @@ msgstr "Het betalingsbedrag kon niet worden geverifieerd voor dit formulier. Bew msgid "Cancellation is not supported for this payment gateway." msgstr "Annulering wordt niet ondersteund voor deze betalingsgateway." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Snelle Schets" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Beschrijf het formulier en laat SureForms AI het voor je genereren." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Beschrijf je formulier" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Voorbeeld: Maak een contactformulier met velden voor naam, e-mail, telefoon en bericht." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Omleiden..." @@ -18795,14 +18796,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "De prompt is te lang. Verkort deze en probeer het opnieuw." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "Het gedeelte voor @ mag niet meer dan %s tekens bevatten." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18889,22 +18890,97 @@ msgstr "Sorry, je mag dit formulier niet weergeven." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Dit formulier vereist een betaling. Voltooi de betaling en dien opnieuw in." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "Je mag deze prompt niet bijwerken." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Voltooi het instellen van je formulier" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Bekijk of bewerk je formulier" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Formulier bewerken" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Personaliseer het bedankbericht" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Bericht bewerken" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Kies wie op de hoogte wordt gesteld van nieuwe reacties" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "E-mail instellen" + +#: admin/admin.php:570 +msgid "your form" +msgstr "je formulier" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Voltooi het instellen van %s" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "Bekijk %s (opent in een nieuw tabblad)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Pas je formulier aan om het klaar te maken voor echte inzendingen:" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "We hebben dit formulier al voor je gemaakt. Voltooi de aanpassing zodat het klaar is om echte inzendingen te verzamelen." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Voltooi het instellen van “%s”" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Bewerk het bedankbericht" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Stel in waar reacties naartoe gaan" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(opent in een nieuw tabblad)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Formulieren" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Formulier" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Formulieren" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Nieuw toevoegen" diff --git a/languages/sureforms-pl_PL.mo b/languages/sureforms-pl_PL.mo index 4fc4af1d86d9f4c7558bf851ea0f36e6530d271e..cbd924d9e5101a416ca19ba614f436184b4dbedb 100644 GIT binary patch delta 72300 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 delta 70881 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 F{2xECL0A9) diff --git a/languages/sureforms-pl_PL.po b/languages/sureforms-pl_PL.po index b478b9c9e..fc3afc43d 100644 --- a/languages/sureforms-pl_PL.po +++ b/languages/sureforms-pl_PL.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Prosty, ale potężny sposób na tworzenie nowoczesnych formularzy na Tw msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Panel sterowania" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Panel sterowania" msgid "Settings" msgstr "Ustawienia" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Nowy formularz" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Wpisy" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "Edytuj %1$s" @@ -126,18 +126,18 @@ msgid "Nonce verification failed." msgstr "Weryfikacja nonce nie powiodła się." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Proszę %1$saktywować%2$s swoją kopię %3$s, aby uzyskać nowe funkcje, dostęp do wsparcia, otrzymywać powiadomienia o aktualizacjach i więcej." #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "SureForms %1$s wymaga co najmniej %2$s %3$s, aby działać poprawnie. Proszę zaktualizować do najnowszej wersji z %4$stąd%5$s." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -207,7 +207,7 @@ msgstr "Śmieci" msgid "Published" msgstr "Opublikowano" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Widok" @@ -299,11 +299,11 @@ msgstr "Nie określono wtyczki" msgid "Plugin Successfully Activated" msgstr "Wtyczka została pomyślnie aktywowana" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Aktywowanie..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -318,17 +318,17 @@ msgstr "Aktywowanie..." msgid "Activated" msgstr "Aktywowany" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Aktywuj" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Instalowanie..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Zainstalowano" @@ -336,11 +336,11 @@ msgstr "Zainstalowano" msgid "You do not have permission to access this page." msgstr "Nie masz uprawnień do dostępu do tej strony." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -540,7 +540,7 @@ msgid "Dropdown" msgstr "Lista rozwijana" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Wybierz opcję" @@ -560,7 +560,7 @@ msgstr "Potwierdź" msgid "Confirm %s" msgstr "Potwierdź %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Wyrażam zgodę na przechowywanie przez tę stronę moich przesłanych informacji, aby mogli odpowiedzieć na moje zapytanie." @@ -617,7 +617,7 @@ msgstr "Dane formularza nie zostały znalezione." msgid "Sorry, you are not allowed to view the form." msgstr "Przepraszam, nie masz uprawnień do przeglądania formularza." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "Wystąpił błąd podczas próby przesłania formularza. Proszę spróbować ponownie." @@ -625,7 +625,7 @@ msgstr "Wystąpił błąd podczas próby przesłania formularza. Proszę spróbo msgid "Test Email Sent Successfully." msgstr "Testowy e-mail został wysłany pomyślnie." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "Nie znaleziono formularzy." @@ -666,7 +666,7 @@ msgstr "Wartość musi być unikalna." msgid "Sorry, you are not allowed to perform this action." msgstr "Przepraszam, nie masz uprawnień do wykonania tej czynności." -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Oceń SureForms" @@ -713,9 +713,10 @@ msgstr "Pokaż" msgid "Hide" msgstr "Ukryj" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Edytuj formularz" @@ -726,7 +727,7 @@ msgstr "Edytuj formularz" msgid "Edit" msgstr "Edytuj" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -740,32 +741,32 @@ msgstr "Utwórz" msgid "Import Form" msgstr "Formularz importu" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Dodaj nowy formularz" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "Nie znaleziono rekordów" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "To tutaj pojawią się Twoje wpisy w formularzu" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Wyświetl formularz" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Wyświetl formularze" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -779,30 +780,30 @@ msgstr "Wyświetl formularze" msgid "Forms" msgstr "Formularze" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Formularze wyszukiwania" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Formularze nadrzędne:" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "Nie znaleziono formularzy w koszu." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Formularz opublikowany." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Formularz zaktualizowany." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Powiadomienie e-mail dla administratora" @@ -810,7 +811,7 @@ msgstr "Powiadomienie e-mail dla administratora" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8335,7 +8336,7 @@ msgstr "Zmień formularz" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Ten formularz został usunięty lub jest niedostępny." @@ -8886,9 +8887,9 @@ msgstr "Dodaj bloki do paska szybkich akcji" msgid "Re-arrange block inside Quick Action Bar" msgstr "Przestaw blok wewnątrz paska szybkich akcji" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9260,7 +9261,7 @@ msgstr "Centrum" msgid "Right" msgstr "Prawo" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9270,7 +9271,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "CloudFlare Turnstile" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9331,7 +9332,7 @@ msgstr "Poprzedni" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Dziękuję" @@ -9566,7 +9567,7 @@ msgstr "Klucz strony" msgid "Secret Key" msgstr "Klucz tajny" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Cloudflare Turnstile" @@ -10616,7 +10617,7 @@ msgstr "Odblokuj formularze konwersacyjne" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Dzięki planowi SureForms Pro możesz przekształcić swoje formularze w angażujące, konwersacyjne układy, zapewniając płynne doświadczenie użytkownika." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Pobierz SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Wybierz gradient" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "Weryfikacja Captcha nie powiodła się. Nie podano kodu błędu." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "Weryfikacja Captcha nie powiodła się." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Nieznana Captcha" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Nieprawidłowy typ captcha." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "Weryfikacja %s nie powiodła się. Proszę skontaktować się z administratorem strony." @@ -11242,8 +11243,8 @@ msgstr "Opisz formularz, który chcesz utworzyć" msgid "We are building your form…" msgstr "Budujemy Twój formularz…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Włącz powiadomienia administratora" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "Powiadomienia administracyjne informują Cię o nowych wpisach formularza od Twojej ostatniej wizyty." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Nieautoryzowany użytkownik." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sZacznij od %2$szbudowania swojego pierwszego formularza%3$s.%4$s%5$sDoświadcz mocy naszego intuicyjnego Kreatora Formularzy AI%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "SureForms czeka na Ciebie!" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Zbuduj mój pierwszy formularz" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Odrzuć" @@ -11417,51 +11418,51 @@ msgstr "Zaloguj się" msgid "Register" msgstr "Zarejestruj się" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Ostatnie wpisy" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( Ostatnie 7 dni )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Użyj logiki warunkowej, aby pokazać tylko to, co ważne" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Podziel swój formularz na etapy, aby był łatwy." -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Pozwól ludziom przesyłać pliki bezpośrednio do Twojego formularza" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Automatycznie przekształcaj odpowiedzi w pliki PDF do pobrania" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Pozwól użytkownikom podpisać się w prostym polu podpisu" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Połącz swój formularz z innymi narzędziami za pomocą webhooków" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Użyj Formularzy Konwersacyjnych, aby uzyskać doświadczenie podobne do czatu" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Pozwól użytkownikom zarejestrować się lub zalogować przez Twój formularz" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Twórz formularze, które tworzą konta użytkowników WordPress" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Dodaj obliczenia do automatycznego sumowania wyników lub cen" @@ -11883,7 +11884,7 @@ msgstr "Odkryj SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Coś poszło nie tak. Zarejestrowaliśmy błąd do dalszego zbadania" -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "Pole jest nieprawidłowe." @@ -11951,8 +11952,8 @@ msgstr "Miniatura wideo SureForms" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Oczekiwany format dla e-maili - email@sureforms.com lub John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12330,7 +12331,7 @@ msgstr "Nieznany" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Użytkownik gościnny" @@ -12356,7 +12357,7 @@ msgstr "Stripe nie jest połączony." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Nie znaleziono tajnego klucza Stripe." @@ -12465,7 +12466,7 @@ msgstr "Nie znaleziono subskrypcji dla płatności." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "ID użytkownika: %d" @@ -12499,7 +12500,7 @@ msgstr "Identyfikator subskrypcji: %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12544,7 +12545,7 @@ msgstr "ID klienta: %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12554,7 +12555,7 @@ msgstr "Kwota: %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Tryb: %s" @@ -12563,24 +12564,24 @@ msgstr "Tryb: %s" msgid "Failed to verify subscription." msgstr "Nie udało się zweryfikować subskrypcji." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Nie udało się pobrać intencji płatności." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "Płatność nie została pomyślnie potwierdzona." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Weryfikacja płatności" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12588,18 +12589,18 @@ msgstr "ID transakcji: %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Status: %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Nie udało się utworzyć klienta Stripe." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Nie udało się utworzyć gościa klienta Stripe." @@ -13466,7 +13467,7 @@ msgstr "Edytuj ten formularz" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Twój formularz został pomyślnie przesłany. Przejrzymy Twoje dane i wkrótce się z Tobą skontaktujemy." @@ -15163,7 +15164,7 @@ msgstr "Wartość pola zmiennej kwoty jest wymagana." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Kwota płatności poniżej minimum. Minimum: %1$s, otrzymano %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Kopiuj)" @@ -15362,12 +15363,12 @@ msgid "Stripe Settings" msgstr "Ustawienia Stripe" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "SureForms %1$s wymaga co najmniej %2$s %3$s do prawidłowego działania. Proszę zaktualizować do najnowszej wersji." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Zaktualizuj teraz" @@ -15415,8 +15416,8 @@ msgstr "Pozycja znaku waluty" msgid "Select the position of the currency symbol relative to the amount." msgstr "Wybierz pozycję symbolu waluty względem kwoty." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15430,40 +15431,40 @@ msgstr "Wybierz pozycję symbolu waluty względem kwoty." msgid "Learn" msgstr "Ucz się" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "Niesamowite! SureForms napędza Twoje formularze i zgłoszenia - rozwijajmy się razem!" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Jeśli SureForms okazał się pomocny, czy mógłbyś poświęcić chwilę na pozostawienie 5-gwiazdkowej recenzji na WordPress.org?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Może później" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "Już to zrobiłem" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms jest gotowy, aby zasilić Twoje formularze — odkryj, co jest możliwe!" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Zarządzaj swoimi formularzami, śledź zgłoszenia i odkrywaj funkcje takie jak AI Form Builder, integracje płatności i inne z poziomu pulpitu SureForms." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Przejdź do pulpitu nawigacyjnego" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Już wiem" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Nieprawidłowe parametry." @@ -15841,8 +15842,8 @@ msgstr "Pole tekstowe" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Ten formularz nie jest jeszcze dostępny. Sprawdź ponownie po zaplanowanym czasie rozpoczęcia." @@ -16126,8 +16127,8 @@ msgstr "Nie można usunąć webhooka." msgid "Unable to connect to Stripe." msgstr "Nie można połączyć się ze Stripe." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Formularz jest zamknięty. Okres składania wniosków zakończył się." @@ -16797,19 +16798,19 @@ msgstr "Tajny klucz webhooka nie jest skonfigurowany." msgid "Invalid webhook signature." msgstr "Nieprawidłowy podpis webhooka." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Quizy" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Wpisy do quizu" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Nowy" @@ -17327,9 +17328,9 @@ msgstr "Idealne do edukacji, szkoleń i zabawnych ciekawostek" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Wybierz to, aby utworzyć quiz z punktowanymi pytaniami i ocenianymi wynikami." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Raporty z ankiet" @@ -17735,7 +17736,7 @@ msgid "Error creating SureForms Form." msgstr "Błąd podczas tworzenia formularza SureForms." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17893,9 +17894,9 @@ msgstr "Odpowiedź AI była pusta. Proszę dopracować swój prompt i spróbowa msgid "Unable to build form fields from the AI response." msgstr "Nie można utworzyć pól formularza z odpowiedzi AI." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Częściowe wpisy" @@ -18766,23 +18767,23 @@ msgstr "Nie można zweryfikować kwoty płatności dla tego formularza. Proszę msgid "Cancellation is not supported for this payment gateway." msgstr "Anulowanie nie jest obsługiwane dla tej bramki płatności." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Szybki Szkic" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Opisz formularz, a SureForms AI wygeneruje go dla Ciebie." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Opisz swój formularz" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Przykład: Utwórz formularz kontaktowy z polami na imię, email, telefon i wiadomość." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Przekierowywanie..." @@ -18795,14 +18796,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "Podpowiedź jest zbyt długa. Skróć ją i spróbuj ponownie." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "Część przed @ nie może przekraczać %s znaków." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18889,22 +18890,97 @@ msgstr "Przepraszamy, nie masz uprawnień do renderowania tego formularza." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Ten formularz wymaga płatności. Proszę dokończyć płatność i przesłać ponownie." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "Nie masz uprawnień do aktualizacji tego polecenia." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Dokończ konfigurowanie formularza" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Przejrzyj lub edytuj formularz" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Edytuj formularz" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Spersonalizuj wiadomość podziękowania" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Edytuj wiadomość" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Wybierz, kto zostanie powiadomiony o nowych odpowiedziach" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "Skonfiguruj e-mail" + +#: admin/admin.php:570 +msgid "your form" +msgstr "twój formularz" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Dokończ konfigurowanie %s" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "Zobacz %s (otwiera się w nowej karcie)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Dostosuj swój formularz, aby był gotowy do rzeczywistych zgłoszeń:" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "Już stworzyliśmy ten formularz dla Ciebie. Dokończ jego dostosowywanie, aby był gotowy do zbierania rzeczywistych zgłoszeń." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Dokończ konfigurowanie „%s”" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Edytuj wiadomość podziękowania" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Ustaw, gdzie mają trafiać odpowiedzi" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(otwiera się w nowej karcie)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Formularze" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Formularz" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Formularze" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Dodaj nowy" diff --git a/languages/sureforms-pt_PT.mo b/languages/sureforms-pt_PT.mo index 203990d3ecdf6b2974adfdfbc7d1557ecb9ea107..d3c551837402e0bc9127cb802a63fd7a479c95c6 100644 GIT binary patch delta 72241 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 J;fzuR{uew0ObGx0 delta 70903 zcmX`!dAyEA|G@G498$I<ds&Ws-}imr_a%fxw(O~dEH^E(gisW1NJ>(oP+FBpDn$=c z+EA$!T7}=|bI-hf&p+>(xvp#GJKveP?)x0_d~qtzvaj<bzq&f}Lka$ukvownjD_b~ z!>iN&-^(c#q23cq<CQoC8{r(xj_;vQ?8h$n8D4`W@}#BuZHzUj_rt8X0J)w_EDwdm zOIVx>`>+F^MmuVdH!YD9=VB3Dj>Yh0oQMap33kkvmZ*;Nuomt>2l^fJ;Cak}x$>ta zI$>eV%lL_r6rAA<bb#4-6+VSU@ntN42ha@tj0TjoKw5&NB?_Q3Eg$QxuoU&)SRbdx z`pf9RN6_)g7EDWIWBf!_3K`e{O>KWPrK8Zu@4%~Z9vawVXaF10`*xrK?nWo@H5%AO zG^1A)3KOY;S5WVc-q#P44Jb^eP#QPmjd&P4V*P8<5;x(!cmw``E=`+jL;GSh_2<xz zYZgvRG{r`k52s-+T!Kz)b#xP&fwu~$B@<aF?4}_bevCeF1fA(m=*-Te9p)(#>gCb< znqw90jxBH|8pzJr{vq1$d8~$6iiU~QMelp4XfoXJI1Q%yS@eO|qr2mcpT+u7yo~E7 z(cS(FK8~lc7%nUp0@;YJ_3zjcn`ERV2H{<p3BN-(=gA}mXYxC?$F$;Mtvg~t>H{%9 zPD0mwA-cAY;u_qDRk25ju)FWVEz}pGo3B;Lw1i7M1D)V@bT92g$4!1s!BqT)F2z6S zjfqlWjq;+`3u9g^jV?t4?2Fwn1D{1_^Z|Mr4xj;_j$T0f&t5uY;A&)o$wYn%K3Fw0 zB<iEPx<_;%x>-h{=l520GbPc$7NUD)Il8N#K?B`|2Ji*i|BvV%Ig4enPMNgCB+vgq z3eM<rbhG`8p8L#YLuyN+0rf=NZ^Ujm15NSA=&sLNE-f(<+ha}KjBdJ<*aZug5B-n8 z5!91dhw&39DflWaS|QA|KRVMP(Ob}&Opo>X=)e!7fqjau=~w8U`5k*=wu&J`1JSh} zfo5hBx`*z^q^WzHf~kA~&BQkJfsfDuzQT6+6Z%4_St+dLb?DLzKm#6%208&fMM?De zdFT=>L-)Xw=y>ZYasCb9#dyQp(Y<Jg2eC7Li)N@=<*>QNqPu<$dK|Z*d*TiBLuMbg z!9<m`#1v?YCGl-E1IN(-{;k6KceiJ%nwBVs1<(vMLyui=G{CXw`JRE!;Bj>KuZ{JK z=!`F`7M{Bb3sEnNer7aBpBoq*hGu3=l7eeC8Oz{ebmrU8-TWRJz<21HokM4srFuAa z^|3Pbepnvopu77e^v!q#Q=79!T4FBs_GtYx^g}9{r)EfLJ#?4$L?c~|X69LRCa=f( z|Io-!p@IE{?tv?6g*CnkU6O0ijATSBqR-VqQ{N)glZlS;LLW@+dUUhgg0AVE=m2vu zGcHC0TZZ1ZK3?B~ZrUAaU>~A^e2L!o9lEr?pn+tn?RCyyE()z^$cGNp4<Epra2TG& z=kfYFX^DDxdEK<cMr?+U;%U4c@2{7Z=z(eV!}05d*HM24d*Ma&bo6WxmTEATWBkN? z3a<4Qtcjmu24-m(c7Itkl@rm7%#1FIK90`(d31)aqf7P~`d;`YwkH~e=kufemByqG zR-<5K&Ct|zL3e*YbaPHXQ#voUuSA#NC3I8nLI*m8-ggQO^gp!!?2SYJ*P?4*9$o4h zjXD1on#P7s=nSq$KSai(0n9@KT!Rk0DPDgs*1wLPL;Jg;Nw_Z`+FyAz(57f+x}*J# zZo>I@##3l;pnK67JRWa&A^JMn!Co|gFVPwPj&_)68m?c1rnVAR!Mf;-hok+D$8?;D zCGhSf1<&Er=q}xh?(&0ZM@OQ^(arfA8pz-1OtUo$^#YihDORVwDca8jbSdw^I=BG+ z5PKKfV)8o*#VAy49yVP^tVMkc*2Y!X5dRm=(;~cjyP|KlB-X`8(GCybTrAu&E%6{e zjb^xEs}OKo^!?HcIiATxe+qt;8jOB58iHnGM66FhXEG68vpZvb4w}*h(Z|t@y%6iK zqML6ox&&XK&wn31gQ@eMXdQ0If)1PuO>H6c1yUxqS3(1<gU+Y{x+HDT0lJ_|(<io% z#MBa?1K)w}nS0Rtmtt<u|DzNfXd@c&7IY@>q8)sUc5na<?Az#R^#1?QHO|o{JXaD8 zv<f<*8tA}{(C0g%f%nCv7Y0#qpz&z^b~J#y(SaADGkX-<<3=2af1@4tX&X8miq32d z`rJe`z`N0<T8i$Kr_lb7w&naA;Yk|wcQmr|Xvdk_g}|;tAIKNYh*m`JuY(TQ1l?Sn zqCKPiqJz;)-;7RpT)SlG;5HfzU~2T<c*COTgV9IO3_Tv}&qrU1ZjJ6h1AaUDAsXQS z(D%o2bb|jRDL8PJ_8~=Ap$`_1Rzg!+7b{>hT!Ev}bDpI`c)lJw^A_my?a>!gFLbkx zLj$-IU6MKIxXFhpn2Oa{4%fx{C+JKMqLF@&4)A+y{~PV#@{YmW=zZ6so39)?a3ypC z_0YhYM>`<_B@=x@Au$YH%iGX3nu-oM3k_rrn!4p^$Isy`+=|{;zf-v03{x|Y^>OI^ zccB3;L<3)mx&8cKOTl;XRxFE0&{U;&4uM>SMxGz-pg6jltDrM$iU!;c4Wvu-Iy4gl z&;bXbnI46Hiyn`8JpYR+xVCH2Kt4g=<!7-nX6+K**>$lw_1;(&AI8?W8>i!yUBj#T ze)RjqZZyCXcrBhr`_0}h)Qe-%hQ<_}QBQQ{L!-B%GoFcVngwVoAB)$YMVDqPI>0V; zz;Dt1PN6gZ4}C#p=^m~ZiI(XefBvsZgDI?o4%7%uT_-g4-O!HvV=6#2)wiMpO+f>j z7hQ%vw;Ijp^XO;HCzy_(qJbUk&iVJoV>CF^pU^kmU$LIGM_hY!fZ}K%mC>2kL7!`l z2G%3C4~q5i(dn^$J{tH6^tn~Zc*90CkR50S-bZ))|Ii0cp#hwU?HAENuI?E&)3xYx zjia5>0d7Els2zpAdhfzY_$r!#<VgzN_<Qss8c6nDVSxPDih40@hC|WoYvc77(XVRT z(H~3>pvU;~>%zC*T<B5`MJI4GI`Hkt#FB{_6r9Pu(S_&$%h8Tj$NKu{%V<Y$q0fDY zX6PWAfurbzenvO<Kj?tDdWR({6fKLHJpZ*RctibYOSHqz=$iJ5-h>8rOLQuF-)!`S zvj7cj9lDt}qxWw|1A7<UTL;klPN?Vq3<V>;h^|%kKH<TVXnPfW6&s=f{fX}S%zeXs z`Opbup!Zim2dEpbw~W`j#Or<00Ec1H2S!t{<H=}BXQR7&5&FIU@#rRW#_ysX>_wm7 zj}G`1I^&;W`ya8Meto!}6TMyteXi8?@%w*u8VsOGyrC01Kp(W@8_<A8#`<J5(0kC1 z7DQK|0j@(&&qnn5cd#UW6x+{W73x{~asDS#sNF9-@Ep2}-^Af~2FKy`{X@sQ(HVRk z>qnyBplka>^j|b{IR=EaFNOwM6%DLWv|ExwUK)m?9ZW%Y?R<2gRp<;hpdD^QXTCSq z55(&yqi4~9E=6<P5bA}ZWzha=Mw3k`xH~(do2ozB!I*f%6m)al8|#bW^_A$S*)y^J zJbq05RrJ`-8yE&!f-c?T=#oB<PGmDOPBO8Jf@}X-yzmX0qH|~luDCIL)5(K=$h1aZ zID^r^rlAv<jSjR79bj#&Z$k%uAI<Q-SU;AM^LIR6I2A8kKr@kPQ0Oo(8c4}luM+Ex z(Sh5=dS5i~A<;=_fb-G79zvJ;DYU=s);<64Qs{z*u{@R=oR+AFJ<uCxpu2i*^Z_*W z%h9!bH2Ms>bX(AY-$tL`i_ZLWbZLHw*MGyLsri>e8BE-imUs@z;t2c<M`ObwX^D4n z9S*`VL&Jy3K6HS~hJ_Sgg$|G(ooUfnuNmtN(SW<5fesiJKmSM4;M(4TX5fCbqgT+> zy@5Wk4^8<IbkF>RcKA1XDl!ib*K?xRi=fX}M4xYf_S+U+;;zG!;gvgxhSD@lMpO4V zx|YwN9q)*~hj#c8`p*9n-E4oMzdy(}BBZ(`+D~n)hfUFpOvbjj0Db;ol7e3bPh(@u zeRGJgD>`r=G{u9^h)1I{n-=Ty&^OykbbvR}wLXA;^ErXupLJyDrvRFP5@;rq6)04o z&;U*4F!V!c0$zu6(eG}@Z~*>^4$yN{xNjJir9K@EU@dmUS8*$586Ezh;ti}y{iZP? zQ%jJ*l8NUi*x`0GWqZ*G526u%iB0gA*j{ODI1RPX`x>H|X^Cd67q-S5(4|^~2KEyA zW_>@_zf4`{{GFj-iqgh~j&q@z$d7KC60yB1I$$02_%%TXXo)Ui4|F28qZ65p-uD37 z|3m0$TZ0YpSuErEKTg5Tmt%bRRH}jAI2beG2y`=!M&AQTbimnI4WB`e?_o6X#4Ta1 zbD$Y4fG%lSGy_f1@vg(9zYLm6!I`W;BYhT^<5v6uyG{r*t9NVIY#p!>?c?wcd=A@U ziQB?%ABEP}pff#%wXp2%;YYRsXux0H&iUU(;j)QgQ+$ZeQ9q8(WbqwgZ68B_*|ZT| z%e`0%zeXo;*`%<EOJRBHUD5U_=;nPGJ#H_c@0mTZ{rDu#za9Tag98?t95PTEUAvlS zdp&eXTA|0WL%e=nZ10CI%^);`BjWXm@%o*yeI^>vLUifYCMmdkKSw(_8T~c3|A7ve zWlAtNdVgW`g;N;~unoHTdZ70YMVE9u7Q-3ni|TRo{!Qo-BwwfCCixzX{2ZFP^gDya z(T<y8CG3F}F^Rqpp2MDa#niOKN*sU&_BR?x?rGsiufk}(D7vZ32a}1)6ijV(H05>C zOf*8zb4&C%b&Bo1WBU#0{ln22jYb2V6rCH}SE3VJhfeHeG>`)+Ie*6}IN(p{`TiZv z$UkU@S*M2%u8o#Q_e@>%xn9x!==<U(G@$X(spwMNhxWS+U5ckMpXYx&1$XDiXa_%{ z5&nsGlr|%n6TMyt%}5zEL)Fk@Rv%sKiRkHg2>on$6&>&^w7=icz%O9Z-I$qE@GxGB zRdEZNiSMI7qYs>m_48;TnPvvBLSIlt&>2=oGuIsLrzaXfe>C86=+aG^$@#ZoTD<XI zbY=^p%hBtrqU+JjY>xFe(EHy<*LXiV&@prqo<ZLi*=L3J3^cHs=qYMFi<#JAZyH>J z!STXWH1hk=0Uks<dOWsoj=qKtv@_O^Vl(RBqf1fxuJA{-t<hbdL^F9e+W$NojATi? zVNJYYU34QlvzO!bo#-0AkDi*(&~L+su^XO4Q``FP5O@dl{$8;@2n}FVG&zBS4@|}k zoQ}@;aWwVMpflfue(3DN4EzBNEbBd?!vg3por=bKBXp0nMEmK6?v3lwfJP$sCleDX zn2M$7jVsaP@)Y{6-W>fHz3&t{@L4qQw0lE63;JAMbbyj*e^sOP(C3<?{dC2v{rSHS z1!p`8UCY~XA}&B9&NMr0nmlOgN}~f+LO)I$Vj6Zwf4S5X{kZLo1~3lYW0RtHp_y5L zS9<<e#0$^H3tP}g-^MohF;2z&_l3{xC1?lR&|~)=nu){cM7}}?{2|uQqW53GGMH^n zxLzHT9*0I0oKY9FgBvjQ#RJ`BqhtF7tVew+I<qa&*U^4<p@AGiGw~(*{MYD&PM}M3 z4n3xcxtxDrKzZhdh6?D68l$Q2j#Y6my2}@1HQa#ijW5x6`akG>1?Pp$*$z8XABh!l zD_)1+VQs8GKLj#<KIh+#r_#^@m!WHV7~Kn}(HUHEe_G;xyb>$mO7z(7Lf;$zLwEo0 zXeM(l2+tQq_d;ECqFvGchojF;OU4V!qR(RqF1(8db`lLFePQ^s;cL-UcSSQbIMyek z1K)?Hb{Uq(XVHN_LtjWgp#f!E6h0f0B`EZup$&S&BWUWkV`<!jHSsh)i6tLMOU%J{ zu@QD&9QMpS^!W$T0Jfl?lJBES^*v@_VoA7O9GO@$QHz2p>5RT;hM?zjGCISV=o&wW zO>i^1hG)>FDYrBXPzBw*9nkxGp((x%GjIWVDmJ2<cRS|u{J#?~9EyI2uI;brdB21{ zkmbP;XfAX&mquq=6HR@a=ym8WABsMIOLS6n2KxNHSd{S-ODQ<hm(WeLE8g%un!+<^ z0J$Ct7DSI(@n{)z<`uCk)<*BY7wvx`cEl@}g~0luduTYO&i`ZzMmi7O3yaYg#`n?R z(NtbU_eR0xAw%V&^`jl4{n3ENp#9!~rhYp5{2X+XKfIjtpF!a@8hqg#MN{`Rn$n-q zj?Sa6*vlRc9bF#18V$5atXDt>s2$r|qtEw1`x}7nvC-%f&wQBkZ(%VF9+TB*2iv22 z;*E#VWAhWbS<@d09Ttq1MF*-A>&?)Cx}q~5iuOAmO?@)f7h7<xR-qBDk2h>bXSNsJ zEQipJPM{tA9!*;juIEOt7eo825bHJ3P1*!qitacL`(k-azE8o;_d9ytFIyRoPerUo zy#uD+kmzPyhQ)C+mc@hUEA|3rVEISGuj@LX$8Z|@{7Q5Wy@Edf3G!Y@CeDOH;>yQD zhZWGJ=z-;MBv!&DXh&~iDLjH1cnRxZ#^Yf|eb5)yEVTV)tcpLQ{S<y81l%4|fB$zP z1>aEf&|Ud7X5gOaPw27C{$zOfmq%a8z0jGAMW0`UmGL>Oj)&0<WM37mfNt{k=-%jz zSv;RNQE=Cfj5ka~-+)ulwVs8(=@z4FxEu%I<LDkaAFp4rI^1_9x)<`Id#4z>#Ffz{ zY#!SOV$vCpp<u_0(1DhrFPKNs09K(LZ9+SK6Wzrhpr_(!te-<qQ<gPhh6T|3Dxs&N z3EEFPbd&a8!}+(v8)+~DqtN;tu|5l(;R199E8_Kyv3)z*(XQynXuyZifqy{z{TDr5 zS)L00<wM6Q@l-NIRG9`NY=}P48tte%nu)>j`tVr41<lw*bS<Z$0WL=Oz*?+}pP{=x z``U22N~8C8M8_GFq+my5(1C7?7bc@KxF@<S`V6`^UPS|Z2kq!nbVgsr`j6;R{DCe} zmZwAiMbU|t#D_3hnSyJ+6HWCVG?35HlzoAw_$Tzfv*<wopn+#z7dp(229hsY9Nq1e z(fg{SYhMo?rwwv{GSM>>5;sOiqXA4pZ=8m{59UUn#0u26q62=5&gj?Z-{^Dc&xF8p zq5Ty^H+zxT-Yg~OuRR54)B}z12K1FV8eM`J@%jVkdtfEH*4xpw+=mA6EjsYe(SI;? z8lDaP6hN1(JUUK&Onv`vOTh<w+kivRfNqUWM<1MnmGI%%{vI}>{t33noa@8+?t=z& zJG%BW&==M+ERQds{T;@n1N}&$BA$yEGM)=FtA^g#8tve^*gg(xQokDwXe(C7@6i`b z{taOQHPHZ?pfm1`?xCURL`QAl{8yncB{n>RcCZ!A$N_ZoeS_}$pJMx&=p}RlIi3#| zK-ani`r%X-eXc9I3H!wB1JUP(JkR+zRpa7~lj99D;|=#>1+G7UcJLae;XCL+@1mP< z54vX#q8a-E-8+BBdbW)rkZaHhm5B9<NeZT<CK^$Fbmpzl4!XzdL(l<7#`-w)c-@XZ zHyNGj-Dqm(qf52|-GrObf!~eo`_NCv<cWAgkr%>%RnP#M#d>FSW;aG}MR)(b(MQmZ zpGO0E1<lCY=*RUwbRs`sWBeDpV7(VpzY9(#?xS!!4Ous(C8psF?2G5I9`<@EWM~1J zfu*tjFq(nK(V4GCmuNk@q?=;>wdgxIh4wvYfGsyW5zc>C3U)9AU5e4MJ^@|JDbcy{ z`XiW5`xBTNI9^|m?($dB0d}J=t^;Ubr{eW9Xn=_=+~?<iHVQp4KbrbcUcgDwyV2Ax ziuD!Ir_ljlioS)e^+#x6$IzuY8QXu0ro9}VyBbq}|1X1rYg83Yar1aX8+71aXka&@ zdtnTEUou|52i+5k(16yUn{X34^S9#l_t6Z0f%f;!%bb53ex<>I&czFt&>7@-C3Kh< z?WhDgaCvm?tDwiR2D&7*qIIJUqK%`?qAjsA_qTb4^KXX_(qPITK~uOEozW|?{R1?> z&(T1>K?DB*eg0Q;#%IyBP2U>KfzC8P+FwcZGovn=@lHt!rgUJuFaZr@c5GjQ4!joK zj4wvtLIeE-P5C$IK&NB<zi75?;rW7SU?tJOE2En;S(AbTc0fDojm~6ftlx%4J`0Wf zq1e72?Qk0!*gI%IpQ0Uq7u)|uH(|EzA&@+1y(qH8$wb+Bp(@%@gIMnn>(`+_at%WR zn;P5ap-Zs>-7BlmfS!$Rj=mm!Ke|8q1!njBAE)5JzoV&6do`?04z$Cf=m6!=)K!bu z>!3^54t>@3kM-N*_4{J|5j4XaqTA5G-^J8_|F@Tdo8fbG34TBa{u6yL@mi?oK)=D{ zkM;UkjCxCKk3+CJK9BxDat!?vdLErX%^hKa4RJ2@Hkh=7Pbe7CZ|Ela3*FV3Uk?Lk zjpjj@pa{0XN@#$$#r9-$A)2Yj(0<mS_dSDtAJ`J>AHL4{_rf6>+!WuVo9Gv`gNx{r zWPT%D&xN)ZMB9tT_VQ@vYM=o&LnqV~y}x&?4?r_J1igRk8=QaFermjNe!Q?4-StnP zn{P9^)_c%Xa5UC`N7p{{o8fv9bVAk802@WyqD$NZOW{y7({q#YhGl3(tI&_l7cc`q zi1kxw09oD&4;Di2FM|$L3!Q1xXlrzUj_BI=MQ1(;ePfP7GoBnn!Hy=Psk<9{;}RT% zKcWM7css1+4d{S3MaQBYPeup23tjVh@%kb(kQL~C>(D?qAps;4TPgV9Tj-6u@n$@T zJ+a9<X^CdI1by(c=wWoP97C7tH*^A-cLwvIftElgP#Mi^Gjz%OV;0Z<=v0BP+h_+< z&^4Tc2J|4hYgfhV+p#|N-SK+*yJ?C3)N`S0JR0q1Iu6DA(SCl%7I+cuzxjJ)fbkQZ zDWrBO8u0*h_l`gx9EWy1HM#&@yC=|8KZE{Y@;sKoz32dE(3xLEmpJ#X&|VA;up*}Z z{!ar64%7_oxHGy|z0su^gm!c@n)0dWDYze-;VSh0Z_yP0j1GAD`=Q@_XnP6tG&M$_ z@A*FG-w%tMX{dxr^vC55I0kp2GpV^de5f=<1MQ6lIt0zknAko89e6%E;3H^%ThL?o z5jyZ$td3XgNrvCeG}sdcx*pw3!_W?<pqu4EEQ?QJdHfJP_kW@@%Jo5b<(5WY(akXf zhob%6i%#?rG?Oo)&+SZ7Fv7!VYR{tY?#z3`FAOr!_BQCu`k);QL)UyVx|Yk(f!1OM zZbt(-65B7J{pS8K1X3B@)X7#9x=|Q_M)W-TnXog~zr%9W|3L#Nu`m3=K{Yf(z0l{z zqxap5RdFLaz*p#ff1>y0{wQRwEYhA#G^60peEreXPL8g|4C)`E9sGjM^oox|1`6N| z>J@M#K8v23JfDR7u0i)sdGw7}8(qq}=pJf|slWf*i-NniFM6DALT?-q>yyx9ISn1) zKD6V7Xh18_=bpu;xDh?hzoNhYI~VJD_J`*Rp_wd=?0<GQ1v{>dKG-PMTcEqUJ$f4Y zqml1M&-p?0TkwCep7=EMQx-k8RnSvXC$=|518;){&;yg+FeqLa8J&n`WEMKZ`DhAP zpaDLLwQ)6ij1HlJW&11)SO6U$BU&Z4H$o@W8l7;T&*JC*KpKo}6guD?=nU>f2V8&# zv^4q{mZ!cBOXGg@`M=PPGaU#^k`3)A7urt&bSaCV{gpew`M0444R+8NQz=I~>W`^C z5wDMk-WE-w9nDAkc?dn8PokOKj1Ig5?dKiz{`b*6w%-maQuqcdW6p!&cRCHR3iZiY z3D;pKJb(sR{PU2hn&`Q1fp$DFdNVrkt+75C&BR?;1LvUuC10oD%-=!R@FR5QU!ZIF zEqdc`=nVfrUr34ng&F2XpT7out_(VGWi+6g=<|)y=Ubo?=!^uEOx#Gpck&3FgVVx= z#ASy<06Ec)u0>N;8ttfdv>Cc*I-+mDe&|HTMW><z&WWx-1KNOD{rulV!N^}jBYy{- z`R>#Wd@YadU!yZUfu4pl=<z#;PT+4eu$+g(00q(OMbOk2N5?6TX0RF-_WU=e;D^IN z^p!ag{Y+R8+t;D5&Nt9Z9Ke$J72bpCN5b{{&<s6>&iHw3h;O19I*$u6+ZQ2#M=<sK zzx5QH*~@6eZ=)%E4~_IwbOzsHMLdPhq`=W|y(l_hRdn|^N1yM74m=p`=azVV7J51! zJj(gEqsM4)O`bv@cot3RHZ-t((ZlFK$I<)#LYFGbm*M`r=pHDKsZEDwtOa^sC$ztQ z=u!>;lJoBk6KF7XQ{#>EG4*+kM*1T9al0M8?|*1UPNEYyjo$Ysmd8tICdz*m?r(%H zX(zOOI2zEDWV~=6dM;O?106s!a0ZR|@?&AZJm@C979F^Fv>X~h)mX0=>rK%>+eN!Y z`=U#f97LfCg|X-thDXtk-;6ixLR0k_nyIg1{RebS&!U;i{B@{bi{4)ey}xd>IXd%> zu|5z9IGMPaf@?V;-Y_$|6iw07*cP{7OZ+chZ}v_2OQk*0OwB<v^BB4Z)}Y@TwxZuJ zK1G-2G?vCf-#SswUsDS1`Zj0^JD?r)Ox?iWSc(opQ#Jw}@OCu7xzXk5^J~!zZj8Q+ zW@HEY{QKx8K7gtJ{_lhZ8vaE$*OlMJV}-7L)o4RBg>BI_?S~F{6S~_+V=24^4eTK_ zkTvLi>(Kx<<AeAXrq2I$--j6wLT?<7b}$}&U^?D|^U#^+IvxTph2B>W4X6z|(=O<9 z*Q0x5IQk(q9i8AK=nL)H<D7pt-J3M%x9A)2vJ>IPB4|LBW4#W#G;PpVa3^%>y2R@} zV*MsGkl|=%CZGY{5$iM1!0$eh4F5dNVj5hN57Cr;g${HaE8!^|gauEA0jHpWO-FwY zn2j#Y6X;UDgwA+Zy#8&xejc6Rl|O{<ie-`%JSM}@NN+)p)kHLfv(cF>MF)I5*4Lqd zzJ%_P?dS~OL+{&%o~qB${*PmKJdFm>{Kv4A$?GXN;5anmB)T>$(GE6YU3?3DLH&(x zvWh>2fx4kfcRhOlG&Cdg(Qm&`p=-Vq&G2VvrjFxk&;Q>PdeN}*R5+)<p&jJ>IefV+ zgFes~?PxTb;;HCN7NHYZ7u|*qv<L6UFJk@XU&6%hM3?jd?CAM_ok9f~vi=$ZsD&BS zyQ4F>6`lEFG{x_tOY$N5g83i1bZ5{M|Aj71`_m!dZs-yWLYHb3`rIAZ%FqAB6ei;5 zXsSE?7JdVA557eG7j!c|`Fq&4Pou|h3p(>XXoil&>%U+}>gUlw+MWq}sSCR6`=if~ z#H5886inGtw4=3H61SnR%%f=JS<Z%IcQux#o)-<Q0h*C!=%($6?uEW+#zw^Ycr<_+ zvHkwDoPT%ggEYAL9z#3Wj_J4y?PyPIKZISVAIBb8>s<KH^zK9Z`4!!qf1#VW@E>8O zHPCunw7(nBy))(y&c7+VhX#Ep-taWK6fdKj^A~J_E&dE^Hw%5UJ&JC|&1k0HM>py3 zXh3Oyg(b*_-j^HASZU0_ib)Elq!YSH`k|>FiskSY?1qov82ky{y?y=;Gr9*yQeS}% znE9XZtJ$3BK)ui<?icIh(IuIPPB=N8f@{4nUU&)JG_S_`+i2?cpffv$F41Xp!2i%! z@n!#p)LxG6?)>PhxjMR(wb6m=q5U^QPE9h=mV%q76B<#USic$F6Stwqa}k=MSJ9ch ziypfV(11Qh`#FjZbP^rtbo5U&;0u`A%;)Wo^LI4`m!NQ}fnO+~YgH?@w~O|U?L*N4 zCZiddi3a)rdU`gX1HBpDjRw3Q8{_}b=kxtXyXU_M1s^PlMqCFCs4+UDj%X@-qu&kt zVJZN0CNt6Fdp{cZ<LL7*#rj)lpa;<YzDIZeX-xXS<rl&lUyG))I(kf+pbvJA?KhzJ zk3s{Ufqtu99IrozZnkaM5clCQ%z82WVe@z_P5o)Cjvrp+{Ci$6(oh9UUJA#e2RhJg zXdw5Yn`#+)|0W!VpW|3;%@(^EH)A_2oR*%-$T0N7X%ZUn3iOr!e5`+%mP}9mO@?DM z)Z#*(^iXeyWvNd?*YYVe#m}Ql@Fu!cU!om<kFN1w=u%xkpG(V>p4zn8&?U<o>xI!J zDwCvON44S&4bfB35?zX3=o$}3Gch(gEw;}`*K|2L!0PCFtV;bQ^u_con&BLoLqHAj zM(WAd6r9;wG?1<6n!XV|ghqM>4JdJ0dTNbxqV*DJfK}0c8lp?r8SQ6qtWQNVwFrH4 zt`6<V#C8hKY#;ifIf{0C27TZXx(Tn&67DO3ZnEm=fNju>^+f|6iGF{Wg!cCU8pzY= zIB%i-eT=C;|2sy(0Z+vn{*GRLd3Yc{+Hq-g;F{<R+o2r|KnEIw4saK`$rhuV_C+j% zd(oMnK?BTs1p#>eOHlC5R>cOahj!cwonbF@hQrZKHVM6NI+~%m=pJ}9wy#4cv^loF zg;S{S#n#w5YkHzN&d1c}|2_&1_$?aQ8MMRf*}{PN(Etmh1D8Q}d5w6zPHb<42HGyx zug9CH4?|zoyU_{kLo@nWw)A9b2H()&z~|5z<;)%e%0L6Dh7Q~iJyvaFd$-u$A01#s zY#$TbC!w4AZoC8MVKq$45%xrl9Gw3eG<2e&0w&SV`Sn;Fe?*T-_MGXdKl2%luIXBI zQ@w>H@d%E^i&z@RTp8Mzpf9Xf&<TElzIxB0Ka}Q3=1Ncf`<&&`b2=2=JPWZHK96p$ zedwF)JIuf=SA{^zqJg$RUsyx2E#8kAcmU1JAL!Eji|(oHxkDhyA{1<>jo#2U*88HV z8-+D-0{Z4#i`8)_8t5Nr#`0br2I`3}Szq*pGz4Ai(deF;g6^g1NMQW^9}3R!espbD z#~YrDzKpeLe-jPp4|I3`hYpZ6PpIcck7ZHx<G2ReZx^)Rq0zC?J5qA~lCfb<bTQiT zis)+eT(6IAM?2gd>-*7xzeZ<z4l81M-mu%NpwHKew#3oYdtmC%|KFfsq<hc~jzxb# zXL>$*MZR!4@?i$;<**L6N0)FWuE!-f1{>!Osa}uvvnAHwMl-n=Q~&<Qr?KG}rg7l} z`kn2E*nSFKvoq)(`47!N&H|z1{OG4=Npw&2#SEMj>kp%+U@LlBj-ve~3UdD4o!JV8 zj&h;Lq%gV!wb2(wV{}usMBf8l&_Mg49SuNdG(6VFqR&l=?bFfz?m;tgfAo=poPXEm z>3HMI@x~oEk@k1795yHvIvj!qFcJ-XBKqdM6Afe@8pwm_X<3Q(za0%=H~Rc1vHfV0 zLSq_EVLdE=O^EO&>`8rmtnWlS`UD;D7@CpOSOxz@2Pl7S2%tK;MD@@Co1;I_bVirr zUbMgDdI~pC*p9Akfx@AKa_CZ2MF(t$ZqB~weZ$dBHz~Hy#n#l9qi?`3(adEk681tR z^v%~99e5b>=1nGUr!bC&b!f!-i-rM<q4lcxAJ#)tTDw@-^*zxH%)<)!5c=8i7Mh9A z(53hy`YqbukI^$JIsfNlL*|TdL(XXaXfbTTgXPdoH5y&(3Gw<=G?07Hj4Z-gxGG*R zSv<_V61w?Xp`RVyG4=0%jHY16GtrJ_qbXX94)i2?Y}TVQ{Rqq8Kj=&|N`$2;hYnB& z{i4wlD`G!%$!4P&SdM-lcoLICC|pxAyf9`U2}zv72XJ($^n};{LjxRCIt(}*P3^eo zM09{@=zR;KOVNNHi9Q|OjH#t6&G~o6pV6RSp|8>((GD-58Mv}cIBo@_MbM5*pu4*& zn)-&A+GMdl41InQdfzNe1&B^yX_;iWu!06t`E<On5q;ogbfCA<)P02B_dm3wW9avR z<CqB(Wy3@=qxD?qeR<F&Erd?2T&&kmQkYIdJ9KyNLNoC_8o+7v*qujTI9bbu`jzM# zurNB4qG({H(fcZ+$F~L=NJq54u4w=L(dUxGDLAvS@xmRLN)?*Y1?aclC(w?!pefys z&S)pv;iqUnU!wP&K;Iju&~G~D(dP=556_iAGLcMFr{Jewi_nnhi^ZvrL?fJ!?ujMn zv3WYy-$DaD5d9j>z|UwP=g{XbpaW;F5bnPc-F(+z>i7SZQw2Vs(Y0=fcGNDmcZ=<P z@FCiVqM7+OnxkSkZbi`<*G2<tjSk!$Qz=LL9gbab9On19y+OgXKZup^ELO&hO6jS8 zdaVoIOnoUjv;WYwy{vMuC>nTObV*vFf%HTJ9fAflF}BY_?_Z2bH`n77JT@Dm@1pHT z(Y5~x?dVc$&s`;SPz)WgQmi*b?{9}be*;#>(dhG!#r7AlFZI`}aQ@3v$X_)ai)QF| zx9;e%8jDqN4*I}0tb)0#g-^3)Sb_Rv^qbHc^i%T)`pT|SJw0(fPC&n;?#1qytwwt4 zFE9?M!TE1a!x|bK_&A!{w3_Lu|EGg%(9JmvU81Sz5<G%#uGQ#FpGCi(Z^d$W1U=`O zYK8W^*q?e`Y=cX&t@kA<ETmAPcKDjT2_5h_x_Qo{9bHx@445BXyCUeo70{)thaIsS z^0AtD6wTDf=ubWu<MoMk!w)iVV*}cg=P9(LP^Vscq95Lg?eHMFmPPA_FD5n7nU6uw z^F;K!-V$`FHsMJ85Z!!r8iXZjgJx<v`X;;w-3#-OO_@wQN}(wY&!98<AzVoOi9VR# zFdUz((Y)w=#n4Ptjy6DFJZ;f|I-#4h2fF(Q$LnL!%-)LG{J5J&!E<>ZI>SZrhKJD( zSEB>1Lua-H&A_{8hQ2`u_!I3Xy-|3<WJ5Dk1U>)turanoGdv43JpUh1xEoL5GdR9+ zn0dh_VKWuOF|@ZsGx9Pz&<->c@1g;I8m}KiXLtgA)BT19kf~{y;FV}U1u$vkMJc$+ zDxeQEL}%Uw%}7tQ!vSbV!(;mdG>|*d`|m<KzAx4n#`@A&Ux6;o6X<wrn{xhbc!dT# z-VtwjAMI#gtRIN=Bj|wNp!ffX4tx&n=N~MMmv9A^ZWg|LzJ=cR4f^~EbYj0YONN>K z6)&VU4;Qkc4_u9@RG|YDMKe|^)~lf(R&}rs_C?qHMJ$7R(Nl5;eZS;x5x&Y*#){Ot zCn@x!FdfU{A#`&jT84An9({#QL*IlOu@ZiT4KRDF5NI28i8`V)ybj&0H=vmsi+(4Z zjBegVu|2tgf@{7NU6T*cFAQIx9UVhoFelMB<0Z7?f~~{uFNd}_Ml;qMeXc*cDTm;V zcng}jPtc4WMea)`zN1iqhEt&-k-tq$HQG@rbY_*%K<l6#w2yW}-<W;S7t7da61{&h z8t_wSKwDz{ZA|_CZ$AY$!<X@f6KKlLqA!q(v7WPSNMS*=qpIkDjnJ8OiP!s~?}Z7` z*=T<&(SV*t1KN%`JpX$v;OA&Z-=PDaj$TAFkh5LfjF{StXv#~Wfs{w@YltpoYxMol z8|{B6X5a+${w0_!OW`RBwedqV<>~Fi4cTxb^}=Y%_eMWOzmgqB@Bamz;UCdNhxEjg z)U%^&zX83TqhkoX02)w{j`93gputG1p&4irZ|H!|un(5P0qAC&h0gR5w4*g>MqWgp ze+3Qr9h`uBVtd0*VVt(;_3Juu{xc{Hpushpj;_%XOueDdz3~dVW^ba$=wmF8C!$w% z4yT|2`URvXdd${gO?(#(>~D0UnY)B>u1->Lpwj3J>Y%A=6x-XPFPOeq1MfsTdLB*v zb~K>3(HR|z*N>qSIfWk2i|D`wx`xb^Ml+YJO2Ggcp<k~%qYsQgkJU_cfMw_#?0Ga( zd(iv8LNoI>I^!$4g*RYnbdNMc1L=i6KO(l@jr7C+{}%;!;|6q~H_$ach(7QOI#AZ` zArmFhz0ex%coe#cr=!oUMPI?MqnSH|74cv6Ra~Y=$V6*Q{rO){3eMmL^ntNxDi@(C zT833{4QAk{=$<%>X70ae&Yt1TSrk3KCD4AVqZ6oyE?tl4K(BlLN5zH-=z!DF-8~O) z#RqW^UfwHQzZqSkiD(8EqD!?Z*0-V=`T(8SX*8fq=+a$zUHEEN5>x;FM?VUteheDv z-S`bYhP^S_J3X-kKS$paBm0DzKY?#je-Zr-c}w5$EqMzzqW&pX#$4Bjj5S7=v<+U5 zH(k&9H<deRaOUr!Df<+S_%OPbKVU1&)Gxdb+M%bUGrFt$qNis#n&L5NMkZrtT!?1k zD0*ssMl*b_ALrkOi!`KRmj0omE6|RvL^tO(=s=awfg7Mp&>9VRV7xvIP4R7LzjM$f zdI0@YU4xl%U35b-7B-<7cqP_%q7m*!XZ9&N@F6r~-=RzPGdf_V0U^+W=%%a?Z5Zu@ zsZEX^%du!?ld~weSsq1a_%=Gw$7rNS&|`HBP3d3gfH`jn1C>AntceCzAAP<B`V&)U zbRwg1G)_eO`3C7fnfQx>5BwJ|Ts|<QzDTq@dcAhE8G1}RVm%xi+n+{fxCss9ZFCQP z5Ze!<f&3Ufi!B&Gae+b`E;PF_ob&szD)m>eKAu3oYGn)xySzWz{scC}!{~0$H#qzz zwFhQUe-X{V{#ZYa&8c5?Q}_zk1B-e7lN7x13G9cj;|we~B<zXhSe^P)coTk({jvVg zFyKR2h5A{17E25ZKMQ_{9jF%^9)8#yg1=IK4j;x9BRK!RP^fuxdg|Z%EIu+l@i+DD zXewVCm7e-b=kK5c<Qg5`4^7aYcKf33Q_+mA#~bkow#Eiy!l&d+^u4hjYvI@E(&Zb= z`8Ty)#)g#5#fsjD{;2dhIzZlWAp<SZlutz0aua&YUc;`q6Psb4@nH}3LNhlAJK_?o zj9;P8=eQ*qZp?p6_=Q0U^i4JlUDIdL-G2go@FKcYl_rD?bU<e|7Q5gYbaS3TKWy^e z8kV3YcBeiA4dfGSkA;)Bh0Qe_2hgwzz2PD{(+;<Xj%Q<O>Icz`oyWCUXJYJ$`w zxFclnYAjE+3Az+FqZ8POCGjYl*<@l;h^#8srC}C2z;>*I=g`0^P7bfqIoOx_=a?O< zP6?@O7;TLnzpm(;u`lMt8)JPe`d+ymc|Mt#Lcs^_#hJJeFT-4ShCPuF%Tlj{)o>tA z$3-{+b52c99L6MmjMq;K?~C%&LtwSgK$@U$*w*MPxd-O*{12nxD{~?`z-+99ThYz+ zJsQx@=sWxj`a=3MUQe45W|$Sr&|UyNJx$R2x}ZyQJ(~K_=<Z*HmwWzqQ!s!}&|Ucr znzB>gfd8NY_?K0j!R2VjdC}*J;gwho3u04rhJDfgMx!6!6Vc;$#mumDjWPA#|Fx%J z2VKzz2BIC@jHYfXx@LF9>-WX>#pu#KjD9ApitVpNUq>hME;@lv(M%kQ?LW=r{5zAs zX>c=TniT@ch1QFr9aM<cLo?7O+7rER5ITV|=me&sOLZ@r!MW%}7NgHUj0UoHR!q@W z8a!@qV=26VK3L+eaLy}W4eFh72+qXP_&xglKHJ^lR5U>YSdLwA6{h2FXaHx?e*Z-? znx4ETJa9RhqTFak3Sb(Ri1kwOdR260wWIaX0UM)B(H6^KH*|nW@%l9MMK&9K{&94Z zCRbDN#+T3tx1yWs4fIX-F&gnN=m3A9slJG2Am_c|6<ZTMHN&tOF2Tb18TzUB8(xDo zW{1!J&RE^^KZHUdE<A+Z@B)^_53n4bK|8+ozHnbV^uC+08&1b!_z@cLujn_U9CJcH zC6R#=9i!9H7uyS1-t&KgLPZ*`nj0=O!fMoSLyyZ-cpV-_1FAYNoZr6a^~LCE*%dvE zF3Hd6srVD!blK;J%~}x6OeswL_rJ|4nDP#2s{5mBGX&lJx1k-(iuHwP#vVoY$}8y7 zy^TJ%8?VJf=$fC4=D0s(suX&?6{i0Ge+E(T#c>C^wu{gQA4iYLE0}@1(JzlbqBFRF z_u@4Rf={A>mRT4As)+{F0Npzs&<Xa8_5KSv|ITnI4L*2lydjCE^uAbMfqvmwji&TH zwBsXaKtG{tei6+`zC~e^W#Dbp>)<6^k3P5lf$%4wuRg%}_XSdGafqxLT5pHWyjQFb zM>BIP8o;c0eHr>W{|wH>_t6ih?n}bw{>S(r^=p=fjJ$wO_!V@*?<Of2@qY9La}*6A z*Ms2&axMCGc@(;-W}+V+^RO!JL|;H>(Nj_Op%73D{E7NtJb|5-g+B+VxjeWYJuS)N z52q*IpwJY3V_ihw2b~`YGwy)~I5;{6&CDb;(7CbwAvCp5qJh4M&h*uIeK)%HpP|ov zf$WK7;v@xA@f$kO1@tsru_6Re2<@;Odc8)pakL$}xq71a4L}1Nj_&fw=ztGKpG5oF zfLD0_x26h-#9L^@d(hMHKlH}m&{y;MXxhrK=`KgFUmGnGt&V1*5jt=ubV7a6Ku4ml z_FIwt&sQM|zLO`Rkxxa>^8&1b529<l6EpBHwBv%0hW9`zwB7{GWC!%QK3EQCqZ4=m zo#4x{z7tb_|7Q;cXYx53;Wy|W_zCUsG`e>Gp@C(7EL_iy27DFzd<k@*%F&w9`e=Yn z(PP~a?SJ57%-;cq(BRtLf*!Lw(GKUv`h)0wYhwG0Xh*N1yZ$3IkRQ?1pT`!M{qb<B zy5LIcv(O0?c_IW_>Iu%jkyMBcRnbUmqa8Mn^`2-3Zba8|1lrMLY=cSkxn1Z)K1J_8 zicaMFc>Q#&pO0oqJ{e|~J6aU&xFWhqYM?2tg?7{++8Q088!pDa=-U2-KL0m*|0VPd znQc|LUKGbuuY?Age3Zgm3QyymSZ#H9;5l^QH__C;htBX*G-F?(p8?;Yuh_(z@I&V9 zSdHoqG{9f5B>sVAvCvcD2b1Q=3n-Zw9UJC`hQwy9%#HieSL-Egg+<qf%{c^HQXhj= z@kR9huW<@q`E;1s95fS4qK}|^>q$(VhEzM}@8x)52RhTe=q5UZzUzNLU%?m951Bmc z!se@hrnoVhnRe*&z0lMSMl&=Ty>AZM?^5iGYp|N<|33;hV&!Mj6Gw3Y?!Zycrl<a8 zw6g2NhsvX9My`1-q_RF%r#={6`=#j2R-sF@4h?KWtZzdDcs;rgQ~&<gmlRy9pV0@- zp%EuGgx#JUXHYGSci~F(8&T2c(-TYacJu{y#m11a9B2T=(al!|eXle?m!Ktjih6A1 z{QFI22o1imrlSvTK-X>)+QBw7@(<BdaTJ~DSLprUM}Lg%zoJWV4!u9^g;39gPV6eQ z|7%}JhC&G%T<h{^hfU%QEn~d{I)koghWf_(P&AOS=*Q`8SOFJfMcjcI_yhW)%KBp1 zw56iGk`&y%_n^n-CG^4XVtcMl;SJUptI~c8cEu;L1OA3XvEfVUssBsXC$T&AOXz0p zzBw%2&FBPAqW%Aeeve3&+Y;7(Ft(>*B>LTNGmgZ)=x(k3a(L4%#KzPQVmr+9N;sYa zun+ZB*Z}`Q2dK3*I2M~xe;Rw^Nu=LoqRF=Ki-qObnhVFV4OZM9{wU>E>_L4OK8%H4 z4FkS}z6bt_HheAoppnE<w7-o5@dVbv);q#pn1(Ld3@qX2|2-7k{p-+O`2u>J-a>cl zN9dmT5`BYxi{78@^^nr5(M?)5+A!J`d(u7xXW>??h4tSEzcU(#wLJe%#fHP^cfee4 zh95>-V14Q{uqJLpJNOyBulQTx{P)7z)MsPr)r-Eceu-v!J1l7-w7ojI7usU#@Ba^= z;AWW+orBKk2`q@4(FZ?7AN&^mYV{ZTT%LEr{T0ybO=7(#`Y}BsdMDb?0`$H$?{NO@ zXd4X<cp%>R1KRQVSigE_c%U?TUxR2D^jO`54m2I@_yKgFwb9qm=k}xb9gp?DcP7IF zIo=HxkJdp?LC5G2^ueiUU<=WK)}jHtihf@>hz@)b9q<BrU+(w9SG6)|y%~D{bx8_t zx)EqclhKSUMF)HV?dYA@{yDlNXVB-e?+P6jM&FRt(KlOjbd$D2H*+`ijW`hfa2kz1 zpPWd+H`;78vL)!dd>z`+bLcDcrReKu$Gg!}@d<j|4#w;Mq61y_e(-Aa%~=fnN>&bi zQ;x=Bp8vTN?C@E%!%b)kUqMs-A$nfFLuc|M8rWax{TJi)OuIurS);kpfeXcY3H1I7 z=<`)mb<STM3a)iSbfBJSK-Z(07>qtJ3=Lomx^{P>pYQiapGBYBg{Jr;9Ds+=jMUx} zCe#A0UyoTm|HEU$E$C8AM+cni4fp^$lNIO;)}VnrgQPI=3L5C==n@`5?>mj|iF4>X zKl2A6z-s9AdYCLup)mz-yb-OB$1=DW-Gtk4Cho;TY5YX9Hv}~N!}P=`+Q*}t=?Heg zQ)u7~_Jvn&EA&;|220^uH1H4hasKO3_=yG|DEU#iP#H^7?~Fb$0sG@Jya~^s8MyA_ zaQ_f2LH%x=i%(-GtoBKGlTJrJTehQ_yo4^{75h2=c681D@D;2adc5YK@BUR-7GI3* zhp;sD-=hUS4c}%PqnmaFdW@%|8GIPsBX6Q#aE_uM-`PJ4OVU3{!H>=R(9LrUJ#Ht_ z44gp&$$ua$QE7Cb+UQz$L{mQqozVnz58aJ^S6qay{YLbg))90<=c38N2g87^(3y3` z&Nvav<4zopzhF1K;q&lo_l@Y<XZ$bBXg-di{smr-?GA-NR%1Wv8_`pi^>BEh6-OqP zOw<mAL@RXWJ<&`IM3-hbI>Xze_oAD08M=wK#rh$1hX10e&U+-ha9W~kJ{z0kBJ}v} zPhIEyeMMmk4aL6*H?Bkjc?x~?zJNZkGx`bI;g_*~0)20sMGi;eAKZoK(Kp>YN5dDG zukjY@HNOnso}a>789(ta1$Y10ufmKcVFvYku?IdK>;Ir@dd;!WaeXwvKGD&*k9rbo zVdt;I65NG<P+y2H?LFUwWBMs3O<D18!<(rgx`}$AGaQP(h{ne2x1&olKejJLH{ptS z{RMQbccDvE{JU^}OY{_UL^tQn(c8b{{F}O&G?;<e=y`tteIdP!<?uc9Mf58=VA}WL zdVch{l|er%nxm(sFS^-Apqn^}2J|eNvAt;j$G%U7<9C{d>NK=Ho}O5SQ_zmDIuRnT zh#sSM*dA|3GxbJn{{$ye{}0>YttZ22c@6KTp5uq`W%U7ULj3@msXWOa!;4}Zx(Oe` zhM4Q8@GZC_nwcf&j2=ZZum#P?p6F3*N&PgMiJGUvUg?0I_mMam7o+`U`#DS?nU_Ka z4Q0?7w?&WJP3RuD4PCowvHcM=b?dPMzKZVh%YF%ar6jsXDxevvfd<qHO?`hf@bSoA zNG9&0;3iv$uH8eJflr|Wy@v*LFxF4tFzSC|PaN=T*fTF;9q&T}&v7~om=7CKFONPq z9G}1sG4=cZF~5Zym!T1_M`yePeUThSGjql7;niCb4Xi%8C)%SEn25d+r^Wh7^gZ$` zdTjqePg}t=A>bOA`ujh9D0t&QwBwOzN~d5MT#lyf4K%R*vHoi`?QB^4yy#l@#R@nR z{S0|7wttMJssDv;(jw<L|H~;1r{Ig>B38mqf5ZTAB=zO!nx_33BF~BjSOs0%PUzYW zK_@T?z5hORvn`7CN6?9^LYH*QpPc{H8q;9v5278NM0ff5SikD8@L(x)kJLp6XoH!t z3;KLdbiiTp`gnA}N$7y{(4|_5-naTM&c8F+K!Y8BfOdQsJK;Cz09F1De}q~Sr%~U9 zyRhXy>8YP;v;7<D9dQHgSDz2R6?+p$P_Ox4_;bUR(MxFikmQB%;j$Oqy@#+i=DHZ( ze66uD^>J7YH{ekG63twTOCe)DqQj$iqTdr1q7!@yE8{!p8}>K!=M4V*CsQir)zOr< zMt6HZG-VUx_1RdC`ikgIbT|Kue)Y<dmMQg$Ess9m5xqV<)@R20N;L47k@1p=_b8b9 zBj{TF82vArD?JQQ0*$;iX5c6^;Q6urNvuWvJ@l0Piw064Q|Pw_nu*rYA()@>6SF9I zOddu*opwZbqo?5jx+&8#hm7PyH(MEW_t!%M?}`q56Z&D3jP0w?<Glr4;y2OF_a|QE z=YQg|Oo?>JjlNLwVhwDD-gq0jYp0{1miNT=dFY$&L3FJj!<@Jo4d`w3Gvfd@#h=mV zD`g28tbxgnH1wq48a{!e@Et6Vl`ju#-UnMzpNXyUJ?xIzugH}847dT^q|aamp1}5a zdDcv+FEHKl73xpn8`wWv$mBKIGlk#(SIiz}SPwmZO)(AIVkT^lW}<Vf_d#dUA6<&U zXohY>m*mdqV)VXeFb8f#GxQp|Bzv+aL#htY;BG&OKJa(E;UYS4)*Ru!Jm~c@=>3(@ zJ<}NNxIMZgeWHWV-98cxbPD?Xd~{DOPEv5~)}jx-hW-HZE}Dri(SeSm1O171ke)LP zcttcn+F>b7ZA!G?uINmMVP?Dq4Rj*9H<EW#aDbKQfE&=`xCMP+C)(j|^uc53OnyO+ z-z6M~d9Tcr`Z?h?w7>7r%$-9gb`ib*@?0UX!brc#L=6g^xzHYsbUE6=YP5sRXkf3S zGkgyX>@a%&SLjTCL<75oP9XPHp`Q$NZ&Z)gi#AQk`D;VL2s_6Mz0rYhh>nO(K<}H1 z26PV^$o=RVFGiPURcv1u-4NS1p-Z?G&E!tZ?fKtN!I^!BuKi!=ZoMjZXfJ}!s5<&! zGc=GcSP%Q)oA>}Wz;0KE3Cxc^gl6gqEQ9M~`+iLQ_kUkda5MaframoCn90@Xi>M%) z!j5QQJ<$7ZL<6}6U4kjGeG!_GC!;T-nRzQ---Y(`zdW3OZ~Q)9IEQB9vb<p}3!$m5 zhz?W}4WtqJTuby*tS6e8@#q(t>F9v@@`V@Mwdj3K&`sD6-7DksasFMCSv2^-0<@#0 zSP55Q75oSt@B$i0&io+*`O%Kbq8Y4@rn);C=m50eA+bIZQ^yd^z{F&{;VyK*Iq0kS zWo(3puoUJi5I(&cU?=K*u{5s5ZnziyxuI~uOo_o>$Hn+6w#80`!iU_0=)l`B^&#~h zh4M6<#B!MXn((pN09}gf(3Fjg&OkG<6#bA{gKo}O;`R5?j2uBX+t28Id9DphPzJr; z0-0zs(Tjp9ofMskF3DW<7(RqP@C3RSHlYD*N1xjhuYZcB{CjjWo<i?SD;$<8H@Y+> z&<s~b{{1VC3x#wVdc+&9LkAp$?uA>?V>uHI=n*u)HE1edi1i)l=l^bW#>deN{*CsR zqeuv(C>mf@Or8JM6r5QfG?h1^1CNXC)6nB~4;sir=*%~w_iaT7dJhfoFjm0t(C4l! z8UiSW-d`R4X4Dju%_#Jv;4WW@cJKi@vjfp@&;fo$2Tm`RDfMSU*|7)pp_qEJq0jHc z4BUq;@K<z#)iW}szCG7RPsJ-4oPQ(SL4zsVhYtKTnzCQeh%ce{<t!coD2lFaS#)#O zMFZ@FW^fQX;CS@hPm0%<#`-$6-<`#i;lcehq}B{QpMRqRUWi^<B5bZ==)h&r4(h~u zD|B=9Lcg%wh<@1|f~ofl8qflC<`1DuxiU$?$hSmyqcb=fJ%xUa{uk{iZ^>{y15Z$| ziawveRJgAKnz>fd-sr?`j`gY01<~Xa6rAZMbnV_jXZRu7@lmvc-_TTMDjnL3MQftR zu5Gjn`uuhA`Y<$8Q_ykli`O3x^<?6i*svWPXivD1I2zl3L1%OU-F&&qgpLZLYhNDC zSQB&tozXqiCpr{;ZUTBd??eM!j@3Q?>nJ$zVXT8c<18#$Hq3Y}R;T_pPQ<hLFpex2 zW}aR?tbJBA6M4}AuSM6m6uK80qXG0sKPx6<AwT~gpkQj(+km^!2fs$o=|8bOZ-p?^ zD(KQQM(^v6ZoW}y#}m<h7N8kghh}I8x&(WpM=|x^|NIhfxP-3Nl@-H-h0%ekM_Z$r zx*kpS7<7O;&;jP78CZd4U=<$6_2~T%R0{X4h(241^X~)OXz)wsn`i)^#~Z#!Q+F2q zw8~vMoPwI@H=U+f7VpGjxEjsCJ6H~nU<PKY5<dM(McbhPj;X@=_lAiy7|62dV`!?L zLeJ~VXsTaBXM6w+^hY#9f1xwXUNvm4d}u~Wqwo4!vAqL&U%yx%nxtTdx1(z~H`X7- zk<_2XYM7^5rqu5RTA}ydi3WBr8u)zl1+xU*-7C;jvmTwu4m30S(D9CA1}6Wd;Dgsz z50RBbJFJYRuomve8}M$dS|d~H?}BW`OVn%B45y+-t*|7|paFb`z6sBwf&PVV<_oc2 zuy!h-WTGeqQ&k6zv^DxbZ!CiYuom8puGuzpfVZRj(Ixl>?dK2l{AaEc%#B_ziY{3V zbev{*rRTpp1v?&ure-8&;0!baPoOE^jc&5f&^0_8+b^I4Tv0b1<HBgY9(sSLSRaG- zGZVYwd`$iOA74-yOT!s-w-2fp2A+XEsjou^JRiNRewbM<G~mMMv8*2Jt*{>T>(TeX z5_A)8z>4?|nyFtg_4ofSP%s188iWq>pf{F7Z|sGsPcs}xeHPmBZ|EB_Tf-2*O!Sm2 z#VWV~4e$%>hri+P*s)Qj#BOZdnDg(q+$>GPtFa}zMuX59jY9*Q72D^byZT{lkL%IR zdM<h%%~X2R@IJ|b)=T2eSQ(wrGW0a8ZJG?Jd7TC${|wz6KchEZKnKY2e=Xg2z|GYk z!14QVWu!uq6dq-7GO{9M6``WCMJannaVsk!$%=$ZA*+aoN}^;{Mt(G;(vnh1Lq&e? z_dVyY*E!$&{hskTpL4$Vc@mAnnqG<~Um0}Q)J6x`5WTMjI^$c=<n4u}a0)u`SJCI* zK_|K=MZs+U1n<Nzup!pDA$$7IevCpRv<{ugujm()f6#%RN1xBvIGk{W(4Pb9VkI1b zcDw{lz76O}yA`j&)W;Nj`JBZvShz{}pb<L4Ug(U5;2NBSnHkKyX^7k%H-@8m0QThb zCviHS#x^*vS@;fk0J~AYta<o>WOy)@*i2yxALM8eUcWQ&E9yHj6JKtbJ+Tk>pfgy| zD$IN-nv@&S0UknsQu-0ycKL3~p8gY4Rk1qt?&$aanP~EENSoqMFi<c8C(s5jxH;Td z65Yqm(Ol?+uJQe7WCo*4k&2E-mtt~sI(q+XbO{!q_pgqhufz23|29!@0K2gceuvH| zvvp{oCfZ?rG;3R-$=VZb_(AmfX=t)7N7r~SX5x3~eL35N$X$VDsh7v}pZ~d)f*th1 zDmVgt;3YKMH)1C4L__=o8kvi438B3j%Td1_31}jPuJw6bi{09WkQZndB2*DGxL&;- z``<OK!3AFy4WmuaZ@bOW5Z;Pr|6S;I>xG^V{p0nA(It8u4e>nm`Gx32UXH$rPUyq< z`O$W%uuo6K3;ElJBrA$`To&E0RnQ34MjN~_);mUfqf0Op9l&(-xmjq33($zIjJ}Pw zb1+50nS6(??cZn;=D#(Byb78NZP6L^M&E9Oqhry5O+h0xFZu%dqt_~QTmOocu<&ic zW@rwjhEcHLY3PjSVF_G}FX1+<hxgqcX7nOD@>S?_ThIaRiGCbE{}vtiU+B#9b_ma9 zqDxpE89*vgkAfq=4Gmq_c*EUj2>YQqG7Rl76|YZ0JDwRoUyQc10zDbmqmg+J9mqk< z#2?UeAWugRFw(UW1(%=+I<pRFM}5#W9fmgeBs!qy&>1X8zt69Y*Y~0WIE?=HzOT@T zChiEY@to)qbi(U#GLrvnD+)IJe)J$ZkR#rJKcfx(7X2H|_QaiGAeW#MD2yIJ70?-0 z!%lb`8o^i4h`bTqh3WVI;dsM0Xam1Q|3KINUo_OU?+OEHiiY$itcu;SIL<&jcomJr z7W5^v3!UIebfABr5zN(z`MW*xcM2gcffcD&M<3{hHh3>O<KbvW<IyBtg67P7=zV+8 zNPU8~`z6}puhHzC!{>$20Tk`b{<q=M@j^}Xf$L+v9lDlx;S3ywewDhgOSrED+F^}Y zuZM2qHs}d=4`#zYXfE|dBRL7(6|++D!ZLIQ>(K$cgC^mj`1vt334g)PnCO~4F$ub0 zHT)Kx$mQL_0866-tB<zR1pWLLwEeDVgi?bkRHE<*I)F9k$Tp)dk^N}$97mJ!G}`cA z=o<fr*I};iA*45;Gi-%E-w|D+0ca$KqB%AK8AvMe5Cumz9S!Y5bX&cKhH`)O2Q&g1 zJ;Kie1+XOb=IGCY{m`6Pie~>VbYMTB6D-v;d*W`q6>DM^_HqB8q~Lz+aChi%HkPNp z3U9-Y(FQB^3fbHioxw1C6-T4@SL_`^+Yw7qzaLBEljsDq(4T<bLzDO`ypsMC8TW)F zD;lkjcGxM_$D%WQ7Jcwzw4pQTz%RWwM6Nyhc^`BMAB)!)py$b2tc~xYXa8ADm8Ec5 zpU~m;Xh?hDJvb3fu9N6e6u&QgMXQZ|DII_taRnNQUiXKeYzp-aIdBg;prL3k%tRyd za&&*+?5XsHGh8q$i}wp>baixux1tA4KXku7f^NshF%y@gOSBuCV)6dr+~|dV-Ve?G zX=umu(8#`x9!y{NPlcq)IUr<zVRXc$(T<y;1L+hUh7M#}bPl@Ki_q<~9esWO51r6y zbnPz~7@oTf&7ESgUNS}D0xncSv%3a5(i_o+`e8YIJbwNfx<uR2ft-k*#w7K#(TqW% zy$i4h*Dpu!AB8jVQS6ARLW9Fv4M0155DoD>^ns0dJ8nhy_2ol?CDHq;p~=-2opI0T z@aSXFXVCLvHKyA|&YM(XD+NQn7c1a5=sO_a&@iJ0=o&UgJ8FX-RNXNH2cQERgdS95 zV*N4n{@G~qE=8AO3;O(rn9u!xgn~a1oJ4QTIV=pQIC^H+Ko6$2=;!yu&&S5kXQGi< zgXxCRY(Ii_cp7~!+whQlMbJnzz>DZV(VT+&`F3>Q4nk)#9*xX&GzpiWA>ND*Xdjw0 z-$nmIJIXa8bexF}s0teL257s@(01Bk%H-=s;SubM{s3|k?Xb+qaMU(Jcg1k@`@rm2 z-yc1NMj-zKVF|0EN!uCS9TV|dT!~KfOElO1eSrP%h_4tG9;}9T)CJwAW6%c|qXRmK zHSi=}hgXjd_jkfF)E`7Ud;y!_F7&>O9t?kQp&8yxeJVQ9Pab6dTe$S0FtgU^fF`3a zq35s?zJ=BCC(Oj+V?w<V+QCrtKv{_<?>;Pn=db}59~(~0E|^Jue)NqL1=r*Vy4K&L zYjqYKNDc;=9gCv-+y7wUn(_~aqz{rB=n~e&k$3~T8#cwy-;2JFK6e1koiEXdrv9Yh zh%b3K%(y<f4evx7o`9ZMQ_-(vPoV>wk7oH=beru$52nx1wdIf1q(3i)c32bLWjDp^ zy^$p3{ZGLxo{sMG#pp;^q8+`Cc5oopzd?`MvuMM49}S;hjb5*Tw$n6TZ;NJoPqe+^ z@%l7OfB#<;Z&)8c*olVbQ#6#P(FYUb!u7)F{;h@%pdK2bc4)*pqLJwuKOc_nnkm>G zcc8gdWIW00{;y5JgQg2Q(otv*OhwmxHX4EXXooAK+tB+zMwjMC^uE*R!INV`h-5*u zel^;0HO#~|nEv}e22$|g8ICXGWVGWN6GH^*paW`#4&at}y*E1JA!x`)#rgy^LQ~P_ z=AcWn2yJ%_8nM?Vvj1J{*STN=JJFCIM0dqk=!||sANUV#C^;#FxFBXyuYgtXW;7xX zVLGSKfh<PbeHo2Z7TVvINo2nV#~v=&@M*Mx?2m<x3!xz^8@(~w6Wy*UtbnsH{lx;^ z1z)2P%{4jX&Q)kTHP92V9lGTGQt`rL=n?t?dgC@U)L)<t{SnRmc$j%nw4oa4Nq0-U zJ`>wge;Iq?zgQZ(P6-2^fJSP5G_{+;^<4M|J;CZs4L5edX4HqE1KNZ(bO_DvbFp4< zTDV>hTXMZ8dPJ{8Pu8z66R&(CJXasfQNI=0RjI@n3a-s;^x$|NtKr+>hQx1ZNb^h& z_f<iYs($oFbgkQ<OV|y~oq=f9k4D#gGS<f#vHl^Z|NhTI6wJzFXv5#f8-7Kz`wW_V z=h0-%@nrl@GHAn1F#~T#+i8Qgb1Rx7ozW#6j4tT}G^wA#^xyxpDqdLc1wPmj-HS%% zFgmku&<1~xpXZ(tW||+(=Bv;Fl#TUD=)mis18;~facgu52V;8wKSse5?+I**OVN&h zLPPjB+HtO@!Wmu^P1f4c4ruldN0;zv^!W|ZchHFJLwDOJ=!u#!ll|X@!WA>a4;+1P zIrY6b2}jM!p8g9+GiGN`JWBl)G`p{z6B-;Jordo7Iq2JRF&fDw=n}4spRbGc&Cz$~ zu>YUthCN&`M7`#Q&<sHvn2e5m2HL@VbmU8-Z=xYSh}rN{w8PKQr2HoO2O7Z(o({X^ zO7y<QDGGkj678TXx|V%#Fb+dQ`5k&NosOShFfXiq0rdW&(Q@cSYDSx&18Ij&s3+Rb z{b+lsVX-g?&C2;`wyuozx6ua<pbZ~Elkr5n{tucX$@yVGm!cCYhUUn%=yUDS`?{kM z8;ImwDlwdbA$|hAaW2~7i|7c~pxb5}I)jhV8GVU9cPd{02hIL$&xGxm6J3(r(Y(=1 zq6O0O{=F<-D2#o1;7YWiN$5<cqTgH=pl9|5G~@@+gXSnYupiKwokE}g3!U-V=!FZy z=S9#7Wa4GM|Ep0j<jtd<(Cs)7-KUSC16dS5UxN<d9W+9F(NG^lw_nDy;rZfdN7tdx zw~X~W(ShHODMvn>f+HV;C2<^@bjzaa(QMs@cDxH6;QyjOqf3`_VVLn{Xv9jQ6Sy9I zhun_l#t?MrCM}Hb|0m;xh3J5mqM=)ZM&>Ov2M(YeA4eO`SQM6|Fxp`abY^YPcJ4%T zsYkSLba*tiC>3s)952j7cfqr0gKN;x?LzncCuj$!Fuk^D2Ny05OK=(b156F{M7#~n znUU!0dS<MzMkla4MZpffLPLBC4gDE(ra7JqHx@%fUlYCm26O=J&?W00>l4s3einAc zjd(L&{(Kl<FKk4896IpSyA)je4{;41MAvBi3t>R>&;cz**K8HKBpYIVH#(4y&<>Bq z>o+V3_qD=Iu6IQzkV2Pc3X;63#7qiy_!63}Z=g56AN?5Z@EdfXXV4}1FV=Iv7zTO? zx^#umftE$vt%gRV85+6!(RM~-`rrR}n1Z30gbrW^`rz~EKF*5Q-$b|92k6rLh-P*2 zrH~sXumtrw=vsF|2R;HF*yGU!Xg{m*D);{u3Kj7PnmoCeh6l=_p|6MKumzUFA?SX8 z8XZU$y8ZT{_a8+&_z|7y+4y<3Wnn=1&?P8|DMM9}f=6XdG!oaLA#NOPjlHPffqii^ zx;x4(4-smDcH9EZh1<~%dZF#~Lz8<XI?%D`cAmPN{cmWV=YkKshKBCVc*9|IrYG?p z%=>cq9qv%Pi~3=7iK?#%9n?mb?s_zmx1#M2MVDeitj|OHS+OD&z7D?^Kll?JNUoJ3 ziSnWQ{t9#-S3^hM8r|P_qx*Oww!>%R=f7YN>N!@0j_yU<c@ziZd^8eyQ>(+aDT0P@ z6uKl6(KVcohH!Dbz5;#lHFOEKq4ym@?>mXMa|X*`jx`~-Dxvq?g$|@Irr-bLD7a>G z;temN5!eu~zl9Fy12i`d#rl_MXn%<QizeemuY^C&UmCrC7`jWwq62>hy>B^^)TzWa z3hvLJ!i7Y>SHp<wVhyg}i>}oI?2lRK3`?yI+p#*@a9ebSUD1IJL?`wLy6>Mv`&o=G z-Md(c{uAF*FeI0)3%_itgdV9q(1s_XYd#CzelMdP?86FpEPC;4;iRjJ4!9HA;Rs}= ziTUV~yo;VAKVdQVf1dT>LOC>4&9OB0iuEa2mijWRh5O_6TpL32l|pl&K031wXe36V z19=>);*01&4xtlHWU>G4s4xXPZitSoGxovJ==S>>eK6a`a9>5NNxdc7PztNyTr_e! zFcW`@*Du->ego0~ZEqABiKjQQ|2;C_=7QVn7`ku&L$4QmJ<PaKbR;^E)tHGNqci;* z-S>Ik2>+R`IF6(KDw@1C-waE3J(?43F$253$^Lf+J-Fank3tWWN%6+1vHlF2M2lnn z6?D6;M^Co5(WKmg9yABhc8=pMcoIE|8*C0s*#zycUy6eJa5Q?5OhZSu1a0^w^ublJ zz79>k*YRO|Kh|5n6@C%f4ZZ(qboVSo+xZCH)}Ka?#p|gP6nx#DLPvBCoymn;!u7)F zj7p-PUx$Xe89LBTXo$ODW4s6J<8pLD-=X)Pixzl0M7#_#pj4tE1#f5`?TpTFaC97+ zoU_pxtVL(^Iy#`Om>c(Eb^HWP;=Ef!Zj?vwuZKpaG1^WGO#l6VZ7H~xccL@z73+i1 z$UKB@ugB1ao=0cA9L<Tf=zzDy`av|wzCn}oG<xDCw}tzPqU}_{^uPaIi-I$#k3QH8 zo8j%)5*J_({0`e;i+95BeCA^>>POM%n!FnZ+8#Xz`k|4Xj()xbv*S8+0$G@T|G!P4 zA{Ta{A^H=Y*;#a?dAA2IMQ2(B&F+fm5>!LCZ$q@<PH5zMq0bLO+Z~DCKPJ|vY-j(Q zBr~|+!LST%U<bN}`*0cl9IwxPFAQKYx>Re?-LnN9@PX(t^vM1#nrlZ$#$xDF*2EHc z%Z^kyA_sH9q?n3^Y8JXAFQ7A6g^v6+bY|PofqsZ~d>Gvg-=iV^0qy7{I?$XuL&OTA zpI?FYS2RVz(3FZdR6rl7iY8A3w8J*&jP62{br3qh2cr|P8ujTo8@FO6cH9*v^gwhH zHs|^rOuzq+QdrA{Q)sd**&RZ>2_48Dbge%|2k<$%RHxAa7T6R1AJA*iNDV-9VK}Cj zHo6SGe+$~qzHmL2_%7aX4h?C+_k%^z$dpExq$1jIJv1U6<Mq4Iq#P3K<IyFVi7vql zXos88_CJcBA4y;5{reLIN0#k_(9osmiB}4pL7iA{i_W|k+R!*OiKe3Okk#nG-a{jC z09~R_ur7X$4y4$Jp`RL<{_p?IDA-|7G|5Jw`*%Fn#--?6@e6c7=g}D#+8dInY_uxc z@pb3`8%A41+ePm}lkaX!Il{j2gW+hyW3eJWi6+%%^nqW{0se(1VUB%ahWVmJF#WDT zLw_BbQ|-}Qx)<$l82bF!ee8cjGMNjm*`j#E8Z<jMp`X8xHhc^nz@K;rCijQ`{@(@d zXf57=JJ3kwJ`i#!6Fq`Uqf6KjufeYV=ddOe9_2!1d=E{!KhO~V8%=%`Mtl((;=<A5 z=*&u^1HBd<U`upD9np5~jn@aE&yPhXG$BR7na)GMtF4Ugz|z!@p(D?IFg$QII@4Nc zh;PD7?2R@&5e@M)^q`rGmGBv~pIzvHjzm-6QZV~}#=UqR-S2z<7b0;Gec)5Hfv?e- z{fX=Gf<xh`eiPjdpP~aii$)^<;c$O(G`Ff?S-b&Rid5qM_`zf}0?))7Heea*U&QM< zKMoCCjc&6V=vp>Hld~IU;JxU~??cax{;~cLI)I1K2|k56{r*2UURZ>#<r4Ip%&TZ* zen&%_<C74Pyx5R>0UVC)(FS*-_kVyU*HLuovV9r`dL<g6y6AT9jF-}X;vou|_#}41 zSJ4hH`YeRLAlgt-bO~yq9koOUd{^{d^toYZgdRkfZW4O`lW057p-cEWrg~A>O~C`F z%8{@H?W6s%9M>O1A6$!`bbGKVevS38?C0U<fnI1w^U;HA1^OEQ8f_=zX!wb#0=je^ zkFx(WDU9HPXZu|I8rR`S>tBQiF8MNqt{xitF6ei{XVG2oI+{BN<Mm%+J?~ec-7@I? zO>i-GNAJ%##{PFCR~-xATI-=p@BrR`2hk)f^mX`peLXspk=P8MLzC|~dZPV`nfNcd z6jyx{zPeq5)+eA5nu^~4Y>I+wxC~3<dTfA4a6A_IHhcQ-YFUH>s2|5yu;X_j8FPIf zvixE+H;STJUKKq78^_P@M3c1-I^d&d4y3-L;DdjnYn=Od@M`pWJ@jO2gYMg2SQDqA zN%jtA;9m5g*^i!}=h2zw_#s#b9atGODeEBHGnHse!Goe*v>V!Sf6T;((T1MGY`7L3 z=z6rl53x6Xi9N8{iSV=EGIXXDe++*-uLe4iZfInNV}AGlR0@V-A)4K*(GK5>9*&<M z$GTiUgMIPZpTf&$5t_Weqe+(UWEfy2G*Zpbfj)%J{0TG{=3=J%e__0^1>G+1p%M88 zO_JZx0iMHJc+t<{w_#0j3iTD}uBiP>ct?!HQPiiPxs~JB?CF2vy#Ts2gU|?$!1SO0 znNGn_%|W-tLiBC82|YrO$It(Y_4DXjUwkUeygnMzJJ6gMh~~tDXe7s=6MF(ZnpdJr z`N}EwzcXFO1w*nG9mq~JWc$#N9*gz!Sdx1F-@;F~wa~X+Uvy@}F^LbN5qlVI_sQto z=)&lWzp?*ala*ZXf%RxZ+tK&)9&`!5KnHXJ9q?In#(7SM`%0h#uZiB*0NpLOprL*M zZD$60-vYFsB`FFwQ+PRk@K^lcJlar>-@^l!qXR6ChPVnk(|Tw}jnGKkhYoNk`Wk)& z9l#uPLTh6EooMO^1snbYOJI&aLJpKc>y6Qw_Cgzc5Zy*kq62&h?O-Fid-kKx{SZID z@Xyd*QEbBX>u@?ggd{D0|I1$?*=|O+*MqUX0euaBixsi#nb6VgXi^QpQkcT(_#)20 zkI@e9|2up7?}GdXdr=?%Pk2}SfVP+YUkAqit4hJQ-%aRD2VgUtfX(rJyb%kY4G-Rh zuH_{3{-@9xFGrJY54wvEpxJ&hUO$CK`b;#}IqL5J!W3MyvY7sEhc<K*nw;&?jyj<; z9}*phHaIKRm&E$|=yo*O{)gtw=jb`{16IOv|FQq;Q0Pd(8)o1Ld=_2Xg6G3PO5-)u zE1_@8cIb&W2u-S~=#jlR*4LpO?}+ui=(hbD-Ojm4U2~{ZBAH6hxE>dZbD?egU=Vun zOhjis8y(O}G}+!lJ3Nd=?gW~AXV3xV%Lw<EjMhS*Yk@|%2f9QfGE$+V8C)=wi_u8D zf*zf3#_PM#0epfk!H?0i=ogTSvL(|IDT5BY33|Of`dmLW0%Ot0y?~yuTT&D}8h?)F z%^qe}9_^?BI-oY_Oz%P)?1M&NG@2vR;`KS`OqZbp*&46!L+?Kp{R3xGPvuG`(|?3| z0p7%gQ|N#i<Orefgzk<ZXh*Z73(*5-DLTMc(QMz0o@`su0qlq#LI?gWPR75G`%;NV zE=Z=ceG+=Z6KF0hj=qh~=*#%|-{?#(%o&!f7`jxI(TLSUJH8nmNGG)29_T=aq61Ii z6Yl@X6x{EHb0yQiGVO*<sn0^!=o9RSxpF7d@AK|BfchNtxg2?t>F<a)qvyadtmfx9 z33p-*Y<poc{cHFMSb_QmEK2{0V-!q^MBZfj%jH$rj%qWkk59+z|3e3K9_^^|MWNmn z-OnjB$yQ-`Jb+d39QMOX7l)4Lqvy+em@>2<P;h^LhwjfjmxTRU2Hh?VV!b{3U?22k z9EfhCEcAptfaS1ozGV7OIyS~6_1Wl&IUhY2UPO1>s(kE!*Jv{r+_&$b^~2~uK1bK; zAN0UT<_}3&1RcONXoG#xoERGG6VaS_0zE&TK@YCAXr%X}xpFc;``^NU@xmnqLOnBD zE!r3z@vZ1U??wkW5)Jt*ba!k*+uMd7NFSlw_DA%);NR$dRW1!leO-!z4YtFFus52e z$Knk?quHFZV6YH6vr_1ctD`f#5zURx*aWAbOS>08!{ay>-@PnEv`L{buvBXbZjVlA zsQaTMABnE@bj-jx=y$fK<Mn6IHGLkve-%2j?dX6%M4$gW`VG2NKgRlL<i1qm9}3PW z_vK*#h0u^?qM@veRk0!3@E|ltQfN+0K<|479q3AQBCF8>Y(xjTCDwPNNx46Lo&9%+ zf?50(I*_wygSiWbr6_`qyfjY7%6Kilg?8{8x@3Q&Ct!{%!mi1U4!9Wld?hS{HPQCF zVEXU>96-SahNDaI2zJ1k=(ak64y<aCaPTxhb7m#FJ>Nzf{2$uRcUTL5Lzkr7m0_UO z(RS*f{WQZ=YYKNzD2p$}5B6d|>R(|dwz(>VbRb$Eg$`hTbTyiU+t6J21WnFU=s}h& znoNI1>wq3qlcQNh+5f(5zU6`qWG|LXf9ETLPf_oJ&gfUP!?Wnx<}02|)Ml}ZU<vB& zGsA&13|;FTSRN0c&z(ct$zLKwqA0o~B}=gXZLlI2v{tlHv{m#rG?ZOq{a&n3eQ>O= zMnk$0?Pz!O5SpaN&<UMEmte}(;U)KUih>t5#tYlg5Ppje=p5QW&TGN}R1}?IC3J?@ z;k9@-R>isKb34%i9YCM|20gI;!3KDF$q<>;?G&8ZeK-e);84t6Dw!CMV{idxE1gXL z+3-a;g?g(pA?XgG9e$7QhEwSFI)f(XxmYhyHf-C=(Fqqtk~WnnPr+?c4}G9j_#n{@ zJqHG%5gCiF<s7tum(h;0(6xLse*P{x^N+C<o<Lu2`O1Z_WHr!s+F(K7|2-*qpo~Nt z8iTIkgjk;uKc9z&auGVv_2|rZqxT;~2lOTS+Wi(i4=yVo26P1)p$gIJnEwC&>%<#c zp)Z-v_&D}Mx8+~)^UMmNq3URdP0^)mi#~TJvMCbxp&j)_Co}{d*l6_amqG{j45n;o z5e1WK1^VCy^uf*X`gZhy*@rgp75bg<9NKVZ#Sn>7=)SLlw%ZtOrw!U}hxmCHEKYq; zMfSfpKFI|`x&U44SJC(NE_AJqV`)5#Hgrv;u<y&G=f}<H`EfrwfJe}X%t9ly1RcmK zbinJ;rF*>+``_eymkat4+QBh2Cw@Sa@E0^f=g<dpRSvJ$0{8*-3TSTpjZWl}Dk14g zq7iF>PP7-Ayo1no$D}AYvMJaDXQJ8q2b#TCR1If&L%f0d2<(6x(eI9zR0}hjjz(fu zbS*leedyAC5&boOo>4tSELEI>Bd&#Ro13Ct&;w&2I*_U8Pc&=MrFkEHYyOBncfqw` zsS2Y@P!YY}5WT-0`h{c=w!q0q#8Qa^p^!L^5AeZ%cs-7+5kk5FJ>%bx{*0br`D!N9 zzvXI!9>qJ+A7*pZ3NM?6SeN<`ybD*M5zJLPnf`M`t+0(T+(@A_ALP6)+}I0SQQv}Y zzdUuqcf4!y9_n|Xq23a&e~u<uwz?sAE<|Tu04rljY=XC<Njev6;c9%$HT;&s?Kq%b zSlf5;S?X8TPo{rf--L$lZ#4M|Gzg)-3hlTmnpAbrj+<dgyaUatF<2YFz-oB;^~uCE zY>Daj|6vNwxKzXN`W=Mrsjou^ctNA^6VOC7CywHc_%FK6Znz;NZ9A+&eK^*@7x8iY z6y4Un8;7MEgYL378ngc$`8F;Xn!V@@zQfjd22G}BO@eo#5B5X1(@-?aQ|LgRK(l=z zy1mw*`+YO|+&1*SUFdfGqzU`q8-C$}5B`qs^BhgXw#<iyxG>saiFmyVdVg&+yIWvI zyceD6toZp#bby=DgY13u{x8vioKI13rkC89O#hWBU9bZ6&A1YOz@0d!Sr|yS=Hb2H z2S;#yCOW`8EyBPrMH?=Lc3c@f$Qs1Yo1nSW2E8wJF9kz65<Q5<#rhO<#B<RlSb@GY z-a;d>4UND)w4txic21#7dJc_jo|Yl>m!RzziWWl##{d5vFH}Silp5iK#4Ttp+#c)q zqHEY6o$)YqfMd`OXP`^B5S{UIw8J&%`H+R%@pr6>ueWl*r1y^$eBdv%;dAH=FSsd$ zupnB$2K~GmI*_{Pb2p#^XpVMx8@hy@aWFoH9_jy}yQ0|5VVB&BW!+xmD0on;#Af&z z4#lfmhoqW=o?P#sCu5E_$@KpP(-d!{J{ue3XXxj}ZV3bFf<~w}x`d<9BYY|vsh2SQ z=l@=%;DPaR{NNlK`dn?p+7?0AzC1e9%IH$nL*H&4(Cs?}&F;yViObLfYZn@skI?%* z!@l@iTlT*Vb!`_yItm@x!{~`MC0>6gx*Kh1Ke{BJpfmd(U7CNQ+1rPAMqYHrmC<e4 zBG$X3yI^#C_P;mG<bpF^g>IWI=s-S<^-p5`INH!@H0v+CH9UVM`g~1vhRxC4&=rl) z{b)ZE(Frd`Bl$)u-mnvWseFSrob9$SkOF8!C1Sl&v_2Zzo6v~dj&8RuvECD1`}@(3 z#-an8g0}yBG_{sOaV~6&Hyp#7)c?kMSmpK*+P>(1ABIP90y=<R9m3KLKxa4{9nf?% zf^*U5p2s(F9X^bMI;KBQB~DRr8=XZ%nC*_xU_o>#u0+?mJUWx>(3#$d)v*;ivoUC- zW}(k5M(<mL4&*g-+it;0_#WnU|F^j_jJOke!`)aB??)S+i>}#fbSAsd8Gee+_*ne> zES95w`CZ}5>J8{_=!5s;BrJ=+VN<-a69abtcc<W*^h1;Dq3A4hKr7L=)jD(_yU->2 z20br|bPhA@fex%6I<R5r^G~3WnT=-sb7()WWBU950Sd0=Q8ZM?(GZ?S-}l+Nge)$O zepjp)ZHpzT_eLZ2IGXLxp^@5*{+#e3mcUc!^OtrF_m}O;{?Ft>LoT?FyQ3o;ie~Q= zw82H_$lr+dgVA5n<jvbHbWjl;NE>tsd!x@kh3>A^=>6|wRs5-2D$Jm0_Yk7SXaw4z z1Gp12u|K9mi6-f6tb<GA=U<`8maRuf(wt}n3!*3IHR#03pi9&ceJ3<eQ826fqHFX3 zx)kGM{fYSb{CIsSKF;T_;wY@&Gd#Zmo#8v^0KY;bb{bv6ymyD>EQdzuRy3zl_fs%g z9>zvEAD#JU=vw`PnV9UwZ?7`=j)?bBZ{0hYcn-7Bm(QK|gf(A)o)4?A6HdK1MEE$G ztQYkO*?${yWTz7ID3~PA<K4JDe2^%2Uzk~S^lWd4hOh;Ce|NkC$DyG=g3jnGG?IUz zq0WAPSc(hL=Zau|Y=G&1|6>IOZ`_7<v^&;6LMEK}4DH}^G)a%4+wc!G)cN{`nO}`Y z@>(=kTF2|Rp-a&l?Po07&P2@R{+~y|HGdxMXl3+OG&eS&C*(WmeY?;OK0=f1Q*_`z zpa;%x=m7Kg3j?eey&jEFTXcKggXzEjcO(TzI2oP6^H>4jM33I%=uH1a2a>CQ2<63S zht;BO(RK!+19~hv10CpmH0zh6?S9ao{XdMtXI!wMwgW;31JRieM+fvMdO|LUu0$Jr z6P?K(tb|9<WXv-#eBK%jb>~<gi005(bf9wvvj1&(4Hq2o7Ho<;u{~ZiDEws99j~Xp z0$bt<?0_`}`$HrL6}HAtu?3bLl1%@(|G_wh`c^D~4Tpx^&;vb)CZ;IdLE$Ad<ma&z zRu~p+hkdD!#PRqwI^aIT!<Wbh(Cf=^6jmA$zB?|(%G9qMnM{0yt<ddQ?13<_(b$c8 zYBz;Sq<Q&K$@IU?a>r<Xp-BDm2a}0+x#6aVIO(Y88xum^YHTvmi|d`RA-;`<lz;9f z{oC!rSe<GkycUO|=fzTV0QnydM{j?u?fzd#p$;D$!bX_yk+6pC&@*}#`nKDShW=ly zhBrPMIvj~NQD21ajvvu&_6OSWx%m0L<HEVH4sCY}-s$`QR|+OgtMQ?MX=rlI#ar+t zw1Yp<HEuj1yi}gVTGUr!N&Fg1W3Gwer`#&omU@3QIp4xE_!Ihlpx~q=|NaAo6otF+ z5A29-9}68W!;#c~M{}g#<nZhC?RY2k%O4LpG8j$Hxwsn-VOe}`N;txIqXYc{>tUg( zVPfquWs*Ek!IAGr)+BKT9eLGh;RlaL&@6ukjZ}drlIg!(;&wDb8_@yfnjW@WPxQPP zj_#^S=yrY*U7BanBz|!^``?pnJr_J!-i#k?Ltn!Oa6W#HKKQ_sVP+3wMe57Z+&F|Y zFz<|HVgfG293*YYr;>@&)XUEdOIvJKI62Fr?N^yaR_3EnmkU?mP3T*%cXTv1qCOoB z-M)A|@9Z$(5}4$A8N3K9q64jqMxZg4!`slKcP!f9tXO|BMWG58-ate9BN~y)bHWK# z6Mdi!dXjZRI~am?JQ^>=6q>YC(AW2TbO5Wd48DyH;5d5!fA|`v^2`k<-WGI?l23<* z^P^uB3ZWfVLL*cY9pEkTdIz+_uJQU1bj?ShFQG@#=buF<@M65a5!tS(#77kD=yP-i zzoR41J})$U8Tw$kSg((M-Zt73eSR1^!zpOQp2I6~Et+f}qF=?1q7yxa>Hq)t7YZiB zpJ+oF^TP}ZqbFPmG}(H@>rbHjc`ka^Z^ub^@iXE29IQ+IUG(~SGy;<rg#W5G9kWqC zi|POVcb<YbT<~lN?ZxOCU54(866gTSAW5C5jz+3R{JaS|vzF1;=nUJT?R3Q&ct4sm zi_qtnV9GCz>nPa3el+|4hu(MsUF%=a2mZt|m}6ng3ACe{Xbv>SM%V#c;aoJSkKsL7 zYEd|6rsA#C*DYfI+hESc;e#sJmU;*Di^5X88uwrW{24vzDn1u}^U)W5TfU0ke;9k> zzj!TneLlQZpThFg-$Iw{2W*GcUts^Yq%i)4@V@^Ln@}&YBy`Xl+f!eG&GA3<C~o#* zGW~x@F2bhNbG;P)6isWqo%-|WZaITSw7}AE0F^-_RSk{kjVTJQ(QW8VyQAA@9Gb;b z(GWk2HuN%@{aes)F#BWu1eTzF7QMgNve0e?bQ{)2Bh()Kd0+$@`P57bo=|UKS^O3= z@#5v-V5)+4+zowj7<&H<tblJ|N&FriK;D;=iN#nsx)*(Z(25X&3FyG5BNOG{|DceQ z3$LP)*o2qkc68r<jy7---Ot%phR_v5UsjdSf%Qi3dlbEIE;^ufXgmMI;`lAjz#Oai zfh2?X?_3J5$<fu}*W$mSYxD4$FyiTGeI9z>vRHpJ*7u+T{sLX|zpymse<hjzTQRT0 z4b)Gdx%1qs;WhmaroaDhUmHgLAv)5p(KS4cCSzh<c)2viE>zp29lnA_Y$v*F4q_cF z^;$^QZs<}ijqb;bGuR#I+cD1u_WxvV$d?uVOxAofWF<Ey6Te_Hybo(_3Q4&bjlgnr zrkl}_A4b2v|AbE9!q-ERUWq1gCG=#yK3=~aJ<{)eo&9fUN5>13(FPVoS4Q7N&-VAD z$Iy<?pwD0QM(`?hfECaV8ltb|_UQfH(Oemh-uKiS?0;{3i3>KgDc-mfU4qZi?REm) zo@defioY3hqjK~*bcT)5?7kCicSv*sx@1qI6MO}|@9h)?*YFc$NfO^;HvAs5;|X*C zKch!+VsrRyc24v}Y>Fn^qv(K_quIX!eeM9-;WyX_f5+>v=3C+2k{Uq48-}4Bj7J-q z5`7vykY0?RuSRFK9^JM(<Mn;f!)Oj2MJL8TcbUE~FZwboi1t$i>4*RSn}P$VjK1Zr z4<962#_Ju>P~C$jQwm+vC!-6|=T@Qv%R-lGHyVkPn2EXH4iPAiMxZZl^85c13XZ7j z)-b}}=-aO^dVLTYk&$Qz<70hp{Co*Iz!kCnE_R~62hEi-+k&;wh~0=rv^A!G|JQ+n z9rQ$JI55^9j!r`dG9S&6=g?5TfX;k*^fk1DEw})8ppokJPUvt5+Wv!RvQEX6BYc6v z2waPftlYcdPpeeN$Ej~eA85NhbbK$mWc|_S$Dk3LiluP|&cuz_9&dgxd;wX64)7qB z#Ut;r|NSbJV@G&DUyH6;SM>U5^k7+rp7lG>m(6*!;gUPUfJb5r>JMWT+=W%~Z*(B# zcZCSQg+_8utRL8w3N!eE3x@P(bSA%}q5B&RS<c;I#)Z*HltuS*L-eK6F<u{uKKBHg zD+|zVxCV{bRx~;HqwW5lqF{qL_Jlv%brsg9J_X0%PP~dmZ}xsNai03!A0!jw^uzGq zh`&c8Heqjw%yZ~F<2|&)Jo`e(i=Y#{8r_y<V?9-af+MLLy(!umU90}FJ{+CdMD*yK zg>!HjK7|eUhhM85z}KiZIuH)9KhUH1Z#1$Oe-yruT#7^{m8eX?v%OKckm!IOAbqeQ zK8}ujH#&fQXy}ikA^sEH6}b<FwY?DSs6g~`^!cmM=dVWZuZrp4|5vBr8Z|_dqh0h4 zbmZO8qj(tF&;w`(W6{WsLmQrj?w;q-`&M8{d==~AA*_J~{ujP_HOKVd|2dF?AIy&K z#%k2hqd!PgI~0DU(huDQi_rTI$9mqw;ahK0yp8KiaWJ06AvoaU@H?ch(1WV=C&|P- zya!W;GVy8HE`_l<)t2bm&%ib~4-4XP9FFI(8xH*}eB1p9n^7-!B>W;{5cZ<J2k*wJ zpNFs8v(WawL+`J7l>OhD!b3-s>HmjoceLsk;a4Pc@Gd^j_%i$vjm|ib`X=m)<-STL z-oV+|5!)RLzm{8$4lwa`c&<BErn(t>;!k)3-trCm-(;BaO<1#;Sb_RHbWOLTNApMM zT7QY2c&E_k65ocCEE^iJ3TUoei`lStv~IlK0Go3C1{{YIQxr;3$n#woVO1<oy&IOm z$I%00C6>XxSQY<@*UNq%p1%oAw!!FgbI^7+qR)SgCglak!xxvlXtJjYQSd-08ZVTK zH&jKpS6y`Gt<jlv#q`SxZEzqOso`jjjEnWB(GFfh?^_jJhxWG#lkWfR6moN6H@bZe zq78nIhV)0|#>DA({Y<=m!4IK>i_zyULpv&lZs(HdbG6WR>Y?{FLHoNoT~G1DCIxTo zhK{%w`daOaHaH?)e+YeW9NN&d`1u?(Cl<u(E6@nNhDK~F+WvM-PZW*pK`coBiSH>m z<Fjaoc}|27<wG033Y}2}bS4eZhHgan^DXF++y{OBA@sRN(E-drCpH^>egWFw5={U5 zA8RQ%<1Oe~??%_?Gc1bVqYdTwF*J}Hy+42Ss(8H&I@2mx25X=%q0Z=l`k|3|5RKqt zKeGS*iDm{D?C2LPhZp@6I;f2{*cg3BG)Lc-UC@~hLkBz>o#B+|Q_*?oj2B0jp&h>x z>zjUJ|J%@3E;!O1XorW<lkrHb|Bg2FHyVkIlcAmieeNQ3iHf2#tb#_cKDtybqU~`6 z_0H&hAEhYR(U<YUnP`rmL&F8oWVsq`sAjYwI+K>@1lpr(dIy%od(eSSLAT{}G(t<z z0k1&cEsfux;LQF+ANUWi!EC>T8%v`N*22=*2_4X*_%P1?C9C|U8C&ygD3<Zd^;ws9 z$!M9GHGfRTHF@Xmn4D2GEAQhOR~OA1y)<J@&#asBWNTkEYeSiA`7WLNQQd6MWR0tr zt$DAk?-ylzCwErim$Plnm6cqVtzD6<ZXaa3?vkw4N3u=3C2L^C?B&a59lb64;}_3; z@b2uzv);cu``ab6&OVlX_SmdVIg=lj%vxG8S*Y;by-kz*=1xDGJ$Kfg8<TgB&ARp7 bWTgwU{@j~9lqW0OXUX+fWbODpSuo@OZGb%} diff --git a/languages/sureforms-pt_PT.po b/languages/sureforms-pt_PT.po index 8b190b55f..bf86d3983 100644 --- a/languages/sureforms-pt_PT.po +++ b/languages/sureforms-pt_PT.po @@ -14,9 +14,9 @@ msgstr "" #. Plugin Name of the plugin #. Author of the plugin #: sureforms.php -#: admin/admin.php:406 -#: admin/admin.php:407 -#: admin/admin.php:1970 +#: admin/admin.php:1052 +#: admin/admin.php:1053 +#: admin/admin.php:2623 #: inc/abilities/abilities-registrar.php:139 #: inc/gutenberg-hooks.php:109 #: inc/page-builders/bricks/elements/form-widget.php:67 @@ -43,8 +43,8 @@ msgstr "Uma maneira simples, mas poderosa, de criar formulários modernos para o msgid "https://sureforms.com/" msgstr "https://sureforms.com/" -#: admin/admin.php:419 -#: admin/admin.php:420 +#: admin/admin.php:1065 +#: admin/admin.php:1066 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -59,9 +59,9 @@ msgstr "https://sureforms.com/" msgid "Dashboard" msgstr "Painel de Controle" -#: admin/admin.php:437 -#: admin/admin.php:438 -#: admin/admin.php:870 +#: admin/admin.php:1083 +#: admin/admin.php:1084 +#: admin/admin.php:1516 #: inc/compatibility/multilingual/string-collector.php:236 #: inc/compatibility/multilingual/string-collector.php:245 #: inc/compatibility/multilingual/string-collector.php:313 @@ -79,15 +79,15 @@ msgstr "Painel de Controle" msgid "Settings" msgstr "Configurações" -#: admin/admin.php:706 -#: admin/admin.php:707 -#: inc/post-types.php:231 +#: admin/admin.php:1352 +#: admin/admin.php:1353 +#: inc/post-types.php:270 msgid "New Form" msgstr "Novo Formulário" -#: admin/admin.php:715 -#: admin/admin.php:716 -#: admin/admin.php:2179 +#: admin/admin.php:1361 +#: admin/admin.php:1362 +#: admin/admin.php:2832 #: inc/generate-form-markup.php:203 #: inc/generate-form-markup.php:216 #: inc/global-settings/email-summary.php:225 @@ -105,7 +105,7 @@ msgid "Entries" msgstr "Entradas" #. Translators: Post Title. -#: admin/admin.php:958 +#: admin/admin.php:1604 #, php-format msgid "Edit %1$s" msgstr "Editar %1$s" @@ -126,18 +126,18 @@ msgid "Nonce verification failed." msgstr "A verificação do nonce falhou." #. translators: %1$s: Opening anchor tag with URL, %2$s: Closing anchor tag, %3$s: SureForms Pro Plugin Name. -#: admin/admin.php:1596 +#: admin/admin.php:2242 #, php-format msgid "Please %1$sactivate%2$s your copy of %3$s to get new features, access support, receive update notifications, and more." msgstr "Por favor, %1$sative%2$s sua cópia do %3$s para obter novos recursos, acessar suporte, receber notificações de atualizações e muito mais." #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version, %4$s: Anchor tag open, %5$s: Closing anchor tag. -#: admin/admin.php:1614 +#: admin/admin.php:2260 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version from %4$shere%5$s." msgstr "O SureForms %1$s requer um mínimo de %2$s %3$s para funcionar corretamente. Por favor, atualize para a versão mais recente %4$saqui%5$s." -#: admin/admin.php:2178 +#: admin/admin.php:2831 #: inc/global-settings/email-summary.php:224 #: assets/build/entries.js:172 #: assets/build/payments.js:172 @@ -207,7 +207,7 @@ msgstr "Lixo" msgid "Published" msgstr "Publicado" -#: admin/admin.php:2170 +#: admin/admin.php:2823 msgid "View" msgstr "Visualizar" @@ -299,11 +299,11 @@ msgstr "Nenhum plugin especificado" msgid "Plugin Successfully Activated" msgstr "Plugin ativado com sucesso" -#: admin/admin.php:1030 +#: admin/admin.php:1676 msgid "Activating..." msgstr "Ativando..." -#: admin/admin.php:1031 +#: admin/admin.php:1677 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/formEditor.js:172 @@ -318,17 +318,17 @@ msgstr "Ativando..." msgid "Activated" msgstr "Ativado" -#: admin/admin.php:1032 +#: admin/admin.php:1678 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Activate" msgstr "Ativar" -#: admin/admin.php:1033 +#: admin/admin.php:1679 msgid "Installing..." msgstr "Instalando..." -#: admin/admin.php:1034 +#: admin/admin.php:1680 msgid "Installed" msgstr "Instalado" @@ -336,11 +336,11 @@ msgstr "Instalado" msgid "You do not have permission to access this page." msgstr "Você não tem permissão para acessar esta página." -#: admin/admin.php:1762 -#: admin/admin.php:1861 -#: admin/admin.php:1899 -#: admin/admin.php:1920 -#: admin/admin.php:2133 +#: admin/admin.php:2408 +#: admin/admin.php:2514 +#: admin/admin.php:2552 +#: admin/admin.php:2573 +#: admin/admin.php:2786 #: inc/admin-ajax.php:162 #: inc/payments/admin/admin-handler.php:638 #: inc/payments/stripe/admin-stripe-handler.php:80 @@ -540,7 +540,7 @@ msgid "Dropdown" msgstr "Menu suspenso" #: inc/fields/dropdown-markup.php:112 -#: inc/gutenberg-hooks.php:223 +#: inc/gutenberg-hooks.php:234 msgid "Select an option" msgstr "Selecione uma opção" @@ -560,7 +560,7 @@ msgstr "Confirmar" msgid "Confirm %s" msgstr "Confirmar %s" -#: inc/gutenberg-hooks.php:222 +#: inc/gutenberg-hooks.php:233 msgid "I consent to have this website store my submitted information so they can respond to my inquiry." msgstr "Eu consinto que este site armazene as informações que enviei para que possam responder à minha consulta." @@ -617,7 +617,7 @@ msgstr "Os dados do formulário não foram encontrados." msgid "Sorry, you are not allowed to view the form." msgstr "Desculpe, você não tem permissão para visualizar o formulário." -#: inc/generate-form-markup.php:1102 +#: inc/generate-form-markup.php:1114 msgid "There was an error trying to submit your form. Please try again." msgstr "Houve um erro ao tentar enviar seu formulário. Por favor, tente novamente." @@ -625,7 +625,7 @@ msgstr "Houve um erro ao tentar enviar seu formulário. Por favor, tente novamen msgid "Test Email Sent Successfully." msgstr "Email de teste enviado com sucesso." -#: inc/post-types.php:238 +#: inc/post-types.php:277 msgid "No forms found." msgstr "Nenhum formulário encontrado." @@ -666,7 +666,7 @@ msgstr "O valor precisa ser único." msgid "Sorry, you are not allowed to perform this action." msgstr "Desculpe, você não tem permissão para realizar esta ação." -#: admin/admin.php:1660 +#: admin/admin.php:2306 msgid "Rate SureForms" msgstr "Avalie SureForms" @@ -713,9 +713,10 @@ msgstr "Mostrar" msgid "Hide" msgstr "Esconder" +#: inc/generate-form-markup.php:1444 #: inc/page-builders/elementor/form-widget.php:332 #: inc/post-types.php:95 -#: inc/post-types.php:232 +#: inc/post-types.php:271 #: assets/build/blocks.js:172 msgid "Edit Form" msgstr "Editar Formulário" @@ -726,7 +727,7 @@ msgstr "Editar Formulário" msgid "Edit" msgstr "Editar" -#: admin/admin.php:2021 +#: admin/admin.php:2674 #: inc/page-builders/elementor/form-widget.php:346 #: assets/build/dashboard.js:2 msgid "Create New Form" @@ -740,32 +741,32 @@ msgstr "Criar" msgid "Import Form" msgstr "Formulário de Importação" -#: inc/post-types.php:230 +#: inc/post-types.php:269 #: assets/build/forms.js:172 msgid "Add New Form" msgstr "Adicionar Novo Formulário" -#: inc/post-types.php:208 +#: inc/post-types.php:247 msgid "No records found" msgstr "Nenhum registro encontrado" -#: inc/post-types.php:209 +#: inc/post-types.php:248 msgid "This is where your form entries will appear" msgstr "É aqui que as entradas do seu formulário aparecerão" -#: inc/post-types.php:233 +#: inc/post-types.php:272 #: assets/build/forms.js:172 #: assets/build/payments.js:172 msgid "View Form" msgstr "Ver Formulário" -#: inc/post-types.php:234 +#: inc/post-types.php:273 msgid "View Forms" msgstr "Ver Formulários" -#: admin/admin.php:697 -#: admin/admin.php:698 -#: inc/post-types.php:235 +#: admin/admin.php:1343 +#: admin/admin.php:1344 +#: inc/post-types.php:274 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -779,30 +780,30 @@ msgstr "Ver Formulários" msgid "Forms" msgstr "Formulários" -#: inc/post-types.php:236 +#: inc/post-types.php:275 msgid "Search Forms" msgstr "Formulários de Pesquisa" -#: inc/post-types.php:237 +#: inc/post-types.php:276 msgid "Parent Forms:" msgstr "Formulários dos Pais:" -#: inc/post-types.php:239 +#: inc/post-types.php:278 msgid "No forms found in Trash." msgstr "Nenhum formulário encontrado na Lixeira." -#: inc/post-types.php:240 +#: inc/post-types.php:279 msgid "Form published." msgstr "Formulário publicado." -#: inc/post-types.php:241 +#: inc/post-types.php:280 msgid "Form updated." msgstr "Formulário atualizado." #: inc/global-settings/global-settings-defaults.php:166 #: inc/migrator/importers/cf7-importer.php:168 #: inc/migrator/importers/ninja-importer.php:1152 -#: inc/post-types.php:1004 +#: inc/post-types.php:1031 msgid "Admin Notification Email" msgstr "Email de Notificação do Administrador" @@ -810,7 +811,7 @@ msgstr "Email de Notificação do Administrador" #. translators: %s: {form_title} smart tag placeholder. #: inc/global-settings/global-settings-defaults.php:173 #: inc/global-settings/global-settings.php:588 -#: inc/post-types.php:1011 +#: inc/post-types.php:1038 #: assets/build/settings.js:172 #, php-format,js-format msgid "New Form Submission - %s" @@ -8335,7 +8336,7 @@ msgstr "Alterar Formulário" #: inc/blocks/sform/block.php:42 #: inc/page-builders/bricks/elements/form-widget.php:508 #: inc/page-builders/elementor/form-widget.php:827 -#: inc/post-types.php:1324 +#: inc/post-types.php:1351 #: assets/build/blocks.js:172 msgid "This form has been deleted or is unavailable." msgstr "Este formulário foi excluído ou está indisponível." @@ -8886,9 +8887,9 @@ msgstr "Adicionar blocos à Barra de Ação Rápida" msgid "Re-arrange block inside Quick Action Bar" msgstr "Reorganizar bloco dentro da Barra de Ação Rápida" -#: admin/admin.php:490 -#: admin/admin.php:491 -#: admin/admin.php:2403 +#: admin/admin.php:1136 +#: admin/admin.php:1137 +#: admin/admin.php:3248 #: assets/build/blocks.js:172 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 @@ -9260,7 +9261,7 @@ msgstr "Centro" msgid "Right" msgstr "Certo" -#: inc/form-submit.php:1215 +#: inc/form-submit.php:1216 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "Google reCAPTCHA" @@ -9270,7 +9271,7 @@ msgstr "Google reCAPTCHA" msgid "CloudFlare Turnstile" msgstr "CloudFlare Turnstile" -#: inc/form-submit.php:1219 +#: inc/form-submit.php:1220 #: assets/build/formEditor.js:172 #: assets/build/settings.js:172 msgid "hCaptcha" @@ -9331,7 +9332,7 @@ msgstr "Anterior" #: inc/global-settings/global-settings.php:530 #: inc/migrator/base-migrator.php:548 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 #: assets/build/formEditor.js:172 msgid "Thank you" msgstr "Obrigado" @@ -9566,7 +9567,7 @@ msgstr "Chave do Site" msgid "Secret Key" msgstr "Chave Secreta" -#: inc/form-submit.php:1223 +#: inc/form-submit.php:1224 #: assets/build/settings.js:172 msgid "Cloudflare Turnstile" msgstr "Cloudflare Turnstile" @@ -10616,7 +10617,7 @@ msgstr "Desbloquear Formulários Conversacionais" msgid "With the SureForms Pro Plan, you can transform your forms into engaging conversational layouts for a seamless user experience." msgstr "Com o Plano SureForms Pro, você pode transformar seus formulários em layouts conversacionais envolventes para uma experiência do usuário perfeita." -#: admin/admin.php:329 +#: admin/admin.php:975 msgid "Get SureForms Pro" msgstr "Obtenha o SureForms Pro" @@ -10828,24 +10829,24 @@ msgstr "Selecionar Gradiente" msgid "reCAPTCHA" msgstr "reCAPTCHA" -#: inc/form-submit.php:1159 +#: inc/form-submit.php:1160 msgid "Captcha validation failed. No error code provided." msgstr "A validação do Captcha falhou. Nenhum código de erro fornecido." -#: inc/form-submit.php:1160 +#: inc/form-submit.php:1161 msgid "Captcha validation failed." msgstr "Falha na validação do captcha." -#: inc/form-submit.php:1227 +#: inc/form-submit.php:1228 msgid "Unknown Captcha" msgstr "Captcha Desconhecido" -#: inc/form-submit.php:1228 +#: inc/form-submit.php:1229 msgid "Invalid captcha type." msgstr "Tipo de captcha inválido." #. translators: %s is the captcha title. -#: inc/form-submit.php:1241 +#: inc/form-submit.php:1242 #, php-format msgid "%s verification failed. Please contact your site administrator." msgstr "A verificação de %s falhou. Por favor, entre em contato com o administrador do seu site." @@ -11242,8 +11243,8 @@ msgstr "Descreva o formulário que você deseja criar" msgid "We are building your form…" msgstr "Estamos construindo seu formulário…" -#: admin/admin.php:605 -#: admin/admin.php:606 +#: admin/admin.php:1251 +#: admin/admin.php:1252 msgid "SMTP" msgstr "SMTP" @@ -11375,29 +11376,29 @@ msgstr "Ativar Notificação de Administrador" msgid "Admin notifications keep you informed about new form entries since your last visit." msgstr "As notificações de administrador mantêm você informado sobre novas entradas de formulário desde sua última visita." -#: admin/admin.php:1766 -#: admin/admin.php:1857 -#: admin/admin.php:1895 -#: admin/admin.php:1916 -#: admin/admin.php:2137 +#: admin/admin.php:2412 +#: admin/admin.php:2510 +#: admin/admin.php:2548 +#: admin/admin.php:2569 +#: admin/admin.php:2790 msgid "Unauthorized user." msgstr "Usuário não autorizado." #. translators: 1: opening span, 2: opening strong (inline), 3: closing strong, 4: closing span, 5: opening strong (block), 6: closing strong -#: admin/admin.php:1866 +#: admin/admin.php:2519 #, php-format msgid "%1$sGet started by %2$sbuilding your first form%3$s.%4$s%5$sExperience the power of our intuitive AI Form Builder%6$s" msgstr "%1$sComece por %2$scriar o seu primeiro formulário%3$s.%4$s%5$sExperimente o poder do nosso intuitivo Criador de Formulários com IA%6$s" -#: admin/admin.php:1877 +#: admin/admin.php:2530 msgid "SureForms is waiting for you!" msgstr "SureForms está esperando por você!" -#: admin/admin.php:1879 +#: admin/admin.php:2532 msgid "Build My First Form" msgstr "Construir Meu Primeiro Formulário" -#: admin/admin.php:1880 +#: admin/admin.php:2533 msgid "Dismiss" msgstr "Dispensar" @@ -11417,51 +11418,51 @@ msgstr "Entrar" msgid "Register" msgstr "Registrar" -#: admin/admin.php:2166 +#: admin/admin.php:2819 msgid "Recent Entries" msgstr "Entradas Recentes" -#: admin/admin.php:2167 +#: admin/admin.php:2820 msgid "( Last 7 days )" msgstr "( Últimos 7 dias )" -#: admin/admin.php:2344 +#: admin/admin.php:3189 msgid "Use Conditional Logic to show only what matters" msgstr "Use lógica condicional para mostrar apenas o que importa" -#: admin/admin.php:2345 +#: admin/admin.php:3190 msgid "Split your form into steps to keep it easy" msgstr "Divida seu formulário em etapas para mantê-lo simples" -#: admin/admin.php:2346 +#: admin/admin.php:3191 msgid "Let people upload files directly to your form" msgstr "Permita que as pessoas enviem arquivos diretamente para o seu formulário" -#: admin/admin.php:2347 +#: admin/admin.php:3192 msgid "Turn responses into downloadable PDFs automatically" msgstr "Transforme as respostas em PDFs baixáveis automaticamente" -#: admin/admin.php:2348 +#: admin/admin.php:3193 msgid "Let users sign with a simple signature field" msgstr "Permita que os usuários assinem com um campo de assinatura simples" -#: admin/admin.php:2349 +#: admin/admin.php:3194 msgid "Connect your form to other tools using webhooks" msgstr "Conecte seu formulário a outras ferramentas usando webhooks" -#: admin/admin.php:2350 +#: admin/admin.php:3195 msgid "Use Conversational Forms for a chat-like experience" msgstr "Use Formulários de Conversa para uma experiência semelhante a um chat" -#: admin/admin.php:2351 +#: admin/admin.php:3196 msgid "Let users register or log in through your form" msgstr "Permita que os usuários se registrem ou façam login através do seu formulário" -#: admin/admin.php:2352 +#: admin/admin.php:3197 msgid "Build forms that create WordPress user accounts" msgstr "Crie formulários que criem contas de usuário no WordPress" -#: admin/admin.php:2353 +#: admin/admin.php:3198 msgid "Add calculations to auto-total scores or prices" msgstr "Adicione cálculos para totalizar automaticamente pontuações ou preços" @@ -11883,7 +11884,7 @@ msgstr "Explore o SureDash" msgid "Something went wrong. We have logged the error for further investigation" msgstr "Algo deu errado. Registramos o erro para investigação posterior" -#: inc/field-validation.php:410 +#: inc/field-validation.php:413 msgid "Field is not valid." msgstr "O campo não é válido." @@ -11951,8 +11952,8 @@ msgstr "Miniatura de Vídeo do SureForms" msgid "Expected format for emails - email@sureforms.com or John Doe <email@sureforms.com>" msgstr "Formato esperado para e-mails - email@sureforms.com ou John Doe <email@sureforms.com>" -#: admin/admin.php:725 -#: admin/admin.php:726 +#: admin/admin.php:1371 +#: admin/admin.php:1372 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -12330,7 +12331,7 @@ msgstr "Desconhecido" #: inc/payments/admin/admin-handler.php:1505 #: inc/payments/admin/admin-handler.php:1509 #: inc/payments/front-end.php:872 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 msgid "Guest User" msgstr "Usuário Convidado" @@ -12356,7 +12357,7 @@ msgstr "O Stripe não está conectado." #: inc/payments/front-end.php:122 #: inc/payments/front-end.php:348 #: inc/payments/front-end.php:641 -#: inc/payments/front-end.php:1195 +#: inc/payments/front-end.php:1196 msgid "Stripe secret key not found." msgstr "Chave secreta do Stripe não encontrada." @@ -12465,7 +12466,7 @@ msgstr "Assinatura não encontrada para o pagamento." #. translators: %d: User ID #: inc/payments/front-end.php:870 -#: inc/payments/front-end.php:1316 +#: inc/payments/front-end.php:1317 #, php-format msgid "User ID: %d" msgstr "ID do usuário: %d" @@ -12499,7 +12500,7 @@ msgstr "ID de Assinatura: %s" #. translators: %s: payment gateway #. translators: %s: Payment gateway name (e.g., Stripe). #: inc/payments/front-end.php:891 -#: inc/payments/front-end.php:1327 +#: inc/payments/front-end.php:1328 #: inc/payments/stripe/admin-stripe-handler.php:190 #: inc/payments/stripe/admin-stripe-handler.php:492 #: inc/payments/stripe/admin-stripe-handler.php:667 @@ -12544,7 +12545,7 @@ msgstr "ID do Cliente: %s" #. translators: 1: Amount, 2: Currency #. translators: %1$s: amount, %2$s: currency. #: inc/payments/front-end.php:901 -#: inc/payments/front-end.php:1329 +#: inc/payments/front-end.php:1330 #: inc/payments/stripe/stripe-webhook.php:1089 #: inc/payments/stripe/stripe-webhook.php:1166 #, php-format @@ -12554,7 +12555,7 @@ msgstr "Quantia: %1$s %2$s" #. translators: %s: Payment mode (e.g. Live or Test) #. translators: %s: payment mode #: inc/payments/front-end.php:904 -#: inc/payments/front-end.php:1334 +#: inc/payments/front-end.php:1335 #, php-format msgid "Mode: %s" msgstr "Modo: %s" @@ -12563,24 +12564,24 @@ msgstr "Modo: %s" msgid "Failed to verify subscription." msgstr "Falha ao verificar a assinatura." -#: inc/payments/front-end.php:1228 -#: inc/payments/front-end.php:1246 -#: inc/payments/front-end.php:1254 -#: inc/payments/front-end.php:1261 +#: inc/payments/front-end.php:1229 +#: inc/payments/front-end.php:1247 +#: inc/payments/front-end.php:1255 +#: inc/payments/front-end.php:1262 msgid "Failed to retrieve payment intent." msgstr "Falha ao recuperar a intenção de pagamento." -#: inc/payments/front-end.php:1269 +#: inc/payments/front-end.php:1270 msgid "Payment was not confirmed successfully." msgstr "O pagamento não foi confirmado com sucesso." -#: inc/payments/front-end.php:1321 +#: inc/payments/front-end.php:1322 msgid "Payment Verification" msgstr "Verificação de Pagamento" #. translators: %s: Stripe transaction ID #. translators: %s: Charge ID -#: inc/payments/front-end.php:1325 +#: inc/payments/front-end.php:1326 #: inc/payments/stripe/stripe-webhook.php:1162 #, php-format msgid "Transaction ID: %s" @@ -12588,18 +12589,18 @@ msgstr "ID da Transação: %s" #. translators: %s: payment status #. translators: %s: Status -#: inc/payments/front-end.php:1331 +#: inc/payments/front-end.php:1332 #: inc/payments/stripe/stripe-webhook.php:576 #: inc/payments/stripe/stripe-webhook.php:1168 #, php-format msgid "Status: %s" msgstr "Status: %s" -#: inc/payments/front-end.php:1437 +#: inc/payments/front-end.php:1438 msgid "Failed to create Stripe customer." msgstr "Falha ao criar cliente Stripe." -#: inc/payments/front-end.php:1501 +#: inc/payments/front-end.php:1502 msgid "Failed to create Stripe guest customer." msgstr "Falha ao criar cliente convidado do Stripe." @@ -13466,7 +13467,7 @@ msgstr "Edite este formulário" #: inc/global-settings/global-settings.php:531 #: inc/migrator/base-migrator.php:549 -#: inc/post-types.php:1087 +#: inc/post-types.php:1114 msgid "Your form has been submitted successfully. We'll review your details and get back to you soon." msgstr "Seu formulário foi enviado com sucesso. Analisaremos seus dados e entraremos em contato em breve." @@ -15163,7 +15164,7 @@ msgstr "É necessário o valor do campo de quantidade variável." msgid "Payment amount below minimum. Minimum: %1$s, received %2$s." msgstr "Valor do pagamento abaixo do mínimo. Mínimo: %1$s, recebido %2$s." -#: inc/rest-api.php:1853 +#: inc/rest-api.php:1876 msgid " (Copy)" msgstr "(Cópia)" @@ -15362,12 +15363,12 @@ msgid "Stripe Settings" msgstr "Configurações do Stripe" #. translators: %1$s: SureForms version, %2$s: SureForms Pro Plugin Name, %3$s: SureForms Pro Version. -#: admin/admin.php:1531 +#: admin/admin.php:2177 #, php-format msgid "SureForms %1$s requires minimum %2$s %3$s to work properly. Please update to the latest version." msgstr "O SureForms %1$s requer o mínimo %2$s %3$s para funcionar corretamente. Por favor, atualize para a versão mais recente." -#: admin/admin.php:1544 +#: admin/admin.php:2190 msgid "Update Now" msgstr "Atualizar agora" @@ -15415,8 +15416,8 @@ msgstr "Posição do Sinal de Moeda" msgid "Select the position of the currency symbol relative to the amount." msgstr "Selecione a posição do símbolo da moeda em relação ao valor." -#: admin/admin.php:668 -#: admin/admin.php:669 +#: admin/admin.php:1314 +#: admin/admin.php:1315 #: assets/build/dashboard.js:172 #: assets/build/entries.js:172 #: assets/build/forms.js:172 @@ -15430,40 +15431,40 @@ msgstr "Selecione a posição do símbolo da moeda em relação ao valor." msgid "Learn" msgstr "Aprender" -#: admin/admin.php:1657 +#: admin/admin.php:2303 msgid "Amazing! SureForms is powering your forms and submissions - let's keep growing together!" msgstr "Incrível! SureForms está alimentando seus formulários e submissões - vamos continuar crescendo juntos!" -#: admin/admin.php:1658 +#: admin/admin.php:2304 msgid "If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?" msgstr "Se o SureForms foi útil, você se importaria de deixar um comentário de 5 estrelas no WordPress.org?" -#: admin/admin.php:1661 -#: admin/admin.php:1705 +#: admin/admin.php:2307 +#: admin/admin.php:2351 msgid "Maybe later" msgstr "Talvez mais tarde" -#: admin/admin.php:1662 +#: admin/admin.php:2308 msgid "I already did" msgstr "Eu já fiz" -#: admin/admin.php:1701 +#: admin/admin.php:2347 msgid "SureForms is ready to power your forms — explore what's possible!" msgstr "SureForms está pronto para potencializar seus formulários — explore o que é possível!" -#: admin/admin.php:1702 +#: admin/admin.php:2348 msgid "Manage your forms, track submissions, and discover features like AI Form Builder, payment integrations, and more from the SureForms dashboard." msgstr "Gerencie seus formulários, acompanhe as submissões e descubra recursos como o Construtor de Formulários com IA, integrações de pagamento e muito mais no painel do SureForms." -#: admin/admin.php:1704 +#: admin/admin.php:2350 msgid "Go to Dashboard" msgstr "Ir para o Painel" -#: admin/admin.php:1706 +#: admin/admin.php:2352 msgid "I already know" msgstr "Eu já sei" -#: admin/admin.php:1786 +#: admin/admin.php:2439 msgid "Invalid parameters." msgstr "Parâmetros inválidos." @@ -15841,8 +15842,8 @@ msgstr "Campo de texto" #: inc/form-restriction.php:183 #: inc/form-restriction.php:184 -#: inc/post-types.php:1230 -#: inc/post-types.php:1270 +#: inc/post-types.php:1257 +#: inc/post-types.php:1297 msgid "This form is not yet available. Check back after the scheduled start time." msgstr "Este formulário ainda não está disponível. Verifique novamente após o horário de início programado." @@ -16126,8 +16127,8 @@ msgstr "Não foi possível excluir o webhook." msgid "Unable to connect to Stripe." msgstr "Não foi possível conectar ao Stripe." -#: inc/post-types.php:1231 -#: inc/post-types.php:1271 +#: inc/post-types.php:1258 +#: inc/post-types.php:1298 msgid "This form is closed. The submission period has ended." msgstr "Este formulário está fechado. O período de envio terminou." @@ -16797,19 +16798,19 @@ msgstr "Segredo do webhook não configurado." msgid "Invalid webhook signature." msgstr "Assinatura de webhook inválida." -#: admin/admin.php:507 -#: admin/admin.php:1101 +#: admin/admin.php:1153 +#: admin/admin.php:1747 #: assets/build/formEditor.js:172 msgid "Quizzes" msgstr "Questionários" -#: admin/admin.php:506 +#: admin/admin.php:1152 msgid "Quiz Entries" msgstr "Entradas do Quiz" -#: admin/admin.php:509 -#: admin/admin.php:542 -#: admin/admin.php:575 +#: admin/admin.php:1155 +#: admin/admin.php:1188 +#: admin/admin.php:1221 #: assets/build/settings.js:172 msgid "New" msgstr "Novo" @@ -17327,9 +17328,9 @@ msgstr "Perfeito para educação, treinamento e curiosidades divertidas" msgid "Select this to create a quiz with scored questions and graded results." msgstr "Selecione isto para criar um questionário com perguntas pontuadas e resultados avaliados." -#: admin/admin.php:539 -#: admin/admin.php:540 -#: admin/admin.php:1106 +#: admin/admin.php:1185 +#: admin/admin.php:1186 +#: admin/admin.php:1752 msgid "Survey Reports" msgstr "Relatórios de Pesquisa" @@ -17735,7 +17736,7 @@ msgid "Error creating SureForms Form." msgstr "Erro ao criar o formulário SureForms." #. translators: %s represents the minimum number of characters required -#: inc/field-validation.php:423 +#: inc/field-validation.php:426 #: inc/translatable.php:94 #, php-format msgid "Please enter at least %s characters." @@ -17893,9 +17894,9 @@ msgstr "A resposta da IA estava vazia. Por favor, refine seu prompt e tente nova msgid "Unable to build form fields from the AI response." msgstr "Não foi possível criar campos de formulário a partir da resposta da IA." -#: admin/admin.php:572 -#: admin/admin.php:573 -#: admin/admin.php:1111 +#: admin/admin.php:1218 +#: admin/admin.php:1219 +#: admin/admin.php:1757 msgid "Partial Entries" msgstr "Entradas Parciais" @@ -18766,23 +18767,23 @@ msgstr "O valor do pagamento não pôde ser verificado para este formulário. Po msgid "Cancellation is not supported for this payment gateway." msgstr "O cancelamento não é suportado para este gateway de pagamento." -#: admin/admin.php:1988 +#: admin/admin.php:2641 msgid "SureForms AI Quick Draft" msgstr "SureForms AI Rascunho Rápido" -#: admin/admin.php:2007 +#: admin/admin.php:2660 msgid "Describe the form and let SureForms AI generate it for you." msgstr "Descreva o formulário e deixe o SureForms AI gerá-lo para você." -#: admin/admin.php:2010 +#: admin/admin.php:2663 msgid "Describe your form" msgstr "Descreva seu formulário" -#: admin/admin.php:2017 +#: admin/admin.php:2670 msgid "Example: Create a contact form with name, email, phone, and message fields." msgstr "Exemplo: Crie um formulário de contato com campos de nome, email, telefone e mensagem." -#: admin/admin.php:2058 +#: admin/admin.php:2711 msgid "Redirecting..." msgstr "Redirecionando..." @@ -18795,14 +18796,14 @@ msgid "The prompt is too long. Please shorten it and try again." msgstr "O prompt é muito longo. Por favor, encurte-o e tente novamente." #. translators: %s: maximum characters allowed before the @ symbol. -#: inc/field-validation.php:445 +#: inc/field-validation.php:448 #: inc/translatable.php:97 #, php-format msgid "The part before @ may not exceed %s characters." msgstr "A parte antes do @ não pode exceder %s caracteres." #. translators: %s: maximum characters allowed after the @ symbol. -#: inc/field-validation.php:451 +#: inc/field-validation.php:454 #: inc/translatable.php:100 #, php-format msgid "The part after @ may not exceed %s characters." @@ -18889,22 +18890,97 @@ msgstr "Desculpe, você não tem permissão para renderizar este formulário." msgid "This form requires a payment. Please complete the payment and submit again." msgstr "Este formulário requer um pagamento. Por favor, complete o pagamento e envie novamente." -#: inc/post-types.php:226 +#: admin/admin.php:474 +msgid "You are not allowed to update this prompt." +msgstr "Você não tem permissão para atualizar este prompt." + +#: admin/admin.php:517 +msgid "Finish setting up your form" +msgstr "Conclua a configuração do seu formulário" + +#: admin/admin.php:549 +msgid "Review or edit your form" +msgstr "Revise ou edite seu formulário" + +#: admin/admin.php:550 +#: admin/admin.php:3038 +msgid "Edit form" +msgstr "Editar formulário" + +#: admin/admin.php:555 +msgid "Personalize the Thank You message" +msgstr "Personalize a mensagem de agradecimento" + +#: admin/admin.php:556 +msgid "Edit message" +msgstr "Editar mensagem" + +#: admin/admin.php:561 +msgid "Choose who gets notified of new replies" +msgstr "Escolha quem será notificado sobre novas respostas" + +#: admin/admin.php:562 +msgid "Set up email" +msgstr "Configurar e-mail" + +#: admin/admin.php:570 +msgid "your form" +msgstr "seu formulário" + +#. translators: %s: form title. +#: admin/admin.php:573 +#, php-format +msgid "Finish setting up %s" +msgstr "Conclua a configuração de %s" + +#. translators: %s: form title. +#: admin/admin.php:581 +#, php-format +msgid "View %s (opens in a new tab)" +msgstr "Visualizar %s (abre em uma nova aba)" + +#: admin/admin.php:586 +msgid "Customize your form to get it ready for real submissions:" +msgstr "Personalize seu formulário para deixá-lo pronto para envios reais:" + +#: admin/admin.php:3021 +msgid "We’ve already created this form for you. Finish customising it so it’s ready to collect real submissions." +msgstr "Já criamos este formulário para você. Termine de personalizá-lo para que esteja pronto para coletar envios reais." + +#. translators: %s: form name. +#: admin/admin.php:3030 +#, php-format +msgid "Finish setting up “%s”" +msgstr "Conclua a configuração de “%s”" + +#: admin/admin.php:3039 +msgid "Edit the Thank You message" +msgstr "Edite a mensagem de agradecimento" + +#: admin/admin.php:3040 +msgid "Set where replies go" +msgstr "Defina para onde vão as respostas" + +#: inc/generate-form-markup.php:1445 +msgid "(opens in a new tab)" +msgstr "(abre em uma nova aba)" + +#: inc/post-types.php:265 msgctxt "post type general name" msgid "Forms" msgstr "Formulários" -#: inc/post-types.php:227 +#: inc/post-types.php:266 msgctxt "post type singular name" msgid "Form" msgstr "Formulário" -#: inc/post-types.php:228 +#: inc/post-types.php:267 msgctxt "admin menu" msgid "Forms" msgstr "Formulários" -#: inc/post-types.php:229 +#: inc/post-types.php:268 msgctxt "form" msgid "Add New" msgstr "Adicionar Novo" From e1c8f8aa5a3530ff0f875979d55d06f30c7f5191 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 16:42:27 +0530 Subject: [PATCH 61/65] fix: address 2.12.4 release review (#3050) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Blocking: - inc/rest-api.php: resolve Admin at dispatch instead of while get_endpoints() builds the route table. That runs on rest_api_init for every REST request, and plugin-loader only constructs Admin under is_admin(), so the front-end submit-form path was running Admin's constructor (40 hook registrations, an option read, the notices library, the wpforms_current_user_can filter). Verified: route-table build no longer instantiates Admin; dispatch still 200. - readme.txt / README.md: add the four undocumented user-visible changes (#3026, #3029, #3030, #3031). README.md regenerated via 'grunt readme'. - EditorToolbar.js: 413, 403, network failure and upload-succeeded-but-no-URL all ended at console.error, so an oversized photo looked like nothing happened. All four now surface via notify.error, using WP's message when the failure reached the REST API and generic copy when it did not. Follow-ups taken: - Gate both meta_query builders on ASTRA_SITES_VER. Starter Templates stamps the marker, so without it the query can never match; the Thank You one ran on every admin pageview. - orderby tiebreaker [ date DESC, ID DESC ] on both queries — an import creates several forms in the same second, leaving 'newest' to MySQL. - Replace the remaining '_astra_sites_imported_post' literals with Admin::ASTRA_SITES_IMPORT_META. - aria-label now uses the $card_title fallback, so an untitled form no longer reads 'View (opens in a new tab)'. - Editor.js: check the complementary-area scope under both 'core' and 'core/edit-post'. The area name is stable but the scope is not, and 6.4 is our declared minimum — checking only 'core' meant the early-exit never matched there, re-dispatching openGeneralSidebar 20 times over 6s. PHPStan level 9, PHPCS, PHP Insights 100/100/100 and ESLint clean; build passes; 13/13 affected tests pass. The one wider failure (Test_Rest_Api::test_forms_manage_args_required_and_enum) reproduces on unmodified next-release. --- admin/admin.php | 38 +++++++++++++++---- inc/rest-api.php | 18 ++++++++- src/admin/single-form-settings/Editor.js | 18 ++++++--- .../email-settings/EditorToolbar.js | 30 +++++++++++++-- tests/unit/admin/test-admin.php | 28 +++++++++++++- 5 files changed, 113 insertions(+), 19 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index 619afb932..f5fabda89 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -578,7 +578,7 @@ public function render_form_setup_widget() { <p class="srfm-setup-checklist__title"> <?php echo esc_html( $heading ); ?> <?php if ( ! empty( $card['view_url'] ) ) { ?> - <a class="srfm-setup-checklist__view" data-srfm-event="view_form" href="<?php echo esc_url( $card['view_url'] ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo esc_attr( sprintf( /* translators: %s: form title. */ __( 'View %s (opens in a new tab)', 'sureforms' ), $card['title'] ) ); ?>"> + <a class="srfm-setup-checklist__view" data-srfm-event="view_form" href="<?php echo esc_url( $card['view_url'] ); ?>" target="_blank" rel="noopener noreferrer" aria-label="<?php echo esc_attr( sprintf( /* translators: %s: form title. */ __( 'View %s (opens in a new tab)', 'sureforms' ), $card_title ) ); ?>"> <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg> </a> <?php } ?> @@ -2862,8 +2862,15 @@ private static function compute_form_setup_card() { return null; } + // Starter Templates stamps the marker this query looks for, so without that + // plugin the meta can never exist and the query below can never match. Bail + // before running it rather than repeating it on every dashboard load. + if ( ! defined( 'ASTRA_SITES_VER' ) ) { + return null; + } + // Only forms created from an Astra Sites starter template — those carry the - // `_astra_sites_imported_post` marker Astra Sites stamps on imported posts. + // marker Starter Templates stamps on imported posts (self::ASTRA_SITES_IMPORT_META). // Prime post + meta caches (the loop reads title, permalink and edit link // per candidate) so this is a single query, not a follow-up per form. $query = new \WP_Query( @@ -2871,14 +2878,19 @@ private static function compute_form_setup_card() { 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => [ 'publish', 'draft', 'pending' ], 'posts_per_page' => 10, - 'orderby' => 'date', - 'order' => 'DESC', + // ID breaks the tie: a starter-template import creates several forms + // within the same second, so post_date alone leaves "the newest form" + // up to MySQL and it can differ between page loads. + 'orderby' => [ + 'date' => 'DESC', + 'ID' => 'DESC', + ], 'no_found_rows' => true, 'update_post_meta_cache' => true, 'update_post_term_cache' => false, 'meta_query' => [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Bounded to 10 recent forms; dashboard-only. [ - 'key' => '_astra_sites_imported_post', + 'key' => self::ASTRA_SITES_IMPORT_META, 'compare' => 'EXISTS', ], ], @@ -2930,6 +2942,14 @@ private static function compute_thankyou_prompt_forms() { return []; } + // Starter Templates stamps the marker below, so on an install without that + // plugin the meta cannot exist and this query can never match. This notice + // renders on every admin screen, so bailing here is what keeps the query + // off every admin pageview on the majority of installs. + if ( ! defined( 'ASTRA_SITES_VER' ) ) { + return []; + } + // Only forms imported from a Starter Templates (Astra Sites) starter // template — see self::ASTRA_SITES_IMPORT_META. Prime post + meta caches // (the loop reads meta, title and creation time per candidate) so this is a @@ -2939,8 +2959,12 @@ private static function compute_thankyou_prompt_forms() { 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'posts_per_page' => 10, - 'orderby' => 'date', - 'order' => 'DESC', + // ID breaks the tie — an import creates several forms in the same + // second, so post_date alone makes "newest" MySQL-dependent. + 'orderby' => [ + 'date' => 'DESC', + 'ID' => 'DESC', + ], 'no_found_rows' => true, 'update_post_meta_cache' => true, 'update_post_term_cache' => false, diff --git a/inc/rest-api.php b/inc/rest-api.php index abde3c72c..0b01c3273 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1417,7 +1417,23 @@ private function get_endpoints() { // Per-form capability is re-checked in the handler. 'dismiss-form-setup-card' => [ 'methods' => 'POST', - 'callback' => [ \SRFM\Admin\Admin::get_instance(), 'dismiss_form_setup_card' ], + /** + * Resolve Admin at dispatch rather than while the route table is + * built. get_endpoints() runs on rest_api_init for *every* REST + * request, and plugin-loader.php only constructs Admin under + * is_admin() — which REST dispatch is not. Naming the instance + * here would therefore run Admin's constructor (40 admin hook + * registrations, an option read, the notices library, and the + * wpforms_current_user_can filter) on the front-end + * submit-form path too. + * + * @param \WP_REST_Request<array<string,mixed>> $request Request. + * @return \WP_REST_Response|\WP_Error + */ + 'callback' => static function ( $request ) { + /** @phpstan-ignore-next-line -- PHPStan resolves SRFM\Admin\Admin via tests/php/stubs/srfm-stubs.php (admin/ is outside its `paths`), and that generated stub predates this method. The method exists at admin/admin.php:470. */ + return \SRFM\Admin\Admin::get_instance()->dismiss_form_setup_card( $request ); + }, 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], 'args' => [ 'form_id' => [ diff --git a/src/admin/single-form-settings/Editor.js b/src/admin/single-form-settings/Editor.js index 08ee46280..76e529751 100644 --- a/src/admin/single-form-settings/Editor.js +++ b/src/admin/single-form-settings/Editor.js @@ -128,11 +128,19 @@ const SureformsFormSpecificSettings = () => { // scope). Skip the dispatch when already there to avoid fighting the // user each tick. const iface = dataSelect( 'core/interface' ); - const onDocument = - iface && - typeof iface.getActiveComplementaryArea === 'function' && - iface.getActiveComplementaryArea( 'core' ) === - 'edit-post/document'; + // The area name is 'edit-post/document' on every supported version, but + // the scope it is registered under is not: current WP uses 'core', + // while 6.4 — our declared minimum — used 'core/edit-post'. Checking + // only 'core' means this never matches on 6.4, so the early-exit below + // never fires and the tick re-dispatches openGeneralSidebar 20 times + // over 6s, fighting the user's own tab choice and rewriting their + // panel preferences on every pass. + const activeArea = + iface && typeof iface.getActiveComplementaryArea === 'function' + ? iface.getActiveComplementaryArea( 'core' ) ?? + iface.getActiveComplementaryArea( 'core/edit-post' ) + : null; + const onDocument = 'edit-post/document' === activeArea; if ( ! onDocument ) { dataDispatch( 'core/edit-post' )?.openGeneralSidebar?.( diff --git a/src/admin/single-form-settings/components/email-settings/EditorToolbar.js b/src/admin/single-form-settings/components/email-settings/EditorToolbar.js index 841960d24..6f9b912dc 100644 --- a/src/admin/single-form-settings/components/email-settings/EditorToolbar.js +++ b/src/admin/single-form-settings/components/email-settings/EditorToolbar.js @@ -2,6 +2,7 @@ import { __, _x } from '@wordpress/i18n'; import parse from 'html-react-parser'; import svgIcons from '@Svg/svgs.json'; import apiFetch from '@wordpress/api-fetch'; +import { notify } from '@Utils/notify'; // Undo and redo functions for Custom Toolbar function undoChange() { @@ -22,9 +23,13 @@ function imageHandler() { input.click(); input.onchange = ( e ) => { - const file = e.target.files[ 0 ]; + const file = e.target.files?.[ 0 ]; + if ( ! file ) { + return; + } + if ( ! /^image\//.test( file.type ) ) { - console.warn( 'You could only upload images.' ); + notify.error( __( 'Please choose an image file.', 'sureforms' ) ); return; } @@ -41,7 +46,12 @@ function imageHandler() { response?.source_url || response?.media_details?.sizes?.full?.source_url; if ( ! url ) { - console.error( 'Media upload succeeded but no URL returned.' ); + notify.error( + __( + 'The image uploaded but could not be inserted. Please try again.', + 'sureforms' + ) + ); return; } const range = quill.getSelection( true ); @@ -52,7 +62,19 @@ function imageHandler() { } ); } ) .catch( ( err ) => { - console.error( 'Image upload failed:', err ); + // Surface the failure — 413 (post_max_size), 403 (no upload_files) + // and network errors all landed here silently, so picking an + // oversized photo looked like nothing happened at all. WP sends a + // human-readable `message` for REST-level errors; a request that + // never reached the API (size cap, connection drop) has none, so + // fall back to generic copy rather than printing an object. + notify.error( + err?.message || + __( + 'The image could not be uploaded. It may be too large, or you may not have permission to upload files.', + 'sureforms' + ) + ); } ); }; } diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index f3bc79d75..0d654ec15 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -982,7 +982,13 @@ public function test_get_form_setup_card() { wp_set_current_user( is_wp_error( $admin_user ) ? 0 : (int) $admin_user ); $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Card Form' ] ); - update_post_meta( $form_id, '_astra_sites_imported_post', 1 ); + update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); + // Stamping the import marker simulates a Starter Templates install, so the + // ASTRA_SITES_VER gate in the query must hold too — without it the payload + // builders correctly bail before querying. + if ( ! defined( 'ASTRA_SITES_VER' ) ) { + define( 'ASTRA_SITES_VER', '4.0.0' ); + } try { Admin::reset_form_setup_card_cache(); @@ -1087,7 +1093,13 @@ public function test_render_form_setup_widget() { wp_set_current_user( is_wp_error( $admin_user ) ? 0 : (int) $admin_user ); $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Render Form' ] ); - update_post_meta( $form_id, '_astra_sites_imported_post', 1 ); + update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); + // Stamping the import marker simulates a Starter Templates install, so the + // ASTRA_SITES_VER gate in the query must hold too — without it the payload + // builders correctly bail before querying. + if ( ! defined( 'ASTRA_SITES_VER' ) ) { + define( 'ASTRA_SITES_VER', '4.0.0' ); + } try { // Positive: a qualifying form renders the full checklist. @@ -1310,6 +1322,12 @@ public function test_get_thankyou_prompt_forms() { $imported = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Imported TY' ] ); update_post_meta( $imported, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'same page', 'message' => $default_message ] ] ); update_post_meta( $imported, Admin::ASTRA_SITES_IMPORT_META, 1 ); + // Stamping the import marker simulates a Starter Templates install, so the + // ASTRA_SITES_VER gate in the query must hold too — without it the payload + // builders correctly bail before querying. + if ( ! defined( 'ASTRA_SITES_VER' ) ) { + define( 'ASTRA_SITES_VER', '4.0.0' ); + } // Same default message but NOT an Astra Sites import → excluded by the gate. $plain = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Plain TY' ] ); @@ -1377,6 +1395,12 @@ public function test_render_thankyou_prompt_notice() { // message → exactly the srfm-thankyou-prompt notice is registered. $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Positive TY' ] ); update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); + // Stamping the import marker simulates a Starter Templates install, so the + // ASTRA_SITES_VER gate in the query must hold too — without it the payload + // builders correctly bail before querying. + if ( ! defined( 'ASTRA_SITES_VER' ) ) { + define( 'ASTRA_SITES_VER', '4.0.0' ); + } update_post_meta( $form_id, '_srfm_form_confirmation', From f01a99c051e82d57672e21488d57b0ce4609f6c0 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 16:51:49 +0530 Subject: [PATCH 62/65] =?UTF-8?q?fix:=20WP=207.1=20editor=20regressions=20?= =?UTF-8?q?=E2=80=94=20form=20block=20preview=20and=20settings=20modal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ports #3053 to next-release so these ship in 2.12.4. That PR merged into dev, but the release ships next-release, so without this the fixes would slip a release. Byte-identical to #3053's merged result: - Edit.js: clear the loader unconditionally (it sat behind the contentDocument guard, which is null on 7.1's cross-origin-isolated canvas, so the spinner never cleared), plus a 3s fallback, height over the srfm-preview-height postMessage, and guarded contentDocument reads. - preview-styling.js: report height to the embedder, tolerance-guarded so the apply -> reflow -> report cycle cannot loop. - Dialog.js: offset from the measured admin-bar height rather than inferred from fullscreen mode, which no longer hides the bar on 7.1. - header-styles.scss: margin: 0 on .editor-header__back-button. Verified the four files on next-release were identical to #3053's pre-image, so this carries only that PR, and each result is byte-identical to a83be1e30. ESLint and Stylelint clean; build passes with all three fixes in the bundles. Note: the preview height path is still not fully confirmed on 7.1 — see the PR description. --- assets/js/unminified/preview-styling.js | 53 +++++++ sass/header-styles.scss | 3 + .../components/dialog/Dialog.js | 32 +++- src/blocks/sureforms-form/components/Edit.js | 137 ++++++++++++++---- 4 files changed, 194 insertions(+), 31 deletions(-) diff --git a/assets/js/unminified/preview-styling.js b/assets/js/unminified/preview-styling.js index 6b0085184..2b7a1f2ae 100644 --- a/assets/js/unminified/preview-styling.js +++ b/assets/js/unminified/preview-styling.js @@ -54,6 +54,59 @@ overrideStyle.textContent = cssText; } + /** + * Report our rendered height to the embedding editor. + * + * The block editor used to measure this document directly, but from WP 7.1 its + * canvas is cross-origin isolated, so the embed is opaque to it and the iframe + * stayed at its default height. Pushing the height out is the only channel that + * works in both cases. + * + * targetOrigin is '*' deliberately: the embedder can be an opaque/blob origin + * under WP 7.1, so no specific origin can be computed, and the payload is a + * single layout number with nothing sensitive in it. The editor side verifies + * the sender by comparing against its own iframe's contentWindow. + * + * @since x.x.x + */ + let lastReportedHeight = 0; + + function reportHeight() { + const height = container.offsetHeight; + + // Skip unchanged heights. The embedder applies what we send to the frame, + // which reflows this document — so re-reporting the same measurement is how + // a height feedback loop starts. The tolerance also absorbs sub-pixel + // rounding that would otherwise oscillate between two neighbouring values. + if ( ! height || Math.abs( height - lastReportedHeight ) < 4 ) { + return; + } + + lastReportedHeight = height; + + const message = { type: 'srfm-preview-height', height }; + + // The editor's React tree runs in the top window while the canvas is a + // separate document, so parent and top can differ — post to both. + [ window.parent, window.top ].forEach( function ( target ) { + if ( target && target !== window ) { + target.postMessage( message, '*' ); + } + } ); + } + + // Only meaningful when framed; a directly-loaded preview has no embedder. + // + // Deliberately not a ResizeObserver on the container: the embedder resizes the + // frame in response, which resizes this container, which fires the observer + // again — an unbounded loop that froze the editor tab. Reporting on load and on + // viewport resize matches what the previous same-origin measurement did. + if ( window.parent !== window ) { + reportHeight(); + window.addEventListener( 'load', reportHeight ); + window.addEventListener( 'resize', reportHeight ); + } + window.addEventListener( 'message', function ( event ) { if ( event.origin !== window.location.origin ) { return; diff --git a/sass/header-styles.scss b/sass/header-styles.scss index 4720bafee..a625a82f6 100644 --- a/sass/header-styles.scss +++ b/sass/header-styles.scss @@ -40,6 +40,9 @@ body.post-type-sureforms_form .edit-post-header .edit-post-fullscreen-mode-close // styles the back-button wrapper as the logo tile. body.post-type-sureforms_form .editor-header__back-button { + // WP 7.1 gives the wrapper its own margin, which broke the tile's flush fit + // against the header edge. + margin: 0; align-items: center; align-self: stretch; background: #1e1e1e; diff --git a/src/admin/single-form-settings/components/dialog/Dialog.js b/src/admin/single-form-settings/components/dialog/Dialog.js index cba6527b6..0c95d1e90 100644 --- a/src/admin/single-form-settings/components/dialog/Dialog.js +++ b/src/admin/single-form-settings/components/dialog/Dialog.js @@ -183,6 +183,22 @@ const Dialog = ( { return width + 40; }; + /** + * Measured height of the WP admin bar, or 0 when there isn't one. + * + * Measured rather than derived from fullscreen mode: up to WP 7.0 fullscreen + * hid the admin bar, but from 7.1 the bar stays visible in fullscreen, so + * assuming "fullscreen means nothing above us" slid the dialog's top edge + * (and its close button) underneath the bar. offsetHeight is 0 whenever the + * bar is hidden, which keeps the pre-7.1 behaviour intact. + * + * @return {number} Admin bar height in pixels. + */ + const getAdminBarHeight = () => { + const adminBar = document.getElementById( 'wpadminbar' ); + return adminBar ? adminBar.offsetHeight : 0; + }; + const isFullscreen = useSelect( // Param renamed to `wpSelect` to avoid shadowing the imported // `select` from `@wordpress/data` used by the toast listener below. @@ -221,10 +237,22 @@ const Dialog = ( { if ( ! dialogWrapper ) { return; } - if ( ! isFullscreen ) { - dialogWrapper.style.marginTop = '40px'; + + // Outside fullscreen the offset stays 40px (admin bar plus the editor + // header). In fullscreen, clear whatever admin bar is actually on screen: + // WP 7.1 keeps the bar in fullscreen mode, so removing the offset outright + // put the dialog header — and its close button — behind it. Pre-7.1 the bar + // is hidden there and this measures 0, giving the previous no-offset layout. + const topOffset = isFullscreen ? getAdminBarHeight() : 40; + + if ( topOffset > 0 ) { + dialogWrapper.style.marginTop = `${ topOffset }px`; + // The panel is h-full, so the offset has to come off its height too or + // the same number of pixels drops off the bottom of the viewport. + dialogWrapper.style.height = `calc(100% - ${ topOffset }px)`; } else { dialogWrapper.style.removeProperty( 'margin-top' ); + dialogWrapper.style.removeProperty( 'height' ); } }, [ open, isFullscreen ] ); diff --git a/src/blocks/sureforms-form/components/Edit.js b/src/blocks/sureforms-form/components/Edit.js index 4aceae9b8..af5446663 100644 --- a/src/blocks/sureforms-form/components/Edit.js +++ b/src/blocks/sureforms-form/components/Edit.js @@ -39,6 +39,9 @@ export default ( { attributes, setAttributes, clientId } ) => { const iframeRef = useRef( null ); const iframeContainerRef = useRef( null ); + // Last height written to the frame, so an unchanged measurement is a no-op + // rather than another resize → reflow → report cycle. + const appliedHeightRef = useRef( 0 ); const [ loading, setLoading ] = useState( false ); const [ formIframeHeight, setFormIframeHeight ] = useState( 0 ); const [ showUpgradeModal, setShowUpgradeModal ] = useState( false ); @@ -106,9 +109,27 @@ export default ( { attributes, setAttributes, clientId } ) => { [ id ] ); - // Remove unwanted elements from the iframe and add styling for the form - const modifyIframeContent = () => { - const iframeDocument = iframeRef.current.contentDocument; + /** + * Read the preview document, when the browser lets us. + * + * Returns null instead of throwing: from WP 7.1 the editor canvas is a + * cross-origin-isolated document, so this iframe is treated as cross-origin + * and both `contentDocument` and any property access on it are unavailable. + * + * @return {Document|null} The preview document, or null when unreachable. + */ + const getPreviewDocument = () => { + try { + return iframeRef.current?.contentDocument ?? null; + } catch ( error ) { + // Cross-origin (or isolated) preview — nothing readable here. + return null; + } + }; + + // Sync the iframe height from the preview document, where that is readable. + const syncHeightFromDocument = () => { + const iframeDocument = getPreviewDocument(); if ( ! iframeDocument ) { return; @@ -121,14 +142,29 @@ export default ( { attributes, setAttributes, clientId } ) => { if ( formOuterContainerSelector ) { const getHeight = formOuterContainerSelector.offsetHeight; - if ( getHeight && 0 !== getHeight ) { - // set height of iframe if form is not empty. + // set height of iframe if form is not empty, and only when it actually + // changed — writing the same height back reflows the preview for nothing. + if ( + getHeight && + 0 !== getHeight && + appliedHeightRef.current !== getHeight + ) { + appliedHeightRef.current = getHeight; setFormIframeHeight( getHeight ); iframeRef.current.height = getHeight; } } + }; + // Remove unwanted elements from the iframe and add styling for the form + const modifyIframeContent = () => { + // Clear the loader first, unconditionally. Height measurement below is + // best-effort — when the preview document is unreadable (WP 7.1's isolated + // canvas) the height instead arrives over the srfm-preview-height message. + // Clearing last, behind that guard, is what left the spinner up forever. setLoading( false ); + + syncHeightFromDocument(); }; useEffect( () => { @@ -147,25 +183,12 @@ export default ( { attributes, setAttributes, clientId } ) => { const observerCallback = ( entries ) => { entries.forEach( ( entry ) => { - // Check if form is visible and iframe height hasn't been set + // Check if form is visible and iframe height hasn't been set. + // syncHeightFromDocument() no-ops when the preview document is + // unreachable; reading `.contentDocument.querySelector()` directly + // threw a TypeError there. if ( ! formIframeHeight && entry.isIntersecting ) { - // Access the iframe's content - const iframeDocument = iframeRef.current.contentDocument; - - // Find the form container inside the iframe - const formOuterContainerSelector = - iframeDocument.querySelector( '.srfm-form-container' ); - - if ( formOuterContainerSelector ) { - const getHeight = - formOuterContainerSelector.offsetHeight; - - // Set iframe height if a valid height is found - if ( getHeight && getHeight !== 0 ) { - setFormIframeHeight( getHeight ); - iframeRef.current.height = getHeight; - } - } + syncHeightFromDocument(); } } ); }; @@ -181,15 +204,71 @@ export default ( { attributes, setAttributes, clientId } ) => { }, [] ); useEffect( () => { - if ( iframeRef && iframeRef.current ) { - setLoading( true ); - - iframeRef.current.onload = () => { - modifyIframeContent(); - }; + if ( ! iframeRef?.current ) { + return; } + + setLoading( true ); + + iframeRef.current.onload = () => { + modifyIframeContent(); + }; + + // The load event can be missed entirely: the iframe is `loading="eager"` + // so it may already have loaded before this effect runs, and a preview + // blocked by the embedder's isolation policy never fires load at all. + // Without this the loader would stay up for the rest of the session. + const loaderFallback = setTimeout( () => { + setLoading( false ); + syncHeightFromDocument(); + }, 3000 ); + + return () => clearTimeout( loaderFallback ); }, [ id, iframeRef, hasResolved, attributes.formTheme ] ); + // Height over postMessage — the only channel that survives a cross-origin + // preview (WP 7.1's isolated editor canvas), where the document cannot be + // measured from here. The preview page posts its own height on load/resize. + // Identity is checked by comparing the event source against this iframe's + // contentWindow: a reference comparison needs no cross-origin access, and is + // stricter than an origin check when the embedder origin is opaque. + useEffect( () => { + const onPreviewMessage = ( event ) => { + if ( + 'srfm-preview-height' !== event.data?.type || + event.source !== iframeRef.current?.contentWindow + ) { + return; + } + + const height = Number( event.data.height ); + + if ( ! Number.isFinite( height ) || height <= 0 ) { + return; + } + + setLoading( false ); + + // Ignore a height we have already applied. Applying it resizes the + // frame, which reflows the preview and can prompt another report, so + // this is the second half of the loop guard (the first is in + // preview-styling.js) and keeps repeated messages from re-rendering. + if ( appliedHeightRef.current === height ) { + return; + } + + appliedHeightRef.current = height; + setFormIframeHeight( height ); + + if ( iframeRef.current ) { + iframeRef.current.height = height; + } + }; + + window.addEventListener( 'message', onPreviewMessage ); + return () => window.removeEventListener( 'message', onPreviewMessage ); + }, [] ); + // Send styling updates to iframe via PostMessage const sendStylingToIframe = useCallback( () => { if ( ! iframeRef.current?.contentWindow || ! formUrl ) { From 301989dc52252ae6948a408274899b5fd8a6537a Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 17:20:45 +0530 Subject: [PATCH 63/65] fix: negative cache instead of a live Starter Templates check, and fix PHPCS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the re-review on #3054. 1. PHPCS was red and I reported it green. The inline /** @phpstan-ignore-next-line */ parsed as a doc comment with no short description (Generic.Commenting.DocComment.MissingShort). Now a line comment, which PHPStan honours just the same. My earlier check grepped colour-coded PHPCS output, so the ANSI codes between '|' and 'ERROR' meant the pattern never matched a real error — checking exit codes from here on. 2. The ASTRA_SITES_VER gate was wrong and I introduced it. Verified against the installed Starter Templates 4.7.4: the constant is defined in the main plugin file, so it only exists while the plugin is active, and neither uninstall.php nor astra_sites_deactivate() removes _astra_sites_imported_post — that hook only deletes a handful of options. So import-then-remove-the-importer left the marker on every form while both features silently stopped appearing, which is precisely the population they target. Replaced with the negative cache originally asked for: a transient set only when the marker query itself returns zero posts (a site-wide fact, not a per-user one), invalidated on added_post_meta/updated_post_meta for the marker key so a later import surfaces immediately rather than waiting a week. The invalidator narrows to SRFM_FORMS_POST_TYPE, since a full-site import stamps the marker on every post it creates. Both misleading comments rewritten. 3. Both cache branches are now testable, which the constant made impossible. The four tests no longer define ASTRA_SITES_VER; they clear the transient instead. test_negative_cache_short_circuits_the_marker_query covers the bail path, the populated path, invalidation on the marker key, and that an unrelated key leaves the cache alone. Revert-tested: it fails when the gate is disabled and passes when restored. invalidate_starter_template_cache() reads its arguments via func_get_args() because the hook passes ( $meta_id, $post_id, $meta_key ) and the meta id is never used — declaring it tripped the unused-parameter sniff, and Insights runs at --min-quality=100 in CI. Verified by exit code this time: PHPCS 0, PHPStan 0, phpinsights -n --min-quality=100 --min-architecture=100 --min-style=100 returns 0 with 100/100/100 project-wide. 14 affected tests pass (52 assertions). --- admin/admin.php | 89 ++++++++++++++++++++++++--- inc/rest-api.php | 2 +- tests/unit/admin/test-admin.php | 106 ++++++++++++++++++++++++-------- 3 files changed, 163 insertions(+), 34 deletions(-) diff --git a/admin/admin.php b/admin/admin.php index f5fabda89..35e38aeea 100644 --- a/admin/admin.php +++ b/admin/admin.php @@ -50,6 +50,19 @@ class Admin { */ public const ASTRA_SITES_IMPORT_META = '_astra_sites_imported_post'; + /** + * Negative-cache transient: no form on this site carries the import marker. + * + * Set only when the marker query itself returns zero posts, which is a + * site-wide fact rather than a per-user one, and cleared as soon as any post is + * stamped with the marker (see invalidate_starter_template_cache()). This keeps + * the query off the majority of installs without tying the features to whether + * Starter Templates happens to still be active — the marker outlives it. + * + * @since 2.12.4 + */ + public const NO_IMPORTED_FORMS_TRANSIENT = 'srfm_no_starter_template_forms'; + /** * Inline CSS for Quill 1.x (react-quill) list markers. * @@ -179,6 +192,12 @@ public function __construct() { add_action( 'wp_dashboard_setup', [ $this, 'register_form_setup_widget' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_form_setup_widget_assets' ] ); + // Drop the "no imported forms" negative cache as soon as a post is stamped + // with the import marker, so a template imported after the cache was written + // surfaces immediately instead of waiting for the transient to expire. + add_action( 'added_post_meta', [ $this, 'invalidate_starter_template_cache' ], 10, 3 ); + add_action( 'updated_post_meta', [ $this, 'invalidate_starter_template_cache' ], 10, 3 ); + // Save first form creation time stamp. add_action( 'admin_init', [ $this, 'save_first_form_creation_time_stamp' ] ); add_action( 'admin_notices', [ $this, 'display_srfm_rating_notice' ] ); @@ -441,6 +460,39 @@ public static function get_form_setup_card() { return self::$setup_card_cache[ $user_id ]; } + /** + * Drop the "no imported forms" negative cache when the marker is written. + * + * Hooked to added_post_meta/updated_post_meta. Without this, a starter template + * imported after the negative cache was written would show neither the Thank You + * prompt nor the setup widget until the transient expired. + * + * Arguments are read from func_get_args() rather than declared: the hook passes + * ( $meta_id, $post_id, $meta_key ) and the meta id is never needed, so declaring + * it would leave an unused parameter that the coding-standards gate rejects. + * + * @since 2.12.4 + * @return void + */ + public function invalidate_starter_template_cache() { + $args = func_get_args(); + $post_id = isset( $args[1] ) ? (int) $args[1] : 0; + $meta_key = isset( $args[2] ) ? (string) $args[2] : ''; + + if ( self::ASTRA_SITES_IMPORT_META !== $meta_key ) { + return; + } + + // A full-site import stamps this marker on every post it creates, so narrow to + // our own post type: both features only ever query sureforms_form, and this + // avoids clearing the cache repeatedly for pages and products during an import. + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) || SRFM_FORMS_POST_TYPE !== get_post_type( $post_id ) ) { + return; + } + + delete_transient( self::NO_IMPORTED_FORMS_TRANSIENT ); + } + /** * Clear the setup-card request memo (#3031). * @@ -2862,10 +2914,13 @@ private static function compute_form_setup_card() { return null; } - // Starter Templates stamps the marker this query looks for, so without that - // plugin the meta can never exist and the query below can never match. Bail - // before running it rather than repeating it on every dashboard load. - if ( ! defined( 'ASTRA_SITES_VER' ) ) { + // Negative cache. Deliberately not a `defined( 'ASTRA_SITES_VER' )` check: + // Starter Templates defines that constant in its main plugin file, so it only + // exists while the plugin is active, yet neither its uninstall.php nor its + // deactivation hook removes the import marker. Gating on the constant would + // silently switch this feature off for the very people it targets — anyone who + // imported a starter template and then removed the one-shot import plugin. + if ( 'no' === get_transient( self::NO_IMPORTED_FORMS_TRANSIENT ) ) { return null; } @@ -2897,6 +2952,14 @@ private static function compute_form_setup_card() { ] ); + // Nothing on this site carries the marker — remember that, so the query does + // not repeat on every load. Keyed on the query result rather than on anything + // user-specific, so it is safe to share, and invalidated the moment a post is + // stamped (see invalidate_starter_template_cache()). + if ( empty( $query->posts ) ) { + set_transient( self::NO_IMPORTED_FORMS_TRANSIENT, 'no', WEEK_IN_SECONDS ); + } + foreach ( $query->posts as $post ) { $form_id = (int) $post->ID; @@ -2942,11 +3005,11 @@ private static function compute_thankyou_prompt_forms() { return []; } - // Starter Templates stamps the marker below, so on an install without that - // plugin the meta cannot exist and this query can never match. This notice - // renders on every admin screen, so bailing here is what keeps the query - // off every admin pageview on the majority of installs. - if ( ! defined( 'ASTRA_SITES_VER' ) ) { + // Negative cache — this notice renders on every admin screen, so keeping the + // query off installs that can never match is what matters here. See + // self::NO_IMPORTED_FORMS_TRANSIENT for why this is not gated on whether + // Starter Templates is still active: the marker outlives the plugin. + if ( 'no' === get_transient( self::NO_IMPORTED_FORMS_TRANSIENT ) ) { return []; } @@ -2977,6 +3040,14 @@ private static function compute_thankyou_prompt_forms() { ] ); + // Nothing on this site carries the marker — remember that, so the query does + // not repeat on every load. Keyed on the query result rather than on anything + // user-specific, so it is safe to share, and invalidated the moment a post is + // stamped (see invalidate_starter_template_cache()). + if ( empty( $query->posts ) ) { + set_transient( self::NO_IMPORTED_FORMS_TRANSIENT, 'no', WEEK_IN_SECONDS ); + } + $prompts = []; $now = time(); diff --git a/inc/rest-api.php b/inc/rest-api.php index 0b01c3273..3a5674df1 100644 --- a/inc/rest-api.php +++ b/inc/rest-api.php @@ -1431,7 +1431,7 @@ private function get_endpoints() { * @return \WP_REST_Response|\WP_Error */ 'callback' => static function ( $request ) { - /** @phpstan-ignore-next-line -- PHPStan resolves SRFM\Admin\Admin via tests/php/stubs/srfm-stubs.php (admin/ is outside its `paths`), and that generated stub predates this method. The method exists at admin/admin.php:470. */ + // @phpstan-ignore-next-line -- PHPStan resolves SRFM\Admin\Admin via tests/php/stubs/srfm-stubs.php (admin/ is outside its `paths`) and that generated stub predates this method. Real location: admin/admin.php:470. return \SRFM\Admin\Admin::get_instance()->dismiss_form_setup_card( $request ); }, 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 0d654ec15..095042cf7 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -983,12 +983,9 @@ public function test_get_form_setup_card() { $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Card Form' ] ); update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); - // Stamping the import marker simulates a Starter Templates install, so the - // ASTRA_SITES_VER gate in the query must hold too — without it the payload - // builders correctly bail before querying. - if ( ! defined( 'ASTRA_SITES_VER' ) ) { - define( 'ASTRA_SITES_VER', '4.0.0' ); - } + // The negative cache is site-wide, so clear it after stamping the marker — + // a previous test may have recorded that no imported forms exist. + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); try { Admin::reset_form_setup_card_cache(); @@ -1024,6 +1021,76 @@ public function test_reset_form_setup_card_cache() { $this->assertTrue( null === Admin::get_form_setup_card() || is_array( Admin::get_form_setup_card() ) ); } + /** + * The negative cache short-circuits both payload builders (#3031, #3030). + * + * This is the branch that keeps the marker query off installs that can never + * match it. It is deliberately a transient rather than a + * `defined( 'ASTRA_SITES_VER' )` check — Starter Templates defines that constant + * in its main plugin file, so it disappears when the plugin is deactivated, while + * the import marker it stamps stays on the forms. Gating on the constant would + * silently disable both features for exactly the people who imported a template + * and then removed the importer. + */ + public function test_negative_cache_short_circuits_the_marker_query() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $admin_user = wp_insert_user( + [ + 'user_login' => 'srfm_negcache_' . wp_rand(), + 'user_pass' => 'password', + 'user_email' => 'srfm_negcache_' . wp_rand() . '@example.com', + 'role' => 'administrator', + ] + ); + wp_set_current_user( is_wp_error( $admin_user ) ? 0 : (int) $admin_user ); + + // A form that would otherwise qualify. + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Cached Away' ] ); + update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); + + try { + // Cache says "nothing imported here" → both builders bail without querying. + set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); + Admin::reset_form_setup_card_cache(); + Admin::reset_thankyou_prompt_cache(); + $this->assertNull( Admin::get_form_setup_card(), 'The negative cache must short-circuit the setup card.' ); + $this->assertSame( [], Admin::get_thankyou_prompt_forms(), 'The negative cache must short-circuit the Thank You prompt.' ); + + // Clearing it restores the populated path, so the bail really was the cache + // and not a missing prerequisite. + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); + Admin::reset_form_setup_card_cache(); + Admin::reset_thankyou_prompt_cache(); + $card = Admin::get_form_setup_card(); + $this->assertIsArray( $card, 'With the cache cleared the qualifying form is found.' ); + $this->assertSame( $form_id, $card['id'] ); + + // Writing the marker clears the cache, so an import after the cache was + // recorded surfaces immediately instead of waiting for expiry. + set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); + Admin::get_instance()->invalidate_starter_template_cache( 0, $form_id, Admin::ASTRA_SITES_IMPORT_META ); + $this->assertFalse( get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), 'Stamping the marker must drop the negative cache.' ); + + // An unrelated meta key must leave it alone. + set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); + Admin::get_instance()->invalidate_starter_template_cache( 0, $form_id, '_srfm_unrelated_key' ); + $this->assertSame( 'no', get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), 'An unrelated meta key must not drop the cache.' ); + } finally { + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); + Admin::reset_form_setup_card_cache(); + Admin::reset_thankyou_prompt_cache(); + wp_delete_post( $form_id, true ); + wp_set_current_user( 0 ); + if ( ! is_wp_error( $admin_user ) ) { + wp_delete_user( (int) $admin_user ); + } + } + } + /** * The setup-card REST handler records a CTA click without error (#3031). * @@ -1094,12 +1161,9 @@ public function test_render_form_setup_widget() { $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Render Form' ] ); update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); - // Stamping the import marker simulates a Starter Templates install, so the - // ASTRA_SITES_VER gate in the query must hold too — without it the payload - // builders correctly bail before querying. - if ( ! defined( 'ASTRA_SITES_VER' ) ) { - define( 'ASTRA_SITES_VER', '4.0.0' ); - } + // The negative cache is site-wide, so clear it after stamping the marker — + // a previous test may have recorded that no imported forms exist. + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); try { // Positive: a qualifying form renders the full checklist. @@ -1322,12 +1386,9 @@ public function test_get_thankyou_prompt_forms() { $imported = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Imported TY' ] ); update_post_meta( $imported, '_srfm_form_confirmation', [ [ 'confirmation_type' => 'same page', 'message' => $default_message ] ] ); update_post_meta( $imported, Admin::ASTRA_SITES_IMPORT_META, 1 ); - // Stamping the import marker simulates a Starter Templates install, so the - // ASTRA_SITES_VER gate in the query must hold too — without it the payload - // builders correctly bail before querying. - if ( ! defined( 'ASTRA_SITES_VER' ) ) { - define( 'ASTRA_SITES_VER', '4.0.0' ); - } + // The negative cache is site-wide, so clear it after stamping the marker — + // a previous test may have recorded that no imported forms exist. + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); // Same default message but NOT an Astra Sites import → excluded by the gate. $plain = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Plain TY' ] ); @@ -1395,12 +1456,9 @@ public function test_render_thankyou_prompt_notice() { // message → exactly the srfm-thankyou-prompt notice is registered. $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Positive TY' ] ); update_post_meta( $form_id, Admin::ASTRA_SITES_IMPORT_META, 1 ); - // Stamping the import marker simulates a Starter Templates install, so the - // ASTRA_SITES_VER gate in the query must hold too — without it the payload - // builders correctly bail before querying. - if ( ! defined( 'ASTRA_SITES_VER' ) ) { - define( 'ASTRA_SITES_VER', '4.0.0' ); - } + // The negative cache is site-wide, so clear it after stamping the marker — + // a previous test may have recorded that no imported forms exist. + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); update_post_meta( $form_id, '_srfm_form_confirmation', From 2cc3e609f35f8e476dccb85edab884c150d5eaf4 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 17:26:48 +0530 Subject: [PATCH 64/65] test: cover invalidate_starter_template_cache() by name (#3054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check-test-coverage flagged invalidate_starter_template_cache(): the gate greps for a test named after the function, and its behaviour was covered inside test_negative_cache_short_circuits_the_marker_query() instead. Split those assertions into test_invalidate_starter_template_cache() rather than adding a stub to satisfy the grep, and added the case that was missing: the marker on a non-form post must leave the cache alone, since a full-site import stamps pages and products too and neither feature queries those. Revert-tested — stubbing the post-type narrowing to 'if ( false )' fails the test, and it passes restored. 15 affected tests pass (53 assertions); PHPCS, PHPStan and phpinsights --min-quality=100 all return 0. --- tests/unit/admin/test-admin.php | 63 +++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/tests/unit/admin/test-admin.php b/tests/unit/admin/test-admin.php index 095042cf7..0bcd74e05 100644 --- a/tests/unit/admin/test-admin.php +++ b/tests/unit/admin/test-admin.php @@ -1068,17 +1068,6 @@ public function test_negative_cache_short_circuits_the_marker_query() { $card = Admin::get_form_setup_card(); $this->assertIsArray( $card, 'With the cache cleared the qualifying form is found.' ); $this->assertSame( $form_id, $card['id'] ); - - // Writing the marker clears the cache, so an import after the cache was - // recorded surfaces immediately instead of waiting for expiry. - set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); - Admin::get_instance()->invalidate_starter_template_cache( 0, $form_id, Admin::ASTRA_SITES_IMPORT_META ); - $this->assertFalse( get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), 'Stamping the marker must drop the negative cache.' ); - - // An unrelated meta key must leave it alone. - set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); - Admin::get_instance()->invalidate_starter_template_cache( 0, $form_id, '_srfm_unrelated_key' ); - $this->assertSame( 'no', get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), 'An unrelated meta key must not drop the cache.' ); } finally { delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); Admin::reset_form_setup_card_cache(); @@ -1091,6 +1080,58 @@ public function test_negative_cache_short_circuits_the_marker_query() { } } + /** + * Stamping the import marker drops the negative cache (#3031, #3030). + * + * Without this, a starter template imported after the cache was written would + * show neither feature until the transient expired a week later. Narrowed to our + * post type on purpose: a full-site import stamps this marker on every post it + * creates, and both features only ever query sureforms_form. + */ + public function test_invalidate_starter_template_cache() { + if ( ! defined( 'SRFM_FORMS_POST_TYPE' ) ) { + $this->markTestSkipped( 'SRFM_FORMS_POST_TYPE not defined' ); + } + remove_all_actions( 'wp_insert_post_data' ); + + $admin = Admin::get_instance(); + $form_id = wp_insert_post( [ 'post_type' => SRFM_FORMS_POST_TYPE, 'post_status' => 'publish', 'post_title' => 'Marker Form' ] ); + $page_id = wp_insert_post( [ 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => 'Imported Page' ] ); + + try { + // The marker on one of our forms drops the cache. + set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); + $admin->invalidate_starter_template_cache( 0, $form_id, Admin::ASTRA_SITES_IMPORT_META ); + $this->assertFalse( + get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), + 'Stamping the marker on a form must drop the negative cache.' + ); + + // An unrelated meta key leaves it alone. + set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); + $admin->invalidate_starter_template_cache( 0, $form_id, '_srfm_unrelated_key' ); + $this->assertSame( + 'no', + get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), + 'An unrelated meta key must not drop the cache.' + ); + + // The same marker on a non-form post leaves it alone — a full-site import + // stamps pages and products too, and neither feature queries those. + set_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT, 'no', HOUR_IN_SECONDS ); + $admin->invalidate_starter_template_cache( 0, $page_id, Admin::ASTRA_SITES_IMPORT_META ); + $this->assertSame( + 'no', + get_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ), + 'The marker on a non-form post must not drop the cache.' + ); + } finally { + delete_transient( Admin::NO_IMPORTED_FORMS_TRANSIENT ); + wp_delete_post( $form_id, true ); + wp_delete_post( $page_id, true ); + } + } + /** * The setup-card REST handler records a CTA click without error (#3031). * From de3a6d72d9cd8adae2fb28762c70300f59ea2234 Mon Sep 17 00:00:00 2001 From: Vansh Kapoor <kvansh297@gmail.com> Date: Wed, 19 Aug 2026 21:28:37 +0530 Subject: [PATCH 65/65] chore: strip internal-only paths from public mirror sync --- .claude/agents/code-simplifier.md | 48 - .claude/agents/srfm-block-checker.md | 60 - .claude/commands/sureforms:investigate.md | 67 - .claude/commands/sureforms:optimize-readme.md | 170 --- .claude/commands/sureforms:sync-public.md | 299 ---- .claude/commands/sureforms:update-readme.md | 327 ----- .claude/commands/sureforms:version-bump.md | 204 --- .claude/commands/sync-release-branches.md | 96 -- .claude/settings.json | 73 - .../workflows/push-asset-readme-update.yml | 28 - .github/workflows/push-to-deploy.yml | 31 - .github/workflows/release-pr-template.yml | 41 - .github/workflows/release-tag-draft.yml | 83 -- .github/workflows/update-translations.yml | 205 --- .scripts/git-hooks/pre-commit | 106 -- ARCHITECTURE.md | 355 ----- CLAUDE.md | 180 --- COMPREHENSIVE_ANALYSIS.md | 304 ----- PRODUCT_ANALYSIS.md | 251 ---- TECHNICAL_OVERVIEW.md | 393 ------ bin/build-zip.sh | 47 - bin/checkout-and-build | 21 - bin/i18n.sh | 75 -- docs/01-getting-started/GETTING-STARTED.md | 647 --------- docs/04-backend/DATABASE-SCHEMA.md | 962 ------------- docs/04-backend/HOOKS-REFERENCE.md | 1055 --------------- docs/05-frontend/FRONTEND-GUIDE.md | 1197 ----------------- docs/FORM_MIGRATION_OVERVIEW.md | 77 -- docs/FORM_MIGRATION_PLAN.md | 458 ------- docs/wiki/AI-Form-Builder.md | 103 -- docs/wiki/Admin-Dashboard.md | 121 -- docs/wiki/Architecture-Overview.md | 294 ---- docs/wiki/Block-Editor-Controls.md | 109 -- docs/wiki/Changelog.md | 39 - docs/wiki/Contributing-Guide.md | 205 --- docs/wiki/Data-Export-Import.md | 120 -- docs/wiki/Database-Schema.md | 173 --- docs/wiki/Deployment-Guide.md | 109 -- docs/wiki/Email-Notifications.md | 86 -- docs/wiki/Environment-Configuration.md | 197 --- docs/wiki/Form-Fields-Architecture.md | 137 -- docs/wiki/Form-Submission-Flow.md | 191 --- docs/wiki/Frontend-Assets.md | 122 -- docs/wiki/Getting-Started.md | 149 -- docs/wiki/Gutenberg-Blocks.md | 129 -- docs/wiki/Home.md | 58 - docs/wiki/Payment-Integration.md | 127 -- docs/wiki/REST-API-Reference.md | 114 -- docs/wiki/State-Management.md | 109 -- docs/wiki/Testing-Guide.md | 172 --- docs/wiki/Troubleshooting-FAQ.md | 232 ---- docs/wiki/Using-WPML-With-SureForms.md | 243 ---- docs/wiki/WordPress-Hooks-Reference.md | 152 --- docs/wiki/_Footer.md | 3 - docs/wiki/_Sidebar.md | 36 - inc/abilities/CLAUDE.md | 66 - internal-docs/README.md | 160 --- internal-docs/ai-agent-guide.md | 459 ------- internal-docs/apis.md | 418 ------ internal-docs/architecture.md | 329 ----- internal-docs/codebase-map.md | 303 ----- internal-docs/coding-standards.md | 312 ----- internal-docs/faq.md | 1003 -------------- internal-docs/glossary.md | 723 ---------- internal-docs/maintenance.md | 842 ------------ internal-docs/onboarding.md | 1086 --------------- internal-docs/product-vision.md | 688 ---------- internal-docs/troubleshooting.md | 1031 -------------- internal-docs/ui-and-copy.md | 1077 --------------- tests/play/specs/CLAUDE.md | 324 ----- tests/play/specs/TODO.md | 244 ---- 71 files changed, 20455 deletions(-) delete mode 100644 .claude/agents/code-simplifier.md delete mode 100644 .claude/agents/srfm-block-checker.md delete mode 100644 .claude/commands/sureforms:investigate.md delete mode 100644 .claude/commands/sureforms:optimize-readme.md delete mode 100644 .claude/commands/sureforms:sync-public.md delete mode 100644 .claude/commands/sureforms:update-readme.md delete mode 100644 .claude/commands/sureforms:version-bump.md delete mode 100644 .claude/commands/sync-release-branches.md delete mode 100644 .claude/settings.json delete mode 100644 .github/workflows/push-asset-readme-update.yml delete mode 100644 .github/workflows/push-to-deploy.yml delete mode 100644 .github/workflows/release-pr-template.yml delete mode 100644 .github/workflows/release-tag-draft.yml delete mode 100644 .github/workflows/update-translations.yml delete mode 100644 .scripts/git-hooks/pre-commit delete mode 100644 ARCHITECTURE.md delete mode 100644 CLAUDE.md delete mode 100644 COMPREHENSIVE_ANALYSIS.md delete mode 100644 PRODUCT_ANALYSIS.md delete mode 100644 TECHNICAL_OVERVIEW.md delete mode 100644 bin/build-zip.sh delete mode 100755 bin/checkout-and-build delete mode 100644 bin/i18n.sh delete mode 100644 docs/01-getting-started/GETTING-STARTED.md delete mode 100644 docs/04-backend/DATABASE-SCHEMA.md delete mode 100644 docs/04-backend/HOOKS-REFERENCE.md delete mode 100644 docs/05-frontend/FRONTEND-GUIDE.md delete mode 100644 docs/FORM_MIGRATION_OVERVIEW.md delete mode 100644 docs/FORM_MIGRATION_PLAN.md delete mode 100644 docs/wiki/AI-Form-Builder.md delete mode 100644 docs/wiki/Admin-Dashboard.md delete mode 100644 docs/wiki/Architecture-Overview.md delete mode 100644 docs/wiki/Block-Editor-Controls.md delete mode 100644 docs/wiki/Changelog.md delete mode 100644 docs/wiki/Contributing-Guide.md delete mode 100644 docs/wiki/Data-Export-Import.md delete mode 100644 docs/wiki/Database-Schema.md delete mode 100644 docs/wiki/Deployment-Guide.md delete mode 100644 docs/wiki/Email-Notifications.md delete mode 100644 docs/wiki/Environment-Configuration.md delete mode 100644 docs/wiki/Form-Fields-Architecture.md delete mode 100644 docs/wiki/Form-Submission-Flow.md delete mode 100644 docs/wiki/Frontend-Assets.md delete mode 100644 docs/wiki/Getting-Started.md delete mode 100644 docs/wiki/Gutenberg-Blocks.md delete mode 100644 docs/wiki/Home.md delete mode 100644 docs/wiki/Payment-Integration.md delete mode 100644 docs/wiki/REST-API-Reference.md delete mode 100644 docs/wiki/State-Management.md delete mode 100644 docs/wiki/Testing-Guide.md delete mode 100644 docs/wiki/Troubleshooting-FAQ.md delete mode 100644 docs/wiki/Using-WPML-With-SureForms.md delete mode 100644 docs/wiki/WordPress-Hooks-Reference.md delete mode 100644 docs/wiki/_Footer.md delete mode 100644 docs/wiki/_Sidebar.md delete mode 100644 inc/abilities/CLAUDE.md delete mode 100644 internal-docs/README.md delete mode 100644 internal-docs/ai-agent-guide.md delete mode 100644 internal-docs/apis.md delete mode 100644 internal-docs/architecture.md delete mode 100644 internal-docs/codebase-map.md delete mode 100644 internal-docs/coding-standards.md delete mode 100644 internal-docs/faq.md delete mode 100644 internal-docs/glossary.md delete mode 100644 internal-docs/maintenance.md delete mode 100644 internal-docs/onboarding.md delete mode 100644 internal-docs/product-vision.md delete mode 100644 internal-docs/troubleshooting.md delete mode 100644 internal-docs/ui-and-copy.md delete mode 100644 tests/play/specs/CLAUDE.md delete mode 100644 tests/play/specs/TODO.md diff --git a/.claude/agents/code-simplifier.md b/.claude/agents/code-simplifier.md deleted file mode 100644 index 2dfa2039d..000000000 --- a/.claude/agents/code-simplifier.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: code-simplifier -description: Reviews recent code changes and suggests simplifications — reduces complexity, removes dead code, flattens nesting, applies DRY. -tools: Read, Glob, Grep -model: sonnet ---- - -You are a code simplification expert for a WordPress/React plugin. - -## Your Task - -Review the recently changed files and suggest concrete simplifications. Do NOT make changes — only report findings. - -## What to Look For - -### PHP -- Duplicated logic that can be extracted into a shared method -- Deeply nested conditionals that can be flattened with early returns -- Dead code (unused variables, unreachable branches, commented-out code) -- Verbose array/string operations that WordPress has helpers for -- Overly complex conditionals that can be simplified - -### JavaScript/React -- Components doing too much — can they be split? -- Duplicated JSX or logic across components -- State that could be derived instead of stored -- useEffect with dependencies that could be simplified -- Unnecessary re-renders from inline objects/functions in props - -## Output Format - -For each finding: - -``` -### file-path:line-number -**Type:** DRY | Complexity | Dead Code | Optimization -**Current:** Brief description of current code -**Suggestion:** How to simplify (1-2 sentences) -**Impact:** Low | Medium | High -``` - -End with a summary: total findings by type and priority. - -## Rules -- Only report findings with clear, concrete improvements -- No subjective style preferences — only measurable simplifications -- Skip third-party code (`inc/lib/`, `node_modules/`, `vendor/`) -- Be precise with line numbers diff --git a/.claude/agents/srfm-block-checker.md b/.claude/agents/srfm-block-checker.md deleted file mode 100644 index ec7bbf8b9..000000000 --- a/.claude/agents/srfm-block-checker.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -name: srfm-block-checker -description: Audits SureForms block render files for security issues — checks output escaping, input sanitization, ABSPATH guards, and WPCS compliance. -tools: Read, Glob, Grep -model: sonnet ---- - -You are a WordPress security reviewer specialized in Gutenberg block rendering. - -## Your Task - -Audit SureForms block PHP files for common security and quality issues. - -## Files to Check - -1. All block render files: `inc/blocks/*/block.php` -2. All field markup files: `inc/fields/*.php` -3. The base block class: `inc/blocks/base.php` - -## Checklist for Each File - -For every file, check and report: - -### Security -- [ ] **ABSPATH guard** — File starts with `if ( ! defined( 'ABSPATH' ) ) { exit; }` -- [ ] **Output escaping** — All `echo` statements use `esc_html()`, `esc_attr()`, `wp_kses_post()`, or `wp_kses()`. Flag any raw `echo $var` without escaping (note: `// phpcs:ignore` comments may indicate intentional bypass — flag these for review) -- [ ] **Attribute sanitization** — Block attributes accessed from `$attributes` are sanitized before use -- [ ] **No direct `$_GET`/`$_POST`/`$_REQUEST`** — Block render should never read superglobals directly - -### Quality -- [ ] **`@since` tag present** — Class and methods have `@since` docblock tags -- [ ] **Namespace follows convention** — Uses `SRFM\Inc\Blocks\{BlockName}` pattern -- [ ] **Extends Base** — Block class extends `SRFM\Inc\Blocks\Base` -- [ ] **Return type** — `render()` method returns `string|bool` - -## Output Format - -For each file, output: - -``` -### block-name/block.php -- PASS: ABSPATH guard present -- WARN: Line 33 — raw echo with phpcs:ignore, verify markup() output is pre-escaped -- PASS: No superglobals used -- FAIL: Missing @since tag on render() method -``` - -End with a summary table: - -| Block | Security | Quality | Issues | -|-------|----------|---------|--------| -| input | WARN | FAIL | 2 | -| email | PASS | PASS | 0 | - -## Important - -- Be precise — include line numbers for every issue -- Distinguish FAIL (must fix) from WARN (review needed) -- Do NOT suggest code changes — only report findings -- Check ALL block files, not just a sample diff --git a/.claude/commands/sureforms:investigate.md b/.claude/commands/sureforms:investigate.md deleted file mode 100644 index d171756ec..000000000 --- a/.claude/commands/sureforms:investigate.md +++ /dev/null @@ -1,67 +0,0 @@ -# Investigate Issue - -Investigate a reported issue using parallel subagents for speed. - -## Input - -$ARGUMENTS — GitHub issue URL, Jira ticket ID, or a description of the issue. - -If no arguments provided, stop and ask: "Please provide an issue URL, Jira ticket ID, or describe the issue." - -## Step 1 — Read the Issue - -- If a GitHub URL: use `gh issue view` to read the issue -- If a Jira ticket: use the Jira MCP tools to read the ticket -- If a description: use the provided text directly - -Extract: title, description, steps to reproduce, expected vs actual behavior, screenshots, labels. - -## Step 2 — Classify - -Determine the type: -- **Bug** — something is broken, unexpected behavior, error, regression -- **Feature** — new functionality requested -- **Improvement** — enhancement to existing functionality - -Tell the user: "This looks like a **[type]**. Proceeding with [investigation/planning]." - -## Step 3 — Investigate with Subagents - -Use subagents to parallelize the investigation: - -### For Bugs: -Launch these subagents in parallel: -1. **Code Search Agent** — Search the codebase for files related to the bug (grep for keywords, function names, error messages, related hooks/filters) -2. **Test Coverage Agent** — Check if there are existing tests covering this area, identify gaps -3. **Impact Analysis Agent** — Trace all usages of the affected code to understand blast radius - -Once all agents report back, synthesize findings: -- Present the probable root cause with file path and line number -- Show which other areas might be affected -- Suggest a fix with a clear explanation -- Ask the user: "Should I apply this fix?" -- If yes — apply the fix, run linters, and suggest running relevant tests - -### For Features: -1. Enter plan mode -2. Launch subagents in parallel: - - **Pattern Discovery Agent** — Find similar existing features in the codebase to follow the same patterns - - **Impact Analysis Agent** — Identify all files that will need changes -3. Use findings to outline implementation steps -4. Present the plan for approval - -### For Improvements: -1. Launch subagents in parallel: - - **Code Search Agent** — Read the relevant existing code - - **Impact Analysis Agent** — Trace dependencies to understand what might break -2. Suggest the minimal changes needed -3. Ask the user: "Should I implement these changes?" -4. If yes — apply changes and run linters - -## Rules -- Always use subagents for investigation to maximize speed -- Show your reasoning — which files you checked and why -- Be precise with file paths and line numbers -- For bugs, prioritize finding the root cause over applying a quick patch -- Never make changes without asking first -- After any code change, run the verification checklist from CLAUDE.md diff --git a/.claude/commands/sureforms:optimize-readme.md b/.claude/commands/sureforms:optimize-readme.md deleted file mode 100644 index d7721ed71..000000000 --- a/.claude/commands/sureforms:optimize-readme.md +++ /dev/null @@ -1,170 +0,0 @@ -# SureForms readme.txt search-ranking optimizer - -Optimize the three readme.txt header fields that WordPress.org search actually scores — the -plugin **title**, the **short description**, and the **Tags** line — so SureForms ranks better for -its target keywords, without touching anything release-managed and without breaking WordPress.org -guidelines. - -This command **only rewrites copy**. It never bumps a version, never edits `Stable tag`, and never -invents facts. - -## Arguments - -Parse from: `$ARGUMENTS` - -- `keywords` — optional, comma-separated. The search terms to optimize for, most important first. - Default (SureForms' live priorities): `form, contact form, form builder, payment form, survey`. -- `--apply` — optional. Write the changes to `readme.txt`. Without it, run in **dry-run**: print the - proposed header and the reasoning, change nothing. - -Default is dry-run. The title is the plugin's public display name, so always show the before/after -and get a "yes" from the user before writing it, even with `--apply`. - -## Working directory - -Run from the sureforms plugin root — the directory containing `sureforms.php` and `readme.txt`. - ---- - -## How WordPress.org scores a search result (the facts this command relies on) - -Source of truth — read it if a rule below is ever in doubt: -`https://github.com/WordPress/wordpress.org/blob/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-search.php` - -Final score = **where the term matches** × **six quality signals**. - -**Where the term matches (per-field weight):** - -| Field | Weight | Editable here? | -|---|---|---| -| Plugin name (a whole word) **or** slug | 5 | Title: yes. Slug (`sureforms`): **no — immutable** | -| Author name | 3 | No | -| Term as a substring inside a title word (`form` in `SureForms`, via the `title.engram` analyzer) | 2 | Indirect | -| Short description **or** Tags (`excerpt`, `description`, `tags`) | 2 | **Yes — this is the main lever** | -| Anywhere else in the readme (description body, FAQ, features) | 0.1 | Not worth optimizing | - -Search analyzers split the **slug on hyphens**, so `contact-form-7` indexes as `contact` · `form` · -`7` — each a whole-word ×5 match. `sureforms` is one indivisible token and can never produce a -standalone `form`, so it only ever earns the ×2 `title.engram` substring credit. The slug is -permanent on WordPress.org; do not plan around changing it. - -**The six quality signals (multipliers) — none live in these three fields**, so this command never -touches them. Kept here only so the analysis can explain *why* a readme edit can't move quality, and -so a stale `Tested up to` gets flagged (not changed). Verbatim `function_score` params from the -[ranking code](https://github.com/WordPress/wordpress.org/blob/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-search.php#L313-L381): - -| Signal | Config | Rule of thumb | -|---|---|---| -| Last updated (`plugin_modified`) | decay, origin today, offset 180d, scale 360d, decay 0.5 | free for 6 months; ~×0.5 at ~18 months | -| Tested up to (`tested`) | decay, origin current WP, offset 0.1, scale 0.4, decay 0.6 | half a major version behind ≈ ×0.6 | -| Active installs (`active_installs`) | `log2p`, factor 0.375, missing 1 | log-scaled; 10k→100k ≈ 100k→1M | -| Under-1M penalty | decay, filter ≤ 1,000,000, origin 1M, scale 900k, decay 0.75 | extra ~×0.85 handicap below 1M installs | -| Support resolved (`support_threads_resolved`) | `log2p`, factor 0.25, missing 0.5 | resolved **percentage** scored directly | -| Star rating (`rating`) | `sqrt`, factor 0.25, missing 2.5 | only the **average** counts, never the review count | - -**The three consequences that drive every rewrite below:** - -1. The slug is `sureforms` (one word), so a search for `form` never gets the 5-point whole-word name - credit. The closest recoverable credit is a **standalone** high-value word in the *title* - (`Contact Form Builder` → `form` is its own word), which beats the 2-point substring credit from - `SureForms` alone. -2. Score is **concentrated per field** (Elasticsearch length-normalizes each field). A shorter title - and a tight short description give each keyword a larger share; padding words dilute *every* - keyword in the field. Past a point, adding a keyword to the title *lowers* the score of the ones - already there — keyword-stuffing the title is actively counterproductive. -3. For a **multi-word** target (`contact form`, `form builder`, `payment form`), position and - adjacency matter, not just presence. The winners hold the phrase as **consecutive tokens early in - a short field** — e.g. `Contact Form` as tokens 2–3 of a 4-token title beats the same words - buried mid-way through a 14-token one. This is the single factor that lets a 20k-install, 2.7★ - plugin outrank a 500k-install, 4.9★ one for "contact form". - ---- - -## Hard constraints — never cross these - -These protect the listing from being flagged or rejected. A rewrite that violates any of them is -worse than no rewrite. - -- **Short description: 150 characters max.** WordPress.org truncates past that. Count it. -- **Tags: only the first 5 are indexed.** Extra tags are dead weight — never list more than 5. -- **No competitor trademarks as keywords.** Never add `wpforms`, `gravity forms`, `ninja forms`, - `contact form 7`, `elementor`, `jetpack`, etc. to the title, tags, or short description. This is a - direct WordPress.org guideline violation and risks removal. -- **No keyword stuffing.** Repeating a keyword doesn't stack — the field is scored once per term. - `Form Builder, Form Maker, Form Creator, Forms` is stuffing; write natural phrases a human reads. -- **Only claim real features.** Every keyword must map to a shipped capability. Survey/Quiz/Calculator - are Business-tier — keep them phrased the way the current short description does (e.g. "in SureForms - Business") so the claim stays honest. Never add a keyword for a feature SureForms doesn't have. -- **Never edit** `Stable tag`, `Requires at least`, `Requires PHP`, `Contributors`, `License`, or the - `Plugin Name:` header in `sureforms.php`. If `Tested up to` is behind the current WordPress - release, only *report* it — do not change it (it must reflect a real tested version). -- **Keep the `=== ... ===` and header syntax intact** — WordPress.org's parser is strict. - ---- - -## Steps - -### 1 — Read the current header - -Read the top block of `readme.txt` (through the short-description line). Capture the current title, -short description (with its character count), and tags. - -### 2 — Score the current fields - -For each target keyword, note where it currently lands (whole word in title = 5, substring = 2, in -short description / tags = 2, or absent). For **multi-word** keywords, also record whether the words -are adjacent and how early they sit — a phrase split apart or buried late is a weak match even if all -its words are present. Count the title's token length: a long title (say > ~9 words) is itself a -finding, because it dilutes every keyword in the ×5 field. List the gaps — a target keyword at 0.1 -weight, absent, non-adjacent, or stranded at the end of a long title is the opportunity. - -### 3 — Propose the rewrite - -Produce candidate values for the three fields, applying the two consequences above: - -- **Title** — front-load the highest-value keywords as **standalone words**, drop filler, keep it - reading like a real product name. Aim for ≤ ~9 words. Apply consequences 2 and 3: - - Put the **single most important target early** and as its own word (`Form Builder`, not only - `SureForms`). - - For a multi-word target, keep its words **adjacent and near the front** — e.g. lead with - `SureForms – Contact Form Builder` so `Contact Form` sits in tokens 2–3, then append the - lower-priority terms. Do not scatter the phrase across the title or repeat it. - - Stop adding keywords once the title reads like stuffing — each extra token shrinks the share of - the ones already there. Example shape: - `SureForms – Contact Form Builder, Payment Form, Survey, Quiz & Calculator`. -- **Short description** — one natural sentence, ≤ 150 chars, carrying the top 2–3 keywords that the - title couldn't. Report the exact character count. -- **Tags** — exactly the 5 highest-value distinct keywords, no overlap-for-overlap's-sake, no - trademarks. - -For **each** field, give a one-line rationale tied to the scoring model (which keyword moved from -which weight to which, or why a word was cut). - -### 4 — Show before/after - -Print a compact before → after for all three fields, the character count for the short description, -and any constraint check that mattered (e.g. "tags trimmed to 5", "short desc = 143/150"). If -`Tested up to` looks stale versus the current WordPress release, note it here as a separate -recommendation — do not fold it into the edit. - -### 5 — Apply (only with `--apply` and after title confirmation) - -On confirmation, use `Edit` to replace exactly the title line, the short-description line, and the -`Tags:` line in `readme.txt`. Change nothing else. Re-read the three lines and confirm the header -still parses (syntax intact, short desc ≤ 150, ≤ 5 tags). - -### 6 — Report - -Summarize what changed and what was deliberately left alone (versions, quality signals). Remind the -user that title/short-description/tags are also worth mirroring wherever the marketing site controls -the same listing, and that the quality-signal wins (resolving support threads, crossing 1M installs, -keeping `Tested up to` current) live outside this file. - ---- - -## Notes - -- Dry-run first. Only pass `--apply` once the copy reads well to a human — search reads it, but so do - buyers. -- This is intentionally a copy tool. If a rewrite ever tempts you to change a version or a quality - signal to "help the score", stop — that's out of scope and, for `Tested up to`, dishonest. diff --git a/.claude/commands/sureforms:sync-public.md b/.claude/commands/sureforms:sync-public.md deleted file mode 100644 index 08f2bba4c..000000000 --- a/.claude/commands/sureforms:sync-public.md +++ /dev/null @@ -1,299 +0,0 @@ ---- -allowed-tools: Bash(git:*), Bash(gh:*), Bash(rm:*), Bash(rmdir:*), Bash(mktemp:*), Bash(echo:*), Bash(cd:*), Bash(test:*) -description: Sync private master to the sureforms-public mirror, stripping internal-only paths in one commit ---- - -# SureForms — Sync to Public Mirror - -Sync `brainstormforce/sureforms@master` (private, this repo) to `brainstormforce/sureforms-public@master` (public WordPress.org-facing mirror), stripping internal-only paths. The sync branch is bulk re-signed (verified signatures) and capped with a merge commit against the mirror so the public PR diff stays clean. - -This skill is the **only sanctioned way** to sync the public mirror. Running raw `git push mirror …` skips the strip and re-leaks internal artifacts. - -## Stripped paths (single source of truth) - -Edit this list when the leak surface changes — there is no other place to update. - -``` -.claude -.scripts/git-hooks -internal-docs -docs -CLAUDE.md # ALL CLAUDE.md at ANY depth (root + nested, e.g. inc/abilities/, tests/play/specs/) — stripped via `git ls-files '*CLAUDE.md'` (matches the root file too), NOT just the root path -ARCHITECTURE.md -COMPREHENSIVE_ANALYSIS.md -PRODUCT_ANALYSIS.md -TECHNICAL_OVERVIEW.md -tests/play/specs/TODO.md -.github/workflows/push-to-deploy.yml -.github/workflows/push-asset-readme-update.yml -.github/workflows/release-tag-draft.yml -.github/workflows/update-translations.yml -.github/workflows/release-pr-template.yml -bin/build-zip.sh -bin/checkout-and-build -bin/i18n.sh -``` - -These paths must NOT appear on the public mirror. They legitimately exist on private `master` and stay there (internal release CI, AI tooling, internal team wiki, internal dev docs under `docs/`). - -> **README.md is the ONLY markdown doc that should appear in the public PR diff.** After stripping, sanity-check with `git ls-files '*.md'` — anything beyond `README.md`, third-party `inc/lib/**` readmes, `modules/gutenberg/readme.md`, and `tests/play/README.md` is a likely leak. (A prior sync leaked `inc/abilities/CLAUDE.md`, `tests/play/specs/CLAUDE.md`, and the whole `docs/` tree because the strip matched only the root `CLAUDE.md`.) - -## Preconditions - -Working directory: any worktree of this repo. - -Required remotes: -- `origin` → `https://github.com/brainstormforce/sureforms` (private) -- public-mirror remote → `https://github.com/brainstormforce/sureforms-public` (public). May be named `mirror` **or** `public` — detect with `git remote -v` and use whichever points at `sureforms-public`. Examples below use `$MIRROR`. - -Verify with `git remote -v`. Abort if neither a `mirror` nor `public` remote points at `sureforms-public`. - -### ⚠️ `sureforms-public` ruleset constraints (READ FIRST) - -The public repo enforces a branch ruleset (since 2026-06-01) that the previous version of this skill violated. This flow is built around them: - -1. **Every commit needs a *verified* signature.** Signing is not enough — GitHub must mark it **Verified**, which requires BOTH the signing key registered on the pushing account as a **Signing Key** (an *Authentication* key does NOT count) AND the **committer email** verified on that account. **The skill uses the identity of whoever runs it** — your local `git config user.name` / `user.email` / `user.signingkey`. Before running, confirm: your `user.signingkey` points at an SSH public-key file (`*.pub`, since `gpg.format=ssh`) that is registered as a **Signing Key** on *your* GitHub account, and your `user.email` is a **verified** email on that same account. Hardware-backed keys (e.g. Secretive) verify fine but prompt for a tap **per commit**, so they cannot bulk-sign ~150 commits — use an on-disk passphrase-less key for the bulk re-sign. -2. **`sync/master` is force-push protected.** Push each sync to a **fresh** branch `sync/master-<YYYYMMDD>` (`-v2`, `-v3`… if re-pushing the same day — reusing a branch makes the ruleset re-evaluate the mirror's own unsigned ancestors and reject). -3. **Claude's auto-mode guardrail blocks the agent from pushing to the public mirror.** The agent prepares everything and hands the user the exact `git push` to run themselves. `gh pr` / `gh api` ARE agent-allowed. - -## Instructions - -Follow steps sequentially. If any step fails, jump to **Error Recovery**. - -### Step 1: Record current state - -```bash -ORIGINAL_BRANCH=$(git rev-parse --abbrev-ref HEAD) -HAD_STASH=false -if [ -n "$(git status --porcelain)" ]; then - git stash push -m "sureforms-sync-public auto-stash" - HAD_STASH=true -fi -``` - -### Step 2: Detect the mirror remote + signing identity, then fetch - -Detect the public-mirror remote (named `mirror` or `public`) once, and capture the running user's signing identity. These vars are used throughout: - -```bash -MIRROR=$(git remote -v | awk '/sureforms-public(\.git)?[[:space:]]/{print $1; exit}') -[ -n "$MIRROR" ] || { echo "No remote points at sureforms-public — add one and retry"; exit 1; } - -# Identity of whoever runs the skill (must satisfy the ruleset — see Preconditions) -SIGN_NAME=$(git config user.name) -SIGN_EMAIL=$(git config user.email) -SIGN_KEY=$(git config user.signingkey) # expected: path to an SSH *.pub registered as a Signing Key -[ -n "$SIGN_NAME" ] && [ -n "$SIGN_EMAIL" ] && [ -n "$SIGN_KEY" ] || { echo "git user.name/user.email/user.signingkey must all be set"; exit 1; } - -git fetch origin master -git fetch "$MIRROR" master sync/master 2>/dev/null || git fetch "$MIRROR" master -``` - -### Step 3: Detect no-op - -```bash -PRIVATE_TIP=$(git rev-parse origin/master) -PUBLIC_TIP=$(git rev-parse "$MIRROR/master") -``` - -If `PRIVATE_TIP` == `PUBLIC_TIP`, report "Public mirror is already up to date with private master — nothing to sync." Run **Step 8 cleanup** and exit. - -Capture the upstream commit range and count for reporting: - -```bash -COMMIT_COUNT=$(git rev-list --count "$PUBLIC_TIP..$PRIVATE_TIP") -``` - -### Step 4: Stage cleaned tree on a temp worktree - -Use a temp worktree so the developer's current working tree is never modified. - -```bash -WORKTREE=$(mktemp -d)/srfm-sync-public -git worktree add "$WORKTREE" "$PRIVATE_TIP" -cd "$WORKTREE" -``` - -### Step 5: Strip internal paths idempotently - -For each path in the **Stripped paths** list above, only act if it exists: - -```bash -for p in \ - .claude \ - .scripts/git-hooks \ - internal-docs \ - docs \ - ARCHITECTURE.md \ - COMPREHENSIVE_ANALYSIS.md \ - PRODUCT_ANALYSIS.md \ - TECHNICAL_OVERVIEW.md \ - tests/play/specs/TODO.md \ - .github/workflows/push-to-deploy.yml \ - .github/workflows/push-asset-readme-update.yml \ - .github/workflows/release-tag-draft.yml \ - .github/workflows/update-translations.yml \ - .github/workflows/release-pr-template.yml \ - bin/build-zip.sh \ - bin/checkout-and-build \ - bin/i18n.sh \ -; do - if [ -e "$p" ]; then - git rm -r --quiet "$p" - fi -done - -# Strip ALL CLAUDE.md at any depth (root + nested) — NOT just the root path. -# No pipe-to-while: a subshell would swallow a failing `git rm`. These paths never -# contain spaces, so word-splitting the list is safe. -CLAUDE_FILES=$(git ls-files '*CLAUDE.md') -if [ -n "$CLAUDE_FILES" ]; then - git rm --quiet $CLAUDE_FILES -fi - -# Remove now-empty .scripts directory if applicable -if [ -d .scripts ] && [ -z "$(ls -A .scripts 2>/dev/null)" ]; then - rmdir .scripts -fi - -# Sanity check (FAIL-CLOSED): README.md must be the ONLY non-third-party markdown -# doc left. This control already leaked once — a detected anomaly must HALT the -# sync, not just warn. The check runs in the temp worktree before any push, so -# aborting here means nothing internal reaches the mirror. -LEAKS=$(git ls-files '*.md' | grep -vE '^(README\.md|inc/lib/.*|modules/gutenberg/readme\.md|tests/play/README\.md|inc/abilities/ABILITIES\.md)$') || true -if [ -n "$LEAKS" ]; then - printf 'ABORT: unexpected markdown would be published:\n%s\n' "$LEAKS" - exit 1 -fi -echo "OK: only README.md + known readmes" -``` - -> If the sanity check aborts (`exit 1`), treat it as a failed step: jump to **Error Recovery** to tear down the temp worktree and restore the developer's branch/stash before investigating which path needs adding to the **Stripped paths** list. - -### Step 6: Commit the strip, then bulk re-sign ALL commits - -First commit the strip (committer is the running user — must be the verified email, see ruleset constraints): - -```bash -STRIPPED=false -if ! git diff --cached --quiet; then - STRIPPED=true - STRIPPED_PATHS=$(git diff --cached --name-only | tr '\n' ' ') - git commit -m "chore: strip internal-only paths from public mirror sync" -fi -``` - -Then re-sign **every** commit new to the mirror so they all carry verified signatures. Use `filter-branch` (it reuses each commit's tree + parents and only adds a signature → zero conflicts; `rebase --rebase-merges` re-merges and hits conflicts): - -> **Note:** this rewrites the **committer** of all re-signed commits to `$SIGN_EMAIL` (the original **author** of each commit is preserved). That committer/attribution change on the mirror is intentional — it's what lets the running user's registered key produce verified signatures. - -```bash -BASE=$(git merge-base "$MIRROR/master" "$PRIVATE_TIP") -FILTER_BRANCH_SQUELCH_WARNING=1 git \ - -c gpg.format=ssh -c user.signingkey="$SIGN_KEY" \ - filter-branch -f \ - --env-filter "export GIT_COMMITTER_NAME=\"$SIGN_NAME\"; export GIT_COMMITTER_EMAIL=\"$SIGN_EMAIL\"" \ - --commit-filter "git -c gpg.format=ssh -c user.signingkey=\"$SIGN_KEY\" commit-tree -S \"\$@\"" \ - -- "$BASE..HEAD" -``` - -### Step 7: Cap with a merge commit on the mirror, push to a fresh branch - -Cap the branch with a merge commit whose **first parent is `$MIRROR/master`**. This makes GitHub diff the PR against `$MIRROR/master` (which has no internal files), so the public PR shows **only real upstream changes — no internal-file deletions**. - -```bash -SIGNED_TIP=$(git rev-parse HEAD) -MERGE=$(git -c gpg.format=ssh -c user.signingkey="$SIGN_KEY" \ - -c user.name="$SIGN_NAME" -c user.email="$SIGN_EMAIL" \ - commit-tree -S "$(git rev-parse HEAD^{tree})" -p "$MIRROR/master" -p "$SIGNED_TIP" \ - -m "Sync master from upstream") -BRANCH="sync/master-$(date +%Y%m%d)" -git branch -f "$BRANCH" "$MERGE" -``` - -Then **the user runs the push** (the agent's push to the public mirror is blocked by Claude's guardrail). Push to a **fresh** branch — never `sync/master` (force-protected), and never reuse an existing branch (its prior value makes the ruleset re-evaluate the mirror's unsigned ancestors): - -```bash -git push "$MIRROR" "$BRANCH:refs/heads/$BRANCH" -``` - -If the push is rejected for "verified signatures", isolate before re-signing ~150 commits: push a single test commit signed the same way to a throwaway branch and confirm it's accepted (and `gh api .../commits/<sha> -q .commit.verification.verified` is `true`). - -### Step 8: Open or update the sync PR - -Check whether an open PR already exists for the current sync branch → `master` on `brainstormforce/sureforms-public`: - -```bash -EXISTING_PR=$(gh pr list -R brainstormforce/sureforms-public \ - --base master --head "$BRANCH" --state open \ - --json number -q '.[0].number') -``` - -- **If `EXISTING_PR` is non-empty:** comment a refresh note: - - ```bash - gh pr comment "$EXISTING_PR" -R brainstormforce/sureforms-public \ - --body "Refreshed: synced \`$COMMIT_COUNT\` commit(s) from private master ($PUBLIC_TIP..$PRIVATE_TIP). Strip applied: $STRIPPED." - ``` - -- **If `EXISTING_PR` is empty:** open a new PR. - - Title: `Sync master from upstream` - - Body: upstream commit range, count, strip status, and a "## Highlights" section (`git log --oneline "$PUBLIC_TIP..$PRIVATE_TIP"`). Note that the diff is computed against `public/master` (merge-cap) so no internal files appear. - - ```bash - gh pr create -R brainstormforce/sureforms-public \ - --base master --head "$BRANCH" \ - --title "Sync master from upstream" \ - --body "$PR_BODY" - ``` - - Close/delete any superseded sync branch + PR: - - ```bash - gh pr close <OLD_PR> -R brainstormforce/sureforms-public - gh api -X DELETE repos/brainstormforce/sureforms-public/git/refs/heads/<OLD_BRANCH> - ``` - -### Step 9: Tear down the temp worktree - -```bash -cd - -git worktree remove --force "$WORKTREE" -``` - -### Step 10: Restore developer state - -```bash -git checkout "$ORIGINAL_BRANCH" -if [ "$HAD_STASH" = "true" ]; then - git stash pop -fi -``` - -## Output to user - -Report at the end: - -- Upstream range: `<old-mirror-sha>..<new-mirror-sha>` (`$COMMIT_COUNT` commits) -- Whether the strip commit was created (`$STRIPPED`); if true, list the stripped paths -- PR URL — new or existing - -## Error Recovery - -If any step fails: - -1. **`cd` back to the original repo dir** if currently inside `$WORKTREE`. -2. **Remove temp worktree** if it was created: `git worktree remove --force "$WORKTREE"` (ignore errors). -3. **Restore branch and stash** as in Step 10. -4. Surface the failing command and its error to the user — do not retry blindly. - -Common failure modes: - -- **Push rejected, "Commits must have verified signatures"** — a commit is signed by an unregistered key or committed under an unverified email. Confirm your `git config user.signingkey` (the `*.pub`) is registered as a **Signing Key** (not Authentication) on your GitHub account and your `git config user.email` is a verified email there. Test with a single throwaway commit before re-signing ~150. -- **Push rejected, "Cannot force-push to this branch"** — you targeted `sync/master`; use a fresh `sync/master-<date>` branch instead. -- **Push rejected naming a few commits already on `master`** — you reused/updated an existing branch; push to a brand-new branch name so the ruleset only evaluates the new commits. -- **Agent push "denied by auto mode classifier"** — expected; the user must run the `git push` to the mirror themselves. -- **`gh pr create` fails with "PR already exists"** — Step 8 detection missed a draft PR. Re-run Step 8 with `--state all` and reuse / reopen the existing PR. -- **No mirror remote** — add it and re-run: `git remote add public https://github.com/brainstormforce/sureforms-public`. diff --git a/.claude/commands/sureforms:update-readme.md b/.claude/commands/sureforms:update-readme.md deleted file mode 100644 index b3d9d8a6f..000000000 --- a/.claude/commands/sureforms:update-readme.md +++ /dev/null @@ -1,327 +0,0 @@ ---- -description: Audit and update the WordPress.org readme.txt — analyze new features, research competitors, draft changes, and create a PR ---- - -# SureForms readme.txt Update - -Comprehensive audit and update of the `readme.txt` (and `README.md`) for the WordPress.org listing. - -## Arguments - -Parse from: $ARGUMENTS - -Expected format: `[version] [--full]` - -- `version` — optional. Baseline version to analyze changes since (e.g., `2.5.0`). If not provided, auto-detect from the most recent `= X.X.X` changelog header in `readme.txt`. -- `--full` — optional flag. Perform a full rewrite of all sections instead of an incremental update. - -If no arguments are given, auto-detect the baseline and proceed with incremental mode. - -## Working Directory - -All commands and file paths are relative to the sureforms plugin root — the directory containing `sureforms.php`. - ---- - -## Phase 1: Analyze What's New - -### Step 1.1 — Determine Baseline Version - -- If `version` argument was provided, use that as the baseline. -- Otherwise, read the `== Changelog ==` section of `readme.txt`, extract the most recent version header (`= X.X.X - ... =`), and use that version as the baseline. -- Resolve the git tag: `v<version>` (e.g., `v2.5.0`). Verify it exists with `git tag -l "v<version>"`. -- If the tag does not exist, list available tags (`git tag --sort=-version:refname | head -10`) and ask the user to pick one. - -### Step 1.2 — Gather Changes Since Baseline - -Launch **3 Explore subagents in parallel** (single message, 3 Agent tool calls): - -**Agent 1 — Git History Analysis:** -- Run `git log v<baseline>..HEAD --oneline` to get all commits since the baseline. -- Categorize commits: new features, improvements, bug fixes, refactors. -- Focus on commits touching: `inc/blocks/`, `inc/fields/`, `inc/payments/`, `inc/ai-form-builder/`, `modules/`, `src/blocks/`, `inc/page-builders/`. -- Report: list of significant user-facing changes with commit hashes and affected areas. - -**Agent 2 — Free Codebase Feature Scan:** -- List all blocks in `inc/blocks/` — compare against the readme's "Input Fields" and feature bullets. -- Check `inc/payments/` for payment providers. -- Check `inc/ai-form-builder/` for AI feature updates. -- Check `modules/` for any new modules. -- Check `inc/global-settings/` for new settings sections. -- Check `inc/rest-api.php` for new REST endpoints. -- Check `inc/page-builders/` for page builder compatibility additions. -- Report: features present in code but missing from readme. - -**Agent 3 — Pro Codebase Feature Scan:** -- Check `../sureforms-pro/inc/pro/native-integrations/integrations/` — list ALL integration JSON files and compare against the readme's integration list. -- Check `../sureforms-pro/inc/blocks/` for pro-only blocks. -- Check `../sureforms-pro/inc/pro/` subdirectories for pro features (conversational-form, save-resume, signature, zapier, etc.). -- Check `../sureforms-pro/inc/extensions/` for conditional logic, field-restrictions, etc. -- If `../sureforms-pro/` does not exist, skip this agent and warn: "Pro plugin not found. Only free features will be analyzed." -- Report: pro features/integrations present in code but missing from readme. - -### Step 1.3 — Present Gap Analysis - -Merge all agent results and present a table: - -``` -┌─────────────────────────────────────┬────────┬──────────────────────────────┐ -│ Area │ Status │ Details │ -├─────────────────────────────────────┼────────┼──────────────────────────────┤ -│ Free field types match readme │ ✅/❌ │ Code: N, Readme: M │ -│ Pro blocks mentioned │ ✅/❌ │ Missing: ... │ -│ Integration list up to date │ ✅/❌ │ Missing: ... │ -│ Pro features all listed │ ✅/❌ │ Missing: ... │ -│ Payment providers accurate │ ✅/❌ │ │ -│ Page builder compat listed │ ✅/❌ │ │ -│ "Tested up to" WP version │ ✅/❌ │ Readme: X.X, Current: Y.Y │ -│ New features since v<baseline> │ ℹ️ │ N features found │ -└─────────────────────────────────────┴────────┴──────────────────────────────┘ -``` - -Tell the user: "Phase 1 complete. Found **N gaps** and **M new features** to incorporate. Proceeding to competitor research." - ---- - -## Phase 2: Competitor & Market Research - -### Step 2.1 — Research Competitor READMEs - -Use **WebSearch** to run these searches in parallel: - -1. `"WPForms" site:wordpress.org/plugins description features` -2. `"Gravity Forms" site:wordpress.org/plugins description features` -3. `"Fluent Forms" site:wordpress.org/plugins fluentform features` -4. `"Formidable Forms" site:wordpress.org/plugins description features` -5. `"Contact Form 7" site:wordpress.org/plugins description` -6. `"WordPress.org readme.txt best practices 2025 2026"` - -For each competitor, use **WebFetch** on the top result URL if needed to extract: -- How they structure feature lists -- Marketing language and benefit-focused copy -- How they distinguish free vs pro features -- FAQ structure and common questions -- Trust signals (install counts, star ratings, testimonials) - -### Step 2.2 — Present Research Summary - -Show a comparison table: - -``` -Feature Highlighted by Competitors │ SureForms Has It? │ In Readme? -──────────────────────────────────────┼───────────────────┼────────── -Conditional Logic │ ✅ (Pro) │ ✅/❌ -File Upload │ ✅ (Pro) │ ✅/❌ -Drag & Drop Builder │ ✅ (Free) │ ✅/❌ -... │ │ -``` - -Also note: -- SEO-relevant keywords competitors use that SureForms is missing. -- Structural patterns that work well (comparison tables, benefit-focused headers). -- Any WordPress.org formatting trends. - -Tell the user: "Phase 2 complete. Ready to draft the update. Shall I proceed?" - -**⏸️ WAIT for user confirmation before proceeding to Phase 3.** - ---- - -## Phase 3: Draft the Update - -### Step 3.1 — Determine Scope - -- If `--full` flag was passed: draft ALL sections from scratch. -- Otherwise: draft only sections that need changes based on Phase 1 and Phase 2 findings. - -### Step 3.2 — Draft Each Section - -For each section that needs updating, present in this format: - -``` -━━━ SECTION: [Section Name] ━━━ - -── CURRENT ── -[Current text from readme.txt, abbreviated if very long] - -── PROPOSED ── -[New text] - -── CHANGES ── -• Added: [what was added] -• Removed: [what was removed, if any] -• Reworded: [what was reworded and why] -``` - -Sections to evaluate (in order): - -1. **Plugin header** — Stable tag, Tested up to, Tags (optimize for WordPress.org search) -2. **Short description** — Must be under 150 characters. Make it compelling and keyword-rich. -3. **Long description** — Feature bullets, AI section, payment section, field types list -4. **Premium features section** — Integration list, pro-only features, pro field types -5. **FAQ** — Add questions for new features, update outdated answers -6. **3rd Party Services** — Add any new external services used -7. **Compatibility lists** — Themes and plugins - -### Step 3.3 — WordPress.org Compliance Check - -Verify the draft against WordPress.org readme standards: -- ✅ Short description is under 150 characters -- ✅ No disallowed HTML in description -- ✅ `== Changelog ==` section exists and is properly formatted -- ✅ `== Frequently Asked Questions ==` uses correct `= Question =` format -- ✅ No broken markdown that WordPress.org would render incorrectly -- ✅ Stable tag matches the version in the main plugin file - -### Step 3.4 — Present Full Draft - -Present all drafted sections together with a summary: - -``` -📋 Readme Update Summary -───────────────────────────────────── -Sections modified: N -Lines added: +X -Lines removed: -Y -New features listed: Z -New integrations: W -New FAQ entries: Q -WP.org compliance: ✅ All checks pass -``` - -Tell the user: "Please review the draft above. You can: -1. **Approve** — proceed to apply changes and create PR -2. **Request edits** — tell me what to change -3. **Abort** — cancel the update" - -**⏸️ WAIT for explicit user approval. Do NOT proceed without it.** - ---- - -## Phase 4: User Review & Iteration - -This phase is a loop: - -1. If user **requests edits** → apply them to the draft and re-present the affected sections. Ask again for approval. -2. If user **approves** → proceed to Phase 5. -3. If user **aborts** → stop and report "Readme update cancelled. No changes were made." - ---- - -## Phase 5: Apply & Create PR - -### Step 5.1 — Create Branch - -```bash -git fetch origin -git checkout dev -git pull origin dev -git checkout -b chore/update-readme -``` - -If `chore/update-readme` already exists, append a date suffix: `chore/update-readme-YYYYMMDD`. - -### Step 5.2 — Apply Changes - -Edit `readme.txt` with the approved draft changes. Apply section by section — do NOT rewrite sections that weren't modified. - -### Step 5.3 — Regenerate README.md - -```bash -npx grunt readme -``` - -Verify `README.md` was updated. If `grunt readme` fails, check that `npm install` has been run and `grunt-wp-readme-to-markdown` is in `devDependencies`. - -### Step 5.4 — Verify - -Read the updated `readme.txt` and confirm: -- Stable tag matches current plugin version -- Tested up to is correct -- Short description is under 150 characters -- All sections are properly formatted -- No stray draft markers or debug text - -### Step 5.5 — Commit and Push - -```bash -git add readme.txt README.md -git commit -m "chore: update readme.txt for WordPress.org listing - -Update plugin description, feature lists, integrations, FAQ, -and compatibility information to reflect current capabilities. - -Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>" -git push -u origin chore/update-readme -``` - -### Step 5.6 — Create PR - -```bash -gh pr create \ - --title "chore: Update readme.txt for WordPress.org" \ - --base dev \ - --body "$(cat <<'EOF' -## Summary -- Updated readme.txt to reflect current plugin capabilities -- Regenerated README.md via `grunt readme` - -## What Changed -[List each section that was modified and what changed] - -## Research Notes -- Competitor READMEs reviewed: WPForms, Gravity Forms, Fluent Forms, Formidable, CF7 -- Gaps identified and addressed: [count] - -## Test Plan -- [ ] Preview on WordPress.org readme validator -- [ ] Verify all links in the readme are working -- [ ] Confirm feature claims match actual plugin capabilities -- [ ] Verify short description is under 150 characters - -🤖 Generated with [Claude Code](https://claude.com/claude-code) -EOF -)" -``` - -### Step 5.7 — Final Report - -``` -✅ Readme Update Complete -───────────────────────────────────────── -✅ Phase 1: Gap analysis complete -✅ Phase 2: Competitor research complete -✅ Phase 3: Draft created -✅ Phase 4: User review passed -✅ Phase 5: Changes applied -✅ Branch: chore/update-readme (from dev) -✅ readme.txt updated -✅ README.md regenerated -✅ PR: <pr-url> - -Sections updated: - • [List each modified section] -``` - ---- - -## Rules - -- **NEVER modify readme.txt without user approval.** Always present the full draft first. -- **NEVER invent features.** Only document what actually exists in the codebase. -- **NEVER modify changelog entries.** The changelog is managed by `/sureforms:version-bump`. -- **ALWAYS branch from `dev`**, never from `master` or `next-release`. -- **ALWAYS run `npx grunt readme`** after modifying `readme.txt` to regenerate `README.md`. -- **ALWAYS verify feature claims** by checking the actual codebase, not just commit messages. -- **Keep the 150-character limit** for the WordPress.org short description. -- **Maintain the existing voice and tone** — professional, benefit-focused, not overly salesy. - -## Error Recovery - -| Symptom | Fix | -|---------|-----| -| `grunt readme` fails | Run `npm install` first; verify `grunt-wp-readme-to-markdown` is in `devDependencies` | -| Branch already exists | Append date suffix: `chore/update-readme-YYYYMMDD` | -| Pro plugin not found at `../sureforms-pro/` | Skip pro analysis, warn user, document only free features | -| Git tag not found | List available tags and ask user to pick one | -| WebSearch unavailable | Skip Phase 2, proceed with codebase analysis only, note the limitation | diff --git a/.claude/commands/sureforms:version-bump.md b/.claude/commands/sureforms:version-bump.md deleted file mode 100644 index 5f48a2e1f..000000000 --- a/.claude/commands/sureforms:version-bump.md +++ /dev/null @@ -1,204 +0,0 @@ -# SureForms Release Version Bump - -Automates the SureForms version bump release checklist end-to-end. - -## Arguments - -Parse from: $ARGUMENTS - -Expected format: `<version> [pro-version] [branch]` - -- `version` — **required**. Version number to release (e.g., `2.5.2`). If not provided, stop immediately and tell the user: `"Version number is required. Usage: /sureforms:version-bump <version> [pro-version] [branch]"` -- `pro-version` — optional. Version to set for `SRFM_PRO_RECOMMENDED_VER`. If not provided, ask: `"What should SRFM_PRO_RECOMMENDED_VER be set to? (default: <version>)"` and default to the core version if the user presses Enter or skips. -- `branch` — optional. Source branch to cut from — must be `dev` or `next-release`. Default: `next-release`. - -## Working Directory - -All commands and file paths are relative to the sureforms plugin root. Detect it as the directory containing `sureforms.php` — typically the current working directory or a `sureforms/` subdirectory of it. - ---- - -## Steps - -### Step 1 — Validate Arguments - -- Extract `version`, `pro-version`, and `branch` from `$ARGUMENTS`. -- Abort with usage message if `version` is missing. -- If `branch` is provided but not `dev` or `next-release`, abort: `"Invalid branch. Must be 'dev' or 'next-release'."` -- If `pro-version` was not passed as an argument, prompt the user for it (default: same as `version`). - ---- - -### Step 2 — Create Version Bump Branch - -Run from the sureforms plugin root: - -```bash -git fetch origin -git checkout <branch> -git pull origin <branch> -git checkout -b version-bump-<version> -``` - -Confirm the new branch was created successfully before continuing. - ---- - -### Step 3 — Run Grunt Version Bump - -```bash -npx grunt version-bump --ver=<version> -``` - -This runs `bumpup` (updates `package.json`) and `replace` (updates version strings in `readme.txt` and `sureforms.php`). - ---- - -### Step 4 — Verify package.json and package-lock.json - -- Read `package.json` → confirm `"version"` equals `<version>`. -- Read `package-lock.json` → confirm the top-level `"version"` and `packages[""].version` both equal `<version>`. -- If `package-lock.json` is out of sync, patch **only** the two version string values — do not alter any whitespace, indentation, line endings, or surrounding characters: - - Top-level: replace only the value in `"version": "<old-version>"` → `"version": "<version>"` - - Inside `"packages": { "": { ... } }`: replace only the value in `"version": "<old-version>"` → `"version": "<version>"` - - The resulting diff must show **exactly 2 lines changed** — only the version string on each line. No other bytes in the file should change. - - Do **not** run `npm install` — dependency conflicts can cause it to fail and it is not needed for this change. - ---- - -### Step 5 — Verify readme.txt — Stable tag - -- Read `readme.txt` and confirm `Stable tag: <version>`. -- If incorrect, edit the line to the correct value. - ---- - -### Step 6 — Verify readme.txt — Tested up to - -- Fetch the latest WordPress version by running: - ```bash - curl -s "https://api.wordpress.org/core/version-check/1.7/" | grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4 - ``` -- Store the result as `<wp-latest>`. -- Read `readme.txt` and check the current `Tested up to:` value. -- If it does **not** match `<wp-latest>`, update the line to `Tested up to: <wp-latest>`. -- Confirm the final value in the file after any edit. - ---- - -### Step 7 — Verify sureforms.php — Plugin Header Version - -- Read `sureforms.php` lines 1–15. -- Confirm `Version: <version>` in the plugin header comment. -- If incorrect, edit to the correct value. - ---- - -### Step 8 — Verify SRFM_VER - -- Confirm `define( 'SRFM_VER', '<version>' );` in `sureforms.php`. -- If incorrect, edit to the correct value. - ---- - -### Step 9 — Verify SRFM_PRO_RECOMMENDED_VER - -- Confirm `define( 'SRFM_PRO_RECOMMENDED_VER', '<pro-version>' );` in `sureforms.php`. -- If incorrect, edit to the correct value. - ---- - -### Step 10 — Verify Changelog Entry in readme.txt - -- Read the `== Changelog ==` section of `readme.txt`. -- **Check for a placeholder entry** matching `= x.x.x =` (case-insensitive): - - If **found**: ask the user: `"What is the release date for <version>? (e.g. 19th February 2026)"`. Replace the placeholder header with `= <version> - <date> =`, matching the exact formatting of existing changelog entries (spaces around the `=`, date style matching what is already present). -- **Check for an entry** matching `= <version> -`: - - If **missing** after the above: warn the user and **pause** — they must add a changelog entry for `<version>` before the process can continue. The expected format is: - ``` - = <version> - DD Month YYYY = - * New: ... - * Improvement: ... - * Fix: ... - ``` - - If **found**: confirm the date is present and the format matches SureForms standards. -- **Polish each bullet line** of the `<version>` entry: - - Fix any grammatical or spelling errors. - - Rewrite passive or vague phrasing into clear, active, benefit-led language (e.g. "Fixed bug where X" → "Fix: Resolved an issue where X to ensure Y"). - - Keep the improvements **subtle and factual** — do not invent features or exaggerate. The prefix (`New:`, `Improvement:`, `Fix:`) must stay unchanged. - - Show the user a before/after diff of any lines you changed and ask for confirmation before writing. -- Then sort the bullet lines of the `<version>` entry so they follow this group order: - 1. `* New:` lines - 2. `* Improvement:` lines - 3. `* Fix:` lines - 4. Any other prefixes come last -- Within each group, sort lines **alphabetically** (case-insensitive) by the text that follows the prefix. -- Write the re-ordered lines back to `readme.txt` if any reordering was needed, and report whether changes were made. - ---- - -### Step 11 — Trim Changelog to 3 Entries - -- Parse the `== Changelog ==` section of `readme.txt` to identify all version entries (lines matching `= X.X.X - ...=`). -- Keep only the **3 most recent** entries (the new `<version>` entry plus the 2 entries immediately before it), including all their bullet lines. -- Remove all older entries that follow the 3rd entry, up to but not including the next `==` section header. -- Write the trimmed content back to `readme.txt`. -- Report how many entries were removed (e.g., "Removed 4 old changelog entries"). - ---- - -### Step 12 — Generate README.md - -```bash -npx grunt readme -``` - ---- - -### Step 13 — Generate POT File - -```bash -npm run makepot -``` - ---- - -### Step 14 — Commit and Open PR - -```bash -git add -A -git commit -m "Version Bump <version>" -git push origin version-bump-<version> -gh pr create \ - --repo brainstormforce/sureforms \ - --title "Version Bump <version>" \ - --base <branch> \ - --label "Release PR,skip-title-check" -``` - ---- - -### Step 15 — Final Report - -Print a status summary for every step, then the PR URL: - -``` -Release Bump: <version> -───────────────────────────────────────── -✅ Branch created: version-bump-<version> (from <branch>) -✅ grunt version-bump: completed -✅ package.json: <version> -✅ package-lock.json: <version> -✅ readme.txt Stable tag: <version> -✅ readme.txt Tested up to: <wp-latest> -✅ sureforms.php Version: <version> -✅ SRFM_VER: <version> -✅ SRFM_PRO_RECOMMENDED_VER: <pro-version> -✅ Changelog entry polished, confirmed, and sorted (New → Improvement → Fix, alphabetical within groups) -✅ Changelog trimmed to 3 entries (N removed) -✅ README.md generated -✅ POT file generated -✅ PR opened: <pr-url> -``` - -If any step failed (❌) or needs attention (⚠️), list the required actions at the bottom. diff --git a/.claude/commands/sync-release-branches.md b/.claude/commands/sync-release-branches.md deleted file mode 100644 index 210f07139..000000000 --- a/.claude/commands/sync-release-branches.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -allowed-tools: Bash(git:*) -auto-approve: true -description: Sync master into dev and dev into next-release after a release ---- - -# Sync Release Branches - -After a release, sync the three main branches: master → dev → next-release. - -## Instructions - -Follow these steps sequentially. If any step fails, jump to the Error Recovery section. - -### Step 1: Record current state - -1. Record the current branch: -```bash -git rev-parse --abbrev-ref HEAD -``` -Store this as ORIGINAL_BRANCH. - -2. Check for uncommitted changes: -```bash -git status --porcelain -``` -If there is ANY output, stash the changes: -```bash -git stash -``` -Store HAD_STASH=true. Otherwise HAD_STASH=false. - -### Step 2: Fetch latest from remote - -```bash -git fetch origin -``` - -### Step 3: Update master - -```bash -git checkout master -git pull origin master -``` - -### Step 4: Merge master into dev - -```bash -git checkout dev -git pull origin dev -git pull origin master -``` - -If there are merge conflicts, STOP. Tell the user: "Merge conflicts while merging master into dev. Please resolve them manually." List the conflicting files. - -If merge succeeds: -```bash -git push origin dev -``` - -### Step 5: Merge dev into next-release - -```bash -git checkout next-release -git pull origin next-release -git pull origin dev -``` - -If there are merge conflicts, STOP. Tell the user: "Merge conflicts while merging dev into next-release. Please resolve them manually." List the conflicting files. - -If merge succeeds: -```bash -git push origin next-release -``` - -### Step 6: Return to original branch - -```bash -git checkout ${ORIGINAL_BRANCH} -``` - -If HAD_STASH=true: -```bash -git stash pop -``` - -Report success: "Branch sync complete. master → dev → next-release are now in sync." - -## Error Recovery - -If any step fails after switching branches: -1. Switch back to original branch: `git checkout ${ORIGINAL_BRANCH}` -2. Restore stash if needed: `git stash pop` (only if HAD_STASH=true) -3. Report the error to the user. - -NEVER force-push. If a merge has conflicts, stop and let the user resolve them. diff --git a/.claude/settings.json b/.claude/settings.json deleted file mode 100644 index 02b620f27..000000000 --- a/.claude/settings.json +++ /dev/null @@ -1,73 +0,0 @@ -{ - "hooks": { - "PreToolUse": [ - { - "matcher": "Bash", - "hooks": [ - { - "type": "command", - "command": "if echo \"$CLAUDE_BASH_COMMAND\" | grep -q '^git commit'; then echo '--- PreCommit: Running checks ---' && composer lint 2>&1 | tail -5 && composer phpstan 2>&1 | tail -5 && composer insights 2>&1 | tail -5; fi" - } - ] - } - ], - "PostToolUse": [ - { - "matcher": "Write|Edit", - "hooks": [ - { - "type": "command", - "command": "case \"$CLAUDE_FILE_PATH\" in *.php) vendor/bin/phpcbf \"$CLAUDE_FILE_PATH\" 2>/dev/null || true;; *.js|*.jsx) npx wp-scripts lint-js --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true;; *.scss|*.css) npx wp-scripts lint-style --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true;; esac" - } - ] - } - ] - }, - "permissions": { - "allow": [ - "Bash(npm run lint-js*)", - "Bash(npm run lint-css*)", - "Bash(npm run pretty*)", - "Bash(npm run build*)", - "Bash(npm run start)", - "Bash(npm run test:unit)", - "Bash(npm run test:e2e)", - "Bash(npm run play:*)", - "Bash(npm run makepot)", - "Bash(npm run i18n:*)", - "Bash(composer lint*)", - "Bash(composer format*)", - "Bash(composer test*)", - "Bash(composer phpstan*)", - "Bash(composer insights*)", - "Bash(npx playwright test*)", - "Bash(npx grunt *)", - "Bash(composer install*)", - "Bash(npm install*)", - "Bash(curl *)", - "Bash(git status*)", - "Bash(git diff*)", - "Bash(git log*)", - "Bash(git branch*)", - "Bash(git show*)", - "Bash(git stash*)", - "Bash(git checkout*)", - "Bash(git add*)", - "Bash(git commit*)", - "Bash(git merge*)", - "Bash(git rebase*)", - "Bash(git fetch*)", - "Bash(git pull*)", - "Bash(gh pr *)", - "Bash(gh issue *)", - "Bash(gh api *)", - "Bash(ls *)", - "Bash(wc *)", - "Bash(which *)", - "Bash(node -e *)", - "Bash(php -r *)", - "Bash(wp *)" - ], - "deny": [] - } -} diff --git a/.github/workflows/push-asset-readme-update.yml b/.github/workflows/push-asset-readme-update.yml deleted file mode 100644 index de4769aaf..000000000 --- a/.github/workflows/push-asset-readme-update.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Plugin asset/readme update -on: - push: - branches: - - master - paths: - - 'readme.txt' - - '.wordpress-org/**' -jobs: - master: - name: Push to main - runs-on: ubuntu-22.04 - environment: production - steps: - - uses: actions/checkout@master - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: '24.16.0' - - name: Build - run: | - npm ci - npm run build - - name: WordPress.org plugin asset/readme update - uses: 10up/action-wordpress-plugin-asset-update@stable - env: - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} diff --git a/.github/workflows/push-to-deploy.yml b/.github/workflows/push-to-deploy.yml deleted file mode 100644 index e10b21ba8..000000000 --- a/.github/workflows/push-to-deploy.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Deploy to WordPress.org -on: - release: - types: [published] -jobs: - tag: - name: New tag - runs-on: ubuntu-22.04 - environment: production - steps: - - uses: actions/checkout@master - - name: Verify release tag is reachable from master - run: | - git fetch --no-tags --depth=50 origin master:refs/remotes/origin/master - if ! git merge-base --is-ancestor "$GITHUB_SHA" refs/remotes/origin/master; then - echo "::error::Tag $GITHUB_REF_NAME ($GITHUB_SHA) is not reachable from master. Refusing to deploy." - exit 1 - fi - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: '24.16.0' - - name: Build - run: | - npm ci - npm run build - - name: WordPress Plugin Deploy - uses: 10up/action-wordpress-plugin-deploy@master - env: - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} diff --git a/.github/workflows/release-pr-template.yml b/.github/workflows/release-pr-template.yml deleted file mode 100644 index b296fcd31..000000000 --- a/.github/workflows/release-pr-template.yml +++ /dev/null @@ -1,41 +0,0 @@ - -name: Update checklist for Release PR - -on: - pull_request: - types: [ labeled ] - -jobs: - update_pr: - name: Update checklist for Release PR - if: ${{ github.event.label.name == 'Release PR' }} - runs-on: ubuntu-latest - steps: - - name: Check Branch - id: check-branch - run: | - if [[ ${{ github.base_ref }} == master || ${{ github.base_ref }} == dev || ${{ github.base_ref }} == next-release ]]; then - echo ::set-output name=match::true - fi - - uses: tzkhan/pr-update-action@v2 - if: steps.check-branch.outputs.match == 'true' - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" - base-branch-regex: '[A-Za-z\d-_.\\/]+' - head-branch-regex: '[A-Za-z\d-_.\\/]+' - body-template: | - --- - ### Release Checklist: - - [ ] Run to update version number : `grunt version-bump --ver=<version-number>` - - [ ] Verify the version number in `package.json` and `package-lock.json` - - [ ] Verify `Stable tag` is `<version-number>` in readme.txt - - [ ] Verify `Tested upto` is set to latest tested version of WordPress - - [ ] Update version in `sureforms.php` in plugin description - - [ ] Verify constant `SRFM_VER` in `sureforms.php` with latest version of SureForms - - [ ] Verify constant `SRFM_PRO_RECOMMENDED_VER` in `sureforms.php` with compatible version of SureForms Pro - - [ ] Verify changelog `date` and `content` as per SureForms standards - - [ ] Generate README.md : `grunt readme` - - [ ] Generate POT file : `npm run makepot` - --- - body-update-action: 'suffix' - body-uppercase-base-match: false diff --git a/.github/workflows/release-tag-draft.yml b/.github/workflows/release-tag-draft.yml deleted file mode 100644 index 55a6449bf..000000000 --- a/.github/workflows/release-tag-draft.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Create a release tag - -on: - push: - branches: - - master - paths: - # Release happens only if the version number in main file is updated. - - 'sureforms.php' - -jobs: - build-artifact: - name: Build Release Artifact - runs-on: ubuntu-22.04 - outputs: - current_version: ${{ steps.get_version.outputs.current_version }} - steps: - - name: Checkout code - uses: actions/checkout@v6 - with: - ref: master - - - name: Initialize mandatory git config - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - - name: Compute current version - id: get_version - run: | - CURRENT_VERSION=$(jq --raw-output '.version' package.json) - echo "current_version=${CURRENT_VERSION}" >> $GITHUB_OUTPUT - - - name: Install Node.js and npm - uses: actions/setup-node@v6 - with: - node-version: '24.16.0' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Build - run: npm run build - - - name: Build plugin ZIP file - run: bash ./bin/build-zip.sh - - - name: Upload artifact - uses: actions/upload-artifact@v7 - with: - name: sureforms-plugin - path: ./artifact/sureforms.zip - - create-release: - name: Create Release Draft and Attach Asset - needs: [build-artifact] - runs-on: ubuntu-latest - steps: - - name: Set Release Version - id: get_release_version - env: - VERSION: ${{ needs.build-artifact.outputs.current_version }} - run: echo "version=$(echo $VERSION | cut -d / -f 3 | sed 's/-rc./ RC/' )" >> $GITHUB_OUTPUT - - - name: Download Plugin Zip Artifact - uses: actions/download-artifact@v8 - with: - name: sureforms-plugin - - - name: Create Release Draft - id: create_release - uses: softprops/action-gh-release@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - name: Version ${{ steps.get_release_version.outputs.version }} - tag_name: "v${{ steps.get_release_version.outputs.version }}" - target_commitish: master - draft: true - prerelease: false - body: 'Replace changelog here' - files: ./sureforms.zip diff --git a/.github/workflows/update-translations.yml b/.github/workflows/update-translations.yml deleted file mode 100644 index 38ca26957..000000000 --- a/.github/workflows/update-translations.yml +++ /dev/null @@ -1,205 +0,0 @@ -name: Update Translations - -on: - issue_comment: - types: [created] - -# Only allow one i18n job per PR at a time. -concurrency: - group: i18n-${{ github.event.issue.number }} - cancel-in-progress: true - -permissions: - contents: write - pull-requests: write - issues: write - -jobs: - i18n: - # Only trusted users may trigger a run — this job executes branch build - # scripts with secrets, so gate on the commenter's association. - if: | - github.event.comment.body == '/i18n' && - github.event.issue.pull_request != null && - contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) - runs-on: ubuntu-latest - - steps: - # Acknowledge the command with a reaction - - name: Add reaction to comment - uses: peter-evans/create-or-update-comment@v5 - with: - comment-id: ${{ github.event.comment.id }} - reactions: rocket - - # Get PR metadata (head branch, fork detection) - - name: Get PR details - id: pr - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - PR_JSON=$(gh api repos/${{ github.repository }}/pulls/${{ github.event.issue.number }}) - HEAD_REF=$(echo "$PR_JSON" | jq -r '.head.ref') - HEAD_REPO=$(echo "$PR_JSON" | jq -r '.head.repo.full_name') - IS_FORK=$(echo "$PR_JSON" | jq -r '.head.repo.full_name != .base.repo.full_name') - - echo "head_ref=$HEAD_REF" >> "$GITHUB_OUTPUT" - echo "head_repo=$HEAD_REPO" >> "$GITHUB_OUTPUT" - echo "is_fork=$IS_FORK" >> "$GITHUB_OUTPUT" - - # Block fork PRs — secrets are not available - - name: Block fork PRs - if: steps.pr.outputs.is_fork == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "**i18n update skipped**: This PR is from a fork. Translation updates require repository secrets and cannot run on fork PRs." - exit 1 - - # Notify that the workflow has started - - name: Comment starting - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "**Translations update started** :hourglass_flowing_sand: - Building and generating translations for 7 languages (nl, fr, de, es, it, pt, pl)... - [View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" - - # Checkout the actual PR branch (not default branch) - - name: Checkout PR branch - uses: actions/checkout@v6 - with: - ref: ${{ steps.pr.outputs.head_ref }} - fetch-depth: 0 - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Set up Node.js - uses: actions/setup-node@v6 - with: - node-version: '24.16.0' - cache: 'npm' - - # Pin WP-CLI to a fixed release. `wp i18n make-json` stamps - # "generator":"WP-CLI/<version>" into every languages/*.json, so - # installing "latest" rewrites all JSON files whenever WP-CLI - # ships a new version. Bump this pin deliberately. - - name: Install WP-CLI - run: | - curl -sSfL -o wp-cli.phar https://github.com/wp-cli/wp-cli/releases/download/v2.12.0/wp-cli-2.12.0.phar - chmod +x wp-cli.phar - sudo mv wp-cli.phar /usr/local/bin/wp - wp --info - - - name: Install dependencies - run: npm ci - - # Build first so makepot picks up all the latest strings - - name: Build - run: npm run build - - # Run the full i18n pipeline (makepot -> po -> gpt-translate -> mo -> json) - - name: Run i18n script - env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} - run: | - set -euo pipefail - bash bin/i18n.sh - - # Check if any files changed - - name: Check for changes - id: changes - run: | - if git diff --quiet; then - echo "changed=false" >> "$GITHUB_OUTPUT" - else - echo "changed=true" >> "$GITHUB_OUTPUT" - CHANGED_FILES=$(git diff --name-only | wc -l | tr -d ' ') - echo "file_count=$CHANGED_FILES" >> "$GITHUB_OUTPUT" - fi - - # Push the i18n branch at the current PR-head tip. This only creates a - # branch ref pointing at an existing commit — no new (unverified) commit - # object is introduced here. - - name: Create i18n branch - if: steps.changes.outputs.changed == 'true' - env: - # Pass via env so the branch name can't inject shell commands. - HEAD_REF: ${{ steps.pr.outputs.head_ref }} - run: | - BRANCH="i18n/$HEAD_REF" - echo "BRANCH=$BRANCH" >> "$GITHUB_ENV" - git push --force origin "HEAD:refs/heads/$BRANCH" - - # Commit the generated translation files through the GitHub GraphQL API - # so the commit is signed by GitHub's GPG key and shows as "Verified" - # (a plain `git push` over HTTPS is never signed). Pinned to the v0.2.20 - # commit SHA for supply-chain safety. - - name: Commit translations (verified) - if: steps.changes.outputs.changed == 'true' - uses: planetscale/ghcommit-action@25309d8005ac7c3bcd61d3fe19b69e0fe47dbdde # v0.2.20 - with: - commit_message: | - chore: update i18n translations - - Auto-generated by /i18n command on PR #${{ github.event.issue.number }} - repo: ${{ github.repository }} - branch: ${{ env.BRANCH }} - file_pattern: '.' - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Open the translations PR against the original PR's head branch. - - name: Create PR - if: steps.changes.outputs.changed == 'true' - id: create_pr - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # Pass via env so the base branch name can't inject shell commands. - HEAD_REF: ${{ steps.pr.outputs.head_ref }} - run: | - PR_URL=$(gh pr create \ - --title "chore: update i18n translations" \ - --body "This PR updates translation files for 7 languages (nl, fr, de, es, it, pt, pl). - - Triggered by \`/i18n\` command on #${{ github.event.issue.number }}." \ - --base "$HEAD_REF" \ - --head "$BRANCH") - - echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT" - - # Comment on the original PR with a link to the translations PR - - name: Comment success - if: steps.changes.outputs.changed == 'true' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "**Translations PR created** :white_check_mark: - ${{ steps.changes.outputs.file_count }} files changed across 7 languages. - Review and merge: ${{ steps.create_pr.outputs.pr_url }}" - - - name: Comment no changes - if: steps.changes.outputs.changed == 'false' - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "**No translation changes** :white_check_mark: - All translation files are already up to date." - - # On any failure, comment with a link to the logs - - name: Comment failure - if: failure() - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr comment "${{ github.event.issue.number }}" \ - --repo "${{ github.repository }}" \ - --body "**Translation update failed** :x: - [View workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details." diff --git a/.scripts/git-hooks/pre-commit b/.scripts/git-hooks/pre-commit deleted file mode 100644 index ce0ba23ea..000000000 --- a/.scripts/git-hooks/pre-commit +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh - -# Check PHPCS before commit -# Ref - -# https://github.com/smgladkovskiy/phpcs-git-pre-commit/blob/master/src/pre-commit -# https://dev.to/akdevcraft/git-pre-hook-pre-commit-hook-with-npm-project-44p2 - -echo "***** Running pre-commit ******" - -PROJECT=$(php -r "echo dirname(dirname(dirname(realpath('$0'))));") -STAGED_FILES_CMD=$(git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\.php) -UNSTAGED_FILES_CMD=$(git diff --name-only --diff-filter=ACMR | grep \\.php) - -# Determine if a file list is passed -if [ "$#" -eq 1 ] -then - oIFS=$IFS - IFS=' - ' - SFILES="$1" - IFS=$oIFS -fi - -SFILES=${SFILES:-$STAGED_FILES_CMD} - -STAGED_BUT_MODIFIED_FILES=$(php -r "\$sfiles=(explode(\"\\n\", '$SFILES'));\$usfiles=(explode(\"\\n\", '$UNSTAGED_FILES_CMD'));echo implode(\"\\n\",array_intersect(\$usfiles,\$sfiles));") - -if [ -z "$STAGED_BUT_MODIFIED_FILES" ]; then - echo "OK" -else - echo "Files staged but then modified:\n" - echo "${STAGED_BUT_MODIFIED_FILES}" - exit 1 -fi - -# echo $PROJECT -# echo $SFILES - -echo "Checking files for PHP Lint..." -for FILE in $SFILES -do - # echo "$PROJECT/$FILE" - php -l -d display_errors=0 "./$FILE" - if [ $? != 0 ] - then - echo "Fix the error before commit." - exit 1 - fi - FILES="$FILES ./$FILE" -done - -if [ "$FILES" = "" ] -then - echo "All good..." - exit 0 -fi - -if [ "$FILES" != "" ] -then - echo "Running PHPCS (Code Sniffer) Check..." - composer lint -n $FILES - if [ $? != 0 ] - then - echo "Please fix the PHPCS errors before commit!" - echo " => Run this command for automatic fixes." - echo " composer format-- $FILES" - exit 1 - fi -fi - -if [ "$FILES" != "" ] -then - echo "Running PHPStan Check..." - composer phpstan - if [ $? != 0 ] - then - echo "Please fix the PHPStan errors before commit!" - echo " => Run this command to check PHPStan errors." - echo " composer phpstan" - exit 1 - fi -fi - -if [ "$FILES" != "" ] -then - echo "Running CSS linting issues..." - npm run lint-css - if [ $? != 0 ] - then - echo "Please fix the CSS issues before commit!" - exit 1 - fi -fi - -if [ "$FILES" != "" ] -then - echo "Running JS linting issues..." - npm run lint-js - if [ $? != 0 ] - then - echo "Please fix the JS issues before commit!" - exit 1 - fi -fi - -exit $? diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md deleted file mode 100644 index 2afeea1d5..000000000 --- a/ARCHITECTURE.md +++ /dev/null @@ -1,355 +0,0 @@ -# SureForms Architecture Documentation - -## Table of Contents - -1. [Introduction](#introduction) -2. [System Architecture](#system-architecture) -3. [Core Components](#core-components) -4. [Data Flow](#data-flow) -5. [Form Building Process](#form-building-process) -6. [AI Integration](#ai-integration) -7. [Form Submission and Processing](#form-submission-and-processing) -8. [Security Features](#security-features) -9. [Extension Points](#extension-points) -10. [Technical Debt and Improvement Areas](#technical-debt-and-improvement-areas) -11. [Development Guidelines](#development-guidelines) - -## Introduction - -SureForms is a modern WordPress form builder plugin designed to provide an intuitive, no-code form building experience. It leverages WordPress's native block editor (Gutenberg) to create a seamless form building experience that integrates naturally with the WordPress ecosystem. - -### Key Features - -- **Native WordPress Integration**: Built on top of the WordPress block editor -- **AI-Powered Form Generation**: Create forms quickly using AI suggestions -- **No-Code Flexibility**: Advanced features without requiring coding knowledge -- **Mobile-First Design**: Responsive forms that work across all devices -- **Modern UI/UX**: Clean, intuitive interface for both admins and users -- **Security Features**: Anti-spam protection, GDPR compliance, and data security -- **Extensibility**: Developer-friendly architecture with hooks and filters - -## System Architecture - -SureForms follows a modular architecture pattern, separating concerns into distinct components that interact through well-defined interfaces. - -```mermaid -graph TD - A[WordPress Core] --> B[SureForms Plugin] - B --> C[Admin Interface] - B --> D[Form Builder] - B --> E[Form Renderer] - B --> F[Form Processor] - B --> G[Database Layer] - B --> H[AI Integration] - - C --> I[Settings Management] - C --> J[Form Management] - C --> K[Entry Management] - - D --> L[Block Editor Integration] - D --> M[Form Templates] - D --> N[Field Components] - - E --> O[Frontend Rendering] - E --> P[Validation] - - F --> Q[Submission Handler] - F --> R[Email Notifications] - F --> S[Confirmation Handler] - - G --> T[Custom Post Types] - G --> U[Custom Database Tables] - G --> V[Metadata Storage] - - H --> W[AI Form Generator] - H --> X[AI Middleware] -``` - -## Core Components - -### Plugin Loader (`Plugin_Loader`) - -The central initialization class that bootstraps the plugin, registers hooks, and loads core components. It follows a singleton pattern to ensure only one instance exists. - -### Post Types (`Post_Types`) - -Registers and manages custom post types for forms and entries. Handles the admin UI customizations for these post types. - -### Form Submit (`Form_Submit`) - -Processes form submissions through REST API endpoints, validates input data, handles file uploads, processes anti-spam measures, and triggers email notifications. - -### AI Form Builder (`AI_Form_Builder`) - -Integrates with AI services to generate form structures based on user prompts. Communicates with middleware services to process AI requests. - -### Database Layer - -Custom database tables for storing form entries and related data, separate from the WordPress post tables for better performance and data organization. - -### Frontend Assets (`Frontend_Assets`) - -Manages the loading of CSS and JavaScript assets for the frontend rendering of forms. - -### Email Notifications - -Handles the sending of email notifications based on form submissions, with support for multiple notification templates and recipients. - -## Data Flow - -### Form Creation Flow - -```mermaid -sequenceDiagram - participant User - participant WordPress - participant FormBuilder - participant Database - - User->>WordPress: Access Form Builder - WordPress->>FormBuilder: Initialize Builder Interface - FormBuilder->>User: Display Form Builder UI - - alt Manual Form Creation - User->>FormBuilder: Add/Configure Form Fields - FormBuilder->>User: Update UI Preview - else AI-Assisted Creation - User->>FormBuilder: Enter Form Description - FormBuilder->>AI: Send Form Description - AI->>FormBuilder: Return Suggested Form Structure - FormBuilder->>User: Display AI-Generated Form - User->>FormBuilder: Modify/Approve Form - end - - User->>FormBuilder: Save Form - FormBuilder->>Database: Store Form Configuration - Database->>WordPress: Return Form ID - WordPress->>User: Confirm Form Creation -``` - -### Form Submission Flow - -```mermaid -sequenceDiagram - participant User - participant Frontend - participant REST_API - participant Validation - participant AntiSpam - participant Database - participant EmailSystem - - User->>Frontend: Fill Form - Frontend->>User: Validate Client-Side - User->>Frontend: Submit Form - Frontend->>REST_API: POST Form Data - - REST_API->>Validation: Validate Data - Validation->>REST_API: Validation Result - - REST_API->>AntiSpam: Check for Spam - AntiSpam->>REST_API: Spam Check Result - - alt Valid Submission - REST_API->>Database: Store Entry - Database->>REST_API: Entry ID - REST_API->>EmailSystem: Trigger Notifications - EmailSystem->>REST_API: Email Status - REST_API->>Frontend: Success Response - Frontend->>User: Show Confirmation - else Invalid Submission - REST_API->>Frontend: Error Response - Frontend->>User: Show Error Message - end -``` - -## Form Building Process - -SureForms uses WordPress's block editor as the foundation for its form builder. This approach provides several advantages: - -1. **Familiar Interface**: Users already familiar with WordPress's editor can easily adapt -2. **Native Integration**: Seamless integration with WordPress core functionality -3. **Extensibility**: Ability to leverage the block ecosystem - -### Block Structure - -Forms are composed of various block types: - -- **Container Blocks**: Group and organize form fields -- **Field Blocks**: Individual form inputs (text, email, checkbox, etc.) -- **Layout Blocks**: Control the visual arrangement of fields -- **Special Blocks**: Submit buttons, GDPR notices, etc. - -Each block has its own edit and save components, following the WordPress block API pattern. - -### Form Data Storage - -Form configurations are stored as custom post types with: - -- Post content: Stores the block structure (serialized blocks) -- Post meta: Stores form settings, styling options, and other configuration data - -## AI Integration - -SureForms features an AI-powered form generation system that allows users to create forms by describing them in natural language. - -```mermaid -graph TD - A[User Input] --> B[AI Middleware] - B --> C[AI Service] - C --> D[Form Structure Generation] - D --> E[Field Mapping] - E --> F[Block Generation] - F --> G[Form Preview] - G --> H[User Edits] - H --> I[Final Form] -``` - -### AI Form Generation Process - -1. User provides a description of the desired form -2. The description is sent to the AI middleware -3. AI analyzes the description and generates a structured form definition -4. The form definition is mapped to SureForms field types -5. Blocks are generated and inserted into the editor -6. User can review and modify the generated form - -## Form Submission and Processing - -### Submission Handling - -Form submissions are processed through a custom REST API endpoint that: - -1. Validates the form data against defined rules -2. Checks for spam using various methods (honeypot, reCAPTCHA, etc.) -3. Processes file uploads if present -4. Stores the submission in the database -5. Triggers email notifications -6. Returns appropriate success/error responses - -### Email Notifications - -The email notification system supports: - -- Multiple notification templates per form -- Dynamic content using smart tags -- HTML email formatting -- Conditional sending based on form data -- Custom headers (CC, BCC, Reply-To) - -```mermaid -graph TD - A[Form Submission] --> B[Email Notification System] - B --> C{Multiple Recipients?} - C -->|Yes| D[Process Each Recipient] - C -->|No| E[Single Email] - D --> F[Parse Email Template] - E --> F - F --> G[Replace Smart Tags] - G --> H[Apply Email Template] - H --> I[Send Email] - I --> J{Success?} - J -->|Yes| K[Log Success] - J -->|No| L[Log Failure] -``` - -## Security Features - -SureForms implements multiple security measures to protect against common vulnerabilities: - -### Anti-Spam Protection - -- **Honeypot Fields**: Hidden fields to catch automated submissions -- **reCAPTCHA Integration**: Multiple versions of Google reCAPTCHA -- **hCaptcha Support**: Alternative to reCAPTCHA -- **Cloudflare Turnstile**: Modern CAPTCHA alternative - -### Data Protection - -- **GDPR Compliance**: Options to enable GDPR-compliant data handling -- **Data Encryption**: Sensitive data can be encrypted in storage -- **Auto-Delete Entries**: Automatic deletion of entries after a specified period - -### Input Validation - -- **Client-Side Validation**: Immediate feedback to users -- **Server-Side Validation**: Thorough validation of all submitted data -- **File Upload Security**: Strict file type and size validation - -## Extension Points - -SureForms provides several extension points for developers: - -### WordPress Hooks - -```php -// Example of filter hook for email notification -add_filter('srfm_email_notification', function($parsed, $submission_data, $item, $form_data) { - // Modify email content or recipients - return $parsed; -}, 10, 4); - -// Example of action hook before form submission -add_action('srfm_before_submission', function($form_data) { - // Perform custom actions before form processing -}); -``` - -### JavaScript API - -```javascript -// Example of extending the form validation -window.sureFormsHooks.addFilter( - 'srfm.validation.rules', - 'my-plugin/custom-validation', - function(rules, fieldData) { - // Add custom validation rules - return rules; - } -); -``` - -## Technical Debt and Improvement Areas - -1. **Performance Optimization**: - - Lazy loading of form assets - - Improved caching strategies - -2. **Code Refactoring**: - - Further modularization of components - - Consistent naming conventions - -3. **Testing Coverage**: - - Increase unit and integration test coverage - - Automated UI testing - -## Development Guidelines - -### Coding Standards - -SureForms follows WordPress coding standards with some additional guidelines: - -- PHP: PSR-12 with WordPress-specific adaptations -- JavaScript: ESLint with WordPress configuration -- CSS: Follows WordPress CSS coding standards - -### Development Workflow - -1. **Feature Planning**: Document requirements and design -2. **Development**: Implement features with appropriate tests -3. **Code Review**: Peer review for quality assurance -4. **Testing**: Automated and manual testing -5. **Documentation**: Update technical and user documentation -6. **Release**: Version tagging and deployment - -### Version Control - -- Feature branches for new development -- Pull request workflow for code review -- Semantic versioning for releases - -## Conclusion - -SureForms represents a modern approach to WordPress form building, combining the power of the block editor with advanced features like AI form generation. Its modular architecture and extensive extension points make it both user-friendly and developer-friendly, while its focus on security and performance ensures a reliable experience for all users. - -The plugin continues to evolve with a focus on improving user experience, expanding integration capabilities, and optimizing performance across all devices and platforms. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index fb62799fc..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,180 +0,0 @@ -# SureForms - CLAUDE.md - -## Project Overview -SureForms is a WordPress form builder plugin (v2.5.1) by Brainstorm Force. AI-powered drag-and-drop form building using the Gutenberg block editor. - -- **Plugin slug:** `sureforms` | **Text domain:** `sureforms` -- **Prefix:** `SRFM_` (constants), `srfm` (slug), `sureforms_` (post types/DB) -- **Minimum PHP:** 7.4 | **Minimum WP:** 6.4 - -## Tech Stack -- **Backend:** PHP 7.4+ / WordPress Plugin API / Custom REST endpoints -- **Frontend:** React 18 + WordPress Gutenberg blocks -- **Styling:** TailwindCSS 3.4 + SASS + PostCSS -- **Build:** WordPress Scripts (Webpack 5) + Grunt -- **Testing:** PHPUnit 9 (unit) + Playwright (E2E) -- **Static Analysis:** PHPStan level 9 + PHPCS (WordPress-Extra) -- **Node:** 24.16.0 (Volta) | **UI Library:** @bsf/force-ui - -## Commands - -### Build -```bash -npm run start # Dev server with watch -npm run build # Full production build -npm run build:script # Webpack only -npm run build:sass # SASS only -``` - -### Lint & Format -```bash -npm run lint-js # ESLint -npm run lint-js:fix # ESLint auto-fix -npm run lint-css # Stylelint -composer lint # PHPCS -composer format # PHPCBF auto-fix -composer phpstan # PHPStan level 9 -composer insights # PHP Insights -``` - -### Test -```bash -composer test # PHPUnit -composer test:coverage # PHPUnit with coverage -npm run test:unit # JS unit tests -npm run play:up # Start WP test env -npm run play:run # Playwright E2E -npm run play:stop # Stop WP test env -``` - -### i18n -```bash -npm run makepot # Generate .pot -npm run i18n:po # Update .po from .pot -npm run i18n:mo # Compile .mo -npm run i18n:json # JSON translations -``` - -## Architecture - -### Directory Structure -``` -sureforms/ -├── sureforms.php # Entry point, constants -├── plugin-loader.php # Bootstrap -├── inc/ # PHP backend -│ ├── helper.php # Central utility (large — minimize changes) -│ ├── rest-api.php # REST endpoints -│ ├── form-submit.php # Submission handler -│ ├── entries.php # Entry management -│ ├── post-types.php # CPT registration -│ ├── blocks/ # PHP block rendering -│ ├── fields/ # Field type handlers -│ ├── database/ # Custom DB tables -│ ├── payments/ # Stripe integration -│ ├── ai-form-builder/ # AI form generation -│ ├── global-settings/ # Plugin settings -│ ├── page-builders/ # Elementor/Bricks compat -│ └── lib/ # Third-party (DO NOT modify) -├── src/ # React/JS source -│ ├── admin/ # Admin UI -│ ├── blocks/ # Gutenberg block JS -│ ├── components/ # Shared React components -│ ├── store/ # WordPress data store -│ ├── utils/ # JS utilities -│ └── srfm-controls/ # Custom block controls -├── assets/ # Compiled output (gitignored) -├── sass/ # SASS source -├── modules/ # Feature modules -├── templates/ # PHP templates -├── tests/ # PHPUnit + Playwright + Docker -└── languages/ # Translation files -``` - -### Webpack Aliases -``` -@Admin → src/admin/ @Blocks → src/blocks/ @Controls → src/srfm-controls/ -@Components → src/components/ @Utils → src/utils/ @Svg → assets/svg/ -@Attributes → src/blocks-attributes/ @Image → images/ @IncBlocks → inc/blocks/ -``` - -### Key Data Structures -- **Post Type:** `sureforms_form` — Forms as CPT with block content -- **Custom Tables:** `sureforms_entries`, `sureforms_payments` -- **REST Namespace:** Custom endpoints in `inc/rest-api.php` - -## Code Rules - -### PHP -- Follow WPCS. Use `sureforms` text domain for all translatable strings -- `@since x.x.x` on all new functions/classes (updated in release PRs) -- NEVER `echo` without escaping — use `esc_html()`, `esc_attr()`, `wp_kses_post()` -- NEVER use `$_GET/$_POST/$_REQUEST` directly — use `sanitize_text_field( wp_unslash( ... ) )` -- NEVER skip security verification on endpoints/AJAX handlers - - **Public form submission endpoints** use HMAC tokens via `Submit_Token::verify()` (`inc/submit-token.php`) — NOT nonces. These are cache-safe and session-independent. The `// phpcs:ignore WordPress.Security.NonceVerification.Missing` comment is expected on these handlers. - - **Admin/authenticated endpoints** still use traditional nonces (`wp_verify_nonce()` / `check_ajax_referer()`) -- NEVER skip capability checks — use `current_user_can()` before privileged operations -- NEVER use `wp_die()` in REST callbacks — use `WP_Error` with proper response codes -- NEVER hardcode table names — use `$wpdb->prefix . 'sureforms_entries'` -- ALWAYS use `wp_json_encode()`, `wp_remote_get/post()`, `gmdate()`, `wp_safe_redirect()` - -### JavaScript/React -- Follow WordPress Scripts ESLint config -- Use WordPress data stores (`useSelect`/`useDispatch`) — never raw fetch in blocks -- Import from `@wordpress/*` packages — never import React directly -- Use `__()` from `@wordpress/i18n` — never hardcode user-facing strings -- Use TailwindCSS utility classes; use `@bsf/force-ui` for admin UI -- NEVER use `dangerouslySetInnerHTML` — use `RawHTML` from `@wordpress/element` - - **Deliberate exception:** the entries admin view — `EntryDataSection.js` and - `EntryLogsSection.js` — inserts `sanitizeEntryValue.js` output directly. - (Pre-existing unrelated sites: `src/components/presets/index.js`, - `src/components/image/index.js`.) Two separate rules apply here: - - **Never re-parse the sanitized string.** Feeding sanitizer output to a - SECOND HTML parser (e.g. `html-react-parser`) is what caused the stored-XSS - CVE-2026-18406: the re-parse decoded entities DOMPurify had deliberately - left inert. Sanitizer-straight-to-DOM is DOMPurify's documented, mXSS-safe - contract, so any post-sanitize transform of that string reopens the hole. - - **`RawHTML` is not the fix here, but it is not dangerous either.** It does - not re-parse — it hands the string straight to `dangerouslySetInnerHTML`, - so it is exactly as safe as what ships in these files. It is avoided only - for structural reasons: it renders a `<div>`, which breaks the inline - `<span>` + `whitespace-pre-wrap` layout, and it adds no safety over the - explicit call. - -### General -- NEVER create files unless absolutely necessary — prefer editing existing files -- NEVER proactively create documentation files unless explicitly requested - -## Gotchas -- **Custom DB tables** introduced in v0.0.13 — migration is irreversible -- **PHPStan level 9** is strict; check baseline before adding new ignores -- **Grunt** still used alongside Webpack for CSS minification and release packaging -- **`inc/lib/`** is third-party code — do not lint or modify -- **Node 24.16.0** pinned via Volta — other versions may cause build issues - -## Verification Before Done -After code changes, verify before reporting done: - -**JS:** `npm run lint-js` → `npm run build:script` -**SASS:** `npm run build:sass` (if touched) - -Checklist: -- Re-read the diff for obvious issues -- No debug code left (`console.log`, `error_log`, `var_dump`) -- All new functions have `@since x.x.x` -- All user-facing strings use `__()` / `_e()` -- Security checks on new endpoints/handlers (HMAC token for public, nonce for admin) -- For significant changes, suggest `npm run play:run` - -## Self-Improvement Loop -- When corrected, add a rule to **Learned Rules** so the mistake never repeats -- When a pattern causes a bug or CI failure, document it immediately -- Periodically prune outdated rules - -## Learned Rules -<!-- Format: "- NEVER/ALWAYS [action] — [reason]" --> -- NEVER flag `phpcs:ignore WordPress.Security.NonceVerification.Missing` as a security issue on public form submission handlers (form submit, field validation, Stripe/PayPal payment intents) — these use HMAC token verification (`Submit_Token::verify()`) instead of nonces for page-cache compatibility. The HMAC token is embedded in the form at render time and verified server-side without any session dependency. -- ALWAYS use `Submit_Token::generate($form_id)` / `Submit_Token::verify($token, $form_id)` for public-facing form security — nonces (`wp_verify_nonce`) are only for admin/authenticated endpoints. - -## Current Focus -<!-- Update with current sprint/milestone priorities --> diff --git a/COMPREHENSIVE_ANALYSIS.md b/COMPREHENSIVE_ANALYSIS.md deleted file mode 100644 index aed786d38..000000000 --- a/COMPREHENSIVE_ANALYSIS.md +++ /dev/null @@ -1,304 +0,0 @@ -# SureForms: Comprehensive Analysis - -This document provides a multi-perspective analysis of the SureForms WordPress plugin, examining it from software architecture, development, and product management viewpoints. - -## Table of Contents - -1. [Software Architecture Analysis](#software-architecture-analysis) -2. [Development Perspective](#development-perspective) -3. [Product Management Analysis](#product-management-analysis) -4. [Integration Capabilities](#integration-capabilities) -5. [Future Development Roadmap](#future-development-roadmap) - -## Software Architecture Analysis - -### Core Architecture - -SureForms follows a modular architecture pattern with clear separation of concerns. The plugin is built around several key components: - -```mermaid -graph TD - A[WordPress Core] --> B[SureForms Plugin] - B --> C[Plugin_Loader] - C --> D[Core Components] - D --> E[Post_Types] - D --> F[Form_Submit] - D --> G[Block_Patterns] - D --> H[Frontend_Assets] - D --> I[AI_Form_Builder] - D --> J[Rest_Api] - D --> K[Database] - K --> L[Custom Tables] - K --> M[Post Meta] -``` - -The architecture leverages WordPress's plugin system and follows object-oriented principles with extensive use of the singleton pattern for core components. - -### Data Flow Architecture - -The data flow within SureForms follows a clear pattern: - -```mermaid -sequenceDiagram - participant User - participant Frontend - participant BlockEditor - participant REST_API - participant Database - - User->>BlockEditor: Create Form - BlockEditor->>Database: Store Form Configuration - User->>Frontend: View & Submit Form - Frontend->>REST_API: Submit Form Data - REST_API->>Database: Store Submission - REST_API->>Frontend: Return Response -``` - -This separation ensures clean data handling and allows for extensibility at various points in the process. - -### Component Analysis - -#### Plugin Loader - -The `Plugin_Loader` class serves as the entry point for the plugin, handling initialization, autoloading, and hook registration. It follows the singleton pattern to ensure only one instance exists. - -#### Post Types - -The `Post_Types` class manages custom post types for forms and entries, including admin UI customizations, shortcode functionality, and metadata registration. - -#### Form Submit - -The `Form_Submit` class processes form submissions through REST API endpoints, handling validation, file uploads, anti-spam measures, and email notifications. - -#### Database Layer - -SureForms uses both WordPress custom post types and custom database tables: -- Custom post type `sureforms_form` for form configurations -- Custom table `{prefix}_srfm_entries` for form submissions - -This hybrid approach leverages WordPress's content management for forms while optimizing data storage for submissions. - -#### AI Integration - -The AI form builder component connects with external AI services through a middleware layer, translating natural language descriptions into structured form definitions. - -### Technical Debt Assessment - -Current areas of technical debt include: - -1. **Performance Optimization** - - Opportunity for more aggressive asset loading strategies - - Potential for improved caching mechanisms - -2. **Code Organization** - - Some components have grown large and could benefit from further modularization - - Inconsistent naming conventions in some areas - -3. **Testing Coverage** - - Limited automated testing for JavaScript components - - Opportunity for more comprehensive integration tests - -## Development Perspective - -### Code Quality - -The codebase demonstrates several positive qualities: - -- **Consistent Structure**: Well-organized directory structure -- **Modern Practices**: Use of namespaces, autoloading, and OOP principles -- **Documentation**: Comprehensive inline documentation -- **Separation of Concerns**: Clear boundaries between components - -Areas for improvement include: - -- **Testing Coverage**: Expanding unit and integration tests -- **Consistent Naming**: Standardizing naming conventions across all components -- **Performance Profiling**: Identifying and addressing performance bottlenecks - -### Development Workflow - -The development process appears to follow modern practices: - -- **Version Control**: Git-based workflow with feature branches -- **Code Review**: Evidence of peer review processes -- **Continuous Integration**: GitHub Actions for automated testing -- **Semantic Versioning**: Clear versioning strategy - -### Extension Points - -SureForms provides several extension mechanisms: - -1. **WordPress Hooks** - - Actions for process intervention - - Filters for data modification - -2. **JavaScript API** - - Client-side hooks for extending functionality - - Custom events for integration - -3. **Block API** - - Ability to register custom form field blocks - - Block filters for modifying existing blocks - -4. **Template System** - - Customizable templates for form rendering - - Theme override capabilities - -### Technology Stack - -The plugin leverages a modern technology stack: - -- **PHP**: Core server-side logic -- **JavaScript/React**: Block editor integration and frontend functionality -- **CSS/SCSS**: Styling with preprocessor support -- **MySQL**: Database storage -- **REST API**: Data communication -- **AI Services**: Form generation capabilities - -## Product Management Analysis - -### User Segments - -SureForms targets several distinct user segments: - -1. **Website Owners** - - Need: Simple form creation without technical knowledge - - Value: Intuitive interface, pre-designed templates - -2. **Designers** - - Need: Visually appealing forms that match site design - - Value: Design customization, aesthetic controls - -3. **Developers** - - Need: Extensible platform with clean APIs - - Value: Hooks, filters, and documentation - -4. **No-Code Professionals** - - Need: Advanced functionality without coding - - Value: Conditional logic, multi-step forms - -### Feature Analysis - -The feature set is well-aligned with user needs: - -| Feature | User Segment | Value Proposition | -|---------|--------------|-------------------| -| Block Editor Integration | All | Familiar, native WordPress experience | -| AI Form Generation | All | Rapid form creation with minimal effort | -| Mobile-First Design | All | Forms work well on all devices | -| Advanced Field Types | No-Code Professionals | Complex form capabilities without coding | -| Developer Hooks | Developers | Extensibility for custom needs | -| Visual Customization | Designers | Forms match site aesthetics | -| Anti-Spam Features | All | Protection from spam submissions | -| GDPR Compliance | All | Legal compliance and data protection | - -### Competitive Positioning - -SureForms differentiates itself through: - -1. **Native WordPress Integration**: Using the block editor rather than a custom interface -2. **AI-Powered Creation**: Faster form building through AI assistance -3. **Design Focus**: Emphasis on visual appeal and user experience -4. **Developer-Friendly**: Clean architecture and extension points - -### Market Fit - -The product demonstrates strong market fit by addressing several key pain points: - -1. **Complex Form Building**: Simplifying the process through AI and intuitive interface -2. **Design Limitations**: Providing modern styling out-of-the-box -3. **Mobile Responsiveness**: Ensuring forms work well on all devices -4. **Technical Barriers**: Enabling advanced features without coding requirements - -## Integration Capabilities - -### WordPress Ecosystem - -SureForms integrates well with the WordPress ecosystem: - -- **Themes**: Compatible with major themes including Astra, Kadence, GeneratePress -- **Page Builders**: Works with Elementor, Beaver Builder, Divi -- **Plugins**: Compatible with popular plugins like WooCommerce, Easy Digital Downloads - -### External Services - -The plugin offers integration with several external services: - -- **reCAPTCHA**: Anti-spam protection -- **hCaptcha**: Alternative CAPTCHA solution -- **Cloudflare Turnstile**: Modern CAPTCHA alternative -- **AI Services**: Form generation capabilities - -### API Architecture - -The API architecture facilitates integration: - -```mermaid -graph LR - A[WordPress] --> B[SureForms Core] - B --> C[REST API] - C --> D[External Integrations] - D --> E[CRM Systems] - D --> F[Email Marketing] - D --> G[Payment Processors] - D --> H[AI Services] -``` - -This architecture allows for flexible integration with various third-party services. - -## Future Development Roadmap - -Based on the analysis, several development priorities emerge: - -### Short-Term Priorities - -1. **Performance Optimization** - - Implement lazy loading for form assets - - Optimize database queries for large form submissions - -2. **Code Quality Improvements** - - Increase test coverage - - Standardize naming conventions - - Refactor larger components - -3. **Integration Expansion** - - Add more third-party service integrations - - Enhance existing integrations with deeper functionality - -### Medium-Term Priorities - -1. **Advanced AI Capabilities** - - Improve form generation accuracy - - Add form analytics and insights - -2. **Enhanced User Experience** - - Streamline the form building process - - Improve form submission handling - -3. **Developer Tools** - - Create comprehensive API documentation - - Develop example extensions - -### Long-Term Vision - -1. **Form Ecosystem** - - Develop a marketplace for extensions - - Create specialized form solutions for different industries - -2. **Enterprise Features** - - Advanced workflow automation - - Enhanced security and compliance features - -3. **SaaS Potential** - - Explore hosted form solution alongside WordPress plugin - - Develop cloud-based form management - -## Conclusion - -SureForms represents a modern approach to WordPress form building, combining native block editor integration with AI-powered form generation. Its architecture demonstrates good separation of concerns and extensibility, while its feature set addresses key user needs across multiple segments. - -The product is well-positioned in the competitive form builder market, with clear differentiation through its WordPress integration, AI capabilities, and design focus. Future development should focus on expanding integrations, enhancing AI capabilities, and improving performance to maintain this competitive advantage. - -From a technical perspective, the codebase is well-structured but would benefit from increased test coverage and some refactoring of larger components. The extension system provides good flexibility for developers, though more comprehensive documentation would enhance this further. - -Overall, SureForms shows strong potential for continued growth and adoption, particularly as the WordPress ecosystem continues to embrace the block editor and AI-powered tools become increasingly important in the website building process. diff --git a/PRODUCT_ANALYSIS.md b/PRODUCT_ANALYSIS.md deleted file mode 100644 index a6c4e595e..000000000 --- a/PRODUCT_ANALYSIS.md +++ /dev/null @@ -1,251 +0,0 @@ -# SureForms Product Analysis - -## Executive Summary - -SureForms is a modern WordPress form builder plugin that differentiates itself through its native WordPress integration, AI-powered form generation, and focus on user experience. This analysis examines the product from multiple perspectives to provide a comprehensive understanding of its strengths, challenges, and opportunities for growth. - -## Table of Contents - -1. [Product Overview](#product-overview) -2. [Market Analysis](#market-analysis) -3. [User Experience Analysis](#user-experience-analysis) -4. [Technical Analysis](#technical-analysis) -5. [Competitive Analysis](#competitive-analysis) -6. [SWOT Analysis](#swot-analysis) -7. [Growth Opportunities](#growth-opportunities) -8. [Recommendations](#recommendations) - -## Product Overview - -SureForms is a WordPress form builder plugin that leverages the native WordPress block editor (Gutenberg) to provide an intuitive form building experience. Key features include: - -- **Native WordPress Integration**: Built on top of the WordPress block editor -- **AI-Powered Form Generation**: Create forms quickly using AI suggestions -- **No-Code Flexibility**: Advanced features without requiring coding knowledge -- **Mobile-First Design**: Responsive forms that work across all devices -- **Modern UI/UX**: Clean, intuitive interface for both admins and users -- **Security Features**: Anti-spam protection, GDPR compliance, and data security -- **Extensibility**: Developer-friendly architecture with hooks and filters - -The plugin is currently at version 1.7.0 and requires WordPress 6.4+ and PHP 7.4+. - -## Market Analysis - -### Target Audience - -SureForms targets several key user segments: - -1. **Website Owners**: Individuals and businesses who manage their own WordPress websites and need to collect information from visitors -2. **Designers**: Professionals who value good design and want to create visually appealing forms -3. **Developers**: Technical users who need a developer-friendly solution with clean APIs and hooks -4. **No-Code Professionals**: Users who need advanced form features without coding skills - -### Market Positioning - -SureForms positions itself as a modern alternative to traditional form builders, emphasizing: - -1. **Seamless WordPress Integration**: Using the native block editor rather than a separate interface -2. **Design-First Approach**: Focusing on aesthetics and user experience -3. **AI-Powered Efficiency**: Leveraging AI to speed up form creation -4. **Simplicity Without Compromise**: Providing advanced features in an accessible way - -### Market Trends - -Several trends in the WordPress form builder market are relevant to SureForms: - -1. **Shift to Block Editor**: Growing adoption of Gutenberg and block-based themes -2. **AI Integration**: Increasing use of AI for content and design generation -3. **Mobile-First Design**: Continued emphasis on mobile responsiveness -4. **Privacy Compliance**: Growing importance of GDPR and other privacy regulations -5. **No-Code Movement**: Rising demand for powerful tools that don't require coding skills - -## User Experience Analysis - -### Form Creation Experience - -SureForms provides a streamlined form creation experience: - -- **Block-Based Building**: Drag-and-drop interface using familiar WordPress blocks -- **AI Form Generation**: Natural language prompts to quickly create form structures -- **Visual Editing**: Real-time preview of forms as they're built -- **Templates**: Pre-designed form templates for common use cases - -### Form Submission Experience - -The end-user experience for form submission is optimized for: - -- **Responsive Design**: Forms adapt to different screen sizes -- **Inline Validation**: Real-time feedback on form inputs -- **Accessibility**: Support for screen readers and keyboard navigation -- **Confirmation Messages**: Customizable success messages and redirects - -### Admin Experience - -The admin interface focuses on: - -- **Intuitive Management**: Easy access to forms, entries, and settings -- **Data Visualization**: Visual reporting of form submission data -- **Entry Management**: Tools for viewing, filtering, and exporting submissions -- **Email Notifications**: Customizable email alerts for new submissions - -## Technical Analysis - -### Architecture - -SureForms follows a modular architecture with clear separation of concerns: - -- **Core Plugin**: Handles initialization, hooks, and basic functionality -- **Block System**: Manages form field blocks and their behavior -- **Form Processing**: Handles form submissions and data storage -- **AI Integration**: Connects with AI services for form generation -- **Extension System**: Provides hooks and filters for customization - -### Performance - -The plugin is designed with performance in mind: - -- **Optimized Asset Loading**: CSS and JS loaded only when needed -- **Efficient Database Usage**: Custom tables with appropriate indexes -- **Caching Strategies**: Caching of frequently accessed data -- **Minimal Dependencies**: Limited reliance on external libraries - -### Security - -Security features include: - -- **Input Validation**: Thorough validation of all user inputs -- **Anti-Spam Measures**: Multiple options for spam prevention -- **Data Protection**: GDPR compliance features -- **File Upload Security**: Strict validation of uploaded files - -### Extensibility - -The plugin provides several extension points: - -- **WordPress Hooks**: Actions and filters for modifying behavior -- **JavaScript API**: Client-side hooks for extending functionality -- **Block API**: Ability to create custom form field blocks -- **Template System**: Customizable templates for form rendering - -## Competitive Analysis - -### Key Competitors - -1. **Gravity Forms**: Established premium form builder with extensive features -2. **WPForms**: User-friendly form builder with a focus on simplicity -3. **Formidable Forms**: Advanced form builder with data management features -4. **Ninja Forms**: Modular form builder with add-on marketplace -5. **Contact Form 7**: Simple, free form builder with large user base - -### Competitive Advantages - -SureForms differentiates itself through: - -1. **Native Block Editor Integration**: More seamless WordPress experience -2. **AI-Powered Form Creation**: Faster form building process -3. **Modern Design Focus**: Better out-of-the-box aesthetics -4. **Developer-Friendly Architecture**: Clean APIs and extension points -5. **Mobile-First Approach**: Better experience on mobile devices - -### Competitive Challenges - -Areas where competitors may have advantages: - -1. **Ecosystem Maturity**: Established competitors have larger add-on ecosystems -2. **Market Recognition**: Lower brand awareness as a newer entrant -3. **Feature Depth**: Some competitors have more specialized features -4. **Integration Breadth**: Fewer third-party service integrations - -## SWOT Analysis - -### Strengths - -- Native integration with WordPress block editor -- AI-powered form generation capabilities -- Modern, clean design aesthetic -- Mobile-first responsive approach -- Developer-friendly architecture -- Focus on user experience - -### Weaknesses - -- Newer entrant in a mature market -- Smaller ecosystem of extensions and add-ons -- Limited third-party integrations compared to competitors -- Requires newer versions of WordPress and PHP - -### Opportunities - -- Growing adoption of the WordPress block editor -- Increasing demand for AI-powered tools -- Rising importance of mobile-friendly forms -- Expanding market for no-code solutions -- Potential for vertical-specific form solutions - -### Threats - -- Established competitors with loyal user bases -- WordPress core changes affecting block editor functionality -- Potential AI regulation affecting AI form generation -- Market commoditization driving price competition -- Alternative form solutions outside WordPress ecosystem - -## Growth Opportunities - -### Product Development - -1. **Expanded AI Capabilities**: More sophisticated form generation and analysis -2. **Vertical-Specific Templates**: Forms tailored to specific industries or use cases -3. **Advanced Conditional Logic**: More powerful dynamic form behavior -4. **Enhanced Data Analysis**: Better visualization and reporting of form data -5. **Multi-Step Form Improvements**: More sophisticated multi-page form experiences - -### Market Expansion - -1. **Agency Partner Program**: Dedicated resources for agencies and developers -2. **Vertical Marketing**: Targeted solutions for specific industries -3. **Educational Content**: Tutorials and resources to drive adoption -4. **Integration Partnerships**: Collaborations with complementary services -5. **International Expansion**: Localization for key markets - -### Business Model - -1. **Freemium Model**: Free core plugin with premium add-ons or features -2. **Subscription Tiers**: Different service levels for different user needs -3. **White-Label Solutions**: Customizable versions for agencies and resellers -4. **Enterprise Offerings**: Custom solutions for larger organizations -5. **Marketplace**: Platform for third-party extensions - -## Recommendations - -### Short-Term (0-6 months) - -1. **Expand Integration Ecosystem**: Add connections to popular CRM and email marketing platforms -2. **Enhance AI Form Builder**: Improve accuracy and capabilities of AI form generation -3. **Develop Educational Content**: Create tutorials and documentation to drive adoption -4. **Optimize Performance**: Further improve loading speed and resource usage -5. **Implement User Feedback System**: Gather structured feedback from early adopters - -### Medium-Term (6-12 months) - -1. **Launch Partner Program**: Develop resources for agencies and developers -2. **Create Vertical Solutions**: Develop specialized templates for key industries -3. **Expand Block Library**: Add more specialized form field types -4. **Improve Analytics**: Enhance data visualization and reporting capabilities -5. **Develop Extension Marketplace**: Create platform for third-party add-ons - -### Long-Term (12+ months) - -1. **Develop Enterprise Features**: Add capabilities for larger organizations -2. **Explore SaaS Model**: Consider hosted form solution alongside WordPress plugin -3. **Implement Advanced AI**: Add predictive analytics and personalization -4. **Create Form Ecosystem**: Develop complementary products and services -5. **Explore International Markets**: Localize for key global markets - -## Conclusion - -SureForms represents a modern approach to WordPress form building, combining the power of the native block editor with AI-powered form generation. Its focus on user experience, design, and developer-friendly architecture positions it well in the competitive form builder market. - -By leveraging its strengths in WordPress integration and AI capabilities while addressing its challenges in market recognition and ecosystem development, SureForms has significant potential for growth. The recommended strategies focus on expanding integrations, enhancing AI capabilities, developing educational resources, and creating specialized solutions for key market segments. - -With continued development and strategic focus, SureForms can establish itself as a leading WordPress form solution for the modern web. diff --git a/TECHNICAL_OVERVIEW.md b/TECHNICAL_OVERVIEW.md deleted file mode 100644 index 9d2d44140..000000000 --- a/TECHNICAL_OVERVIEW.md +++ /dev/null @@ -1,393 +0,0 @@ -# SureForms Technical Overview - -## Introduction - -SureForms is a modern WordPress form builder plugin that leverages the native WordPress block editor (Gutenberg) to provide an intuitive, no-code form building experience. This document provides a comprehensive technical overview of the plugin's architecture, components, and functionality. - -## Table of Contents - -1. [Plugin Architecture](#plugin-architecture) -2. [Core Components](#core-components) -3. [Database Structure](#database-structure) -4. [Form Building System](#form-building-system) -5. [Form Submission Process](#form-submission-process) -6. [AI Integration](#ai-integration) -7. [Security Features](#security-features) -8. [Extension Points](#extension-points) -9. [Performance Considerations](#performance-considerations) -10. [Future Development](#future-development) - -## Plugin Architecture - -SureForms follows a modular architecture pattern with clear separation of concerns. The plugin is structured around several key components that interact through well-defined interfaces. - -### Directory Structure - -``` -sureforms/ -├── admin/ # Admin-specific functionality -├── api/ # REST API endpoints -├── assets/ # CSS, JS, and other assets -├── inc/ # Core functionality -│ ├── ai-form-builder/ # AI form generation -│ ├── blocks/ # Block registration -│ ├── compatibility/ # Theme/plugin compatibility -│ ├── database/ # Custom database tables -│ ├── email/ # Email notification system -│ ├── fields/ # Form field definitions -│ ├── global-settings/ # Global plugin settings -│ ├── lib/ # Third-party libraries -│ ├── page-builders/ # Page builder integrations -│ ├── single-form-settings/ # Form-specific settings -│ └── traits/ # Shared PHP traits -├── languages/ # Internationalization files -├── modules/ # Feature modules -│ ├── gutenberg/ # Gutenberg integration -│ └── quick-action-sidebar/ # Quick action UI -├── src/ # JavaScript source files -│ ├── admin/ # Admin JS -│ ├── blocks/ # Block JS -│ ├── components/ # Reusable React components -│ ├── lib/ # JS libraries -│ ├── store/ # Redux store -│ ├── styles/ # SCSS files -│ └── utils/ # Utility functions -└── templates/ # Template files -``` - -### Initialization Flow - -The plugin follows a structured initialization process: - -1. `sureforms.php` - Main plugin file that defines constants and includes the plugin loader -2. `plugin-loader.php` - Initializes the plugin and registers core components -3. Core components are loaded through the `Plugin_Loader` class using autoloading -4. WordPress hooks are registered to integrate with the WordPress lifecycle - -```mermaid -graph TD - A[sureforms.php] --> B[plugin-loader.php] - B --> C[Plugin_Loader class] - C --> D[Register hooks] - C --> E[Autoload classes] - C --> F[Load textdomain] - D --> G[Init core components] - G --> H[Post_Types] - G --> I[Form_Submit] - G --> J[Block_Patterns] - G --> K[Frontend_Assets] - G --> L[AI_Form_Builder] - G --> M[Rest_Api] -``` - -## Core Components - -### Plugin_Loader - -The central initialization class that bootstraps the plugin, registers hooks, and loads core components. It follows a singleton pattern to ensure only one instance exists. - -```php -class Plugin_Loader { - private static $instance = null; - - public static function get_instance() { - if (null === self::$instance) { - self::$instance = new self(); - do_action('srfm_core_loaded'); - } - return self::$instance; - } - - // Initialization methods... -} -``` - -### Post_Types - -Registers and manages custom post types for forms and entries. Handles the admin UI customizations for these post types. - -Key features: -- Registers `sureforms_form` post type for storing form configurations -- Adds custom columns to the admin list view -- Implements shortcode functionality -- Manages form metadata registration - -### Form_Submit - -Processes form submissions through REST API endpoints, validates input data, handles file uploads, processes anti-spam measures, and triggers email notifications. - -Key features: -- Registers `/sureforms/v1/submit-form` REST API endpoint -- Validates form submissions against defined rules -- Processes file uploads with security checks -- Handles anti-spam measures (honeypot, reCAPTCHA, hCaptcha, Cloudflare Turnstile) -- Stores submissions in the database -- Triggers email notifications - -### AI_Form_Builder - -Integrates with AI services to generate form structures based on user prompts. Communicates with middleware services to process AI requests. - -Key features: -- Processes natural language descriptions into form structures -- Maps AI-generated fields to SureForms field types -- Generates block structures for the editor - -## Database Structure - -SureForms uses both WordPress custom post types and custom database tables to store data efficiently. - -### Custom Post Types - -- **sureforms_form**: Stores form configurations - - Post content: Serialized blocks representing the form structure - - Post meta: Form settings, styling options, and other configuration data - -### Custom Database Tables - -- **{prefix}_srfm_entries**: Stores form submissions - - ID: Primary key - - form_id: Associated form ID - - user_id: Submitter's user ID (if logged in) - - form_data: JSON-encoded submission data - - submission_info: Browser, IP, and device information - - status: Entry status (read, unread, trash) - - logs: Activity logs for the entry - - created_at: Submission timestamp - -```mermaid -erDiagram - FORMS ||--o{ ENTRIES : "has" - FORMS { - int ID - string post_title - text post_content - string post_status - datetime post_date - } - ENTRIES { - int ID - int form_id - int user_id - json form_data - json submission_info - string status - json logs - datetime created_at - } - FORMS ||--o{ FORM_META : "has" - FORM_META { - int meta_id - int post_id - string meta_key - mixed meta_value - } -``` - -## Form Building System - -SureForms uses WordPress's block editor as the foundation for its form builder. - -### Block Structure - -Forms are composed of various block types: - -- **Container Blocks**: Group and organize form fields -- **Field Blocks**: Individual form inputs (text, email, checkbox, etc.) -- **Layout Blocks**: Control the visual arrangement of fields -- **Special Blocks**: Submit buttons, GDPR notices, etc. - -Each block has its own edit and save components, following the WordPress block API pattern. - -### Block Registration - -Blocks are registered using the WordPress block registration API: - -```javascript -registerBlockType('sureforms/input', { - title: __('Text Field', 'sureforms'), - icon: 'text', - category: 'sureforms', - attributes: { - // Block attributes - }, - edit: Edit, - save: Save -}); -``` - -### Form Rendering - -Forms are rendered on the frontend using a combination of server-side rendering and client-side JavaScript: - -1. The form shortcode or block triggers the `Generate_Form_Markup::get_form_markup()` method -2. The method retrieves the form configuration and generates the HTML markup -3. Frontend JavaScript initializes the form functionality (validation, submission, etc.) - -## Form Submission Process - -### Client-Side Flow - -1. User fills out the form -2. Client-side validation checks for errors -3. Form data is collected and serialized -4. AJAX request is sent to the REST API endpoint -5. Response is processed and appropriate feedback is shown to the user - -### Server-Side Flow - -1. REST API endpoint receives the form submission -2. Data is validated and sanitized -3. Anti-spam checks are performed -4. If GDPR compliance is enabled, appropriate data handling is applied -5. Submission is stored in the database (unless configured not to) -6. Email notifications are triggered -7. Response is sent back to the client - -```mermaid -sequenceDiagram - participant User - participant Browser - participant REST_API - participant Database - participant Email - - User->>Browser: Fill form - Browser->>Browser: Validate input - User->>Browser: Submit form - Browser->>REST_API: POST /sureforms/v1/submit-form - REST_API->>REST_API: Validate data - REST_API->>REST_API: Anti-spam check - REST_API->>Database: Store submission - REST_API->>Email: Send notifications - REST_API->>Browser: Return response - Browser->>User: Show confirmation -``` - -## AI Integration - -SureForms features an AI-powered form generation system that allows users to create forms by describing them in natural language. - -### AI Form Generation Process - -1. User provides a description of the desired form -2. The description is sent to the AI middleware -3. AI analyzes the description and generates a structured form definition -4. The form definition is mapped to SureForms field types -5. Blocks are generated and inserted into the editor -6. User can review and modify the generated form - -### AI Middleware - -The AI middleware acts as a bridge between SureForms and the AI service: - -1. Receives the form description from SureForms -2. Processes the description using AI models -3. Returns a structured form definition -4. Handles authentication and rate limiting - -## Security Features - -SureForms implements multiple security measures to protect against common vulnerabilities: - -### Anti-Spam Protection - -- **Honeypot Fields**: Hidden fields to catch automated submissions -- **reCAPTCHA Integration**: Multiple versions of Google reCAPTCHA -- **hCaptcha Support**: Alternative to reCAPTCHA -- **Cloudflare Turnstile**: Modern CAPTCHA alternative - -### Data Protection - -- **GDPR Compliance**: Options to enable GDPR-compliant data handling -- **Data Encryption**: Sensitive data can be encrypted in storage -- **Auto-Delete Entries**: Automatic deletion of entries after a specified period - -### Input Validation - -- **Client-Side Validation**: Immediate feedback to users -- **Server-Side Validation**: Thorough validation of all submitted data -- **File Upload Security**: Strict file type and size validation - -## Extension Points - -SureForms provides several extension points for developers: - -### WordPress Hooks - -```php -// Example of filter hook for email notification -add_filter('srfm_email_notification', function($parsed, $submission_data, $item, $form_data) { - // Modify email content or recipients - return $parsed; -}, 10, 4); - -// Example of action hook before form submission -add_action('srfm_before_submission', function($form_data) { - // Perform custom actions before form processing -}); -``` - -### JavaScript API - -```javascript -// Example of extending the form validation -window.sureFormsHooks.addFilter( - 'srfm.validation.rules', - 'my-plugin/custom-validation', - function(rules, fieldData) { - // Add custom validation rules - return rules; - } -); -``` - -## Performance Considerations - -SureForms is designed with performance in mind: - -### Asset Loading - -- CSS and JavaScript assets are loaded only when needed -- Assets are minified and optimized for production -- Critical CSS is inlined for faster rendering - -### Database Optimization - -- Custom database tables with appropriate indexes -- Efficient queries with proper WHERE clauses -- Caching of frequently accessed data - -### Form Rendering - -- Server-side rendering for initial form display -- Progressive enhancement for JavaScript features -- Lazy loading of heavy components - -## Future Development - -Planned enhancements for future versions: - -1. **Enhanced AI Capabilities** - - More sophisticated form generation - - AI-powered form analytics - -2. **Advanced Integrations** - - More third-party service integrations - - Improved CRM connections - -3. **Performance Optimizations** - - Further asset optimization - - Enhanced caching strategies - -4. **Accessibility Improvements** - - Better screen reader support - - Keyboard navigation enhancements - -5. **Developer Tools** - - More comprehensive API documentation - - Additional extension points - -## Conclusion - -SureForms represents a modern approach to WordPress form building, combining the power of the block editor with advanced features like AI form generation. Its modular architecture and extensive extension points make it both user-friendly and developer-friendly, while its focus on security and performance ensures a reliable experience for all users. diff --git a/bin/build-zip.sh b/bin/build-zip.sh deleted file mode 100644 index 0bf38a51d..000000000 --- a/bin/build-zip.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bash - -# Exit if any command fails. -set -e - -# Enable nicer messaging for build status. -BLUE_BOLD='\033[1;34m'; -GREEN_BOLD='\033[1;32m'; -RED_BOLD='\033[1;31m'; -YELLOW_BOLD='\033[1;33m'; -COLOR_RESET='\033[0m'; -error () { - echo -e "\n${RED_BOLD}$1${COLOR_RESET}\n" -} -status () { - echo -e "\n${BLUE_BOLD}$1${COLOR_RESET}\n" -} -success () { - echo -e "\n${GREEN_BOLD}$1${COLOR_RESET}\n" -} -warning () { - echo -e "\n${YELLOW_BOLD}$1${COLOR_RESET}\n" -} - - -status "💃 Time to build the plugin ZIP file 🕺" - -if [ ! -d "artifact" ]; then - mkdir "artifact" -fi - - -# Copy files for zip. -rsync -rc --delete --exclude-from ".distignore" "./" "artifact/sureforms" - -# Go to directory -cd artifact - -# Create a zip copied files. -zip -r sureforms.zip "./sureforms" - -if [ "no-clean" != "$1" ]; then - # Removed copied files folder. - rm -rf sureforms -fi - -success "Done. Your sureforms zip is ready..! 🎉" diff --git a/bin/checkout-and-build b/bin/checkout-and-build deleted file mode 100755 index c7529e42e..000000000 --- a/bin/checkout-and-build +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -# Script to checkout a branch and build the project - -# Check if branch name is provided as an argument -if [ -z "$1" ]; then - echo "Error: No branch name provided." - echo "Usage: ./checkout-and-build.sh <branch-name>" - exit 1 -fi - -# Assign the first argument to a variable -branch_name=$1 - -# Checkout the specified branch -git checkout "$branch_name" - -# pull the latest version -git pull origin "$branch_name" - -# Run the build command -npm run build diff --git a/bin/i18n.sh b/bin/i18n.sh deleted file mode 100644 index bd71a862a..000000000 --- a/bin/i18n.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -# Run release script -#bash bin/i18n.sh -# -# Generates/updates the .pot, .po, .mo and JS .json translation files for the -# BSF Top 20 languages standard. Run at release time. New locales are created -# automatically via msginit, so the .po files do not need to be committed. - -# Always run from the plugin root so relative paths resolve. -cd "$(dirname "${BASH_SOURCE[0]}")/.." || exit 1 - -# Target locales (BSF Top 20). Format: <wp-locale-filename>:<msginit-locale> -LANGS=( - "de_DE:de_DE" "es_ES:es_ES" "fr_FR:fr_FR" "it_IT:it_IT" "nl_NL:nl_NL" - "pl_PL:pl_PL" "pt_PT:pt_PT" "id_ID:id_ID" "pt_BR:pt_BR" "ru_RU:ru_RU" - "tr_TR:tr_TR" "ja:ja_JP" "zh_CN:zh_CN" "ar:ar" "sv_SE:sv_SE" - "vi:vi_VN" "he_IL:he_IL" "th:th_TH" "el:el_GR" "cs_CZ:cs_CZ" -) - -# Run textdomain updates and generate the POT file -echo "Running textdomain update and POT file generation..." -npm run makepot - -# Create a .po for any target locale that does not exist yet. -echo "Ensuring .po files exist for all target locales..." -for entry in "${LANGS[@]}"; do - file="${entry%%:*}"; loc="${entry##*:}" - po="languages/sureforms-${file}.po" - if [ ! -f "$po" ]; then - echo " creating $po ($loc)" - msginit --input=languages/sureforms.pot --output="$po" --locale="$loc" --no-translator - fi -done - -# Update PO files -echo "Updating PO files..." -npm run i18n:po - -# Translate using GPT-PO (only empty msgstr entries are filled). -echo "Translating PO files using GPT-PO..." -npm run i18n:gptpo:nl -npm run i18n:gptpo:fr -npm run i18n:gptpo:de -npm run i18n:gptpo:es -npm run i18n:gptpo:it -npm run i18n:gptpo:pt -npm run i18n:gptpo:pl -npm run i18n:gptpo:id -npm run i18n:gptpo:ptbr -npm run i18n:gptpo:ru -npm run i18n:gptpo:tr -npm run i18n:gptpo:ja -npm run i18n:gptpo:zh -npm run i18n:gptpo:ar -npm run i18n:gptpo:sv -npm run i18n:gptpo:vi -npm run i18n:gptpo:he -npm run i18n:gptpo:th -npm run i18n:gptpo:el -npm run i18n:gptpo:cs - -# Update PO files again after translation -echo "Updating PO files again..." -npm run i18n:po - -# Generate MO files -echo "Generating MO files..." -npm run i18n:mo - -# Generate JSON translation files -echo "Generating JSON translation files..." -npm run i18n:json - -echo "All commands executed successfully." diff --git a/docs/01-getting-started/GETTING-STARTED.md b/docs/01-getting-started/GETTING-STARTED.md deleted file mode 100644 index a9c0b0c34..000000000 --- a/docs/01-getting-started/GETTING-STARTED.md +++ /dev/null @@ -1,647 +0,0 @@ -# Getting Started with SureForms Development - -> **Goal:** Get productive in less than 30 minutes -> **Audience:** New developers, contractors, open-source contributors -> **Prerequisites:** Basic WordPress, PHP, and React knowledge - -## Prerequisites - -Before you begin, ensure you have: - -- **PHP 7.4+** with extensions: mysqli, mbstring, curl, json -- **Composer 2.3+** for PHP dependencies -- **Node.js 18.15+** (check with `node --version`, use nvm: `nvm use`) -- **npm** (comes with Node.js) -- **Git** for version control -- **Code editor** (VS Code recommended with extensions: PHP Intelephense, ESLint, Prettier) -- **Docker** (optional, for wp-env local environment) - ---- - -## Quick Start (5 Minutes) - -### 1. Clone Repository -```bash -git clone https://github.com/brainstormforce/sureforms.git -cd sureforms -``` - -### 2. Install Dependencies -```bash -# PHP dependencies -composer install - -# JavaScript dependencies -npm install -``` - -This installs: -- **PHP:** Action Scheduler, NPS Survey, Analytics libraries -- **JavaScript:** React 18, WordPress scripts, TailwindCSS, Webpack, testing tools - -### 3. Build Assets -```bash -npm run build -``` - -This compiles: -- JavaScript bundles (Webpack → assets/build/) -- CSS from SASS (sass/ → assets/css/) -- Minified production files - -**Time:** ~2-3 minutes - -### 4. Start Local Environment - -**Option A: Using wp-env (Recommended)** -```bash -npm run play:up -``` - -This creates a Docker-based WordPress installation: -- **URL:** http://localhost:8888 -- **Admin:** http://localhost:8888/wp-admin -- **Username:** admin -- **Password:** password - -**Option B: Manual WordPress Setup** -1. Install WordPress locally (MAMP, Local by Flywheel, or XAMPP) -2. Symlink or copy plugin to `wp-content/plugins/sureforms` -3. Activate plugin in WordPress admin - -### 5. Activate Plugin - -Visit http://localhost:8888/wp-admin/plugins.php and activate "SureForms". - -**You're now ready to develop!** 🎉 - ---- - -## Project Structure Overview - -``` -sureforms/ -├── sureforms.php # Main plugin file (entry point) -├── plugin-loader.php # Bootstrap and autoloader -│ -├── inc/ # PHP backend logic (176+ files) -│ ├── form-submit.php # Form submission handler -│ ├── post-types.php # Custom post type registration -│ ├── rest-api.php # REST API endpoints -│ ├── helper.php # Utility functions -│ ├── blocks/ # Gutenberg block PHP classes -│ │ ├── base.php # Abstract base for blocks -│ │ ├── register.php # Block registration -│ │ ├── input/ # Text input block -│ │ └── [14+ more blocks] -│ ├── database/ # Custom database layer -│ │ ├── base.php # Abstract CRUD operations -│ │ ├── register.php # Table initialization -│ │ └── tables/ -│ │ ├── entries.php # Form submissions table -│ │ └── payments.php # Payment transactions table -│ └── [many more directories] -│ -├── src/ # JavaScript/React source -│ ├── blocks/ # Gutenberg block components -│ │ ├── blocks.js # Block registration entry -│ │ ├── input/ # Input block React component -│ │ │ ├── edit.js # Editor interface -│ │ │ ├── save.js # Frontend save (usually null) -│ │ │ └── block.json # Block metadata -│ │ └── [14+ more blocks] -│ ├── admin/ # Admin dashboard React apps -│ │ ├── dashboard/ # Forms listing -│ │ ├── settings/ # Settings page -│ │ ├── entries/ # Entry management -│ │ └── single-form-settings/ # Form editor -│ ├── components/ # Reusable React components -│ ├── store/ # WordPress Data Store (Redux) -│ └── utils/ # Helper functions -│ -├── assets/ # Compiled build output -│ ├── build/ # Webpack bundles -│ ├── css/ # Compiled CSS -│ └── js/ # Compiled JavaScript -│ -├── sass/ # SCSS source files -├── tests/ # PHPUnit and Playwright tests -├── webpack.config.js # Build configuration -├── package.json # npm dependencies and scripts -└── composer.json # PHP dependencies -``` - -### Key Entry Points - -**PHP Initialization:** -``` -sureforms.php (defines constants) - → plugin-loader.php (Plugin_Loader class) - → Autoloader registration - → WordPress hooks: plugins_loaded, init, admin_init -``` - -**JavaScript Entry:** -- **Blocks:** [src/blocks/index.js](../../src/blocks/index.js) -- **Admin Pages:** [src/admin/{page}/index.js](../../src/admin/) - ---- - -## Development Workflow - -### Daily Development - -**1. Start Development Server** -```bash -npm start -``` - -This starts Webpack in watch mode: -- Automatically rebuilds on file changes -- Hot reload for React components -- Source maps for debugging - -**2. Make Changes** -- Edit PHP files in `inc/` or `admin/` -- Edit React components in `src/` -- Edit styles in `sass/` - -**3. See Changes** -- **Admin:** Refresh browser (Cmd/Ctrl + R) -- **Frontend:** Hard refresh (Cmd/Ctrl + Shift + R) to clear cache - -### Before Committing - -**CRITICAL: Always run these commands before committing** - -```bash -# 1. Fix JavaScript linting issues -npm run lint-js:fix - -# 2. Fix CSS linting issues -npm run lint-css:fix - -# 3. Production build (REQUIRED) -npm run build - -# 4. Check PHP coding standards -composer phpcs - -# 5. Run static analysis -composer phpstan - -# 6. Run tests (optional but recommended) -composer test -npm run test:e2e -``` - -**If all pass, commit:** -```bash -git add . -git commit -m "feat: your change description" -git push -``` - -### Commit Message Format - -Follow [Conventional Commits](https://www.conventionalcommits.org/): - -``` -feat: add date picker field block -fix: resolve form submission nonce error -docs: update API endpoint documentation -style: format code with PHPCS -refactor: simplify validation logic -test: add unit tests for Helper class -chore: update dependencies -``` - ---- - -## Common Development Tasks - -### Task 1: Create a Test Form - -**Time:** 5 minutes - -1. Navigate to **SureForms → Add New** in WordPress admin -2. Block editor opens with empty form -3. Add fields by clicking "+" button: - - Add "Input" block → Configure as "Name" - - Add "Email" block → Configure as "Email Address" - - Add "Textarea" block → Configure as "Message" -4. Click "Publish" -5. View form on frontend or use shortcode `[sureforms id="{ID}"]` - -### Task 2: Submit a Test Form - -**Time:** 2 minutes - -1. Visit form on frontend -2. Fill out fields -3. Click "Submit" -4. Check **SureForms → Entries** to see submission - -### Task 3: Add a New Setting to Existing Block - -**Time:** 30-45 minutes -**Difficulty:** Easy -**Files Modified:** 2 - -**Example: Add "Max Length" setting to Input block** - -**Step 1:** Update [src/blocks/input/edit.js](../../src/blocks/input/edit.js) - -Find the `<InspectorControls>` section and add: -```javascript -import { TextControl } from '@wordpress/components'; - -// Inside InspectorControls > PanelBody -<TextControl - label={__('Max Length', 'sureforms')} - type="number" - value={attributes.maxLength || ''} - onChange={(value) => setAttributes({ maxLength: parseInt(value) })} - help={__('Maximum number of characters allowed', 'sureforms')} -/> -``` - -**Step 2:** Update [src/blocks/input/block.json](../../src/blocks/input/block.json) - -Add to `attributes` object: -```json -"maxLength": { - "type": "number", - "default": 0 -} -``` - -**Step 3:** Build and test -```bash -npm run build -# Refresh block editor -# Test setting in Inspector panel -``` - -**Step 4:** Update PHP rendering (if needed) - -Edit [inc/blocks/input/class-input.php](../../inc/blocks/input/class-input.php) to use the attribute: -```php -$max_length = $attributes['maxLength'] ?? 0; - -// In HTML output -<input - type="text" - <?php if ($max_length > 0): ?> - maxlength="<?php echo esc_attr($max_length); ?>" - <?php endif; ?> -/> -``` - -### Task 4: Debug a Form Submission Issue - -**Time:** 10-20 minutes - -**Symptoms:** Form submission fails silently, no error message - -**Debug Steps:** - -1. **Check Browser Console** (F12 → Console tab) - - Look for JavaScript errors - - Check Network tab for failed AJAX requests - - Look for 403 (nonce error) or 500 (server error) - -2. **Check PHP Error Logs** -```bash -# If using wp-env -npm run play:logs - -# Or tail WordPress debug log -tail -f wp-content/debug.log -``` - -3. **Enable WordPress Debug Mode** (wp-config.php) -```php -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -define('SCRIPT_DEBUG', true); -``` - -4. **Test REST API Directly** -```bash -# Get nonce from browser (inspect form, look for data-nonce attribute) -curl -X POST "http://localhost:8888/wp-json/sureforms/v1/submit-form" \ - -H "X-WP-Nonce: YOUR_NONCE_HERE" \ - -H "Content-Type: application/json" \ - -d '{"form_id":123,"field_data":{"email":{"value":"test@example.com"}}}' -``` - -5. **Common Fixes:** - - **Nonce expired:** Refresh page - - **Spam protection:** Disable reCAPTCHA temporarily - - **PHP error:** Check debug.log for syntax errors - - **REST API disabled:** Check .htaccess or security plugins - ---- - -## Testing Your Changes - -### Unit Tests (PHP) - -```bash -# Run all PHPUnit tests -composer test - -# Run specific test file -./vendor/bin/phpunit tests/unit/test-helper.php - -# Generate coverage report -composer test:coverage -``` - -### E2E Tests (Playwright) - -```bash -# Run all E2E tests -npm run test:e2e - -# Run specific test -npx playwright test tests/play/specs/basic-form-test-submit-text-field.spec.js - -# Run in headed mode (see browser) -npx playwright test --headed - -# Debug mode -npx playwright test --debug -``` - -### Manual Testing Checklist - -After making changes, test: -- [ ] Form appears in block editor -- [ ] Settings panel works -- [ ] Form renders on frontend -- [ ] Form submission works -- [ ] Entry appears in admin -- [ ] Email notification sent (if configured) -- [ ] No console errors -- [ ] No PHP errors in debug.log - ---- - -## Debugging Tips - -### Enable Debugging - -**WordPress Debug Mode** (wp-config.php): -```php -define('WP_DEBUG', true); // Enable debug mode -define('WP_DEBUG_LOG', true); // Log to wp-content/debug.log -define('WP_DEBUG_DISPLAY', false); // Don't display errors on page -define('SCRIPT_DEBUG', true); // Load unminified JS/CSS -define('SAVEQUERIES', true); // Log database queries -``` - -**Plugin Debug Mode** (wp-config.php): -```php -define('SRFM_DEBUG', true); // Load unminified assets -``` - -### View Logs - -**PHP Errors:** -```bash -tail -f wp-content/debug.log -``` - -**JavaScript Console:** -- Open browser DevTools (F12) -- Console tab shows errors and logs -- Network tab shows AJAX requests - -### Common Issues - -#### Issue: "Class not found" Error -**Cause:** Namespace doesn't match file path -**Fix:** Ensure `SRFM\Inc\Blocks\Input` maps to `inc/blocks/input/class-input.php` - -#### Issue: Blocks Don't Appear in Editor -**Cause:** JavaScript not rebuilt -**Fix:** -```bash -npm run build -# Hard refresh browser (Cmd/Ctrl + Shift + R) -``` - -#### Issue: Form Submission Fails -**Cause:** Nonce expired or invalid -**Fix:** Refresh page to get new nonce - -#### Issue: Styling Not Applied -**Cause:** CSS not compiled or cached -**Fix:** -```bash -npm run build:sass -# Hard refresh browser -``` - -#### Issue: PHP Syntax Error After Edit -**Cause:** Syntax mistake in PHP file -**Fix:** Check debug.log, fix syntax, refresh - ---- - -## Next Steps - -Now that you're set up, here's how to continue learning: - -### 1. Read Core Documentation (2-3 hours) - -**Essential:** -- [CLAUDE.md](../../CLAUDE.md) - AI agent guide with constraints and patterns -- [ARCHITECTURE.md](../02-architecture/ARCHITECTURE.md) - System design overview - -**Important:** -- [CODING-STANDARDS.md](../03-development/CODING-STANDARDS.md) - Code style rules -- [DATABASE-SCHEMA.md](../04-backend/DATABASE-SCHEMA.md) - Data model -- [FRONTEND-GUIDE.md](../05-frontend/FRONTEND-GUIDE.md) - React/Gutenberg patterns - -### 2. Explore the Codebase (2-3 hours) - -**Follow the Request Flow:** - -**Admin Page Load:** -``` -1. WordPress loads: admin.php?page=sureforms_forms -2. admin/admin.php → render_forms_page() -3. Outputs: <div id="srfm-forms-root"></div> -4. React app mounts from assets/build/forms.js -5. Fetches data from REST API -``` - -**Form Submission:** -``` -1. User fills form → formSubmit.js validates -2. AJAX POST → /wp-json/sureforms/v1/submit-form -3. inc/form-submit.php → handle_form_submission() -4. Validates → Saves to wp_srfm_entries table -5. Sends email notifications -6. Returns success response -``` - -### 3. Study Example Implementations - -**Reference Block:** [inc/blocks/input/](../../inc/blocks/input/) -- See complete block implementation -- PHP class extends Base -- React component structure -- Attribute schema in block.json - -**Reference React App:** [src/admin/dashboard/](../../src/admin/dashboard/) -- React Query for data fetching -- React Router for navigation -- Component structure - -### 4. Make Your First Contribution - -**Choose from "Good First Issue" labels:** -- Add documentation -- Fix typos -- Add unit tests -- Improve error messages -- Add new field setting - -**Contribution Process:** -1. Fork repository -2. Create feature branch: `git checkout -b feat/your-feature` -3. Make changes -4. Run tests and linters -5. Commit with conventional commit message -6. Push and create pull request -7. Address review feedback - ---- - -## Getting Help - -### Documentation -- [CLAUDE.md](../../CLAUDE.md) - AI agent guide -- [docs/](../) - Full documentation -- [README.md](../../README.md) - Plugin overview - -### Community -- **GitHub Issues:** https://github.com/brainstormforce/sureforms/issues -- **Pull Requests:** https://github.com/brainstormforce/sureforms/pulls - -### Code Questions - -**When asking for help, include:** -1. What you're trying to do -2. What you've tried -3. Error messages (browser console + PHP debug.log) -4. Code snippets -5. Environment (WordPress version, PHP version, plugin version) - ---- - -## Development Tools - -### Recommended VS Code Extensions - -- **PHP Intelephense** - PHP intelligence and autocomplete -- **ESLint** - JavaScript linting -- **Prettier** - Code formatting -- **EditorConfig** - Consistent editor config -- **WordPress Snippets** - WordPress function snippets -- **GitLens** - Git integration -- **Auto Rename Tag** - HTML tag renaming -- **Path Intellisense** - File path autocomplete - -### Browser Extensions - -- **React Developer Tools** - Inspect React components -- **Redux DevTools** - Inspect WordPress Data Store state - -### Command Line Tools - -```bash -# Install WP-CLI globally (optional but helpful) -curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -chmod +x wp-cli.phar -sudo mv wp-cli.phar /usr/local/bin/wp - -# Useful WP-CLI commands -wp plugin list -wp post list --post_type=sureforms_form -wp cache flush -``` - ---- - -## Keyboard Shortcuts (Block Editor) - -| Action | Mac | Windows | -|--------|-----|---------| -| Save | Cmd + S | Ctrl + S | -| Add block | / | / | -| Duplicate block | Cmd + Shift + D | Ctrl + Shift + D | -| Delete block | Shift + Alt + Z | Shift + Alt + Z | -| Block settings | Cmd + Shift + , | Ctrl + Shift + , | -| Undo | Cmd + Z | Ctrl + Z | -| Redo | Cmd + Shift + Z | Ctrl + Shift + Z | - ---- - -## Quick Reference - -### Important npm Scripts - -```bash -npm start # Watch mode with hot reload -npm run build # Production build -npm run build:script # JavaScript only -npm run build:sass # CSS only -npm run lint-js # Check JavaScript -npm run lint-js:fix # Fix JavaScript -npm run lint-css # Check CSS -npm run lint-css:fix # Fix CSS -npm test:unit # JavaScript unit tests -npm run test:e2e # Playwright E2E tests -npm run play:up # Start wp-env -npm run play:stop # Stop wp-env -npm run play:down # Destroy wp-env -npm run makepot # Generate translation template -``` - -### Important Composer Scripts - -```bash -composer install # Install dependencies -composer test # Run PHPUnit tests -composer test:coverage # Generate coverage report -composer phpcs # Check coding standards -composer phpcbf # Fix coding standards -composer phpstan # Static analysis -composer phpinsights # Code quality metrics -``` - -### Important File Paths - -| Purpose | Path | -|---------|------| -| Main plugin file | sureforms.php | -| Plugin loader | plugin-loader.php | -| Form submission | inc/form-submit.php | -| REST API | inc/rest-api.php | -| Helper functions | inc/helper.php | -| Block base class | inc/blocks/base.php | -| Database entries | inc/database/tables/entries.php | -| Webpack config | webpack.config.js | -| TailwindCSS config | tailwind.config.js | - ---- - -**Congratulations!** You're now ready to contribute to SureForms. Happy coding! 🚀 - -**Questions?** Check [CLAUDE.md](../../CLAUDE.md) or create an issue on GitHub. diff --git a/docs/04-backend/DATABASE-SCHEMA.md b/docs/04-backend/DATABASE-SCHEMA.md deleted file mode 100644 index 68f5de98f..000000000 --- a/docs/04-backend/DATABASE-SCHEMA.md +++ /dev/null @@ -1,962 +0,0 @@ -# SureForms Database Schema - -> **Purpose:** Document custom database tables, WordPress post types, and data migration strategies -> **Audience:** Backend developers, database administrators -> **Last Updated:** 2026-02-06 -> **Plugin Version:** 2.5.0 - -## Overview - -SureForms uses a **hybrid data storage approach** combining WordPress native tables with custom optimized tables: - -1. **WordPress Custom Post Type (`sureforms_form`)** - Form configurations and structure -2. **Custom Table (`wp_srfm_entries`)** - Form submission data (performance-optimized) -3. **Custom Table (`wp_srfm_payments`)** - Payment transaction tracking - -**Why Custom Tables?** -- **Performance:** Separate from WordPress posts/postmeta tables (millions of rows) -- **Query Optimization:** Custom indexes for form-specific queries -- **Data Integrity:** Structured schema with foreign keys -- **Scalability:** Handle large volumes of form submissions efficiently - ---- - -## Custom Tables - -### Table: `wp_srfm_entries` - -**Purpose:** Store form submission data separate from WordPress posts for optimized query performance. - -**Schema Definition:** [inc/database/tables/entries.php](../../inc/database/tables/entries.php) -**Table Version:** 1 -**Character Set:** utf8mb4_unicode_ci - -#### SQL Schema - -```sql -CREATE TABLE wp_srfm_entries ( - ID BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY, - form_id BIGINT(20) UNSIGNED, - user_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0, - form_data LONGTEXT, - logs LONGTEXT, - notes LONGTEXT, - submission_info LONGTEXT, - status VARCHAR(10), - type VARCHAR(20), - extras LONGTEXT, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - - INDEX idx_form_id (form_id), - INDEX idx_user_id (user_id), - INDEX idx_form_id_created_at_status (form_id, created_at, status) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -``` - -#### Column Descriptions - -| Column | Type | Nullable | Default | Description | -|--------|------|----------|---------|-------------| -| `ID` | BIGINT(20) UNSIGNED | No | AUTO_INCREMENT | Primary key, unique entry identifier | -| `form_id` | BIGINT(20) UNSIGNED | No | - | Foreign key to wp_posts.ID (sureforms_form post type) | -| `user_id` | BIGINT(20) UNSIGNED | No | 0 | Foreign key to wp_users.ID (0 for guest submissions) | -| `form_data` | LONGTEXT | Yes | NULL | JSON-encoded submission data (field values) | -| `logs` | LONGTEXT | Yes | NULL | JSON-encoded activity logs array | -| `notes` | LONGTEXT | Yes | NULL | JSON-encoded admin notes array | -| `submission_info` | LONGTEXT | Yes | NULL | JSON-encoded metadata (IP, browser, device, referrer) | -| `status` | VARCHAR(10) | Yes | 'unread' | Entry status: 'unread', 'read', 'trash' | -| `type` | VARCHAR(20) | Yes | NULL | Form type: 'quiz', 'standard', NULL (standard default) | -| `extras` | LONGTEXT | Yes | NULL | JSON-encoded additional data | -| `created_at` | TIMESTAMP | No | CURRENT_TIMESTAMP | Entry creation timestamp | -| `updated_at` | TIMESTAMP | No | CURRENT_TIMESTAMP ON UPDATE | Last modification timestamp | - -#### Indexes - -**Purpose:** Optimize query performance for common access patterns - -| Index Name | Columns | Type | Purpose | -|------------|---------|------|---------| -| PRIMARY | ID | PRIMARY KEY | Unique entry lookup | -| idx_form_id | form_id | INDEX | Filter entries by form | -| idx_user_id | user_id | INDEX | Filter entries by user | -| idx_form_id_created_at_status | form_id, created_at, status | COMPOSITE INDEX | Optimize form dashboard queries with date/status filters | - -**Index Usage Examples:** -```sql --- Uses idx_form_id index -SELECT * FROM wp_srfm_entries WHERE form_id = 123; - --- Uses idx_form_id_created_at_status composite index -SELECT * FROM wp_srfm_entries -WHERE form_id = 123 - AND status = 'unread' - AND created_at > '2026-01-01' -ORDER BY created_at DESC; -``` - -#### JSON Column Structures - -**form_data** (LONGTEXT, JSON): -```json -{ - "field_slug": { - "value": "user input", - "label": "Field Label", - "type": "text" - }, - "email": { - "value": "user@example.com", - "label": "Email Address", - "type": "email" - }, - "phone": { - "value": "+1234567890", - "label": "Phone Number", - "type": "phone" - } -} -``` - -**submission_info** (LONGTEXT, JSON): -```json -{ - "ip_address": "192.168.1.1", - "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...", - "browser": "Chrome", - "browser_version": "120.0.0.0", - "device": "Desktop", - "os": "Mac OS X", - "referrer": "https://example.com/landing-page", - "timestamp": 1706800000 -} -``` - -**logs** (LONGTEXT, JSON): -```json -[ - { - "title": "Entry Created", - "messages": ["Entry submitted successfully"], - "timestamp": "2026-02-06 10:30:00" - }, - { - "title": "Email Sent", - "messages": [ - "Notification sent to admin@example.com", - "User confirmation sent to user@example.com" - ], - "timestamp": "2026-02-06 10:30:05" - }, - { - "title": "Integration Triggered", - "messages": ["Data sent to MailChimp", "Subscriber added successfully"], - "timestamp": "2026-02-06 10:30:10" - } -] -``` - -**notes** (LONGTEXT, JSON): -```json -[ - { - "note": "Follow up required", - "author": "admin", - "timestamp": "2026-02-06 12:00:00" - } -] -``` - -**extras** (LONGTEXT, JSON): -```json -{ - "quiz_score": 85, - "quiz_result": "passed", - "conversational_form": true, - "utm_source": "google", - "utm_campaign": "summer_2026" -} -``` - -#### Status Values - -| Status | Description | -|--------|-------------| -| `unread` | New submission, not yet viewed by admin (default) | -| `read` | Admin has viewed the submission | -| `trash` | Soft-deleted, can be restored or permanently deleted | - -#### Type Values - -| Type | Description | -|------|-------------| -| NULL or `standard` | Regular form submission (default) | -| `quiz` | Quiz form submission with score/results | -| Other custom types | Extensible for future form types | - -#### Migration History - -**Version 1:** -- **Renamed Column:** `user_data` → `form_data` (v0.0.13) - - Reason: More descriptive name - - Migration: ALTER TABLE RENAME COLUMN - - Backward compatibility: Old queries updated - -- **Added Columns:** - - `type` VARCHAR(20) (v0.0.13) - - `extras` LONGTEXT (v0.0.13) - - `user_id` BIGINT(20) (v0.0.13) - ---- - -### Table: `wp_srfm_payments` - -**Purpose:** Store payment transaction records for Stripe integration and payment tracking. - -**Schema Definition:** [inc/database/tables/payments.php](../../inc/database/tables/payments.php) -**Table Version:** 1 -**Character Set:** utf8mb4_unicode_ci - -#### SQL Schema - -```sql -CREATE TABLE wp_srfm_payments ( - id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY, - form_id BIGINT(20) UNSIGNED, - block_id VARCHAR(255) NOT NULL, - status VARCHAR(50) NOT NULL, - total_amount DECIMAL(26,8) NOT NULL, - refunded_amount DECIMAL(26,8) NOT NULL, - currency VARCHAR(10) NOT NULL, - entry_id BIGINT(20) UNSIGNED NOT NULL, - gateway VARCHAR(20) NOT NULL, - type VARCHAR(30) NOT NULL, - mode VARCHAR(20) NOT NULL, - transaction_id VARCHAR(50) NOT NULL, - customer_id VARCHAR(50) NOT NULL, - subscription_id VARCHAR(50) NOT NULL, - subscription_status VARCHAR(20) NOT NULL, - parent_subscription_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0, - payment_data LONGTEXT, - extra LONGTEXT, - log LONGTEXT, - created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - srfm_txn_id VARCHAR(100) NOT NULL, - customer_email VARCHAR(255) NOT NULL, - customer_name VARCHAR(255) NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; -``` - -#### Column Descriptions - -| Column | Type | Nullable | Default | Description | -|--------|------|----------|---------|-------------| -| `id` | BIGINT(20) UNSIGNED | No | AUTO_INCREMENT | Primary key, unique payment identifier | -| `form_id` | BIGINT(20) UNSIGNED | No | - | Foreign key to wp_posts.ID (form) | -| `block_id` | VARCHAR(255) | No | '' | Block client ID (unique identifier for payment field) | -| `status` | VARCHAR(50) | No | 'pending' | Payment status (Stripe-specific) | -| `total_amount` | DECIMAL(26,8) | No | 0.00000000 | Total amount after discount (8 decimal precision) | -| `refunded_amount` | DECIMAL(26,8) | No | 0.00000000 | Total refunded amount | -| `currency` | VARCHAR(10) | No | '' | ISO 4217 currency code (USD, EUR, GBP, etc.) | -| `entry_id` | BIGINT(20) UNSIGNED | No | 0 | Foreign key to wp_srfm_entries.ID | -| `gateway` | VARCHAR(20) | No | '' | Payment gateway ('stripe') | -| `type` | VARCHAR(30) | No | '' | Payment type: 'payment', 'subscription', 'renewal' | -| `mode` | VARCHAR(20) | No | '' | Payment mode: 'test' or 'live' | -| `transaction_id` | VARCHAR(50) | No | '' | Gateway transaction ID (e.g., Stripe pi_xxx) | -| `customer_id` | VARCHAR(50) | No | '' | Gateway customer ID (e.g., Stripe cus_xxx) | -| `subscription_id` | VARCHAR(50) | No | '' | Gateway subscription ID (e.g., Stripe sub_xxx) | -| `subscription_status` | VARCHAR(20) | No | '' | Subscription status ('active', 'canceled', etc.) | -| `parent_subscription_id` | BIGINT(20) UNSIGNED | No | 0 | Parent subscription payment ID (for renewal payments) | -| `payment_data` | LONGTEXT | Yes | NULL | JSON-encoded gateway-specific data | -| `extra` | LONGTEXT | Yes | NULL | JSON-encoded additional metadata | -| `log` | LONGTEXT | Yes | NULL | JSON-encoded payment activity logs | -| `created_at` | TIMESTAMP | No | CURRENT_TIMESTAMP | Payment creation timestamp | -| `updated_at` | TIMESTAMP | No | CURRENT_TIMESTAMP ON UPDATE | Last update timestamp | -| `srfm_txn_id` | VARCHAR(100) | No | '' | SureForms transaction ID (custom format) | -| `customer_email` | VARCHAR(255) | No | '' | Customer email address | -| `customer_name` | VARCHAR(255) | No | '' | Customer full name | - -#### Valid Enum Values - -**Payment Status** (Stripe-specific): -- `pending` - Payment initiated but not completed -- `succeeded` - Payment completed successfully -- `failed` - Payment failed -- `canceled` - Payment canceled by user or admin -- `requires_action` - Requires additional authentication (3D Secure) -- `requires_payment_method` - Payment method needs to be provided -- `processing` - Payment is being processed -- `refunded` - Full refund processed -- `partially_refunded` - Partial refund processed - -**Currency Codes** (ISO 4217): -``` -USD, EUR, GBP, JPY, CAD, AUD, CHF, CNY, SEK, NZD, -MXN, SGD, HKD, NOK, TRY, RUB, INR, BRL, ZAR, KRW -``` - -**Payment Gateway:** -- `stripe` (currently only Stripe supported) - -**Payment Mode:** -- `test` - Test/sandbox mode -- `live` - Production mode - -**Subscription Status** (Stripe-specific): -- `active` - Subscription is active -- `canceled` - Subscription canceled -- `past_due` - Payment failed, retrying -- `unpaid` - Payment failed, no retry -- `trialing` - In trial period -- `incomplete` - Initial payment not completed -- `incomplete_expired` - Initial payment window expired -- `paused` - Subscription paused - -#### JSON Column Structures - -**payment_data** (LONGTEXT, JSON): -```json -{ - "stripe_payment_intent": { - "id": "pi_1234567890", - "amount": 4999, - "currency": "usd", - "status": "succeeded", - "created": 1706800000 - }, - "refunds": { - "re_1234567890": { - "refund_id": "re_1234567890", - "amount": 1000, - "status": "succeeded", - "created": 1706900000, - "reason": "requested_by_customer" - } - } -} -``` - -**extra** (LONGTEXT, JSON): -```json -{ - "discount_code": "SUMMER2026", - "discount_amount": 10.00, - "original_amount": 59.99, - "tax_amount": 5.00, - "metadata": { - "utm_source": "google", - "utm_campaign": "summer_sale" - } -} -``` - -**log** (LONGTEXT, JSON): -```json -[ - { - "title": "Payment Initiated", - "message": "Stripe Payment Intent created", - "timestamp": "2026-02-06 10:30:00" - }, - { - "title": "Payment Succeeded", - "message": "Payment completed successfully", - "timestamp": "2026-02-06 10:30:15" - } -] -``` - ---- - -## WordPress Custom Post Type - -### Post Type: `sureforms_form` - -**Purpose:** Store form configurations and structure using WordPress's content management system. - -**Registration:** [inc/post-types.php](../../inc/post-types.php) -**Supports:** title, editor, custom-fields -**Public:** false (admin-only) -**Has Archive:** false -**Rewrite:** false - -#### Post Fields - -| Field | Type | Description | -|-------|------|-------------| -| `post_title` | VARCHAR(200) | Form name (user-editable) | -| `post_content` | LONGTEXT | Serialized Gutenberg blocks (form structure) | -| `post_status` | VARCHAR(20) | 'draft', 'publish', 'trash' | -| `post_type` | VARCHAR(20) | 'sureforms_form' (constant) | -| `post_author` | BIGINT(20) | WordPress user ID who created the form | -| `post_date` | DATETIME | Form creation date | -| `post_modified` | DATETIME | Last modification date | - -#### Post Meta Keys - -Form-specific settings stored in `wp_postmeta`: - -| Meta Key | Description | Data Type | Example | -|----------|-------------|-----------|---------| -| `_srfm_form_settings` | General form settings | Serialized array | [complex settings object] | -| `_srfm_email_notifications` | Email notification rules | Serialized array | Multiple notification configs | -| `_srfm_confirmation_settings` | Post-submission behavior | Serialized array | Message or redirect URL | -| `_srfm_spam_protection` | Anti-spam settings | Serialized array | reCAPTCHA, honeypot config | -| `_srfm_gdpr_settings` | GDPR compliance options | Serialized array | Consent, auto-delete rules | -| `_srfm_styling_settings` | Form visual customization | Serialized array | Colors, fonts, spacing | -| `_srfm_conditional_logic` | Conditional field display | Serialized array | Field visibility rules | -| `_srfm_integrations_webhooks` | Third-party integrations | Serialized array | MailChimp, webhooks | -| `_srfm_instant_form_settings` | Instant form configuration | Serialized array | AI-generated form data | -| `_srfm_conversational_form` | Conversational mode settings | Serialized array | Step-by-step form config | -| `_srfm_premium_common` | Pro features settings | Serialized array | Pro-only configurations | -| `_srfm_user_registration_settings` | User registration integration | Serialized array | Create user on submission | - -#### Block Structure (post_content) - -Forms stored as serialized Gutenberg blocks (HTML comments): - -```html -<!-- wp:sureforms/sform {"formId":123} --> - <!-- wp:sureforms/input { - "slug":"name", - "label":"Full Name", - "required":true, - "placeholder":"Enter your name" - } /--> - - <!-- wp:sureforms/email { - "slug":"email", - "label":"Email Address", - "required":true, - "placeholder":"you@example.com" - } /--> - - <!-- wp:sureforms/textarea { - "slug":"message", - "label":"Message", - "required":false, - "placeholder":"Your message here..." - } /--> - - <!-- wp:sureforms/payment { - "slug":"payment", - "amount":49.99, - "currency":"USD", - "gateway":"stripe" - } /--> -<!-- /wp:sureforms/sform --> -``` - ---- - -## Database Schema Migrations - -### Version Control System - -**Implementation:** Each table class maintains a `$table_version` property. - -**Version Storage:** WordPress options table -``` -Option Name: srfm_entries_version -Option Value: 1 (integer) - -Option Name: srfm_payments_version -Option Value: 1 (integer) -``` - -### Migration Flow - -``` -1. Plugin loads → Database\Register::init() -2. For each table: - a. Get stored version from wp_options - b. Compare with code version ($table_version) - c. If mismatch: run upgrade() method - d. Execute schema changes - e. Update version in wp_options -``` - -### Migration Methods - -**Base Class Methods** ([inc/database/base.php](../../inc/database/base.php)): - -| Method | Purpose | -|--------|---------| -| `maybe_create_table()` | Create table if not exists | -| `maybe_add_new_columns()` | Add new columns to existing table | -| `maybe_rename_columns()` | Rename columns (e.g., user_data → form_data) | -| `upgrade($old_version)` | Custom migration logic per version | - -### Adding a New Column (Example) - -**Step 1:** Increment table version in table class -```php -// In inc/database/tables/entries.php -protected $table_version = 2; // Increment from 1 to 2 -``` - -**Step 2:** Add column to schema -```php -public function get_schema() { - return [ - // ... existing columns - 'new_column' => [ - 'type' => 'string', - 'default' => '', - ], - ]; -} -``` - -**Step 3:** Add column definition -```php -public function get_new_columns_definition() { - return [ - 'new_column VARCHAR(255) DEFAULT "" AFTER status', - ]; -} -``` - -**Step 4:** Implement upgrade logic (if needed) -```php -public function upgrade($old_version) { - global $wpdb; - - if ($old_version < 2) { - // Additional migration logic beyond column addition - $wpdb->query("UPDATE {$this->table_name} SET new_column = 'default_value'"); - } -} -``` - -### Migration Best Practices - -1. **Never Delete Columns** - Mark as deprecated instead - ```php - // DON'T: ALTER TABLE DROP COLUMN old_column - // DO: Leave column, document as deprecated - ``` - -2. **Always Provide Defaults** - Avoid NULL for new columns - ```php - 'new_column VARCHAR(255) DEFAULT ""' // Good - 'new_column VARCHAR(255)' // Bad (no default) - ``` - -3. **Test with Production Data** - Use staging environment first -4. **Log All Migrations** - Use error_log() for debugging -5. **Backwards Compatible** - Old code must work during migration -6. **Atomic Operations** - Use transactions where possible - ---- - -## Common Query Patterns - -### Get All Entries for a Form - -```php -use SRFM\Inc\Database\Tables\Entries; - -$entries = Entries::get_all([ - 'where' => [ - [ - ['key' => 'form_id', 'compare' => '=', 'value' => 123], - ['key' => 'status', 'compare' => '!=', 'value' => 'trash'], - ] - ], - 'orderby' => 'created_at', - 'order' => 'DESC', - 'limit' => 20, - 'offset' => 0 -]); -``` - -**Generated SQL:** -```sql -SELECT * FROM wp_srfm_entries -WHERE form_id = 123 - AND status != 'trash' -ORDER BY created_at DESC -LIMIT 0, 20 -``` - -### Get Entry Count by Status - -```php -$unread_count = Entries::get_total_entries_by_status('unread', $form_id); -$all_count = Entries::get_total_entries_by_status('all', $form_id); -``` - -**Generated SQL:** -```sql --- Unread count -SELECT COUNT(*) FROM wp_srfm_entries -WHERE status = 'unread' AND form_id = 123 - --- All count (excluding trash) -SELECT COUNT(*) FROM wp_srfm_entries -WHERE status != 'trash' AND form_id = 123 -``` - -### Get Entries with Payments - -```php -global $wpdb; - -$entries_with_payments = $wpdb->get_results($wpdb->prepare( - "SELECT e.*, p.total_amount, p.status as payment_status, p.currency - FROM {$wpdb->prefix}srfm_entries e - INNER JOIN {$wpdb->prefix}srfm_payments p ON e.ID = p.entry_id - WHERE e.form_id = %d - AND p.status = 'succeeded' - ORDER BY e.created_at DESC", - $form_id -)); -``` - -### Get Payments by Status - -```php -use SRFM\Inc\Database\Tables\Payments; - -$succeeded_payments = Payments::get_all([ - 'where' => [ - [ - ['key' => 'form_id', 'compare' => '=', 'value' => 123], - ['key' => 'status', 'compare' => '=', 'value' => 'succeeded'], - ] - ], - 'orderby' => 'created_at', - 'order' => 'DESC' -]); -``` - ---- - -## Performance Optimization - -### Indexing Strategy - -**Why Indexes Matter:** -- 10,000+ entries: ~50ms query time with indexes vs ~500ms without -- Composite indexes optimize multi-column WHERE clauses -- Index order matters: (form_id, created_at, status) ≠ (status, form_id, created_at) - -**Index Usage Guidelines:** - -1. **Use Indexed Columns in WHERE Clauses** -```php -// GOOD - Uses idx_form_id index -$entries = Entries::get_all(['where' => [[['key' => 'form_id', 'compare' => '=', 'value' => 123]]]]); - -// BAD - No index on 'type' column (full table scan) -$entries = Entries::get_all(['where' => [[['key' => 'type', 'compare' => '=', 'value' => 'quiz']]]]); -``` - -2. **Leverage Composite Indexes** -```php -// GOOD - Uses idx_form_id_created_at_status composite index -$entries = Entries::get_all([ - 'where' => [ - [ - ['key' => 'form_id', 'compare' => '=', 'value' => 123], - ['key' => 'created_at', 'compare' => '>', 'value' => '2026-01-01'], - ['key' => 'status', 'compare' => '=', 'value' => 'unread'], - ] - ] -]); -``` - -3. **Avoid SELECT *** -```php -// GOOD - Specify columns -$entries = Entries::get_instance()->get_results( - ['form_id' => 123], - 'ID, form_data, created_at' -); - -// BAD - Selects all columns including large LONGTEXT -$entries = Entries::get_all(['where' => [[['key' => 'form_id', 'compare' => '=', 'value' => 123]]]]); -``` - -### Pagination Best Practices - -```php -// Paginate large result sets -$per_page = 20; -$page = 2; -$offset = ($page - 1) * $per_page; - -$entries = Entries::get_all([ - 'where' => [[['key' => 'form_id', 'compare' => '=', 'value' => 123]]], - 'limit' => $per_page, - 'offset' => $offset, - 'orderby' => 'created_at', - 'order' => 'DESC' -]); - -// Cache total count separately -$total = Entries::get_total_entries_by_status('all', 123); -$total_pages = ceil($total / $per_page); -``` - -### JSON Column Optimization - -**MySQL 5.7+ JSON Functions:** -```sql --- Extract specific field from form_data JSON -SELECT - ID, - JSON_EXTRACT(form_data, '$.email.value') as email -FROM wp_srfm_entries -WHERE form_id = 123; - --- Search within JSON -SELECT * FROM wp_srfm_entries -WHERE JSON_EXTRACT(form_data, '$.email.value') = 'user@example.com'; -``` - -**Performance Warning:** -- JSON queries are slower than indexed columns -- Avoid wildcard searches in JSON (`LIKE '%value%'`) -- Consider extracting frequently-queried JSON fields to dedicated columns - ---- - -## Data Retention & GDPR - -### Auto-Delete Configuration - -**Setting Location:** [inc/single-form-settings/compliance-settings.php](../../inc/single-form-settings/compliance-settings.php) - -**Per-Form Settings:** -```php -$retention_days = get_post_meta($form_id, '_srfm_entry_retention_days', true); -// Values: 0 (never delete), 7, 30, 60, 90, 365 (days) -``` - -**Implementation:** WordPress Cron (Action Scheduler) - -```php -// Scheduled task runs daily at 2 AM -add_action('srfm_daily_scheduled_action', 'srfm_auto_delete_entries'); - -function srfm_auto_delete_entries() { - global $wpdb; - - // Get forms with auto-delete enabled - $forms = $wpdb->get_results(" - SELECT post_id, meta_value as retention_days - FROM {$wpdb->postmeta} - WHERE meta_key = '_srfm_entry_retention_days' - AND meta_value > 0 - "); - - foreach ($forms as $form) { - $cutoff_date = date('Y-m-d H:i:s', strtotime("-{$form->retention_days} days")); - - // Delete entries older than cutoff - $wpdb->delete( - $wpdb->prefix . 'srfm_entries', - [ - 'form_id' => $form->post_id, - 'created_at < ' => $cutoff_date - ] - ); - } -} -``` - -### Manual Entry Management - -**Soft Delete (Trash):** -```php -Entries::update($entry_id, ['status' => 'trash']); -``` - -**Permanent Delete:** -```php -// Fires srfm_before_delete_entry hook -Entries::delete($entry_id); -``` - -**Restore from Trash:** -```php -Entries::update($entry_id, ['status' => 'unread']); -``` - ---- - -## Backup & Recovery - -### Backup Recommendations - -**1. Full Database Backup** (before plugin updates) -```bash -mysqldump -u username -p database_name > sureforms_backup.sql -``` - -**2. Table-Specific Dumps** -```bash -# Entries table -mysqldump -u username -p database_name wp_srfm_entries > entries_backup.sql - -# Payments table -mysqldump -u username -p database_name wp_srfm_payments > payments_backup.sql - -# Form configurations (WordPress tables) -mysqldump -u username -p database_name wp_posts wp_postmeta \ - --where="post_type='sureforms_form'" > forms_backup.sql -``` - -**3. Export Entries via Admin UI** -- Navigate to SureForms → Entries -- Select entries → Export CSV -- Includes all form data and metadata - -### Restore Process - -```bash -# Restore from backup -mysql -u username -p database_name < entries_backup.sql - -# Restore specific table -mysql -u username -p database_name < wp_srfm_entries.sql -``` - ---- - -## Troubleshooting - -### Issue: Missing Tables - -**Symptom:** "Table doesn't exist" errors in PHP logs -**Cause:** Tables not created during activation -**Fix:** -1. Deactivate plugin -2. Delete option: `srfm_entries_version`, `srfm_payments_version` -3. Reactivate plugin (triggers table creation) - -### Issue: Charset/Collation Errors - -**Symptom:** Garbled text in submissions (emoji, special characters) -**Cause:** Incorrect charset (not utf8mb4) -**Fix:** -```sql -ALTER TABLE wp_srfm_entries -CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - -ALTER TABLE wp_srfm_payments -CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -``` - -### Issue: JSON Parsing Errors - -**Symptom:** "Invalid JSON" errors when retrieving form_data -**Cause:** Unescaped quotes in field values -**Fix:** -```php -// Always use wp_json_encode() for JSON storage -$form_data_json = wp_json_encode($form_data); - -// Always use json_decode() with error handling -$form_data = json_decode($form_data_json, true); -if (json_last_error() !== JSON_ERROR_NONE) { - error_log('JSON decode error: ' . json_last_error_msg()); -} -``` - -### Issue: Slow Queries - -**Symptom:** Dashboard loads slowly with many entries -**Cause:** Missing indexes or inefficient queries -**Debug:** -```sql --- Check query execution plan -EXPLAIN SELECT * FROM wp_srfm_entries -WHERE form_id = 123 - AND status = 'unread' -ORDER BY created_at DESC -LIMIT 20; - --- Should show "Using index" in Extra column -``` - -**Fix:** -1. Ensure indexes exist (check `SHOW INDEX FROM wp_srfm_entries`) -2. Use indexed columns in WHERE clauses -3. Add pagination (LIMIT/OFFSET) - ---- - -## Entity Relationship Diagram - -```mermaid -erDiagram - wp_posts ||--o{ wp_srfm_entries : "has many" - wp_posts ||--o{ wp_srfm_payments : "has many" - wp_srfm_entries ||--o| wp_srfm_payments : "may have" - wp_users ||--o{ wp_srfm_entries : "submits" - - wp_posts { - bigint ID PK - varchar post_type "sureforms_form" - longtext post_content "Gutenberg blocks" - varchar post_status "draft|publish|trash" - } - - wp_srfm_entries { - bigint ID PK - bigint form_id FK - bigint user_id FK - longtext form_data "JSON" - varchar status "unread|read|trash" - timestamp created_at - } - - wp_srfm_payments { - bigint id PK - bigint form_id FK - bigint entry_id FK - varchar status "pending|succeeded|failed" - decimal total_amount - varchar currency - varchar transaction_id - timestamp created_at - } - - wp_users { - bigint ID PK - varchar user_email - } -``` - ---- - -## Summary - -**Storage Strategy:** -- **Forms:** WordPress custom post type (native CMS benefits) -- **Entries:** Custom table (performance optimization) -- **Payments:** Custom table (financial data tracking) - -**Key Design Decisions:** -- Custom tables for scalability (handle millions of entries) -- JSON columns for flexible schema (form fields vary per form) -- Composite indexes for query optimization -- Version-controlled migrations for safe schema updates - -**Maintenance:** -- Regular backups before plugin updates -- Monitor table sizes (OPTIMIZE TABLE if needed) -- Review slow query logs -- Test migrations on staging first - ---- - -**Related Documentation:** -- [CLAUDE.md](../../CLAUDE.md) - AI agent guide -- [ARCHITECTURE.md](../02-architecture/ARCHITECTURE.md) - System design -- [CODING-STANDARDS.md](../03-development/CODING-STANDARDS.md) - Code style -- [SECURITY.md](../07-security/SECURITY.md) - Security practices diff --git a/docs/04-backend/HOOKS-REFERENCE.md b/docs/04-backend/HOOKS-REFERENCE.md deleted file mode 100644 index 35b5c4c12..000000000 --- a/docs/04-backend/HOOKS-REFERENCE.md +++ /dev/null @@ -1,1055 +0,0 @@ -# SureForms Hooks Reference - -> **Purpose:** Complete reference of all WordPress actions and filters for extending SureForms -> **Audience:** Plugin developers, theme developers, integrators -> **Last Updated:** 2026-02-06 -> **Plugin Version:** 2.5.0 - -## Overview - -SureForms provides **450+ hooks** (actions and filters) for extending functionality without modifying core files. This document catalogs the most commonly used hooks with usage examples. - -**Hook Naming Convention:** -- **Prefix:** All hooks start with `srfm_` -- **Format:** `srfm_{context}_{action}` or `srfm_{data_type}_{modification}` -- **Examples:** `srfm_before_submission`, `srfm_field_validation`, `srfm_email_content` - ---- - -## Table of Contents - -- [Plugin Lifecycle](#plugin-lifecycle) -- [Form Submission](#form-submission) -- [Field Validation](#field-validation) -- [Email Notifications](#email-notifications) -- [Form Rendering](#form-rendering) -- [Data Modification](#data-modification) -- [Database Operations](#database-operations) -- [Payment Processing](#payment-processing) -- [Block Registration](#block-registration) -- [Admin Operations](#admin-operations) -- [Integration Points](#integration-points) - ---- - -## Plugin Lifecycle - -### `srfm_core_loaded` - -Fires after the plugin core is fully loaded and initialized. - -**Location:** [plugin-loader.php](../../plugin-loader.php) -**Since:** 0.0.1 -**Parameters:** None - -**Usage:** -```php -add_action('srfm_core_loaded', function() { - // Plugin is ready, initialize custom extensions - error_log('SureForms plugin loaded'); - - // Register custom integrations - my_custom_sureforms_integration(); -}); -``` - -### `srfm_init` - -Fires during WordPress `init` hook after SureForms initialization. - -**Location:** [plugin-loader.php](../../plugin-loader.php) -**Since:** 0.0.1 -**Parameters:** None - -**Usage:** -```php -add_action('srfm_init', function() { - // Register custom post types, taxonomies, or other WordPress entities - register_post_type('custom_form_data', [ - 'public' => false, - 'supports' => ['title'] - ]); -}); -``` - ---- - -## Form Submission - -### `srfm_before_submission` - -Fires immediately before form data is processed and saved to database. Use to validate or modify data before processing. - -**Location:** [inc/form-submit.php:525](../../inc/form-submit.php) -**Since:** 0.0.1 -**Parameters:** -- `array $form_data` - Submitted form data including form_id, fields, and metadata - -**Usage:** -```php -add_action('srfm_before_submission', function($form_data) { - $form_id = $form_data['form_id'] ?? 0; - - // Log submission attempt - error_log(sprintf('Form %d submission started', $form_id)); - - // Perform custom validation - if ($form_id === 123) { - $email = $form_data['email']['value'] ?? ''; - if (strpos($email, '@company.com') === false) { - // Throw exception to halt submission - throw new Exception('Only company emails allowed'); - } - } -}, 10, 1); -``` - -### `srfm_after_submission_process` - -Fires after form entry is saved to database but before email notifications are sent. - -**Location:** [inc/form-submit.php:556](../../inc/form-submit.php) -**Since:** 0.0.1 -**Parameters:** -- `array $form_data` - Complete form data including entry_id - -**Usage:** -```php -add_action('srfm_after_submission_process', function($form_data) { - $entry_id = $form_data['entry_id'] ?? 0; - $form_id = $form_data['form_id'] ?? 0; - - // Trigger third-party integration - if ($form_id === 123) { - $email = $form_data['email']['value'] ?? ''; - $name = $form_data['name']['value'] ?? ''; - - // Add to MailChimp - mailchimp_add_subscriber($email, $name); - - // Send to CRM - crm_create_lead([ - 'email' => $email, - 'name' => $name, - 'source' => 'sureforms' - ]); - } -}, 10, 1); -``` - -### `srfm_form_submit` - -Fires after complete form submission process (entry saved, emails sent). - -**Location:** [inc/form-submit.php:548,644](../../inc/form-submit.php) -**Since:** 0.0.1 -**Parameters:** -- `array $response` - Submission response with entry_id, success status, message - -**Usage:** -```php -add_action('srfm_form_submit', function($response) { - if ($response['success']) { - $entry_id = $response['entry_id']; - - // Custom logging - error_log(sprintf('Form submission %d completed', $entry_id)); - - // Update custom database - global $wpdb; - $wpdb->insert('wp_custom_leads', [ - 'sureforms_entry_id' => $entry_id, - 'created_at' => current_time('mysql') - ]); - } -}, 10, 1); -``` - ---- - -## Field Validation - -### `srfm_field_validation` - -Filters field validation result. Return `WP_Error` to fail validation. - -**Location:** [inc/field-validation.php](../../inc/field-validation.php) -**Since:** 0.0.1 -**Parameters:** -- `bool|WP_Error $is_valid` - Current validation status -- `mixed $field_value` - Field value to validate -- `array $field_data` - Field metadata (type, label, required, etc.) -- `int $form_id` - Form post ID - -**Return:** `bool|WP_Error` - True if valid, WP_Error if invalid - -**Usage:** -```php -add_filter('srfm_field_validation', function($is_valid, $field_value, $field_data, $form_id) { - // Custom validation for specific field type - if ($field_data['type'] === 'text' && $field_data['slug'] === 'phone') { - // Validate phone format - if (!preg_match('/^\+?[1-9]\d{1,14}$/', $field_value)) { - return new WP_Error( - 'invalid_phone', - __('Please enter a valid phone number', 'your-plugin') - ); - } - } - - // Custom validation for specific form - if ($form_id === 123 && $field_data['slug'] === 'age') { - if (intval($field_value) < 18) { - return new WP_Error( - 'age_restriction', - __('You must be 18 or older', 'your-plugin') - ); - } - } - - return $is_valid; -}, 10, 4); -``` - -### `srfm_validate_{field_type}` - -Filters validation for specific field type. - -**Location:** [inc/field-validation.php](../../inc/field-validation.php) -**Since:** Various -**Available Types:** `email`, `phone`, `url`, `number`, `text`, etc. - -**Usage:** -```php -// Custom email validation -add_filter('srfm_validate_email', function($is_valid, $value, $field_data) { - // Block disposable email domains - $disposable_domains = ['tempmail.com', 'throwaway.email']; - $domain = substr(strrchr($value, '@'), 1); - - if (in_array($domain, $disposable_domains)) { - return new WP_Error( - 'disposable_email', - __('Disposable email addresses are not allowed', 'your-plugin') - ); - } - - return $is_valid; -}, 10, 3); -``` - ---- - -## Email Notifications - -### `srfm_email_notification_should_send` - -Filters whether email notification should be sent. - -**Location:** [inc/form-submit.php:796](../../inc/form-submit.php) -**Since:** Various -**Parameters:** -- `array $email_notification` - Email configuration -- `array $submission_data` - Submitted form data -- `array $form_data` - Complete form metadata - -**Return:** `array|false` - Email config to send, false to skip - -**Usage:** -```php -add_filter('srfm_email_notification_should_send', function($email_notification, $submission_data, $form_data) { - $form_id = $form_data['form_id'] ?? 0; - - // Only send email for specific form if user opted in - if ($form_id === 123) { - $opted_in = $submission_data['email_optin']['value'] ?? false; - if (!$opted_in) { - return false; // Skip email - } - } - - return $email_notification; -}, 10, 3); -``` - -### `srfm_email_notification` - -Filters parsed email data before sending. - -**Location:** [inc/form-submit.php:809](../../inc/form-submit.php) -**Since:** Various -**Parameters:** -- `array $parsed` - Parsed email data (to, subject, message, headers) -- `array $submission_data` - Submitted form data -- `array $item` - Email notification configuration -- `array $form_data` - Form metadata - -**Return:** `array` - Modified email data - -**Usage:** -```php -add_filter('srfm_email_notification', function($parsed, $submission_data, $item, $form_data) { - // Add custom header - $parsed['headers'][] = 'X-Form-ID: ' . ($form_data['form_id'] ?? 0); - - // Modify subject based on submission data - if (isset($submission_data['priority']['value']) && $submission_data['priority']['value'] === 'high') { - $parsed['subject'] = '[URGENT] ' . $parsed['subject']; - } - - // Add custom footer to message - $parsed['message'] .= "\n\n---\nSubmitted via SureForms"; - - return $parsed; -}, 10, 4); -``` - -### `srfm_before_email_send` - -Action fired immediately before email is sent via `wp_mail()`. - -**Location:** [inc/form-submit.php:812](../../inc/form-submit.php) -**Since:** Various -**Parameters:** -- `array $parsed` - Email data (to, subject, message, headers) -- `array $submission_data` - Submitted form data -- `array $item` - Email notification configuration -- `array $form_data` - Form metadata - -**Usage:** -```php -add_action('srfm_before_email_send', function($parsed, $submission_data, $item, $form_data) { - // Log email send attempt - error_log(sprintf( - 'Sending email to %s for form %d', - $parsed['to'], - $form_data['form_id'] ?? 0 - )); - - // Save email to custom table for tracking - global $wpdb; - $wpdb->insert('wp_email_log', [ - 'recipient' => $parsed['to'], - 'subject' => $parsed['subject'], - 'sent_at' => current_time('mysql') - ]); -}, 10, 4); -``` - -### `srfm_after_email_send` - -Action fired after email is sent. - -**Location:** [inc/form-submit.php:904-905](../../inc/form-submit.php) -**Since:** Various -**Parameters:** -- `array $parsed` - Email data -- `array $submission_data` - Form data -- `array $item` - Email config -- `array $form_data` - Form metadata -- `bool $sent` - Whether email was sent successfully - -**Usage:** -```php -add_action('srfm_after_email_send', function($parsed, $submission_data, $item, $form_data, $sent) { - if (!$sent) { - // Email failed to send - error_log(sprintf( - 'Email failed for form %d to %s', - $form_data['form_id'] ?? 0, - $parsed['to'] - )); - - // Send alert to admin - wp_mail( - get_option('admin_email'), - 'Form email notification failed', - sprintf('Failed to send notification for form %d', $form_data['form_id']) - ); - } -}, 10, 5); -``` - ---- - -## Data Modification - -### `srfm_form_submit_data` - -Filters complete form submission data before processing. - -**Location:** [inc/form-submit.php:474](../../inc/form-submit.php) -**Since:** 0.0.1 -**Parameters:** -- `array $form_data` - Complete form data - -**Return:** `array` - Modified form data - -**Usage:** -```php -add_filter('srfm_form_submit_data', function($form_data) { - // Add custom calculated field - if (isset($form_data['price'], $form_data['quantity'])) { - $form_data['total'] = [ - 'value' => $form_data['price']['value'] * $form_data['quantity']['value'], - 'label' => 'Total Amount', - 'type' => 'calculated' - ]; - } - - // Add timestamp - $form_data['submitted_timestamp'] = [ - 'value' => current_time('mysql'), - 'label' => 'Submission Time', - 'type' => 'hidden' - ]; - - return $form_data; -}, 10, 1); -``` - -### `srfm_before_entry_data` - -Filters entry data before saving to database. - -**Location:** [inc/form-submit.php:605-606](../../inc/form-submit.php) -**Since:** 0.0.1 -**Parameters:** -- `array $entries_data` - Entry data to be saved -- `int $form_id` - Form post ID - -**Return:** `array` - Modified entry data - -**Usage:** -```php -add_filter('srfm_before_entry_data', function($entries_data, $form_id) { - // Add custom extras data - $entries_data['extras'] = [ - 'ip_country' => get_user_ip_country(), - 'utm_source' => $_GET['utm_source'] ?? '', - 'utm_campaign' => $_GET['utm_campaign'] ?? '', - 'referrer' => wp_get_referer() - ]; - - // Modify status based on conditions - if ($form_id === 123) { - $entries_data['status'] = 'pending_review'; // Custom status - } - - return $entries_data; -}, 10, 2); -``` - -### `srfm_form_submission_response` - -Filters final submission response sent to frontend. - -**Location:** [inc/form-submit.php:660](../../inc/form-submit.php) -**Since:** 2.4.0 -**Parameters:** -- `array $response` - Response data (success, message, entry_id) -- `array $form_data` - Form data -- `array $submission_data` - Submission data - -**Return:** `array` - Modified response - -**Usage:** -```php -add_filter('srfm_form_submission_response', function($response, $form_data, $submission_data) { - // Add custom data to response - if ($response['success']) { - $response['custom_redirect_url'] = 'https://example.com/thank-you'; - $response['tracking_code'] = 'FB-' . $response['entry_id']; - - // Add custom message - $response['custom_message'] = sprintf( - 'Thank you! Your reference number is %d', - $response['entry_id'] - ); - } - - return $response; -}, 10, 3); -``` - -### `srfm_process_field_value` - -Filters individual field value during processing. - -**Location:** [inc/form-submit.php:1211-1212](../../inc/form-submit.php) -**Since:** 0.0.1 -**Parameters:** -- `mixed $value` - Field value -- `array $field` - Field data -- `array $form_data` - Complete form data - -**Return:** `mixed` - Modified field value - -**Usage:** -```php -add_filter('srfm_process_field_value', function($value, $field, $form_data) { - // Normalize phone numbers - if ($field['type'] === 'phone') { - $value = preg_replace('/[^0-9+]/', '', $value); - } - - // Convert text to uppercase for specific field - if ($field['slug'] === 'reference_code') { - $value = strtoupper($value); - } - - // Encrypt sensitive data - if ($field['slug'] === 'ssn') { - $value = encrypt_data($value); - } - - return $value; -}, 10, 3); -``` - ---- - -## Form Rendering - -### `srfm_form_markup` - -Filters complete form HTML before rendering. - -**Location:** [inc/generate-form-markup.php](../../inc/generate-form-markup.php) -**Since:** 0.0.1 -**Parameters:** -- `string $markup` - Generated HTML -- `int $form_id` - Form post ID -- `array $blocks` - Gutenberg blocks array - -**Return:** `string` - Modified HTML - -**Usage:** -```php -add_filter('srfm_form_markup', function($markup, $form_id, $blocks) { - // Add custom wrapper - $markup = '<div class="custom-form-wrapper">' . $markup . '</div>'; - - // Add custom analytics tracking - $markup .= sprintf( - '<script>trackFormView(%d);</script>', - $form_id - ); - - return $markup; -}, 10, 3); -``` - -### `srfm_field_markup` - -Filters individual field HTML. - -**Location:** [inc/fields/base.php](../../inc/fields/base.php) -**Since:** 0.0.1 -**Parameters:** -- `string $markup` - Field HTML -- `array $attributes` - Block attributes -- `string $field_type` - Field type (input, email, etc.) - -**Return:** `string` - Modified HTML - -**Usage:** -```php -add_filter('srfm_field_markup', function($markup, $attributes, $field_type) { - // Add custom class to all email fields - if ($field_type === 'email') { - $markup = str_replace( - 'class="srfm-field', - 'class="srfm-field custom-email-field', - $markup - ); - } - - // Add tooltips - if (!empty($attributes['help_text'])) { - $markup .= sprintf( - '<span class="tooltip">%s</span>', - esc_html($attributes['help_text']) - ); - } - - return $markup; -}, 10, 3); -``` - -### `srfm_form_class` - -Filters CSS classes applied to form element. - -**Location:** [inc/generate-form-markup.php](../../inc/generate-form-markup.php) -**Since:** 0.0.1 -**Parameters:** -- `array $classes` - CSS class array -- `int $form_id` - Form post ID - -**Return:** `array` - Modified classes - -**Usage:** -```php -add_filter('srfm_form_class', function($classes, $form_id) { - // Add custom class - $classes[] = 'custom-form'; - - // Add class based on form ID - $classes[] = 'form-' . $form_id; - - // Add class based on form type - $form_type = get_post_meta($form_id, '_srfm_form_type', true); - if ($form_type === 'contact') { - $classes[] = 'contact-form'; - } - - return $classes; -}, 10, 2); -``` - ---- - -## Database Operations - -### `srfm_before_delete_entry` - -Action fired before entry is permanently deleted from database. - -**Location:** [inc/database/tables/entries.php:297](../../inc/database/tables/entries.php) -**Since:** 0.0.13 -**Parameters:** -- `int $entry_id` - Entry ID being deleted - -**Usage:** -```php -add_action('srfm_before_delete_entry', function($entry_id) { - // Log deletion - error_log(sprintf('Deleting entry %d', $entry_id)); - - // Clean up related data - global $wpdb; - $wpdb->delete('wp_custom_entry_meta', ['entry_id' => $entry_id]); - - // Archive entry before deletion - $entry = SRFM\Inc\Database\Tables\Entries::get($entry_id); - if ($entry) { - $wpdb->insert('wp_deleted_entries_archive', [ - 'entry_id' => $entry_id, - 'form_data' => wp_json_encode($entry), - 'deleted_at' => current_time('mysql') - ]); - } -}, 10, 1); -``` - ---- - -## Payment Processing - -### `srfm_before_payment_process` - -Action fired before payment processing starts. - -**Location:** [inc/payments/front-end.php](../../inc/payments/front-end.php) -**Since:** 2.0.0 -**Parameters:** -- `array $payment_data` - Payment data -- `int $form_id` - Form post ID - -**Usage:** -```php -add_action('srfm_before_payment_process', function($payment_data, $form_id) { - // Log payment attempt - error_log(sprintf( - 'Processing payment of %s %s for form %d', - $payment_data['amount'], - $payment_data['currency'], - $form_id - )); - - // Verify inventory before charging - if ($form_id === 123) { - $product_id = $payment_data['product_id'] ?? 0; - if (!check_inventory($product_id)) { - throw new Exception('Product out of stock'); - } - } -}, 10, 2); -``` - -### `srfm_after_payment_success` - -Action fired after successful payment. - -**Location:** [inc/payments/front-end.php](../../inc/payments/front-end.php) -**Since:** 2.0.0 -**Parameters:** -- `int $payment_id` - Payment record ID -- `array $payment_data` - Payment data -- `int $entry_id` - Entry ID - -**Usage:** -```php -add_action('srfm_after_payment_success', function($payment_id, $payment_data, $entry_id) { - // Send receipt - $customer_email = $payment_data['customer_email']; - wp_mail( - $customer_email, - 'Payment Receipt', - sprintf('Payment of %s received', $payment_data['total_amount']) - ); - - // Update inventory - update_inventory($payment_data['product_id'], -1); - - // Trigger fulfillment - trigger_order_fulfillment($payment_id); -}, 10, 3); -``` - ---- - -## Block Registration - -### `srfm_block_registration_args` - -Filters block registration arguments. - -**Location:** [inc/blocks/register.php](../../inc/blocks/register.php) -**Since:** 0.0.1 -**Parameters:** -- `array $args` - Block registration args -- `string $block_name` - Block name (sureforms/input, etc.) - -**Return:** `array` - Modified args - -**Usage:** -```php -add_filter('srfm_block_registration_args', function($args, $block_name) { - // Modify render callback - if ($block_name === 'sureforms/input') { - $original_callback = $args['render_callback']; - $args['render_callback'] = function($attributes, $content) use ($original_callback) { - // Wrap output in custom div - $output = call_user_func($original_callback, $attributes, $content); - return '<div class="custom-wrapper">' . $output . '</div>'; - }; - } - - return $args; -}, 10, 2); -``` - ---- - -## Admin Operations - -### `srfm_after_form_created` - -Action fired after new form is created. - -**Location:** [inc/create-new-form.php](../../inc/create-new-form.php) -**Since:** 0.0.1 -**Parameters:** -- `int $form_id` - Created form post ID - -**Usage:** -```php -add_action('srfm_after_form_created', function($form_id) { - // Set default form settings - update_post_meta($form_id, '_srfm_custom_setting', 'default_value'); - - // Log form creation - error_log(sprintf('New form created: %d', $form_id)); - - // Notify admin - wp_mail( - get_option('admin_email'), - 'New form created', - sprintf('Form ID %d was created', $form_id) - ); -}, 10, 1); -``` - ---- - -## Form Restrictions - -### `srfm_form_restriction_message` - -Filters restriction message shown to users. - -**Location:** [inc/form-submit.php:267](../../inc/form-submit.php) -**Since:** Various -**Parameters:** -- `string $message` - Default restriction message -- `int $form_id` - Form post ID -- `array $form_restriction` - Restriction settings - -**Return:** `string` - Modified message - -**Usage:** -```php -add_filter('srfm_form_restriction_message', function($message, $form_id, $form_restriction) { - // Custom message based on restriction type - if ($form_restriction['type'] === 'schedule' && $form_restriction['state'] === 'not_started') { - $message = sprintf( - 'This form will open on %s', - date('F j, Y', strtotime($form_restriction['start_date'])) - ); - } - - return $message; -}, 10, 3); -``` - -### `srfm_additional_restriction_check` - -Filters whether form has additional restrictions beyond scheduling. - -**Location:** [inc/form-submit.php:276](../../inc/form-submit.php) -**Since:** Various -**Parameters:** -- `bool $is_restricted` - Whether form is restricted -- `int $form_id` - Form post ID -- `array $form_data` - Form data - -**Return:** `bool` - True to restrict, false to allow - -**Usage:** -```php -add_filter('srfm_additional_restriction_check', function($is_restricted, $form_id, $form_data) { - // Restrict based on user role - if ($form_id === 123 && !current_user_can('subscriber')) { - return true; // Restrict - } - - // Restrict based on IP - $user_ip = $_SERVER['REMOTE_ADDR']; - if (is_ip_blocked($user_ip)) { - return true; - } - - // Restrict based on previous submissions - $user_email = $form_data['email']['value'] ?? ''; - if ($user_email && has_recent_submission($form_id, $user_email)) { - return true; // Already submitted recently - } - - return $is_restricted; -}, 10, 3); -``` - ---- - -## Integration Points - -### Third-Party Service Integration Example - -```php -/** - * Complete integration example: Send form data to CRM after submission - */ -class SureForms_CRM_Integration { - public function __construct() { - add_action('srfm_after_submission_process', [$this, 'send_to_crm'], 10, 1); - add_action('srfm_before_delete_entry', [$this, 'delete_from_crm'], 10, 1); - } - - public function send_to_crm($form_data) { - // Only for contact forms - if ($form_data['form_id'] !== 123) { - return; - } - - $crm_data = [ - 'email' => $form_data['email']['value'] ?? '', - 'name' => $form_data['name']['value'] ?? '', - 'phone' => $form_data['phone']['value'] ?? '', - 'company' => $form_data['company']['value'] ?? '', - 'source' => 'sureforms', - 'entry_id' => $form_data['entry_id'] ?? 0 - ]; - - $response = wp_remote_post('https://crm.example.com/api/leads', [ - 'body' => json_encode($crm_data), - 'headers' => [ - 'Content-Type' => 'application/json', - 'Authorization' => 'Bearer ' . get_option('crm_api_key') - ] - ]); - - if (is_wp_error($response)) { - error_log('CRM sync failed: ' . $response->get_error_message()); - } else { - $crm_id = json_decode(wp_remote_retrieve_body($response))->id; - // Store CRM ID with entry - update_post_meta($form_data['entry_id'], '_crm_lead_id', $crm_id); - } - } - - public function delete_from_crm($entry_id) { - $crm_id = get_post_meta($entry_id, '_crm_lead_id', true); - if ($crm_id) { - wp_remote_request('https://crm.example.com/api/leads/' . $crm_id, [ - 'method' => 'DELETE', - 'headers' => [ - 'Authorization' => 'Bearer ' . get_option('crm_api_key') - ] - ]); - } - } -} - -new SureForms_CRM_Integration(); -``` - ---- - -## Hook Priority Guidelines - -**Priority Values:** -- **5:** Execute before default behavior -- **10:** Default priority (most hooks) -- **15:** Execute after default behavior -- **20+:** Late execution -- **100+:** Very late (cleanup, logging) - -**Example:** -```php -// Execute before SureForms processes submission -add_action('srfm_before_submission', 'my_function', 5); - -// Execute at default time -add_action('srfm_before_submission', 'my_function', 10); - -// Execute after SureForms processes submission -add_action('srfm_before_submission', 'my_function', 15); -``` - ---- - -## Debugging Hooks - -### Enable Hook Debugging - -```php -// Add to wp-config.php -define('SRFM_DEBUG_HOOKS', true); - -// Log all SureForms hooks -add_action('all', function($hook) { - if (strpos($hook, 'srfm_') === 0) { - error_log('Hook fired: ' . $hook); - } -}); -``` - -### View Hook Execution Order - -```php -// Log hook priority and callback -add_action('all', function($hook) { - if (strpos($hook, 'srfm_') === 0) { - global $wp_filter; - if (isset($wp_filter[$hook])) { - foreach ($wp_filter[$hook]->callbacks as $priority => $callbacks) { - foreach ($callbacks as $callback) { - error_log(sprintf( - 'Hook: %s, Priority: %d, Callback: %s', - $hook, - $priority, - is_array($callback['function']) ? - get_class($callback['function'][0]) . '::' . $callback['function'][1] : - $callback['function'] - )); - } - } - } - } -}); -``` - ---- - -## Best Practices - -### 1. Always Check Hook Existence - -```php -if (function_exists('add_action')) { - add_action('srfm_after_submission_process', 'my_function'); -} -``` - -### 2. Use Proper Nonces for Custom Forms - -```php -add_filter('srfm_before_entry_data', function($data, $form_id) { - // Verify custom nonce if adding custom fields - if (isset($_POST['custom_nonce'])) { - if (!wp_verify_nonce($_POST['custom_nonce'], 'custom_action')) { - return new WP_Error('nonce_failed', 'Security check failed'); - } - } - return $data; -}, 10, 2); -``` - -### 3. Return Correct Data Types - -```php -// Filter must return array -add_filter('srfm_form_submit_data', function($data) { - // ✅ GOOD - returns array - return array_merge($data, ['custom' => 'value']); - - // ❌ BAD - returns nothing - // (void return breaks functionality) -}, 10, 1); -``` - -### 4. Handle Errors Gracefully - -```php -add_action('srfm_after_submission_process', function($form_data) { - try { - // Risky operation - send_to_external_api($form_data); - } catch (Exception $e) { - error_log('External API failed: ' . $e->getMessage()); - // Don't throw - allow submission to continue - } -}, 10, 1); -``` - ---- - -## Summary - -**Hook Categories:** -- **Lifecycle:** 2 hooks (core_loaded, init) -- **Submission:** 10+ hooks (before, during, after) -- **Validation:** 5+ hooks (field-specific and general) -- **Email:** 5+ hooks (before, during, after send) -- **Rendering:** 10+ hooks (markup, classes, attributes) -- **Data:** 8+ hooks (modify, filter, transform) -- **Database:** 3+ hooks (before/after operations) -- **Payment:** 6+ hooks (process, success, failure) -- **Admin:** 5+ hooks (form creation, updates) - -**Total:** 450+ hooks across the plugin - -**Auto-Generation Note:** This document contains the most commonly used hooks. For a complete list, run the hook extraction script: -```bash -php scripts/extract-hooks.php > docs/COMPLETE-HOOKS-LIST.md -``` - ---- - -**Related Documentation:** -- [CLAUDE.md](../../CLAUDE.md) - AI agent guide -- [ARCHITECTURE.md](../02-architecture/ARCHITECTURE.md) - System design -- [REST-API.md](REST-API.md) - REST API endpoints -- [DATABASE-SCHEMA.md](DATABASE-SCHEMA.md) - Database tables diff --git a/docs/05-frontend/FRONTEND-GUIDE.md b/docs/05-frontend/FRONTEND-GUIDE.md deleted file mode 100644 index d26f09ee8..000000000 --- a/docs/05-frontend/FRONTEND-GUIDE.md +++ /dev/null @@ -1,1197 +0,0 @@ -# SureForms Frontend Development Guide - -> **Purpose:** Comprehensive guide for React/Gutenberg block development -> **Audience:** Frontend developers working with React, Gutenberg, and WordPress -> **Last Updated:** 2026-02-06 -> **Plugin Version:** 2.5.0 - -## Overview - -SureForms frontend is built with modern JavaScript technologies integrated deeply with WordPress's Gutenberg block editor: - -- **React 18.2:** UI components and interactive features -- **Gutenberg Blocks:** WordPress block editor integration for form building -- **TailwindCSS 3.4:** Utility-first CSS framework -- **React Query 5.x:** Server state management and caching -- **@wordpress/scripts 26.2:** Build tooling (Webpack 5 wrapper) - ---- - -## Table of Contents - -- [Architecture Overview](#architecture-overview) -- [Directory Structure](#directory-structure) -- [Creating Gutenberg Blocks](#creating-gutenberg-blocks) -- [State Management](#state-management) -- [Component Patterns](#component-patterns) -- [Styling](#styling) -- [Form Validation](#form-validation) -- [Internationalization](#internationalization) -- [Performance Optimization](#performance-optimization) -- [Testing](#testing) - ---- - -## Architecture Overview - -### Technology Stack - -``` -┌─────────────────────────────────────────┐ -│ Admin UI (React Apps) │ -│ Dashboard, Settings, Entries, Editor │ -└──────────────┬──────────────────────────┘ - │ - ┌──────────┴──────────┐ - │ │ -┌───▼────────┐ ┌──────▼──────┐ -│ Gutenberg │ │ Admin │ -│ Blocks │ │ Pages │ -│ (Editor) │ │ (Router) │ -└───┬────────┘ └──────┬──────┘ - │ │ - └──────────┬─────────┘ - │ - ┌──────────▼──────────┐ - │ State Management │ - │ Data Store + Hooks │ - └──────────┬──────────┘ - │ - ┌──────────▼──────────┐ - │ REST API │ - │ /sureforms/v1/* │ - └─────────────────────┘ -``` - -### Component Layers - -1. **Gutenberg Block Layer** - Form builder blocks (src/blocks/) -2. **Admin UI Layer** - React SPA pages (src/admin/) -3. **Shared Components** - Reusable UI (src/components/) -4. **State Layer** - Data stores (src/store/) -5. **API Layer** - WordPress REST API - ---- - -## Directory Structure - -``` -src/ -├── blocks/ # Gutenberg block components -│ ├── blocks.js # Block registration entry -│ ├── register-block.js # Block utilities -│ │ -│ ├── sform/ # Form container block -│ │ ├── index.js # Block registration -│ │ ├── edit.js # Editor component -│ │ ├── save.js # Frontend save (returns null) -│ │ ├── block.json # Block metadata -│ │ ├── components/ # Block-specific components -│ │ └── style.scss # Block styles -│ │ -│ ├── input/ # Text input field block -│ │ ├── edit.js # Editor with InspectorControls -│ │ ├── save.js # Server-side rendering -│ │ └── block.json # Attributes schema -│ │ -│ └── [14+ more blocks] # Email, textarea, checkbox, etc. -│ -├── admin/ # Admin dashboard React apps -│ ├── dashboard/ # Forms listing page -│ │ ├── index.js # Entry point -│ │ ├── FormsTable.js # Table component -│ │ ├── Analytics.js # Analytics widgets -│ │ └── styles.scss -│ │ -│ ├── single-form-settings/ # Form editor -│ │ ├── Editor.js # Main editor wrapper -│ │ ├── InstantForm.js # Live preview -│ │ ├── tabs/ # Settings tabs -│ │ │ ├── GeneralSettings.js -│ │ │ └── StyleSettings.js -│ │ └── components/ # Editor components -│ │ -│ ├── entries/ # Entry management -│ ├── settings/ # Global settings -│ ├── payment/ # Payment settings -│ └── onboarding/ # Setup wizard -│ -├── components/ # Shared React components -│ ├── ui/ # UI primitives -│ │ ├── Button/ -│ │ ├── Input/ -│ │ ├── Modal/ -│ │ └── Tooltip/ -│ │ -│ ├── form/ # Form-specific -│ │ ├── FieldWrapper/ -│ │ ├── ValidationMessage/ -│ │ └── FormContainer/ -│ │ -│ ├── inspector-tabs/ # Block editor tabs -│ ├── color-switch-control/ # Color picker -│ ├── spacing-control/ # Responsive spacing -│ └── [40+ component dirs] -│ -├── srfm-controls/ # Gutenberg block controls -│ ├── index.js # Control registry -│ ├── getPreviewType.js # Responsive preview -│ └── [18+ control definitions] -│ -├── store/ # WordPress Data Store (Redux) -│ ├── store.js # Store creation -│ ├── actions.js # Action creators -│ ├── reducer.js # Reducer function -│ ├── selectors.js # Selectors -│ └── constants.js # Action types -│ -├── utils/ # Utility functions -│ ├── Helpers.js # Common helpers -│ ├── datePickerHelper.js -│ └── addressFieldHelper.js -│ -└── styles/ # Global styles - ├── typography/ - └── breakpoints/ -``` - -**Build Output:** -``` -assets/build/ -├── formEditor.js # Form editor bundle (~1.9MB) -├── blocks.js # Gutenberg blocks (~1.3MB) -├── dashboard.js # Dashboard page (~1.3MB) -├── entries.js # Entries page (~728KB) -├── forms.js # Forms listing (~727KB) -├── settings.js # Settings page (~1.1MB) -├── formSubmit.js # Frontend submission (~60KB) -└── *.asset.php # Webpack dependency manifests -``` - ---- - -## Creating Gutenberg Blocks - -### Block Anatomy - -Every form field block consists of: -1. **block.json** - Metadata and attributes schema -2. **edit.js** - Editor component (React) -3. **save.js** - Frontend rendering (usually null, PHP renders) -4. **style.scss** - Block-specific styles -5. **PHP class** - Server-side registration and rendering - -### Step-by-Step: Create a New Block - -#### Step 1: Create Block Directory - -```bash -mkdir -p src/blocks/custom-field -cd src/blocks/custom-field -``` - -#### Step 2: Create block.json - -**File:** [src/blocks/custom-field/block.json](../../src/blocks/custom-field/block.json) - -```json -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, - "name": "sureforms/custom-field", - "title": "Custom Field", - "category": "sureforms", - "icon": "text", - "description": "A custom form field", - "keywords": ["form", "custom", "field"], - "supports": { - "html": false, - "anchor": false, - "customClassName": false - }, - "attributes": { - "label": { - "type": "string", - "default": "Custom Field" - }, - "slug": { - "type": "string", - "default": "custom_field" - }, - "placeholder": { - "type": "string", - "default": "" - }, - "required": { - "type": "boolean", - "default": false - }, - "helpText": { - "type": "string", - "default": "" - } - }, - "editorScript": "file:./index.js", - "editorStyle": "file:./editor.scss", - "style": "file:./style.scss" -} -``` - -#### Step 3: Create edit.js (Editor Component) - -**File:** [src/blocks/custom-field/edit.js](../../src/blocks/custom-field/edit.js) - -```javascript -import { __ } from '@wordpress/i18n'; -import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; -import { PanelBody, TextControl, ToggleControl, TextareaControl } from '@wordpress/components'; - -export default function Edit({ attributes, setAttributes, clientId }) { - const { label, slug, placeholder, required, helpText } = attributes; - - const blockProps = useBlockProps({ - className: 'srfm-block srfm-custom-field-block', - }); - - return ( - <> - {/* Inspector Panel (Right Sidebar) */} - <InspectorControls> - <PanelBody title={__('Field Settings', 'sureforms')}> - <TextControl - label={__('Label', 'sureforms')} - value={label} - onChange={(value) => setAttributes({ label: value })} - help={__('Field label shown to users', 'sureforms')} - /> - - <TextControl - label={__('Field Slug', 'sureforms')} - value={slug} - onChange={(value) => setAttributes({ slug: value })} - help={__('Unique identifier for this field', 'sureforms')} - /> - - <TextControl - label={__('Placeholder', 'sureforms')} - value={placeholder} - onChange={(value) => setAttributes({ placeholder: value })} - /> - - <ToggleControl - label={__('Required', 'sureforms')} - checked={required} - onChange={(value) => setAttributes({ required: value })} - /> - - <TextareaControl - label={__('Help Text', 'sureforms')} - value={helpText} - onChange={(value) => setAttributes({ helpText: value })} - help={__('Additional instructions for users', 'sureforms')} - /> - </PanelBody> - </InspectorControls> - - {/* Block Preview in Editor */} - <div {...blockProps}> - <div className="srfm-field-wrapper"> - <label className="srfm-field__label"> - {label} - {required && <span className="required">*</span>} - </label> - - <input - type="text" - className="srfm-field__input" - placeholder={placeholder} - disabled - /> - - {helpText && ( - <span className="srfm-field__help-text"> - {helpText} - </span> - )} - </div> - </div> - </> - ); -} -``` - -#### Step 4: Create save.js - -**File:** [src/blocks/custom-field/save.js](../../src/blocks/custom-field/save.js) - -```javascript -/** - * Save function - return null for dynamic blocks (rendered server-side). - * - * SureForms blocks are rendered server-side via PHP for: - * - Better security (no client-side data exposure) - * - Consistent rendering across contexts - * - Easier form submission handling - */ -export default function save() { - return null; -} -``` - -#### Step 5: Create index.js (Registration) - -**File:** [src/blocks/custom-field/index.js](../../src/blocks/custom-field/index.js) - -```javascript -import { registerBlockType } from '@wordpress/blocks'; -import Edit from './edit'; -import save from './save'; -import metadata from './block.json'; - -// Register block -registerBlockType(metadata.name, { - ...metadata, - edit: Edit, - save, -}); -``` - -#### Step 6: Add to blocks.js - -**File:** [src/blocks/blocks.js](../../src/blocks/blocks.js) - -```javascript -// ... other imports -import './custom-field'; -``` - -#### Step 7: Create PHP Server-Side Rendering - -**File:** [inc/blocks/custom-field/class-custom-field.php](../../inc/blocks/custom-field/class-custom-field.php) - -```php -<?php -namespace SRFM\Inc\Blocks\CustomField; - -use SRFM\Inc\Blocks\Base; -use SRFM\Inc\Traits\Get_Instance; - -class Custom_Field extends Base { - use Get_Instance; - - protected $block_name = 'custom-field'; - - /** - * Render callback for frontend. - * - * @param array $attributes Block attributes. - * @param string $content Block content. - * @return string HTML output. - */ - public function render_callback($attributes, $content) { - $label = $attributes['label'] ?? ''; - $slug = $attributes['slug'] ?? 'custom_field'; - $placeholder = $attributes['placeholder'] ?? ''; - $required = $attributes['required'] ?? false; - $help_text = $attributes['helpText'] ?? ''; - - ob_start(); - ?> - <div class="srfm-field srfm-custom-field"> - <label for="<?php echo esc_attr($slug); ?>" class="srfm-field__label"> - <?php echo esc_html($label); ?> - <?php if ($required): ?> - <span class="required">*</span> - <?php endif; ?> - </label> - - <input - type="text" - id="<?php echo esc_attr($slug); ?>" - name="<?php echo esc_attr($slug); ?>" - class="srfm-field__input" - placeholder="<?php echo esc_attr($placeholder); ?>" - <?php echo $required ? 'required' : ''; ?> - <?php echo $required ? 'aria-required="true"' : ''; ?> - /> - - <?php if ($help_text): ?> - <span class="srfm-field__help-text"> - <?php echo esc_html($help_text); ?> - </span> - <?php endif; ?> - </div> - <?php - return ob_get_clean(); - } -} -``` - -#### Step 8: Register PHP Class - -**File:** [inc/blocks/register.php](../../inc/blocks/register.php) - -```php -use SRFM\Inc\Blocks\CustomField\Custom_Field; - -// Register custom field block -Custom_Field::get_instance(); -``` - -#### Step 9: Build and Test - -```bash -# Build assets -npm run build - -# Hard refresh browser (Cmd/Ctrl + Shift + R) - -# Test in block editor: -# 1. Create/edit form -# 2. Click "+" to add block -# 3. Find "Custom Field" in inserter -# 4. Add to form -# 5. Test settings in Inspector panel -# 6. Save and preview frontend -``` - ---- - -## State Management - -SureForms uses **three layers** of state management: - -### 1. Local Component State (useState) - -For component-specific state that doesn't need to be shared. - -```javascript -import { useState } from 'react'; - -function FormField({ initialValue }) { - const [value, setValue] = useState(initialValue); - const [error, setError] = useState(''); - - const handleChange = (e) => { - setValue(e.target.value); - - // Validate - if (e.target.value.length < 3) { - setError('Minimum 3 characters'); - } else { - setError(''); - } - }; - - return ( - <div> - <input value={value} onChange={handleChange} /> - {error && <span className="error">{error}</span>} - </div> - ); -} -``` - -### 2. WordPress Data Store (Redux-based) - -For block editor state and form metadata. - -**Define Store** ([src/store/store.js](../../src/store/store.js)): - -```javascript -import { createReduxStore, register } from '@wordpress/data'; -import apiFetch from '@wordpress/api-fetch'; - -const DEFAULT_STATE = { - formSettings: {}, - blockAttributes: {}, - isLoading: false, -}; - -const actions = { - setFormSettings(settings) { - return { - type: 'SET_FORM_SETTINGS', - settings, - }; - }, - - updateBlockAttribute(blockId, attribute, value) { - return { - type: 'UPDATE_BLOCK_ATTRIBUTE', - blockId, - attribute, - value, - }; - }, - - *fetchFormSettings(formId) { - yield { type: 'SET_LOADING', isLoading: true }; - - try { - const settings = yield apiFetch({ - path: `/sureforms/v1/forms/${formId}/settings`, - }); - - return actions.setFormSettings(settings); - } catch (error) { - console.error('Failed to fetch settings:', error); - return { type: 'FETCH_ERROR', error }; - } - }, -}; - -const selectors = { - getFormSettings(state) { - return state.formSettings; - }, - - getBlockAttribute(state, blockId, attribute) { - return state.blockAttributes[blockId]?.[attribute]; - }, - - isLoading(state) { - return state.isLoading; - }, -}; - -const reducer = (state = DEFAULT_STATE, action) => { - switch (action.type) { - case 'SET_FORM_SETTINGS': - return { - ...state, - formSettings: action.settings, - isLoading: false, - }; - - case 'UPDATE_BLOCK_ATTRIBUTE': - return { - ...state, - blockAttributes: { - ...state.blockAttributes, - [action.blockId]: { - ...state.blockAttributes[action.blockId], - [action.attribute]: action.value, - }, - }, - }; - - case 'SET_LOADING': - return { - ...state, - isLoading: action.isLoading, - }; - - default: - return state; - } -}; - -export const store = createReduxStore('srfm/forms', { - reducer, - actions, - selectors, -}); - -register(store); -``` - -**Use Store in Components:** - -```javascript -import { useSelect, useDispatch } from '@wordpress/data'; - -function FormEditor({ formId }) { - // Select data from store - const { formSettings, isLoading } = useSelect((select) => ({ - formSettings: select('srfm/forms').getFormSettings(), - isLoading: select('srfm/forms').isLoading(), - })); - - // Dispatch actions to store - const { fetchFormSettings, setFormSettings } = useDispatch('srfm/forms'); - - useEffect(() => { - fetchFormSettings(formId); - }, [formId]); - - if (isLoading) { - return <Spinner />; - } - - return ( - <div> - <h2>{formSettings.title}</h2> - {/* Editor UI */} - </div> - ); -} -``` - -### 3. React Query (Server State) - -For API responses and caching. - -**Setup Query Client** ([src/admin/dashboard/index.js](../../src/admin/dashboard/index.js)): - -```javascript -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - staleTime: 5 * 60 * 1000, // 5 minutes - retry: 1, - }, - }, -}); - -function App() { - return ( - <QueryClientProvider client={queryClient}> - <Dashboard /> - </QueryClientProvider> - ); -} -``` - -**Create Custom Hooks** ([src/hooks/useFormData.js](../../src/hooks/)): - -```javascript -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; -import apiFetch from '@wordpress/api-fetch'; - -// Fetch form data -export function useFormData(formId) { - return useQuery({ - queryKey: ['form', formId], - queryFn: async () => { - const response = await apiFetch({ - path: `/sureforms/v1/forms/${formId}`, - }); - return response; - }, - enabled: !!formId, - }); -} - -// Update form data -export function useUpdateForm() { - const queryClient = useQueryClient(); - - return useMutation({ - mutationFn: async ({ formId, data }) => { - return await apiFetch({ - path: `/sureforms/v1/forms/${formId}`, - method: 'PUT', - data, - }); - }, - onSuccess: (data, variables) => { - // Invalidate and refetch - queryClient.invalidateQueries(['form', variables.formId]); - }, - }); -} - -// Fetch entries -export function useEntries(formId, page = 1) { - return useQuery({ - queryKey: ['entries', formId, page], - queryFn: async () => { - return await apiFetch({ - path: `/sureforms/v1/forms/${formId}/entries?page=${page}`, - }); - }, - keepPreviousData: true, // For pagination - }); -} -``` - -**Use in Components:** - -```javascript -function FormEditor({ formId }) { - const { data: form, isLoading, error } = useFormData(formId); - const updateForm = useUpdateForm(); - - const handleSave = async () => { - try { - await updateForm.mutateAsync({ - formId, - data: { title: 'Updated Title' }, - }); - // Success toast - toast.success('Form saved!'); - } catch (error) { - // Error toast - toast.error('Failed to save form'); - } - }; - - if (isLoading) return <Spinner />; - if (error) return <div>Error: {error.message}</div>; - - return ( - <div> - <h2>{form.title}</h2> - <button onClick={handleSave}>Save</button> - </div> - ); -} -``` - ---- - -## Component Patterns - -### Functional Components with Hooks - -**Always use functional components** (not class components): - -```javascript -// ✅ GOOD - Functional component -function MyComponent({ prop1, prop2 }) { - const [state, setState] = useState(null); - - useEffect(() => { - // Side effects - }, []); - - return <div>{/* JSX */}</div>; -} - -// ❌ BAD - Class component (deprecated pattern) -class MyComponent extends React.Component { - // Don't use class components in SureForms -} -``` - -### Props Destructuring - -```javascript -// ✅ GOOD - Destructure in signature -function Button({ label, onClick, disabled = false, variant = 'primary' }) { - return ( - <button - onClick={onClick} - disabled={disabled} - className={`btn btn--${variant}`} - > - {label} - </button> - ); -} - -// ❌ BAD - Access via props object -function Button(props) { - return <button onClick={props.onClick}>{props.label}</button>; -} -``` - -### Conditional Rendering - -```javascript -function FormField({ label, required, error }) { - return ( - <div className="form-field"> - <label> - {label} - {/* Short-circuit evaluation */} - {required && <span className="required">*</span>} - </label> - - {/* Ternary for if/else */} - {error ? ( - <span className="error">{error}</span> - ) : ( - <span className="hint">Optional</span> - )} - - {/* Conditional with && */} - {!error && <span className="success">Valid</span>} - </div> - ); -} -``` - -### Event Handlers - -```javascript -function FormContainer() { - // useCallback for stable reference - const handleSubmit = useCallback((event) => { - event.preventDefault(); - // Handle submit - }, []); - - // Arrow function for inline with parameters - const handleFieldChange = useCallback((fieldId, value) => { - setFormData((prev) => ({ - ...prev, - [fieldId]: value, - })); - }, []); - - return ( - <form onSubmit={handleSubmit}> - <input - onChange={(e) => handleFieldChange('name', e.target.value)} - /> - </form> - ); -} -``` - ---- - -## Styling - -### TailwindCSS (Preferred) - -Use Tailwind utility classes for rapid development: - -```javascript -function Card({ title, children }) { - return ( - <div className="bg-white rounded-lg shadow-md p-6 mb-4"> - <h3 className="text-xl font-semibold text-gray-800 mb-4"> - {title} - </h3> - <div className="text-gray-600"> - {children} - </div> - </div> - ); -} -``` - -**Responsive Design:** - -```javascript -<div className="w-full md:w-1/2 lg:w-1/3"> - {/* Full width mobile, half on tablet, third on desktop */} -</div> - -<div className="text-sm md:text-base lg:text-lg"> - {/* Responsive text size */} -</div> -``` - -### Custom SCSS (When Needed) - -**Use BEM methodology** with `.srfm-` prefix: - -```scss -// style.scss -.srfm-custom-field { - // Block - &__label { - // Element - @apply block text-sm font-medium text-gray-700 mb-2; - - .required { - // Nested element - @apply text-red-500 ml-1; - } - } - - &__input { - // Element - @apply w-full px-4 py-2 border border-gray-300 rounded-md; - @apply focus:outline-none focus:ring-2 focus:ring-blue-500; - - &:disabled { - // Modifier via pseudo-class - @apply bg-gray-100 cursor-not-allowed; - } - } - - &--error { - // Block modifier - .srfm-custom-field__input { - @apply border-red-500; - } - } -} -``` - -### Conditional Classes (classnames) - -```javascript -import classnames from 'classnames'; - -function Button({ variant, size, disabled, className }) { - const classes = classnames( - 'srfm-button', - `srfm-button--${variant}`, - `srfm-button--${size}`, - { - 'srfm-button--disabled': disabled, - }, - className // Allow override - ); - - return <button className={classes}>Click me</button>; -} -``` - ---- - -## Form Validation - -### Client-Side Validation (Frontend) - -**Inline validation:** - -```javascript -import { useState } from 'react'; - -function EmailField({ value, onChange, required }) { - const [error, setError] = useState(''); - - const validateEmail = (email) => { - const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return regex.test(email); - }; - - const handleBlur = () => { - if (required && !value) { - setError(__('Email is required', 'sureforms')); - } else if (value && !validateEmail(value)) { - setError(__('Please enter a valid email', 'sureforms')); - } else { - setError(''); - } - }; - - return ( - <div className="form-field"> - <input - type="email" - value={value} - onChange={onChange} - onBlur={handleBlur} - className={error ? 'error' : ''} - /> - {error && <span className="error-message">{error}</span>} - </div> - ); -} -``` - -**Form-level validation:** - -```javascript -function FormContainer() { - const [formData, setFormData] = useState({}); - const [errors, setErrors] = useState({}); - - const validate = () => { - const newErrors = {}; - - if (!formData.name) { - newErrors.name = 'Name is required'; - } - - if (!formData.email || !isValidEmail(formData.email)) { - newErrors.email = 'Valid email is required'; - } - - if (formData.age && formData.age < 18) { - newErrors.age = 'Must be 18 or older'; - } - - setErrors(newErrors); - return Object.keys(newErrors).length === 0; - }; - - const handleSubmit = async (e) => { - e.preventDefault(); - - if (!validate()) { - return; - } - - // Submit form - try { - await submitForm(formData); - toast.success('Form submitted!'); - } catch (error) { - toast.error('Submission failed'); - } - }; - - return ( - <form onSubmit={handleSubmit}> - {/* Form fields */} - <button type="submit">Submit</button> - </form> - ); -} -``` - ---- - -## Internationalization (i18n) - -### Translation Functions - -```javascript -import { __, _n, sprintf } from '@wordpress/i18n'; - -// Simple translation -const label = __('Submit Form', 'sureforms'); - -// Plural forms -const message = _n( - 'One field is required', - '%d fields are required', - count, - 'sureforms' -); - -// String interpolation -const greeting = sprintf( - __('Hello, %s!', 'sureforms'), - userName -); -``` - -### Best Practices - -**✅ DO:** -```javascript -// Use sprintf for variables -const msg = sprintf(__('Form %s saved', 'sureforms'), formName); - -// Separate strings for different contexts -const saveButton = __('Save', 'sureforms'); -const saveForm = __('Save Form', 'sureforms'); -``` - -**❌ DON'T:** -```javascript -// Never use template literals in translations -const msg = __(`Form ${formName} saved`, 'sureforms'); // ❌ WRONG - -// Never concatenate -const msg = __('Form ', 'sureforms') + formName + __(' saved', 'sureforms'); // ❌ WRONG -``` - ---- - -## Performance Optimization - -### Code Splitting - -```javascript -import { lazy, Suspense } from 'react'; - -const HeavyComponent = lazy(() => import('./HeavyComponent')); - -function App() { - return ( - <Suspense fallback={<Spinner />}> - <HeavyComponent /> - </Suspense> - ); -} -``` - -### Memoization - -```javascript -import { useMemo, useCallback } from 'react'; - -function DataTable({ data, onRowClick }) { - // Memoize expensive calculations - const sortedData = useMemo(() => { - console.log('Sorting data...'); - return data.sort((a, b) => a.name.localeCompare(b.name)); - }, [data]); // Only recompute when data changes - - // Memoize callbacks - const handleRowClick = useCallback( - (row) => { - onRowClick(row); - }, - [onRowClick] - ); - - return <table>{/* Render sortedData */}</table>; -} -``` - -### React.memo - -```javascript -import { memo } from 'react'; - -// Prevent re-renders if props haven't changed -const ExpensiveComponent = memo(function ExpensiveComponent({ data }) { - console.log('Rendering...'); - return <div>{/* Complex rendering */}</div>; -}); -``` - ---- - -## Testing - -### Component Testing (Jest + React Testing Library) - -```javascript -import { render, screen, fireEvent } from '@testing-library/react'; -import '@testing-library/jest-dom'; -import FormField from '../FormField'; - -describe('FormField', () => { - it('renders with label', () => { - render(<FormField label="Name" />); - expect(screen.getByText('Name')).toBeInTheDocument(); - }); - - it('shows required indicator', () => { - render(<FormField label="Email" required />); - expect(screen.getByText('*')).toBeInTheDocument(); - }); - - it('calls onChange when value changes', () => { - const handleChange = jest.fn(); - render(<FormField value="" onChange={handleChange} />); - - const input = screen.getByRole('textbox'); - fireEvent.change(input, { target: { value: 'test' } }); - - expect(handleChange).toHaveBeenCalledWith('test'); - }); - - it('displays error message', () => { - render(<FormField error="This field is required" />); - expect(screen.getByText('This field is required')).toBeInTheDocument(); - }); -}); -``` - ---- - -## Summary - -**Key Takeaways:** - -1. **Use React 18 functional components** with hooks -2. **Gutenberg blocks** are registered in JavaScript, rendered in PHP -3. **State management** uses three layers: local, WordPress Data Store, React Query -4. **Styling** prefers TailwindCSS utilities, custom SCSS for complex needs -5. **Validation** happens client-side (UX) and server-side (security) -6. **i18n** uses `@wordpress/i18n` functions, no template literals -7. **Performance** optimized with memoization, code splitting, virtualization - ---- - -**Related Documentation:** -- [CLAUDE.md](../../CLAUDE.md) - AI agent guide -- [GETTING-STARTED.md](../01-getting-started/GETTING-STARTED.md) - Setup -- [CODING-STANDARDS.md](../03-development/CODING-STANDARDS.md) - Code style -- [TESTING.md](../08-testing/TESTING.md) - Testing guide diff --git a/docs/FORM_MIGRATION_OVERVIEW.md b/docs/FORM_MIGRATION_OVERVIEW.md deleted file mode 100644 index dd7fac4d6..000000000 --- a/docs/FORM_MIGRATION_OVERVIEW.md +++ /dev/null @@ -1,77 +0,0 @@ -# SureForms — Form Migration (Overview) - -> Looking for the full technical plan? See `FORM_MIGRATION_PLAN.md` in this folder. - -## What this feature does - -Lets users move their existing forms into SureForms from the other popular form-builder plugins, in one click — no copy-pasting, no rebuilding. - -## Which plugins we'll support - -| Source plugin | Approx. user base | Status | -|---|---|---| -| Contact Form 7 | 10M+ sites | **Available in v1** | -| WPForms | 6M+ sites | Coming next | -| Gravity Forms | ~650K sites | Coming next | -| Ninja Forms | 600K+ sites | Later release | -| Caldera Forms | ~50K sites (unmaintained plugin) | Later release | - -Combined audience: roughly **17 million sites** that could move to SureForms. - -## What an import gives you - -When a user clicks "Import", we bring across: - -1. **The form's fields** — text, email, phone, dropdown, checkbox, radio, file URL, number, textarea, consent checkboxes, etc. They show up as native SureForms blocks, ready to edit in the Gutenberg editor. -2. **The form's title** — same as the original. -3. **A working admin notification email** — recipient is the site admin, subject mentions the form name, body uses `{all_data}` so submissions go straight to your inbox. -4. **A success message** — a clean "Thank you" confirmation shown after submission. - -The imported form works on day one. Users can polish it in SureForms' editor. - -## What doesn't transfer yet (and why) - -| Thing | Why not | -|---|---| -| File-upload fields | SureForms doesn't have a file-upload block yet — coming separately. | -| Quiz / signature / rating fields | No SureForms equivalent yet. | -| The exact email-body text from CF7 | CF7 uses a different placeholder syntax (`[your-name]` vs SureForms' smart tags). Trying to translate it gets unreliable, so we ship a clean default instead. WPForms and Gravity emails will come through fully when those are added. | -| Multi-step / page breaks | Waiting on a SureForms multi-step block. | - -When a field can't be migrated, the import screen lists it under **"Some fields were skipped"** so the user knows what to add by hand. - -## How users will find it - -A new **Migration** tab inside **SureForms → Settings**, at the bottom of the sidebar. The workflow is four short steps: - -1. **Choose a source** — tiles show each detected plugin and how many forms it has. -2. **Pick which forms** — checkbox list; "Select all" if you want everything. -3. **Preview** — see what the migrated form will look like before anything is saved. -4. **Confirm & import** — done. The result screen has direct "Edit in SureForms" links. - -If a user re-runs the import for the same source form, we **update** the existing SureForms version instead of creating a duplicate. - -## What's already built - -- The Migration tab is live in **SureForms → Settings → Migration** -- Contact Form 7 imports work end to end (fields + notification + confirmation) -- "Preview before importing" works — nothing gets saved until the user confirms -- Skipped fields are surfaced clearly to the user - -## What's next - -1. **WPForms importer** — including its full email-notification and confirmation rules -2. **Gravity Forms importer** — including notifications, scheduling, entry limits -3. **Ninja Forms + Caldera Forms importers** -4. **Entry migration** — bringing across historical form submissions (capped at 1,000 per form to keep imports fast) -5. **Filling in field gaps** — once SureForms ships file-upload, multi-step, and signature blocks, the migrator will start carrying those over too - -## Why we chose this approach - -We modelled the migrator on **Fluent Forms**' approach, which has been running in production on 700K+ sites for years. Same flow (source → forms → preview → import), same safety net (re-imports update rather than duplicate), and the same honest stance on edge cases like CF7 email templates. - -## Where to find things (for engineers) - -- Full technical plan with code structure, REST endpoints, field-mapping tables: `FORM_MIGRATION_PLAN.md` -- PHP code: `inc/migrator/` -- Admin tab UI: `src/admin/settings/migration/` diff --git a/docs/FORM_MIGRATION_PLAN.md b/docs/FORM_MIGRATION_PLAN.md deleted file mode 100644 index 9d7c2a9a8..000000000 --- a/docs/FORM_MIGRATION_PLAN.md +++ /dev/null @@ -1,458 +0,0 @@ -# SureForms — Form Migration Implementation Plan - -## 1. Goal - -Build a one-click migrator that imports forms (and optionally entries) from the 5 major WordPress form plugins into SureForms, modelled on Fluent Forms' production-tested migrator architecture (~5,400 LOC across 5 sources, deployed on 700K+ sites). - -**Sources to support in v1**: Contact Form 7, WPForms (Lite + Pro), Gravity Forms, Ninja Forms, Caldera Forms. - -## 2. Why Fluent Forms' pattern - -Fluent's full migrator source was read end-to-end (`fluentform/app/Services/Migrator/`). Their architecture is: - -- **One abstract base class** with the import loop, idempotency map, and a ~1,200-line canonical field dictionary. -- **Thin per-source subclasses** (500–900 LOC each) that only do (a) `source_type → fluent_id` mapping and (b) source-specific args formatting. -- **4 AJAX endpoints** for: list sources, list forms in source, import forms, import entries. -- **Template Method pattern** — base class drives the flow, subclasses fill in 5 abstract methods (`exist`, `get_source_forms`, `get_source_form_id`, `get_source_form_name`, `build_form_content`, `get_form_metas`). - -It's clean, proven, and easy to extend. SureForms will adopt the same shape, adapted for: - -1. **REST instead of AJAX** — SureForms already uses `/sureforms/v1/` namespace (`inc/rest-api.php`); AJAX would be inconsistent. -2. **Block markup output instead of JSON** — SureForms forms are Gutenberg block strings in `post_content` of the `sureforms_form` CPT, not JSON in a custom table. So the importer's final stage is to serialize block markup, not assemble a flat field array. -3. **15 SureForms blocks as targets** — instead of Fluent's ~25 field types. - -## 3. Sources to import — confirmed field type maps - -These are lifted directly from Fluent's `fieldTypes()` methods in each migrator class. Total source field types we need to handle: **110** (with overlap). - -### 3.1 Contact Form 7 (13 form-tag types → SureForms blocks) -Source: `wpcf7_contact_form` post type, `_form` meta (shortcode template). - -| CF7 form-tag | SureForms block | Notes | -|---|---|---| -| `text`, `text*` | `srfm/input` | type=text | -| `email`, `email*` | `srfm/email` | | -| `url`, `url*` | `srfm/url` | | -| `tel`, `tel*` | `srfm/phone` | | -| `number`, `number*` | `srfm/number` | | -| `range` | `srfm/number` | slider mode | -| `date` | `srfm/input` | type=date (no native date block) | -| `textarea`, `textarea*` | `srfm/textarea` | | -| `select`, `select*` | `srfm/dropdown` | `multiple` → multi-select | -| `checkbox`, `checkbox*` | `srfm/checkbox` | | -| `radio` | `srfm/multi-choice` | | -| `acceptance` | `srfm/gdpr` | tnc_html → content | -| `file`, `file*` | unsupported in v1 | no native `srfm/file` — flag | -| `quiz`, `captchar`, `hidden` | skipped | legacy / not in v1 scope | - -Detection: `defined('WPCF7_PLUGIN')`. Entries: requires Flamingo plugin. - -### 3.2 WPForms (22 field types → SureForms blocks) -Source: CPT `wpforms`, field data as JSON in `post_content`. - -| WPForms type | SureForms block | Notes | -|---|---|---| -| `text` | `srfm/input` | | -| `email` | `srfm/email` | | -| `url` | `srfm/url` | | -| `phone` | `srfm/phone` | | -| `number`, `number-slider` | `srfm/number` | | -| `textarea`, `richtext` | `srfm/textarea` | rich → fallback | -| `select`, `multi_select` | `srfm/dropdown` | | -| `radio` | `srfm/multi-choice` | | -| `checkbox` | `srfm/checkbox` | | -| `name` | `srfm/input × 3` | split first/middle/last | -| `address` | `srfm/address` | structured fields | -| `date-time` | `srfm/input` | type=date until native block | -| `password` | `srfm/input` | type=password | -| `hidden` | `srfm/input` | type=hidden | -| `html`, `divider` | structural — core/html or section break | | -| `pagebreak` | unsupported in v1 | no native multi-step yet | -| `file-upload`, `rating`, `layout` | unsupported in v1 | flag | - -Detection: `function_exists('wpforms')`. Entries: WPForms Pro only. - -### 3.3 Gravity Forms (22 field types → SureForms blocks) -Source: custom tables `gf_form` + `gf_form_meta` (serialized PHP array). - -| Gravity type | SureForms block | Notes | -|---|---|---| -| `email` | `srfm/email` | | -| `text` | `srfm/input` | | -| `name` | `srfm/input × 3` | first/middle/last sub-inputs | -| `hidden` | `srfm/input` (type=hidden) | | -| `textarea` | `srfm/textarea` | | -| `website` | `srfm/url` | | -| `phone` | `srfm/phone` | | -| `select`, `multiselect` | `srfm/dropdown` | | -| `checkbox` | `srfm/checkbox` | | -| `radio` | `srfm/multi-choice` | | -| `date`, `time` | `srfm/input` (type=date/time) | | -| `number` | `srfm/number` | | -| `address` | `srfm/address` | | -| `consent` | `srfm/gdpr` | | -| `captcha` | unsupported | external service | -| `html` | core/html (or skip) | | -| `section` | section break / divider | | -| `page` | unsupported in v1 | multi-step | -| `list` | unsupported in v1 | repeater not in srfm | -| `fileupload` | unsupported in v1 | no srfm/file | - -Detection: `class_exists('GFForms')`. Entries: `gf_entry`, `gf_entry_meta` tables. - -### 3.4 Ninja Forms (27 field type aliases → SureForms blocks) -Source: custom tables `nf3_forms`, `nf3_fields`, `nf3_field_meta` (JOIN-based). - -| Ninja type | SureForms block | Notes | -|---|---|---| -| `email` | `srfm/email` | | -| `textbox`, `firstname`, `lastname`, `address`, `city`, `zip` | `srfm/input` | (Ninja splits address into individual text fields) | -| `liststate`, `listcountry` | `srfm/dropdown` | | -| `textarea` | `srfm/textarea` | | -| `phone` | `srfm/phone` | | -| `select`, `listselect` | `srfm/dropdown` | | -| `listmultiselect` | `srfm/dropdown` (multi) | | -| `radio`, `listradio`, `listimage`, `toggle_switch` | `srfm/multi-choice` | | -| `checkbox`, `listcheckbox` | `srfm/checkbox` | | -| `date` | `srfm/input` (type=date) | | -| `number` | `srfm/number` | | -| `hidden` | `srfm/input` (type=hidden) | | -| `html` | core/html | | -| `hr` | section divider | | -| `starrating` | unsupported in v1 | no srfm/rating | -| `repeater` | unsupported in v1 | | -| `recaptcha` | spam protection — emit as form-level setting | | -| `submit` | handled by `srfm/inline-button` | | - -Detection: `defined('NF_SERVER_URL')`. Entries: `nf_sub` CPT. - -### 3.5 Caldera Forms (26 field types → SureForms blocks) -Source: `Caldera_Forms_Forms::get_forms()` static API. Caldera is unmaintained — migration is a one-shot rescue. - -| Caldera type | SureForms block | Notes | -|---|---|---| -| `email` | `srfm/email` | | -| `text` | `srfm/input` | | -| `hidden` | `srfm/input` (type=hidden) | | -| `textarea`, `paragraph`, `wysiwyg` | `srfm/textarea` | | -| `url` | `srfm/url` | | -| `phone`, `phone_better` | `srfm/phone` | | -| `select`, `dropdown` | `srfm/dropdown` | | -| `filtered_select2` | `srfm/dropdown` (multi) | | -| `radio`, `toggle_switch` | `srfm/multi-choice` | | -| `checkbox` | `srfm/checkbox` | | -| `date_picker`, `date` | `srfm/input` (type=date) | | -| `number`, `range`, `calculation` | `srfm/number` | | -| `range_slider` | `srfm/number` (slider) | | -| `gdpr` | `srfm/gdpr` | | -| `section_break`, `html` | structural | | -| `color_picker`, `star_rating`, `file`, `cf2_file`, `advanced_file` | unsupported in v1 | flag | -| `button` | handled by `srfm/inline-button` | | - -Detection: `defined('CFCORE_VER')`. Caldera abandoned in 2022 — entries critical. - -## 4. SureForms target blocks (the destination schema) - -From `find sureforms/inc/blocks/*/block.json` — **15 blocks** total: - -| Block | Type | Used for | -|---|---|---| -| `srfm/form` | wrapper | Outer form container | -| `srfm/input` | field | Text/email/url/phone/password/date/hidden (HTML type via attr) | -| `srfm/email` | field | Email input | -| `srfm/textarea` | field | Paragraph text | -| `srfm/url` | field | URL input | -| `srfm/number` | field | Numeric input + slider mode | -| `srfm/phone` | field | International phone | -| `srfm/dropdown` | field | Select / multi-select | -| `srfm/multi-choice` | field | Radio / multiple choice | -| `srfm/checkbox` | field | Checkbox group | -| `srfm/address` | field | Structured address (line1/2/city/state/zip/country) | -| `srfm/gdpr` | field | Consent checkbox | -| `srfm/payment` | field | Stripe payment | -| `srfm/payment-history` | display | Past payments table | -| `srfm/inline-button` | structural | Submit / action button | - -**Gaps acknowledged**: no native rich-text, file upload, signature, rating, date-picker, multi-step (page break), or repeater blocks. Fields mapped to these in source plugins are flagged as `unsupported_fields[]` in the v1 response and surfaced in the import UI as warnings. They will be added in subsequent releases. - -## 5. Code layout (mirrors Fluent's, adapted to SureForms conventions) - -``` -sureforms/inc/migrator/ -├── class-migrator-bootstrap.php # ~200 LOC — REST routes, capability checks, factory -├── class-base-migrator.php # ~800 LOC — abstract import loop + idempotency + helpers -├── class-block-templates.php # ~600 LOC — canonical srfm/* block markup templates -├── importers/ -│ ├── class-cf7-importer.php # ~600 LOC — shortcode regex parser -│ ├── class-wpforms-importer.php # ~700 LOC — JSON decode -│ ├── class-gravity-importer.php # ~800 LOC — serialized array parser -│ ├── class-ninja-importer.php # ~600 LOC — JOIN across nf3_* tables -│ └── class-caldera-importer.php # ~500 LOC — Caldera static API -└── views/admin-page.php # ~150 LOC — admin page mount point - -sureforms/src/admin/migrator/ # React UI (~800 LOC) -├── MigratorApp.jsx # Top-level component -├── SourceList.jsx # Tile per detected source -├── FormSelector.jsx # Pick forms to import -├── ImportPreview.jsx # Dry-run rendered output -├── ImportResult.jsx # Success + unsupported warnings -└── EntryImporter.jsx # Per-form entry import -``` - -**Total estimate: ~5,750 LOC** for all 5 sources (close to Fluent's ~5,400 LOC, with the extra slack accounting for SureForms' block-markup serialization). - -## 6. REST API design - -Namespace: `/wp-json/sureforms/v1/migrator/` (extending the existing `/sureforms/v1/` namespace from `inc/rest-api.php`). - -| Method | Route | Body / Query | Returns | -|---|---|---|---| -| GET | `/migrator/sources` | — | `[{key, title, installed, form_count, supports_entries}]` | -| GET | `/migrator/sources/{key}/forms` | — | `[{id, name, field_count, imported_srfm_id, last_imported_at}]` | -| POST | `/migrator/sources/{key}/import` | `{form_ids: [], dry_run: bool, behavior: {}, post_status?: 'draft'\|'publish'}` | `{imported: [{srfm_id, edit_url, source_id}], failed: [], skipped: [], unsupported_fields: [], preview?: {}}` | -| POST | `/migrator/sources/{key}/forms/{id}/entries` _(planned — P3, not yet registered)_ | `{limit?: 1000}` | `{count_imported, count_skipped, count_total}` | - -**Security model** (per `sureforms/CLAUDE.md`): -- Every route's `permission_callback` requires `current_user_can('manage_options')`. -- REST cookie nonce (`X-WP-Nonce`) for all routes — these are admin-only, no public access. -- Sanitize `form_ids` via `array_map('absint', ...)`, `key` via allowlist `['cf7','wpforms','gravity','ninja','caldera']`. - -## 7. Canonical block template dictionary - -Analogue of Fluent's 1,200-line `defaultFieldConfig()` array, but emitting Gutenberg block markup strings instead of field-config arrays. - -One method per target block in `class-block-templates.php`: - -```php -final class SRFM_Block_Templates { - - public static function input( array $args ): string { - $defaults = [ - 'label' => '', - 'placeholder' => '', - 'required' => false, - 'field_type' => 'text', // text|email|number|password|date|hidden - 'help_text' => '', - 'default_val' => '', - 'min_length' => '', - 'max_length' => '', - 'css_class' => '', - ]; - $attrs = wp_parse_args( $args, $defaults ); - // Match the schema in src/blocks/input/block.json - $json = wp_json_encode( self::strip_empty( [ - 'label' => $attrs['label'], - 'placeholder' => $attrs['placeholder'], - 'required' => $attrs['required'], - 'fieldType' => $attrs['field_type'], - 'help' => $attrs['help_text'], - 'defaultValue' => $attrs['default_val'], - 'minLength' => $attrs['min_length'], - 'maxLength' => $attrs['max_length'], - 'className' => $attrs['css_class'], - ] ) ); - return "<!-- wp:srfm/input {$json} /-->\n"; - } - - public static function email( array $args ): string { /* ... */ } - public static function dropdown( array $args ): string { /* ... */ } - public static function checkbox( array $args ): string { /* ... */ } - // ... one per srfm/* block - - public static function form_wrapper( string $inner_content ): string { - return "<!-- wp:srfm/form -->\n{$inner_content}\n<!-- /wp:srfm/form -->"; - } -} -``` - -The base migrator's import loop concatenates the per-field strings, wraps them in `form_wrapper()`, and persists via `wp_insert_post(['post_type' => 'sureforms_form', 'post_content' => $markup])`. - -## 8. Base migrator contract (abstract methods) - -```php -abstract class SRFM_Base_Migrator { - - protected string $key; // 'cf7' | 'wpforms' | 'gravity' | 'ninja' | 'caldera' - protected string $title; // Display name - protected array $unsupported_fields = []; - - // Per-source plumbing (abstract — subclasses implement) - abstract public function exist(): bool; - abstract protected function get_source_forms(): array; - abstract protected function get_source_form_id( array $form ); - abstract protected function get_source_form_name( array $form ): string; - abstract protected function build_form_content( array $form ): string; // concatenated block markup - abstract protected function get_form_metas( array $form ): array; // notifications, confirmations - // NOTE: get_entries() is planned for the entries-migration phase (P3); not shipped yet. - - // Shared (in base): - public function list_forms(): array; - public function count_source_forms(): int; - public function import_forms( array $selected_ids = [], bool $dry_run = false, array $behavior = [], string $post_status = 'publish' ): array; - protected function find_existing_srfm_id( $source_id ): int; - protected function record_import_mapping( int $srfm_id, $source_id ): void; -} -``` - -## 9. Idempotent re-imports - -Same pattern as Fluent: a single `wp_option('srfm_imported_forms_map')` storing: - -```php -[ - 123 => [ 'source_id' => 'cf7-45', 'source_key' => 'cf7', 'last_imported' => '2026-05-22 10:00:00' ], - 124 => [ 'source_id' => '8', 'source_key' => 'wpforms', 'last_imported' => '2026-05-22 10:01:00' ], -] -``` - -`is_already_imported()`: -1. Look up `source_key` + `source_id` in the map. -2. If found and the matching `sureforms_form` post still exists → **update** (not insert). -3. If the SureForms form was deleted → prune the stale entry, fresh insert. - -## 10. Unsupported field tracking - -Same pattern as Fluent: -- `$this->unsupported_fields[]` is pushed each time a source field's type isn't in the source's `field_type_map`, capturing the field's user-facing label (not internal id). -- Returned in the REST response as `unsupported_fields: []`. -- Admin UI renders these as a yellow callout: "These fields couldn't be migrated to SureForms — add them manually after import: Field A, Field B, Field C." - -## 11. Entry migration - -- **Form-by-form, not bulk** — same as Fluent. -- **Hard cap of 1,000 entries per form**, override via the `srfm/entry_migration_max_limit` filter. -- **Idempotent**: import deletes existing SureForms entries for that form first (via the same `resetEntries()` pattern Fluent uses) before inserting. -- **Files**: copy via `WP_Filesystem_Direct::copy()` into `wp-content/uploads/sureforms/migrated/`. - -## 12. Admin UI flow - -Lives at **WordPress → SureForms → Tools → Migrator** (new sub-tab next to existing export/import). - -``` -[ Step 1: Select source ] Detected plugins shown as tiles with logo + install count - ▼ click "Migrate from Contact Form 7" - -[ Step 2: Select forms ] Table of forms in source (name | fields | already-imported badge) - ▼ bulk select + "Preview" - -[ Step 3: Dry-run preview ] Server returns block markup; UI renders in a code pane - + warning callout for unsupported fields - ▼ "Confirm & Import" - -[ Step 4: Result ] "Imported X forms." Links: [Edit in SureForms] [Import entries] - Unsupported-fields list (if any) -``` - -The dry-run preview is the **one improvement over Fluent's UX** — it answers the user's "is this going to break anything?" anxiety before they commit. - -## 13. Implementation phasing - -Four mergeable PRs, each ~7–10 working days: - -| Phase | Deliverable | LOC | -|---|---|---| -| **P1: Foundation** | `Base_Migrator`, `Block_Templates`, REST routes, admin page shell, CF7 importer end-to-end | ~2,400 | -| **P2: WPForms + Gravity** | Two more importers + dry-run preview UI | ~1,700 | -| **P3: Ninja + Caldera** | Final two importers + entry import flow | ~1,300 | -| **P4: Polish** | Field-mapping overrides, entry import UI, docs, E2E tests | ~350 | - -Total: ~5,750 LOC delivered across ~4–5 weeks. - -## 14. Testing approach - -- **Unit tests** (PHPUnit, per `composer test`): per importer, fixture-driven — store sample source-form payloads in `tests/fixtures/migrator/{source}/*.json` and assert the produced block markup string matches a golden snapshot. -- **Integration tests**: a real CF7 / WPForms / Gravity form created via their PHP APIs in a `tests/Integration/Migrator/` test, imported via `Base_Migrator::import_forms()`, then assert a `sureforms_form` post exists with the right block content. -- **Playwright E2E** (per `npm run play:run`): full admin flow — open Migrator, pick CF7, select a form, dry-run, confirm import, verify the new form renders correctly on the front-end. -- **Manual exploratory**: all 5 source plugins are already installed locally, so the test environment is real, not mocked. - -## 15. Verification (when is this done) - -1. All 5 importers exist under `sureforms/inc/migrator/importers/` and pass their PHPUnit fixtures. -2. REST endpoints respond correctly: `GET /sureforms/v1/migrator/sources` lists the 5 sources with `installed: true` for whichever plugins are active. -3. Admin page at SureForms → Tools → Migrator renders the tile-based source picker. -4. Dry-run for a non-trivial CF7 form (text + email + textarea + radio + acceptance) produces valid Gutenberg block markup that renders correctly in the SureForms editor. -5. Re-importing the same source form updates the existing SureForms form (not a duplicate). -6. Entry migration imports up to 1,000 entries for a WPForms Pro form and the entries appear in SureForms' Entries admin. -7. Unsupported-field warnings appear in the UI for source fields without a SureForms target (e.g. CF7 `[file]`, WPForms `rating`). -8. PHPStan level 9 passes (`composer phpstan`) and PHPCS passes (`composer lint`). - -## 16. Reference source files (Fluent Forms — production reference) - -| Fluent file | Our equivalent | Why useful | -|---|---|---| -| `app/Services/Migrator/Bootstrap.php` | `class-migrator-bootstrap.php` | AJAX → REST route mapping | -| `app/Services/Migrator/Classes/BaseMigrator.php` | `class-base-migrator.php` | Import loop, idempotency, file migration helpers | -| `app/Services/Migrator/Classes/ContactForm7Migrator.php` | `class-cf7-importer.php` | Battle-tested shortcode regex parser (`formatAsFluentField()`) | -| `app/Services/Migrator/Classes/WpFormsMigrator.php` | `class-wpforms-importer.php` | JSON-decode + 22-entry field map | -| `app/Services/Migrator/Classes/GravityFormsMigrator.php` | `class-gravity-importer.php` | Serialized-array parsing + Name/Address sub-input handling | -| `app/Services/Migrator/Classes/NinjaFormsMigrator.php` | `class-ninja-importer.php` | JOIN across `nf3_*` tables via Ninja's PHP API | -| `app/Services/Migrator/Classes/CalderaMigrator.php` | `class-caldera-importer.php` | `Caldera_Forms_Forms` static API | - -Fluent Forms is GPL-2.0+ — we can lift regexes and parsing patterns directly with attribution comments. The `defaultFieldConfig()` array structure should be re-written for SureForms blocks, not copied (different output format). - -## 16a. Metadata migration - -Form metadata (email notifications, confirmation messages, compliance flags, integrations) lives **outside** the block-markup pipeline — it's persisted as `sureforms_form` post meta. The migrator handles it via the abstract `Base_Migrator::get_form_metas()` method which returns a `meta_key => meta_value` array passed to `wp_insert_post()` / `wp_update_post()` via `meta_input`. - -### What every importer must produce - -A SureForms-shaped payload. The two keys every importer should populate are: - -| SureForms meta key | Schema (registered in `inc/post-types.php`) | -|---|---| -| `_srfm_email_notification` | Array of objects: `{id, status, is_raw_format, name, email_to, email_reply_to, from_name, from_email, email_cc, email_bcc, subject, email_body}` | -| `_srfm_form_confirmation` | Array of objects: `{id, confirmation_type, page_url, custom_url, message, submission_action, enable_query_params, query_params}` | - -Other meta keys exist (`_srfm_compliance`, `_srfm_conditional_logic`, `_srfm_forms_styling`, `_srfm_integrations_webhooks`) but are not required for a usable imported form — they default to SureForms' built-in `register_post_meta` defaults if not provided. - -### What each source can give us (and what we ship in v1) - -| Source | Notifications | Confirmations | Other meta | Status in v1 | -|---|---|---|---|---| -| **CF7** | `_mail`, `_mail_2` use `[field-name]` shortcodes — incompatible with SureForms smart tags | `_messages` array (success/error text) | None | **Stub only** — admin notification to `{admin_email}` with `{all_data}` body, generic success message. Form is usable; users can refine in Single Form Settings. (Matches Fluent's CF7 approach for the same reason.) | -| **WPForms** | `settings.notifications[]` — fully structured (subject/body/recipient/CC/BCC/replyTo/fromName) | `settings.confirmations[]` — multi-confirmation with conditional logic | Webhooks | **Full migration planned in P2** | -| **Gravity** | Notifications, conditional notifications, routing | Confirmations, scheduling, login-required, entry limits | Advanced validation | **Full migration planned in P2** | -| **Ninja** | `Actions` API — type `email`, `successmessage`, `redirect`, `save` | Same Actions API | — | **Full migration planned in P3** | -| **Caldera** | `mailer` config in form settings | `successMessage` field | — | **Full migration planned in P3** | - -### Why CF7 is special - -CF7's email body uses `[your-name]`, `[your-email]` style shortcodes that reference the form-tag `name` attribute. Translating these to SureForms' `{slug_field_id}` smart-tag system requires either (a) maintaining a per-form name→slug mapping during import, or (b) rewriting the body string with regex substitutions that match the field tokens we emitted. Both approaches add ~400 LOC and break easily on edge cases (multi-line bodies, mixed shortcodes/text, CF7 special mail tags like `[_remote_ip]`). - -Fluent Forms — with 700K+ installs and 5+ years of migrator iteration — landed on the same stub-only conclusion for CF7. v1 matches that decision; if user demand surfaces, CF7 mail-template translation is a separate scoped feature. - -### Code pointers (live) - -- **Abstract method**: `Base_Migrator::get_form_metas()` — `inc/migrator/base-migrator.php` -- **Wire-up**: `Base_Migrator::insert_form_post()` / `update_form_post()` both accept a `$metas` arg and pass it to `wp_insert_post()` via `meta_input` -- **CF7 implementation**: `Cf7_Importer::get_form_metas()` — `inc/migrator/importers/cf7-importer.php` -- **SureForms meta schemas** (the contract we have to match): `inc/post-types.php` lines 911-1010 (notification), 1086-1182 (confirmation) - -### Verification - -After importing a CF7 form via the Migration tab, open the resulting SureForms form's settings: -- **Email Notifications** tab → should show one enabled notification named "Admin Notification Email" with subject "New submission: {form title}" and body `{all_data}`. -- **Form Confirmation** tab → should show a centered "Thank you" success message, "Same page" confirmation type. - -If those panels are empty, the meta payload didn't persist — check `wp_options.srfm_imported_forms_map` and `wp_postmeta` for the form id. - -## 17. Out of scope for v1 - -- Polls / Quizzes (Forminator, Gravity surveys) — no SureForms equivalent. -- Formidable Views — front-end data display is its own feature. -- WS Form — niche, defer. -- Multi-step / page break preservation — wait for native `srfm/page-break` block. -- File-upload, signature, rating, repeater fields — wait for native blocks (flagged as unsupported until then). -- Bulk source-selection ("import everything from everywhere") — one source at a time in v1. - -## 18. Sources verified live (May 2026) - -All wordpress.org plugin pages were fetched live during research: - -- [Contact Form 7](https://wordpress.org/plugins/contact-form-7/) — 10M+ installs, v6.1.6 -- [WPForms Lite](https://wordpress.org/plugins/wpforms-lite/) — 6M+ installs, v1.10.0.5 -- [Gravity Forms docs](https://docs.gravityforms.com/form-fields/) — ~655K live sites, commercial -- [Ninja Forms](https://wordpress.org/plugins/ninja-forms/) — 600K+ installs, v3.14.4 -- Caldera Forms — unmaintained since 2022, ~50K legacy sites - -**Combined migration pool: ~17.3M active sites** — the addressable target for v1. diff --git a/docs/wiki/AI-Form-Builder.md b/docs/wiki/AI-Form-Builder.md deleted file mode 100644 index a35a46a4e..000000000 --- a/docs/wiki/AI-Form-Builder.md +++ /dev/null @@ -1,103 +0,0 @@ -# AI Form Builder - -SureForms includes an AI-powered form generator that creates complete forms from natural language descriptions. - -## Architecture - -``` -inc/ai-form-builder/ -|-- ai-form-builder.php # Main AI builder class -|-- ai-auth.php # Authentication and billing -|-- ai-helper.php # AI utility functions -|-- field-mapping.php # Maps AI response to Gutenberg blocks -``` - -## Authentication Flow - -The `AI_Auth` class handles authentication with the SureForms middleware API: - -1. User initiates authentication from admin settings -2. `GET /initiate-auth` REST endpoint generates an auth URL -3. User is redirected to the billing portal (`SRFM_BILLING_PORTAL`) -4. After authentication, an encrypted access key is returned -5. `POST /handle-access-key` decrypts and stores the key in WordPress options -6. Subsequent AI requests use this key for authorization - -### Constants - -| Constant | URL | Purpose | -|----------|-----|---------| -| `SRFM_AI_MIDDLEWARE` | `https://credits.startertemplates.com/sureforms/` | AI credits API | -| `SRFM_MIDDLEWARE_BASE_URL` | `https://api.sureforms.com/` | API middleware | -| `SRFM_BILLING_PORTAL` | `https://billing.sureforms.com/` | Billing portal | - -## Form Generation Process - -### Step 1: User Input - -The user provides a natural language description of the form they want (e.g., "Create a contact form with name, email, phone, and message fields"). - -### Step 2: AI Generation - -`POST /generate-form` sends the description to the AI middleware: - -``` -User prompt -> REST API -> AI_Form_Builder::generate_ai_form() - -> External AI middleware API call - -> AI generates form structure as JSON - -> Returns field definitions -``` - -### Step 3: Field Mapping - -`POST /map-fields` converts the AI response to SureForms Gutenberg blocks: - -``` -AI JSON response -> Field_Mapping::generate_gutenberg_fields_from_questions() - -> Maps each AI field to a SureForms block type - -> Generates block attributes - -> Creates Gutenberg block markup - -> Returns blocks ready for the editor -``` - -### Field Type Mapping - -The `Field_Mapping` class maps AI-suggested field types to SureForms blocks: - -| AI Field Type | SureForms Block | -|---------------|----------------| -| text / name | `srfm/input` | -| email | `srfm/email` | -| phone / tel | `srfm/phone` | -| textarea / message | `srfm/textarea` | -| number | `srfm/number` | -| url / website | `srfm/url` | -| select / dropdown | `srfm/dropdown` | -| checkbox | `srfm/checkbox` | -| radio / multiple choice | `srfm/multichoice` | -| address | `srfm/address` | - -## REST API Endpoints - -| Method | Endpoint | Handler | Description | -|--------|----------|---------|-------------| -| POST | `/generate-form` | `AI_Form_Builder::generate_ai_form` | Send prompt to AI, get form structure | -| POST | `/map-fields` | `Field_Mapping::generate_gutenberg_fields_from_questions` | Convert AI fields to blocks | -| GET | `/initiate-auth` | `AI_Auth::get_auth_url` | Get billing portal auth URL | -| POST | `/handle-access-key` | `AI_Auth::handle_access_key` | Save decrypted access key | - -All endpoints require `manage_options` capability. - -## AI Helper - -The `AI_Helper` class provides utility functions for: -- API key management -- Credit balance checking -- Request formatting -- Error handling for AI middleware responses - -## Related Pages - -- [REST API Reference](REST-API-Reference) -- All API endpoints -- [Gutenberg Blocks](Gutenberg-Blocks) -- Block types the AI maps to -- [Architecture Overview](Architecture-Overview) -- AI classes in bootstrap flow diff --git a/docs/wiki/Admin-Dashboard.md b/docs/wiki/Admin-Dashboard.md deleted file mode 100644 index 9c16aea85..000000000 --- a/docs/wiki/Admin-Dashboard.md +++ /dev/null @@ -1,121 +0,0 @@ -# Admin Dashboard - -The SureForms admin dashboard is a React single-page application (SPA) integrated into the WordPress admin area. - -## Architecture - -### Entry Point - -The admin React app is bootstrapped in `src/admin/editor-scripts.js`, which serves as the Webpack entry point. It mounts the React app to a DOM container registered by the PHP `Admin` class. - -### Tech Stack - -| Technology | Purpose | -|------------|---------| -| React 18 | UI rendering | -| react-router-dom 6 | Client-side routing | -| @tanstack/react-query 5 | Server state management and data fetching | -| @wordpress/api-fetch | REST API client with nonce handling | -| @wordpress/data | WordPress data store integration | -| @bsf/force-ui | BSF component library (buttons, modals, inputs, etc.) | -| Tailwind CSS 3 | Utility-first styling | -| react-hot-toast | Toast notifications | - -### Admin Pages - -The React app includes the following pages/routes: - -| Route | Component | Description | -|-------|-----------|-------------| -| Dashboard | `src/admin/dashboard/` | Overview with charts and stats | -| Forms | `src/admin/forms/` | Forms listing with search, filter, bulk actions | -| Entries | `src/admin/entries/` | Entry listing and management | -| Settings | `src/admin/settings/` | Global plugin settings | -| Payments | `src/admin/payment/` | Payment transactions listing | -| Single Form Settings | `src/admin/single-form-settings/` | Per-form configuration | - -### Shared Components - -Common admin components are in `src/admin/components/`: - -- `PageHeader` -- Consistent page header with title and actions -- `TemplatePicker` -- Form template selection UI -- Loading skeletons (via `react-loading-skeleton`) -- Modal dialogs and confirmation prompts - -## WordPress Integration - -### Menu Registration - -The PHP `Admin` class (`admin/admin.php`) registers the WordPress admin menu: - -```php -add_menu_page( - 'SureForms', - 'SureForms', - 'manage_options', - 'sureforms_menu', - [ $this, 'render_admin_page' ], - 'dashicons-feedback', - 30 -); -``` - -### Asset Enqueuing - -Admin assets are enqueued only on SureForms admin pages: - -- React app bundle (from `assets/build/`) -- Tailwind CSS styles -- Localized data via `wp_localize_script()` providing: - - REST API URL and nonce - - Current user data - - Plugin settings - - Form data - -## Data Fetching - -### @tanstack/react-query - -Used for server state management with automatic caching, refetching, and invalidation: - -```javascript -const { data, isLoading } = useQuery({ - queryKey: ['entries', filters], - queryFn: () => apiFetch({ path: '/sureforms/v1/entries/list', ... }), -}); -``` - -### @wordpress/api-fetch - -WordPress API client with automatic nonce injection: - -```javascript -import apiFetch from '@wordpress/api-fetch'; - -apiFetch({ path: '/sureforms/v1/form-data' }) - .then(data => { /* handle response */ }); -``` - -## Force UI Component Library - -`@bsf/force-ui` is BSF's internal component library providing: - -- Buttons, inputs, selects, toggles -- Modals and dialogs -- Tables and data display -- Navigation components -- Consistent design system - -Components are imported directly: - -```javascript -import { Button, Modal, Input } from '@bsf/force-ui'; -``` - -## Related Pages - -- [State Management](State-Management) -- WordPress data store -- [Frontend Assets](Frontend-Assets) -- Asset loading pipeline -- [REST API Reference](REST-API-Reference) -- API endpoints used by dashboard -- [Environment Configuration](Environment-Configuration) -- Build setup diff --git a/docs/wiki/Architecture-Overview.md b/docs/wiki/Architecture-Overview.md deleted file mode 100644 index 523f18cc8..000000000 --- a/docs/wiki/Architecture-Overview.md +++ /dev/null @@ -1,294 +0,0 @@ -# Architecture Overview - -This page describes the high-level architecture of the SureForms WordPress plugin (v2.5.1), covering the bootstrap flow, namespace conventions, directory layout, design patterns, and data flow. - -## High-Level Architecture Diagram - -``` -+------------------------------------------------------+ -| WordPress Core | -| (hooks: plugins_loaded, init, rest_api_init, etc.) | -+---------------------------+--------------------------+ - | - +--------v---------+ - | sureforms.php | - | (entry point, | - | constants) | - +--------+---------+ - | - +--------v---------+ - | plugin-loader.php| - | (Plugin_Loader) | - | - autoloader | - | - hook setup | - | - class init | - +--------+---------+ - | - +------------------+------------------+ - | | | - plugins_loaded(99) init admin_init - load_plugin() load_classes() activation_redirect() - | | - +------v------+ +------v------+ - | Core Classes| | Admin/Block | - | Post_Types | | Register | - | Form_Submit | | Admin | - | Rest_Api | | Payments | - | Helper | | Duplicate | - | ...20+ more | +-------------+ - +------+------+ - | - +------v------+ +-------------+ +-------------+ - | Database | | REST API | | Frontend | - | Register | | /sureforms/ | | Assets | - | Entries tbl | | v1/... | | Form Markup | - | Payments tbl| +-------------+ +-------------+ - +-------------+ -``` - -## Plugin Bootstrap Flow - -### 1. Entry Point: sureforms.php - -The main plugin file defines all global constants and then requires `plugin-loader.php`: - -```php -define( 'SRFM_FILE', __FILE__ ); -define( 'SRFM_DIR', plugin_dir_path( SRFM_FILE ) ); -define( 'SRFM_URL', plugins_url( '/', SRFM_FILE ) ); -define( 'SRFM_VER', '2.5.1' ); -define( 'SRFM_FORMS_POST_TYPE', 'sureforms_form' ); -define( 'SRFM_ENTRIES', 'sureforms_entries' ); -define( 'SRFM_PAYMENTS', 'sureforms_payments' ); -require_once 'plugin-loader.php'; -``` - -### 2. Plugin Loader: plugin-loader.php - -The `SRFM\Plugin_Loader` class is the central bootstrap orchestrator: - -1. Loads the Action Scheduler library from `inc/lib/action-scheduler/action-scheduler.php` -2. Registers the PSR-4-style autoloader via `spl_autoload_register()` -3. Hooks into WordPress lifecycle events: - - `plugins_loaded` (default priority) -- `load_textdomain()` - - `plugins_loaded` (priority 99) -- `load_plugin()` (main class initialization) - - `init` -- `load_classes()` (block registration, admin, payments) - - `admin_init` -- `activation_redirect()` -4. Instantiates `Analytics` singleton immediately -5. Registers activation hook (`Activator::activate()`) -6. Registers deactivation hook (clears scheduled events) - -The `Plugin_Loader` fires the `srfm_core_loaded` action after first instantiation. - -### 3. Class Initialization Order - -**On `plugins_loaded` (priority 99) via `load_plugin()`:** - -| Order | Class | Responsibility | -|-------|-------|---------------| -| 1 | `Post_Types` | Registers `sureforms_form` CPT and all post meta | -| 2 | `Form_Submit` | Registers `/submit-form` and `/refresh-nonces` REST endpoints | -| 3 | `Gutenberg_Hooks` | Block editor integration hooks | -| 4 | `Frontend_Assets` | Frontend CSS/JS enqueue | -| 5 | `Helper` | Utility/helper functions | -| 6 | `Activator` | First-run setup and migrations | -| 7 | `Admin_Ajax` | WordPress AJAX handlers | -| 8 | `Forms_Data` | Form data queries and listing | -| 9 | `Export` | Import/export functionality | -| 10 | `Smart_Tags` | Template tag processing | -| 11 | `Generate_Form_Markup` | Form HTML rendering | -| 12 | `Create_New_Form` | New form creation flow with default meta | -| 13 | `Global_Settings` | Plugin-wide settings management | -| 14 | `Email_Summary` | Scheduled email digest reports | -| 15 | `Compliance_Settings` | GDPR/privacy per-form settings | -| 16 | `Events_Scheduler` | Cron-based scheduled events | -| 17 | `AI_Form_Builder` | AI-powered form generation | -| 18 | `Field_Mapping` | AI response to Gutenberg block mapping | -| 19 | `Background_Process` | Background task processing via Action Scheduler | -| 20 | `Page_Builders` | Third-party page builder integrations | -| 21 | `Rest_Api` | Admin REST endpoint registration (20+ routes) | -| 22 | `AI_Helper` | AI utility functions | -| 23 | `AI_Auth` | AI authentication and billing portal | -| 24 | `Updater` | Plugin update logic | -| 25 | `Onboarding` | First-run onboarding wizard | -| 26 | `DatabaseRegister` | Custom table creation/migration | -| 27 | `Form_Restriction` | Submission limits, scheduling, and entry caps | -| 28 | `Astra` | Astra theme compatibility layer | - -**On `init` via `load_classes()`:** - -| Class | Condition | Responsibility | -|-------|-----------|---------------| -| `Blocks\Register` | Always | Gutenberg block type registration | -| `Admin` | `is_admin()` only | Admin menu pages, assets, and screens | -| `Notice_Manager` | `is_admin()` only | Admin notice display and management | -| `Payments` | Always | Payment gateway setup (Stripe) | -| `Duplicate_Form` | Always | Form duplication handler | - -## Namespace and Autoloading - -### Namespace Structure - -The root namespace is `SRFM`. All classes follow `SRFM\{directory}\{ClassName}`: - -``` -SRFM\ -> plugin-loader.php -SRFM\Inc\Helper -> inc/helper.php -SRFM\Inc\Rest_Api -> inc/rest-api.php -SRFM\Inc\Form_Submit -> inc/form-submit.php -SRFM\Inc\Database\Base -> inc/database/base.php -SRFM\Inc\Database\Tables\Entries -> inc/database/tables/entries.php -SRFM\Inc\AI_Form_Builder\* -> inc/ai-form-builder/ -SRFM\Inc\Traits\Get_Instance -> inc/traits/get-instance.php -SRFM\Admin\Admin -> admin/admin.php -``` - -### Autoloader Logic - -The autoloader in `Plugin_Loader::autoload()`: - -1. Strips the root `SRFM\` namespace prefix -2. Converts `CamelCase` to `kebab-case` -3. Replaces underscores with hyphens -4. Replaces namespace separators with directory separators -5. Converts to lowercase, prepends `SRFM_DIR`, appends `.php` -6. Rejects any path containing `..` (directory traversal protection) - -## Directory Layout - -``` -sureforms/ -|-- sureforms.php # Plugin entry point, all SRFM_* constants -|-- plugin-loader.php # Autoloader, bootstrap, hook registration -|-- inc/ # Core PHP classes (SRFM\Inc namespace) -| |-- helper.php # Static utility methods -| |-- rest-api.php # REST API endpoint registration -| |-- form-submit.php # Public form submission handler -| |-- post-types.php # sureforms_form CPT and post meta -| |-- entries.php # Entry CRUD operations -| |-- blocks/ # Gutenberg block server-side rendering -| |-- database/ # Custom DB table management -| |-- fields/ # Form field type definitions and validation -| |-- payments/ # Payment gateway integrations (Stripe) -| |-- email/ # Email template rendering -| |-- ai-form-builder/ # AI-powered form generation -| |-- global-settings/ # Plugin-wide settings -| |-- single-form-settings/ # Per-form configuration -| |-- compatibility/ # Theme/plugin compatibility -| |-- page-builders/ # Page builder integrations -| |-- traits/ # Shared PHP traits (Get_Instance) -| |-- lib/ # Bundled third-party libraries (do not modify) -|-- src/ # JS/React source (compiled by wp-scripts) -| |-- admin/ # Admin dashboard React app -| |-- blocks/ # Gutenberg block editor components -| |-- components/ # Shared React components -| |-- store/ # WordPress @wordpress/data store -| |-- utils/ # JS utilities -|-- modules/ # Feature modules (Gutenberg, Quick Action Sidebar) -|-- admin/ # Admin PHP classes and assets -|-- sass/ # SASS source files (compiled to assets/css/) -|-- assets/ # Compiled and static assets -|-- templates/ # PHP templates (BladeOne engine) -|-- tests/ # PHPUnit, Playwright, and Docker setup -``` - -## Design Patterns - -### Singleton via Get_Instance Trait - -Nearly every class uses the `Get_Instance` trait from `inc/traits/get-instance.php`: - -```php -trait Get_Instance { - private static $instance = null; - public static function get_instance() { - if ( null === self::$instance ) { - self::$instance = new self(); - } - return self::$instance; - } -} -``` - -### Abstract Base Class (Database) - -The database layer uses `SRFM\Inc\Database\Base` providing: - -- Table creation via `dbDelta()` -- Schema versioning with integer versions stored in options -- Column migration (`maybe_add_new_columns()`, `maybe_rename_columns()`) -- CRUD wrappers (`use_insert()`, `use_update()`, `use_delete()`) -- Query builder with parameterized WHERE supporting `=`, `!=`, `>`, `<`, `LIKE`, `IN` -- In-memory result caching keyed by MD5 of SQL query -- Schema-driven JSON encoding/decoding for array columns - -### Hook-Based Initialization - -Classes register WordPress hooks in their constructors, invoked during singleton instantiation in `load_plugin()` or `load_classes()`. - -### Filter-Driven Extensibility - -| Filter | Purpose | -|--------|---------| -| `srfm_rest_api_endpoints` | Extend REST API routes | -| `srfm_register_post_meta` | Register additional form post meta | -| `srfm_form_submit_data` | Modify form data before processing | -| `srfm_entry_value` | Transform entry field values | -| `srfm_is_special_block` | Declare custom blocks as special | -| `srfm_handle_special_block` | Custom processing for special blocks | -| `srfm_form_confirmation_params` | Extend form confirmation settings | -| `srfm_normalize_csv_field_value` | Custom CSV export formatting | - -## Data Flow - -``` -1. FORM CREATION - Admin creates form in Gutenberg block editor - -> Saved as sureforms_form CPT (wp_posts) - -> Settings stored as post meta (_srfm_* keys) - -> Block content in post_content column - -2. FORM DISPLAY - Form embedded via shortcode, Gutenberg block, or Instant Form URL - -> Generate_Form_Markup::get_form_markup() renders HTML - -> Frontend_Assets enqueues CSS/JS - -> Submission nonce generated - -3. FORM SUBMISSION - User submits via JavaScript fetch() - -> POST /wp-json/sureforms/v1/submit-form - -> Nonce verification, field validation - -> CAPTCHA validation (reCAPTCHA, hCaptcha, Turnstile) - -> Honeypot spam check - -4. ENTRY STORAGE - -> JSON-encoded form data inserted into wp_srfm_entries - -> Email notifications sent - -> Payment processed if applicable (wp_srfm_payments) - -> Confirmation response returned - -5. POST-SUBMISSION - -> srfm_form_submit and srfm_after_submission_process actions fired -``` - -## Key Constants - -| Constant | Value | Purpose | -|----------|-------|---------| -| `SRFM_FILE` | `__FILE__` | Main plugin file path | -| `SRFM_DIR` | Plugin dir path | File system operations | -| `SRFM_URL` | Plugin URL | Asset URL generation | -| `SRFM_VER` | `2.5.1` | Version for cache busting | -| `SRFM_SLUG` | `srfm` | Short identifier slug | -| `SRFM_FORMS_POST_TYPE` | `sureforms_form` | Custom post type slug | -| `SRFM_ENTRIES` | `sureforms_entries` | Entries identifier | -| `SRFM_PAYMENTS` | `sureforms_payments` | Payments identifier | -| `SRFM_PRO_RECOMMENDED_VER` | `2.5.1` | Minimum Pro version | - -## Related Pages - -- [Database Schema](Database-Schema) -- Custom tables, post types, and meta keys -- [Environment Configuration](Environment-Configuration) -- Development setup, build tools, and linting -- [REST API Reference](REST-API-Reference) -- Full endpoint documentation -- [Form Submission Flow](Form-Submission-Flow) -- Detailed submission pipeline -- [WordPress Hooks Reference](WordPress-Hooks-Reference) -- All actions and filters diff --git a/docs/wiki/Block-Editor-Controls.md b/docs/wiki/Block-Editor-Controls.md deleted file mode 100644 index 7d5cd1e33..000000000 --- a/docs/wiki/Block-Editor-Controls.md +++ /dev/null @@ -1,109 +0,0 @@ -# Block Editor Controls - -SureForms provides custom inspector controls and utilities for the Gutenberg block editor experience. - -## Directory Structure - -``` -src/srfm-controls/ -|-- addCommonData.js # Inject common data into blocks -|-- generateCSS.js # Dynamic CSS generation for blocks -|-- block-icons.js # Block icon definitions -|-- fonts.js # Font management utilities -|-- maybeGetColorForVariable.js # CSS variable color resolution -|-- parseIcon.js # SVG icon parser -|-- renderIcon.js # Icon rendering component - -src/blocks-attributes/ -|-- getMetakeys.js # Form meta key retrieval -|-- getFormId.js # Get current form ID -|-- getBlocksDefaultAttributes.js # Block attribute defaults -``` - -## CSS Generation System - -`generateCSS.js` dynamically generates CSS for block styling: - -- Converts block attributes to CSS properties -- Supports responsive breakpoints (desktop, tablet, mobile) -- Generates inline styles injected into the page -- Handles CSS variable references - -This system allows each block instance to have unique styling without class conflicts. - -## Block Icons - -`block-icons.js` provides SVG icon components for all SureForms blocks, used in: - -- Block inserter panel -- Block toolbar -- Block settings sidebar - -Additional icon sets from Spectra are available via `spectra-icons-v*.php` files. - -Icon utilities: -- `parseIcon.js` -- Parses SVG string into React-renderable format -- `renderIcon.js` -- React component for rendering parsed icons - -## Common Data Injection - -`addCommonData.js` injects shared data into block components: - -- Form-level settings accessible to all child blocks -- Common attributes and defaults -- Shared configuration values - -## Meta Key Integration - -`getMetakeys.js` retrieves form post meta keys for use in block controls: - -- Provides meta key names for form settings -- Used by inspector controls to read/write form meta -- Integrates with `@wordpress/data` store - -## Block Attribute Defaults - -`getBlocksDefaultAttributes.js` provides default attribute values for all block types: - -- Ensures consistent defaults across block instances -- Used during block registration -- Prevents undefined attribute errors - -## Form ID Resolution - -`getFormId.js` resolves the current form's post ID: - -- Used by blocks to identify their parent form -- Required for meta key operations -- Supports nested block contexts - -## Field Preview - -`src/blocks/FieldsPreview.jsx` renders a preview of form fields in the block editor: - -- Shows a visual representation of the field in editor mode -- Responds to attribute changes in real-time -- Handles edit vs preview states - -## Font Management - -`fonts.js` manages font loading for form styling: - -- Font family selection in block settings -- Google Fonts integration -- Font weight and style options - -## Color Variable Resolution - -`maybeGetColorForVariable.js` resolves WordPress CSS custom properties: - -- Maps color slugs to CSS variable references -- Supports theme color palette integration -- Falls back to raw color values when variables are not available - -## Related Pages - -- [Gutenberg Blocks](Gutenberg-Blocks) -- Block types and registration -- [State Management](State-Management) -- WordPress data store -- [Frontend Assets](Frontend-Assets) -- Editor asset loading -- [Form Fields Architecture](Form-Fields-Architecture) -- Field types diff --git a/docs/wiki/Changelog.md b/docs/wiki/Changelog.md deleted file mode 100644 index 058c89f45..000000000 --- a/docs/wiki/Changelog.md +++ /dev/null @@ -1,39 +0,0 @@ -# Changelog - -Recent changes to SureForms. For the full changelog, see [sureforms.com/whats-new](https://sureforms.com/whats-new/). - -## 2.5.1 - 16th February 2026 - -- **New:** Added option to change currency position (e.g., $100, 100$, $ 100, 100 $) -- **Fix:** Fixed the payment block amount not updating correctly with conditional logic - -## 2.5.0 - 2nd February 2026 - -- **Improvement:** Added translation support for the country list in the phone number field -- **Fix:** Fixed dropdown placeholder and GDPR label translation on the frontend - -## 2.4.0 - 20th January 2026 - -- **New:** Added form scheduling restrictions with start and end date/time -- **New:** Added Previous/Next navigation for single entry page -- **Improvement:** Improved multi-choice block settings UI -- **Improvement:** Updated Syria flag in the Phone field -- **Fix:** Fixed HTML block content corruption when duplicating forms -- **Fix:** Fixed multi-choice options being translated in entries -- **Fix:** Fixed reCAPTCHA v3 validation triggering multiple times on the same page -- **Fix:** Fixed Spectra button styles being affected by SureForms CSS - -## Version Bumping - -When preparing a release, update the version in: - -1. `sureforms.php` -- Plugin header `Version:` and `SRFM_VER` constant -2. `readme.txt` -- `Stable tag:` and changelog section -3. `package.json` -- `version` field - -See [Deployment Guide](Deployment-Guide) for the full release process. - -## Related Pages - -- [Deployment Guide](Deployment-Guide) -- Release workflow and CI/CD -- [Contributing Guide](Contributing-Guide) -- Development workflow diff --git a/docs/wiki/Contributing-Guide.md b/docs/wiki/Contributing-Guide.md deleted file mode 100644 index 441736c7e..000000000 --- a/docs/wiki/Contributing-Guide.md +++ /dev/null @@ -1,205 +0,0 @@ -# Contributing Guide - -Thank you for your interest in contributing to SureForms! This guide covers the development workflow, coding standards, and submission process. - -## Prerequisites - -- **PHP** 7.4+ -- **Node.js** 24.16.0 (managed via [Volta](https://volta.sh/)) -- **Composer** for PHP dependencies -- **Git** for version control -- **Docker** (optional, for wp-env test environment) - -## Getting Started - -1. Fork the repository on GitHub -2. Clone your fork: - ```bash - git clone https://github.com/YOUR_USERNAME/sureforms.git - cd sureforms - ``` -3. Install dependencies: - ```bash - composer install - npm install - ``` -4. Create a feature branch from `next-release`: - ```bash - git checkout next-release - git pull origin next-release - git checkout -b feature/your-feature-name - ``` - -## Git Workflow - -``` -feature/branch --> next-release --> master --> tag/release - (development) (production) -``` - -- **Feature branches** are created from `next-release` -- **Pull requests** target `next-release` -- **Hotfixes** may target `master` directly -- **Release merges** go from `next-release` into `master` - -## Development Workflow - -### Running the Dev Server - -```bash -npm start # Start wp-scripts dev server (hot reload) -``` - -### Building - -```bash -npm run build # Full production build (JS + SASS + minify) -npm run build:script # Build JS only -npm run build:sass # Build SASS only -``` - -### Linting - -Run linters before submitting a PR: - -```bash -# JavaScript -npm run lint-js # ESLint check -npm run lint-js:fix # Auto-fix JS issues - -# CSS -npm run lint-css # Stylelint check -npm run lint-css:fix # Auto-fix CSS issues - -# Formatting -npm run pretty # Prettier check -npm run pretty:fix # Auto-format - -# PHP -vendor/bin/phpcs # PHP CodeSniffer (WPCS) -vendor/bin/phpcbf # Auto-fix PHPCS issues -``` - -### Testing - -All tests should pass before submitting a PR: - -```bash -# PHP unit tests -vendor/bin/phpunit - -# JavaScript unit tests -npm run test:unit - -# E2E tests (requires wp-env) -npm run play:up # Start environment -npm run play:run # Run Playwright tests -``` - -See [Testing Guide](Testing-Guide) for detailed test setup. - -## Coding Standards - -### PHP Standards - -SureForms follows **WordPress Coding Standards (WPCS)** enforced via `phpcs.xml`: - -- **Escaping**: Use `esc_html()`, `esc_attr()`, `esc_url()`, `wp_kses_post()` for all output -- **Nonces**: Use `wp_nonce_field()` / `check_ajax_referer()` for form submissions and AJAX -- **Capabilities**: Always check `current_user_can()` before privileged operations -- **Sanitization**: Use `sanitize_text_field()`, `absint()`, `wp_kses()` for all input -- **Prefixes**: `SRFM_` for constants, `srfm_` for function names and handles -- **Text domain**: `sureforms` for all translatable strings -- **PHP compatibility**: 7.4+ (enforced via `PHPCompatibilityWP`) - -### JavaScript Standards - -- Follow `@wordpress/scripts` ESLint configuration -- Use `@wordpress/data` store for state management -- Use `@wordpress/api-fetch` for REST API calls -- Import WordPress dependencies from `@wordpress/*` packages -- Use Force UI (`@bsf/force-ui`) components in admin dashboard pages - -### CSS Standards - -- **Admin dashboard**: Tailwind CSS 3.x utility classes -- **Block frontend**: SASS files in `sass/` directory -- **Class prefix**: `srfm-` for all frontend CSS classes -- Do not edit generated CSS in `assets/css/` -- edit SASS source files instead - -## Pull Request Process - -### PR Checklist - -Before submitting your PR, verify: - -- [ ] Code follows the coding standards (PHP, JS, CSS) -- [ ] All linters pass without errors -- [ ] Tests pass (PHPUnit, Jest) -- [ ] New features include tests -- [ ] Translatable strings use the `sureforms` text domain -- [ ] No debug code, `console.log`, or `var_dump` statements -- [ ] No secrets or credentials committed -- [ ] Build completes without errors (`npm run build`) - -### PR Title Format - -PR titles are validated by CI. Use a clear, descriptive title that summarizes the change. - -### CI Checks - -Pull requests automatically run: - -1. **PHPUnit** -- PHP unit tests -2. **PHPStan** -- Static analysis -3. **PHP Insights** -- Code quality -4. **PR Title Validation** -- Title format check -5. **E2E Tests** -- When the PR is labeled with `e2e` - -All checks must pass before merge. - -### Code Review - -- PRs require at least one approving review -- Address all review comments -- Keep PRs focused on a single feature or fix -- Large changes should be discussed in an issue first - -## Directory Guide for Contributors - -| Directory | Purpose | Edit? | -|-----------|---------|-------| -| `src/` | JS/React source code | Yes | -| `sass/` | SASS stylesheets | Yes | -| `inc/` | PHP classes and logic | Yes | -| `tests/` | Test files | Yes | -| `build/` | Compiled JS output | No (generated) | -| `assets/css/` | Compiled CSS output | No (generated) | -| `assets/js/minified/` | Minified JS | No (generated) | -| `inc/lib/` | Bundled third-party libraries | No | -| `node_modules/` | NPM packages | No | -| `vendor/` | Composer packages | No | - -## Adding a New Gutenberg Block - -See [Gutenberg Blocks](Gutenberg-Blocks) for the full guide on adding blocks, including: - -- Block registration (server-side and client-side) -- `block.json` schema -- Editor and frontend rendering - -## Adding a New REST Endpoint - -See [REST API Reference](REST-API-Reference) for endpoint patterns and the registration system. - -## Reporting Issues - -- Use [GitHub Issues](https://github.com/brainstormforce/sureforms/issues) for bug reports and feature requests -- Security vulnerabilities should be reported through the [Bug Bounty Program](https://brainstormforce.com/bug-bounty-program/) - -## Related Pages - -- [Environment Configuration](Environment-Configuration) -- Development setup details -- [Architecture Overview](Architecture-Overview) -- Codebase structure -- [Testing Guide](Testing-Guide) -- Test framework details -- [Deployment Guide](Deployment-Guide) -- Release process diff --git a/docs/wiki/Data-Export-Import.md b/docs/wiki/Data-Export-Import.md deleted file mode 100644 index fc07271ae..000000000 --- a/docs/wiki/Data-Export-Import.md +++ /dev/null @@ -1,120 +0,0 @@ -# Data Export & Import - -SureForms supports exporting and importing forms and entries for backup, migration, and data analysis. - -## Form Export - -### REST Endpoint - -`POST /wp-json/sureforms/v1/forms/export` - -**Parameters:** -- `form_ids` (required) -- Array of form IDs to export - -**Response:** JSON file containing form data including: -- Form post data (title, content, status) -- All form post meta (`_srfm_*` keys) -- Block content (Gutenberg blocks) - -### Export Format - -Forms are exported as a JSON structure containing all data needed to recreate the form on another site. - -## Form Import - -### REST Endpoint - -`POST /wp-json/sureforms/v1/forms/import` - -**Parameters:** -- File upload containing exported JSON data - -**Process:** -1. Validates the uploaded JSON structure -2. Creates new `sureforms_form` posts -3. Restores all post meta keys -4. Assigns new post IDs (no ID conflicts) -5. Returns count of imported forms - -## Form Duplication - -### REST Endpoint - -`POST /wp-json/sureforms/v1/forms/duplicate` - -**Parameters:** -- `form_id` (required) -- ID of the form to duplicate - -**Process:** - -Handled by `Duplicate_Form` class (`inc/duplicate-form.php`): - -1. Reads the original form post and all meta -2. Creates a new post with "(Copy)" appended to the title -3. Copies all `_srfm_*` post meta to the new form -4. Returns the new form ID - -## Entry Export - -### REST Endpoint - -`POST /wp-json/sureforms/v1/entries/export` - -**Parameters:** -- `entry_ids` -- Specific entry IDs to export (optional) -- `form_id` -- Export all entries for a specific form -- `status` -- Filter by status (all, read, unread) -- `search` -- Search filter -- `date_from` / `date_to` -- Date range filter - -**Response:** CSV file (or ZIP for large exports) - -### Export Format - -The `Export` class (`inc/export.php`) generates CSV with: -- One row per entry -- Columns for each form field -- Submission metadata (date, status, IP) -- Field values normalized via `srfm_normalize_csv_field_value` filter - -### CSV Field Value Normalization - -The `srfm_normalize_csv_field_value` filter allows customizing how field values appear in CSV exports: - -```php -add_filter( 'srfm_normalize_csv_field_value', function( $value, $field ) { - // Custom formatting for specific field types - return $value; -}, 10, 2 ); -``` - -## Form Lifecycle Management - -### REST Endpoint - -`POST /wp-json/sureforms/v1/forms/manage` - -**Parameters:** -- `form_ids` (required) -- Array of form IDs -- `action` (required) -- `trash`, `restore`, or `delete` - -| Action | Behavior | -|--------|----------| -| `trash` | Move forms to trash (recoverable) | -| `restore` | Restore trashed forms | -| `delete` | Permanently delete forms | - -## Create New Form - -The `Create_New_Form` class (`inc/create-new-form.php`) handles new form creation with default meta values: - -- Sets default styling options -- Configures default submit button text -- Initializes email notification defaults -- Applies default form confirmation settings - -## Related Pages - -- [REST API Reference](REST-API-Reference) -- All export/import endpoints -- [Database Schema](Database-Schema) -- Entry and form data structure -- [Admin Dashboard](Admin-Dashboard) -- UI for export/import operations diff --git a/docs/wiki/Database-Schema.md b/docs/wiki/Database-Schema.md deleted file mode 100644 index c0a47044b..000000000 --- a/docs/wiki/Database-Schema.md +++ /dev/null @@ -1,173 +0,0 @@ -# Database Schema - -SureForms uses two custom database tables alongside the WordPress `sureforms_form` custom post type. All custom tables use the `wp_srfm_` prefix. - -## Table Relationships - -``` -+-------------------+ +-------------------+ -| wp_posts | | wp_srfm_entries | -| (sureforms_form) |<---------| form_id | -| ID (PK) | | | ID (PK) | -| post_content | | | user_id | -| post_meta (_srfm)| | | form_data (JSON) | -+-------------------+ | | status | - | +--------+-----------+ - | | - | +--------v-----------+ - | | wp_srfm_payments | - +----| form_id | - | id (PK) | - | entry_id (FK) | - | transaction_id | - | total_amount | - +--------------------+ -``` - -## Custom Tables - -### wp_srfm_entries - -Stores all form submissions. Table version: 1. - -| Column | Type | Default | Description | -|--------|------|---------|-------------| -| `ID` | BIGINT(20) UNSIGNED | AUTO_INCREMENT | Primary key | -| `form_id` | BIGINT(20) UNSIGNED | -- | Reference to sureforms_form post ID | -| `user_id` | BIGINT(20) UNSIGNED | 0 | WordPress user ID (0 = anonymous) | -| `status` | VARCHAR(10) | `unread` | Entry status: `unread`, `read`, `trash` | -| `type` | VARCHAR(20) | -- | Form type: `quiz`, `standard`, etc. | -| `form_data` | LONGTEXT | `[]` | JSON-encoded submitted field values | -| `submission_info` | LONGTEXT | `[]` | JSON-encoded browser/device/IP metadata | -| `notes` | LONGTEXT | `[]` | JSON-encoded admin notes | -| `logs` | LONGTEXT | `[]` | JSON-encoded activity log entries | -| `extras` | LONGTEXT | `[]` | JSON-encoded misc additional data | -| `created_at` | TIMESTAMP | CURRENT_TIMESTAMP | Submission timestamp | -| `updated_at` | TIMESTAMP | CURRENT_TIMESTAMP ON UPDATE | Last update timestamp | - -**Indexes:** -- `PRIMARY KEY (ID)` -- `INDEX idx_form_id (form_id)` -- `INDEX idx_user_id (user_id)` -- `INDEX idx_form_id_created_at_status (form_id, created_at, status)` -- composite index for list queries - -**Log Entry Structure:** -```json -{ - "title": "Form Submitted", - "messages": ["Email notification sent", "Entry stored"], - "timestamp": "2024-01-15 10:30:00" -} -``` - -### wp_srfm_payments - -Stores payment transaction records linked to form entries. Table version: 1. Added in v2.0.0. - -| Column | Type | Default | Description | -|--------|------|---------|-------------| -| `id` | BIGINT(20) UNSIGNED | AUTO_INCREMENT | Primary key | -| `form_id` | BIGINT(20) UNSIGNED | -- | Reference to sureforms_form post | -| `block_id` | VARCHAR(255) | `''` | Payment block identifier | -| `status` | VARCHAR(50) | `pending` | Payment status (see below) | -| `total_amount` | DECIMAL(26,8) | `0.00000000` | Total amount after discount | -| `refunded_amount` | DECIMAL(26,8) | `0.00000000` | Total refunded amount | -| `currency` | VARCHAR(10) | `''` | ISO 4217 currency code | -| `entry_id` | BIGINT(20) UNSIGNED | 0 | Reference to entries table | -| `gateway` | VARCHAR(20) | `''` | Payment gateway: `stripe` | -| `type` | VARCHAR(30) | `''` | Payment type: `payment`, `subscription`, `renewal` | -| `mode` | VARCHAR(20) | `''` | Mode: `test` or `live` | -| `transaction_id` | VARCHAR(50) | `''` | Gateway transaction ID | -| `customer_id` | VARCHAR(50) | `''` | Gateway customer ID | -| `subscription_id` | VARCHAR(50) | `''` | Subscription ID (if recurring) | -| `subscription_status` | VARCHAR(20) | `''` | Subscription status | -| `parent_subscription_id` | BIGINT(20) UNSIGNED | 0 | Parent subscription payment ID | -| `payment_data` | LONGTEXT | `[]` | JSON-encoded payment details (includes refunds) | -| `extra` | LONGTEXT | `[]` | JSON-encoded additional data | -| `log` | LONGTEXT | `[]` | JSON-encoded payment log | -| `created_at` | TIMESTAMP | CURRENT_TIMESTAMP | Creation timestamp | -| `updated_at` | TIMESTAMP | CURRENT_TIMESTAMP ON UPDATE | Last update timestamp | -| `srfm_txn_id` | VARCHAR(100) | `''` | Custom transaction ID format | -| `customer_email` | VARCHAR(255) | `''` | Customer email | -| `customer_name` | VARCHAR(255) | `''` | Customer name | - -**Valid Payment Statuses:** -`pending`, `succeeded`, `failed`, `canceled`, `requires_action`, `requires_payment_method`, `processing`, `refunded`, `partially_refunded` - -**Valid Subscription Statuses:** -`active`, `canceled`, `past_due`, `unpaid`, `trialing`, `incomplete`, `incomplete_expired`, `paused` - -**Supported Currencies:** -USD, EUR, GBP, JPY, CAD, AUD, CHF, CNY, SEK, NZD, MXN, SGD, HKD, NOK, TRY, RUB, INR, BRL, ZAR, KRW - -## WordPress Post Type: sureforms_form - -Forms are stored as a custom post type (`sureforms_form`) in the standard `wp_posts` table. Block content is in `post_content`, and form configuration is stored as post meta with `_srfm_` prefixed keys. - -### Key Post Meta Keys - -| Meta Key | Type | Description | -|----------|------|-------------| -| `_srfm_forms_styling` | string | Form styling mode | -| `_srfm_color` | string | Primary form color | -| `_srfm_bg_color` | string | Background color | -| `_srfm_fontsize` | string | Font size | -| `_srfm_label_color` | string | Label text color | -| `_srfm_input_color` | string | Input text color | -| `_srfm_submit_button_text` | string | Submit button text | -| `_srfm_submit_alignment` | string | Button alignment | -| `_srfm_submit_width` | string | Button width | -| `_srfm_submit_width_backend` | string | Backend button width | -| `_srfm_is_inline_button` | boolean | Inline button mode | -| `_srfm_email_notification` | array | Email notification settings | -| `_srfm_form_confirmation` | array | Confirmation settings (message/redirect) | -| `_srfm_captcha` | string | CAPTCHA type (recaptcha_v2, v3, hcaptcha, turnstile) | -| `_srfm_honeypot` | boolean | Honeypot spam protection | -| `_srfm_is_page_break` | boolean | Multi-step form enabled | -| `_srfm_single_page_form_title` | boolean | Show title on instant form | -| `_srfm_instant_form_settings` | array | Instant form configuration | -| `_srfm_page_form_logo` | string | Form logo URL | -| `_srfm_submit_type` | string | Submission type | - -Post meta is extensible via the `srfm_register_post_meta` filter. - -## Database Base Class - -All custom tables extend `SRFM\Inc\Database\Base`, which provides: - -### Schema Versioning -- Each table has a `$table_version` integer -- Versions stored in `srfm_database_table_versions` option -- On version mismatch, `start_db_upgrade()` runs migrations (new columns, renames) - -### Query Builder -```php -// Simple equality -$results = $instance->get_results(['form_id' => 123]); - -// Complex conditions with operators -$results = $instance->get_results([ - [ - ['key' => 'status', 'compare' => '!=', 'value' => 'trash'], - ['key' => 'created_at', 'compare' => '>', 'value' => '2024-01-01'], - ] -]); - -// IN operator -$results = $instance->get_results([ - [['key' => 'ID', 'compare' => 'IN', 'value' => [1, 2, 3]]] -]); -``` - -### Caching -Results are cached in-memory using MD5 of the SQL query as the cache key. Cache is reset on insert, update, or delete operations. - -### Data Encoding -Array-type columns (defined in `get_schema()`) are automatically JSON-encoded on write and decoded on read. Number types are cast to integers. - -## Related Pages - -- [Architecture Overview](Architecture-Overview) -- Plugin bootstrap and class initialization -- [Payment Integration](Payment-Integration) -- Stripe payment flow -- [Form Submission Flow](Form-Submission-Flow) -- Entry creation pipeline -- [REST API Reference](REST-API-Reference) -- API endpoints for entries and payments diff --git a/docs/wiki/Deployment-Guide.md b/docs/wiki/Deployment-Guide.md deleted file mode 100644 index 1511856ec..000000000 --- a/docs/wiki/Deployment-Guide.md +++ /dev/null @@ -1,109 +0,0 @@ -# Deployment Guide - -## Release Process Overview - -SureForms follows a branch-based release workflow with automated CI/CD via GitHub Actions. - -## Git Workflow - -``` -feature/branch --> next-release --> master --> tag/release - (development) (production) -``` - -1. Feature branches are created from `next-release` -2. PRs target `next-release` for review and merge -3. `next-release` is merged to `master` for releases -4. Tags trigger release artifacts - -## Build Steps - -### Production Build - -```bash -# Full production build (JS + SASS + minify) -npm run build - -# Individual steps: -npm run build:script # Build JS via wp-scripts -npm run build:sass # Compile SASS via Grunt -``` - -The build process: -1. Webpack bundles JS/React source from `src/` to `assets/build/` -2. Grunt compiles SASS from `sass/` to `assets/css/` -3. Grunt minifies CSS to `assets/css/minified/` -4. Grunt minifies JS to `assets/js/minified/` -5. PostCSS applies Autoprefixer - -### i18n - -```bash -npm run makepot # Generate .pot translation file -``` - -## CI/CD Pipelines - -### GitHub Actions Workflows - -| Workflow | Trigger | Purpose | -|----------|---------|---------| -| `phpunit.yml` | Pull requests | Run PHP unit tests | -| `playwright.yml` | PR labeled `e2e` | Run E2E browser tests | -| `code-analysis.yml` | Pull requests | PHPStan static analysis | -| `insights.yml` | Pull requests | PHP Insights code quality | -| `pr-title.yml` | Pull requests | Validate PR title format | -| `push-to-deploy.yml` | Push to master | Deploy to production | -| `push-asset-readme-update.yml` | Push to master | Update readme/assets | -| `release-tag-draft.yml` | Tag push | Create draft GitHub release | -| `release-pr-template.yml` | Release PRs | Apply release PR template | -| `claude-code-review.yml` | Pull requests | AI-powered code review | - -### Test Pipeline - -Pull requests automatically run: -1. PHPUnit tests (PHP 8.2, WordPress trunk) -2. PHPStan static analysis -3. PHP Insights code quality -4. PR title validation -5. E2E tests (when labeled `e2e`) - -### Deployment Pipeline - -On push to `master`: -1. `push-to-deploy.yml` triggers deployment -2. `push-asset-readme-update.yml` updates WordPress.org assets - -### Release Pipeline - -1. Merge `next-release` into `master` -2. Create a version tag (e.g., `v2.5.1`) -3. `release-tag-draft.yml` creates a draft GitHub release -4. Review and publish the release - -## Pre-Deployment Checklist - -- [ ] All tests pass (PHPUnit, Playwright, Jest) -- [ ] PHPStan analysis clean -- [ ] PHPCS standards pass -- [ ] Production build completes without errors -- [ ] Version bumped in `sureforms.php` and `readme.txt` -- [ ] `SRFM_VER` constant updated -- [ ] `SRFM_PRO_RECOMMENDED_VER` checked -- [ ] Changelog updated in `readme.txt` -- [ ] Translation .pot file regenerated -- [ ] No debug code or console.log statements -- [ ] Database migrations tested (if any) - -## Version Bumping - -Update version in these files: -1. `sureforms.php` -- Plugin header `Version:` and `SRFM_VER` constant -2. `readme.txt` -- `Stable tag:` and changelog section -3. `package.json` -- `version` field - -## Related Pages - -- [Testing Guide](Testing-Guide) -- Test setup and execution -- [Contributing Guide](Contributing-Guide) -- Development workflow -- [Environment Configuration](Environment-Configuration) -- Build tools diff --git a/docs/wiki/Email-Notifications.md b/docs/wiki/Email-Notifications.md deleted file mode 100644 index 642751bcb..000000000 --- a/docs/wiki/Email-Notifications.md +++ /dev/null @@ -1,86 +0,0 @@ -# Email Notifications - -SureForms sends email notifications on form submission and supports scheduled email summary digests. - -## Email System Overview - -``` -Form Submission - -> Form_Submit::handle_form_submission() - -> Email_Template (inc/email/email-template.php) - -> Smart_Tags resolution - -> wp_mail() dispatch -``` - -## Email Template - -The `Email_Template` class (`inc/email/email-template.php`) handles: - -- HTML email template rendering -- Dynamic content insertion via smart tags -- Multiple notification recipients -- Customizable subject lines and body content -- Reply-to address configuration - -### Per-Form Email Settings - -Email notifications are configured per-form via the `_srfm_email_notification` post meta key. Each form can have: - -- **To** -- Recipient email addresses (supports multiple, comma-separated) -- **Subject** -- Email subject line (supports smart tags) -- **Body** -- Email content (supports smart tags and HTML) -- **Reply-To** -- Reply-to email address -- **CC/BCC** -- Additional recipients - -## Smart Tags - -The `Smart_Tags` class (`inc/smart-tags.php`) provides template variables that are resolved at email send time: - -| Smart Tag | Description | -|-----------|-------------| -| `{admin_email}` | WordPress admin email | -| `{site_title}` | WordPress site title | -| `{site_url}` | WordPress site URL | -| `{form_title}` | Name of the submitted form | -| `{form_id}` | ID of the submitted form | -| `{entry_id}` | ID of the created entry | -| `{all_fields}` | All submitted field values formatted | -| `{field:field_name}` | Specific field value by field name | -| `{user_ip}` | Submitter's IP address | -| `{user_agent}` | Submitter's browser user agent | -| `{submission_date}` | Date of submission | - -Smart tags are processed by replacing the tag placeholders with actual values from the form submission data. - -## Email Summary - -The `Email_Summary` class (`inc/global-settings/email-summary.php`) provides scheduled digest reports: - -- Configurable frequency (daily, weekly, monthly) -- Summary of form submissions over the period -- Entry counts per form -- Sent to configured admin email addresses -- Uses WordPress cron (`Events_Scheduler`) for scheduling - -## Customization - -### Modifying Email Content - -Email content is filtered through smart tag processing, allowing dynamic content: - -```php -// In per-form settings, the email body supports: -// - Smart tags: {form_title}, {all_fields}, etc. -// - HTML formatting -// - Custom text -``` - -### Extending Smart Tags - -Smart tags can be extended by hooking into the tag resolution process to add custom replacements. - -## Related Pages - -- [Form Submission Flow](Form-Submission-Flow) -- When emails are triggered -- [WordPress Hooks Reference](WordPress-Hooks-Reference) -- Email-related hooks -- [Architecture Overview](Architecture-Overview) -- Email_Template initialization diff --git a/docs/wiki/Environment-Configuration.md b/docs/wiki/Environment-Configuration.md deleted file mode 100644 index b4a89da2f..000000000 --- a/docs/wiki/Environment-Configuration.md +++ /dev/null @@ -1,197 +0,0 @@ -# Environment Configuration - -## Prerequisites - -| Requirement | Version | Notes | -|-------------|---------|-------| -| PHP | 7.4+ | WordPress minimum requirement | -| WordPress | 6.4+ | Gutenberg block editor required | -| Node.js | 24.16.0 | Managed via Volta (see `package.json`) | -| Composer | 2.x | PHP dependency management | -| npm | 11.x+ | Comes with Node 24 | - -## Plugin Constants - -Defined in `sureforms.php`: - -| Constant | Value | Purpose | -|----------|-------|---------| -| `SRFM_FILE` | `__FILE__` | Absolute path to main plugin file | -| `SRFM_BASENAME` | `sureforms/sureforms.php` | Plugin basename for hooks | -| `SRFM_DIR` | Plugin directory path | File system path operations | -| `SRFM_URL` | Plugin URL | Asset URL generation | -| `SRFM_VER` | `2.5.1` | Version for cache busting | -| `SRFM_SLUG` | `srfm` | Short identifier slug | -| `SRFM_FORMS_POST_TYPE` | `sureforms_form` | Custom post type slug | -| `SRFM_ENTRIES` | `sureforms_entries` | Entries identifier | -| `SRFM_PAYMENTS` | `sureforms_payments` | Payments identifier | -| `SRFM_WEBSITE` | `https://sureforms.com/` | Official website | -| `SRFM_AI_MIDDLEWARE` | `https://credits.startertemplates.com/sureforms/` | AI credits API | -| `SRFM_MIDDLEWARE_BASE_URL` | `https://api.sureforms.com/` | API middleware | -| `SRFM_BILLING_PORTAL` | `https://billing.sureforms.com/` | Billing portal | -| `SRFM_PRO_RECOMMENDED_VER` | `2.5.1` | Minimum recommended Pro version | -| `SRFM_SURETRIGGERS_INTEGRATION_BASE_URL` | `https://app.ottokit.com/` | OttoKit integration | - -## Development Environment Setup - -### Option 1: wp-env (Docker) - -```bash -# Start the WordPress environment -npm run play:up - -# Stop the environment -npm run play:stop - -# Clean environment data -npm run env:clean -``` - -Configuration is in `.wp-env.json`. Requires Docker to be installed. - -### Option 2: Local by Flywheel / MAMP / XAMPP - -1. Set up a local WordPress installation -2. Clone the repo into `wp-content/plugins/sureforms` -3. Run `composer install` for PHP dependencies -4. Run `npm install` for JS dependencies -5. Run `npm start` for development with hot reload - -## Build Tools - -### wp-scripts (JavaScript) - -Primary build tool for JS/React compilation via Webpack: - -```bash -npm start # Dev server with hot reload -npm run build:script # Production JS build -``` - -Entry points are defined in `webpack.config.js` and output to `assets/build/`. - -### Grunt (SASS / Minification) - -```bash -npm run build:sass # Compile SASS to CSS -npm run build # Full build (JS + SASS + minify) -``` - -The `Gruntfile.js` handles: -- SASS compilation (`sass/` -> `assets/css/`) -- CSS minification -- JS minification -- PostCSS with Autoprefixer - -### Tailwind CSS - -Used for admin dashboard styles. Configuration in `tailwind.config.js`: -- Content scanning paths: `src/admin/**/*.{js,jsx}` -- Plugin: `@tailwindcss/forms` -- Custom theme extensions for Force UI integration - -### PostCSS - -Configuration in `postcss.config.js`: -- Autoprefixer for browser compatibility -- cssnano for production minification - -## NPM Scripts Reference - -| Script | Command | Description | -|--------|---------|-------------| -| `start` | `wp-scripts start` | Dev server with hot reload | -| `build` | Full pipeline | JS + SASS + minify | -| `build:script` | `wp-scripts build` | Build JS only | -| `build:sass` | Grunt sass tasks | Build SASS only | -| `lint-js` | `wp-scripts lint-js` | ESLint check | -| `lint-js:fix` | `wp-scripts lint-js --fix` | Auto-fix JS lint | -| `lint-css` | `wp-scripts lint-style` | Stylelint check | -| `lint-css:fix` | `wp-scripts lint-style --fix` | Auto-fix CSS lint | -| `pretty` | `prettier --check` | Prettier check | -| `pretty:fix` | `prettier --write` | Prettier format | -| `test:unit` | `wp-scripts test-unit-js` | Jest unit tests | -| `play:up` | `wp-env start` | Start Docker env | -| `play:stop` | `wp-env stop` | Stop Docker env | -| `play:run` | `playwright test` | Run E2E tests | -| `play:run:interactive` | `playwright test --headed` | E2E tests (headed) | -| `env:clean` | `wp-env clean` | Clean Docker data | -| `makepot` | `wp i18n make-pot` | Generate .pot file | - -## Composer Scripts - -| Script | Description | -|--------|-------------| -| `vendor/bin/phpunit` | Run PHPUnit tests | -| `vendor/bin/phpcs` | PHP CodeSniffer (WPCS) | -| `vendor/bin/phpcbf` | Auto-fix PHPCS issues | -| `vendor/bin/phpstan` | PHPStan static analysis | - -## Linting Configuration - -### PHP (PHPCS) - -Configured via `phpcs.xml`: -- Ruleset: WordPress Coding Standards (WPCS) -- PHPCompatibility for PHP 7.4+ -- Text domain: `sureforms` -- Prefixes: `srfm`, `SRFM_` - -### JavaScript (ESLint) - -Uses `@wordpress/scripts` ESLint configuration which extends WordPress defaults. - -### CSS (Stylelint) - -WordPress Stylelint configuration via `@wordpress/scripts`. - -### Prettier - -Code formatting for JS/CSS files. - -## Volta Configuration - -Node version is pinned in `package.json`: - -```json -{ - "volta": { - "node": "24.16.0" - } -} -``` - -Install Volta to automatically use the correct Node version when entering the project directory. - -## Key Dependencies - -### PHP (Composer) - -| Package | Purpose | -|---------|---------| -| `yoast/phpunit-polyfills` | PHPUnit compatibility | -| `squizlabs/php_codesniffer` | Code style checking | -| `wp-coding-standards/wpcs` | WordPress standards | -| `phpcompatibility/php-compatibility` | PHP version checks | -| `phpstan/phpstan` | Static type analysis | -| `nunomaduro/phpinsights` | Code quality insights | - -### JavaScript (npm) - -| Package | Purpose | -|---------|---------| -| `@bsf/force-ui` | BSF internal UI component library | -| `@wordpress/scripts` | Build tooling | -| `@wordpress/api-fetch` | REST API client | -| `@tanstack/react-query` | Data fetching/caching | -| `react-router-dom` | Client-side routing | -| `tailwindcss` | Utility-first CSS | -| `@playwright/test` | E2E testing | -| `@wordpress/env` | Docker test environment | - -## Related Pages - -- [Architecture Overview](Architecture-Overview) -- Plugin structure and bootstrap -- [Testing Guide](Testing-Guide) -- Test setup and execution -- [Contributing Guide](Contributing-Guide) -- Coding standards and workflow -- [Frontend Assets](Frontend-Assets) -- Asset pipeline details diff --git a/docs/wiki/Form-Fields-Architecture.md b/docs/wiki/Form-Fields-Architecture.md deleted file mode 100644 index 285f4793c..000000000 --- a/docs/wiki/Form-Fields-Architecture.md +++ /dev/null @@ -1,137 +0,0 @@ -# Form Fields Architecture - -SureForms uses a layered architecture for form fields: Gutenberg blocks define the editor experience, field markup classes generate the frontend HTML, and the validation system ensures data integrity on submission. - -## Field Type Hierarchy - -``` -Fields\Base (inc/fields/base.php) - |-- Input_Markup (text, hidden) - |-- Email_Markup (email with validation) - |-- Textarea_Markup (multi-line text) - |-- Number_Markup (numeric with min/max) - |-- Phone_Markup (with country selector) - |-- URL_Markup (URL with validation) - |-- Dropdown_Markup (select options) - |-- Checkbox_Markup (single/multiple) - |-- Multichoice_Markup (radio/checkbox groups) - |-- Address_Markup (composite address field) - |-- GDPR_Markup (consent checkbox) - |-- Payment_Markup (Stripe payment field) - |-- Inlinebutton_Markup (inline buttons) -``` - -## Base Field Class - -`inc/fields/base.php` provides the foundation: - -- Common HTML wrapper generation -- Label rendering with required indicator -- Help text / description output -- Error message container -- CSS class assembly with `srfm-` prefix -- Conditional logic attribute output -- Accessibility attributes (aria-label, aria-required) - -## Markup Generation Pattern - -Each field markup class follows a consistent pattern: - -1. Receive block attributes from the Gutenberg block -2. Process and sanitize attribute values -3. Generate field-specific HTML using WordPress escaping functions -4. Wrap in the standard field container with label and error placeholder -5. Return the complete HTML string - -## Available Field Types - -### Input (input-markup.php) -Standard text input supporting `text`, `hidden`, and other HTML5 input types. Supports placeholder, default value, min/max length. - -### Email (email-markup.php) -Email input with built-in email format validation. Supports confirmation email field option. - -### Textarea (textarea-markup.php) -Multi-line text area with configurable rows and max length. - -### Number (number-markup.php) -Numeric input with min/max value constraints, step size, and format validation. - -### Phone (phone-markup.php) -Phone number input integrated with `intl-tel-input` library for country code selection. Uses `countries.json` for country data. - -### URL (url-markup.php) -URL input with format validation. - -### Dropdown (dropdown-markup.php) -Select dropdown with configurable options. Supports default selection and placeholder text. - -### Checkbox (checkbox-markup.php) -Single or multiple checkbox inputs with label positioning options. - -### Multi Choice (multichoice-markup.php) -Radio button or checkbox groups for multiple choice questions. Supports image choices and custom layouts. - -### Address (address-markup.php) -Composite field with subfields: street address, city, state/province, zip/postal code, and country. Each subfield is independently configurable. - -### GDPR (gdpr-markup.php) -GDPR consent checkbox with customizable compliance text. Integrates with form-level compliance settings. - -### Payment (payment-markup.php) -Payment collection field for Stripe integration. Renders the payment form elements and connects to the payment processing flow. - -## Validation System - -### Server-Side Validation (field-validation.php) - -`inc/field-validation.php` handles validation during form submission: - -- **Required field check** -- Ensures required fields have values -- **Type validation** -- Validates data types (email format, URL format, number ranges) -- **Unique value check** -- Optional unique validation against existing entries -- **Custom validation** -- Extensible via filters - -Common error messages are defined in `Helper::get_common_err_msg()`: -- `required`: "This field is required." -- `unique`: "Value needs to be unique." - -### Client-Side Validation - -Frontend JavaScript provides instant validation feedback before submission, matching server-side rules. - -## Field Rendering Pipeline - -``` -1. Block Editor (Gutenberg) - -> Block attributes saved in post_content - -2. Frontend Request - -> Generate_Form_Markup::get_form_markup() - -> Parses post_content blocks - -> For each block, calls its render callback - -3. Block Render Callback - -> Block class (inc/blocks/{type}/block.php) - -> Instantiates field markup class - -> Passes block attributes - -4. Field Markup Generation - -> Field markup class (inc/fields/{type}-markup.php) - -> Base class wraps with container, label, error placeholder - -> Field-specific HTML generated - -> Returns escaped HTML string - -5. Form Assembly - -> All field HTML concatenated inside <form> wrapper - -> Submit button appended - -> Nonce field added - -> Final form HTML returned -``` - -## Related Pages - -- [Gutenberg Blocks](Gutenberg-Blocks) -- Block registration and editor components -- [Form Submission Flow](Form-Submission-Flow) -- How field data is validated and processed -- [WordPress Hooks Reference](WordPress-Hooks-Reference) -- Field-related filters -- [Payment Integration](Payment-Integration) -- Payment field details diff --git a/docs/wiki/Form-Submission-Flow.md b/docs/wiki/Form-Submission-Flow.md deleted file mode 100644 index 81a9e3806..000000000 --- a/docs/wiki/Form-Submission-Flow.md +++ /dev/null @@ -1,191 +0,0 @@ -# Form Submission Flow - -This page documents the end-to-end form submission process from frontend to entry storage. - -## Flow Diagram - -``` -+------------------+ +-------------------+ +------------------+ -| User fills form |---->| JavaScript fetch() |---->| REST API | -| in browser | | POST /submit-form | | Form_Submit | -+------------------+ +-------------------+ +--------+---------+ - | - +--------------------------------+ - | - +----------v-----------+ - | Permission Check | - | - X-WP-Submit-Nonce | - | - Form data exists | - +----------+-----------+ - | - +----------v-----------+ - | Form Restrictions | - | - Max entries check | - | - Date scheduling | - | - Login required | - +----------+-----------+ - | - +----------v-----------+ - | Field Validation | - | - Required fields | - | - Type validation | - | - Unique values | - +----------+-----------+ - | - +----------v-----------+ - | Security Checks | - | - CAPTCHA verify | - | - Honeypot check | - +----------+-----------+ - | - +----------v-----------+ - | Data Processing | - | - Sanitize fields | - | - Smart tag resolve | - | - Collect metadata | - +----------+-----------+ - | - +----------------+----------------+ - | | -+--------v--------+ +--------v--------+ -| Email Notify | | Entry Storage | -| Email_Template | | wp_srfm_entries | -+-----------------+ +--------+--------+ - | - +--------v--------+ - | Payment Process | - | (if applicable) | - | wp_srfm_payments| - +--------+--------+ - | - +--------v--------+ - | Confirmation | - | Response | - +-----------------+ -``` - -## Step-by-Step Process - -### 1. Frontend Submission - -The form is submitted via JavaScript `fetch()` to `POST /wp-json/sureforms/v1/submit-form` with: - -- Form field data as POST body -- `X-WP-Submit-Nonce` header for security (does not require logged-in user) -- Form ID to identify which form was submitted - -Nonces can be refreshed via `GET /refresh-nonces` (public, no auth required). - -### 2. Permission Check - -`Form_Submit::submit_form_permissions_check()`: - -- Verifies the `X-WP-Submit-Nonce` header -- Validates that form data and form ID are present -- Returns `WP_Error` on failure - -### 3. Form Restrictions - -`Form_Restriction` class checks: - -- **Maximum entries** -- Has the form reached its submission limit? -- **Date scheduling** -- Is the form within its active date range? -- **Login required** -- Does the form require a logged-in user? -- **Entry caps** -- Per-user submission limits - -### 4. Field Validation - -`Field_Validation` (`inc/field-validation.php`): - -- **Required fields** -- Ensures all required fields have non-empty values -- **Type validation** -- Email format, URL format, number ranges, phone format -- **Unique values** -- Checks existing entries for uniqueness if configured -- Returns validation errors that prevent submission - -### 5. Security Verification - -- **CAPTCHA** -- Validates reCAPTCHA v2/v3, hCaptcha, or Cloudflare Turnstile token -- **Honeypot** -- Checks the hidden honeypot field is empty (bots fill it) - -### 6. Data Processing - -- `apply_filters('srfm_form_submit_data', $data, $form_id)` -- allows modification -- Sanitizes each field value -- Resolves smart tags for email templates -- Collects submission metadata (IP, browser via Browser class, device info) -- `do_action('srfm_before_submission', $data, $form_id)` - -### 7. Email Notifications - -`Email_Template` sends configured email notifications: - -- Processes smart tags in subject and body -- Sends to configured recipients -- Handles CC/BCC -- See [Email Notifications](Email-Notifications) for details - -### 8. Entry Storage - -Checks GDPR compliance (`do_not_store_entries` setting). If storage is allowed: - -```php -Entries::add([ - 'form_id' => $form_id, - 'user_id' => get_current_user_id(), - 'form_data' => $sanitized_data, // JSON-encoded - 'submission_info' => $metadata, // JSON-encoded - 'logs' => $activity_logs, // JSON-encoded - 'status' => 'unread', - 'type' => $form_type, // 'standard', 'quiz', etc. -]); -``` - -### 9. Payment Processing - -If the form includes a payment block: - -- Stripe payment is processed -- Payment record created in `wp_srfm_payments` -- Payment ID linked to the entry -- See [Payment Integration](Payment-Integration) for details - -### 10. Post-Submission - -- `do_action('srfm_form_submit', $entry_id, $form_id, $form_data)` -- `do_action('srfm_after_submission_process', $entry_id, $form_id)` -- Returns confirmation response: - - **Message** -- Display a success message - - **Redirect** -- Redirect to a specified URL - -## Form Confirmation Types - -Configured via `_srfm_form_confirmation` post meta: - -| Type | Behavior | -|------|----------| -| Message | Display a success message on the same page | -| Redirect | Redirect to a specified URL after submission | - -Confirmation parameters are filterable via `srfm_form_confirmation_params`. - -## Error Handling - -Errors at any stage return a JSON error response to the frontend: - -```json -{ - "success": false, - "data": "Validation error message" -} -``` - -The frontend JavaScript displays errors inline next to the relevant fields. - -## Related Pages - -- [REST API Reference](REST-API-Reference) -- Submit endpoint details -- [Database Schema](Database-Schema) -- Entry and payment table structure -- [Email Notifications](Email-Notifications) -- Email dispatch details -- [Payment Integration](Payment-Integration) -- Payment processing -- [WordPress Hooks Reference](WordPress-Hooks-Reference) -- Submission hooks -- [Form Fields Architecture](Form-Fields-Architecture) -- Field validation diff --git a/docs/wiki/Frontend-Assets.md b/docs/wiki/Frontend-Assets.md deleted file mode 100644 index 99b4cca91..000000000 --- a/docs/wiki/Frontend-Assets.md +++ /dev/null @@ -1,122 +0,0 @@ -# Frontend Assets - -SureForms manages assets across three contexts: frontend (form display), admin (dashboard), and block editor. - -## Asset Loading Strategy - -### Frontend (Form Display) - -`inc/frontend-assets.php` (`Frontend_Assets` class) handles loading CSS/JS on pages containing SureForms forms: - -- Detects form blocks in page content -- Enqueues only necessary field-specific CSS/JS -- Loads Stripe JS SDK only when payment fields are present -- Enqueues `intl-tel-input` only when phone fields exist - -### Admin Dashboard - -Admin assets are enqueued only on SureForms admin pages: - -- React app bundle from `assets/build/` -- Tailwind CSS base styles from `src/admin/tw-base.scss` -- Localized data via `wp_localize_script()` - -### Block Editor - -`inc/gutenberg-hooks.php` (`Gutenberg_Hooks` class) loads editor assets: - -- Block editor JS/CSS from `assets/build/` -- Editor-specific stylesheets -- Block preview styles - -## Build Pipeline - -### wp-scripts (Webpack) - -Primary JS build tool. Configuration extends `@wordpress/scripts` defaults: - -```bash -npm start # Development with hot reload -npm run build:script # Production build -``` - -**Entry Points:** -- `src/blocks/blocks.js` -- Gutenberg block registration -- `src/admin/editor-scripts.js` -- Admin dashboard React app -- Additional entries per block type - -**Output:** `assets/build/` directory - -**Webpack Features:** -- Code splitting per entry point -- WordPress dependency extraction (`@wordpress/*` packages) -- Source maps in development -- Asset hashing for cache busting - -### Grunt (SASS / Minification) - -```bash -npm run build:sass # Compile SASS only -npm run build # Full build (JS + SASS + minify) -``` - -The `Gruntfile.js` tasks include: - -| Task | Description | -|------|-------------| -| `sass` | Compile SASS files from `sass/` to `assets/css/` | -| `postcss` | Run PostCSS with Autoprefixer | -| `cssmin` | Minify CSS to `assets/css/minified/` | -| `uglify` | Minify JS to `assets/js/minified/` | -| `copy` | Copy assets to distribution directories | - -### SASS Directory Structure - -``` -sass/ -|-- frontend block styles -|-- form field styles -|-- layout and grid styles -``` - -Compiled output: `assets/css/` (unminified) and `assets/css/minified/` - -### Tailwind CSS - -Used exclusively for admin dashboard pages: - -**Configuration (`tailwind.config.js`):** -- Content paths: `src/admin/**/*.{js,jsx}` -- Plugins: `@tailwindcss/forms` -- Custom theme extensions for Force UI compatibility -- `tailwind-merge` used for dynamic class composition - -**Base styles:** `src/admin/tw-base.scss` - -## CSS Naming Conventions - -| Context | Prefix | Example | -|---------|--------|---------| -| Frontend form styles | `srfm-` | `srfm-input-field`, `srfm-form-container` | -| Admin dashboard | Tailwind utilities | `flex items-center gap-2` | -| Block editor | `srfm-editor-` | `srfm-editor-preview` | - -## Asset Versioning - -All enqueued assets use `SRFM_VER` (currently `2.5.1`) for cache busting: - -```php -wp_enqueue_style( - 'srfm-frontend', - SRFM_URL . 'assets/css/minified/frontend.min.css', - [], - SRFM_VER -); -``` - -## Related Pages - -- [Admin Dashboard](Admin-Dashboard) -- React admin asset details -- [Gutenberg Blocks](Gutenberg-Blocks) -- Block editor assets -- [Environment Configuration](Environment-Configuration) -- Build tool setup -- [Contributing Guide](Contributing-Guide) -- CSS/JS conventions diff --git a/docs/wiki/Getting-Started.md b/docs/wiki/Getting-Started.md deleted file mode 100644 index a0f2ea908..000000000 --- a/docs/wiki/Getting-Started.md +++ /dev/null @@ -1,149 +0,0 @@ -# Getting Started - -This guide walks you through setting up a SureForms development environment from scratch. - -## Prerequisites - -| Tool | Version | Notes | -|------|---------|-------| -| PHP | 7.4+ | Required for plugin runtime | -| WordPress | 6.4+ | Required for block editor features | -| Node.js | 24.16.0 | Managed via Volta (auto-switches) | -| Composer | 2.x | PHP dependency manager | -| Git | 2.x | Version control | -| Docker | Latest | Optional, for wp-env test environment | - -### Installing Volta (Recommended) - -[Volta](https://volta.sh/) ensures you use the correct Node.js version automatically: - -```bash -curl https://get.volta.sh | bash -``` - -The `package.json` pins Node 24.16.0 via Volta config -- it activates automatically when you enter the project directory. - -## Initial Setup - -### 1. Clone the Repository - -```bash -git clone https://github.com/brainstormforce/sureforms.git -cd sureforms -``` - -### 2. Install Dependencies - -```bash -composer install # PHP dependencies -npm install # Node dependencies -``` - -### 3. Build the Plugin - -```bash -npm run build # Full production build (JS + SASS + minify) -``` - -This runs three steps: -1. `wp-scripts build` -- Bundles JS/React from `src/` to `build/` -2. SASS compilation -- Compiles `sass/` to `assets/css/` -3. `grunt minify` -- Minifies CSS and JS to `assets/css/minified/` and `assets/js/minified/` - -### 4. Start Development Server - -```bash -npm start # wp-scripts dev server with hot reload -``` - -This watches `src/` for changes and rebuilds JS automatically. For SASS changes, run `npm run build:sass` separately. - -## WordPress Environment - -### Option A: Local WordPress Installation - -1. Set up a local WordPress site (e.g., using Local, MAMP, or Docker) -2. Symlink or copy the plugin into `wp-content/plugins/sureforms/` -3. Activate the plugin from the WordPress admin - -### Option B: wp-env (Docker-Based) - -The project includes a `.wp-env.json` configuration for a Docker-based WordPress environment: - -```bash -npm run play:up # Start WordPress + MySQL containers -``` - -This provides: -- WordPress at `http://localhost:8888` (admin: `admin` / `password`) -- Test WordPress at `http://localhost:8889` -- Plugin auto-mounted and activated -- Consistent environment across developers - -Additional commands: -```bash -npm run play:stop # Stop containers -npm run env:clean # Reset all data -``` - -## Verifying Your Setup - -### Run Linters - -```bash -vendor/bin/phpcs # PHP CodeSniffer -npm run lint-js # ESLint -npm run lint-css # Stylelint -npm run pretty # Prettier -``` - -### Run Tests - -```bash -vendor/bin/phpunit # PHP unit tests -npm run test:unit # JavaScript unit tests -``` - -### Build Check - -```bash -npm run build # Should complete without errors -``` - -## Project Structure Overview - -``` -sureforms/ -├── sureforms.php # Plugin entry point -├── plugin-loader.php # Autoloader and bootstrap -├── inc/ # PHP classes (core logic) -├── src/ # JS/React source (compiled by wp-scripts) -│ ├── admin/ # Admin dashboard React app -│ ├── blocks/ # Gutenberg block components -│ ├── components/ # Shared React components -│ └── store/ # WordPress data store -├── sass/ # SASS source files -├── assets/ # Compiled assets (CSS, JS, images) -├── templates/ # PHP templates (BladeOne) -├── tests/ # Test files -├── modules/ # Feature modules -└── admin/ # Admin PHP + assets -``` - -See [Architecture Overview](Architecture-Overview) for a detailed breakdown. - -## Key Concepts - -- **Custom Post Type**: Forms are stored as `sureforms_form` posts with block content -- **Custom Database Tables**: Entries in `wp_srfm_entries`, payments in `wp_srfm_payments` -- **REST API**: All data operations use the `sureforms/v1` REST namespace -- **Block Editor**: Form fields are Gutenberg blocks registered via `block.json` -- **Admin SPA**: The dashboard is a React single-page application using Force UI components - -## Next Steps - -- [Architecture Overview](Architecture-Overview) -- Understand the codebase -- [Contributing Guide](Contributing-Guide) -- Development workflow and standards -- [Gutenberg Blocks](Gutenberg-Blocks) -- How form blocks work -- [REST API Reference](REST-API-Reference) -- Available API endpoints -- [Testing Guide](Testing-Guide) -- Running and writing tests diff --git a/docs/wiki/Gutenberg-Blocks.md b/docs/wiki/Gutenberg-Blocks.md deleted file mode 100644 index ed38cd9b3..000000000 --- a/docs/wiki/Gutenberg-Blocks.md +++ /dev/null @@ -1,129 +0,0 @@ -# Gutenberg Blocks - -SureForms provides 14+ Gutenberg block types for building forms in the WordPress block editor. - -## Block Types - -### Field Blocks - -| Block | Slug | Description | -|-------|------|-------------| -| Input | `srfm/input` | Text input (text, hidden, etc.) | -| Email | `srfm/email` | Email address input with validation | -| Textarea | `srfm/textarea` | Multi-line text area | -| Number | `srfm/number` | Numeric input with min/max | -| Phone | `srfm/phone` | Phone number with country selector (intl-tel-input) | -| URL | `srfm/url` | URL input with validation | -| Dropdown | `srfm/dropdown` | Select dropdown with options | -| Checkbox | `srfm/checkbox` | Single/multiple checkboxes | -| Multi Choice | `srfm/multichoice` | Radio/checkbox group | -| Address | `srfm/address` | Address field with subfields (street, city, state, zip, country) | -| GDPR | `srfm/gdpr` | GDPR consent checkbox | -| Payment | `srfm/payment` | Payment collection (Stripe integration) | -| Inline Button | `srfm/inlinebutton` | Inline form button | - -### Container Block - -| Block | Slug | Description | -|-------|------|-------------| -| SForm | `srfm/sform` | Main form wrapper block (required container for all field blocks) | - -## Block Registration - -### Server-Side (PHP) - -Blocks are registered in `inc/blocks/register.php` via the `Blocks\Register` class, initialized on the `init` hook: - -```php -// inc/blocks/register.php -register_block_type_from_metadata( - SRFM_DIR . 'inc/blocks/{block-type}/', - [ - 'render_callback' => [ $block_instance, 'render' ], - ] -); -``` - -Each block type has: -- `block.json` -- Block metadata, attributes, and category -- `block.php` -- Server-side rendering class extending `Blocks\Base` - -### Client-Side (JavaScript) - -Block registration happens in `src/blocks/blocks.js`: - -```javascript -// src/blocks/blocks.js -import { registerBlockType } from '@wordpress/blocks'; -// Block imports and registrations... -``` - -The `src/blocks/register-block.js` utility handles individual block registration. - -## Block Architecture - -### Base Class: `Blocks\Base` - -All block PHP classes extend `SRFM\Inc\Blocks\Base`, which provides: - -- `render()` -- Main render callback invoked by WordPress -- Access to block attributes from `block.json` -- Common rendering logic shared across field types -- Integration with field markup classes - -### Block to Field Mapping - -Each block delegates HTML generation to its corresponding field markup class in `inc/fields/`: - -``` -Block (inc/blocks/input/block.php) - -> Field Markup (inc/fields/input-markup.php) - -> Base Field (inc/fields/base.php) - -> HTML output -``` - -### block.json Structure - -Each block directory contains a `block.json` file defining: - -```json -{ - "apiVersion": 3, - "name": "srfm/input", - "title": "Input", - "category": "sureforms", - "attributes": { - "label": { "type": "string", "default": "Input" }, - "required": { "type": "boolean", "default": false }, - "placeholder": { "type": "string", "default": "" } - }, - "supports": { "html": false } -} -``` - -## Adding a New Block Type - -1. **Create block directory:** `inc/blocks/{new-type}/` -2. **Add `block.json`** with attributes, name, and category -3. **Create `block.php`** extending `Blocks\Base` with a `render()` method -4. **Create field markup:** `inc/fields/{new-type}-markup.php` extending `Fields\Base` -5. **Register in `Blocks\Register`** -- add to the blocks array -6. **Create editor component:** `src/blocks/{new-type}/` with `edit.js` and `index.js` -7. **Add to `src/blocks/blocks.js`** -- import and register the new block - -## The sform Container Block - -The `srfm/sform` block is the required wrapper for all form fields. It: - -- Renders the `<form>` HTML element -- Handles form-level settings (styling, confirmation, CAPTCHA) -- Manages submission nonce generation -- Controls form layout and submit button -- Integrates with frontend JavaScript for submission handling - -## Related Pages - -- [Form Fields Architecture](Form-Fields-Architecture) -- Field markup and validation -- [Block Editor Controls](Block-Editor-Controls) -- Custom inspector controls -- [Architecture Overview](Architecture-Overview) -- Block registration in bootstrap -- [Frontend Assets](Frontend-Assets) -- Block editor asset loading diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md deleted file mode 100644 index 365d8af63..000000000 --- a/docs/wiki/Home.md +++ /dev/null @@ -1,58 +0,0 @@ -# SureForms Wiki - -Welcome to the SureForms developer wiki. This documentation covers the architecture, APIs, development workflows, and internals of the SureForms WordPress form builder plugin. - -**Version:** 2.5.1 | **WordPress:** 6.4+ | **PHP:** 7.4+ | **Node:** 24.16.0 - -## Quick Links - -- [Getting Started](Getting-Started) -- Set up your development environment -- [Architecture Overview](Architecture-Overview) -- Understand the codebase structure -- [Contributing Guide](Contributing-Guide) -- How to contribute - -## Architecture & Core - -| Page | Description | -|------|-------------| -| [Architecture Overview](Architecture-Overview) | Plugin bootstrap, namespaces, directory layout, design patterns | -| [Database Schema](Database-Schema) | Custom tables (`wp_srfm_entries`, `wp_srfm_payments`), post meta keys | -| [Environment Configuration](Environment-Configuration) | Constants, build tools, linting, development setup | -| [Form Submission Flow](Form-Submission-Flow) | End-to-end submission pipeline from frontend to storage | - -## WordPress / Backend - -| Page | Description | -|------|-------------| -| [Gutenberg Blocks](Gutenberg-Blocks) | Block types, registration, `block.json` structure | -| [Form Fields Architecture](Form-Fields-Architecture) | Field type hierarchy, validation, rendering pipeline | -| [WordPress Hooks Reference](WordPress-Hooks-Reference) | Custom actions, filters, and execution order | -| [Payment Integration](Payment-Integration) | Stripe setup, payment flow, webhooks, refunds | -| [Email Notifications](Email-Notifications) | Email templates, smart tags, notification settings | -| [AI Form Builder](AI-Form-Builder) | AI-powered form generation process | -| [Data Export & Import](Data-Export-Import) | Form/entry export, import, duplication | - -## Frontend / React - -| Page | Description | -|------|-------------| -| [Admin Dashboard](Admin-Dashboard) | React SPA architecture, routing, data fetching | -| [State Management](State-Management) | WordPress data store, actions, selectors | -| [Frontend Assets](Frontend-Assets) | Asset loading, build pipeline, SASS, Tailwind | -| [Block Editor Controls](Block-Editor-Controls) | Custom inspector controls, CSS generation, icons | - -## API - -| Page | Description | -|------|-------------| -| [REST API Reference](REST-API-Reference) | All endpoints with methods, parameters, authentication | - -## Development Workflow - -| Page | Description | -|------|-------------| -| [Getting Started](Getting-Started) | Prerequisites, installation, first build | -| [Contributing Guide](Contributing-Guide) | Git workflow, coding standards, PR process | -| [Testing Guide](Testing-Guide) | PHPUnit, Playwright, Jest setup and execution | -| [Deployment Guide](Deployment-Guide) | CI/CD pipelines, release process, version bumping | -| [Troubleshooting & FAQ](Troubleshooting-FAQ) | Common issues and debugging tips | -| [Changelog](Changelog) | Recent version history | diff --git a/docs/wiki/Payment-Integration.md b/docs/wiki/Payment-Integration.md deleted file mode 100644 index 28d985e6e..000000000 --- a/docs/wiki/Payment-Integration.md +++ /dev/null @@ -1,127 +0,0 @@ -# Payment Integration - -SureForms supports Stripe payment processing with one-time payments and recurring subscriptions. - -## Architecture Overview - -``` -inc/payments/ -|-- payments.php # Main payments orchestrator -|-- front-end.php # Frontend payment handling -|-- payment-helper.php # Shared payment utilities -|-- admin/ -| |-- admin-handler.php # Admin payment management UI -|-- stripe/ - |-- payments-settings.php # Stripe settings + REST routes - |-- stripe-helper.php # Stripe API utilities - |-- stripe-webhook.php # Webhook event handler - |-- admin-stripe-handler.php # Admin Stripe config -``` - -## Stripe Setup - -### Configuration - -Stripe settings are managed via the admin settings page and stored as WordPress options: - -1. Navigate to SureForms > Settings > Payments -2. Connect your Stripe account via OAuth flow -3. Configure test/live mode -4. Set default currency - -The `Payments_Settings` class registers REST routes for settings management and handles the Stripe OAuth callback via `admin_init`. - -### OAuth Flow - -1. Admin clicks "Connect Stripe" in settings -2. `intercept_stripe_callback()` on `admin_init` handles the OAuth redirect -3. Stripe credentials are securely stored in WordPress options - -## Payment Flow - -``` -1. FORM DISPLAY - - Payment block renders Stripe Elements - - Frontend_Assets enqueues Stripe JS SDK - - Payment form elements injected into the form - -2. FORM SUBMISSION - - User fills form + enters payment details - - Frontend JavaScript creates Stripe PaymentIntent - - Form data + payment token submitted to /submit-form - -3. SERVER PROCESSING - - Form_Submit validates form data - - Payment processing triggered - - Stripe API called to confirm payment - - Payment record created in wp_srfm_payments table - - Entry created in wp_srfm_entries table - - Payment ID linked to entry - -4. WEBHOOK HANDLING - - Stripe sends webhook events to /wp-json endpoint - - Stripe_Webhook validates signature - - Payment status updated in database - - Subscription events handled (renewal, cancellation, etc.) -``` - -## Payment Database Schema - -Payments are stored in the `wp_srfm_payments` custom table. See [Database Schema](Database-Schema) for full column definitions. - -### Payment Types - -| Type | Description | -|------|-------------| -| `payment` | One-time payment | -| `subscription` | Recurring subscription record | -| `renewal` | Subscription renewal payment | - -### Payment Statuses - -`pending`, `succeeded`, `failed`, `canceled`, `requires_action`, `requires_payment_method`, `processing`, `refunded`, `partially_refunded` - -### Subscription Statuses - -`active`, `canceled`, `past_due`, `unpaid`, `trialing`, `incomplete`, `incomplete_expired`, `paused` - -## Webhook Handling - -The `Stripe_Webhook` class (`inc/payments/stripe/stripe-webhook.php`) processes Stripe webhook events: - -- Validates webhook signature using Stripe signing secret -- Handles payment status updates (succeeded, failed, etc.) -- Processes subscription lifecycle events (renewal, cancellation) -- Creates renewal payment records for subscription billing cycles -- Updates payment and subscription statuses in the database - -## Refund Management - -The `Payments` table class provides refund tracking: - -- `add_refund_to_payment_data()` -- Record refund details in payment_data JSON -- `add_refund_amount()` -- Increment the refunded_amount column -- `get_refundable_amount()` -- Calculate remaining refundable balance -- `is_fully_refunded()` / `is_partially_refunded()` -- Status checks - -## Supported Currencies - -USD, EUR, GBP, JPY, CAD, AUD, CHF, CNY, SEK, NZD, MXN, SGD, HKD, NOK, TRY, RUB, INR, BRL, ZAR, KRW - -## Payment Modes - -| Mode | Description | -|------|-------------| -| `test` | Stripe test mode (test API keys) | -| `live` | Stripe live mode (production) | - -## Admin Payment Management - -The `Admin_Handler` class provides the admin interface for viewing and managing payments. Payment IDs in entry views are rendered as clickable links via the `srfm_entry_value` filter. - -## Related Pages - -- [Database Schema](Database-Schema) -- Payment table columns and relationships -- [Form Submission Flow](Form-Submission-Flow) -- Payment processing in submission pipeline -- [REST API Reference](REST-API-Reference) -- Payment-related endpoints -- [Gutenberg Blocks](Gutenberg-Blocks) -- Payment block type diff --git a/docs/wiki/REST-API-Reference.md b/docs/wiki/REST-API-Reference.md deleted file mode 100644 index d366470e5..000000000 --- a/docs/wiki/REST-API-Reference.md +++ /dev/null @@ -1,114 +0,0 @@ -# REST API Reference - -All endpoints are registered under the namespace `sureforms/v1` and accessible at `/wp-json/sureforms/v1/`. - -## Authentication - -### Admin Endpoints -All admin endpoints require the `manage_options` capability. Authentication is via WordPress REST API nonce (`X-WP-Nonce` header) or cookie-based auth. - -Permission check: `Helper::get_items_permissions_check()` verifies `current_user_can('manage_options')`. - -### Public Endpoints -The form submission endpoint uses a custom nonce (`X-WP-Submit-Nonce` header) that does not require a logged-in user. - -## Endpoints - -### AI Form Builder - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/generate-form` | Generate a form using AI | -| POST | `/map-fields` | Map AI response to SureForms Gutenberg blocks | -| GET | `/initiate-auth` | Get auth URL for AI billing portal | -| POST | `/handle-access-key` | Decrypt and save AI access key | - -### Dashboard - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | `/entries-chart-data` | Get entries chart data for analytics | -| GET | `/form-data` | Get all forms data for dashboard | -| GET | `/plugin-status` | Check integration plugin install status | - -### Onboarding - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | `/onboarding/set-status` | Mark onboarding as complete | -| GET | `/onboarding/get-status` | Get current onboarding status | - -### Entries - -| Method | Endpoint | Description | Parameters | -|--------|----------|-------------|------------| -| GET | `/entries/list` | Paginated entries listing | `form_id`, `status`, `search`, `date_from`, `date_to`, `orderby`, `order`, `per_page`, `page` | -| POST | `/entries/read-status` | Bulk mark entries read/unread | `entry_ids` (required), `action` (required: read/unread) | -| POST | `/entries/trash` | Bulk trash/restore entries | `entry_ids` (required), `action` (required: trash/restore) | -| POST | `/entries/delete` | Permanently delete entries | `entry_ids` (required) | -| POST | `/entries/export` | Export entries to CSV/ZIP | `entry_ids`, `form_id`, `status`, `search`, `date_from`, `date_to` | -| GET | `/entry/{id}/details` | Single entry with form data | `id` (required) | -| GET | `/entry/{id}/logs` | Entry activity logs | `id` (required), `page`, `per_page` | - -### Forms - -| Method | Endpoint | Description | Parameters | -|--------|----------|-------------|------------| -| GET | `/forms` | Paginated forms listing | `page`, `per_page`, `search`, `status`, `orderby`, `order`, `date_from`, `date_to` | -| POST | `/forms/export` | Export forms as JSON | `form_ids` (required) | -| POST | `/forms/import` | Import forms from JSON | File upload | -| POST | `/forms/manage` | Manage form lifecycle | `form_ids` (required), `action` (trash/restore/delete) | -| POST | `/forms/duplicate` | Duplicate a form | `form_id` (required) | - -### Form Submission (Public) - -| Method | Endpoint | Auth | Description | -|--------|----------|------|-------------| -| POST | `/submit-form` | Custom nonce | Public form submission | -| GET | `/refresh-nonces` | None | Refresh frontend nonces | - -## Extending the API - -Endpoints are extensible via the `srfm_rest_api_endpoints` filter: - -```php -add_filter( 'srfm_rest_api_endpoints', function( $endpoints ) { - $endpoints['custom/endpoint'] = [ - 'methods' => 'GET', - 'callback' => [ $this, 'handle_custom' ], - 'permission_callback' => [ Helper::class, 'get_items_permissions_check' ], - ]; - return $endpoints; -} ); -``` - -## Error Responses - -Errors are returned via `wp_send_json_error()`: - -```json -{ - "success": false, - "data": "Error message string" -} -``` - -## Pagination - -List endpoints support pagination with consistent parameters: - -| Parameter | Default | Description | -|-----------|---------|-------------| -| `page` | 1 | Current page number | -| `per_page` | 20 | Items per page | -| `orderby` | `created_at` | Sort column | -| `order` | `DESC` | Sort direction (ASC/DESC) | - -Response includes total counts for pagination UI. - -## Related Pages - -- [Architecture Overview](Architecture-Overview) -- API registration flow -- [Form Submission Flow](Form-Submission-Flow) -- Submit endpoint details -- [Data Export Import](Data-Export-Import) -- Export/import endpoints -- [Payment Integration](Payment-Integration) -- Payment API endpoints diff --git a/docs/wiki/State-Management.md b/docs/wiki/State-Management.md deleted file mode 100644 index 6cb4b072a..000000000 --- a/docs/wiki/State-Management.md +++ /dev/null @@ -1,109 +0,0 @@ -# State Management - -SureForms uses the `@wordpress/data` package to create a Redux-like data store for managing application state in the block editor. - -## Store Structure - -Located in `src/store/`: - -``` -src/store/ -|-- store.js # Store registration -|-- reducer.js # State reducers -|-- actions.js # Action creators -|-- selectors.js # State selectors -|-- constants.js # Store constants -|-- setInitialState.js # Initial state configuration -``` - -## Store Registration - -The store is registered with `@wordpress/data` in `store.js`: - -```javascript -import { createReduxStore, register } from '@wordpress/data'; -import reducer from './reducer'; -import * as actions from './actions'; -import * as selectors from './selectors'; - -const store = createReduxStore('sureforms', { - reducer, - actions, - selectors, -}); - -register(store); -``` - -The store namespace is `sureforms`. - -## Initial State - -`setInitialState.js` configures the initial state from server-side localized data (`wp_localize_script`), providing: - -- Form settings and metadata -- Block defaults -- User preferences -- Plugin configuration - -## Actions - -Actions are defined in `actions.js` and dispatched to modify the store state. They follow the WordPress data store pattern: - -```javascript -// Dispatching an action -import { dispatch } from '@wordpress/data'; -dispatch('sureforms').updateFormSettings({ key: 'value' }); -``` - -## Selectors - -Selectors in `selectors.js` extract specific data from the store state: - -```javascript -// Using a selector -import { select } from '@wordpress/data'; -const settings = select('sureforms').getFormSettings(); -``` - -## Component Integration - -Components connect to the store using WordPress data hooks: - -```javascript -import { useSelect, useDispatch } from '@wordpress/data'; - -function MyComponent() { - const formData = useSelect((select) => { - return select('sureforms').getFormSettings(); - }, []); - - const { updateFormSettings } = useDispatch('sureforms'); - - return ( - <button onClick={() => updateFormSettings({ key: 'newValue' })}> - Update - </button> - ); -} -``` - -## Constants - -`constants.js` defines store-wide constants used across actions, reducers, and selectors to ensure consistency. - -## Usage Context - -The WordPress data store is primarily used in: - -- **Block editor** -- Form-level settings and block state -- **Inspector controls** -- Sidebar settings panels -- **Block attributes** -- Synchronized state between blocks - -For the admin dashboard pages, `@tanstack/react-query` is used instead for server state management. See [Admin Dashboard](Admin-Dashboard) for details. - -## Related Pages - -- [Admin Dashboard](Admin-Dashboard) -- React admin app architecture -- [Block Editor Controls](Block-Editor-Controls) -- Inspector controls using the store -- [Gutenberg Blocks](Gutenberg-Blocks) -- Block registration and attributes diff --git a/docs/wiki/Testing-Guide.md b/docs/wiki/Testing-Guide.md deleted file mode 100644 index ea129c084..000000000 --- a/docs/wiki/Testing-Guide.md +++ /dev/null @@ -1,172 +0,0 @@ -# Testing Guide - -SureForms uses three testing frameworks: PHPUnit for PHP unit tests, Playwright for end-to-end tests, and Jest for JavaScript unit tests. - -## Testing Strategy - -| Level | Framework | Location | Purpose | -|-------|-----------|----------|---------| -| Unit (PHP) | PHPUnit 9.x | `tests/unit/` | PHP class and function testing | -| Unit (JS) | Jest | Via `wp-scripts` | JavaScript utility testing | -| E2E | Playwright 1.48+ | `tests/play/` | Full browser-based workflow testing | - -## PHPUnit (PHP Unit Tests) - -### Setup - -1. Install PHP dependencies: - ```bash - composer install - ``` - -2. WordPress test environment must be available (via wp-env or local setup) - -### Running Tests - -```bash -# Run all PHP unit tests -vendor/bin/phpunit - -# Run a specific test file -vendor/bin/phpunit tests/unit/test-specific.php - -# Run tests with verbose output -vendor/bin/phpunit --verbose -``` - -### Test File Conventions - -- Location: `tests/unit/` -- File prefix: `test-` (e.g., `test-helper.php`) -- Class naming: `Test_ClassName` extending `WP_UnitTestCase` -- Method naming: `test_` prefix (e.g., `test_form_submission()`) - -### CI Configuration - -PHPUnit runs in GitHub Actions (`.github/workflows/phpunit.yml`): -- PHP: 8.2 -- WordPress: trunk -- MySQL: 5.7 -- Triggered on pull requests - -## Playwright (E2E Tests) - -### Prerequisites - -- Node.js 24.16.0 (Volta) -- Docker (for wp-env) - -### Setup - -```bash -# Install dependencies -npm install - -# Start the WordPress environment -npm run play:up - -# Build the plugin -npm run build - -# Install Playwright browsers -npx playwright install -``` - -### Running Tests - -```bash -# Run all E2E tests (headless) -npm run play:run - -# Run tests in headed mode (visible browser) -npm run play:run:interactive - -# Run a specific test file -npx playwright test tests/play/specific-test.spec.js -``` - -### Test File Conventions - -- Location: `tests/play/` -- File suffix: `.spec.js` -- Uses Playwright Test runner with `expect` assertions -- Page Object Model pattern for reusable interactions - -### CI Configuration - -Playwright runs in GitHub Actions (`.github/workflows/playwright.yml`): -- Triggered when PR is labeled with `e2e` -- Node: 18.15 -- Builds plugin and starts wp-env -- Generates HTML test report (30-day artifact retention) - -## Jest (JavaScript Unit Tests) - -### Running Tests - -```bash -npm run test:unit -``` - -Uses `@wordpress/scripts` Jest configuration with WordPress-specific transforms and module resolution. - -## Test Environment (wp-env) - -The Docker-based test environment is configured in `.wp-env.json`: - -```bash -# Start environment -npm run play:up - -# Stop environment -npm run play:stop - -# Clean all data -npm run env:clean -``` - -wp-env provides: -- WordPress installation with the plugin active -- MySQL database -- Consistent environment across developers -- Used by both Playwright E2E tests and local development - -## Writing New Tests - -### PHP Unit Test - -```php -class Test_My_Feature extends WP_UnitTestCase { - public function test_feature_works() { - // Arrange - $form_id = $this->factory->post->create([ - 'post_type' => 'sureforms_form', - ]); - - // Act - $result = some_function($form_id); - - // Assert - $this->assertEquals('expected', $result); - } -} -``` - -### Playwright E2E Test - -```javascript -const { test, expect } = require('@playwright/test'); - -test('form submission works', async ({ page }) => { - await page.goto('/form-page/'); - await page.fill('[name="email"]', 'test@example.com'); - await page.click('button[type="submit"]'); - await expect(page.locator('.success-message')).toBeVisible(); -}); -``` - -## Related Pages - -- [Environment Configuration](Environment-Configuration) -- Development setup -- [Contributing Guide](Contributing-Guide) -- Test requirements for PRs -- [Deployment Guide](Deployment-Guide) -- CI/CD test pipeline diff --git a/docs/wiki/Troubleshooting-FAQ.md b/docs/wiki/Troubleshooting-FAQ.md deleted file mode 100644 index 7afa4619a..000000000 --- a/docs/wiki/Troubleshooting-FAQ.md +++ /dev/null @@ -1,232 +0,0 @@ -# Troubleshooting & FAQ - -Common issues, debugging tips, and frequently asked questions for SureForms development. - -## Common Development Issues - -### Build Failures - -**Problem:** `npm run build` fails with errors. - -**Solutions:** -1. Ensure Node.js 24.16.0 is active (Volta manages this automatically via `package.json`): - ```bash - node -v # Should output v24.16.0 - ``` -2. Clear and reinstall dependencies: - ```bash - rm -rf node_modules - npm install - ``` -3. If SASS compilation fails, check that `sass/` source files have valid syntax -4. If Grunt minification fails, ensure Grunt CLI is available: - ```bash - npx grunt minify - ``` - -### wp-env Issues - -**Problem:** `npm run play:up` fails to start the Docker environment. - -**Solutions:** -1. Ensure Docker is installed and running -2. Clean the environment: - ```bash - npm run env:clean - ``` -3. Restart the environment: - ```bash - npm run play:stop - npm run play:up - ``` -4. If port conflicts occur, check for other services on ports 8888/8889 - -### PHPCS Errors - -**Problem:** `vendor/bin/phpcs` reports violations. - -**Solutions:** -1. Auto-fix what's possible: - ```bash - vendor/bin/phpcbf - ``` -2. Common issues: - - Missing text domain: Add `'sureforms'` to all translatable strings - - Unescaped output: Wrap output in `esc_html()`, `esc_attr()`, etc. - - Missing nonce verification: Add nonce checks for form/AJAX handlers - - Short array syntax: Use `[]` instead of `array()` (enforced by config) - -### PHPUnit Test Failures - -**Problem:** `vendor/bin/phpunit` tests fail. - -**Solutions:** -1. Ensure WordPress test environment is available (wp-env or local setup) -2. Check database connectivity for the test suite -3. Run a specific test to isolate the issue: - ```bash - vendor/bin/phpunit tests/unit/test-specific.php - ``` - -### JavaScript Lint Errors - -**Problem:** `npm run lint-js` reports errors. - -**Solutions:** -1. Auto-fix most issues: - ```bash - npm run lint-js:fix - ``` -2. Format code with Prettier: - ```bash - npm run pretty:fix - ``` -3. Common issues: - - Import ordering: WordPress dependencies should use `@wordpress/*` - - Unused variables: Remove or prefix with underscore - - Missing dependencies in `useEffect`: Add to dependency array - -## Form Submission Issues - -### Nonce Verification Fails - -**Cause:** The `X-WP-Submit-Nonce` has expired (default: 24-hour lifetime). - -**Debug:** -- Nonces can be refreshed via `GET /wp-json/sureforms/v1/refresh-nonces` -- Check that the nonce is being sent in the request header -- Caching plugins may cache the nonce -- exclude form pages from page cache - -### CAPTCHA Validation Fails - -**Cause:** CAPTCHA keys are misconfigured or the token is expired. - -**Debug:** -1. Verify CAPTCHA keys in SureForms global settings -2. Check browser console for CAPTCHA loading errors -3. Ensure the CAPTCHA provider (reCAPTCHA, hCaptcha, Turnstile) is correctly configured -4. reCAPTCHA v3 can trigger multiple times on pages with multiple forms - -### File Upload Errors - -**Debug:** -1. Check PHP `upload_max_filesize` and `post_max_size` in `php.ini` -2. Verify allowed file types in form field settings -3. Check file size against the configured maximum -4. Ensure the `wp-content/uploads/` directory is writable - -## Database Issues - -### Custom Tables Missing - -**Cause:** The `wp_srfm_entries` or `wp_srfm_payments` table was not created. - -**Debug:** -1. Deactivate and reactivate the plugin to trigger table creation -2. Check the `srfm_db_version` option in `wp_options` -3. Verify database user has `CREATE TABLE` permissions -4. Check for errors in `debug.log` during activation - -### Entry Data Not Saving - -**Debug:** -1. Check the `do_not_store_entries` form setting (GDPR compliance) -2. Verify the form submission response for error messages -3. Check `debug.log` for database insert errors -4. Ensure the entries table schema is up to date - -## REST API Issues - -### 401 Unauthorized on Admin Endpoints - -**Cause:** User is not authenticated or lacks required capabilities. - -**Debug:** -1. Admin endpoints require `manage_options` capability -2. Ensure the user is logged in with a valid session -3. Check that the REST API nonce is being sent (via `X-WP-Nonce` header) -4. WordPress cookie authentication must be active - -### 403 on Form Submission - -**Cause:** The submit nonce is invalid or form restrictions are blocking submission. - -**Debug:** -1. Check the `X-WP-Submit-Nonce` header value -2. Review form restriction settings (max entries, date scheduling, login required) -3. Check the `srfm_form_submit_permissions_check` filter - -## Performance Issues - -### Slow Admin Dashboard - -**Causes & Solutions:** -1. **Large number of entries:** Entries are paginated -- default page size is managed by REST API -2. **Unoptimized queries:** The entries table has indexes on `form_id`, `user_id`, and a composite index on `(form_id, created_at, status)` -3. **Asset loading:** Admin assets are conditionally loaded only on SureForms admin pages - -### Slow Form Rendering - -**Causes & Solutions:** -1. **Too many blocks:** Complex forms with many fields may benefit from multi-step layout -2. **External scripts:** CAPTCHA and payment scripts load conditionally based on form settings -3. **CSS generation:** Each block generates dynamic CSS -- review `generateCSS.js` for optimization - -## Debugging Tips - -### Enable WordPress Debug Mode - -Add to `wp-config.php`: -```php -define( 'WP_DEBUG', true ); -define( 'WP_DEBUG_LOG', true ); -define( 'WP_DEBUG_DISPLAY', false ); -define( 'SCRIPT_DEBUG', true ); -``` - -### Check REST API Responses - -Use the browser developer tools Network tab to inspect REST API calls: -- Filter by `sureforms/v1` to see plugin API requests -- Check response status codes and error messages - -### Inspect Form Data Store - -In the browser console on a form editor page: -```javascript -wp.data.select('starter-starter/starter-starter-forms-data').getFormSettings(); -``` - -## FAQ - -### What WordPress version is required? - -WordPress 6.4 or higher is required. - -### What PHP version is required? - -PHP 7.4 or higher. The `phpcs.xml` enforces PHP 7.4+ compatibility. - -### Can I modify bundled libraries? - -Files in `inc/lib/` are third-party libraries and should not be modified directly. If changes are needed, they should be managed upstream. - -### Where do I put new PHP classes? - -New PHP classes go in the `inc/` directory following the existing namespace structure (`SRFM\Inc\*`). The autoloader in `plugin-loader.php` handles class loading. - -### How do I add a new admin page? - -Admin pages are rendered by the React SPA in `src/admin/`. Add new routes using `react-router-dom` and register the corresponding menu items in PHP. See [Admin Dashboard](Admin-Dashboard) for details. - -### How do I add a new form field type? - -See [Form Fields Architecture](Form-Fields-Architecture) for the field type hierarchy and the process for adding new field types. - -## Related Pages - -- [Environment Configuration](Environment-Configuration) -- Development setup -- [Testing Guide](Testing-Guide) -- Running tests -- [Architecture Overview](Architecture-Overview) -- Codebase structure -- [REST API Reference](REST-API-Reference) -- API endpoints -- [Database Schema](Database-Schema) -- Table structure diff --git a/docs/wiki/Using-WPML-With-SureForms.md b/docs/wiki/Using-WPML-With-SureForms.md deleted file mode 100644 index 540b74aef..000000000 --- a/docs/wiki/Using-WPML-With-SureForms.md +++ /dev/null @@ -1,243 +0,0 @@ -# Using WPML With SureForms - -SureForms ships with native compatibility for **WPML**, the leading WordPress multilingual plugin. With WPML active, you can offer your forms in any number of languages without duplicating the form itself — one form serves every language, every submission is tagged with the visitor's language, and translators work from a single place. - -This guide walks you through everything you need to know as a site owner, content editor, or translator. - ---- - -## What you can do with WPML + SureForms - -Once both plugins are active and configured, SureForms automatically: - -- Translates **field labels, placeholders, help text, error messages** and **dropdown / multi-choice options** based on the visitor's language. -- Translates the **submit button** label. -- Translates the **success message** shown after a submission. -- Translates the **confirmation redirect content** (when "show same page" confirmation is used). -- Translates the **form-restriction notice** (e.g., "This form is closed"). -- Records the **submission language** alongside every entry, so you can see at a glance which language a lead came from. - -You keep one form. You collect entries from every language into the same list. Reports, integrations, and exports stay unified. - ---- - -## Before you start - -You will need: - -| Item | Notes | -|---|---| -| **WordPress 6.4 or higher** | SureForms minimum requirement. | -| **WPML Multilingual CMS** (4.5+) | Paid plugin from [wpml.org](https://wpml.org). | -| **WPML String Translation** add-on | Required to translate form labels, options, and messages. Bundled with most WPML licences. | -| **SureForms 2.5.1 or higher** | Native WPML support shipped in this release. | - -> **Polylang and other multilingual plugins:** SureForms is architected with a generic provider interface so other plugins can be supported in the future. WPML is the only multilingual plugin currently supported out of the box. - ---- - -## Step 1 — Install and configure WPML - -1. Install and activate the following plugins from your WordPress dashboard: - - **WPML Multilingual CMS** (`sitepress-multilingual-cms`) - - **WPML String Translation** - -2. Open **WPML → Languages** and choose at least two languages (for example, English as the default, plus German and French). - -3. Open **WPML → Settings → Translation Options** and confirm that **Posts** are set to *"Translatable — use translation"*. - -That's the only WPML setup that is required. SureForms takes care of the rest automatically. - ---- - -## Step 2 — Create your form (just once) - -Create a SureForms form exactly the way you always have: - -1. Go to **SureForms → Add New Form**. -2. Pick a template or start blank. -3. Add fields (text, email, dropdown, multi-choice, etc.) and configure their labels, placeholders, help text, options, and error messages in your default language. -4. Configure the submit button text, success message, and any other form settings. -5. Save the form. - -> **Important:** Do **not** try to duplicate the form for each language. SureForms intentionally registers the form post type as *non-translatable* in WPML. There is one canonical form post; WPML translates the strings on it. This keeps entries unified and avoids the maintenance nightmare of keeping multiple form copies in sync. - -When you save the form, SureForms automatically registers every translatable string with WPML under the `sureforms` text domain. - ---- - -## Step 3 — Translate your form strings - -1. Go to **WPML → String Translation**. -2. In the **"Select strings within domain"** dropdown at the top, choose `sureforms`. -3. You will see entries for every translatable piece of the form, grouped by form ID for easy scanning. For example, a form with ID `42` will show strings such as: - - - `form_42_submit_button` - - `form_42_confirmation_0_message` - - `form_42_notification_0_subject` - - `form_42_restriction_message` - - `form_42_block_{block-id}_label` - - `form_42_block_{block-id}_placeholder` - - `form_42_block_{block-id}_helpText` - - `form_42_block_{block-id}_errorMsg` - - `form_42_block_{block-id}_option_0_label` *(for dropdown / multi-choice options)* - -4. Click **"translations"** next to any string, enter the translated text for each language, and save. - -You can also use WPML's built-in **Translation Editor** workflow or send strings to a translation service from this screen — the standard WPML String Translation UI applies. - -> **Tip:** The per-form naming scheme (`form_{id}_...`) keeps every form's strings neatly grouped, so translators don't have to hunt across the entire site for a particular form's labels. - ---- - -## Step 4 — Display your form on translated pages - -SureForms forms are added to pages exactly the way they always have been — via the SureForms block or the `[sureforms id="..."]` shortcode. - -For the translated version of a form to render correctly, the **host page must also be translated in WPML**: - -1. Create the original page and embed your form on it. -2. In WPML, translate that page into each language. The form block / shortcode is carried over automatically. -3. Visit the translated URL (e.g., `/de/contact/`) — the form will render with all the labels, placeholders, options, and the submit button in German. - -If you instead use SureForms' **instant form** URL (`/form/{id}/`), append the language code to switch languages: - -``` -https://example.com/form/42/?lang=de -https://example.com/form/42/?lang=fr -``` - ---- - -## Step 5 — Verify everything is translating - -Open the translated form in the browser and confirm that the following are all in the target language: - -- ✅ Field labels -- ✅ Field placeholders -- ✅ Help text -- ✅ Inline error messages (e.g., "This field is required") -- ✅ Dropdown / multi-choice / checkbox option labels -- ✅ Submit button text -- ✅ Success / confirmation message after submission -- ✅ Form restriction notice (if the form is closed or capped) - -If anything appears in the original language: - -1. Check that the host page is translated in WPML. -2. Check that the specific string has a translation in **WPML → String Translation** (filter by domain `sureforms`). -3. Re-save the form once — this regenerates the string registry. - ---- - -## Step 6 — Collect entries and review them by language - -Submissions made on the German version of the page are stored against the **same form** as English submissions, with the submission language recorded on the entry row. - -1. Go to **SureForms → Entries**. -2. You will see a new **Language** column between *Date & Time* and *Actions*. -3. Each entry displays an uppercase language code: `EN`, `DE`, `FR`, etc. -4. Click the **Language** column header to sort entries by language. - -Older entries (and entries submitted on sites where WPML is not active) display `—`. - -> **Tip:** All your usual entry features — search, view details, delete, export — work as normal. Language is just an extra column for filtering and reporting. - ---- - -## Step 7 — Form restriction messages - -If you have configured form restrictions (a closing date or maximum entry count), the **restriction notice** shown to visitors is automatically translated: - -1. Open the form and enable restrictions (e.g., set a close date in the past, or set a max-entry limit). -2. Customise the restriction message in the form settings. -3. Translate `form_{id}_restriction_message` in **WPML → String Translation**. -4. Trigger the restriction (visit the form in a translated URL once it's closed) — visitors see the translated restriction notice. - ---- - -## What about email notifications? - -> **Note:** In the current release, email notifications (the message sent to your admin or to the visitor after a successful submission) are sent in the site's default language. Multilingual email notifications — where each email is composed in the visitor's submission language — are planned for a future SureForms release. - -The submission language is already recorded on the entry, so any custom integration that hooks into the SureForms submission flow can use it. - ---- - -## Graceful fallback when WPML is not active - -You can safely install and uninstall WPML at any time: - -- **WPML active**: forms translate based on the visitor's language. Entries are tagged. -- **WPML deactivated**: forms render in their default language as if WPML had never been installed. New entries record an empty language string. No errors, no broken pages. - -The plugin is designed so that the multilingual layer is completely silent when WPML is not active. - ---- - -## Troubleshooting - -**Translated strings don't appear in WPML String Translation** - -- Confirm that *WPML String Translation* is active (not just WPML core). -- Re-save your form once. The string registry runs on form save. -- Filter by domain `sureforms` in the WPML String Translation UI — strings from other plugins live in different domains. - -**Translated labels still render in the original language on `/de/...`** - -- Make sure the host page is translated in WPML and you are visiting the translated URL. -- Open WPML → String Translation, filter by `sureforms`, and confirm the specific strings actually have translations saved. -- Check that the page language switcher confirms you are on the German (or other target) version of the page. - -**The success message is in English even though I submitted in German** - -- Confirm `form_{id}_confirmation_0_message` has a German translation in WPML String Translation. -- Confirm the form is being submitted from a German page (`/de/...`), not from a query-string variant in some WPML modes. - -**Entries show `—` in the Language column** - -- Older entries submitted before WPML support shipped will not have a language stored. -- Entries created from the admin (e.g., test submissions, or imports) may not carry a language code. -- New front-end submissions on translated pages with WPML active will always carry a language code. - -**An entry's language code is wrong** - -- The visitor's language is determined by WPML based on the URL of the page they submitted from. If your WPML configuration uses query-string mode (`?lang=de`), make sure the parameter is on the page URL when the form is submitted. - ---- - -## Frequently asked questions - -**Do I need to duplicate the form for each language?** - -No. There is one canonical form post regardless of how many languages you support. WPML translates the strings on it. - -**Will entries from different languages mix in the same list?** - -Yes — by design. All entries from a given form, regardless of the visitor's language, belong to that one form. The Language column lets you filter and sort. - -**Can I export entries with the language?** - -The submission language is stored alongside each entry and is available to any integration that reads SureForms entries. A future SureForms release will include the language column in the standard CSV export header. - -**What languages are supported?** - -Any language WPML supports. SureForms records the standard WPML language code (`en`, `de`, `hi`, `zh-cn`, `pt-br`, etc.) — up to 20 characters, which covers the full WPML and BCP-47 locale-code range. - -**Does this work with Polylang or other multilingual plugins?** - -SureForms is built on a generic multilingual provider interface, so support for Polylang and other plugins is straightforward to add. WPML is the only multilingual plugin currently supported in the box. - ---- - -## Need help? - -If you run into anything not covered here, contact the SureForms support team at [sureforms.com/support](https://sureforms.com/support) with: - -1. Your SureForms version (Plugins → Installed Plugins → SureForms). -2. Your WPML version, including whether *WPML String Translation* is active. -3. Your form ID. -4. The specific string or behaviour that isn't translating. -5. A screenshot if possible. - -We're happy to help. diff --git a/docs/wiki/WordPress-Hooks-Reference.md b/docs/wiki/WordPress-Hooks-Reference.md deleted file mode 100644 index 1db16e372..000000000 --- a/docs/wiki/WordPress-Hooks-Reference.md +++ /dev/null @@ -1,152 +0,0 @@ -# WordPress Hooks Reference - -SureForms exposes custom actions and filters for extensibility, and hooks into WordPress core lifecycle events. - -## Custom Actions - -| Action | Parameters | Description | -|--------|-----------|-------------| -| `srfm_core_loaded` | -- | Fired after Plugin_Loader singleton is created | -| `srfm_before_submission` | `$form_data`, `$form_id` | Before form submission is processed | -| `srfm_form_submit` | `$entry_id`, `$form_id`, `$form_data` | After form submission is complete | -| `srfm_after_submission_process` | `$entry_id`, `$form_id` | After all post-submission processing | -| `srfm_before_delete_entry` | `$entry_id` | Before an entry is permanently deleted | - -## Custom Filters - -### REST API - -| Filter | Parameters | Description | -|--------|-----------|-------------| -| `srfm_rest_api_endpoints` | `$endpoints` | Add/modify REST API endpoints | - -### Form Data - -| Filter | Parameters | Description | -|--------|-----------|-------------| -| `srfm_form_submit_data` | `$form_data`, `$form_id` | Modify form data before processing | -| `srfm_entry_value` | `$value`, `$args` | Transform entry field values in responses | -| `srfm_normalize_csv_field_value` | `$value`, `$field` | Custom CSV export value formatting | -| `srfm_form_confirmation_params` | `$params`, `$form_id` | Modify confirmation settings | - -### Post Meta - -| Filter | Parameters | Description | -|--------|-----------|-------------| -| `srfm_register_post_meta` | `$meta_keys` | Register additional form post meta keys | - -### Blocks - -| Filter | Parameters | Description | -|--------|-----------|-------------| -| `srfm_is_special_block` | `$is_special`, `$block_name` | Declare a block as special (nested) | -| `srfm_handle_special_block` | `$result`, `$block` | Custom processing for special blocks | -| `srfm_extract_form_fields_field_name` | `$field_name`, `$block` | Modify generated field names | - -### Settings - -| Filter | Parameters | Description | -|--------|-----------|-------------| -| `srfm_global_settings_data` | `$settings` | Extend global settings data | -| `srfm_disable_nps_survey` | `$disable` | Disable NPS survey module | -| `srfm_enable_redirect_activation` | `$enable` | Control activation redirect behavior | - -## WordPress Core Hooks Used - -### plugins_loaded - -| Priority | Callback | Class | -|----------|----------|-------| -| default | `load_textdomain()` | Plugin_Loader | -| 99 | `load_plugin()` | Plugin_Loader | - -### init - -| Priority | Callback | Purpose | -|----------|----------|---------| -| 10 | `load_classes()` | Block registration, admin, payments | - -### rest_api_init - -| Callback | Class | Purpose | -|----------|-------|---------| -| `register_endpoints()` | Rest_Api | Register all admin REST endpoints | -| `register_routes()` | Form_Submit | Register public submission endpoints | -| `register_rest_routes()` | Payments_Settings | Register payment REST routes | - -### admin_init - -| Callback | Purpose | -|----------|---------| -| `activation_redirect()` | Redirect to onboarding after activation | -| `intercept_stripe_callback()` | Handle Stripe OAuth callback | - -### wp_enqueue_scripts - -| Callback | Class | Purpose | -|----------|-------|---------| -| Asset enqueue | Frontend_Assets | Load form CSS/JS on pages with forms | - -### enqueue_block_editor_assets - -| Callback | Class | Purpose | -|----------|-------|---------| -| Editor asset enqueue | Gutenberg_Hooks | Load block editor JS/CSS | - -## Hook Execution Order (Form Submission) - -``` -1. REST API receives POST /submit-form -2. Form_Submit::submit_form_permissions_check() - -> Nonce verification -3. Form_Submit::handle_form_submission() - -> apply_filters('srfm_form_submit_data', $data, $form_id) - -> Field validation - -> CAPTCHA verification - -> Honeypot check -4. do_action('srfm_before_submission', $data, $form_id) -5. Email notification sent -6. Entry stored in database -7. do_action('srfm_form_submit', $entry_id, $form_id, $data) -8. do_action('srfm_after_submission_process', $entry_id, $form_id) -9. Confirmation response returned -``` - -## Usage Examples - -### Adding a Custom REST Endpoint - -```php -add_filter( 'srfm_rest_api_endpoints', function( $endpoints ) { - $endpoints['my-custom/data'] = [ - 'methods' => 'GET', - 'callback' => 'my_custom_callback', - 'permission_callback' => [ \SRFM\Inc\Helper::class, 'get_items_permissions_check' ], - ]; - return $endpoints; -} ); -``` - -### Modifying Form Data Before Processing - -```php -add_filter( 'srfm_form_submit_data', function( $data, $form_id ) { - // Add custom processing - $data['custom_field'] = 'custom_value'; - return $data; -}, 10, 2 ); -``` - -### Running Code After Submission - -```php -add_action( 'srfm_form_submit', function( $entry_id, $form_id, $form_data ) { - // Send to external service, trigger automation, etc. -}, 10, 3 ); -``` - -## Related Pages - -- [Architecture Overview](Architecture-Overview) -- Plugin bootstrap and hook registration -- [REST API Reference](REST-API-Reference) -- Full endpoint documentation -- [Form Submission Flow](Form-Submission-Flow) -- Submission hook execution order diff --git a/docs/wiki/_Footer.md b/docs/wiki/_Footer.md deleted file mode 100644 index 0a54d2e24..000000000 --- a/docs/wiki/_Footer.md +++ /dev/null @@ -1,3 +0,0 @@ ---- - -**SureForms** by [Brainstorm Force](https://brainstormforce.com/) | [GitHub](https://github.com/brainstormforce/sureforms) | [Website](https://sureforms.com/) | [Support](https://support.brainstormforce.com/) diff --git a/docs/wiki/_Sidebar.md b/docs/wiki/_Sidebar.md deleted file mode 100644 index 4fe3b09d1..000000000 --- a/docs/wiki/_Sidebar.md +++ /dev/null @@ -1,36 +0,0 @@ -**[Home](Home)** - -**Getting Started** -- [Getting Started](Getting-Started) -- [Environment Configuration](Environment-Configuration) - -**Architecture** -- [Architecture Overview](Architecture-Overview) -- [Database Schema](Database-Schema) -- [Form Submission Flow](Form-Submission-Flow) - -**WordPress / Backend** -- [Gutenberg Blocks](Gutenberg-Blocks) -- [Form Fields Architecture](Form-Fields-Architecture) -- [WordPress Hooks Reference](WordPress-Hooks-Reference) -- [Payment Integration](Payment-Integration) -- [Email Notifications](Email-Notifications) -- [AI Form Builder](AI-Form-Builder) -- [Data Export & Import](Data-Export-Import) -- [Using WPML With SureForms](Using-WPML-With-SureForms) - -**Frontend / React** -- [Admin Dashboard](Admin-Dashboard) -- [State Management](State-Management) -- [Frontend Assets](Frontend-Assets) -- [Block Editor Controls](Block-Editor-Controls) - -**API** -- [REST API Reference](REST-API-Reference) - -**Development** -- [Contributing Guide](Contributing-Guide) -- [Testing Guide](Testing-Guide) -- [Deployment Guide](Deployment-Guide) -- [Troubleshooting & FAQ](Troubleshooting-FAQ) -- [Changelog](Changelog) diff --git a/inc/abilities/CLAUDE.md b/inc/abilities/CLAUDE.md deleted file mode 100644 index 869f850ca..000000000 --- a/inc/abilities/CLAUDE.md +++ /dev/null @@ -1,66 +0,0 @@ -# Abilities — Development Guide - -## Adding a New Ability - -1. Create a class extending `Abstract_Ability` in the appropriate subdirectory: - - `forms/` — form CRUD operations - - `entries/` — entry/submission operations - - `embedding/` — shortcodes, block markup, rendering - - `settings/` — global settings read/write - - `analytics/` — form analytics and reporting - - `export/` — form and entry import/export -2. Register it in `Abilities_Registrar::register_abilities()` - -## Abstract_Ability Contract - -Every ability must implement: -- **Constructor** — set `$id`, `$label`, `$description`, `$capability` -- **`get_input_schema()`** — JSON Schema for input validation -- **`get_output_schema()`** — JSON Schema for output contract -- **`execute( $input )`** — business logic, return array or `WP_Error` -- **`get_annotations()`** — override if not default (`readonly`, `destructive`, `idempotent`) - -## Conventions - -- ID format: `sureforms/<verb>-<noun>` (e.g. `sureforms/list-forms`) -- Namespace: `SRFM\Inc\Abilities\<Subdirectory>\<Class_Name>` -- Return `WP_Error` for failures, never throw exceptions -- Default capability: `edit_posts` — override per-ability where needed -- Destructive abilities must set `destructive: true` in annotations -- All classes need `@since x.x.x` tags -- Add PHPUnit tests in `tests/unit/inc/abilities/` for every new ability - -## Architecture - -``` -inc/abilities/ -├── abstract-ability.php # Base class — do not modify without updating all abilities -├── abilities-registrar.php # Singleton — registers category + all abilities -├── forms/ -│ ├── list-forms.php # readonly, idempotent -│ ├── create-form.php # uses Field_Mapping engine -│ ├── get-form.php # readonly, idempotent — parses Gutenberg blocks -│ ├── delete-form.php # destructive -│ ├── duplicate-form.php # delegates to \SRFM\Inc\Duplicate_Form -│ ├── update-form.php # write, idempotent — title/status/metadata -│ └── get-form-stats.php # readonly, idempotent — entry counts -├── entries/ -│ ├── list-entries.php # readonly, idempotent — paginated listing -│ ├── get-entry.php # readonly, idempotent — decoded form_data -│ ├── update-entry-status.php # write, idempotent — read/unread/trash/restore -│ └── delete-entry.php # destructive — permanent delete -├── embedding/ -│ └── get-shortcode.php # readonly, idempotent -├── settings/ -│ ├── get-global-settings.php # readonly, idempotent — all setting categories -│ └── update-global-settings.php # write, idempotent — delegates to Global_Settings -└── analytics/ - └── get-form-analytics.php # readonly, idempotent — submission date queries -``` - -## Extensibility - -- **Filter:** `srfm_register_abilities` — third-party plugins can add abilities (must extend `Abstract_Ability`) -- **Hooks:** `srfm_before_ability_execute` / `srfm_after_ability_execute` — fire around every execution -- **Collision guard:** Registrar checks `wp_has_ability()` before registering to avoid duplicates with zipwp-mcp -- **WP < 6.9:** Registrar bails in constructor — zero overhead when Abilities API is unavailable diff --git a/internal-docs/README.md b/internal-docs/README.md deleted file mode 100644 index 9a933cae0..000000000 --- a/internal-docs/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# SureForms Internal Documentation - -**Version:** 2.5.0 -**Last Updated:** February 2026 -**Target Audience:** Developers, AI Agents, Technical Team - ---- - -## Welcome - -This is the internal documentation for **SureForms Free** and **SureForms Pro** - WordPress form builder plugins used by 300,000+ websites. - -**SureForms Free:** AI-powered form builder with payments (Stripe), native WordPress blocks, 16+ fields -**SureForms Pro:** Advanced features - conversational forms, multi-step, conditional logic, PayPal, 24+ integrations - ---- - -## Quick Start - -### For New Developers (1 Hour) - -1. **Install locally:** - ```bash - cd /path/to/wordpress/wp-content/plugins - git clone https://github.com/brainstormforce/sureforms.git - git clone https://github.com/brainstormforce/sureforms-pro.git - cd sureforms && npm install && npm run build - cd ../sureforms-pro && npm install && npm run build - ``` - -2. **Activate plugins:** - - SureForms Free (required) - - SureForms Pro (optional, requires Free) - -3. **Create first form:** - - Dashboard → SureForms → Add New - - Try AI form builder or blank form - - Add fields from block inserter - - Publish and test submission - -4. **Read these docs:** - - [Architecture](architecture.md) - System design - - [Codebase Map](codebase-map.md) - Where is what - - [APIs](apis.md) - REST, AJAX, hooks - -### For AI Agents - -Start with [ai-agent-guide.md](ai-agent-guide.md) for codebase conventions, patterns, and agent-specific guidance. - ---- - -## Key Files & Directories - -| Path | Purpose | -|------|---------| -| `sureforms/inc/` | Core PHP logic | -| `sureforms/inc/blocks/` | Gutenberg block PHP | -| `sureforms/src/` | React components (admin UI) | -| `sureforms/inc/payments/` | Stripe payment processing | -| `sureforms/inc/ai-form-builder/` | AI form generation | -| `sureforms-pro/inc/business/` | Pro features (PayPal, registration, PDF) | -| `sureforms-pro/inc/pro/native-integrations/` | 24+ service integrations | - ---- - -## Build System - -**SureForms Free:** -```bash -npm run build # Full build (webpack + sass + grunt) -npm run start # Dev mode (watch) -npm run lint-js:fix # Fix JS linting -npm run makepot # Generate translation files -``` - -**SureForms Pro:** -```bash -npm run build # Full build -npm run package # Create distributable zip -``` - -Both use: -- **@wordpress/scripts** (webpack 5, Babel, ESLint) -- **Grunt** (minification, compression) -- **Sass** for CSS compilation - ---- - -## Database Tables - -Custom tables (via `inc/database/`): - -| Table | Purpose | -|-------|---------| -| `wp_sureforms_entries` | Form submissions | -| `wp_sureforms_payments` | Payment transactions (Stripe/PayPal) | -| `wp_sureforms_integrations` | Native integration credentials (encrypted) | -| `wp_sureforms_save_resume` | Draft form state (Pro) | - ---- - -## Testing - -**Unit Tests:** -```bash -composer test # PHPUnit -npm run test:unit # Jest (JS) -``` - -**E2E Tests:** -```bash -npm run play:up # Start wp-env -npm run play:run # Run Playwright tests -``` - -**Code Quality:** -```bash -composer lint # PHP_CodeSniffer -composer phpstan # Static analysis -npm run lint-js # ESLint -``` - ---- - -## Release Process - -**Free (WordPress.org):** -1. Update version in `sureforms.php` and `package.json` -2. Run `npm run build && grunt release` -3. Files excluded via `.distignore` -4. SVN commit to WordPress.org repo - -**Pro (Custom Distribution):** -1. Update version in `sureforms-pro.php` -2. Run `npm run build && npm run package` -3. Generates `sureforms-pro.zip` -4. Deploy to licensing server - ---- - -## Support & Resources - -- **GitHub (Free):** https://github.com/brainstormforce/sureforms -- **GitHub (Pro):** https://github.com/brainstormforce/sureforms-pro -- **Documentation:** https://sureforms.com/docs/ -- **Bug Bounty:** https://brainstormforce.com/bug-bounty-program/ -- **Support:** support@brainstormforce.com - ---- - -## Next Steps - -- **Product Vision:** [product-vision.md](product-vision.md) - Understand goals and personas -- **Architecture:** [architecture.md](architecture.md) - System design and data flow -- **Onboarding:** [onboarding.md](onboarding.md) - 1-hour, 1-day, 1-week learning paths - ---- - -**Maintained by:** SureForms Engineering Team -**Contact:** engineering@brainstormforce.com diff --git a/internal-docs/ai-agent-guide.md b/internal-docs/ai-agent-guide.md deleted file mode 100644 index 867f3c7ea..000000000 --- a/internal-docs/ai-agent-guide.md +++ /dev/null @@ -1,459 +0,0 @@ -# AI Agent Guide - -**Version:** 2.5.0 -**For:** AI Coding Agents & LLMs - ---- - -## Overview - -This guide helps AI agents understand SureForms codebase conventions, make safe changes, and avoid common pitfalls. - ---- - -## Core Principles - -1. **Security First:** Sanitize inputs, escape outputs, use prepared statements -2. **WordPress Standards:** Follow WP coding standards, use WP functions -3. **Backward Compatibility:** Don't break existing forms/entries -4. **Performance:** Avoid N+1 queries, cache when possible -5. **Testing:** Write tests, run existing tests before committing - ---- - -## File Modification Guidelines - -### ✅ Safe to Modify - -**Add features (low risk):** -- New blocks: `inc/blocks/new-block/` -- New integrations (Pro): `inc/pro/native-integrations/integrations/new-service/` -- New validation rules: Add to `inc/field-validation.php` -- New hooks: Add filters/actions (don't remove existing) - -**Extend existing:** -- Add sanitization functions to `inc/helper.php` -- Add validation methods to `inc/field-validation.php` -- Add utility functions to helper classes - -### ⚠️ Modify with Caution - -**Database schema changes:** -- Requires migration script -- Must handle existing data -- Version increments in `inc/database/tables/*.php` - -**Payment processing:** -- `inc/payments/stripe/stripe-webhook.php` -- `inc/business/payments/pay-pal/webhook-listener.php` -- **Risk:** Financial impact if broken - -**Form submission pipeline:** -- `inc/form-submit.php` -- **Risk:** Could break all forms - -### 🚫 High Risk - Avoid Unless Necessary - -**Core WordPress integration:** -- `plugin-loader.php` -- `sureforms.php` / `sureforms-pro.php` - -**Database base class:** -- `inc/database/base.php` (inherited by all tables) - -**Critical security:** -- Nonce verification logic -- Capability checks -- Encryption (Pro): `inc/pro/native-integrations/encryption.php` - ---- - -## Common Patterns - -### Adding a New Field Type - -1. **Create block:** - ``` - inc/blocks/my-field/block.php - src/blocks/my-field/ - ``` - -2. **Register block:** - ```php - // inc/blocks/my-field/block.php - namespace SRFM\Inc\Blocks\My_Field; - - class Block extends \SRFM\Inc\Blocks\Base { - public static function register() { - register_block_type( - 'sureforms/my-field', - [ - 'render_callback' => [__CLASS__, 'render'], - 'attributes' => [/* schema */], - ] - ); - } - - public static function render($attributes) { - // Return HTML - } - } - ``` - -3. **Add to block registry:** - ```php - // inc/blocks/register.php - My_Field\Block::register(); - ``` - -4. **Add sanitization:** - ```php - // inc/helper.php - public static function sanitize_by_field_type($type, $value) { - switch ($type) { - case 'my-field': - return sanitize_text_field($value); - } - } - ``` - -### Adding a REST Endpoint - -```php -// inc/rest-api.php or new file -public function register_routes() { - register_rest_route( - 'sureforms/v1', - '/my-endpoint', - [ - 'methods' => 'POST', - 'callback' => [$this, 'handle_request'], - 'permission_callback' => [$this, 'check_permissions'], - ] - ); -} - -public function check_permissions() { - // CRITICAL: Always verify permissions - return current_user_can('manage_options'); -} - -public function handle_request($request) { - // CRITICAL: Always verify nonce - $nonce = $request->get_header('X-WP-Nonce'); - if (!wp_verify_nonce($nonce, 'wp_rest')) { - return new \WP_Error('invalid_nonce', 'Invalid nonce', ['status' => 403]); - } - - // Sanitize inputs - $data = $request->get_params(); - $clean_data = Helper::sanitize_array_recursively($data); - - // Process... - - return ['success' => true]; -} -``` - -### Adding an Integration (Pro) - -1. **Create integration folder:** - ``` - inc/pro/native-integrations/integrations/myservice/ - ├── config.json - └── actions/ - └── send-data.php - ``` - -2. **config.json:** - ```json - { - "name": "MyService", - "slug": "myservice", - "auth_method": "api_key", - "api_endpoint": "https://api.myservice.com/v1/", - "actions": [ - { - "name": "Send Data", - "slug": "send-data", - "endpoint": "contacts" - } - ] - } - ``` - -3. **actions/send-data.php:** - ```php - namespace SRFM_PRO\Inc\Pro\Native_Integrations\Integrations\Myservice\Actions; - - class Send_Data { - public function execute($integration_data, $form_data) { - $api_key = $integration_data['api_key']; - $response = wp_remote_post( - 'https://api.myservice.com/v1/contacts', - [ - 'headers' => ['Authorization' => 'Bearer ' . $api_key], - 'body' => json_encode($form_data), - ] - ); - - if (is_wp_error($response)) { - return ['success' => false, 'error' => $response->get_error_message()]; - } - - return ['success' => true, 'response' => wp_remote_retrieve_body($response)]; - } - } - ``` - ---- - -## Security Patterns - -### Input Sanitization - -```php -// Text -$name = sanitize_text_field( wp_unslash( $_POST['name'] ?? '' ) ); - -// Email -$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) ); - -// Number -$id = absint( $_POST['id'] ?? 0 ); - -// Array (recursive) -$data = Helper::sanitize_array_recursively( $_POST['data'] ?? [] ); - -// Textarea -$message = Helper::sanitize_textarea( wp_unslash( $_POST['message'] ?? '' ) ); -``` - -### Output Escaping - -```php -// HTML content -echo esc_html( $user_name ); - -// Attributes -echo '<div class="' . esc_attr( $class ) . '">'; - -// URLs -echo '<a href="' . esc_url( $url ) . '">'; - -// Rich text (allows safe HTML) -echo wp_kses_post( $content ); -``` - -### Database Queries - -```php -global $wpdb; - -// ✅ Good - Prepared statement -$results = $wpdb->get_results( - $wpdb->prepare( - "SELECT * FROM {$wpdb->prefix}sureforms_entries WHERE form_id = %d AND status = %s", - $form_id, - $status - ) -); - -// ❌ Bad - SQL injection risk -$results = $wpdb->query("DELETE FROM {$wpdb->prefix}sureforms_entries WHERE id = $_POST[id]"); -``` - ---- - -## Testing Your Changes - -### Before Committing - -```bash -# 1. Lint PHP -composer lint - -# 2. Run PHP tests -composer test - -# 3. Lint JavaScript -npm run lint-js - -# 4. Run JS tests -npm run test:unit - -# 5. Build assets -npm run build - -# 6. Test in browser -# - Create form -# - Submit form -# - Check entries -# - Verify no console errors -``` - -### E2E Testing - -```bash -# Start environment -npm run play:up - -# Run tests -npm run play:run - -# Interactive mode (with browser) -npm run play:run:interactive -``` - ---- - -## Database Queries - Common Patterns - -### Get Entries - -```php -use SRFM\Inc\Database\Tables\Entries; - -// Get all for form -$entries = Entries::get_all([ - 'where' => [ - ['key' => 'form_id', 'value' => 123, 'compare' => '='] - ], - 'orderby' => 'created_at', - 'order' => 'DESC', -]); - -// With pagination -$entries = Entries::get_all([ - 'where' => [['key' => 'form_id', 'value' => 123, 'compare' => '=']], - 'limit' => 20, - 'offset' => 40 // Page 3 (20 per page) -]); - -// Count entries -$count = Entries::get_count([ - 'where' => [['key' => 'status', 'value' => 'published', 'compare' => '=']] -]); -``` - -### Get Payments - -```php -use SRFM\Inc\Database\Tables\Payments; - -// Get completed payments -$payments = Payments::get_all([ - 'where' => [ - ['key' => 'status', 'value' => 'completed', 'compare' => '='] - ] -]); - -// Get payment by transaction ID -$payment = Payments::get_by_transaction_id('ch_xxxxx', 'stripe'); -``` - ---- - -## Hooks - When to Use - -### Modify Data Before Save - -```php -// Filter entry data before save -add_filter('sureforms_submit_form_data', function($data, $form_id) { - // Add custom field - $data['custom_timestamp'] = current_time('mysql'); - return $data; -}, 10, 2); -``` - -### Trigger External Action - -```php -// Action after entry save -add_action('sureforms_after_entry_save', function($entry_id, $form_id, $data) { - // Send to external CRM - send_to_crm($data); -}, 10, 3); -``` - -### Modify Email - -```php -// Filter email template -add_filter('sureforms_email_template', function($html, $entry_id) { - // Add custom header - return '<div class="custom-header">...</div>' . $html; -}, 10, 2); -``` - ---- - -## Debugging Tips - -### Enable Debug Mode - -```php -// wp-config.php -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -``` - -### Check Debug Log - -```bash -tail -f wp-content/debug.log -``` - -### JavaScript Console - -```javascript -// Check for errors -// Open browser DevTools → Console - -// SureForms global -console.log(window.sureforms); -``` - -### Database Queries - -```php -// Install Query Monitor plugin -// Shows all queries, slow queries, errors -``` - ---- - -## Common Pitfalls to Avoid - -1. **Don't bypass sanitization:** "It's internal, it's safe" → Still sanitize -2. **Don't skip nonce checks:** Every AJAX/REST endpoint needs verification -3. **Don't use `$_POST` directly:** Always sanitize first -4. **Don't concatenate SQL:** Use `$wpdb->prepare()` -5. **Don't echo user data raw:** Use `esc_html()`, `esc_attr()`, etc. -6. **Don't modify database schema without migration:** Breaks existing sites -7. **Don't remove existing hooks:** Other plugins may depend on them -8. **Don't hardcode `wp_` prefix:** Use `$wpdb->prefix` - ---- - -## Getting Help - -**Documentation:** -- This folder: All internal docs -- WordPress Codex: https://codex.wordpress.org/ -- React Docs: https://react.dev/ - -**Code Search:** -- Use Glob/Grep tools to find patterns -- Example: `grep -r "sanitize_text_field" inc/` → See how sanitization is used - -**Ask Before:** -- Breaking changes -- Database schema changes -- Removing existing functionality - ---- - -**Next:** [Troubleshooting](troubleshooting.md) - Common problems and solutions diff --git a/internal-docs/apis.md b/internal-docs/apis.md deleted file mode 100644 index 0a7a16ec7..000000000 --- a/internal-docs/apis.md +++ /dev/null @@ -1,418 +0,0 @@ -# APIs - -Complete API reference for SureForms Free & Pro. - ---- - -## REST API Endpoints - -### Free (`/sureforms/v1/`) - -**Form Management:** -```http -POST /sureforms/v1/generate-form -GET /sureforms/v1/forms -GET /sureforms/v1/forms/{id} -DELETE /sureforms/v1/forms/{id} -``` - -**Form Submission:** -```http -POST /sureforms/v1/submit-form -``` -**Body:** `{ form_id, nonce, field_data... }` -**Response:** `{ success, message, entry_id }` - -**Entries:** -```http -GET /sureforms/v1/entries/list -GET /sureforms/v1/entries/{id} -DELETE /sureforms/v1/entries/{id} -POST /sureforms/v1/entries/export -``` - -**Payments:** -```http -GET /sureforms/v1/payments/list -GET /sureforms/v1/payments/{id} -``` - -**Stripe Webhooks:** -```http -POST /sureforms/webhook_test # Stripe webhooks -POST /sureforms/webhook_live -``` - -**Settings:** -```http -GET /sureforms/v1/settings -POST /sureforms/v1/settings/update -``` - -### Pro (`/sureforms-pro/v1/`) - -**OAuth:** -```http -POST /sureforms-pro/v1/oauth/authorize -POST /sureforms-pro/v1/oauth/callback -``` - -**PayPal Webhooks:** -```http -POST /sureforms-pro/paypal-test-webhook -POST /sureforms-pro/paypal-live-webhook -``` - -**User Registration:** -```http -POST /sureforms-pro/v1/login -POST /sureforms-pro/v1/lost-password -POST /sureforms-pro/v1/reset-password -``` - ---- - -## AJAX Handlers - -### Free (30 handlers) - -**Admin:** -```php -'srfm_admin_action' # Generic admin handler -'srfm_get_forms' # Fetch forms list -'srfm_delete_form' # Delete form -'srfm_duplicate_form' # Duplicate form -'srfm_export_entries' # Export CSV -``` - -**Payments (Public):** -```php -'wp_ajax_srfm_create_payment_intent' # Stripe payment -'wp_ajax_nopriv_srfm_create_payment_intent' -'wp_ajax_srfm_create_subscription_intent' # Stripe subscription -'wp_ajax_nopriv_srfm_create_subscription_intent' -``` - -**Admin Stripe:** -```php -'srfm_stripe_cancel_subscription' # Cancel subscription -'srfm_stripe_pause_subscription' # Pause subscription -``` - -**Admin Payments:** -```php -'srfm_create_payment_refund' # Create refund -``` - -**Form Validation (Public):** -```php -'wp_ajax_srfm_field_unique_validation' # Check unique fields -'wp_ajax_nopriv_srfm_field_unique_validation' -``` - -### Pro (22 handlers) - -**PayPal (Public):** -```php -'wp_ajax_srfm_pro_create_paypal_order' -'wp_ajax_nopriv_srfm_pro_create_paypal_order' -'wp_ajax_srfm_pro_create_paypal_subscription' -'wp_ajax_nopriv_srfm_pro_create_paypal_subscription' -``` - -**PayPal Admin:** -```php -'srfm_pro_paypal_cancel_subscription' -'srfm_pro_paypal_pause_subscription' -``` - -**PDF:** -```php -'srfm_pro_generate_pdf' # Generate PDF from entry -'srfm_pro_download_pdf' # Download PDF -``` - -**Licensing:** -```php -'srfm_pro_activate_license' -'srfm_pro_deactivate_license' -``` - -**Entries:** -```php -'sureforms_pro_entry_delete_file' # Delete uploaded file -``` - ---- - -## WordPress Hooks - -### Actions (Form Submission) - -```php -// Before entry save -do_action('sureforms_before_entry_save', $form_id, $entry_data); - -// After entry save -do_action('sureforms_after_entry_save', $entry_id, $form_id, $entry_data); - -// After payment completed -do_action('sureforms_payment_completed', $payment_id, $entry_id, $gateway); - -// After integration success -do_action('sureforms_integration_success', $integration_type, $response); - -// Before email send -do_action('sureforms_before_email_send', $to, $subject, $message); - -// After form submission (success) -do_action('sureforms_form_submitted', $entry_id, $form_id); -``` - -### Filters (Data Modification) - -```php -// Modify form data before save -$entry_data = apply_filters('sureforms_submit_form_data', $entry_data, $form_id); - -// Modify payment amount -$amount = apply_filters('sureforms_payment_amount', $amount, $form_id, $entry_data); - -// Modify email template -$html = apply_filters('sureforms_email_template', $html, $entry_id, $form_id); - -// Modify email subject -$subject = apply_filters('sureforms_email_subject', $subject, $form_id); - -// Modify email recipients -$to = apply_filters('sureforms_email_recipients', $to, $entry_id, $form_id); - -// Modify confirmation message -$message = apply_filters('sureforms_confirmation_message', $message, $entry_id); - -// Modify field validation -$is_valid = apply_filters('sureforms_validate_field', $is_valid, $field, $value); - -// Modify sanitized value -$value = apply_filters("sureforms_sanitize_{$field_type}", $value, $field); -``` - -### Integration Hooks (Pro) - -```php -// Before integration request -do_action('sureforms_pro_before_integration', $integration, $data); - -// After integration request -do_action('sureforms_pro_after_integration', $integration, $response); - -// Integration error -do_action('sureforms_pro_integration_error', $integration, $error); -``` - ---- - -## JavaScript APIs - -### Global Objects - -```javascript -// Form settings -window.sureforms = { - ajaxUrl: '/wp-admin/admin-ajax.php', - nonce: 'xxx', - formId: 123, - settings: {...} -}; - -// Block editor -window.sureformsBlocks = { - registerBlock: (name, settings) => {...}, - getBlock: (name) => {...} -}; -``` - -### Custom Events - -```javascript -// Form submitted -document.addEventListener('sureforms-form-submitted', (e) => { - console.log('Entry ID:', e.detail.entryId); -}); - -// Payment completed -document.addEventListener('sureforms-payment-completed', (e) => { - console.log('Payment ID:', e.detail.paymentId); -}); - -// Validation error -document.addEventListener('sureforms-validation-error', (e) => { - console.log('Field:', e.detail.field, 'Error:', e.detail.message); -}); -``` - ---- - -## Database APIs - -### Entry Operations - -```php -use SRFM\Inc\Database\Tables\Entries; - -// Get all entries for a form -$entries = Entries::get_all([ - 'where' => [ - ['key' => 'form_id', 'value' => 123, 'compare' => '='] - ], - 'orderby' => 'created_at', - 'order' => 'DESC', - 'limit' => 20, - 'offset' => 0 -]); - -// Get single entry -$entry = Entries::get_by_id(456); - -// Insert entry -$entry_id = Entries::insert([ - 'form_id' => 123, - 'entry_data' => json_encode($data), - 'status' => 'published' -]); - -// Update entry -Entries::update(456, ['status' => 'trash']); - -// Delete entry -Entries::delete(456); -``` - -### Payment Operations - -```php -use SRFM\Inc\Database\Tables\Payments; - -// Get payments -$payments = Payments::get_all_main_payments([ - 'where' => [ - ['key' => 'status', 'value' => 'completed', 'compare' => '='] - ] -]); - -// Create payment -$payment_id = Payments::insert([ - 'entry_id' => 456, - 'transaction_id' => 'ch_xxx', - 'gateway' => 'stripe', - 'status' => 'pending', - 'total_amount' => 99.99, - 'currency' => 'USD' -]); - -// Update payment status -Payments::update($payment_id, ['status' => 'completed']); -``` - ---- - -## Helper APIs - -### Sanitization - -```php -use SRFM\Inc\Helper; - -// Sanitize by field type -$clean = Helper::sanitize_by_field_type('email', $value); -$clean = Helper::sanitize_by_field_type('textarea', $value); -$clean = Helper::sanitize_by_field_type('number', $value); - -// Email-specific -$email = Helper::sanitize_email_header($raw_email); - -// Recursive sanitization -$clean_array = Helper::sanitize_array_recursively($array); -``` - -### Validation - -```php -use SRFM\Inc\Field_Validation; - -// Validate field -$result = Field_Validation::validate_field($field_config, $value); -// Returns: ['valid' => true/false, 'message' => 'Error message'] - -// Validate entire form -$result = Field_Validation::validate_form_data($form_id, $data); -``` - -### Payment Helpers - -```php -use SRFM\Inc\Payments\Payment_Helper; - -// Validate amount against form config -$result = Payment_Helper::validate_payment_amount($amount, $currency, $form_id, $block_id); - -// Get currency -$currency = Payment_Helper::get_currency(); -``` - ---- - -## Encryption API (Pro) - -```php -use SRFM_PRO\Inc\Pro\Native_Integrations\Encryption; - -$enc = new Encryption(); - -// Encrypt sensitive data -$encrypted = $enc->encrypt('oauth_token_12345'); - -// Decrypt -$decrypted = $enc->decrypt($encrypted); - -// Storage: wp_sureforms_integrations.data column -``` - -**Algorithm:** AES-256-CTR -**Key:** `SRFM_ENCRYPTION_KEY` constant or `LOGGED_IN_KEY` - ---- - -## Integration Workflow API (Pro) - -```php -use SRFM_PRO\Inc\Pro\Native_Integrations\Services\Workflow_Processor; - -// Execute integration workflow -$processor = new Workflow_Processor(); -$result = $processor->execute_workflow($integration_config, $entry_data); - -// Returns: ['success' => true/false, 'response' => API response] -``` - ---- - -## Rate Limiting - -**Note:** No built-in rate limiting. Implementations should add: - -```php -// Example pattern (not in core) -$key = 'form_submit_' . $user_ip; -$attempts = get_transient($key) ?: 0; - -if ($attempts >= 5) { - wp_send_json_error('Too many submissions', 429); -} - -set_transient($key, $attempts + 1, 15 * MINUTE_IN_SECONDS); -``` - ---- - -**Next:** [Coding Standards](coding-standards.md) - PHP/JS conventions diff --git a/internal-docs/architecture.md b/internal-docs/architecture.md deleted file mode 100644 index 9e59e0b81..000000000 --- a/internal-docs/architecture.md +++ /dev/null @@ -1,329 +0,0 @@ -# Architecture - -**Version:** 2.5.0 - ---- - -## System Overview - -SureForms is a WordPress form builder with a **Free + Pro** plugin architecture: - -``` -WordPress Site -├── SureForms Free (Required) -│ ├── Core form functionality -│ ├── Stripe payments -│ ├── AI form builder -│ └── Entry management -└── SureForms Pro (Optional Extension) - ├── Advanced features (conditional logic, multi-step) - ├── PayPal payments - ├── User registration/login - └── 24+ native integrations -``` - ---- - -## High-Level Architecture - -``` -┌─────────────────────────────────────────────────────────┐ -│ WordPress Admin │ -│ ┌──────────────────────────────────────────────────┐ │ -│ │ React Admin UI (src/) │ │ -│ │ - Form Builder (Gutenberg Blocks) │ │ -│ │ - Entry Dashboard │ │ -│ │ - Settings Panels │ │ -│ └──────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────┘ - ↕ -┌─────────────────────────────────────────────────────────┐ -│ REST API Layer │ -│ - /sureforms/v1/* (Free) │ -│ - /sureforms-pro/v1/* (Pro) │ -│ - AJAX handlers (wp_ajax_*) │ -└─────────────────────────────────────────────────────────┘ - ↕ -┌─────────────────────────────────────────────────────────┐ -│ Business Logic (inc/) │ -│ ┌──────────┬──────────┬──────────┬──────────────────┐ │ -│ │ Forms │ Payments │ AI │ Integrations │ │ -│ │ Submit │ Stripe │ Builder │ (Pro: 24+) │ │ -│ │ Validate │ PayPal │ Field │ Mailchimp, etc │ │ -│ │ Store │ Webhooks │ Mapping │ │ │ -│ └──────────┴──────────┴──────────┴──────────────────┘ │ -└─────────────────────────────────────────────────────────┘ - ↕ -┌─────────────────────────────────────────────────────────┐ -│ Data Layer │ -│ ┌──────────────┬────────────────┬──────────────────┐ │ -│ │ WP Options │ Custom Tables │ Encrypted Data │ │ -│ │ Form configs │ Entries │ OAuth tokens │ │ -│ │ Settings │ Payments │ API keys │ │ -│ └──────────────┴────────────────┴──────────────────┘ │ -└─────────────────────────────────────────────────────────┘ - ↕ -┌─────────────────────────────────────────────────────────┐ -│ Frontend Rendering │ -│ - Gutenberg Blocks (PHP + JS) │ -│ - Form submission (AJAX) │ -│ - reCAPTCHA/Turnstile │ -│ - Real-time validation │ -└─────────────────────────────────────────────────────────┘ -``` - ---- - -## Component Breakdown - -### 1. Block System (Gutenberg) - -**Free Blocks (16):** -- Input types: Text, Email, Number, Phone, URL, Textarea, Dropdown -- Special: Address, Checkbox, Multiple Choice, GDPR, Payment -- Layout: Separator, Heading, Image, Icon, Custom Button - -**Pro Blocks (8):** -- Input: Date Picker, Time Picker, Rating, Slider, Hidden, Password -- Advanced: File Upload, HTML, Page Break (multi-step) -- User Registration: Login, Register, Lost Password, Reset Password - -**Location:** `inc/blocks/*/block.php` and `src/blocks/*/` - -### 2. Form Submission Pipeline - -``` -User Submits Form - ↓ -1. Nonce Verification (inc/form-submit.php:91-95) - ↓ -2. Field Validation (inc/field-validation.php) - - Type validation (email, URL, number) - - Required fields - - Min/max constraints - - Custom regex - ↓ -3. Sanitization (inc/helper.php:258-274) - - Per-field type sanitization - - XSS prevention (wp_kses_post) - - SQL injection prevention - ↓ -4. CAPTCHA Validation (inc/form-submit.php:317-386) - - reCAPTCHA v2/v3 - - Cloudflare Turnstile - - hCaptcha - ↓ -5. Business Logic (Pro: Conditional Logic) - ↓ -6. Payment Processing (if enabled) - - Stripe: Create PaymentIntent - - PayPal: Create Order - ↓ -7. Entry Storage (inc/database/tables/entries.php) - ↓ -8. Integrations (Pro: Send to external services) - ↓ -9. Email Notifications (inc/email/email-template.php) - ↓ -10. Confirmation/Redirect -``` - -### 3. Payment Processing - -**Stripe (Free):** -- Location: `inc/payments/stripe/` -- Flow: - 1. Frontend creates PaymentIntent (AJAX) - 2. User completes payment on Stripe - 3. Webhook updates payment status - 4. Entry marked as paid - -**PayPal (Pro):** -- Location: `inc/business/payments/pay-pal/` -- Flow: - 1. Frontend creates Order via API - 2. User redirected to PayPal - 3. Webhook confirms payment - 4. Entry status updated - -**Database:** `wp_sureforms_payments` table - -### 4. AI Form Builder - -**Location:** `inc/ai-form-builder/` - -**Flow:** -``` -User Prompt ("Create a contact form") - ↓ -AI Middleware (SRFM_AI_MIDDLEWARE) - ↓ -Field Mapping (field-mapping.php) - ↓ -Gutenberg Block Generation - ↓ -Form Preview -``` - -**API:** `https://credits.startertemplates.com/sureforms/` - -### 5. Native Integrations (Pro) - -**Location:** `inc/pro/native-integrations/` - -**Supported Services (24+):** -- Email: Mailchimp, Brevo, Constant Contact -- CRM: HubSpot, Salesforce, Zoho -- Messaging: Telegram, Slack, Discord -- Marketing: FluentCRM, MailerPress -- Booking: LatePoint -- Automation: Zapier, OttoKit - -**Architecture:** -``` -Generic Provider Base Class - ↓ -Integration-Specific Classes -(inc/pro/native-integrations/integrations/*/actions/) - ↓ -OAuth Handler (oauth-handler.php) - ↓ -Encrypted Storage (encryption.php - AES-256-CTR) - ↓ -Workflow Processor (services/workflow-processor.php) -``` - -### 6. Database Schema - -**Custom Tables:** - -```sql --- Entries -wp_sureforms_entries -- id (INT, PK) -- form_id (INT) -- entry_data (LONGTEXT, JSON) -- created_at (DATETIME) -- updated_at (DATETIME) -- status (VARCHAR - 'published', 'trash') -- user_agent (TEXT) -- ip_address (VARCHAR) - --- Payments -wp_sureforms_payments -- id (INT, PK) -- entry_id (INT, FK) -- transaction_id (VARCHAR) -- gateway (ENUM 'stripe', 'paypal') -- status (ENUM 'pending', 'completed', 'failed', 'refunded') -- total_amount (DECIMAL) -- refunded_amount (DECIMAL) -- currency (VARCHAR) - --- Integrations (Pro) -wp_sureforms_integrations -- id (INT, PK) -- type (VARCHAR - 'mailchimp', 'hubspot', etc.) -- data (LONGTEXT, encrypted JSON) -- status (ENUM 'active', 'inactive') - --- Save & Resume (Pro) -wp_sureforms_save_resume -- id (INT, PK) -- form_id (INT) -- token (VARCHAR, unique) -- form_data (LONGTEXT, JSON) -- expires_at (DATETIME) -``` - ---- - -## Security Architecture - -**Input Validation:** -- Nonce verification on all AJAX/REST requests -- Sanitization via `sanitize_*` functions -- Type casting (absint, floatval) - -**Output Escaping:** -- `esc_html()`, `esc_attr()`, `esc_url()` throughout -- `wp_kses_post()` for rich text - -**SQL Security:** -- `$wpdb->prepare()` for all queries -- No direct SQL concatenation - -**Payment Security:** -- Webhook signature verification (Stripe, PayPal) -- Server-side amount validation -- PCI-DSS compliant (payments handled by Stripe/PayPal) - -**Encryption (Pro):** -- AES-256-CTR for OAuth tokens -- Key derivation: `SRFM_ENCRYPTION_KEY` constant or `LOGGED_IN_KEY` -- Storage: `wp_sureforms_integrations.data` (encrypted JSON) - ---- - -## Performance Optimizations - -1. **Lazy Loading:** React components loaded on-demand -2. **Asset Minification:** Grunt uglifies JS/CSS -3. **Database Indexing:** Indexes on `form_id`, `entry_id`, `status` -4. **Caching:** Transients for integration API calls -5. **Query Optimization:** `SELECT` only needed columns - ---- - -## Extensibility - -**Hooks (Filters):** -- `sureforms_submit_form_data` - Modify data before save -- `sureforms_email_template` - Customize email HTML -- `sureforms_payment_amount` - Modify payment amount - -**Hooks (Actions):** -- `sureforms_after_entry_save` - Trigger after entry created -- `sureforms_payment_completed` - After successful payment -- `sureforms_integration_success` - After integration sends data - -**Developer APIs:** -- REST: `/sureforms/v1/*` -- PHP: `SRFM\Inc\Helper` class -- JavaScript: `window.sureforms.*` globals - ---- - -## Technology Stack - -| Layer | Technologies | -|-------|-------------| -| Frontend (Admin) | React 18, @wordpress/components, TanStack Query | -| Frontend (Public) | Vanilla JS, DOMPurify, intl-tel-input | -| Backend | PHP 7.4+, WordPress 6.4+ | -| Build | webpack 5, Babel, Sass, Grunt | -| Testing | PHPUnit, Jest, Playwright | -| Database | MySQL 5.7+, MariaDB 10.3+ | - ---- - -## Deployment Architecture - -``` -Developer Machine - ↓ -Git Commit → GitHub Actions CI - ↓ -Automated Tests (PHPUnit, Playwright) - ↓ -Build Assets (npm run build) - ↓ -Free: WordPress.org SVN -Pro: Licensing Server (ZIP) - ↓ -End User WordPress Sites (300,000+) -``` - ---- - -**Next:** [Codebase Map](codebase-map.md) for detailed folder structure diff --git a/internal-docs/codebase-map.md b/internal-docs/codebase-map.md deleted file mode 100644 index 9d85000c2..000000000 --- a/internal-docs/codebase-map.md +++ /dev/null @@ -1,303 +0,0 @@ -# Codebase Map - -**Version:** 2.5.0 - -Complete folder-by-folder guide to both plugins. - ---- - -## SureForms Free (`sureforms/`) - -### Root Files - -| File | Purpose | -|------|---------| -| `sureforms.php` | Main plugin file, defines constants, loads `plugin-loader.php` | -| `plugin-loader.php` | Bootstraps plugin, registers hooks, loads dependencies | -| `composer.json` | PHP dependencies (nps-survey, bsf-analytics, astra-notices) | -| `package.json` | JS dependencies, build scripts | -| `Gruntfile.js` | Grunt tasks (minify, compress, release) | - -### `admin/` - WordPress Admin UI - -| File | Purpose | -|------|---------| -| `admin.php` | Admin page registration, AJAX handlers for admin actions | -| `analytics.php` | Usage analytics, event tracking | -| `notice-manager.php` | Admin notices, dismissible alerts | - -### `inc/` - Core PHP Logic - -#### `inc/blocks/` - Gutenberg Block Definitions (PHP) - -Each block has a `block.php` with: -- Block registration (`register_block_type`) -- Server-side rendering callback -- Attribute schema -- Enqueue scripts/styles - -**Blocks (16):** -- `address/`, `checkbox/`, `dropdown/`, `email/`, `gdpr/`, `inlinebutton/` -- `input/`, `multichoice/`, `number/`, `payment/`, `phone/`, `sform/`, `textarea/`, `url/` -- `base.php` - Base block class - -#### `inc/fields/` - Field Markup Generation - -Mirrors `blocks/` - generates HTML markup for each field type. - -**Pattern:** -```php -*-markup.php files: -- render_field() method -- Outputs escaped HTML -- Handles field attributes, validation states -``` - -#### `inc/payments/` - Payment Processing - -**Core Files:** -| File | Purpose | -|------|---------| -| `front-end.php` | Public AJAX handlers (`srfm_create_payment_intent`, `srfm_create_subscription_intent`) | -| `payment-helper.php` | Utility functions, amount validation, currency formatting | - -**`payments/stripe/`:** -| File | Purpose | -|------|---------| -| `stripe-webhook.php` | Webhook handler (charge, refund, subscription events) | -| `stripe-helper.php` | Stripe API wrapper, PaymentIntent creation | -| `admin-stripe-handler.php` | Admin AJAX for subscription management | -| `payments-settings.php` | Stripe connection settings, API keys | - -**`payments/admin/`:** -| File | Purpose | -|------|---------| -| `admin-handler.php` | Admin AJAX for refunds, payment management | - -#### `inc/ai-form-builder/` - AI Form Generation - -| File | Purpose | -|------|---------| -| `ai-form-builder.php` | Main AI form builder class, API integration | -| `ai-auth.php` | Middleware authentication | -| `ai-helper.php` | Helper functions, prompt processing | -| `field-mapping.php` | Maps AI response to Gutenberg blocks | - -**API:** `SRFM_AI_MIDDLEWARE` - `https://credits.startertemplates.com/sureforms/` - -#### `inc/database/` - Custom Database Tables - -| File | Purpose | -|------|---------| -| `base.php` | Abstract base class for all table classes (CRUD operations) | -| `register.php` | Table registration, schema creation | -| `tables/entries.php` | `wp_sureforms_entries` table (1,300+ lines) | -| `tables/payments.php` | `wp_sureforms_payments` table (1,200+ lines) | - -**Key Methods:** -- `get_all()`, `get_by_id()`, `insert()`, `update()`, `delete()` -- `get_all_main_payments()` - Payment queries with filtering - -#### Other `inc/` Files - -| File | Purpose | Lines | -|------|---------|-------| -| `form-submit.php` | Form submission handler (AJAX + REST) | 1,280 | -| `helper.php` | Utility functions (sanitization, escaping, validation) | 1,500+ | -| `field-validation.php` | Server-side field validation | 800+ | -| `rest-api.php` | REST API registration (`/sureforms/v1/*`) | 800 | -| `entries.php` | Entry management (list, view, export) | 1,000+ | -| `email/email-template.php` | Email notification templates | 400 | -| `frontend-assets.php` | Enqueue public scripts/styles | 300 | - -### `src/` - React Admin UI - -**Structure:** -``` -src/ -├── admin/ # Main admin app -│ ├── components/ # Reusable React components -│ ├── pages/ # Page-level components -│ └── index.js # Entry point -├── blocks/ # Block editor components -│ ├── address/ # Block-specific React -│ ├── email/ -│ └── ... -└── common/ # Shared utilities - ├── api.js # API client (wp.apiFetch) - └── utils.js # Helper functions -``` - -**Build:** webpack via `@wordpress/scripts` - ---- - -## SureForms Pro (`sureforms-pro/`) - -### Root Files - -| File | Purpose | -|------|---------| -| `sureforms-pro.php` | Main plugin file, requires Free plugin | -| `plugin-loader.php` | Bootstraps Pro features | - -### `inc/business/` - Pro Business Features - -#### `inc/business/payments/pay-pal/` - PayPal Integration - -| File | Purpose | Lines | -|------|---------|-------| -| `webhook-listener.php` | PayPal webhook handler (orders, refunds, subscriptions) | 1,173 | -| `frontend.php` | Public AJAX for PayPal orders, subscriptions | 1,100 | -| `api-payments.php` | PayPal API wrapper (create order, capture, refund) | 178 | -| `helper.php` | PayPal utilities, amount formatting | 520 | -| `settings.php` | PayPal connection settings | AJAX | - -#### `inc/business/user-registration/` - Login & Registration - -| File | Purpose | Lines | -|------|---------|-------| -| `init.php` | REST API registration, login/password endpoints | 600+ | -| `processor.php` | Registration processing, `wp_insert_user()` | 1,000+ | -| `login/block.php` | Login block definition | | -| `register/block.php` | Registration block | | -| `lost-password/block.php` | Lost password block | | -| `reset-password/block.php` | Reset password block | | - -**⚠️ Security Note:** Registration processor creates WordPress users from form submissions. - -#### `inc/business/pdf/` - PDF Generation - -| File | Purpose | -|------|---------| -| `pdf.php` | PDF generation API, AJAX handlers | -| `document.php` | PDF document builder (uses TCPDF or similar) | -| `utils.php` | PDF utilities | - -#### `inc/business/custom-app/` - Custom Application Builder - -| File | Purpose | -|------|---------| -| `load.php` | Custom post type forms, standalone applications | -| `utils.php` | App utilities | - -#### `inc/business/custom-post-type/` - Custom Post Type Integration - -Allows forms to create/update custom post types. - -### `inc/pro/native-integrations/` - 24+ Service Integrations - -**Core:** -| File | Purpose | Lines | -|------|---------|-------| -| `native-integrations.php` | Main integration manager | | -| `encryption.php` | AES-256-CTR encryption for OAuth tokens | 200 | -| `oauth-handler.php` | OAuth authorization flow | 400+ | -| `generic-provider.php` | Base provider class | | -| `integration-provider.php` | Provider interface | | - -**`inc/pro/native-integrations/integrations/`:** - -Each integration has its own folder: -``` -mailchimp/ -├── config.json # API endpoints, auth method -└── actions/ - ├── add-contact.php # Action: Add subscriber - └── remove-contact.php - -hubspot/ -├── config.json -└── actions/ - └── create-contact.php - -...24+ integrations -``` - -**Supported:** -- Email: Mailchimp, Brevo, Constant Contact -- CRM: HubSpot, Salesforce, Zoho -- Messaging: Telegram, Slack, Discord -- WP: FluentCRM, MailerPress, MailPoet -- Booking: LatePoint -- Automation: Zapier, OttoKit - -**Encryption:** OAuth tokens encrypted via `encryption.php` before storage in `wp_sureforms_integrations`. - -### `inc/pro/database/tables/` - Pro Database Tables - -| File | Purpose | -|------|---------| -| `integrations.php` | `wp_sureforms_integrations` table | -| `save-resume.php` | `wp_sureforms_save_resume` table (draft forms) | - -### `inc/extensions/` - Pro Extensions - -| File | Purpose | -|------|---------| -| `conditional-logic.php` | Show/hide fields based on conditions | -| `conditional-emails.php` | Conditional email notifications | -| `conditional-confirmations.php` | Conditional redirects | -| `field-validation.php` | Extended validation (file uploads, MIME types) | -| `entries-management.php` | Enhanced entry features (edit, delete files) | -| `page-break.php` | Multi-step form logic | - -### `inc/blocks/` - Pro Blocks (8) - -- `date-picker/`, `time-picker/`, `rating/`, `slider/` -- `upload/`, `hidden/`, `html/`, `page-break/` - ---- - -## Key Patterns & Conventions - -### Naming Conventions - -**Functions:** -- Public: `srfm_function_name()` -- Internal: `_srfm_internal_function()` - -**Classes:** -- Namespaced: `SRFM\Inc\ClassName` -- Pro: `SRFM_PRO\Inc\ClassName` - -**Hooks:** -- Actions: `sureforms_action_name` -- Filters: `sureforms_filter_name` - -**Database:** -- Tables: `wp_sureforms_table_name` -- Options: `sureforms_option_name` - -### File Organization - -``` -feature/ -├── block.php # Block registration -├── feature-markup.php # HTML generation -├── api-handler.php # AJAX/REST handlers -└── helper.php # Utilities -``` - -### REST API Convention - -**Free:** `/sureforms/v1/endpoint` -**Pro:** `/sureforms-pro/v1/endpoint` - ---- - -## Where to Find Things - -**Need to:** -- **Add a new field type?** → `inc/blocks/` + `inc/fields/` + `src/blocks/` -- **Modify form submission?** → `inc/form-submit.php` -- **Change email template?** → `inc/email/email-template.php` -- **Add payment gateway?** → `inc/payments/` (copy Stripe/PayPal pattern) -- **Add integration?** → `inc/pro/native-integrations/integrations/new-service/` -- **Debug entries?** → `inc/database/tables/entries.php` -- **Fix validation?** → `inc/field-validation.php` -- **Customize admin UI?** → `src/admin/` - ---- - -**Next:** [APIs](apis.md) - REST endpoints, AJAX handlers, hooks diff --git a/internal-docs/coding-standards.md b/internal-docs/coding-standards.md deleted file mode 100644 index 0b746674c..000000000 --- a/internal-docs/coding-standards.md +++ /dev/null @@ -1,312 +0,0 @@ -# Coding Standards - -**Version:** 2.5.0 - ---- - -## PHP Standards - -**WordPress Coding Standards:** https://developer.wordpress.org/coding-standards/wordpress-coding-standards/php/ - -### Code Style - -- **PSR-12 inspired** but follows WordPress conventions -- **Tabs for indentation** (not spaces) -- **Yoda conditions:** `if ( 'value' === $variable )` -- **Braces:** Required for all control structures - -```php -// ✅ Good -if ( $condition ) { - do_something(); -} - -// ❌ Bad -if ($condition) do_something(); -``` - -### Naming Conventions - -**Functions:** -```php -srfm_public_function() // Public functions -_srfm_private_function() // Internal (leading underscore) -``` - -**Classes:** -```php -namespace SRFM\Inc; -class Form_Submit { } // Underscores in class names - -namespace SRFM_PRO\Inc\Business; -class PayPal_Helper { } -``` - -**Variables:** -```php -$snake_case_variable = 'value'; // Lowercase with underscores -``` - -**Constants:** -```php -define( 'SRFM_CONSTANT', 'value' ); -``` - -### Security - -**Always:** -- Sanitize input: `sanitize_text_field()`, `absint()`, `sanitize_email()` -- Validate: Check types, ranges, allowed values -- Escape output: `esc_html()`, `esc_attr()`, `esc_url()` -- Use nonces: `wp_verify_nonce()` for AJAX/forms -- Use `$wpdb->prepare()` for SQL queries -- Check capabilities: `current_user_can()` - -**Example:** -```php -// Input -$email = sanitize_email( wp_unslash( $_POST['email'] ?? '' ) ); - -// Database -$results = $wpdb->get_results( - $wpdb->prepare( - "SELECT * FROM {$wpdb->prefix}sureforms_entries WHERE form_id = %d", - $form_id - ) -); - -// Output -echo '<div>' . esc_html( $user_name ) . '</div>'; -``` - -### Documentation - -**PHPDoc blocks:** -```php -/** - * Short description. - * - * Longer description if needed. - * - * @since 2.5.0 - * - * @param int $form_id Form ID. - * @param array $data Entry data. - * @return int|false Entry ID on success, false on failure. - */ -function srfm_create_entry( $form_id, $data ) { - // Implementation -} -``` - ---- - -## JavaScript Standards - -**WordPress JavaScript Coding Standards:** https://developer.wordpress.org/coding-standards/wordpress-coding-standards/javascript/ - -### Code Style (ESLint) - -**Config:** `@wordpress/eslint-plugin` - -```javascript -// ✅ Good - ES6+, const/let, arrow functions -const handleSubmit = (event) => { - event.preventDefault(); - const formData = new FormData(event.target); - // ... -}; - -// ❌ Bad - var, function expressions -var handleSubmit = function(event) { - event.preventDefault(); -}; -``` - -### React Conventions - -**Functional components with hooks:** -```jsx -import { useState, useEffect } from '@wordpress/element'; - -function FormBuilder({ formId }) { - const [fields, setFields] = useState([]); - - useEffect(() => { - fetchFields(formId).then(setFields); - }, [formId]); - - return ( - <div className="form-builder"> - {fields.map(field => <Field key={field.id} {...field} />)} - </div> - ); -} -``` - -**Naming:** -- Components: `PascalCase` -- Hooks: `useCamelCase` -- Functions: `camelCase` -- Constants: `UPPER_SNAKE_CASE` - ---- - -## CSS/SCSS Standards - -**BEM-inspired naming:** -```scss -.srfm-form { - &__field { - // Field styles - } - - &__field--error { - // Error state - } -} -``` - -**Prefix:** All classes start with `srfm-` to avoid conflicts. - ---- - -## Database Standards - -### Table Names - -```php -$wpdb->prefix . 'sureforms_entries' -$wpdb->prefix . 'sureforms_payments' -``` - -**Always use `$wpdb->prefix`**, never hardcode `wp_`. - -### Queries - -**Always use prepared statements:** -```php -// ✅ Good -$wpdb->get_results( - $wpdb->prepare( - "SELECT * FROM {$wpdb->prefix}sureforms_entries WHERE id = %d", - $entry_id - ) -); - -// ❌ Bad -$wpdb->query( "DELETE FROM wp_sureforms_entries WHERE id = $entry_id" ); -``` - ---- - -## Git Commit Messages - -**Format:** -``` -type(scope): brief description - -Longer explanation if needed. - -Co-Authored-By: Name <email> -``` - -**Types:** -- `feat`: New feature -- `fix`: Bug fix -- `docs`: Documentation -- `style`: Formatting, no code change -- `refactor`: Code restructuring -- `test`: Adding tests -- `chore`: Build/tooling - -**Example:** -``` -feat(payments): add PayPal subscription support - -- Implement PayPal billing agreement API -- Add webhook handler for subscription events -- Update admin UI for PayPal subscriptions - -Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> -``` - ---- - -## File Organization - -**One class per file:** -``` -inc/payments/stripe/stripe-helper.php → class Stripe_Helper -``` - -**Group related functionality:** -``` -inc/payments/ -├── payment-helper.php # Shared utilities -├── front-end.php # Public AJAX handlers -├── stripe/ -│ ├── stripe-helper.php -│ ├── stripe-webhook.php -│ └── admin-stripe-handler.php -└── admin/ - └── admin-handler.php -``` - ---- - -## Testing Standards - -**PHPUnit:** -```php -class Test_Form_Submit extends WP_UnitTestCase { - public function test_form_submission_saves_entry() { - $entry_id = srfm_submit_form( $data ); - $this->assertIsInt( $entry_id ); - } -} -``` - -**Playwright:** -```javascript -test('form submission works', async ({ page }) => { - await page.goto('/test-form/'); - await page.fill('[name="email"]', 'test@example.com'); - await page.click('button[type="submit"]'); - await expect(page.locator('.success-message')).toBeVisible(); -}); -``` - ---- - -## Code Review Checklist - -Before submitting PR: - -- [ ] Code follows WordPress/project standards -- [ ] All inputs sanitized -- [ ] All outputs escaped -- [ ] SQL queries use `prepare()` -- [ ] Nonces verified for AJAX/forms -- [ ] Capabilities checked for admin actions -- [ ] PHPDoc blocks added -- [ ] No PHP/JS errors in console -- [ ] Tested in latest WordPress version -- [ ] Tests pass: `composer test && npm run test:unit` -- [ ] Linting passes: `composer lint && npm run lint-js` - ---- - -**Automated Checks:** - -```bash -# PHP linting -composer lint # PHP_CodeSniffer - -# JS linting -npm run lint-js # ESLint - -# Auto-fix -composer format # phpcbf -npm run lint-js:fix # ESLint --fix -``` diff --git a/internal-docs/faq.md b/internal-docs/faq.md deleted file mode 100644 index 8e174c45f..000000000 --- a/internal-docs/faq.md +++ /dev/null @@ -1,1003 +0,0 @@ -# Frequently Asked Questions - -**Version:** 2.5.0 - ---- - -## General Questions - -### What is SureForms? - -SureForms is an AI-powered WordPress form builder that uses Gutenberg blocks. - -**Key features:** -- AI form generation (describe in plain language, get complete form) -- Built-in payments (Stripe in Free, PayPal in Pro) -- Mobile-first design -- Native WordPress (no proprietary builder) -- Custom database tables (not post meta) - -**Target users:** Website owners, designers, developers who need forms without complexity. - ---- - -### What's the difference between Free and Pro? - -**Free (sureforms):** -- Unlimited forms & submissions -- All 15+ field types -- Stripe payments (one-time & subscriptions) -- Email notifications -- Spam protection (reCAPTCHA, Honeypot) -- Form analytics -- CSV export - -**Pro (sureforms-pro):** -- **All Free features, plus:** -- PayPal payments -- 24+ native integrations (Mailchimp, HubSpot, Salesforce, etc.) -- Conditional logic -- Multi-step & conversational forms -- User registration & login -- PDF generation -- File upload fields -- Priority support (< 24hr response) - -**Pricing:** -- Free: $0 (WordPress.org) -- Pro: $99-$299/year (3 sites to unlimited) - ---- - -### Can I use SureForms on multiple sites? - -**Free:** Yes, unlimited sites. - -**Pro:** Depends on license: -- Essential ($99/year): 3 sites -- Plus ($199/year): 20 sites -- Agency ($299/year): Unlimited sites - -**License activation:** -- Enter license key in SureForms → Settings → License -- Deactivate from one site to move to another -- All sites must be owned by you (not for client sites unless Agency plan) - ---- - -### Is SureForms GDPR compliant? - -**Yes.** SureForms provides tools for GDPR compliance: - -**Features:** -- GDPR checkbox field (explicit consent) -- Data export (users can request their data) -- Data deletion (users can request deletion) -- No third-party data sharing (unless you enable integrations) -- Privacy policy link support - -**What you must do:** -1. Add GDPR checkbox to forms collecting personal data -2. Link to your privacy policy -3. Honor data export/deletion requests -4. Configure data retention policies - -**Data storage:** -- Submissions stored in your WordPress database -- No data sent to SureForms servers (AI calls go through middleware but don't store data) -- Payment data stored encrypted (PCI-compliant) - ---- - -### Does SureForms work with my theme? - -**Yes.** SureForms is designed to work with any properly-coded WordPress theme. - -**Tested with:** -- Astra -- GeneratePress -- Kadence -- Neve -- Blocksy -- Twenty Twenty-Three/Four -- Page builder themes (Elementor, Divi, Beaver Builder) - -**If you experience styling conflicts:** -1. Check [troubleshooting guide](troubleshooting.md#form-breaks-after-theme-update) -2. Use SureForms → Settings → Custom CSS to override -3. Contact support with theme name - ---- - -### Can I use SureForms with page builders? - -**Yes.** SureForms works with: -- **Gutenberg** (native, best experience) -- **Elementor** (via shortcode or WordPress widget) -- **Divi** (via shortcode or code module) -- **Beaver Builder** (via WordPress widget) -- **Bricks** (via shortcode or WordPress element) - -**How to add:** - -**Elementor:** -1. Add "Shortcode" widget -2. Paste: `[sureforms id="123"]` -3. Replace 123 with your form ID - -**Divi:** -1. Add "Code" module -2. Paste shortcode -3. Save - -**Beaver Builder:** -1. Add "WordPress Widget" module -2. Select "SureForms" widget -3. Choose form - ---- - -## Technical Questions - -### What are the system requirements? - -**Minimum:** -- WordPress 6.4+ -- PHP 7.4+ -- MySQL 5.6+ or MariaDB 10.1+ -- HTTPS (for payments) - -**Recommended:** -- WordPress 6.6+ -- PHP 8.1+ -- MySQL 8.0+ or MariaDB 10.6+ -- 256MB PHP memory limit -- Object caching (Redis or Memcached) - -**Browser support:** -- Chrome 90+ -- Firefox 88+ -- Safari 14+ -- Edge 90+ - ---- - -### Does SureForms slow down my site? - -**No.** SureForms is optimized for performance: - -**Impact on page load:** -- Additional CSS: ~15KB (minified) -- Additional JS: ~25KB (minified, deferred) -- Total: ~40KB additional assets - -**Database queries:** -- Form render: 2-3 queries (cached) -- Form submission: 4-5 queries (optimized with indexes) -- No N+1 query issues - -**Performance features:** -- Lazy loading for non-critical assets -- Custom database tables (not post meta) -- Query optimization (indexed columns) -- Minified & concatenated assets -- CDN-friendly (versioned static files) - -**Benchmarks:** -- Lighthouse score: 95+ (with proper hosting) -- Time to Interactive: < 2 seconds on 3G -- Form submission latency: < 500ms - ---- - -### Can I export my data? - -**Yes.** Multiple export options: - -**Entries export:** -1. Go to SureForms → Entries -2. Select entries (or "Select All") -3. Click "Export to CSV" -4. Download file - -**Format:** CSV with all fields as columns - -**Form export:** -- Export form as JSON (Settings → Export) -- Import on another site (Settings → Import) - -**Database export:** -```bash -# Export all SureForms data -wp db export sureforms-backup.sql --tables=wp_sureforms_entries,wp_sureforms_payments,wp_sureforms_integrations -``` - ---- - -### How do I migrate forms to another site? - -**Method 1: Export/Import (Recommended)** - -**On old site:** -1. Go to SureForms → Forms -2. Hover over form → "Export" -3. Download JSON file - -**On new site:** -1. Install SureForms (same version) -2. Go to SureForms → Import -3. Upload JSON file -4. Map any dependencies (integrations, etc.) - -**Method 2: Database migration** - -```bash -# On old site -wp db export sureforms-data.sql --tables=wp_sureforms_entries,wp_sureforms_payments - -# Transfer file to new site - -# On new site -wp db import sureforms-data.sql - -# Update URLs in entries (if domain changed) -wp search-replace 'https://oldsite.com' 'https://newsite.com' wp_sureforms_entries -``` - ---- - -### Can I use SureForms offline / localhost? - -**Yes, with limitations:** - -**Works offline:** -- Form creation -- Form editing -- Local submissions (saved to database) - -**Requires internet:** -- AI form generation (external API) -- Payment processing (Stripe/PayPal API) -- Native integrations (Mailchimp, HubSpot, etc.) -- Google Fonts (if used) -- reCAPTCHA (if enabled) - -**Development setup:** -```bash -# Use Local by Flywheel or similar -# Or manual setup: -cd ~/Sites/my-wordpress-site -wp core download -wp core config --dbname=sureforms_dev --dbuser=root -wp core install --url=http://localhost:8080 --title="Dev Site" -wp plugin install sureforms --activate -``` - ---- - -## Payment Questions - -### Which payment gateways are supported? - -**Free plugin:** -- Stripe (one-time payments & subscriptions) - -**Pro plugin:** -- Stripe (one-time payments & subscriptions) -- PayPal (one-time payments & subscriptions) - -**Coming soon:** -- Razorpay (India) -- Mollie (Europe) - -**Not planned:** -- WooCommerce (use WooCommerce for full e-commerce) -- Square (low demand) -- Bitcoin/crypto (regulatory complexity) - ---- - -### How do I test payments before going live? - -**Stripe test mode:** - -1. Get test API keys: - - Go to https://dashboard.stripe.com/test/apikeys - - Copy "Publishable key" (pk_test_...) - - Copy "Secret key" (sk_test_...) - -2. In SureForms: - - Go to Settings → Payments → Stripe - - Enable "Test Mode" - - Paste test keys - - Save - -3. Test with card: - - Card number: `4242 4242 4242 4242` - - Expiry: Any future date (e.g., 12/28) - - CVC: Any 3 digits (e.g., 123) - -4. Verify in Stripe dashboard: - - Go to Payments → Test Mode - - See your test payment - -**PayPal sandbox (Pro):** - -1. Create sandbox account: - - Go to https://developer.paypal.com/ - - Sign in with PayPal account - - Create sandbox business & buyer accounts - -2. Get sandbox credentials: - - Apps & Credentials → Sandbox - - Copy Client ID & Secret - -3. In SureForms: - - Settings → Payments → PayPal - - Enable "Sandbox Mode" - - Paste credentials - - Save - -4. Test with sandbox buyer account - ---- - -### How are payment fees handled? - -**SureForms fees:** $0 (we charge nothing) - -**Gateway fees:** - -**Stripe:** -- Standard: 2.9% + $0.30 per transaction -- International cards: +1.5% -- Currency conversion: +1% -- (Varies by country, see Stripe pricing) - -**PayPal:** -- Standard: 2.9% + $0.30 per transaction -- International: +1.5% -- (Varies by country, see PayPal pricing) - -**Who pays fees:** -- Fees deducted from amount received -- Example: $100 charge → You receive ~$97 - -**Passing fees to customer:** -- Not built-in (would require payment gateway approval) -- Workaround: Add fee as separate amount field - ---- - -### Can I accept subscriptions? - -**Yes** (both Stripe and PayPal). - -**Setup:** - -1. Create form with Payment block -2. Payment block settings: - - Payment Type: ● Subscription - - Interval: Monthly/Yearly/Weekly - - Amount: [price] - -3. Customer pays once, charged automatically recurring - -**Management:** - -**Stripe:** -- View subscriptions: Stripe Dashboard → Subscriptions -- Cancel: Click subscription → "Cancel subscription" -- Refund: Not automatic, manual refund in Stripe - -**PayPal (Pro):** -- View subscriptions: PayPal Dashboard → Subscriptions -- Cancel: Click subscription → "Cancel" - -**Customer cancellation:** -- Customers can cancel in Stripe/PayPal customer portal -- You can provide link in confirmation email - ---- - -## AI & Form Generation Questions - -### How does AI form generation work? - -**Technical flow:** - -``` -User enters prompt ("job application form") - ↓ -SureForms sends to AI middleware - ↓ -Middleware calls GPT-4 API - ↓ -GPT-4 returns structured JSON (field types, labels, validations) - ↓ -Middleware sends back to SureForms - ↓ -SureForms creates Gutenberg blocks from JSON - ↓ -Form appears in editor, ready to customize -``` - -**What data is sent:** -- Your prompt ("create a contact form") -- Form context (if modifying existing form) -- No user data, no submissions, no PII - -**What data is stored:** -- None. AI responses are not logged. -- Form configuration stored in WordPress database only - -**Privacy:** -- AI calls routed through SureForms middleware (not direct to OpenAI) -- No data retention -- No training on your data - ---- - -### Can I use AI without internet? - -**No.** AI requires external API call to GPT-4. - -**Offline alternatives:** -- Create forms manually (no AI) -- Use templates (no AI needed) -- Import pre-made forms - ---- - -### What languages does AI support? - -**Prompts:** Any language GPT-4 supports (100+ languages) - -**Field labels:** Generated in same language as prompt - -**Example:** -- Prompt (Spanish): "formulario de contacto" -- Result: Fields with Spanish labels ("Nombre", "Correo electrónico", etc.) - -**Limitations:** -- Some languages better than others (English, Spanish, French, German excellent) -- Less common languages may have lower quality - ---- - -## Integration Questions (Pro) - -### What integrations are available? - -**24+ native integrations:** - -**Email Marketing:** -- Mailchimp -- Brevo (Sendinblue) -- ActiveCampaign -- ConvertKit -- MailerLite - -**CRM:** -- HubSpot -- Salesforce -- Zoho CRM -- Pipedrive - -**Communication:** -- Slack -- Telegram -- Discord (coming soon) - -**Productivity:** -- Google Sheets -- Airtable (coming soon) -- Notion (coming soon) - -**WordPress Plugins:** -- FluentCRM (native) -- OttoKit (SureTriggers) - -**Webhooks:** -- Custom webhooks (POST to any URL) - -**Not included:** -- Zapier (use webhooks instead) -- Make/Integromat (use webhooks) - ---- - -### How do I connect Mailchimp? - -**Setup (OAuth):** - -1. Go to SureForms → Settings → Integrations -2. Click "Mailchimp" → "Connect" -3. Redirected to Mailchimp → "Allow access" -4. Redirected back, connection confirmed - -**Use in form:** - -1. Edit form -2. Settings → Actions → "Add Action" -3. Select "Mailchimp" -4. Choose audience (list) -5. Map fields: - - Email field → Mailchimp EMAIL - - Name field → Mailchimp FNAME -6. Save - -**On form submission:** -- Contact added to Mailchimp list automatically -- Tags applied (if configured) -- Double opt-in email sent (if enabled in Mailchimp) - ---- - -### Can I send form data to custom webhook? - -**Yes** (Pro feature). - -**Setup:** - -1. Form settings → Actions → "Add Action" -2. Select "Webhook" -3. Configure: - - URL: `https://yourapi.com/endpoint` - - Method: POST (or GET, PUT) - - Headers: (optional, e.g., `Authorization: Bearer token`) -4. Save - -**Payload format:** - -```json -{ - "form_id": 123, - "entry_id": 456, - "fields": { - "email": "user@example.com", - "name": "John Doe", - "message": "Hello!" - }, - "meta": { - "submitted_at": "2026-02-12 10:30:00", - "user_ip": "192.168.1.1", - "user_agent": "Mozilla/5.0..." - } -} -``` - -**Retry logic:** -- Failed webhooks retried 3 times -- Exponential backoff (1s, 5s, 25s) -- After 3 failures, logged as error - ---- - -## Security & Privacy Questions - -### Is SureForms secure? - -**Yes.** Security is a core priority. - -**Security measures:** - -**Input sanitization:** -- All user input sanitized before storage -- WordPress functions: `sanitize_text_field()`, `sanitize_email()`, etc. -- Custom sanitization for complex fields - -**Output escaping:** -- All output escaped before rendering -- `esc_html()`, `esc_attr()`, `esc_url()` used throughout -- Prevents XSS attacks - -**SQL injection prevention:** -- All database queries use `$wpdb->prepare()` -- No direct SQL concatenation -- Custom database class with built-in protection - -**CSRF protection:** -- Nonce verification on all AJAX/REST endpoints -- `wp_verify_nonce()` checked before state-changing operations - -**Authorization:** -- Capability checks: `current_user_can()` -- Admin actions require `manage_options` capability -- User-specific data access controlled - -**Payment security:** -- PCI DSS compliant (no card storage) -- Stripe/PayPal handle sensitive data -- API credentials encrypted at rest (AES-256) - -**File uploads (Pro):** -- MIME type validation (server-side) -- File size limits enforced -- Path traversal prevention -- Disallowed file types: `.php`, `.js`, `.exe`, etc. - ---- - -### Where is my data stored? - -**Form submissions:** -- Your WordPress database -- Table: `wp_sureforms_entries` -- No data sent to SureForms servers - -**Payment data:** -- Stripe: Stored in Stripe (not in WordPress) -- PayPal: Stored in PayPal (not in WordPress) -- WordPress stores: Transaction ID, amount, status only - -**Integration credentials (Pro):** -- WordPress database -- Table: `wp_sureforms_integrations` -- Encrypted with AES-256 -- Encryption key in `wp-config.php` (recommended) - -**AI prompts:** -- Sent to AI middleware → OpenAI GPT-4 -- Not stored or logged -- Not used for training - ---- - -### Can users delete their data? - -**Yes** (GDPR requirement). - -**Manual deletion:** - -1. User requests deletion via email -2. Admin finds submissions by email -3. Delete from SureForms → Entries - -**Automatic (Pro):** -- Data retention policy: Auto-delete entries after X days -- Settings → Privacy → Data Retention -- Configure per form or globally - -**What gets deleted:** -- Entry data (all fields) -- Entry metadata (IP, user agent) -- File uploads (if any) - -**What's preserved:** -- Form configuration (for re-use) -- Analytics (anonymized counts only) - ---- - -## Troubleshooting Questions - -### My forms aren't showing on the frontend. Why? - -**Common causes:** - -**1. Form not published:** -- Check form status in SureForms → Forms -- Must be "Published" not "Draft" - -**2. Form not embedded:** -- Add SureForms block to page -- Select your form from dropdown -- Or use shortcode: `[sureforms id="123"]` - -**3. Theme conflict:** -- Try default theme: `wp theme activate twentytwentythree` -- If works → Theme issue, contact theme developer - -**4. JavaScript disabled:** -- Check browser console for errors -- Disable other plugins to find conflict - -**Debug:** -```bash -# Enable debugging -wp config set WP_DEBUG true --raw -wp config set WP_DEBUG_LOG true --raw - -# Check debug log -tail -f wp-content/debug.log -``` - -See [troubleshooting guide](troubleshooting.md) for more. - ---- - -### Form submissions aren't saving. What's wrong? - -**Check:** - -**1. Database tables exist:** -```bash -wp db query "SHOW TABLES LIKE '%sureforms%';" -``` - -Should show `wp_sureforms_entries` table. - -**2. Database permissions:** -```bash -wp db query "SHOW GRANTS;" -``` - -User must have INSERT privilege. - -**3. Nonce verification:** -- If using caching, exclude AJAX endpoints -- WP Super Cache: Exclude `/wp-admin/admin-ajax.php` - -**4. Debug log:** -```bash -tail -f wp-content/debug.log -# Submit form, watch for errors -``` - -See [troubleshooting: submissions not saving](troubleshooting.md#form-submissions-not-saving) - ---- - -### Email notifications aren't sending. Help! - -**Diagnose:** - -```bash -# Test WordPress mail function -wp eval "wp_mail('your@email.com', 'Test', 'Testing');" -``` - -If no email received → Server mail() disabled. - -**Fix:** - -**Install SMTP plugin:** -```bash -wp plugin install wp-mail-smtp --activate -``` - -**Configure with:** -- Gmail -- SendGrid -- Mailgun -- Amazon SES - -**Check spam folder:** -- Default WordPress sender: `wordpress@yourdomain.com` -- Often flagged as spam -- SMTP fixes this - -See [troubleshooting: emails not sending](troubleshooting.md#email-notifications-not-sending) - ---- - -## Customization Questions - -### Can I customize form styling? - -**Yes.** Multiple options: - -**Option 1: Settings panel (no code):** -1. Edit form -2. Settings sidebar → Design -3. Customize: - - Colors (background, text, buttons) - - Typography (fonts, sizes) - - Spacing (padding, margins) - - Border radius - -**Option 2: Custom CSS:** -1. SureForms → Settings → Custom CSS -2. Add your styles: -```css -.srfm-form { - background: #f9f9f9; - padding: 30px; - border-radius: 8px; -} - -.srfm-form input { - border: 2px solid #333; -} -``` - -**Option 3: Theme stylesheet:** - -Add to `style.css`: -```css -.srfm-form { /* Your styles */ } -``` - -**Option 4: Page builder:** - -Use page builder's CSS editor (if using Elementor/Divi). - ---- - -### Can I add custom fields? - -**Yes** (requires development). - -**Process:** - -1. Create block folder: `inc/blocks/my-field/` -2. Register block: `block.php` -3. Create React component: `src/blocks/my-field/edit.js` -4. Add sanitization: `inc/helper.php` -5. Add validation: `inc/field-validation.php` - -**Example:** See [onboarding guide](onboarding.md#step-2-create-block-structure) - -**Pre-built custom fields (Pro):** -- Star rating -- Signature -- File upload -- Date/time picker - ---- - -### Can I change the submit button text? - -**Yes.** - -**Per form:** -1. Edit form -2. Click submit button block -3. Settings sidebar → Button Text -4. Change text -5. Update form - -**Globally:** - -Add to `functions.php`: -```php -add_filter('sureforms_submit_button_text', function($text) { - return __('Send Message', 'sureforms'); -}); -``` - ---- - -## Business & Licensing Questions - -### Can I use SureForms on client sites? - -**Free:** Yes, unlimited sites. - -**Pro:** -- **Agency license required** ($299/year, unlimited sites) -- Essential ($99/year, 3 sites) - only for your own sites -- Plus ($199/year, 20 sites) - only for your own sites - -**License terms:** -- You must own the sites (not client-owned sites with Essential/Plus) -- Agency license allows client sites -- Each site needs separate activation - ---- - -### Can I white-label SureForms? - -**Not officially.** - -**What you can do:** -- Remove branding from admin (CSS) -- Custom email footer (replace "Powered by SureForms") -- Custom confirmation messages - -**What you can't do:** -- Remove copyright notices from code -- Rebrand and resell as your own product -- Remove attribution from free plugin - -**Enterprise white-label:** -- Contact sales for custom licensing -- Available for high-volume agencies - ---- - -### What's your refund policy? - -**14-day money-back guarantee** (Pro licenses) - -**Refund eligibility:** -- Purchased within last 14 days -- Tried to use but encountered issues -- Support unable to resolve - -**Not eligible:** -- After 14 days -- Changed mind (not technical issue) -- Purchased wrong license (can upgrade instead) - -**Process:** -1. Contact support: support@sureforms.com -2. Describe issue (we'll try to help first) -3. If unresolved, refund processed within 3-5 business days - ---- - -### How long do I get updates? - -**Free:** Lifetime updates. - -**Pro:** -- Updates: For duration of license (1 year) -- Renewals: Discounted renewal price after year 1 -- If license expires: Plugin continues working, no new updates - -**Version compatibility:** -- Major updates: Included -- Security updates: Prioritized -- Feature updates: Based on roadmap - ---- - -## Developer Questions - -### Is the code open source? - -**Free plugin:** Yes. -- License: GPL v2 or later -- GitHub: https://github.com/brainstormforce/sureforms - -**Pro plugin:** No. -- Proprietary license -- Source code visible but not redistributable - ---- - -### Can I contribute to SureForms? - -**Yes!** We welcome contributions. - -**How to contribute:** - -1. Fork repo: https://github.com/brainstormforce/sureforms -2. Create branch: `git checkout -b feat/my-feature` -3. Make changes -4. Run tests: `composer test && npm run test:unit` -5. Submit PR - -**Contribution guidelines:** -- Follow [coding standards](coding-standards.md) -- Add tests for new features -- Update docs if needed -- Sign off commits: `Co-Authored-By: Your Name <email>` - ---- - -### Where can I find the API documentation? - -**API docs:** [apis.md](apis.md) - -**Key resources:** -- REST endpoints: [apis.md#rest-api](apis.md#rest-api) -- Hooks & filters: [apis.md#hooks--filters](apis.md#hooks--filters) -- JavaScript APIs: [apis.md#javascript-apis](apis.md#javascript-apis) -- Database APIs: [apis.md#database-apis](apis.md#database-apis) - -**Code examples:** [ai-agent-guide.md](ai-agent-guide.md) - ---- - -## Need More Help? - -**Documentation:** -- [README.md](README.md) - Quick start -- [Troubleshooting](troubleshooting.md) - Common problems -- [Onboarding](onboarding.md) - Developer guide -- [Glossary](glossary.md) - Technical terms - -**Support:** -- **Free users:** WordPress.org forum, GitHub issues -- **Pro users:** https://support.brainstormforce.com/ (< 24hr response) - -**Community:** -- Facebook: https://www.facebook.com/groups/surecart -- GitHub Discussions: https://github.com/brainstormforce/sureforms/discussions - ---- - -**Next:** [Glossary](glossary.md) diff --git a/internal-docs/glossary.md b/internal-docs/glossary.md deleted file mode 100644 index 440e34b70..000000000 --- a/internal-docs/glossary.md +++ /dev/null @@ -1,723 +0,0 @@ -# Glossary - -**Version:** 2.5.0 - ---- - -## A - -### AJAX (Asynchronous JavaScript and XML) -Technique for updating parts of a page without full reload. Used in SureForms for form submissions, payment processing, and file uploads. - -**Example:** -```javascript -// AJAX request to submit form -wp.ajax.post('srfm_submit_form', { data: formData }); -``` - -### API (Application Programming Interface) -Set of functions and methods for interacting with software. SureForms provides REST API, database API, and JavaScript API. - -**Types in SureForms:** -- **REST API:** HTTP endpoints for external access -- **Database API:** Methods to query entries/payments -- **JavaScript API:** Frontend form manipulation - -### Attribute (Gutenberg) -Data stored with a block. In SureForms, attributes define field configuration (label, required, placeholder, etc.). - -**Example:** -```json -{ - "label": "Email", - "required": true, - "placeholder": "name@example.com" -} -``` - ---- - -## B - -### Block (Gutenberg) -Reusable component in WordPress editor. SureForms forms are composed of blocks (Email block, Textarea block, Submit button block, etc.). - -**Types:** -- **Static blocks:** Rendered client-side (React) -- **Dynamic blocks:** Rendered server-side (PHP) - -### Block Editor -WordPress's editing interface (formerly called "Gutenberg"). Native to WordPress 5.0+. - -**Why SureForms uses it:** -- Users already familiar -- No proprietary builder to learn -- Future-proof (WordPress core) - ---- - -## C - -### Capability -WordPress permission level. SureForms checks capabilities before allowing admin actions. - -**Common capabilities:** -- `manage_options` - Admin settings access -- `edit_posts` - Create forms (default) -- `read` - View forms (logged-in users) - -**Example:** -```php -if (current_user_can('manage_options')) { - // Allow admin action -} -``` - -### Conditional Logic (Pro) -Show or hide form fields based on user answers. Example: Show "Dietary restrictions" only if user selects "Yes" to "Will you attend?" - -**Types:** -- **Show when:** Display field if condition matches -- **Hide when:** Hide field if condition matches -- **AND/OR logic:** Multiple conditions combined - -### Conversational Form (Pro) -Form that displays one question at a time, like a chat conversation. Increases engagement and completion rates. - -**Benefits:** -- Less overwhelming than long forms -- Higher completion rate (3x vs single-page) -- Better mobile experience - -### CSRF (Cross-Site Request Forgery) -Attack where malicious site tricks user into submitting request to your site. SureForms prevents with nonce verification. - -**Example attack (prevented):** -```html -<!-- Malicious site --> -<form action="https://yoursite.com/wp-admin/admin-ajax.php" method="POST"> - <input name="action" value="srfm_delete_form"> - <input name="form_id" value="123"> -</form> -<script>document.forms[0].submit();</script> -``` - -### CSV (Comma-Separated Values) -File format for spreadsheet data. SureForms can export form entries as CSV. - -**Example:** -``` -Name,Email,Message -John Doe,john@example.com,Hello! -Jane Smith,jane@example.com,Question about... -``` - ---- - -## D - -### Database Table -MySQL table storing structured data. SureForms uses 4 custom tables: -- `wp_sureforms_entries` - Form submissions -- `wp_sureforms_payments` - Payment records -- `wp_sureforms_integrations` - OAuth credentials -- `wp_sureforms_save_resume` - Draft submissions (Pro) - -**Why custom tables?** -- Faster queries (indexed columns) -- More efficient than post meta -- Easier to export - -### Dynamic Block -Gutenberg block rendered server-side (PHP). Most SureForms field blocks are dynamic for security (server-side validation). - -**Example:** -```php -register_block_type('sureforms/email', [ - 'render_callback' => 'render_email_field' -]); -``` - ---- - -## E - -### Encryption -Converting data to unreadable format. SureForms encrypts OAuth credentials and API keys. - -**Algorithm:** AES-256-CTR - -**Example:** -```php -$encrypted = Encryption::encrypt($api_key); -// Stored in database: "base64encodedIV.encryptedData" -``` - -### Entry -Single form submission. Stored in `wp_sureforms_entries` table. - -**Contains:** -- Form ID -- User ID (if logged in) -- Field values (JSON) -- Metadata (IP, user agent, timestamp) -- Status (published, spam, trash) - -### Escaping (Output Escaping) -Converting special characters to prevent XSS. SureForms escapes all user data before display. - -**Functions:** -- `esc_html()` - For HTML content -- `esc_attr()` - For HTML attributes -- `esc_url()` - For URLs -- `esc_js()` - For JavaScript strings - -**Example:** -```php -echo '<div>' . esc_html($user_input) . '</div>'; -``` - ---- - -## F - -### Field Type -Type of input field (email, text, number, etc.). SureForms has 15+ field types. - -**Common types:** -- Text, Email, URL, Textarea -- Number, Phone -- Multiple Choice, Checkbox, Dropdown -- Address, Upload (Pro) - -### Filter (WordPress Hook) -Function that modifies data. SureForms provides 30+ filters for customization. - -**Example:** -```php -add_filter('sureforms_email_subject', function($subject, $form_id) { - return "[Form $form_id] $subject"; -}, 10, 2); -``` - ---- - -## G - -### GDPR (General Data Protection Regulation) -European privacy law. SureForms provides GDPR-compliance features (consent checkbox, data export/deletion). - -**Requirements:** -- Explicit consent for data collection -- Right to access data (export) -- Right to deletion -- Privacy policy link - -### Gutenberg -WordPress's block editor (officially called "Block Editor"). Named after Johannes Gutenberg, inventor of printing press. - -**Why "Gutenberg"?** -- Revolutionized content creation (like printing press) -- Blocks are reusable components - ---- - -## H - -### Honeypot -Anti-spam technique using hidden field. Bots fill all fields (including hidden), revealing themselves. - -**How it works:** -```html -<input type="text" name="srfm-honeypot" style="display:none"> -<!-- Bots fill this, real users don't --> -``` - -**SureForms logic:** -```php -if (!empty($_POST['srfm-honeypot'])) { - // Spam detected -} -``` - -### Hook (WordPress) -Point where developers can inject custom code. Two types: actions and filters. - -**SureForms hooks:** -- 50+ action hooks (e.g., `sureforms_after_entry_save`) -- 30+ filter hooks (e.g., `sureforms_email_template`) - ---- - -## I - -### Integration (Native Integration) -Connection to third-party service. SureForms Pro has 24+ native integrations (Mailchimp, HubSpot, etc.). - -**Types:** -- **OAuth:** User authorizes connection (Mailchimp, Google) -- **API Key:** User provides key from service -- **Webhook:** SureForms sends POST request to URL - -### Instant Form -SureForms feature allowing forms to be published with unique URL (no embedding needed). - -**Example URL:** -``` -https://yoursite.com/?srfm_form=abc123 -``` - -**Use cases:** -- Email signatures -- Social media links -- QR codes - ---- - -## J - -### JSON (JavaScript Object Notation) -Data format for structured information. SureForms stores entry data and block attributes as JSON. - -**Example entry data:** -```json -{ - "email": "john@example.com", - "name": "John Doe", - "message": "Hello!" -} -``` - ---- - -## L - -### Localization (l10n) -Adapting software for specific language/region. SureForms supports translation. - -**Files:** -- `languages/sureforms-{locale}.po` - Translation strings -- `languages/sureforms-{locale}.mo` - Compiled translations - -**Functions:** -```php -__('Email', 'sureforms'); // Translate string -_e('Submit', 'sureforms'); // Translate and echo -``` - ---- - -## M - -### Middleware -Intermediate server between client and API. SureForms uses middleware for AI form generation (client → middleware → OpenAI). - -**Why middleware?** -- Hides API keys from client -- Rate limiting -- Request logging -- Caching - -### Multi-Step Form (Pro) -Form split into multiple pages/steps. Improves completion rate by reducing cognitive load. - -**Example:** -``` -Step 1: Personal Information (name, email) -Step 2: Address Details -Step 3: Payment Information -``` - ---- - -## N - -### Namespace -PHP feature to organize code and prevent name conflicts. SureForms uses namespaces. - -**Example:** -```php -namespace SRFM\Inc\Database\Tables; - -class Entries { - // ... -} -``` - -### Native Integration -Integration built into SureForms (not requiring Zapier or external connector). - -**Examples:** -- Mailchimp (OAuth) -- HubSpot (OAuth) -- Slack (Webhook URL) - -### Nonce (Number Used Once) -Security token to verify request came from your site. SureForms verifies nonces on all AJAX/REST requests. - -**Example:** -```php -// Generate nonce -$nonce = wp_create_nonce('srfm_submit_form'); - -// Verify nonce -if (!wp_verify_nonce($_POST['nonce'], 'srfm_submit_form')) { - die('Invalid nonce'); -} -``` - ---- - -## O - -### OAuth (Open Authorization) -Protocol for secure authorization. Used by SureForms integrations (Mailchimp, HubSpot, etc.). - -**Flow:** -1. User clicks "Connect to Mailchimp" -2. Redirected to Mailchimp login -3. User approves access -4. Mailchimp redirects back with token -5. SureForms stores encrypted token - ---- - -## P - -### Payment Gateway -Service that processes credit card payments. SureForms supports Stripe and PayPal. - -**Comparison:** -- **Stripe:** 2.9% + $0.30, better for US/Europe -- **PayPal:** 2.9% + $0.30, more global recognition - -### Payment Intent (Stripe) -Stripe object representing payment attempt. Created before customer enters card details. - -**States:** -- `requires_payment_method` - Awaiting card -- `requires_confirmation` - Card entered, needs confirm -- `succeeded` - Payment successful -- `canceled` - Payment canceled - -### PCI DSS (Payment Card Industry Data Security Standard) -Security standard for handling credit card data. SureForms is PCI-compliant (never stores card data). - -**Compliance:** -- Card data sent directly to Stripe/PayPal -- SureForms only stores transaction ID -- No PAN (Primary Account Number) stored - -### Placeholder -Example text shown in empty input field. Disappears when user types. - -**Example:** -```html -<input type="email" placeholder="name@example.com"> -``` - -**Accessibility note:** Never use placeholder as label (screen readers may miss it). - -### Post Meta -WordPress method for storing additional data with posts. SureForms **doesn't** use post meta (uses custom tables instead). - -**Why not post meta?** -- Slow queries (no indexes) -- Hard to search -- Not optimized for large datasets - -### Post Type (Custom Post Type) -WordPress content type. SureForms forms are stored as custom post type `sureforms_form`. - -**Advantages:** -- Uses WordPress admin UI -- Revision history -- Trash/restore functionality - ---- - -## R - -### reCAPTCHA -Google anti-spam service. SureForms supports reCAPTCHA v2 and v3. - -**Versions:** -- **v2:** "I'm not a robot" checkbox -- **v3:** Invisible, scores user behavior (0-1) - -**Setup:** -1. Get API keys from Google reCAPTCHA admin -2. Add to SureForms → Settings → Security -3. Enable on forms - -### REST API -HTTP API for accessing SureForms data. Used by frontend, mobile apps, integrations. - -**Base URL:** `/wp-json/sureforms/v1/` - -**Example endpoints:** -- `POST /submit-form` - Submit form -- `GET /forms/{id}` - Get form data -- `POST /generate-form` - AI form generation - -### RTL (Right-to-Left) -Text direction for languages like Arabic, Hebrew. SureForms supports RTL. - -**CSS:** -```css -.srfm-field { - margin-inline-start: 10px; /* Not margin-left */ -} -``` - ---- - -## S - -### Sanitization (Input Sanitization) -Cleaning user input to prevent attacks. SureForms sanitizes all input before storage. - -**Functions:** -- `sanitize_text_field()` - Remove HTML/PHP -- `sanitize_email()` - Validate email format -- `sanitize_url()` - Validate URL format -- `absint()` - Force integer - -**Example:** -```php -$email = sanitize_email($_POST['email']); -$id = absint($_POST['id']); -``` - -### Schema (Database Schema) -Structure of database table (columns, types, indexes). - -**Example (wp_sureforms_entries):** -```sql -CREATE TABLE wp_sureforms_entries ( - id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, - form_id BIGINT UNSIGNED NOT NULL, - user_id BIGINT UNSIGNED, - entry_data LONGTEXT NOT NULL, - status VARCHAR(20) DEFAULT 'published', - created_at DATETIME NOT NULL, - INDEX idx_form_id (form_id), - INDEX idx_created_at (created_at) -); -``` - -### Shortcode -WordPress feature for embedding content. SureForms forms can be embedded via shortcode. - -**Syntax:** -``` -[sureforms id="123"] -``` - -**Parameters:** -- `id` - Form ID (required) -- `title` - Show title (true/false) -- `description` - Show description (true/false) - -### SQL Injection -Attack injecting malicious SQL into queries. SureForms prevents with `$wpdb->prepare()`. - -**Vulnerable code (DON'T DO THIS):** -```php -$id = $_GET['id']; -$wpdb->query("DELETE FROM table WHERE id = $id"); -// Attack: ?id=1 OR 1=1 (deletes all records!) -``` - -**Safe code:** -```php -$id = absint($_GET['id']); -$wpdb->query($wpdb->prepare("DELETE FROM table WHERE id = %d", $id)); -``` - -### Subscription -Recurring payment. SureForms supports subscriptions via Stripe and PayPal. - -**Intervals:** -- Daily -- Weekly -- Monthly -- Yearly - ---- - -## T - -### Template (Form Template) -Pre-built form configuration. SureForms provides 100+ templates (contact, registration, survey, etc.). - -**Structure:** -```json -{ - "name": "Contact Form", - "fields": [ - { "type": "text", "label": "Name" }, - { "type": "email", "label": "Email" }, - { "type": "textarea", "label": "Message" } - ] -} -``` - -### Transient -WordPress temporary cache. SureForms uses transients for AI rate limiting and API responses. - -**Example:** -```php -// Store for 1 hour -set_transient('srfm_ai_rate_limit_' . $user_id, true, HOUR_IN_SECONDS); - -// Check -if (get_transient('srfm_ai_rate_limit_' . $user_id)) { - // Rate limited -} -``` - ---- - -## U - -### User Agent -String identifying browser/device. SureForms logs user agent for spam detection. - -**Example:** -``` -Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 -``` - ---- - -## V - -### Validation (Form Validation) -Checking if user input meets requirements. SureForms validates both client-side (JavaScript) and server-side (PHP). - -**Types:** -- **Required:** Field must not be empty -- **Format:** Email/URL must be valid -- **Range:** Number within min/max -- **Length:** String length constraints - -**Example:** -```php -if (empty($email) || !is_email($email)) { - $errors[] = 'Please enter a valid email'; -} -``` - ---- - -## W - -### Webhook -HTTP callback sent when event occurs. SureForms can send webhooks on form submission (Pro). - -**Flow:** -``` -User submits form - ↓ -SureForms processes submission - ↓ -Sends POST to webhook URL - ↓ -External service receives data -``` - -**Example payload:** -```json -{ - "event": "form_submit", - "form_id": 123, - "entry_id": 456, - "fields": { ... } -} -``` - -### WordPress Coding Standards (WPCS) -PHP coding style guide for WordPress. SureForms follows WPCS. - -**Key rules:** -- Tabs for indentation (not spaces) -- Yoda conditions: `if ( 'value' === $variable )` -- Braces required for all control structures -- Space after control keywords: `if (` not `if(` - -**Check compliance:** -```bash -composer lint -``` - ---- - -## X - -### XSS (Cross-Site Scripting) -Attack injecting malicious JavaScript into pages. SureForms prevents with output escaping. - -**Vulnerable code (DON'T DO THIS):** -```php -echo '<div>' . $_POST['name'] . '</div>'; -// Attack: <script>steal(document.cookie)</script> -``` - -**Safe code:** -```php -echo '<div>' . esc_html($_POST['name']) . '</div>'; -// Output: <script>steal(document.cookie)</script> -``` - ---- - -## Z - -### Zapier -Third-party automation service. SureForms doesn't have native Zapier integration but supports webhooks (which Zapier can consume). - -**Alternative:** Use SureForms webhooks to trigger Zapier zaps. - ---- - -## Acronyms Quick Reference - -| Acronym | Full Term | Meaning | -|---------|-----------|---------| -| AJAX | Asynchronous JavaScript and XML | Update page without reload | -| API | Application Programming Interface | Methods to interact with software | -| CSRF | Cross-Site Request Forgery | Attack tricking users into unwanted actions | -| CSV | Comma-Separated Values | Spreadsheet file format | -| GDPR | General Data Protection Regulation | EU privacy law | -| JSON | JavaScript Object Notation | Data format | -| OAuth | Open Authorization | Secure authorization protocol | -| PCI DSS | Payment Card Industry Data Security Standard | Credit card security | -| REST | Representational State Transfer | Web API architecture | -| RTL | Right-to-Left | Text direction (Arabic, Hebrew) | -| SQL | Structured Query Language | Database query language | -| URL | Uniform Resource Locator | Web address | -| WCAG | Web Content Accessibility Guidelines | Accessibility standards | -| WPCS | WordPress Coding Standards | PHP coding style | -| XSS | Cross-Site Scripting | JavaScript injection attack | - ---- - -## Common Abbreviations - -| Abbr | Full Term | -|------|-----------| -| Pro | SureForms Pro (premium plugin) | -| CRM | Customer Relationship Management | -| UI | User Interface | -| UX | User Experience | -| CPT | Custom Post Type | -| DB | Database | -| WP | WordPress | -| PHP | PHP: Hypertext Preprocessor | -| JS | JavaScript | -| CSS | Cascading Style Sheets | - ---- - -**Next:** [Maintenance](maintenance.md) diff --git a/internal-docs/maintenance.md b/internal-docs/maintenance.md deleted file mode 100644 index 71c2f2604..000000000 --- a/internal-docs/maintenance.md +++ /dev/null @@ -1,842 +0,0 @@ -# Documentation Maintenance Guide - -**Version:** 2.5.0 - ---- - -## Purpose - -This guide explains how to keep SureForms internal documentation accurate and useful. - -**Goal:** Documentation should always reflect current reality. - -**Principle:** Update docs when code changes, not as afterthought. - ---- - -## When to Update Documentation - -### Always Update - -**1. New Feature Added** -- Update: `architecture.md`, `apis.md`, `product-vision.md` -- Add: Code examples to `ai-agent-guide.md` -- Update: Onboarding guide if workflow changes - -**2. API Changes** -- Update: `apis.md` (new endpoints, hooks, parameters) -- Update: Code examples in all docs referencing changed API -- Mark deprecated APIs in `apis.md` - -**3. Database Schema Changes** -- Update: `architecture.md` (database section) -- Update: `codebase-map.md` (new files) -- Update: Migration guide if schema change requires migration - -**4. Security Fix** -- Update: `ai-agent-guide.md` (add to common pitfalls) -- Update: `troubleshooting.md` if fix addresses known issue -- Add example of vulnerable pattern to avoid - -**5. Breaking Changes** -- Update: `README.md` (migration guide) -- Update: `onboarding.md` (new workflows) -- Update: `faq.md` (address upgrade questions) - ---- - -### Update if Needed - -**6. Bug Fixes** -- Update: `troubleshooting.md` if common issue -- Add: To FAQ if frequently asked - -**7. Performance Improvements** -- Update: `architecture.md` if architecture changed -- Update: Benchmarks in `README.md` - -**8. UI/UX Changes** -- Update: `ui-and-copy.md` (new patterns, copy) -- Update: `onboarding.md` (user journeys) - ---- - -### Don't Update - -**9. Code Refactoring (No Behavior Change)** -- No doc update unless internal architecture significantly changed - -**10. Minor Copy Changes** -- No doc update unless it changes UX patterns - -**11. Version Bumps** -- Update version number at top of each doc -- That's it (unless other changes) - ---- - -## How to Update Documentation - -### Step 1: Identify Affected Docs - -**Use this decision tree:** - -``` -Did you change... - -┌─ Database schema? -│ └─> Update: architecture.md, codebase-map.md -│ -┌─ REST API? -│ └─> Update: apis.md, ai-agent-guide.md (examples) -│ -┌─ AJAX handlers? -│ └─> Update: apis.md -│ -┌─ Hooks/filters? -│ └─> Update: apis.md, ai-agent-guide.md (patterns) -│ -┌─ User-facing UI? -│ └─> Update: ui-and-copy.md, onboarding.md -│ -┌─ Security patterns? -│ └─> Update: ai-agent-guide.md, coding-standards.md -│ -┌─ Build process? -│ └─> Update: README.md, onboarding.md -│ -└─ New file/folder? - └─> Update: codebase-map.md -``` - ---- - -### Step 2: Read Existing Doc - -**Before editing:** -1. Read entire document -2. Identify outdated sections -3. Check for consistency with your changes - -**Don't:** -- Blindly add new section without reading context -- Create duplicate information -- Use different terminology than existing docs - ---- - -### Step 3: Make Minimal Changes - -**Best practices:** - -**Do:** -- Update only what changed -- Keep existing structure -- Match existing tone and style -- Add code examples if helpful - -**Don't:** -- Rewrite entire document (unless necessary) -- Change unrelated sections -- Reorganize without discussion -- Remove information (mark deprecated instead) - ---- - -### Step 4: Verify Examples Still Work - -**All code examples must be tested:** - -**PHP examples:** -```bash -# Create test file -cat > /tmp/test-example.php << 'EOF' -<?php -// Paste example code here -EOF - -# Check syntax -php -l /tmp/test-example.php -``` - -**JavaScript examples:** -```bash -# Check syntax (if using ESLint) -npx eslint /tmp/test-example.js -``` - -**Shell commands:** -```bash -# Test in safe environment -# Don't run destructive commands! -``` - -**WordPress CLI:** -```bash -# Test on development site -wp eval "$(cat /tmp/test-snippet.php)" -``` - ---- - -### Step 5: Update Cross-References - -**Check if other docs reference changed section:** - -```bash -# Search for references -cd internal-docs/ -grep -r "architecture.md#database" . -grep -r "\[Database Schema\]" . -``` - -**Update links if:** -- Section renamed -- Section moved -- File renamed - ---- - -### Step 6: Update Version Number - -**At top of each modified doc:** - -```markdown -**Version:** 2.5.1 # ← Change this -``` - -**When to increment version:** -- **Major (3.0.0):** Complete rewrite, major changes -- **Minor (2.6.0):** New sections, significant updates -- **Patch (2.5.1):** Small fixes, clarifications - -**Match plugin version:** -- Docs version should match plugin version -- Example: Plugin 2.5.0 → Docs 2.5.0 - ---- - -## Documentation Standards - -### File Organization - -**Keep this structure:** - -``` -internal-docs/ -├── README.md # Entry point, always read first -├── architecture.md # High-level system design -├── codebase-map.md # File structure reference -├── apis.md # Technical API reference -├── coding-standards.md # Code conventions -├── ai-agent-guide.md # AI-specific guidance -├── onboarding.md # Learning paths -├── product-vision.md # Product context -├── ui-and-copy.md # UX patterns -├── troubleshooting.md # Problem solutions -├── faq.md # Common questions -├── glossary.md # Term definitions -└── maintenance.md # This file -``` - -**Never:** -- Add files outside this structure -- Create subdirectories -- Rename existing files (without team approval) - ---- - -### Writing Style - -**Tone:** -- Clear, concise, direct -- Friendly but professional -- No marketing fluff - -**Format:** -- Short paragraphs (3-4 sentences max) -- Bullet points for lists -- Code blocks for examples -- Headers for navigation - -**Code Examples:** - -**✅ Good:** -```php -// Specific, realistic example -$entries = Entries::get_all([ - 'where' => [ - ['key' => 'form_id', 'value' => 123, 'compare' => '='] - ], - 'limit' => 20 -]); -``` - -**❌ Bad:** -```php -// Vague, generic -$data = SomeClass::get_stuff($args); -``` - ---- - -### Cross-Referencing - -**Internal links:** -```markdown -See [Architecture Guide](architecture.md) for details. -See [Database Schema](architecture.md#database-schema) for table structure. -``` - -**External links:** -```markdown -Read [WordPress Coding Standards](https://developer.wordpress.org/coding-standards/). -``` - -**Code references:** -```markdown -See `inc/form-submit.php:88-119` for nonce verification. -``` - ---- - -### Code Block Guidelines - -**Always specify language:** - -````markdown -```php -// PHP code here -``` - -```javascript -// JavaScript here -``` - -```bash -# Shell commands here -``` - -```sql --- SQL queries here -``` -```` - -**Include comments:** -```php -// Good: Explain what code does -$entries = Entries::get_all([ - 'where' => [ - ['key' => 'status', 'value' => 'published', 'compare' => '='] - ] -]); -``` - -**Show output if helpful:** -```bash -wp plugin list --status=active -# Output: -# sureforms active -# sureforms-pro active -``` - ---- - -## Deprecation Process - -**When removing features:** - -### Step 1: Mark as Deprecated - -**In code:** -```php -/** - * Old function. - * - * @deprecated 2.5.0 Use new_function() instead. - */ -function old_function() { - _deprecated_function(__FUNCTION__, '2.5.0', 'new_function'); - return new_function(); -} -``` - -**In docs:** -```markdown -## ~~Old Feature~~ (Deprecated) - -**Deprecated in:** 2.5.0 -**Removed in:** 3.0.0 -**Replacement:** [New Feature](#new-feature) - -This feature is deprecated and will be removed in version 3.0.0. -Use [New Feature](#new-feature) instead. - -~~Old documentation here...~~ -``` - ---- - -### Step 2: Update Migration Guide - -**In README.md:** - -```markdown -## Upgrading from 2.4.x to 2.5.0 - -### Breaking Changes - -**Old Feature Deprecated:** -- **What changed:** `old_function()` is now deprecated -- **Action required:** Replace with `new_function()` -- **Code example:** - ```php - // Old (deprecated) - old_function($data); - - // New (recommended) - new_function($data); - ``` -``` - ---- - -### Step 3: Remove After Major Version - -**On next major version (3.0.0):** -1. Remove deprecated code -2. Remove ~~strikethrough~~ docs -3. Update changelog - ---- - -## Changelog Management - -**Keep CHANGELOG.md updated:** - -### Format - -```markdown -# Changelog - -## [2.5.1] - 2026-02-15 - -### Added -- New REST endpoint: `/sureforms/v1/forms/{id}/duplicate` -- Support for custom date formats in email notifications - -### Changed -- Improved performance of entry queries (20% faster) -- Updated Stripe API to v2024-01-01 - -### Deprecated -- `old_function()` - Use `new_function()` instead - -### Fixed -- Bug where conditional logic didn't work with checkboxes -- Memory leak in AI form generation - -### Security -- Fixed XSS vulnerability in admin settings (CVE-2026-0001) - -## [2.5.0] - 2026-02-01 - -... -``` - -**Categories:** -- **Added:** New features -- **Changed:** Changes to existing features -- **Deprecated:** Features marked for removal -- **Removed:** Features removed -- **Fixed:** Bug fixes -- **Security:** Security fixes - ---- - -## Documentation Review Checklist - -**Before committing doc changes:** - -### Content -- [ ] Information is accurate (tested code examples) -- [ ] No outdated information (double-checked) -- [ ] Cross-references updated (links work) -- [ ] Version number updated -- [ ] Terminology consistent with other docs - -### Style -- [ ] Clear and concise (no fluff) -- [ ] Code examples formatted correctly -- [ ] Spelling and grammar correct -- [ ] Tone matches existing docs - -### Technical -- [ ] All code examples tested -- [ ] All commands verified (on dev environment) -- [ ] All links work (no 404s) -- [ ] File paths correct (checked in codebase) - -### Accessibility -- [ ] Headings in logical order (H1 → H2 → H3) -- [ ] Code blocks have language specified -- [ ] Alt text for images (if any) -- [ ] Tables have headers - ---- - -## Automation & Tools - -### Linting Documentation - -**Check Markdown syntax:** - -```bash -# Install markdownlint -npm install -g markdownlint-cli - -# Lint all docs -cd internal-docs/ -markdownlint *.md -``` - -**Common issues caught:** -- Inconsistent heading levels -- Trailing whitespace -- Missing blank lines around code blocks - ---- - -### Link Checking - -**Verify all links work:** - -```bash -# Install markdown-link-check -npm install -g markdown-link-check - -# Check links -markdown-link-check internal-docs/*.md -``` - -**Fix broken links:** -- Update to correct URL -- Remove if resource no longer exists -- Use Internet Archive if critical resource - ---- - -### Spell Checking - -**Use spell checker:** - -```bash -# Install aspell -brew install aspell # macOS -apt install aspell # Linux - -# Check spelling -aspell check internal-docs/README.md -``` - -**Custom dictionary:** - -Create `.aspell.en.pws`: -``` -personal_ws-1.1 en 50 -SureForms -WordPress -Gutenberg -Mailchimp -PayPal -``` - ---- - -## Documentation Templates - -### New Feature Documentation Template - -**When adding new feature:** - -```markdown -## [Feature Name] - -**Since:** [version] -**Type:** [Free/Pro] - -### Overview - -[2-3 sentence description of what feature does and why it exists] - -### Use Cases - -- [Use case 1] -- [Use case 2] -- [Use case 3] - -### How to Use - -**Step 1: [Action]** - -[Description] - -```php -// Code example -``` - -**Step 2: [Action]** - -[Description] - -### Configuration - -| Option | Type | Default | Description | -|--------|------|---------|-------------| -| `option_name` | string | 'default' | What this does | - -### API Reference - -**REST Endpoint:** -``` -POST /sureforms/v1/feature -``` - -**Parameters:** -- `param1` (string, required) - Description -- `param2` (integer, optional) - Description - -**Response:** -```json -{ - "success": true, - "data": { ... } -} -``` - -### Examples - -**Example 1: [Use case]** -```php -// Code here -``` - -**Example 2: [Use case]** -```php -// Code here -``` - -### Troubleshooting - -**Issue:** [Common problem] -**Solution:** [How to fix] - -### Related - -- [Related feature 1](link) -- [Related feature 2](link) -``` - ---- - -### Bug Fix Documentation Template - -**When fixing bug:** - -**In troubleshooting.md:** - -```markdown -### [Issue Description] - -**Symptom:** [What user sees] - -**Diagnosis:** - -[How to identify the issue] - -```bash -# Commands to diagnose -``` - -**Fixes:** - -**Option 1: [Fix description]** -```php -// Code or command -``` - -**Option 2: [Alternative fix]** -```php -// Alternative code -``` - -**Prevents:** [What this prevents] - -**See also:** [Related issues] -``` - ---- - -## Review & Approval Process - -### Before Merging Docs - -**Self-review:** -1. Read your changes out loud -2. Test all code examples -3. Run linters -4. Check cross-references - -**Peer review:** -1. Request review from team member -2. Address feedback -3. Update based on comments - -**Final checks:** -1. Rebase on main branch -2. Verify no conflicts -3. One last proofread - ---- - -### Documentation Pull Request Template - -**PR description:** - -```markdown -## Documentation Update - -**Plugin Version:** 2.5.1 -**Docs Changed:** [List files] - -### Changes Made - -- [ ] Added documentation for [feature] -- [ ] Updated [section] in [file] -- [ ] Fixed typos in [file] - -### Verification - -- [x] All code examples tested -- [x] All links checked -- [x] Spelling checked -- [x] Cross-references updated -- [x] Version numbers updated - -### Related - -- Related PR: #123 -- Related Issue: #456 -``` - ---- - -## Documentation Metrics - -**Track documentation quality:** - -### Metrics to Monitor - -**Coverage:** -- % of features documented -- % of APIs documented -- % of code examples tested - -**Freshness:** -- Days since last update -- Number of outdated sections -- Deprecated content count - -**Quality:** -- Broken link count -- Spelling error count -- User-reported doc issues - -**Engagement:** -- Doc views (if analytics enabled) -- Time spent reading -- Bounce rate (if high, docs unclear) - ---- - -## Long-Term Maintenance - -### Quarterly Review - -**Every 3 months:** - -1. **Audit all docs:** - - Read each document start to finish - - Test all code examples - - Verify all links - - Update outdated info - -2. **User feedback:** - - Review GitHub issues tagged "documentation" - - Survey users about doc clarity - - Identify gaps in coverage - -3. **Reorganize if needed:** - - Move sections to better fit structure - - Split large docs if too long - - Merge duplicate information - ---- - -### Annual Review - -**Every year:** - -1. **Major cleanup:** - - Remove deprecated content - - Archive old versions - - Rewrite outdated sections - -2. **Structure evaluation:** - - Does structure still make sense? - - Should we add/remove files? - - Are cross-references clear? - -3. **Voice & tone:** - - Is tone consistent? - - Is it still beginner-friendly? - - Does it match product evolution? - ---- - -## Questions? - -**For documentation questions:** -- Create GitHub issue: `[Docs] Your question` -- Tag: `documentation` -- Assign: Documentation maintainer - -**For urgent doc bugs:** -- Ping in Slack: `#sureforms-docs` -- Include: File name, line number, issue description - ---- - -## Conclusion - -**Documentation is code.** - -Treat it with same care: -- Test before committing -- Review changes -- Keep it DRY (Don't Repeat Yourself) -- Refactor when needed - -**Good documentation:** -- Saves support time -- Accelerates onboarding -- Prevents bugs -- Shows we care - -**Thank you for maintaining SureForms docs!** 📚 - ---- - -**Version:** 2.5.0 -**Last Updated:** 2026-02-12 -**Maintainer:** SureForms Team diff --git a/internal-docs/onboarding.md b/internal-docs/onboarding.md deleted file mode 100644 index ab5b83ad3..000000000 --- a/internal-docs/onboarding.md +++ /dev/null @@ -1,1086 +0,0 @@ -# Developer Onboarding - -**Version:** 2.5.0 - ---- - -## Welcome to SureForms - -This guide helps you become productive quickly, whether you have 1 hour, 1 day, or 1 week. - -**What you're working on:** -- **SureForms Free:** AI-powered WordPress form builder (219 PHP files, 50+ blocks) -- **SureForms Pro:** Premium extension (206 PHP files, payments, integrations, advanced features) - -**Architecture:** WordPress + Gutenberg blocks + React 18 + Custom database - ---- - -## Prerequisites - -Before starting: -- [ ] WordPress 6.4+ installed locally -- [ ] Node.js 18+ and npm 8+ -- [ ] PHP 7.4+ with Composer -- [ ] Git configured -- [ ] IDE with PHP/JavaScript support -- [ ] Both plugins cloned from GitHub - -**Test environment:** -```bash -# If using Local by Flywheel or similar -http://localhost:10003/wp-admin/ -Username: admin -Password: admin -``` - ---- - -## 1-Hour Quick Start - -**Goal:** Make your first successful change - -### Step 1: Get Code Running (15 min) - -```bash -# Clone repositories (if not already) -cd /path/to/wp-content/plugins/ -git clone https://github.com/brainstormforce/sureforms.git -git clone https://github.com/brainstormforce/sureforms-pro.git - -# Install dependencies - SureForms Free -cd sureforms/ -npm install -composer install - -# Build assets -npm run build - -# Install dependencies - SureForms Pro -cd ../sureforms-pro/ -npm install -composer install -npm run build -``` - -**Verify installation:** -```bash -# In WordPress admin -wp plugin activate sureforms sureforms-pro -wp plugin list | grep sureforms -``` - -### Step 2: Create Your First Form (15 min) - -**Via WordPress admin:** -1. Go to **SureForms → Add New** -2. Click **Create with AI** or **Start from Blank** -3. Add fields: Email, Name, Message -4. Click **Publish** -5. Add to a page with the SureForms block - -**Via WP-CLI:** -```bash -# Create form programmatically -wp post create \ - --post_type=sureforms_form \ - --post_title="Test Contact Form" \ - --post_status=publish \ - --post_content='<!-- wp:sureforms/form -->' -``` - -### Step 3: Make a Simple Change (20 min) - -**Task:** Change the submit button text - -**Files to modify:** -``` -src/blocks/form/edit.js ← React component -inc/blocks/form/block.php ← Server-side rendering -``` - -**Change 1: Edit the React component** - -Open `src/blocks/form/edit.js`: - -```javascript -// Find around line 45-50 -const { submitButtonText } = attributes; - -// Change default value -const defaultSubmitText = __('Send Message', 'sureforms'); // ← Change this -``` - -**Change 2: Rebuild** - -```bash -npm run build -``` - -**Verify:** Create new form, check if default button text changed. - -### Step 4: Debug Your Change (10 min) - -**Enable debugging:** - -Edit `wp-config.php`: -```php -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -define('SCRIPT_DEBUG', true); // Loads unminified JS -``` - -**Check debug log:** -```bash -tail -f wp-content/debug.log -``` - -**Browser console:** -- Open DevTools → Console -- Look for JavaScript errors -- Check Network tab for AJAX failures - ---- - -## 1-Day Deep Dive - -**Goal:** Understand architecture and make meaningful contributions - -### Morning: Core Concepts (4 hours) - -#### Hour 1: Architecture Overview - -**Read these docs first:** -1. [README.md](README.md) - Project overview -2. [architecture.md](architecture.md) - System design -3. [codebase-map.md](codebase-map.md) - File structure - -**Key concepts to understand:** -- **Gutenberg blocks:** React components that render forms -- **Custom post type:** `sureforms_form` stores form configurations -- **Custom database tables:** `wp_sureforms_entries`, `wp_sureforms_payments` -- **REST API:** Handles form submissions, AI generation -- **AJAX handlers:** Payment processing, file uploads - -**Test your understanding:** -- Where is form submission data saved? (Answer: `wp_sureforms_entries` table) -- How does AI form generation work? (Answer: REST endpoint → external middleware → GPT API) -- What's the difference between Free and Pro? (Answer: Pro adds payments, integrations, conditional logic) - -#### Hour 2: Data Flow - -**Trace a form submission from start to finish:** - -``` -User fills form → Frontend validation → AJAX request - ↓ -inc/form-submit.php (Line 88-119: Nonce verification) - ↓ -Field validation (inc/field-validation.php) - ↓ -Sanitization (inc/helper.php::sanitize_by_field_type()) - ↓ -Database insert (inc/database/tables/entries.php::insert()) - ↓ -Email notification (inc/email/email-handler.php) - ↓ -Confirmation message (or redirect) -``` - -**Hands-on exercise:** -1. Enable MySQL query logging -2. Submit a test form -3. Check `wp_sureforms_entries` table -4. Verify entry data matches submission - -```bash -# View recent entries -wp db query "SELECT * FROM wp_sureforms_entries ORDER BY id DESC LIMIT 5;" -``` - -#### Hour 3: Payment Processing - -**Understand Stripe payment flow:** - -``` -User clicks "Pay" → Frontend creates payment intent - ↓ -AJAX: wp_ajax_nopriv_srfm_create_payment_intent - ↓ -inc/payments/front-end.php (Line 77-83: Create Stripe PaymentIntent) - ↓ -Stripe API processes payment - ↓ -Webhook received: sureforms/webhook_test - ↓ -inc/payments/stripe/stripe-webhook.php (Line 220-637: Handle events) - ↓ -Update wp_sureforms_payments table - ↓ -Send confirmation email -``` - -**Hands-on exercise:** -1. Set up Stripe test keys -2. Create a payment form -3. Use Stripe test card: `4242 4242 4242 4242` -4. Check `wp_sureforms_payments` table for payment record - -#### Hour 4: Pro Features - -**Explore key Pro additions:** - -**1. User Registration:** -- File: `inc/business/user-registration/processor.php` -- Creates WordPress user accounts from form submissions -- Handles login/password reset - -**2. Native Integrations:** -- Folder: `inc/pro/native-integrations/integrations/` -- 24+ services: Mailchimp, Brevo, HubSpot, Salesforce, etc. -- OAuth authentication with encrypted token storage - -**3. Conditional Logic:** -- Frontend: `src/pro/conditional-logic/` -- Show/hide fields based on user selections -- Real-time UI updates - -**Hands-on exercise:** -1. Create form with registration block -2. Submit form, verify user created: `wp user list` -3. Enable Mailchimp integration (test mode) -4. Submit form, check integration logs - -### Afternoon: Build Your First Feature (4 hours) - -**Challenge:** Add a new field type - -**Example: "Star Rating" field** - -#### Step 1: Plan (30 min) - -**Requirements:** -- Display 5 stars (clickable) -- Save selected rating (1-5) -- Validate: Required if configured -- Display in entries table - -**Files to create/modify:** -``` -src/blocks/star-rating/ ← New React component -inc/blocks/star-rating/block.php ← Server-side rendering -inc/helper.php ← Add sanitization -inc/field-validation.php ← Add validation -``` - -#### Step 2: Create Block Structure (1 hour) - -**Create block files:** - -```bash -# Create directories -mkdir -p src/blocks/star-rating -mkdir -p inc/blocks/star-rating - -# Copy from existing field (Phone is a good template) -cp -r src/blocks/phone/* src/blocks/star-rating/ -cp inc/blocks/phone/block.php inc/blocks/star-rating/ -``` - -**Edit `src/blocks/star-rating/block.json`:** - -```json -{ - "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 3, - "name": "sureforms/star-rating", - "title": "Star Rating", - "category": "sureforms", - "icon": "star-filled", - "description": "Display a star rating input", - "attributes": { - "label": { - "type": "string", - "default": "Rate your experience" - }, - "required": { - "type": "boolean", - "default": false - }, - "maxRating": { - "type": "number", - "default": 5 - } - }, - "supports": { - "html": false - } -} -``` - -**Edit `src/blocks/star-rating/edit.js`:** - -```javascript -import { __ } from '@wordpress/i18n'; -import { useBlockProps } from '@wordpress/block-editor'; -import { TextControl, ToggleControl, RangeControl } from '@wordpress/components'; - -export default function Edit({ attributes, setAttributes }) { - const { label, required, maxRating } = attributes; - - return ( - <div {...useBlockProps()}> - <TextControl - label={__('Label', 'sureforms')} - value={label} - onChange={(value) => setAttributes({ label: value })} - /> - <ToggleControl - label={__('Required', 'sureforms')} - checked={required} - onChange={(value) => setAttributes({ required: value })} - /> - <RangeControl - label={__('Max Stars', 'sureforms')} - value={maxRating} - onChange={(value) => setAttributes({ maxRating: value })} - min={1} - max={10} - /> - <div className="srfm-star-rating-preview"> - {[...Array(maxRating)].map((_, i) => ( - <span key={i} className="dashicons dashicons-star-filled"></span> - ))} - </div> - </div> - ); -} -``` - -#### Step 3: Server-Side Rendering (45 min) - -**Edit `inc/blocks/star-rating/block.php`:** - -```php -<?php -namespace SRFM\Inc\Blocks\Star_Rating; - -class Block { - public static function register() { - register_block_type( - 'sureforms/star-rating', - [ - 'render_callback' => [__CLASS__, 'render'], - ] - ); - } - - public static function render($attributes) { - $label = esc_html($attributes['label'] ?? 'Rate your experience'); - $required = !empty($attributes['required']); - $max_rating = absint($attributes['maxRating'] ?? 5); - $field_name = 'srfm-star-rating-' . uniqid(); - - ob_start(); - ?> - <div class="srfm-field srfm-star-rating"> - <label> - <?php echo $label; ?> - <?php if ($required) : ?> - <span class="srfm-required">*</span> - <?php endif; ?> - </label> - <div class="srfm-star-rating-input" data-max="<?php echo $max_rating; ?>"> - <?php for ($i = 1; $i <= $max_rating; $i++) : ?> - <span class="srfm-star" data-value="<?php echo $i; ?>"> - ★ - </span> - <?php endfor; ?> - </div> - <input type="hidden" name="<?php echo esc_attr($field_name); ?>" value="" <?php echo $required ? 'required' : ''; ?>> - </div> - <?php - return ob_get_clean(); - } -} -``` - -#### Step 4: Frontend JavaScript (45 min) - -**Create `src/blocks/star-rating/frontend.js`:** - -```javascript -document.addEventListener('DOMContentLoaded', function() { - const ratingContainers = document.querySelectorAll('.srfm-star-rating-input'); - - ratingContainers.forEach(container => { - const stars = container.querySelectorAll('.srfm-star'); - const input = container.nextElementSibling; - const maxRating = parseInt(container.dataset.max); - - stars.forEach(star => { - star.addEventListener('click', function() { - const value = parseInt(this.dataset.value); - input.value = value; - - // Visual update - stars.forEach((s, index) => { - if (index < value) { - s.classList.add('selected'); - } else { - s.classList.remove('selected'); - } - }); - }); - - // Hover effect - star.addEventListener('mouseenter', function() { - const value = parseInt(this.dataset.value); - stars.forEach((s, index) => { - if (index < value) { - s.classList.add('hover'); - } else { - s.classList.remove('hover'); - } - }); - }); - }); - - container.addEventListener('mouseleave', function() { - stars.forEach(s => s.classList.remove('hover')); - }); - }); -}); -``` - -#### Step 5: Register Block (15 min) - -**Edit `inc/blocks/register.php`:** - -```php -// Add to existing blocks registration -Star_Rating\Block::register(); -``` - -**Edit `src/blocks/star-rating/index.js`:** - -```javascript -import { registerBlockType } from '@wordpress/blocks'; -import edit from './edit'; -import metadata from './block.json'; - -registerBlockType(metadata.name, { - edit, - save: () => null, // Server-side rendering -}); -``` - -#### Step 6: Add Sanitization & Validation (30 min) - -**Edit `inc/helper.php`:** - -Find `sanitize_by_field_type()` method and add: - -```php -case 'star-rating': - $value = absint($value); - // Ensure value is between 1 and max rating - return ($value >= 1 && $value <= 10) ? $value : 0; -``` - -**Edit `inc/field-validation.php`:** - -Find validation logic and add: - -```php -if ($field_type === 'star-rating' && $is_required && empty($value)) { - $errors[] = __('Please select a rating', 'sureforms'); -} -``` - -#### Step 7: Build & Test (30 min) - -```bash -# Build assets -npm run build - -# Test in browser -# 1. Create new form -# 2. Add "Star Rating" block -# 3. Configure settings (label, required, max stars) -# 4. Publish form -# 5. Submit test entry -# 6. Verify data saved correctly - -# Check database -wp db query "SELECT * FROM wp_sureforms_entries ORDER BY id DESC LIMIT 1;" -``` - ---- - -## 1-Week Mastery - -**Goal:** Expert-level understanding and complex feature development - -### Day 1: Architecture Deep Dive - -**Morning:** -- Complete 1-day onboarding -- Read all internal docs thoroughly -- Map data flow for all major features - -**Afternoon:** -- Trace payment processing end-to-end -- Understand webhook verification -- Study integration architecture - -### Day 2: Security & Best Practices - -**Focus areas:** -1. **Input sanitization:** Understand all 15+ sanitization methods -2. **Output escaping:** When to use `esc_html()`, `esc_attr()`, `esc_url()` -3. **SQL injection prevention:** Always use `$wpdb->prepare()` -4. **CSRF protection:** Nonce verification patterns -5. **Authorization:** `current_user_can()` checks - -**Hands-on exercises:** -- Review `inc/form-submit.php` (Lines 88-119: Security checks) -- Study `inc/helper.php` sanitization methods -- Find and fix intentional security bugs in test code - -**Read:** -- [coding-standards.md](coding-standards.md) -- [ai-agent-guide.md](ai-agent-guide.md) - Security section - -### Day 3: React & Gutenberg Blocks - -**Topics:** -1. **Block architecture:** How Gutenberg blocks work -2. **Attributes:** Data storage and retrieval -3. **Inspector controls:** Settings sidebar -4. **Block variations:** Different field configurations -5. **Dynamic blocks:** Server-side rendering - -**Build complex block:** -- **Multi-step form block** (if not using Pro feature) -- Add step navigation -- Save progress between steps -- Implement validation per step - -**Resources:** -- Official Gutenberg docs: https://developer.wordpress.org/block-editor/ -- Example: Study `src/blocks/phone/` for complex field - -### Day 4: Database & REST API - -**Morning: Database operations** - -**Study these classes:** -- `inc/database/base.php` - Base table class -- `inc/database/tables/entries.php` - Entries CRUD -- `inc/database/tables/payments.php` - Payment records - -**Practice:** -```php -// Create custom query -use SRFM\Inc\Database\Tables\Entries; - -$entries = Entries::get_all([ - 'where' => [ - ['key' => 'form_id', 'value' => 123, 'compare' => '='], - ['key' => 'status', 'value' => 'published', 'compare' => '='] - ], - 'orderby' => 'created_at', - 'order' => 'DESC', - 'limit' => 20 -]); -``` - -**Afternoon: REST API development** - -**Create custom endpoint:** - -```php -// In new file: inc/rest-api-custom.php -namespace SRFM\Inc; - -class Rest_API_Custom { - public function register_routes() { - register_rest_route('sureforms/v1', '/custom-stats', [ - 'methods' => 'GET', - 'callback' => [$this, 'get_stats'], - 'permission_callback' => [$this, 'check_permissions'] - ]); - } - - public function check_permissions() { - return current_user_can('manage_options'); - } - - public function get_stats($request) { - // Your logic here - return ['success' => true, 'data' => []]; - } -} -``` - -### Day 5: Pro Features & Integrations - -**Morning: Payment processing** - -**Study both gateways:** -- Stripe: `inc/payments/stripe/` -- PayPal (Pro): `inc/business/payments/pay-pal/` - -**Understand webhook handling:** -- Signature verification -- Event processing -- Database updates -- Error handling - -**Afternoon: Build custom integration** - -**Example: Slack integration** - -1. Create integration folder: -``` -inc/pro/native-integrations/integrations/slack/ -├── config.json -└── actions/ - └── send-message.php -``` - -2. Define config: -```json -{ - "name": "Slack", - "slug": "slack", - "auth_method": "webhook_url", - "actions": [ - { - "name": "Send Message", - "slug": "send-message", - "endpoint": "chat.postMessage" - } - ] -} -``` - -3. Implement action: -```php -<?php -namespace SRFM_PRO\Inc\Pro\Native_Integrations\Integrations\Slack\Actions; - -class Send_Message { - public function execute($integration_data, $form_data) { - $webhook_url = $integration_data['webhook_url']; - $message = $this->format_message($form_data); - - $response = wp_remote_post($webhook_url, [ - 'body' => json_encode(['text' => $message]), - 'headers' => ['Content-Type' => 'application/json'] - ]); - - if (is_wp_error($response)) { - return ['success' => false, 'error' => $response->get_error_message()]; - } - - return ['success' => true]; - } - - private function format_message($form_data) { - // Format form data as Slack message - return "New form submission:\n" . print_r($form_data, true); - } -} -``` - ---- - -## Testing Your Changes - -### Local Testing - -**PHP Unit Tests:** -```bash -# Run all tests -composer test - -# Run specific test file -vendor/bin/phpunit tests/unit/test-helper.php - -# Run with coverage -composer test-coverage -``` - -**JavaScript Tests:** -```bash -# Run all JS tests -npm run test:unit - -# Watch mode -npm run test:unit:watch - -# Coverage -npm run test:unit:coverage -``` - -### E2E Testing (Playwright) - -```bash -# Start test environment -npm run play:up - -# Run E2E tests -npm run play:run - -# Interactive mode (see browser) -npm run play:run:interactive - -# Stop environment -npm run play:down -``` - -### Manual Testing Checklist - -Before submitting PR: -- [ ] Form creation works -- [ ] Form submission saves entry -- [ ] Email notifications sent -- [ ] Payment processing works (if touched) -- [ ] No JavaScript console errors -- [ ] No PHP errors in debug.log -- [ ] Works in latest WordPress version -- [ ] Works in Firefox, Chrome, Safari -- [ ] Mobile responsive -- [ ] Accessibility: keyboard navigation works - ---- - -## Code Review Process - -### Before Creating PR - -**Self-review:** -1. Run linters: -```bash -composer lint # PHP_CodeSniffer -npm run lint-js # ESLint -``` - -2. Auto-fix minor issues: -```bash -composer format # phpcbf -npm run lint-js:fix # ESLint --fix -``` - -3. Check for common issues: -- [ ] All inputs sanitized -- [ ] All outputs escaped -- [ ] SQL queries use `prepare()` -- [ ] Nonces verified for AJAX/forms -- [ ] Capabilities checked for admin actions -- [ ] No hardcoded strings (use `__()` for i18n) - -### Creating PR - -**Branch naming:** -```bash -git checkout -b feat/star-rating-field -git checkout -b fix/payment-webhook-error -git checkout -b refactor/database-queries -``` - -**Commit message format:** -``` -type(scope): brief description - -Longer explanation if needed. - -Co-Authored-By: Your Name <email@example.com> -``` - -**Types:** feat, fix, docs, style, refactor, test, chore - -**Example:** -``` -feat(blocks): add star rating field - -- Add new star-rating block -- Implement frontend JavaScript -- Add sanitization and validation -- Update docs with new field type - -Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> -``` - -### PR Checklist - -- [ ] Tests pass: `composer test && npm run test:unit` -- [ ] Linting passes: `composer lint && npm run lint-js` -- [ ] No console errors -- [ ] Database migrations documented (if any) -- [ ] Breaking changes documented -- [ ] Changelog updated -- [ ] Screenshots attached (for UI changes) - ---- - -## Common Tasks & Patterns - -### Add New AJAX Handler - -**Pattern:** -```php -// In controller file -public function register_ajax_actions() { - add_action('wp_ajax_srfm_my_action', [$this, 'handle_my_action']); - add_action('wp_ajax_nopriv_srfm_my_action', [$this, 'handle_my_action']); -} - -public function handle_my_action() { - // CRITICAL: Always verify nonce - check_ajax_referer('srfm_my_action_nonce', 'security'); - - // Check permissions if needed - if (!current_user_can('manage_options')) { - wp_send_json_error(['message' => 'Insufficient permissions']); - } - - // Sanitize inputs - $data = Helper::sanitize_array_recursively($_POST['data'] ?? []); - - // Process... - - wp_send_json_success(['result' => $result]); -} -``` - -### Add New REST Endpoint - -**Pattern:** -```php -// In inc/rest-api.php -public function register_routes() { - register_rest_route('sureforms/v1', '/my-endpoint', [ - 'methods' => 'POST', - 'callback' => [$this, 'handle_request'], - 'permission_callback' => [$this, 'check_permissions'] - ]); -} - -public function check_permissions() { - return current_user_can('manage_options'); -} - -public function handle_request($request) { - // Always verify nonce - $nonce = $request->get_header('X-WP-Nonce'); - if (!wp_verify_nonce($nonce, 'wp_rest')) { - return new \WP_Error('invalid_nonce', 'Invalid nonce', ['status' => 403]); - } - - // Get and sanitize parameters - $params = $request->get_params(); - $clean_params = Helper::sanitize_array_recursively($params); - - // Process... - - return ['success' => true, 'data' => $result]; -} -``` - -### Add WordPress Hook - -**Action hook (notify about event):** -```php -// Trigger action after entry save -do_action('sureforms_after_entry_save', $entry_id, $form_id, $entry_data); - -// Other plugins/themes can listen: -add_action('sureforms_after_entry_save', function($entry_id, $form_id, $data) { - // Custom logic -}, 10, 3); -``` - -**Filter hook (modify data):** -```php -// Allow filtering of email subject -$subject = apply_filters('sureforms_email_subject', $subject, $form_id, $entry_data); - -// Other plugins/themes can modify: -add_filter('sureforms_email_subject', function($subject, $form_id, $data) { - return "[Form $form_id] $subject"; -}, 10, 3); -``` - -### Database Operations - -**Insert entry:** -```php -use SRFM\Inc\Database\Tables\Entries; - -$entry_id = Entries::insert([ - 'form_id' => 123, - 'user_id' => get_current_user_id(), - 'status' => 'published', - 'entry_data' => wp_json_encode($form_data) -]); -``` - -**Update entry:** -```php -Entries::update($entry_id, [ - 'status' => 'spam' -]); -``` - -**Delete entry:** -```php -Entries::delete($entry_id); -``` - -**Query entries:** -```php -$entries = Entries::get_all([ - 'where' => [ - ['key' => 'form_id', 'value' => 123, 'compare' => '='] - ], - 'limit' => 20, - 'offset' => 0 -]); -``` - ---- - -## Debugging Tips - -### Enable Debug Mode - -**wp-config.php:** -```php -define('WP_DEBUG', true); -define('WP_DEBUG_LOG', true); -define('WP_DEBUG_DISPLAY', false); -define('SCRIPT_DEBUG', true); -define('SAVEQUERIES', true); -``` - -### Check Debug Log - -```bash -# Real-time log monitoring -tail -f wp-content/debug.log - -# Search for errors -grep "SureForms" wp-content/debug.log -``` - -### JavaScript Debugging - -**Browser console:** -```javascript -// Check global object -console.log(window.sureforms); - -// Check block attributes -wp.data.select('core/block-editor').getBlocks(); - -// Check form data -document.querySelector('form').addEventListener('submit', (e) => { - console.log('Form data:', new FormData(e.target)); -}); -``` - -### Database Queries - -**Install Query Monitor plugin:** -```bash -wp plugin install query-monitor --activate -``` - -**Check slow queries:** -- Visit any admin page -- Click "Query Monitor" in admin bar -- View "Queries" tab -- Sort by time -- Optimize slow queries - -**Manual query inspection:** -```php -// Add to code temporarily -global $wpdb; -$wpdb->show_errors(); -$wpdb->print_error(); -``` - -### AJAX Debugging - -**Check network tab:** -1. Open DevTools → Network -2. Filter: XHR -3. Submit form -4. Click request -5. Check Response tab for errors - -**Add debug output:** -```php -public function handle_ajax() { - error_log('AJAX data: ' . print_r($_POST, true)); - // ... rest of code -} -``` - ---- - -## Resources - -### Internal Documentation -- [README.md](README.md) - Quick start -- [architecture.md](architecture.md) - System design -- [codebase-map.md](codebase-map.md) - File structure -- [apis.md](apis.md) - API reference -- [coding-standards.md](coding-standards.md) - Code standards -- [ai-agent-guide.md](ai-agent-guide.md) - AI agent guidance -- [troubleshooting.md](troubleshooting.md) - Common problems - -### External Resources -- **WordPress Codex:** https://codex.wordpress.org/ -- **Block Editor Handbook:** https://developer.wordpress.org/block-editor/ -- **REST API Handbook:** https://developer.wordpress.org/rest-api/ -- **React Docs:** https://react.dev/ -- **WP-CLI:** https://wp-cli.org/ - -### Community -- **GitHub Issues:** Report bugs, request features -- **Facebook Group:** https://www.facebook.com/groups/surecart -- **Support:** https://support.brainstormforce.com/ - ---- - -## Next Steps - -After completing onboarding: - -1. **Pick a starter issue:** - - Look for "good first issue" label on GitHub - - Start with documentation or small bug fixes - - Work up to features - -2. **Read code:** - - Pick a feature you use - - Trace it from UI to database - - Understand every line - -3. **Write tests:** - - For code you touch - - Increases confidence - - Helps others understand your changes - -4. **Ask questions:** - - Don't hesitate to ask - - Better to ask than assume - - Document answers for others - -**Welcome to the team!** 🚀 diff --git a/internal-docs/product-vision.md b/internal-docs/product-vision.md deleted file mode 100644 index f41f1951c..000000000 --- a/internal-docs/product-vision.md +++ /dev/null @@ -1,688 +0,0 @@ -# Product Vision - -**Version:** 2.5.0 - ---- - -## Mission - -**Empower anyone to build beautiful, high-converting forms without code.** - -SureForms exists to solve a fundamental problem: creating forms on WordPress is unnecessarily complex, resulting in ugly forms that hurt conversion rates. - ---- - -## The Problem We Solve - -### Pain Points (Before SureForms) - -**1. Complexity** -- Learning curve: New interfaces, proprietary builders -- Time waste: Hours configuring simple contact forms -- Technical barriers: Requires developer for custom fields - -**2. Design Limitations** -- Generic templates that don't match site design -- Limited styling options without CSS knowledge -- Mobile responsiveness as afterthought - -**3. Low Engagement** -- Long, intimidating single-page forms -- No personalization or conditional logic -- High abandonment rates (avg 67% for long forms) - -**4. Spam & Security** -- Constant bot submissions -- Security vulnerabilities in popular plugins -- GDPR compliance challenges - -**5. Integration Friction** -- Payment processing requires multiple plugins -- Manual data export/import to CRMs -- Webhook setup requires developer knowledge - ---- - -## Our Solution - -### Core Differentiators - -**1. Native WordPress (Gutenberg)** -- **Why:** Users already know the interface -- **Benefit:** Zero learning curve, instant productivity -- **Technical:** React blocks, no proprietary builder - -**2. AI-Powered Form Building** -- **Innovation:** First AI form builder for WordPress -- **How:** Natural language → complete functional form in seconds -- **Examples:** - - "Create a job application form" → 12-field form with file upload - - "Simple contact form" → 3 fields, perfectly styled - - "Event RSVP with dietary restrictions" → Conditional logic auto-configured - -**3. Built-in Payments** -- **Why:** No WooCommerce, no add-ons required -- **Gateways:** Stripe (Free), PayPal (Pro) -- **Features:** One-time, subscriptions, custom amounts -- **Security:** PCI-compliant, encrypted credentials - -**4. Mobile-First Design** -- **Approach:** Responsive by default, not opt-in -- **Testing:** Every block tested on iOS/Android -- **Performance:** Fast load times on 3G networks - -**5. Engagement Features (Pro)** -- **Conversational Forms:** Chat-like, one question at a time -- **Multi-Step Forms:** Break long forms into digestible steps -- **Conditional Logic:** Show/hide based on answers -- **Result:** 3x higher completion rates vs single-page forms - ---- - -## Target Users - -### Primary Personas - -#### 1. Website Owner (40% of users) -**Profile:** -- Small business owner or solopreneur -- Limited technical skills -- DIY mentality -- Budget-conscious - -**Needs:** -- Contact forms, quote requests, bookings -- Easy setup (< 10 minutes) -- Professional appearance -- Spam protection - -**Pain Points:** -- Frustrated with complex form builders -- Can't afford developer -- Generic templates don't match brand - -**How SureForms Helps:** -- AI creates form in 30 seconds -- Instant Form feature (no embedding needed) -- Built-in anti-spam (reCAPTCHA, Honeypot) -- Modern, customizable design - ---- - -#### 2. WordPress Designer (30% of users) -**Profile:** -- Freelancer or agency designer -- Strong design skills, basic code knowledge -- Builds sites for clients -- Values aesthetics and UX - -**Needs:** -- Forms that match site design -- Custom styling without CSS -- Fast deployment -- Client-friendly interface - -**Pain Points:** -- Form plugins look "generic" -- CSS overrides are tedious -- Clients can't update forms themselves -- Other plugins don't use Gutenberg - -**How SureForms Helps:** -- Gutenberg-native (feels like page building) -- Extensive styling options in UI -- Client can edit without breaking design -- Block patterns for reusability - ---- - -#### 3. WordPress Developer (20% of users) -**Profile:** -- Full-stack developer -- Builds custom WordPress solutions -- Values clean code and extensibility -- Performance-conscious - -**Needs:** -- Developer-friendly APIs -- Hooks and filters -- Custom field types -- Database access -- Integration capabilities - -**Pain Points:** -- Other plugins have messy codebases -- Limited extensibility -- Poor documentation -- Performance issues (N+1 queries, bloat) - -**How SureForms Helps:** -- Clean, modern codebase (PSR-12-inspired) -- Extensive hooks: 50+ actions/filters -- Well-documented APIs -- Optimized queries (custom tables, not post meta) -- GitHub access for contributions - ---- - -#### 4. E-commerce Store Owner (10% of users) -**Profile:** -- Runs WooCommerce or custom store -- Needs payment forms (not full checkout) -- Sells services, memberships, donations -- Wants simplicity - -**Needs:** -- Accept payments without WooCommerce -- Subscription billing -- Custom pricing fields -- Receipt emails - -**Pain Points:** -- WooCommerce is overkill for simple payments -- Other payment forms require add-ons -- Can't customize payment flow -- Poor mobile checkout experience - -**How SureForms Helps:** -- Built-in Stripe/PayPal (no plugins) -- Subscription support included -- Custom amount fields (donations, tips) -- Mobile-optimized payment UI - ---- - -## Feature Philosophy - -### Design Principles - -**1. Simplicity Over Features** -- Don't add features just because competitors have them -- Every feature must solve real user problem -- Hide complexity behind smart defaults - -**Example:** -- ❌ Bad: 50 font options overwhelming users -- ✅ Good: 5 curated fonts + custom font option - -**2. Progressive Disclosure** -- Show basic options first -- Advanced settings collapsed by default -- Help text on hover, not always visible - -**Example:** -- Default form settings: 4 essential options -- Advanced panel: 15+ options (collapsed) - -**3. Convention Over Configuration** -- Smart defaults based on common use cases -- Zero config for 80% of users -- Power users can customize - -**Example:** -- Email notification auto-configured with sensible template -- User can override if needed - -**4. Performance First** -- Lazy load non-critical assets -- Minimize HTTP requests -- Database queries optimized (no N+1) -- CSS/JS minified and cached - -**Metrics:** -- Page load impact: < 50KB additional assets -- Time to Interactive: < 2 seconds on 3G -- Database queries: Max 5 per form render - -**5. Accessibility Built-In** -- WCAG 2.1 Level AA compliance -- Keyboard navigation -- Screen reader support -- Focus indicators - -**Testing:** -- Every block tested with NVDA/JAWS -- Keyboard-only testing required -- Color contrast checked - ---- - -## Free vs Pro Strategy - -### Free Plugin (Core Experience) - -**Philosophy:** Full-featured, not crippled trial - -**Included:** -- Unlimited forms -- Unlimited submissions -- All 15+ field types -- Email notifications -- Spam protection (reCAPTCHA, Honeypot) -- Stripe payments (one-time, subscriptions) -- Form analytics -- Export entries (CSV) -- GDPR compliance -- Instant Forms - -**Limitations:** -- No PayPal -- No native integrations (Mailchimp, etc.) -- No conditional logic -- No multi-step/conversational forms -- No user registration -- No PDF generation - -**Goal:** Provide genuine value, build trust, convert 5-10% to Pro - ---- - -### Pro Plugin (Power Features) - -**Philosophy:** Advanced features for serious users - -**Added Value:** -- **Payments:** PayPal (one-time, subscriptions) -- **Integrations:** 24+ native (Mailchimp, Brevo, HubSpot, Salesforce, etc.) -- **Logic:** Conditional show/hide, calculations -- **Forms:** Multi-step, conversational, save & resume -- **Users:** Registration, login, password reset -- **Output:** PDF generation from submissions -- **Advanced Fields:** Upload (images, files), signature, calculator -- **Priority Support:** < 24hr response time - -**Pricing Tiers:** -- **Essential:** $99/year (3 sites) -- **Plus:** $199/year (20 sites) -- **Agency:** $299/year (unlimited sites) - -**Conversion Strategy:** -- Free users see "Pro" badge on locked features -- No nag screens or popups -- Upgrade CTA in logical places (when user needs feature) -- 14-day money-back guarantee - ---- - -## Competitive Landscape - -### Direct Competitors - -**1. Gravity Forms** -- **Strengths:** Mature, extensive add-ons, trusted -- **Weaknesses:** Old UI, not Gutenberg-native, expensive -- **Our Advantage:** Modern interface, AI builder, lower cost - -**2. WPForms** -- **Strengths:** Beginner-friendly, drag-and-drop -- **Weaknesses:** Generic designs, limited styling -- **Our Advantage:** Better design flexibility, Gutenberg-native - -**3. Formidable Forms** -- **Strengths:** Advanced features, views/reporting -- **Weaknesses:** Steep learning curve, performance issues -- **Our Advantage:** Simpler, faster, AI-assisted - -**4. Fluent Forms** -- **Strengths:** Conversational forms, modern UI -- **Weaknesses:** Not Gutenberg-native, separate builder -- **Our Advantage:** Native Gutenberg, simpler UX - -**5. Contact Form 7** -- **Strengths:** Free, lightweight, popular -- **Weaknesses:** No UI, requires shortcodes, ugly default styles -- **Our Advantage:** Visual builder, beautiful defaults, AI - ---- - -### Market Positioning - -**SureForms:** The AI-powered Gutenberg form builder - -**Tagline:** "Beautiful forms without code" - -**Positioning Statement:** -> For WordPress users who want high-converting forms without complexity, SureForms is the AI-powered form builder that creates beautiful, mobile-first forms in seconds—unlike outdated plugins that require hours of configuration and result in generic-looking forms. - -**Why Users Choose SureForms:** -1. **Speed:** AI creates forms in 30 seconds vs 30 minutes -2. **Design:** Modern, mobile-first vs generic templates -3. **Ease:** Gutenberg-native vs proprietary builder -4. **Value:** Built-in payments vs add-ons required - ---- - -## Product Roadmap - -### Current Focus (2026 Q1) - -**Theme:** Stability & Performance - -**Priorities:** -1. Bug fixes from user reports -2. Performance optimization (lazy loading, query optimization) -3. Security hardening (code audit, penetration testing) -4. Documentation improvements -5. Accessibility compliance (WCAG 2.2 Level AA) - ---- - -### Near-Term (2026 Q2-Q3) - -**Theme:** Advanced Features & Integrations - -**Planned:** -1. **More Integrations:** - - Google Sheets (native, no Zapier) - - Airtable - - Notion - - Slack (native) - -2. **Field Types:** - - Star rating - - Matrix/grid (Pro) - - File upload enhancements (drag & drop, preview) - -3. **Conditional Logic Enhancements (Pro):** - - Show/hide blocks (not just fields) - - Calculation fields (price quotes, BMI calculators) - - Conditional email notifications - -4. **Analytics:** - - Conversion funnel visualization - - A/B testing (form variations) - - Heatmaps (where users drop off) - -5. **Templates:** - - 100+ pre-built form templates - - Industry-specific (real estate, healthcare, education) - - Import/export custom templates - ---- - -### Long-Term Vision (2027+) - -**Theme:** AI-Driven Personalization - -**Research Areas:** -1. **AI Form Optimization:** - - Auto-suggest field improvements based on completion rates - - Predictive text for common fields - - Smart field ordering (ML-driven) - -2. **Advanced Conversational Forms:** - - Voice input support - - Natural language processing for responses - - Branching logic based on sentiment - -3. **Global Expansion:** - - Multi-language support (WPML, Polylang) - - Currency localization - - Regional compliance (CCPA, PIPEDA, etc.) - -4. **Enterprise Features:** - - Team collaboration (roles, permissions) - - Advanced approval workflows - - Audit logs - - White-label options - -5. **Mobile App:** - - iOS/Android app for managing entries - - Push notifications for new submissions - - Offline form viewing - ---- - -## Success Metrics - -### North Star Metric -**Active Forms:** Number of forms receiving at least 1 submission per month - -**Why:** Indicates genuine usage, not just installs - -**Target:** 100,000 active forms by end of 2026 - ---- - -### Secondary Metrics - -**Growth:** -- New installations per month: 50,000+ -- Activation rate: 60% (user creates first form within 7 days) -- Retention: 80% still active after 30 days - -**Engagement:** -- Forms created per user: 3.5 average -- Submissions per form: 25/month average -- Feature adoption (Pro): 40% use conditional logic - -**Conversion:** -- Free → Pro conversion: 5-7% -- Trial → Paid: 25% -- Annual renewal rate: 85% - -**Quality:** -- Support ticket volume: < 2% of active users -- Bug reports: < 0.5% of installations -- 4.5+ star rating on WordPress.org - -**Performance:** -- Average page load impact: < 40KB -- Time to first form submission: < 5 minutes (from install) -- Support response time: < 12 hours - ---- - -## User Feedback Integration - -### How We Listen - -**1. Support Tickets** -- Every ticket tagged by topic -- Monthly review of common issues -- Feature requests tracked in GitHub - -**2. User Surveys** -- Annual user satisfaction survey -- Post-purchase survey (Pro users) -- Exit survey (churned Pro users) - -**3. Analytics** -- Feature usage tracking (opt-in) -- Error logging (anonymized) -- Performance metrics - -**4. Community** -- Facebook group discussions -- GitHub issues and discussions -- WordPress.org support forum - -**5. Direct Outreach** -- User interviews (quarterly) -- Beta tester program -- Power user advisory board - ---- - -### Decision Framework - -**Feature Requests Evaluation:** - -**Criteria:** -1. **Impact:** How many users need this? (1-10) -2. **Effort:** Development complexity? (1-10) -3. **Strategic Fit:** Aligns with vision? (Yes/No) -4. **Competitive:** Do competitors have it? (Yes/No) -5. **Revenue:** Drives conversions? (Yes/No) - -**Scoring:** -- Impact / Effort = Priority score -- Strategic Fit = multiplier (2x if yes) -- Build if score > 5 - -**Example:** -- Feature: "Drag & drop file upload" -- Impact: 8 (many requests) -- Effort: 4 (moderate complexity) -- Strategic Fit: Yes (better UX) -- Score: (8/4) × 2 = 4 → **Build later** - ---- - -## Brand & Voice - -### Brand Personality - -**Adjectives:** -- Approachable (not intimidating) -- Modern (not trendy) -- Reliable (not boring) -- Empowering (not condescending) - -**Tone:** -- Friendly but professional -- Clear over clever -- Helpful without being pushy -- Honest about limitations - ---- - -### Writing Guidelines - -**Do:** -- Use "you" (conversational) -- Short sentences -- Active voice -- Explain "why" not just "how" - -**Don't:** -- Jargon without explanation -- Marketing fluff ("revolutionary", "game-changing") -- Passive voice ("the form was created") -- Unnecessary exclamation marks!!!! - -**Examples:** - -❌ Bad: "SureForms revolutionizes form building with cutting-edge AI technology!" - -✅ Good: "SureForms uses AI to create forms in seconds. Describe what you need, and we'll build it." - ---- - -❌ Bad: "The form submission process has been optimized for maximum conversion potential." - -✅ Good: "We designed our forms to load fast and look great on mobile, so more people complete them." - ---- - -## Technical Vision - -### Architecture Goals - -**1. Performance** -- Custom database tables (not post meta) -- Lazy loading for non-critical assets -- Query optimization (no N+1) -- CDN-friendly (static assets versioned) - -**2. Scalability** -- Handle 100,000+ submissions per form -- Efficient database queries (indexed columns) -- Background processing for heavy tasks (webhooks, PDFs) -- Caching strategy (transients, object cache) - -**3. Security** -- Input sanitization (all user data) -- Output escaping (all rendered content) -- Nonce verification (all AJAX/REST) -- SQL injection prevention (prepared statements) -- Regular security audits - -**4. Extensibility** -- 50+ hooks (actions and filters) -- Clean, documented APIs -- Developer-friendly codebase -- Backward compatibility promise - -**5. Maintainability** -- WordPress coding standards (PHP_CodeSniffer) -- ESLint for JavaScript -- Automated testing (PHPUnit, Playwright) -- Clear documentation (inline and external) - ---- - -## Values & Principles - -**1. User Privacy** -- No tracking without consent -- GDPR compliance built-in -- Data portability (easy export) -- Clear privacy policy - -**2. Open Source (Free Plugin)** -- Public GitHub repository -- Accept community contributions -- Transparent roadmap -- Active maintenance - -**3. Quality Over Speed** -- Test thoroughly before release -- Fix bugs before adding features -- Code review required for all changes -- No "move fast and break things" - -**4. Accessibility** -- WCAG 2.1 Level AA minimum -- Keyboard navigation always -- Screen reader testing required -- Color contrast compliance - -**5. Sustainability** -- Reasonable pricing (not subscription trap) -- Long-term support commitment -- No vendor lock-in (data always exportable) -- Transparent upgrade policies - ---- - -## What We Won't Do - -**Out of Scope:** - -**1. Full CRM System** -- Why: Bloat, complexity, competing with specialists -- Alternative: Integrate with existing CRMs (HubSpot, Salesforce) - -**2. Email Marketing Platform** -- Why: Already solved by Mailchimp, Brevo, etc. -- Alternative: Native integrations with 24+ email platforms - -**3. Complete E-commerce Solution** -- Why: WooCommerce exists, does it well -- Alternative: Simple payment forms (our niche) - -**4. Website Builder** -- Why: Outside core competency (forms) -- Alternative: Work seamlessly with any page builder - -**5. Survey & Quiz Builder** -- Why: Different use case, different UX requirements -- Alternative: Forms work for simple surveys - ---- - -## Conclusion - -**Core Belief:** -Forms are critical touchpoints between businesses and customers. They should be beautiful, fast, and easy to create. - -**Our Promise:** -We'll keep building tools that make form creation accessible to everyone, without sacrificing power or flexibility. - -**For Developers:** -Your feedback shapes this product. Keep the issues and PRs coming. We're listening. - ---- - -**Next:** [UI & Copy Guidelines](ui-and-copy.md) diff --git a/internal-docs/troubleshooting.md b/internal-docs/troubleshooting.md deleted file mode 100644 index b7f256af5..000000000 --- a/internal-docs/troubleshooting.md +++ /dev/null @@ -1,1031 +0,0 @@ -# Troubleshooting Guide - -**Version:** 2.5.0 - ---- - -## Quick Diagnostic - -**Before diving deep, check these common issues:** - -```bash -# 1. WordPress & PHP versions -wp core version -php -v - -# 2. Plugin status -wp plugin list | grep sureforms - -# 3. Theme compatibility -wp theme list --status=active - -# 4. Recent errors -tail -50 wp-content/debug.log | grep -i "sureforms\|fatal\|error" - -# 5. Database tables exist -wp db query "SHOW TABLES LIKE '%sureforms%';" -``` - ---- - -## Installation & Activation Issues - -### Plugin Won't Activate - -**Symptom:** "Plugin activation failed" or white screen - -**Common Causes:** - -**1. PHP Version Too Old** -```bash -php -v -# Required: PHP 7.4+ -``` - -**Fix:** -```bash -# Update PHP (contact host if shared hosting) -# Or add to wp-config.php temporarily to see error: -define('WP_DEBUG', true); -define('WP_DEBUG_DISPLAY', true); -``` - -**2. WordPress Version Too Old** -```bash -wp core version -# Required: WordPress 6.4+ -``` - -**Fix:** -```bash -wp core update -``` - -**3. Conflicting Plugin** - -**Check for conflicts:** -```bash -# Deactivate all other plugins -wp plugin deactivate --all --exclude=sureforms,sureforms-pro - -# Try activating SureForms -wp plugin activate sureforms - -# Reactivate plugins one by one -wp plugin activate plugin-name -``` - -**Common conflicts:** -- Old caching plugins (W3 Total Cache < 2.0) -- Security plugins with aggressive rules -- Other form builders (namespace collisions) - -**4. Memory Limit Too Low** - -**Check current limit:** -```bash -wp eval 'echo WP_MEMORY_LIMIT;' -``` - -**Fix (wp-config.php):** -```php -define('WP_MEMORY_LIMIT', '256M'); -``` - ---- - -### Pro Plugin Shows "Base Plugin Required" - -**Symptom:** SureForms Pro won't activate - -**Diagnosis:** -```bash -wp plugin list | grep sureforms -# Ensure both sureforms AND sureforms-pro are installed -``` - -**Fix:** -1. Install SureForms Free first -2. Activate SureForms Free -3. Then activate SureForms Pro - -**Check version compatibility:** -```bash -# Free and Pro versions should match -# Both should be 2.5.0 (or same major.minor) -``` - ---- - -### Database Tables Not Created - -**Symptom:** Form submissions fail, entries not showing - -**Check tables exist:** -```bash -wp db query "SHOW TABLES LIKE '%sureforms%';" -``` - -**Expected output:** -``` -wp_sureforms_entries -wp_sureforms_payments -wp_sureforms_integrations -wp_sureforms_save_resume -``` - -**Fix: Force database creation** -```bash -# Deactivate plugin -wp plugin deactivate sureforms sureforms-pro - -# Delete plugin (backup first!) -wp plugin delete sureforms - -# Reinstall -wp plugin install sureforms --activate - -# Tables should be created on activation -``` - -**Manual creation (last resort):** - -Read schema from: -- `inc/database/tables/entries.php` -- `inc/database/tables/payments.php` - -Run CREATE TABLE statements manually. - ---- - -## Form Builder (Editor) Issues - -### Forms Won't Load in Editor - -**Symptom:** Blank screen or infinite loading spinner - -**Diagnosis:** - -**1. Check browser console:** -``` -Open DevTools → Console -Look for JavaScript errors -``` - -**Common errors:** - -**a) "wp.blockEditor is undefined"** -- **Cause:** Outdated WordPress version -- **Fix:** `wp core update` - -**b) "React version mismatch"** -- **Cause:** Another plugin using old React version -- **Fix:** Deactivate other plugins one by one to find conflict - -**c) "Uncaught SyntaxError"** -- **Cause:** JavaScript file corrupted or not minified correctly -- **Fix:** Rebuild assets: `npm run build` in plugin directory - -**2. Check network tab:** -``` -DevTools → Network -Filter: JS -Look for failed requests (red, 404, 500) -``` - -**Common failures:** -- `form-editor.js` (404) → Rebuild assets -- `chunk-vendors.js` (500) → Server misconfiguration - -**3. Enable SCRIPT_DEBUG:** - -In `wp-config.php`: -```php -define('SCRIPT_DEBUG', true); -``` - -This loads unminified JS, easier to debug. - ---- - -### Blocks Not Appearing in Inserter - -**Symptom:** SureForms blocks missing from block library - -**Diagnosis:** -```bash -# Check if blocks are registered -wp eval "print_r(get_option('srfm_blocks_registration'));" -``` - -**Fixes:** - -**1. Re-register blocks:** -```bash -wp plugin deactivate sureforms -wp plugin activate sureforms -``` - -**2. Clear block cache:** -```bash -wp cache flush -wp transient delete --all -``` - -**3. Check block.json files exist:** -```bash -find wp-content/plugins/sureforms/inc/blocks -name "block.json" -# Should return multiple files -``` - ---- - -### Form Preview Shows "Invalid Block" - -**Symptom:** Form renders as "This block contains unexpected or invalid content" - -**Cause:** Block HTML structure changed, saved form has old structure - -**Fix:** - -**Option 1: Update block (preserves data):** -1. Click "Attempt Block Recovery" -2. Verify content looks correct -3. Update form - -**Option 2: Clear and rebuild:** -1. Delete the invalid block -2. Add fresh block -3. Reconfigure settings - -**Prevention:** -- Always test after plugin updates -- Keep staging environment for testing - ---- - -## Form Submission Issues - -### Form Submissions Not Saving - -**Symptom:** User submits form, success message shows, but no entry in database - -**Diagnosis:** - -**1. Check debug log:** -```bash -tail -f wp-content/debug.log -# Submit form while watching log -``` - -**Common errors:** -- "Database insert failed" → Check table permissions -- "Nonce verification failed" → Caching issue (see below) -- "Call to undefined method" → PHP version or missing dependency - -**2. Check database directly:** -```bash -# Get latest entry -wp db query "SELECT * FROM wp_sureforms_entries ORDER BY id DESC LIMIT 1;" -``` - -**3. Test with minimal form:** -Create form with ONLY: -- Email field -- Submit button - -If this works, issue is with specific field type. - -**Fixes:** - -**Database Permissions:** -```bash -# Check MySQL user has INSERT privilege -wp db query "SHOW GRANTS;" -``` - -**Fix permissions (MySQL):** -```sql -GRANT INSERT, UPDATE, DELETE ON database_name.* TO 'wp_user'@'localhost'; -FLUSH PRIVILEGES; -``` - -**Caching Interference:** - -Caching plugins cache nonce values, causing verification failures. - -**Fix:** -1. Exclude `/wp-admin/admin-ajax.php` from cache -2. Exclude REST API `/wp-json/` from cache -3. Or disable caching temporarily to test - ---- - -### Email Notifications Not Sending - -**Symptom:** Form submitted successfully, but no email received - -**Diagnosis:** - -**1. Check if emails are being sent at all:** -```bash -# Install WP Mail SMTP or similar -wp plugin install wp-mail-smtp --activate - -# Or test with simple command: -wp eval "wp_mail('your@email.com', 'Test', 'Testing SureForms');" -``` - -**2. Check SureForms email settings:** -```bash -# View form meta -wp post meta list <form_id> | grep email -``` - -**3. Check spam folder** -- WordPress default `from` address: `wordpress@yourdomain.com` -- Often flagged as spam - -**Fixes:** - -**Configure SMTP:** - -Install WP Mail SMTP plugin: -```bash -wp plugin install wp-mail-smtp --activate -``` - -Configure with: -- Gmail -- SendGrid -- Mailgun -- Amazon SES - -**Check email template:** - -In form settings → Email Notification: -- Verify "To" address is correct -- Check "From" address is valid domain -- Test with simple subject/message - -**Server mail() function:** - -Some hosts disable PHP `mail()` function. - -Test: -```bash -php -r "mail('test@example.com', 'Test', 'Test message');" -``` - -If no email received, `mail()` is disabled. Use SMTP. - ---- - -### Form Validation Not Working - -**Symptom:** Form submits even with empty required fields - -**Causes:** - -**1. JavaScript disabled** (frontend validation skipped) -**2. Theme CSS hiding error messages** -**3. Custom JavaScript conflict** - -**Diagnosis:** - -**Check browser console:** -``` -Look for JavaScript errors -Check if srfm-validation.js loaded -``` - -**Test with default theme:** -```bash -wp theme activate twentytwentythree -# Submit form again -``` - -If works with default theme → Theme conflict. - -**Fixes:** - -**Theme conflict:** - -Add to theme's `functions.php`: -```php -add_action('wp_enqueue_scripts', function() { - // Ensure SureForms scripts load - wp_enqueue_script('srfm-frontend'); -}, 20); -``` - -**CSS hiding errors:** - -Check if theme has: -```css -.srfm-error { display: none !important; } -``` - -Remove or override. - ---- - -## Payment Processing Issues - -### Stripe Payments Failing - -**Symptom:** "Payment failed" error after entering card details - -**Diagnosis:** - -**1. Check Stripe API keys:** -```bash -# In WordPress admin: SureForms → Settings → Payments → Stripe -# Verify: -# - Using correct keys (test vs live) -# - Keys match Stripe dashboard -``` - -**2. Check Stripe webhook:** -```bash -# In Stripe Dashboard → Developers → Webhooks -# Verify webhook URL is: -https://yoursite.com/wp-json/sureforms/webhook_test - -# Check recent webhook deliveries for errors -``` - -**3. Check browser console:** -``` -DevTools → Console -Look for Stripe.js errors -``` - -**Common Errors:** - -**"Invalid API Key"** -- Using test key in live mode (or vice versa) -- API key revoked in Stripe dashboard -- Fix: Copy fresh keys from Stripe - -**"Payment Intent creation failed"** -- Amount is $0 or negative -- Currency mismatch -- Fix: Check form configuration, amount field - -**"Webhook signature verification failed"** -- Webhook secret incorrect -- Middleware issue -- Fix: Copy webhook signing secret from Stripe, update settings - -**Fixes:** - -**Test mode checklist:** -```bash -# 1. Use test API keys (starts with pk_test_ / sk_test_) -# 2. Test card: 4242 4242 4242 4242 -# 3. Any future expiry date -# 4. Any 3-digit CVC -``` - -**Live mode checklist:** -```bash -# 1. Use live API keys (starts with pk_live_ / sk_live_) -# 2. SSL certificate valid (https://) -# 3. Webhook verified in Stripe dashboard -# 4. Test with real card (refund immediately) -``` - ---- - -### PayPal Payments Failing (Pro) - -**Symptom:** Redirected to PayPal but payment doesn't process - -**Diagnosis:** - -**Check PayPal credentials:** -```bash -# SureForms → Settings → Payments → PayPal -# Verify: -# - Client ID matches PayPal dashboard -# - Secret matches -# - Using sandbox for testing, live for production -``` - -**Check webhook endpoint:** -```bash -# PayPal Dashboard → Apps & Credentials → Webhooks -# Webhook URL should be: -https://yoursite.com/wp-json/sureforms-pro/paypal-live-webhook -``` - -**Fixes:** - -**Test in sandbox mode first:** -1. Create PayPal sandbox account: https://developer.paypal.com/ -2. Use sandbox credentials in SureForms -3. Test with sandbox buyer account - -**Common issues:** -- **Wrong environment:** Using sandbox credentials in live mode -- **Webhook not subscribed:** Must subscribe to payment events in PayPal dashboard -- **SSL certificate:** PayPal requires valid HTTPS - ---- - -## Integration Issues (Pro) - -### Native Integration Not Connecting - -**Symptom:** "Connection failed" when adding integration (Mailchimp, HubSpot, etc.) - -**Diagnosis:** - -**1. Check OAuth redirect URL:** - -For OAuth integrations (Mailchimp, HubSpot, Salesforce): -``` -Redirect URL must be: -https://yoursite.com/wp-json/sureforms-pro/v1/oauth/callback -``` - -**2. Test API credentials:** - -For API key integrations (Brevo, etc.): -```bash -# Test API key directly -curl -X GET "https://api.brevo.com/v3/account" \ - -H "api-key: YOUR_API_KEY" -``` - -Should return account info, not error. - -**3. Check error logs:** -```bash -tail -f wp-content/debug.log | grep -i "integration\|oauth" -``` - -**Fixes:** - -**OAuth issues:** -- Ensure site uses HTTPS (required for OAuth) -- Whitelist redirect URL in service's developer console -- Check OAuth app has correct permissions/scopes - -**API key issues:** -- Regenerate key in service dashboard -- Copy entire key (no spaces, no quotes) -- Check key has required permissions (read/write) - ---- - -### Webhook Not Firing - -**Symptom:** Form submitted, but data not sent to integrated service - -**Diagnosis:** - -**Check webhook logs:** - -Install Query Monitor plugin: -```bash -wp plugin install query-monitor --activate -``` - -Submit form, check "HTTP API Calls" panel for webhook requests. - -**Manually trigger webhook:** -```bash -# Find integration ID -wp db query "SELECT * FROM wp_sureforms_integrations;" - -# Trigger webhook manually (developer test) -wp eval "do_action('sureforms_after_entry_save', 123, 456, []);" -``` - -**Fixes:** - -**Webhook URL validation:** - -In `inc/pro/integrations/webhooks.php`, ensure URL is valid: -- HTTPS only (no HTTP) -- No localhost (unless testing) -- Responds with 200 OK - -**Timeout issues:** - -Increase timeout in `wp-config.php`: -```php -define('WP_HTTP_BLOCK_EXTERNAL', false); -define('WP_ACCESSIBLE_HOSTS', 'api.mailchimp.com,api.hubspot.com'); -``` - ---- - -## Performance Issues - -### Form Editor Slow to Load - -**Symptom:** Takes 10+ seconds to load form in editor - -**Diagnosis:** - -**1. Check database size:** -```bash -wp db query "SELECT COUNT(*) FROM wp_sureforms_entries;" -# If > 100,000 entries, database may be slow -``` - -**2. Check server resources:** -```bash -# Memory usage -free -h - -# CPU usage -top - -# Disk I/O -iostat -``` - -**3. Profile with Query Monitor:** -```bash -wp plugin install query-monitor --activate -# Open form editor, check QM panel for slow queries -``` - -**Fixes:** - -**Optimize database:** -```bash -# Clean old entries (backup first!) -wp db query "DELETE FROM wp_sureforms_entries WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);" - -# Optimize tables -wp db optimize -``` - -**Increase PHP limits:** - -In `php.ini` or `.htaccess`: -``` -max_execution_time = 300 -memory_limit = 256M -``` - -**Enable object caching:** - -Install Redis or Memcached: -```bash -wp plugin install redis-cache --activate -wp redis enable -``` - ---- - -### Frontend Form Loads Slowly - -**Symptom:** Form takes 5+ seconds to appear on page - -**Diagnosis:** - -**Check asset loading:** -``` -DevTools → Network → Slow 3G simulation -Watch which assets are slow -``` - -**Common bottlenecks:** -- Google Fonts loading slowly -- Large CSS/JS files -- Unoptimized images in form - -**Fixes:** - -**Lazy load non-critical assets:** - -In `functions.php`: -```php -add_filter('script_loader_tag', function($tag, $handle) { - if ($handle === 'srfm-frontend') { - return str_replace(' src', ' defer src', $tag); - } - return $tag; -}, 10, 2); -``` - -**Use CDN for Google Fonts:** - -In form settings → Design → Typography: -- Limit to 1-2 font families -- Use system fonts for faster load (e.g., -apple-system) - -**Minify and combine assets:** -```bash -npm run build # Ensures assets are minified -``` - -**Enable caching:** - -Install caching plugin: -```bash -wp plugin install wp-super-cache --activate -``` - -Configure to cache pages with forms. - ---- - -## Block Compatibility Issues - -### Form Breaks After Theme Update - -**Symptom:** Form displays incorrectly or not at all after theme update - -**Diagnosis:** - -**Compare theme CSS:** - -Check if new theme has conflicting styles: -```css -/* Common conflicts */ -.srfm-form input { /* Theme override */ } -.srfm-field { /* Theme override */ } -``` - -**Test with default theme:** -```bash -wp theme activate twentytwentythree -``` - -If works → Theme issue. - -**Fixes:** - -**Add theme compatibility CSS:** - -In child theme `style.css`: -```css -/* Reset SureForms blocks */ -.srfm-form, -.srfm-field, -.srfm-form input, -.srfm-form textarea { - all: revert; -} - -/* Then apply minimal SureForms styles */ -``` - -**Use !important (last resort):** - -In SureForms settings → Custom CSS: -```css -.srfm-form input { - border: 1px solid #ccc !important; - padding: 10px !important; -} -``` - ---- - -### Conflicts with Page Builders - -**Symptom:** Forms don't work inside Elementor/Divi/Beaver Builder - -**Common Issues:** - -**1. JavaScript conflicts:** -- Page builder loads own jQuery version -- Conflicts with SureForms scripts - -**Fix:** -```php -// In functions.php -add_action('wp_enqueue_scripts', function() { - if (class_exists('Elementor\Plugin')) { - wp_dequeue_script('jquery'); - wp_enqueue_script('jquery'); - } -}, 100); -``` - -**2. CSS specificity:** -- Page builder CSS overrides SureForms - -**Fix:** - -Use SureForms settings → Custom CSS with higher specificity: -```css -.elementor-widget-container .srfm-form input { - /* Your styles */ -} -``` - ---- - -## Database & Query Issues - -### "Too many connections" Error - -**Symptom:** Site crashes during high form submission volume - -**Diagnosis:** -```bash -wp db query "SHOW STATUS LIKE 'max_used_connections';" -wp db query "SHOW VARIABLES LIKE 'max_connections';" -``` - -**Fixes:** - -**Increase max connections (MySQL):** - -In `my.cnf`: -``` -[mysqld] -max_connections = 500 -``` - -**Use persistent connections:** - -In `wp-config.php`: -```php -define('DB_CHARSET', 'utf8mb4'); -define('DB_COLLATE', ''); -define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_PERSISTENT); -``` - -**Add connection pooling:** - -Use ProxySQL or PgBouncer for connection pooling. - ---- - -### Slow Query: "SELECT * FROM wp_sureforms_entries" - -**Symptom:** Admin page very slow when viewing entries - -**Diagnosis:** -```bash -wp plugin install query-monitor --activate -# View entries page, check QM for slow queries -``` - -**Fixes:** - -**Add database indexes:** -```sql -ALTER TABLE wp_sureforms_entries -ADD INDEX idx_form_id (form_id), -ADD INDEX idx_created_at (created_at), -ADD INDEX idx_status (status); -``` - -**Limit entries displayed:** - -In admin, reduce entries per page from 100 to 20. - -**Paginate large result sets:** - -Ensure code uses `LIMIT` and `OFFSET`: -```php -$entries = Entries::get_all([ - 'limit' => 20, - 'offset' => ($page - 1) * 20 -]); -``` - ---- - -## WordPress.org Review Issues - -### Plugin Rejected for Security - -**Common reasons:** - -**1. Direct database calls without prepare():** -```php -// ❌ Bad -$wpdb->query("DELETE FROM table WHERE id = $id"); - -// ✅ Good -$wpdb->query($wpdb->prepare("DELETE FROM table WHERE id = %d", $id)); -``` - -**2. Unsanitized user input:** -```php -// ❌ Bad -echo $_POST['name']; - -// ✅ Good -echo esc_html(sanitize_text_field($_POST['name'] ?? '')); -``` - -**3. Missing nonce verification:** -```php -// ❌ Bad -if (isset($_POST['action'])) { do_action(); } - -// ✅ Good -if (isset($_POST['action']) && check_ajax_referer('my_action_nonce')) { - do_action(); -} -``` - -**Fix:** - -Run WordPress Coding Standards checker: -```bash -composer require --dev wp-coding-standards/wpcs -vendor/bin/phpcs --standard=WordPress inc/ -``` - -Fix all errors before resubmitting. - ---- - -## Getting Help - -### Before Asking for Help - -**Gather this information:** - -```bash -# 1. WordPress & PHP versions -wp core version -php -v - -# 2. Plugin version -wp plugin list | grep sureforms - -# 3. Active theme -wp theme list --status=active - -# 4. Other active plugins -wp plugin list --status=active - -# 5. Recent errors -tail -50 wp-content/debug.log - -# 6. Browser/OS (if frontend issue) -# Example: Chrome 120 on macOS 14 -``` - -### Where to Get Help - -**1. Documentation** (check first) -- This troubleshooting guide -- [FAQ](faq.md) -- [Architecture](architecture.md) - -**2. GitHub Issues** (bugs & feature requests) -- Search existing issues first -- Provide minimal reproduction steps -- Include system info from above - -**3. Support Portal** (Pro users) -- https://support.brainstormforce.com/ -- < 24hr response time for Pro users - -**4. Community** -- Facebook group: https://www.facebook.com/groups/surecart -- WordPress.org forum (Free only) - ---- - -## Still Stuck? - -If none of the above solutions work: - -**Create detailed bug report:** - -```markdown -**Environment:** -- WordPress: 6.4.2 -- PHP: 8.1 -- SureForms: 2.5.0 (Free/Pro) -- Theme: Astra 4.5.0 -- Browser: Chrome 120 - -**Steps to Reproduce:** -1. Create form with email field -2. Mark field as required -3. Submit form with empty email -4. [Describe unexpected behavior] - -**Expected:** Validation error shows -**Actual:** Form submits anyway - -**Debug Log:** -[Paste relevant errors from debug.log] - -**Screenshots:** -[Attach if visual issue] -``` - -Submit to: https://github.com/brainstormforce/sureforms/issues - ---- - -**Next:** [FAQ](faq.md) diff --git a/internal-docs/ui-and-copy.md b/internal-docs/ui-and-copy.md deleted file mode 100644 index e12a9a45a..000000000 --- a/internal-docs/ui-and-copy.md +++ /dev/null @@ -1,1077 +0,0 @@ -# UI & Copy Guidelines - -**Version:** 2.5.0 - ---- - -## User Experience Philosophy - -**Principle:** Every word and interaction should make the user feel capable, not confused. - -**User Mindset:** -- "I just want to create a form quickly" -- "I don't have time to read documentation" -- "I'm not a developer" - -**Our Responsibility:** -- Make obvious what to do next -- Explain why, not just how -- Never blame the user - ---- - -## User Journeys - -### Journey 1: First-Time User Creates Contact Form - -**Goal:** Create and publish first form in < 5 minutes - -**Steps:** - -**1. Plugin Activation (30 seconds)** - -``` -User activates plugin - ↓ -Redirect to welcome screen - ↓ -Show 2 options: - [Create with AI] [Start from Blank] -``` - -**Copy:** -``` -Welcome to SureForms! - -Let's create your first form. - -[Create with AI] ← Recommended for beginners - Let AI build your form from a simple description - -[Start from Blank] - Build your form block-by-block -``` - -**Design notes:** -- Large, friendly buttons -- "Recommended" badge on AI option -- No walls of text - ---- - -**2. AI Form Creation (2 minutes)** - -``` -User clicks "Create with AI" - ↓ -Modal appears with text input - ↓ -User types: "simple contact form" - ↓ -AI generates form (3-5 seconds) - ↓ -Form opens in editor, ready to publish -``` - -**Copy:** - -``` -Create Form with AI - -Describe the form you need: -┌─────────────────────────────────────┐ -│ Example: "job application with │ -│ file upload" or "event RSVP" │ -└─────────────────────────────────────┘ - -[Cancel] [Generate Form →] -``` - -**Loading state:** -``` -✨ Creating your form... - -AI is adding fields based on your description. -This usually takes 3-5 seconds. -``` - -**Success state:** -``` -✅ Your form is ready! - -We added: -• Name field -• Email field -• Message field -• Submit button - -You can add, remove, or rearrange fields below. - -[Publish Form] -``` - -**Design notes:** -- Loading spinner + encouraging message -- Success message lists what was created -- Clear next action (Publish) - ---- - -**3. Form Publishing (1 minute)** - -``` -User clicks "Publish" - ↓ -Gutenberg publish panel opens - ↓ -SureForms shows additional options -``` - -**Copy in publish panel:** - -``` -📋 Form Settings - -Where should submissions be sent? - -Email: [admin@yoursite.com ▼] - -After submission, show: -○ Confirmation message -○ Redirect to page -● Confirmation message (selected by default) - -Message: -┌─────────────────────────────────────┐ -│ Thank you! We'll respond within │ -│ 24 hours. │ -└─────────────────────────────────────┘ - -[Publish Form] -``` - -**Design notes:** -- Sensible defaults (confirmation message, admin email) -- Inline editing (no separate settings page) -- Jargon-free labels - ---- - -**4. Embedding Form (30 seconds)** - -``` -User wants to add form to page - ↓ -Edit page in Gutenberg - ↓ -Add SureForms block - ↓ -Select form from dropdown -``` - -**Copy in block inserter:** - -``` -SureForms - -Display a form on your page. - -📝 No form yet? Create one in SureForms > Add New -``` - -**Copy in block settings:** - -``` -Form - -Select a form: -[Contact Form ▼] [Create New] - -Display settings: -☑ Show form title -☑ Show form description -☐ Hide labels (show placeholders only) -``` - -**Design notes:** -- Help text guides to form creation if needed -- Checkbox labels explain what they do -- Preview updates in real-time - ---- - -### Journey 2: Pro User Sets Up Payment Form - -**Goal:** Create payment form and collect first payment - -**Complexity:** Higher (involves Stripe setup) - -**Steps:** - -**1. Payment Gateway Setup (5 minutes)** - -``` -User navigates to: -SureForms → Settings → Payments → Stripe -``` - -**Copy:** - -``` -Stripe Payments - -Accept credit card payments with Stripe. - -🔒 Secure: We never store card details. Payments are processed directly by Stripe. - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Test Mode (for testing) - -☑ Enable test mode - -Use these while testing: - Test card: 4242 4242 4242 4242 - Any future expiry, any CVC - -Publishable Key (starts with pk_test_) -┌─────────────────────────────────────┐ -│ │ -└─────────────────────────────────────┘ - -Secret Key (starts with sk_test_) -┌─────────────────────────────────────┐ -│ •••••••••••••••••••••••••••••••• │ -└─────────────────────────────────────┘ - -Where to get keys: -→ Stripe Dashboard > Developers > API Keys - https://dashboard.stripe.com/apikeys - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - -Live Mode (for real payments) - -⚠️ Only use after testing - -Publishable Key (starts with pk_live_) -┌─────────────────────────────────────┐ -│ │ -└─────────────────────────────────────┘ - -Secret Key (starts with sk_live_) -┌─────────────────────────────────────┐ -│ │ -└─────────────────────────────────────┘ - -[Save Settings] -``` - -**Design notes:** -- Test mode emphasized first -- Clear instructions where to get keys -- Security reassurance ("We never store") -- Direct link to Stripe dashboard - ---- - -**2. Creating Payment Form (3 minutes)** - -``` -User creates new form - ↓ -Adds "Payment" block - ↓ -Configures amount and currency -``` - -**Copy in Payment block settings:** - -``` -Payment Details - -Amount -○ Fixed amount - ┌──────┐ - │ 50 │ USD ▼ - └──────┘ - -● Let user choose amount - Min: [10] Max: [1000] USD ▼ - Default: [50] - -Payment Type -● One-time payment -○ Subscription - Interval: [Monthly ▼] - -Button Text -┌─────────────────────────────────────┐ -│ Pay Now │ -└─────────────────────────────────────┘ -``` - -**Design notes:** -- Radio buttons for mutually exclusive options -- Currency dropdown next to amount -- Clear labels (no "recurring" jargon, use "subscription") - ---- - -**3. Testing Payment (2 minutes)** - -**Copy on frontend form:** - -``` -Payment Information - -Amount: $50.00 - -Card Number -┌─────────────────────────────────────┐ -│ 1234 5678 9012 3456 │ [Card icon] -└─────────────────────────────────────┘ - -Expiry CVC -┌──────────┐ ┌─────┐ -│ MM / YY │ │ 123 │ -└──────────┘ └─────┘ - -🔒 Secure payment powered by Stripe - Your card details are encrypted and never stored. - -[Pay $50.00] -``` - -**Success message after payment:** - -``` -✅ Payment Successful! - -Receipt sent to: john@example.com - -Transaction ID: ch_1A2B3C4D5E6F - -[View Receipt] [Back to Home] -``` - -**Error message if payment fails:** - -``` -❌ Payment Failed - -Your card was declined. - -Common reasons: -• Insufficient funds -• Incorrect card number or expiry date -• Card requires 3D Secure verification - -Please try again or use a different card. - -[Try Again] -``` - -**Design notes:** -- Security reassurance prominent -- Success message includes receipt email and transaction ID -- Error message explains why and how to fix - ---- - -### Journey 3: Power User Builds Conditional Logic Form (Pro) - -**Goal:** Show/hide fields based on user selection - -**Example:** Event RSVP with dietary restrictions (only show if attending) - -**Steps:** - -**1. Creating Base Form (2 minutes)** - -``` -User adds fields: - - "Will you attend?" (Multiple Choice: Yes/No) - - "Dietary restrictions" (Dropdown) -``` - -**2. Adding Conditional Logic (3 minutes)** - -``` -User clicks "Dietary restrictions" block - ↓ -Opens block settings panel - ↓ -Enables conditional logic -``` - -**Copy in block settings:** - -``` -Conditional Logic - -Show this field only when certain conditions are met. - -☑ Enable conditional logic - -Show this field when: - -[Will you attend? ▼] [is ▼] [Yes ▼] - -[+ Add Condition] - -Logic: -● Show if ALL conditions match (AND) -○ Show if ANY condition matches (OR) -``` - -**Design notes:** -- Toggle to enable -- Dropdown-based condition builder (no code) -- Visual feedback: field grays out in editor preview when hidden - ---- - -**3. Testing Logic (1 minute)** - -**Copy in editor preview mode:** - -``` -💡 Preview Mode - -This is how your form will appear to users. - -Try selecting different options to see conditional logic in action. - -[Exit Preview] -``` - -**Behavior:** -- User selects "Yes" → Dietary field appears -- User selects "No" → Dietary field disappears - -**Design notes:** -- Clear indication of preview mode -- Real-time updates (no reload) - ---- - -## Microcopy Guidelines - -### Field Labels - -**Be concise and conversational** - -❌ Bad: "Please enter your electronic mail address" -✅ Good: "Email" - -❌ Bad: "Input telephone number (optional)" -✅ Good: "Phone (optional)" - -**Use sentence case, not title case** - -❌ Bad: "First Name" -✅ Good: "First name" - -❌ Bad: "Company Name (If Applicable)" -✅ Good: "Company name (if applicable)" - ---- - -### Help Text - -**Explain why or provide examples** - -**Email field:** -❌ Bad: "Enter email" -✅ Good: "We'll send a confirmation to this email" - -**Phone field:** -❌ Bad: "Phone number" -✅ Good: "We'll only call if there's an issue with your order" - -**File upload:** -❌ Bad: "Upload file" -✅ Good: "Upload your resume (PDF or DOCX, max 10MB)" - ---- - -### Error Messages - -**Be specific and actionable** - -**Email validation:** -❌ Bad: "Invalid email" -✅ Good: "Please enter a valid email (e.g., name@example.com)" - -**Required field:** -❌ Bad: "This field is required" -✅ Good: "Please enter your name" - -**File size:** -❌ Bad: "File too large" -✅ Good: "File must be under 10MB. Yours is 15MB. Try compressing it." - -**Payment failed:** -❌ Bad: "Transaction error" -✅ Good: "Your card was declined. Please check your card details or try a different card." - ---- - -### Success Messages - -**Be enthusiastic but not over-the-top** - -**Form submission:** -❌ Bad: "Form submitted" -✅ Good: "Thanks! We'll get back to you within 24 hours." - -**Payment successful:** -❌ Bad: "Payment processed successfully. Transaction ID: 1234." -✅ Good: "✅ Payment received! Receipt sent to your email." - -**Registration:** -❌ Bad: "Account created. Please log in." -✅ Good: "Welcome! Check your email to verify your account." - ---- - -### Button Labels - -**Use verbs that describe the action** - -❌ Bad: "Submit" -✅ Good: "Send Message" - -❌ Bad: "Click Here" -✅ Good: "Download Receipt" - -❌ Bad: "Proceed" -✅ Good: "Continue to Payment" - -**For payment buttons, include amount** - -❌ Bad: "Pay" -✅ Good: "Pay $50.00" - -❌ Bad: "Subscribe" -✅ Good: "Subscribe for $9.99/month" - ---- - -### Settings & Options - -**Explain consequences, not just features** - -**Email notification:** -❌ Bad: "Send email notification" -✅ Good: "Email me when someone submits this form" - -**Required field:** -❌ Bad: "Required" -✅ Good: "Make this field required" (checkbox label) - -**Conditional logic:** -❌ Bad: "Enable conditional logic" -✅ Good: "Show or hide this field based on other answers" - ---- - -## Visual Design Patterns - -### Empty States - -**When user has no forms yet:** - -``` -┌─────────────────────────────────────────┐ -│ │ -│ 📝 │ -│ │ -│ No forms yet │ -│ │ -│ Forms help you collect information │ -│ from your website visitors. │ -│ │ -│ [Create Your First Form] │ -│ │ -└─────────────────────────────────────────┘ -``` - -**Copy principles:** -- Icon relevant to context -- 1-sentence explanation -- Clear call-to-action button - ---- - -**When form has no submissions:** - -``` -┌─────────────────────────────────────────┐ -│ │ -│ 📭 │ -│ │ -│ No submissions yet │ -│ │ -│ Share this form to start collecting │ -│ responses. │ -│ │ -│ [Copy Form Link] [Embed on Page] │ -│ │ -└─────────────────────────────────────────┘ -``` - -**Design notes:** -- Actionable next steps -- Multiple options (link vs embed) - ---- - -### Loading States - -**Form submission in progress:** - -``` -┌─────────────────────────────────────┐ -│ ⏳ Sending... │ -│ │ -│ Please don't close this page. │ -└─────────────────────────────────────┘ -``` - -**AI form generation:** - -``` -┌─────────────────────────────────────┐ -│ ✨ Creating your form... │ -│ │ -│ [████████░░] 80% │ -│ │ -│ Adding email validation... │ -└─────────────────────────────────────┘ -``` - -**Design notes:** -- Spinner or progress indicator -- Explain what's happening -- Show progress if possible - ---- - -### Confirmation Dialogs - -**Deleting a form:** - -``` -┌─────────────────────────────────────┐ -│ Delete "Contact Form"? │ -│ │ -│ This will permanently delete: │ -│ • The form │ -│ • 47 submissions │ -│ • All settings │ -│ │ -│ This cannot be undone. │ -│ │ -│ [Cancel] [Delete Form] │ -└─────────────────────────────────────┘ -``` - -**Design notes:** -- Specific about what will be deleted -- Use red/destructive style for delete button -- Cancel button should be default (easier to accidentally click) - ---- - -### Tooltips & Hints - -**When to use:** -- Explaining technical terms -- Providing examples -- Showing keyboard shortcuts - -**Format:** - -``` -Field Name [?] - ↓ (on hover) -┌─────────────────────────────────────┐ -│ This is the internal name used in │ -│ the database. │ -│ │ -│ Example: "first_name" │ -└─────────────────────────────────────┘ -``` - -**Guidelines:** -- Keep under 2 sentences -- Provide example if helpful -- Don't repeat the label - ---- - -## Accessibility - -### Screen Reader Text - -**Form structure:** - -```html -<form aria-label="Contact Form"> - <div role="group" aria-labelledby="personal-info"> - <h2 id="personal-info">Personal Information</h2> - <!-- Fields here --> - </div> -</form> -``` - -**Error announcements:** - -```html -<div role="alert" aria-live="polite"> - Please fix 2 errors before submitting. -</div> - -<input - aria-invalid="true" - aria-describedby="email-error" -/> -<span id="email-error" role="alert"> - Please enter a valid email address -</span> -``` - ---- - -### Keyboard Navigation - -**Required interactions:** -- Tab through all fields -- Space to toggle checkboxes/radio buttons -- Enter to submit form -- Escape to close modals - -**Visual focus indicators:** - -```css -.srfm-field input:focus { - outline: 2px solid #0073aa; - outline-offset: 2px; -} -``` - -**Never:** -```css -:focus { - outline: none; /* ❌ Never remove focus outline */ -} -``` - ---- - -### Color Contrast - -**WCAG 2.1 Level AA Requirements:** -- Normal text: 4.5:1 minimum -- Large text (18pt+): 3:1 minimum -- UI components: 3:1 minimum - -**Test tools:** -- WebAIM Contrast Checker -- Chrome DevTools (Lighthouse) - -**Safe color combinations:** -- White text on dark backgrounds (#333 or darker) -- Dark text on light backgrounds (#F0F0F0 or lighter) -- Avoid gray text on gray backgrounds - ---- - -## Tone & Voice - -### Voice Characteristics - -**Friendly but professional** -- Use "we" and "you" -- Conversational, not formal -- Helpful, not condescending - -**Example:** -❌ Formal: "The system has detected an error in your input." -✅ Friendly: "Oops! We couldn't save that. Check for any errors above." - ---- - -**Clear over clever** -- Avoid puns and wordplay -- Be direct -- Technical accuracy over marketing fluff - -**Example:** -❌ Clever: "Houston, we have a problem!" -✅ Clear: "Something went wrong. Please try again." - ---- - -**Empowering, not blaming** -- Focus on solutions, not problems -- Use "we" for errors, "you" for successes - -**Example:** -❌ Blaming: "You entered an invalid email." -✅ Empowering: "Hmm, that email doesn't look quite right. Mind double-checking it?" - ---- - -### Writing for Different Contexts - -**First-time users:** -- More explanation -- Examples provided -- Encouraging tone - -**Example:** -``` -Welcome to SureForms! - -Creating your first form is easy. We'll walk you through each step. - -Let's start by choosing what kind of form you need. -``` - ---- - -**Power users:** -- Less explanation -- Assume knowledge -- Efficiency-focused - -**Example:** -``` -Advanced Settings - -Show field if: [condition builder] -Custom CSS class: [input] -``` - ---- - -**Error states:** -- Apologetic but not dramatic -- Specific about what went wrong -- Clear next steps - -**Example:** -``` -We couldn't save your changes. - -The connection to the server timed out. - -Please try again. If this keeps happening, check your internet connection. - -[Try Again] -``` - ---- - -**Success states:** -- Positive reinforcement -- What happens next -- Optional next action - -**Example:** -``` -✅ Form published! - -Your form is now live at: -https://yoursite.com/contact - -[View Form] [Create Another] -``` - ---- - -## Form Field Best Practices - -### Required vs Optional - -**Default:** Make fields optional - -**Require only when absolutely necessary:** -- Name (if sending personalized response) -- Email (if you need to contact them) -- Payment details (if collecting payment) - -**Label optional fields:** -``` -Phone (optional) -Company name (optional) -``` - -**Don't label required fields:** -❌ Bad: "Email (required)" -✅ Good: "Email" (with * indicator) - ---- - -### Field Order - -**Logical flow:** -1. Personal info (Name, Email) -2. Specific questions -3. Payment details (if applicable) -4. Submit button - -**Example contact form:** -``` -1. Name -2. Email -3. Subject -4. Message -5. [Submit] -``` - -**Example order form:** -``` -1. Name -2. Email -3. Product selection -4. Quantity -5. Payment details -6. [Complete Purchase] -``` - ---- - -### Placeholder Text - -**Use sparingly** - -Only for examples, not as labels: - -❌ Bad: -``` -Label: [empty] -Placeholder: "Enter your email" -``` - -✅ Good: -``` -Label: Email -Placeholder: "name@example.com" -``` - -**Never use placeholders as only label** (accessibility issue) - ---- - -### Multi-Step Forms (Pro) - -**Step indicators:** - -``` -Step 1 of 3: Your Information -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -●━━━━━━━━━━━━○━━━━━━━━━━━━━○ - -[Fields here] - -[Continue to Step 2 →] -``` - -**Navigation:** -- Show progress (Step 1 of 3) -- Visual progress bar -- Allow back navigation (not just forward) - -**Button labels:** -- Step 1: "Continue" (not "Next") -- Step 2: "Continue" -- Step 3: "Submit Form" (or "Complete Order") - ---- - -## Internationalization (i18n) - -### Text Translation - -**All user-facing strings must be translatable:** - -```php -// ✅ Good -__('Email', 'sureforms'); -_e('Submit Form', 'sureforms'); - -// ❌ Bad -echo 'Email'; // Hardcoded English -``` - -**Placeholders for dynamic content:** - -```php -// ✅ Good -sprintf(__('You have %d new submissions', 'sureforms'), $count); - -// ❌ Bad -echo "You have $count new submissions"; -``` - ---- - -### Date & Number Formatting - -**Use WordPress functions:** - -```php -// Dates -echo date_i18n(get_option('date_format'), $timestamp); - -// Numbers -echo number_format_i18n($number); - -// Currency -echo '$' . number_format_i18n($amount, 2); -``` - ---- - -### RTL Support - -**CSS for right-to-left languages:** - -```css -/* Use logical properties */ -.srfm-field { - margin-inline-start: 10px; /* Not margin-left */ - padding-inline-end: 20px; /* Not padding-right */ -} -``` - -**Test with RTL languages:** -- Arabic -- Hebrew -- Persian - ---- - -## Quality Checklist - -Before shipping UI copy: - -- [ ] Spell check passed -- [ ] Grammar correct -- [ ] Tone matches guidelines -- [ ] Actionable error messages -- [ ] Examples provided where helpful -- [ ] Accessibility: screen reader friendly -- [ ] Accessibility: color contrast ≥ 4.5:1 -- [ ] Keyboard navigation works -- [ ] i18n: All strings translatable -- [ ] RTL languages supported -- [ ] Tested with real users (if major UI) - ---- - -**Next:** [FAQ](faq.md) diff --git a/tests/play/specs/CLAUDE.md b/tests/play/specs/CLAUDE.md deleted file mode 100644 index 113b91abd..000000000 --- a/tests/play/specs/CLAUDE.md +++ /dev/null @@ -1,324 +0,0 @@ -# Playwright E2E Specs — Writing Guide - -Rules and patterns for writing reliable SureForms E2E tests. Each section is a lesson learned from real failures. - ---- - -## Auth: Never do a full form-login inside tests - -**Pattern:** `globalSetup` logs in once and saves `storageState.json`. All workers restore it. - -**Why:** Multiple workers calling the WordPress login form simultaneously causes nonce collisions — WordPress redirects to `?reauth=1`, breaking every test in those workers. - -**Correct:** Let `storageState` handle auth. The `loginAsAdmin` util now just navigates to `/wp-admin` and relies on the pre-loaded cookies. - -```js -// DO — storageState is already loaded by playwright.config.js -test.beforeEach(async ({ page }) => { - await loginAsAdmin(page); // navigates to /wp-admin, skips login form -}); - -// DON'T — never re-do a full form login inside specs -await page.goto('/wp-login.php'); -await page.fill('#user_login', 'admin'); -``` - ---- - -## Adding blocks: sidebar vs programmatic insertion - -**Only these blocks appear in the quick-action sidebar by default:** -`input`, `email`, `textarea`, `checkbox`, `number`, `inline-button`, `advanced-heading`, `payment` - -**All other blocks** (`phone`, `url`, `multi-choice`, `dropdown`, `gdpr`, `rating`, `date`, etc.) **must be inserted programmatically.** - -Use `addFieldBlock(page, 'slug')` from `formHelpers.js` — it automatically routes sidebar blocks via click and all other blocks via `insertBlock`. - -```js -// This handles routing automatically -await addFieldBlock(page, 'gdpr'); // programmatic -await addFieldBlock(page, 'input'); // sidebar click -await addFieldBlock(page, 'dropdown'); // programmatic -``` - -**Never** try to open the WP block inserter toolbar to add non-sidebar blocks — it is fragile and frequently breaks tests. - ---- - -## WP 6.9+ iframe editor: no `data-type`, use data store - -WP 6.9 renders the block editor inside an `iframe[name="editor-canvas"]` and **removed the `data-type` attribute** from block wrapper elements. - -**Never** use `page.locator('.wp-block[data-type="srfm/..."]')` — it will find nothing. - -To **select a block** (e.g. to open its settings panel), use `selectBlock(page, 'slug')` from `formHelpers.js`. It dispatches `selectBlock` via the Gutenberg data store: - -```js -const { selectBlock } = require('../utils/formHelpers'); - -await addFieldBlock(page, 'email'); -await selectBlock(page, 'email'); // selects the block via data store -await openBlockSettingsTab(page); // now the sidebar shows this block's settings -``` - -To **verify a block exists**, `addFieldBlock` already checks via `wp.data.select('core/block-editor').getBlocks()` — no need for a separate DOM assertion. - ---- - -## Field CSS selectors - -Always use the most specific class. Do not rely on element order (`.nth(N)`) unless you are certain only N elements exist. - -| Field | Frontend input selector | -|---|---| -| Single line input | `input.srfm-input-input` | -| Email | `input.srfm-input-email` | -| Email confirm | `input.srfm-input-email-confirm` — **NOT** `input.srfm-input-email` | -| Phone | `input.srfm-input-phone` | -| Number | `input.srfm-input-number` | -| URL | `input.srfm-input-url` | -| Textarea | `textarea.srfm-textarea-text` | -| Checkbox | `input[type="checkbox"]` inside `.srfm-checkbox-input-wrap` | -| Submit button | `#srfm-submit-btn` | -| Success box | `.srfm-success-box` | -| Error message | `.srfm-error-message` | - ---- - -## TomSelect dropdowns - -The SureForms dropdown field uses TomSelect. The native `<select>` is hidden — use TomSelect's DOM instead. - -```js -// Open the dropdown -await page.locator('.ts-control').first().click(); - -// Click an option -await page.locator('.ts-dropdown-content .option').filter({ hasText: 'Option A' }).click(); -``` - ---- - -## GDPR field: no Required toggle - -The `GDPR_Markup` PHP class hardcodes `$this->required = true`. There is no `required` attribute in `block.json` and no Required toggle in the block settings panel. - -**Do not** call `enableRequiredField()` for a GDPR block — it will time out looking for a toggle that does not exist. - -```js -// GDPR test — just add the block and submit without filling it -await addFieldBlock(page, 'gdpr'); -const formURL = await publishFormAndGetURL(page); -// No enableRequiredField() needed -``` - ---- - -## Email confirmation block settings - -The block settings toggle in the editor sidebar is labelled **"Enable Email Confirmation"**, not "confirm email". - -```js -// Correct label -const toggle = panel.locator('.components-toggle-control') - .filter({ hasText: /Enable Email Confirmation/i }); - -// Wrong — this will time out -const toggle = panel.locator('.components-toggle-control') - .filter({ hasText: /confirm email/i }); -``` - ---- - -## Form Confirmation dialog: redirect URL - -The Form Confirmation dialog validates redirect URLs and **rejects `http://` URLs** with "Suggestion: URL should use HTTPS". This sets `hasValidationErrors = true` and skips the `updateMeta` call — the meta is never saved. - -**Bypass:** call `dispatch('core/editor').editPost()` directly. - -```js -await page.evaluate(() => { - const { dispatch } = window.wp.data; - dispatch('core/editor').editPost({ - meta: { - _srfm_form_confirmation: [ - { - confirmation_type: 'custom url', - custom_url: 'http://localhost:8888/wp-admin/', - }, - ], - }, - }); -}); -``` - -Only use the dialog UI when you are setting a success message (no validation issues there). - ---- - -## Quill editor debounce (Form Confirmation success message) - -The Form Confirmation success message editor uses `useDebouncedCallback` with a 500ms delay. If you close the dialog immediately after typing, the editor store has not updated yet. - -```js -await quillEditor.click(); -await page.keyboard.press('Control+a'); -await page.keyboard.type('Your submission was received!'); - -// Wait for the debounced auto-save to fire -await page.waitForTimeout(1000); - -// Now safe to close the dialog -await page.keyboard.press('Escape'); -``` - -This is one of the **only valid uses** of `waitForTimeout` in these tests. All other sleeps should be replaced with `expect(...).toBeVisible({ timeout })`. - ---- - -## Opening the Form Settings dialog - -```js -const { openFormSettingsDialog } = require('../utils/formHelpers'); - -// Opens the dialog and clicks the named nav item -await openFormSettingsDialog(page, 'Form Confirmation'); -``` - -Internally: clicks `.srfm-form-settings-button` → finds `.srfm-form-settings-nav-item-label` by text → waits for `.srfm-dialog-panel`. - -The dialog has `exitOnEsc` — pressing Escape closes it reliably without hitting the WP admin bar click-intercept. - ---- - -## Entry detail navigation - -Entry rows in the admin entries table contain `<a href="#/entry/{id}">` links. Click the **link**, not the row element. - -```js -// Correct -const entryLink = page.locator('a[href*="#/entry/"]').first(); -await entryLink.click(); - -// Wrong — the row itself may not be clickable -await entryRow.click(); -``` - ---- - -## No `waitForTimeout` except for debounce - -`expect(...).toBeVisible({ timeout: N })` already polls. Fixed sleeps waste time and hide real timing issues. - -```js -// WRONG — wasteful sleep -await page.waitForTimeout(2000); -await expect(page.locator('.srfm-success-box')).toBeVisible(); - -// CORRECT — just use the timeout on expect -await expect(page.locator('.srfm-success-box')).toBeVisible({ timeout: 15000 }); -``` - -The **only exception** is the 1000ms wait after Quill editor input (debounce pattern above). - ---- - -## Test isolation: each test creates its own form - -Every test creates a fresh form via `createBlankForm(page)`. Tests are safe to run fully in parallel. - -**Never** rely on a form created by a previous test — test execution order is not guaranteed. - ---- - -## CI sharding - -Tests run as 4 parallel shards in CI (`--shard=N/4`). Each shard: -- Gets its own `wp-env` instance -- Runs its own `globalSetup` (creates `storageState.json` inside the shard) -- Has 1 worker (`workers: 1` on CI) - -Local runs use 4 workers with a single `globalSetup`. - ---- - -## Forms list admin UI (`admin.php?page=sureforms_forms`) - -- Table renders as standard `<table>` via `@bsf/force-ui` Table. -- Per-row action buttons are **icon-only** — no `aria-label`, no `title`. Find them by position inside the row: `row.locator('button').nth(N)`. - - **The Edit action renders as `<a href="...">` (not `<button>`), so it is NOT counted when indexing buttons.** - - **The Entries column renders a `<Button>` (link variant, count as text) which IS button[0] in EVERY row.** - - Active form button order: EntriesCount(0) · View(1) · Export(2) · Duplicate(3) · Trash(4) - - Trashed form button order: EntriesCount(0) · Restore(1) · Delete Permanently(2) -- Duplicate and Trash open a `[role="dialog"]` ConfirmationDialog. Restore fires immediately (no dialog). -- **Delete Permanently** opens a special dialog that requires typing `"delete"` in a textbox before the button fires — unlike Duplicate/Trash which only need a button click: - ```js - const input = page.locator('[role="dialog"]') - .filter({ has: page.getByRole('button', { name: 'Delete Permanently', exact: true }) }) - .getByRole('textbox'); - await input.fill('delete'); - await page.getByRole('button', { name: 'Delete Permanently', exact: true }).click(); - ``` -- Status filter is a `@bsf/force-ui` Select. Click the button showing the current label → options appear as `[role="option"]` or `<li>` in a portal. -- Confirmation dialog confirm button text matches the action: `"Duplicate"`, `"Move to Trash"`, `"Delete Permanently"`. - -## Setting post meta directly via editPost - -When the UI rejects a value (e.g., HTTPS validation on redirect URL), bypass the UI and call `editPost` directly: - -```js -await page.evaluate(() => { - window.wp.data.dispatch('core/editor').editPost({ - meta: { _srfm_form_restriction: JSON.stringify({ status: true, maxEntries: 1, ... }) } - }); -}); -``` - -This works for any meta key registered with `show_in_rest: true` on the `sureforms_form` post type: -- `_srfm_form_confirmation` — confirmation type / redirect / success message -- `_srfm_compliance` — GDPR / do-not-store entries (array type, pass as JS array) -- `_srfm_form_restriction` — entry limit + scheduling (string type, pass as `JSON.stringify({...})`) - -## Form restrictions - -When a form is restricted (entry limit reached, or schedule ended), the PHP renders: -```html -<div class="srfm-form-restriction-message"> - <p class="srfm-form-restriction-text">Your custom message here</p> -</div> -``` -Assert with: `expect(page.locator('.srfm-form-restriction-message')).toBeVisible()` - -The restriction check happens **at render time (PHP)** — not at submission time. So: -- For entry-limit tests: submit once to consume the slot, then navigate back to the form URL. -- For schedule tests: set a past end date → navigate to form → restriction shows immediately (no submission needed). - -## Honeypot spam protection - -Every SureForms form renders `<input name="srfm-honeypot-field">`. Filling it simulates a bot: - -```js -await page.evaluate(() => { - const f = document.querySelector('[name="srfm-honeypot-field"]'); - if (f) f.value = 'spambot'; -}); -``` - -Server returns `wp_send_json_error` → `.srfm-success-box` must NOT appear. - -## Helpful utilities - -All utilities live in `tests/play/utils/`. - -| Utility | Purpose | -|---|---| -| `loginAsAdmin(page)` | Navigates to `/wp-admin`, restores auth from storageState | -| `createBlankForm(page)` | Creates a new blank SureForms form in the editor | -| `addFieldBlock(page, slug)` | Adds a field block (sidebar or programmatic) | -| `selectBlock(page, slug)` | Selects a block in the editor via the data store (iframe-safe) | -| `publishFormAndGetURL(page)` | Publishes the current form and returns its front-end URL | -| `openFormSettingsDialog(page, navItem)` | Opens Form Behavior dialog to a specific nav item | -| `setFormTitle(page, title)` | Sets the editor post title via `editPost` (avoids fragile UI title input) | -| `createWPPage(page, title, content)` | Creates a published WP page via REST API | - -When a new utility is needed, add it here rather than inlining complex selectors in spec files. diff --git a/tests/play/specs/TODO.md b/tests/play/specs/TODO.md deleted file mode 100644 index fd594df9a..000000000 --- a/tests/play/specs/TODO.md +++ /dev/null @@ -1,244 +0,0 @@ -# E2E Test Plan — SureForms Free Plugin - -Track progress for all Playwright test cases. -**Update this file every time a test is added or a test ID changes.** - -Last updated: 2026-03-16 -Branch convention: `test/e2e-p{N}-test-cases` - ---- - -## How to update this file - -- When you **add a test**, tick its checkbox and fill in the `Spec file` column. -- When you **add a new test ID** that wasn't listed here, add a row in the correct section. -- Fix the `Last updated` date above. - ---- - -## Coverage status key - -| Symbol | Meaning | -|---|---| -| ✅ | Implemented and passing | -| ⏭️ | Implemented but skipped (requires external keys / infra) | -| ❌ | Not yet implemented | -| 🔢 | Implemented but test ID needs renumbering | - ---- - -## Group 1 — Field types (basic submit) - -All tests live in `field-types.spec.js`. -Single-line input and email are covered in `form-creation-submission.spec.js` (not repeated here). - -| ID | Test case | Status | Spec file | -|------|-----------|--------|-----------| -| 1.1 | Textarea — submit multi-line text | ✅ | field-types.spec.js | -| 1.2 | Number — submit a valid number | ✅ | field-types.spec.js | -| 1.3 | Phone — submit a valid phone number | ✅ | field-types.spec.js | -| 1.4 | URL — submit a valid URL | ✅ | field-types.spec.js | -| 1.5 | Checkbox — check and submit | ✅ | field-types.spec.js | -| 1.6 | Multi-choice (radio) — pick one option and submit | ✅ | field-types.spec.js | -| 1.7 | Multi-choice (multi-select) — pick multiple options and submit | ✅ | field-types.spec.js | -| 1.8 | Dropdown — select one option and submit | ✅ | field-types.spec.js | -| 1.9 | *(reserved — inline-button / advanced-heading behaviour TBD)* | ❌ | — | -| 1.10 | GDPR — check consent and submit | ✅ | field-types.spec.js | - ---- - -## Group 2 — Field validation - -All tests live in `field-validation.spec.js`. - -| ID | Test case | Status | Spec file | -|------|-----------|--------|-----------| -| 2.1 | Email — invalid format shows error | ✅ | field-validation.spec.js | -| 2.2 | Email confirmation — mismatch shows error | ✅ | field-validation.spec.js | -| 2.3 | Email confirmation — matching emails submit successfully | ✅ | field-validation.spec.js | -| 2.4 | URL — invalid format shows error | ✅ | field-validation.spec.js | -| 2.5 | Number — value below minimum shows error | ✅ | field-validation.spec.js | -| 2.6 | Number — value above maximum shows error | ✅ | field-validation.spec.js | -| 2.7 | Required single-line input — submit empty shows error | ✅ | field-validation.spec.js | -| 2.8 | Required email — submit empty shows error | ✅ | field-validation.spec.js | -| 2.9 | Required phone — submit empty shows error | ✅ | field-validation.spec.js | -| 2.10 | Required textarea — submit empty shows error | ✅ | field-validation.spec.js | -| 2.11 | Required checkbox — submit unchecked shows error | ✅ | field-validation.spec.js | -| 2.12 | Required GDPR — submit without consent shows error | ✅ | field-validation.spec.js | -| 2.13 | Required dropdown — submit without selection shows error | ✅ | field-validation.spec.js | -| 2.14 | Required multi-choice — submit without selection shows error | ✅ | field-validation.spec.js | -| 2.15 | Character limit — input/textarea rejects text over max-chars | ❌ | — | - ---- - -## Group 3 — Form settings (confirmation behaviour) - -All tests live in `form-settings.spec.js`. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 3.1 | Redirect on submission — user lands on configured URL | ✅ | form-settings.spec.js | -| 3.2 | Custom success message — configured text shown after submit | ✅ | form-settings.spec.js | -| 3.3 | Store entries disabled — submission succeeds but no entry stored | ✅ | form-settings.spec.js | -| 3.4 | Page confirmation type — redirect to a configured WordPress page | ✅ | form-settings.spec.js | -| 3.5 | Store entries enabled (default) — entry appears in admin after submit | ✅ | form-settings.spec.js | -| 3.6 | Per-form GDPR compliance: do-not-store-entries enabled → no entry created | ✅ | form-settings.spec.js (covered by 3.3) | -| 3.7 | Per-form compliance: auto-delete setting saves and is visible in editor | ❌ | — | - ---- - -## Group 4 — Entries management - -All tests live in `entries.spec.js`. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 4.1 | Submitted entry appears in the admin entries list | ✅ | entries.spec.js | -| 4.2 | Entry detail contains the correct submitted field values | ✅ | entries.spec.js | -| 4.3 | Bulk delete removes selected entries | ✅ | entries.spec.js | -| 4.4 | CSV export downloads a file | ✅ | entries.spec.js | -| 4.5 | Mark entry as read / unread — status updates in the admin list | ✅ | entries.spec.js | - ---- - -## Group 5 — Form embedding - -All tests live in `form-embedding.spec.js`. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 5.1 | Shortcode-embedded form renders on a page | ✅ | form-embedding.spec.js | -| 5.2 | Shortcode-embedded form submits successfully | ✅ | form-embedding.spec.js | -| 5.3 | Gutenberg block-embedded form renders on a page | ✅ | form-embedding.spec.js | -| 5.4 | Gutenberg block-embedded form submits successfully | ✅ | form-embedding.spec.js | - ---- - -## Group 6 — Email notifications - -All tests live in `email-notifications.spec.js`. -All tests are currently skipped — require MailHog wired into the wp-env Docker setup. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 6.1 | Admin notification email is sent after form submission | ⏭️ | email-notifications.spec.js | -| 6.2 | Notification email body contains submitted field values | ⏭️ | email-notifications.spec.js | -| 6.3 | User confirmation email is sent to submitter's address | ❌ | — | - ---- - -## Group 7 — CAPTCHA - -All tests live in `captcha.spec.js`. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 7.2 | reCAPTCHA v2 — submit without solving is blocked | ⏭️ | captcha.spec.js | -| 7.3 | Cloudflare Turnstile — submit without solving is blocked | ❌ | — | -| 7.4 | hCaptcha — submit without solving is blocked | ❌ | — | -| 7.5 | reCAPTCHA v3 — submit with low score is blocked | ❌ | — | -| 7.7 | CAPTCHA disabled — form submits normally without CAPTCHA widget | ✅ | captcha.spec.js | - -> **Note:** 7.3–7.5 require external API keys; add them with `test.skip` pattern matching 7.2. - ---- - -## Group 8 — Payments (Stripe) - -All tests live in `payments.spec.js`. -All tests are currently skipped — require Stripe test keys. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 8.1 | Payment field renders the Stripe card widget | ⏭️ | payments.spec.js | -| 8.2 | Valid Stripe test card — payment succeeds and success message shown | ⏭️ | payments.spec.js | -| 8.3 | Declined Stripe test card — error message shown | ⏭️ | payments.spec.js | -| 8.6 | Successful payment creates an entry in the admin entries list | ⏭️ | payments.spec.js | - ---- - -## Group 9 — Global settings - -All tests live in `global-settings.spec.js`. - -| ID | Test case | Status | Spec file | -|-----|-----------|--------|-----------| -| 9.1 | Global settings page loads without a JS error | ✅ | global-settings.spec.js | -| 9.2 | All main settings tabs are clickable and stay on settings page | ✅ | global-settings.spec.js | - ---- - -## Group 10 — Spam protection - -All tests live in `spam-protection.spec.js`. - -| ID | Test case | Status | Spec file | -|------|-----------|--------|-----------| -| 10.1 | Honeypot — bot fills hidden field → submission is blocked | ✅ | spam-protection.spec.js | -| 10.2 | Double-submit prevention — submit button disabled after first click | ✅ | spam-protection.spec.js | - ---- - -## Group 11 — Form restrictions - -All tests live in `form-restrictions.spec.js`. - -| ID | Test case | Status | Spec file | -|------|-----------|--------|-----------| -| 11.1 | Entry limit — form shows restriction message after limit reached | ✅ | form-restrictions.spec.js | -| 11.2 | Scheduling — restriction message shown when schedule has ended | ✅ | form-restrictions.spec.js | -| 11.3 | Scheduling — restriction message shown when schedule has not started yet | ✅ | form-restrictions.spec.js | - ---- - -## Group 12 — Form lifecycle - -All tests live in `form-lifecycle.spec.js`. - -> **✅ Renaming done:** Comments in `form-lifecycle.spec.js` updated from `8.x` to `12.x`. - -| ID | Test case | Status | Spec file | -|------|-----------|--------|-----------| -| 12.1 | Duplicate form — copy appears in forms list with "(Copy)" suffix | ✅ | form-lifecycle.spec.js | -| 12.2 | Trash form — form disappears from All Forms view | ✅ | form-lifecycle.spec.js | -| 12.3 | Restore form — form reappears in All Forms view after restore from Trash | ✅ | form-lifecycle.spec.js | -| 12.4 | Delete permanently — form is fully removed and not restorable | ✅ | form-lifecycle.spec.js | - ---- - -## Group 13 — AI form generation - -All tests will live in `ai-form-builder.spec.js`. -Tests that require an API key should follow the `test.skip` pattern used in payments and CAPTCHA. - -| ID | Test case | Status | Spec file | -|------|-----------|--------|-----------| -| 13.1 | AI generation panel opens from the "Create Form" flow | ❌ | — | -| 13.2 | Generating a form with a prompt produces at least one block | ❌ | — | - ---- - -## Suggested implementation order - -Work these in priority order — top of each section first: - -### Next up (P1 — no external dependencies) - -- [x] **11.3** Scheduling not-started-yet *(done — form-restrictions.spec.js)* -- [x] **12.4** Delete permanently from trash *(done — form-lifecycle.spec.js)* -- [x] **2.7–2.10** Required validation for remaining field types *(done — field-validation.spec.js)* -- [x] **4.5** Entry read/unread status toggle *(done — entries.spec.js)* -- [x] **3.6** Per-form do-not-store-entries compliance *(already covered by test 3.3)* -- [ ] **2.15** Character limit — low E2E value (browser `maxlength` attribute, no server-side check); defer unless a custom error message is confirmed - -### Later (P2 — needs infra or API keys, use skip pattern) - -- [ ] **6.3** User confirmation email (needs MailHog) -- [ ] **7.3–7.5** Additional CAPTCHA types (need external keys) -- [ ] **13.1–13.2** AI form generation (needs AI API key) - -### Nice to have - -- [ ] **3.7** Auto-delete entries compliance setting -- [ ] **9.x** Global settings save (email From Name/From Email) -- [ ] **1.9** Inline button / advanced heading block behaviour