From 694d80875fa0369838001d9525831b586c381ec4 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 19:52:28 +0200 Subject: [PATCH 01/78] feat: add native search results vertical slice --- .gitignore | 3 + CHANGELOG.md | 14 +- README.md | 179 +++++++++--- assets/css/search-results.css | 128 +++++++++ cc-divi5-search-results.php | 30 +- composer.json | 5 + includes/Plugin.php | 78 ++++++ includes/Query/QueryResult.php | 19 ++ includes/Query/SearchQueryResolver.php | 105 +++++++ includes/Rendering/ResultTypeRule.php | 90 ++++++ includes/Rendering/RuleCollection.php | 35 +++ includes/Rendering/SearchResultsRenderer.php | 167 +++++++++++ includes/Support/AttributeValue.php | 65 +++++ .../SearchResultTypeModule.php | 35 +++ modules/SearchResults/SearchResultsModule.php | 177 ++++++++++++ package.json | 26 +- scripts/check-json.cjs | 11 + shortcodes/SearchResultsShortcode.php | 77 +++++ src/components/search-result-type/edit.tsx | 19 ++ src/components/search-result-type/index.ts | 14 + src/components/search-result-type/module.json | 221 +++++++++++++++ src/components/search-result-type/module.scss | 10 + src/components/search-result-type/types.ts | 20 ++ src/components/search-results/edit.tsx | 35 +++ src/components/search-results/index.ts | 19 ++ .../search-results/module-classnames.ts | 9 + src/components/search-results/module.json | 264 ++++++++++++++++++ src/components/search-results/module.scss | 11 + src/components/search-results/styles.tsx | 23 ++ src/components/search-results/types.ts | 32 +++ src/index.ts | 13 + tsconfig.json | 16 ++ webpack.config.js | 53 ++++ 33 files changed, 1951 insertions(+), 52 deletions(-) create mode 100644 assets/css/search-results.css create mode 100644 includes/Query/QueryResult.php create mode 100644 includes/Query/SearchQueryResolver.php create mode 100644 includes/Rendering/ResultTypeRule.php create mode 100644 includes/Rendering/RuleCollection.php create mode 100644 includes/Rendering/SearchResultsRenderer.php create mode 100644 includes/Support/AttributeValue.php create mode 100644 modules/SearchResultType/SearchResultTypeModule.php create mode 100644 modules/SearchResults/SearchResultsModule.php create mode 100644 scripts/check-json.cjs create mode 100644 shortcodes/SearchResultsShortcode.php create mode 100644 src/components/search-result-type/edit.tsx create mode 100644 src/components/search-result-type/index.ts create mode 100644 src/components/search-result-type/module.json create mode 100644 src/components/search-result-type/module.scss create mode 100644 src/components/search-result-type/types.ts create mode 100644 src/components/search-results/edit.tsx create mode 100644 src/components/search-results/index.ts create mode 100644 src/components/search-results/module-classnames.ts create mode 100644 src/components/search-results/module.json create mode 100644 src/components/search-results/module.scss create mode 100644 src/components/search-results/styles.tsx create mode 100644 src/components/search-results/types.ts create mode 100644 src/index.ts create mode 100644 tsconfig.json create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore index f661351..9d8fddd 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,8 @@ vendor/ build/ dist/ coverage/ +modules-json/ +scripts/bundle.js +styles/vb-bundle.css *.log *.zip diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ec6578..63f04a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ ### Added -- Open-source repository bootstrap. -- Native Divi 5 parent/child module contract. -- Shared renderer and optional-shortcode architecture. +- Native Divi 5 `codecorn/search-results` parent module metadata and server registration. +- Native `codecorn/search-result-type` child-rule metadata and server registration. +- Current-query and isolated-query resolver without global query mutation. +- Shared accessible renderer for result cards, summary, search form, pagination and empty state. +- Optional `[cc_divi5_search_results]` adapter backed by the shared resolver and renderer. +- Visual Builder TypeScript source, webpack build and responsive frontend styles. +- README documentation contract requiring code and documentation to remain synchronized in every PR. + +### Changed + +- Plugin bootstrap now supports Composer autoloading and a source-checkout fallback autoloader. diff --git a/README.md b/README.md index e3b86f4..12b1afd 100644 --- a/README.md +++ b/README.md @@ -2,72 +2,159 @@ > Native Divi 5 search results. The Blog Module workaround ends here. -A public, reusable Divi 5 extension for type-aware WordPress search results with full Visual Builder control. +A public Divi 5 extension for type-aware WordPress search results. The native parent module owns the query and result layout; native child modules act as repeatable rules for individual post types. The optional shortcode calls the same PHP query and rendering services. -## Non-negotiable contract +## Current implementation -- **Native Divi 5 module first.** No mandatory shortcode, Code Module or copied HTML. -- **Real WordPress query.** Current search by default; archive/custom sources can be added explicitly. -- **CPT-first.** Posts, pages and custom post types are treated as distinct result families. -- **Native configuration repeater.** A parent Search Results module contains child Result Type Rule modules. -- **Everything editable.** Labels, icons, colors, card variant, image source/fallback, ratio, excerpt, metadata mappings, CTA, filters, count, highlighting, pagination and empty state. -- **One rendering engine.** The optional shortcode calls the same query, normalization and renderer services as the native module. -- **Generic core.** No Barbagia Musei post types, labels, colors, meta keys or Theme Builder IDs hardcoded. +The `0.1.0` development branch currently includes: -## Planned modules +- safe plugin bootstrap with Composer PSR-4 autoloading and a source-checkout fallback autoloader; +- isolated search-query resolution that never calls `query_posts()` and never replaces the global `$wp_query`; +- reuse of the real current WordPress search query when the module runs on a search-results request; +- an isolated `WP_Query` fallback for Visual Builder previews, non-search pages and shortcode use; +- the native Divi 5 parent module `codecorn/search-results`; +- the native configuration child module `codecorn/search-result-type`; +- repeatable post-type rules for labels, badge, accent, image, excerpt, date and CTA; +- accessible result count, search form, result cards, pagination and empty state; +- shared rendering used by both the native module and `[cc_divi5_search_results]`; +- Visual Builder TypeScript sources and build configuration; +- frontend CSS with responsive grid behavior. -### `codecorn/search-results` +The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. -Dynamic parent module controlling: +## Native module structure -- query source, allowed post types, ordering and results per page; -- result summary and count; -- search form and clear action; -- type filters with counts; -- grid/list layout and responsive columns; -- term highlighting; -- pagination; -- zero-results experience; -- complete Content, Design and Advanced settings. +```text +codecorn/search-results +└── codecorn/search-result-type + ├── post + ├── page + └── any registered custom post type +``` + +`Result Type Rule` children are configuration objects. They do not render independent frontend cards. The parent reads their saved Divi block attributes and applies them to posts returned by the search query. + +## Available parent controls + +### Query + +- current WordPress search query or isolated query; +- explicit search term for the isolated query and Visual Builder preview; +- results per page. + +### Display + +- result count; +- search form; +- one to six desktop columns. -### `codecorn/search-result-type` +### Empty state -Child module used as a native repeater-like rule for each post type/result family: +- title; +- message. -- post type, state and priority; -- singular/plural labels, badge and icon; -- accent color and card preset; -- image source, fallback, ratio and object-fit; -- excerpt source, length and suffix; -- date, location, author, taxonomy and custom-field mappings; -- CTA text and link behavior; -- visibility rules when metadata is empty. +## Available result-type controls -The child items configure dynamic result cards; they are not manually duplicated content cards. +- post type slug; +- singular, plural and badge labels; +- rule priority; +- accent color; +- image, excerpt and date visibility; +- excerpt word count; +- CTA label. -## Shared architecture +Missing labels fall back to the registered WordPress post-type labels. Missing rules fall back to a generic rule derived from the result's post type. -1. `includes/Query` — current search/archive/custom query resolution. -2. `includes/Rendering` — accessible shared markup and view models. -3. `modules` — Divi 5 frontend module definitions. -4. `src/components` — Visual Builder components. -5. `shortcodes` — optional compatibility adapter only. +## Query contract -## Target shortcode +For `source=current`, the module reads the already-resolved main WordPress search query. It does not alter it. + +For `source=isolated`, the plugin creates its own `WP_Query` using the search term, configured result types, result limit and current page. Integrations can adjust only that isolated query through: + +```php +add_filter( 'cc_d5sr_query_args', function ( array $query_args, array $options ): array { + return $query_args; +}, 10, 2 ); +``` + +## Optional shortcode ```text [cc_divi5_search_results] ``` -It is an adapter, never the primary implementation. +Supported attributes in this increment: + +```text +source="current|isolated" +search="museum" +post_types="post,page,event" +posts_per_page="10" +columns="3" +show_summary="on" +show_search_form="on" +show_image="on" +show_excerpt="on" +show_date="on" +excerpt_length="28" +cta_label="View result" +``` + +The shortcode is an adapter, not the primary implementation. + +## Development + +Requirements: + +- WordPress 6.6+; +- Divi 5.9.0 reference target for this development increment; +- PHP 8.1+; +- Node.js 18+ and npm 10+; +- Composer. + +Install and build: + +```bash +composer install +npm install +npm run build +``` + +Validation: + +```bash +composer check:syntax +npm run check:json +``` + +After `npm run build`, the generated files are: + +```text +scripts/bundle.js +styles/vb-bundle.css +modules-json/search-results/module.json +modules-json/search-result-type/module.json +``` + +## Not implemented yet + +The README deliberately does not present the following as available: + +- live query results inside the Visual Builder canvas; +- dynamic post-type selector options populated from WordPress REST data; +- per-type custom-field and taxonomy mappings; +- type filters with counts; +- query-term highlighting; +- per-breakpoint column controls; +- image fallback and ratio controls; +- card presets; +- AJAX navigation. + +Those capabilities will be added in later reviewable increments without changing the shared renderer contract. -## Requirements +## Documentation rule -- WordPress 6.6+ -- Divi 5 -- PHP 8.1+ -- Node.js 18+ -- Composer +Every pull request that changes behavior, controls, requirements, generated paths or public APIs must update this README in the same pull request. Documentation may describe merged or included code only; planned behavior belongs exclusively in **Not implemented yet**. ## License diff --git a/assets/css/search-results.css b/assets/css/search-results.css new file mode 100644 index 0000000..a80baa6 --- /dev/null +++ b/assets/css/search-results.css @@ -0,0 +1,128 @@ +.cc-d5sr { + --cc-d5sr-gap: clamp(16px, 2vw, 28px); +} + +.cc-d5sr__inner { + display: grid; + gap: var(--cc-d5sr-gap); +} + +.cc-d5sr__summary { + display: flex; + flex-wrap: wrap; + gap: 0.35em; + align-items: baseline; +} + +.cc-d5sr__search { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 10px; +} + +.cc-d5sr__search input, +.cc-d5sr__search button { + min-height: 46px; + padding: 10px 14px; + font: inherit; +} + +.cc-d5sr__grid { + display: grid; + grid-template-columns: repeat(var(--cc-d5sr-columns, 3), minmax(0, 1fr)); + gap: var(--cc-d5sr-gap); +} + +.cc-d5sr__card { + overflow: hidden; + border: 1px solid #d7d9dc; + border-color: color-mix(in srgb, var(--cc-d5sr-accent) 28%, transparent); + border-radius: 12px; + background: #fff; +} + +.cc-d5sr__image { + display: block; + aspect-ratio: 16 / 10; + overflow: hidden; +} + +.cc-d5sr__image img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.cc-d5sr__content { + display: grid; + gap: 12px; + padding: 20px; +} + +.cc-d5sr__meta { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; + font-size: 0.85em; +} + +.cc-d5sr__badge { + display: inline-flex; + padding: 0.25em 0.65em; + border-radius: 999px; + color: #fff; + background: var(--cc-d5sr-accent); +} + +.cc-d5sr__title { + margin: 0; + font-size: clamp(1.1rem, 1.8vw, 1.45rem); +} + +.cc-d5sr__excerpt { + margin: 0; +} + +.cc-d5sr__cta { + justify-self: start; + font-weight: 700; +} + +.cc-d5sr__pagination .page-numbers { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin: 0; + padding: 0; + list-style: none; +} + +.cc-d5sr__pagination a, +.cc-d5sr__pagination span { + display: inline-flex; + min-width: 40px; + min-height: 40px; + align-items: center; + justify-content: center; +} + +.cc-d5sr__empty { + padding: clamp(24px, 4vw, 48px); + border: 1px dashed currentColor; + border-radius: 12px; + text-align: center; +} + +@media (max-width: 980px) { + .cc-d5sr__grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 600px) { + .cc-d5sr__search, + .cc-d5sr__grid { + grid-template-columns: 1fr; + } +} diff --git a/cc-divi5-search-results.php b/cc-divi5-search-results.php index 76accea..705de7b 100644 --- a/cc-divi5-search-results.php +++ b/cc-divi5-search-results.php @@ -17,12 +17,38 @@ define( 'CC_D5SR_VERSION', '0.1.0' ); define( 'CC_D5SR_FILE', __FILE__ ); -define( 'CC_D5SR_DIR', __DIR__ ); +define( 'CC_D5SR_DIR', plugin_dir_path( __FILE__ ) ); +define( 'CC_D5SR_URL', plugin_dir_url( __FILE__ ) ); -$cc_d5sr_autoload = CC_D5SR_DIR . '/vendor/autoload.php'; +$cc_d5sr_autoload = CC_D5SR_DIR . 'vendor/autoload.php'; if ( is_readable( $cc_d5sr_autoload ) ) { require_once $cc_d5sr_autoload; +} else { + spl_autoload_register( + static function ( string $class_name ): void { + $prefixes = array( + 'CodeCorn\\Divi5SearchResults\\Modules\\' => CC_D5SR_DIR . 'modules/', + 'CodeCorn\\Divi5SearchResults\\Shortcodes\\' => CC_D5SR_DIR . 'shortcodes/', + 'CodeCorn\\Divi5SearchResults\\' => CC_D5SR_DIR . 'includes/', + ); + + foreach ( $prefixes as $prefix => $base_directory ) { + if ( 0 !== strncmp( $class_name, $prefix, strlen( $prefix ) ) ) { + continue; + } + + $relative_class = substr( $class_name, strlen( $prefix ) ); + $class_file = $base_directory . str_replace( '\\', '/', $relative_class ) . '.php'; + + if ( is_readable( $class_file ) ) { + require_once $class_file; + } + + return; + } + } + ); } if ( class_exists( \CodeCorn\Divi5SearchResults\Plugin::class ) ) { diff --git a/composer.json b/composer.json index 1a7a0e2..12c5ebd 100644 --- a/composer.json +++ b/composer.json @@ -8,10 +8,15 @@ }, "autoload": { "psr-4": { + "CodeCorn\\Divi5SearchResults\\Modules\\": "modules/", + "CodeCorn\\Divi5SearchResults\\Shortcodes\\": "shortcodes/", "CodeCorn\\Divi5SearchResults\\": "includes/" } }, "config": { "sort-packages": true + }, + "scripts": { + "check:syntax": "find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print0 | xargs -0 -n1 php -l" } } diff --git a/includes/Plugin.php b/includes/Plugin.php index 317425e..430eb7d 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -2,6 +2,10 @@ namespace CodeCorn\Divi5SearchResults; +use CodeCorn\Divi5SearchResults\Modules\SearchResultType\SearchResultTypeModule; +use CodeCorn\Divi5SearchResults\Modules\SearchResults\SearchResultsModule; +use CodeCorn\Divi5SearchResults\Shortcodes\SearchResultsShortcode; + final class Plugin { private static bool $booted = false; @@ -11,7 +15,12 @@ public static function boot(): void { } self::$booted = true; + add_action( 'plugins_loaded', array( self::class, 'loadTextdomain' ) ); + add_action( 'init', array( SearchResultsShortcode::class, 'register' ) ); + add_action( 'wp_enqueue_scripts', array( self::class, 'enqueueFrontendAssets' ) ); + add_action( 'divi_module_library_modules_dependency_tree', array( self::class, 'registerDiviDependencies' ) ); + add_action( 'divi_visual_builder_assets_before_enqueue_scripts', array( self::class, 'registerVisualBuilderAssets' ) ); } public static function loadTextdomain(): void { @@ -21,4 +30,73 @@ public static function loadTextdomain(): void { dirname( plugin_basename( CC_D5SR_FILE ) ) . '/languages' ); } + + public static function enqueueFrontendAssets(): void { + wp_enqueue_style( + 'cc-divi5-search-results', + CC_D5SR_URL . 'assets/css/search-results.css', + array(), + CC_D5SR_VERSION + ); + } + + /** + * @param object $dependency_tree Divi dependency tree. + */ + public static function registerDiviDependencies( object $dependency_tree ): void { + if ( ! method_exists( $dependency_tree, 'add_dependency' ) ) { + return; + } + + if ( ! interface_exists( 'ET\\Builder\\Framework\\DependencyManagement\\Interfaces\\DependencyInterface' ) ) { + return; + } + + $dependency_tree->add_dependency( new SearchResultsModule() ); + $dependency_tree->add_dependency( new SearchResultTypeModule() ); + } + + public static function registerVisualBuilderAssets(): void { + $bundle_path = CC_D5SR_DIR . 'scripts/bundle.js'; + + if ( + ! is_readable( $bundle_path ) + || ! class_exists( 'ET\\Builder\\VisualBuilder\\Assets\\PackageBuildManager' ) + ) { + return; + } + + \ET\Builder\VisualBuilder\Assets\PackageBuildManager::register_package_build( + array( + 'name' => 'cc-divi5-search-results-vb', + 'version' => CC_D5SR_VERSION, + 'script' => array( + 'src' => CC_D5SR_URL . 'scripts/bundle.js', + 'deps' => array( + 'divi-module-library', + 'divi-vendor-wp-hooks', + ), + 'enqueue_top_window' => false, + 'enqueue_app_window' => true, + ), + ) + ); + + $style_path = CC_D5SR_DIR . 'styles/vb-bundle.css'; + + if ( is_readable( $style_path ) ) { + \ET\Builder\VisualBuilder\Assets\PackageBuildManager::register_package_build( + array( + 'name' => 'cc-divi5-search-results-vb-style', + 'version' => CC_D5SR_VERSION, + 'style' => array( + 'src' => CC_D5SR_URL . 'styles/vb-bundle.css', + 'deps' => array(), + 'enqueue_top_window' => false, + 'enqueue_app_window' => true, + ), + ) + ); + } + } } diff --git a/includes/Query/QueryResult.php b/includes/Query/QueryResult.php new file mode 100644 index 0000000..c430f5c --- /dev/null +++ b/includes/Query/QueryResult.php @@ -0,0 +1,19 @@ + $posts + */ + public function __construct( + public readonly array $posts, + public readonly int $foundPosts, + public readonly int $maxPages, + public readonly int $currentPage, + public readonly string $searchTerm + ) { + } +} diff --git a/includes/Query/SearchQueryResolver.php b/includes/Query/SearchQueryResolver.php new file mode 100644 index 0000000..745e315 --- /dev/null +++ b/includes/Query/SearchQueryResolver.php @@ -0,0 +1,105 @@ + $options + */ + public function resolve( array $options ): QueryResult { + $source = sanitize_key( (string) ( $options['source'] ?? 'current' ) ); + + if ( 'current' === $source ) { + $current = $this->currentSearchQuery(); + + if ( $current instanceof WP_Query ) { + return $this->fromQuery( $current, get_search_query( false ) ); + } + } + + $search_term = sanitize_text_field( (string) ( $options['search_term'] ?? get_search_query( false ) ) ); + $posts_per_page = max( 1, min( 100, (int) ( $options['posts_per_page'] ?? 10 ) ) ); + $current_page = max( 1, (int) ( $options['current_page'] ?? $this->currentPage() ) ); + $post_types = $this->sanitizePostTypes( $options['post_types'] ?? array() ); + + $query_args = array( + 'ignore_sticky_posts' => true, + 'no_found_rows' => false, + 'paged' => $current_page, + 'post_status' => 'publish', + 'post_type' => $post_types ?: 'any', + 'posts_per_page' => $posts_per_page, + 's' => $search_term, + ); + + /** + * Filter the isolated query used outside the current WordPress search request. + * + * @param array $query_args + * @param array $options + */ + $query_args = apply_filters( 'cc_d5sr_query_args', $query_args, $options ); + $query = new WP_Query( $query_args ); + + return $this->fromQuery( $query, $search_term ); + } + + private function currentSearchQuery(): ?WP_Query { + global $wp_query; + + if ( ! is_search() || ! $wp_query instanceof WP_Query ) { + return null; + } + + return $wp_query; + } + + private function currentPage(): int { + return max( 1, (int) get_query_var( 'paged' ), (int) get_query_var( 'page' ) ); + } + + /** + * @param mixed $post_types + * + * @return list + */ + private function sanitizePostTypes( $post_types ): array { + if ( is_string( $post_types ) ) { + $post_types = preg_split( '/[\s,]+/', $post_types ) ?: array(); + } + + if ( ! is_array( $post_types ) ) { + return array(); + } + + $post_types = array_values( + array_unique( + array_filter( + array_map( 'sanitize_key', $post_types ), + static fn ( string $post_type ): bool => '' !== $post_type && post_type_exists( $post_type ) + ) + ) + ); + + return $post_types; + } + + private function fromQuery( WP_Query $query, string $search_term ): QueryResult { + $posts = array_values( + array_filter( + $query->posts, + static fn ( $post ): bool => $post instanceof \WP_Post + ) + ); + + return new QueryResult( + $posts, + (int) $query->found_posts, + max( 1, (int) $query->max_num_pages ), + max( 1, (int) $query->get( 'paged', 1 ) ), + $search_term + ); + } +} diff --git a/includes/Rendering/ResultTypeRule.php b/includes/Rendering/ResultTypeRule.php new file mode 100644 index 0000000..156861a --- /dev/null +++ b/includes/Rendering/ResultTypeRule.php @@ -0,0 +1,90 @@ + $attrs + */ + public static function fromDiviAttrs( array $attrs ): self { + $values = AttributeValue::get( + $attrs, + array( 'rule', 'innerContent', 'desktop', 'value' ), + array() + ); + $values = is_array( $values ) ? $values : array(); + + return self::fromFlatArray( $values ); + } + + /** + * @param array $values + */ + public static function fromFlatArray( array $values ): self { + $post_type = sanitize_key( (string) ( $values['postType'] ?? $values['post_type'] ?? 'post' ) ); + $object = post_type_exists( $post_type ) ? get_post_type_object( $post_type ) : null; + + $singular = self::label( $values['singularLabel'] ?? $values['singular_label'] ?? '', $object, false, $post_type ); + $plural = self::label( $values['pluralLabel'] ?? $values['plural_label'] ?? '', $object, true, $singular ); + $badge = sanitize_text_field( (string) ( $values['badgeLabel'] ?? $values['badge_label'] ?? $singular ) ); + $accent = sanitize_hex_color( (string) ( $values['accentColor'] ?? $values['accent_color'] ?? '#2b2f36' ) ); + + return new self( + $post_type, + $singular, + $plural, + $badge ?: $singular, + $accent ?: '#2b2f36', + max( 0, (int) ( $values['priority'] ?? 10 ) ), + self::flag( $values['showImage'] ?? $values['show_image'] ?? 'on' ), + self::flag( $values['showExcerpt'] ?? $values['show_excerpt'] ?? 'on' ), + self::flag( $values['showDate'] ?? $values['show_date'] ?? 'on' ), + max( 0, min( 200, (int) ( $values['excerptLength'] ?? $values['excerpt_length'] ?? 28 ) ) ), + sanitize_text_field( (string) ( $values['ctaLabel'] ?? $values['cta_label'] ?? __( 'View result', 'cc-divi5-search-results' ) ) ) + ); + } + + public static function fallback( string $post_type ): self { + return self::fromFlatArray( array( 'postType' => $post_type ) ); + } + + private static function flag( $value ): bool { + if ( is_bool( $value ) ) { + return $value; + } + + return AttributeValue::isOn( (string) $value ); + } + + private static function label( $candidate, ?WP_Post_Type $object, bool $plural, string $fallback ): string { + $candidate = sanitize_text_field( (string) $candidate ); + + if ( '' !== $candidate ) { + return $candidate; + } + + if ( $object instanceof WP_Post_Type ) { + return $plural ? $object->labels->name : $object->labels->singular_name; + } + + return ucfirst( str_replace( array( '-', '_' ), ' ', $fallback ) ); + } +} diff --git a/includes/Rendering/RuleCollection.php b/includes/Rendering/RuleCollection.php new file mode 100644 index 0000000..238214a --- /dev/null +++ b/includes/Rendering/RuleCollection.php @@ -0,0 +1,35 @@ + */ + private array $rules = array(); + + /** + * @param iterable $rules + */ + public function __construct( iterable $rules = array() ) { + foreach ( $rules as $rule ) { + $this->rules[ $rule->postType ] = $rule; + } + + uasort( + $this->rules, + static fn ( ResultTypeRule $left, ResultTypeRule $right ): int => $left->priority <=> $right->priority + ); + } + + public function forPost( WP_Post $post ): ResultTypeRule { + return $this->rules[ $post->post_type ] ?? ResultTypeRule::fallback( $post->post_type ); + } + + /** + * @return list + */ + public function postTypes(): array { + return array_keys( $this->rules ); + } +} diff --git a/includes/Rendering/SearchResultsRenderer.php b/includes/Rendering/SearchResultsRenderer.php new file mode 100644 index 0000000..af45f17 --- /dev/null +++ b/includes/Rendering/SearchResultsRenderer.php @@ -0,0 +1,167 @@ + $options + */ + public function render( QueryResult $result, RuleCollection $rules, array $options = array() ): string { + $show_summary = $this->flag( $options['show_summary'] ?? true ); + $show_search_form = $this->flag( $options['show_search_form'] ?? true ); + $columns = max( 1, min( 6, (int) ( $options['columns'] ?? 3 ) ) ); + + $summary = $show_summary ? $this->summary( $result ) : ''; + $form = $show_search_form ? $this->searchForm( $result->searchTerm ) : ''; + $body = $result->posts + ? $this->resultsGrid( $result, $rules, $columns ) + : $this->emptyState( $result, $options ); + + return sprintf( + '
%s%s%s
', + $summary, + $form, + $body + ); + } + + private function summary( QueryResult $result ): string { + $term = '' !== $result->searchTerm + ? esc_html( sprintf( __( ' for “%s”', 'cc-divi5-search-results' ), $result->searchTerm ) ) + : ''; + + return sprintf( + '
%s%s
', + esc_html( sprintf( _n( '%d result', '%d results', $result->foundPosts, 'cc-divi5-search-results' ), $result->foundPosts ) ), + $term + ); + } + + private function searchForm( string $search_term ): string { + $input_id = wp_unique_id( 'cc-d5sr-search-' ); + + return sprintf( + '', + esc_url( home_url( '/' ) ), + esc_attr( $input_id ), + esc_html__( 'Search for:', 'cc-divi5-search-results' ), + esc_attr( $search_term ), + esc_attr__( 'Search the site', 'cc-divi5-search-results' ), + esc_html__( 'Search', 'cc-divi5-search-results' ) + ); + } + + private function resultsGrid( QueryResult $result, RuleCollection $rules, int $columns ): string { + $cards = ''; + + foreach ( $result->posts as $post ) { + $cards .= $this->card( $post, $rules->forPost( $post ) ); + } + + return sprintf( + '
%s
%s', + $columns, + $cards, + $this->pagination( $result ) + ); + } + + private function card( WP_Post $post, ResultTypeRule $rule ): string { + $permalink = get_permalink( $post ); + $title = get_the_title( $post ); + $image = ''; + + if ( $rule->showImage && has_post_thumbnail( $post ) ) { + $image = sprintf( + '', + esc_url( $permalink ), + get_the_post_thumbnail( + $post, + 'large', + array( + 'loading' => 'lazy', + 'alt' => '', + ) + ) + ); + } + + $date = $rule->showDate + ? sprintf( '', esc_attr( get_the_date( DATE_W3C, $post ) ), esc_html( get_the_date( '', $post ) ) ) + : ''; + + $excerpt = ''; + if ( $rule->showExcerpt && 0 < $rule->excerptLength ) { + $excerpt_text = wp_trim_words( wp_strip_all_tags( get_the_excerpt( $post ) ), $rule->excerptLength, '…' ); + $excerpt = '' !== $excerpt_text ? sprintf( '

%s

', esc_html( $excerpt_text ) ) : ''; + } + + return sprintf( + '', + esc_attr( $rule->postType ), + esc_attr( $rule->accentColor ), + $image, + esc_html( $rule->badgeLabel ), + $date, + esc_url( $permalink ), + esc_html( $title ), + $excerpt, + esc_html( $rule->ctaLabel ) + ); + } + + /** + * @param array $options + */ + private function emptyState( QueryResult $result, array $options ): string { + $title = sanitize_text_field( (string) ( $options['empty_title'] ?? __( 'No results found', 'cc-divi5-search-results' ) ) ); + $body = sanitize_text_field( (string) ( $options['empty_body'] ?? __( 'Try a different search term or browse another section of the site.', 'cc-divi5-search-results' ) ) ); + + return sprintf( + '

%1$s

%2$s

%3$s
', + esc_html( $title ), + esc_html( $body ), + '' !== $result->searchTerm + ? sprintf( '

%s

', esc_html( $result->searchTerm ) ) + : '' + ); + } + + private function pagination( QueryResult $result ): string { + if ( $result->maxPages < 2 ) { + return ''; + } + + $links = paginate_links( + array( + 'current' => $result->currentPage, + 'mid_size' => 2, + 'prev_text' => __( 'Previous', 'cc-divi5-search-results' ), + 'next_text' => __( 'Next', 'cc-divi5-search-results' ), + 'total' => $result->maxPages, + 'type' => 'list', + ) + ); + + if ( ! is_string( $links ) || '' === $links ) { + return ''; + } + + return sprintf( + '', + esc_attr__( 'Search results pages', 'cc-divi5-search-results' ), + wp_kses_post( $links ) + ); + } + + private function flag( $value ): bool { + if ( is_bool( $value ) ) { + return $value; + } + + return in_array( strtolower( (string) $value ), array( '1', 'on', 'true', 'yes' ), true ); + } +} diff --git a/includes/Support/AttributeValue.php b/includes/Support/AttributeValue.php new file mode 100644 index 0000000..a08af5c --- /dev/null +++ b/includes/Support/AttributeValue.php @@ -0,0 +1,65 @@ + $attrs + * @param list $path + * @param mixed $default + * + * @return mixed + */ + public static function get( array $attrs, array $path, $default = null ) { + $value = $attrs; + + foreach ( $path as $segment ) { + if ( ! is_array( $value ) || ! array_key_exists( $segment, $value ) ) { + return $default; + } + + $value = $value[ $segment ]; + } + + return $value; + } + + /** + * @param array $attrs + * @param list $path + */ + public static function desktop( array $attrs, array $path, string $default = '' ): string { + $value = self::get( + $attrs, + array_merge( $path, array( 'desktop', 'value' ) ), + $default + ); + + return is_scalar( $value ) ? (string) $value : $default; + } + + /** + * @param array $attrs + * @param list $path + */ + public static function desktopField( + array $attrs, + array $path, + string $field, + string $default = '' + ): string { + $value = self::get( + $attrs, + array_merge( $path, array( 'desktop', 'value', $field ) ), + $default + ); + + return is_scalar( $value ) ? (string) $value : $default; + } + + public static function isOn( string $value ): bool { + return 'on' === $value || '1' === $value || 'true' === strtolower( $value ); + } +} diff --git a/modules/SearchResultType/SearchResultTypeModule.php b/modules/SearchResultType/SearchResultTypeModule.php new file mode 100644 index 0000000..30174fc --- /dev/null +++ b/modules/SearchResultType/SearchResultTypeModule.php @@ -0,0 +1,35 @@ + array( self::class, 'renderCallback' ), + ) + ); + } + ); + } + + /** + * Configuration-only child modules are consumed by the parent module and do not render frontend markup. + */ + public static function renderCallback(): string { + return ''; + } +} diff --git a/modules/SearchResults/SearchResultsModule.php b/modules/SearchResults/SearchResultsModule.php new file mode 100644 index 0000000..bdfe7c6 --- /dev/null +++ b/modules/SearchResults/SearchResultsModule.php @@ -0,0 +1,177 @@ + array( self::class, 'renderCallback' ), + ) + ); + } + ); + } + + /** + * @param array $attrs + * @param array $default_printed_style_attrs + */ + public static function renderCallback( + array $attrs, + string $child_modules_content, + WP_Block $block, + ModuleElements $elements, + array $default_printed_style_attrs + ): string { + unset( $child_modules_content ); + + $children = self::childrenFromBlock( $block ); + $options = self::optionsFromAttrs( $attrs ); + $rules = self::rulesFromChildren( $children ); + $result = ( new SearchQueryResolver() )->resolve( + array( + 'post_types' => $rules->postTypes(), + 'posts_per_page' => $options['posts_per_page'], + 'search_term' => $options['search_term'], + 'source' => $options['source'], + ) + ); + $content = ( new SearchResultsRenderer() )->render( $result, $rules, $options ); + + return Module::render( + array( + 'attrs' => $attrs, + 'children' => array( + $elements->style_components( + array( + 'attrName' => 'module', + ) + ), + $content, + ), + 'childrenIds' => array_values( + array_filter( + array_map( + static fn ( $child ): string => is_string( $child->id ?? null ) ? $child->id : '', + $children + ) + ) + ), + 'classnamesFunction' => array( self::class, 'moduleClassnames' ), + 'defaultPrintedStyleAttrs' => $default_printed_style_attrs, + 'elements' => $elements, + 'id' => $block->parsed_block['id'], + 'moduleCategory' => $block->block_type->category, + 'name' => $block->block_type->name, + 'orderIndex' => $block->parsed_block['orderIndex'], + 'storeInstance' => $block->parsed_block['storeInstance'], + 'stylesComponent' => array( self::class, 'moduleStyles' ), + ) + ); + } + + /** + * @param array $args + */ + public static function moduleClassnames( array $args ): void { + $args['classnamesInstance']->add( 'cc-d5sr' ); + } + + /** + * @param array $args + */ + public static function moduleStyles( array $args ): void { + $default_printed_style_attrs = $args['defaultPrintedStyleAttrs'] ?? array(); + + Style::add( + array( + 'id' => $args['id'], + 'name' => $args['name'], + 'orderIndex' => $args['orderIndex'], + 'storeInstance' => $args['storeInstance'], + 'styles' => array( + $args['elements']->style( + array( + 'attrName' => 'module', + 'styleProps' => array( + 'defaultPrintedStyleAttrs' => $default_printed_style_attrs['module']['decoration'] ?? array(), + 'disabledOn' => array( + 'disabledModuleVisibility' => $args['settings']['disabledModuleVisibility'] ?? null, + ), + ), + ) + ), + ), + ) + ); + } + + /** + * @param array $attrs + * + * @return array + */ + private static function optionsFromAttrs( array $attrs ): array { + return array( + 'columns' => (int) AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'columns', '3' ), + 'empty_body' => AttributeValue::desktopField( $attrs, array( 'emptyState', 'innerContent' ), 'body', __( 'Try a different search term or browse another section of the site.', 'cc-divi5-search-results' ) ), + 'empty_title' => AttributeValue::desktopField( $attrs, array( 'emptyState', 'innerContent' ), 'title', __( 'No results found', 'cc-divi5-search-results' ) ), + 'posts_per_page' => (int) AttributeValue::desktopField( $attrs, array( 'query', 'innerContent' ), 'postsPerPage', '10' ), + 'search_term' => AttributeValue::desktopField( $attrs, array( 'query', 'innerContent' ), 'searchTerm', '' ), + 'show_search_form' => AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'showSearchForm', 'on' ), + 'show_summary' => AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'showSummary', 'on' ), + 'source' => AttributeValue::desktopField( $attrs, array( 'query', 'innerContent' ), 'source', 'current' ), + ); + } + + /** + * @return array + */ + private static function childrenFromBlock( WP_Block $block ): array { + $block_id = $block->parsed_block['id'] ?? ''; + $store_instance = $block->parsed_block['storeInstance'] ?? null; + + return BlockParserStore::get_children( $block_id, $store_instance ); + } + + /** + * @param array $children + */ + private static function rulesFromChildren( array $children ): RuleCollection { + $rules = array(); + + foreach ( $children as $child ) { + if ( 'codecorn/search-result-type' !== ( $child->blockName ?? '' ) ) { + continue; + } + + $rules[] = ResultTypeRule::fromDiviAttrs( is_array( $child->attrs ?? null ) ? $child->attrs : array() ); + } + + return new RuleCollection( $rules ); + } +} diff --git a/package.json b/package.json index f5ac78f..e7b5af0 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,30 @@ "description": "Native, type-aware search results for Divi 5.", "license": "MIT", "engines": { - "node": ">=18" + "node": ">=18.0.0", + "npm": ">=10.0.0" + }, + "scripts": { + "start": "NODE_ENV=development webpack -w --config webpack.config.js --progress", + "build": "NODE_ENV=production webpack --config webpack.config.js --progress", + "check:json": "node scripts/check-json.cjs" + }, + "devDependencies": { + "@divi/types": "npm:divi-types@^1.0.10", + "@types/divi__module": "npm:divi-types-module@^1.0.10", + "@types/divi__module-library": "npm:divi-types-module-library@^1.0.10", + "@types/react": "18.3.1", + "@types/react-dom": "18.3.0", + "@wordpress/hooks": "^3.57.0", + "copy-webpack-plugin": "^12.0.2", + "css-loader": "^7.1.1", + "mini-css-extract-plugin": "^2.9.0", + "react": "^18.2.0", + "sass": "^1.77.0", + "sass-loader": "^14.2.1", + "ts-loader": "^9.5.1", + "typescript": "^5.4.5", + "webpack": "^5.91.0", + "webpack-cli": "^5.1.4" } } diff --git a/scripts/check-json.cjs b/scripts/check-json.cjs new file mode 100644 index 0000000..89271f1 --- /dev/null +++ b/scripts/check-json.cjs @@ -0,0 +1,11 @@ +const fs = require('fs'); + +const files = [ + 'src/components/search-results/module.json', + 'src/components/search-result-type/module.json', +]; + +for (const file of files) { + JSON.parse(fs.readFileSync(file, 'utf8')); + process.stdout.write(`OK ${file}\n`); +} diff --git a/shortcodes/SearchResultsShortcode.php b/shortcodes/SearchResultsShortcode.php new file mode 100644 index 0000000..57f5085 --- /dev/null +++ b/shortcodes/SearchResultsShortcode.php @@ -0,0 +1,77 @@ +|string $attributes + */ + public static function render( $attributes = array() ): string { + $attributes = shortcode_atts( + array( + 'columns' => '3', + 'cta_label' => __( 'View result', 'cc-divi5-search-results' ), + 'excerpt_length' => '28', + 'post_types' => '', + 'posts_per_page' => '10', + 'search' => '', + 'show_date' => 'on', + 'show_excerpt' => 'on', + 'show_image' => 'on', + 'show_search_form' => 'on', + 'show_summary' => 'on', + 'source' => 'current', + ), + is_array( $attributes ) ? $attributes : array(), + 'cc_divi5_search_results' + ); + + $post_types = array_values( + array_filter( + array_map( 'sanitize_key', preg_split( '/[\s,]+/', (string) $attributes['post_types'] ) ?: array() ) + ) + ); + + $rules = array_map( + static fn ( string $post_type ): ResultTypeRule => ResultTypeRule::fromFlatArray( + array( + 'post_type' => $post_type, + 'cta_label' => $attributes['cta_label'], + 'excerpt_length' => $attributes['excerpt_length'], + 'show_date' => $attributes['show_date'], + 'show_excerpt' => $attributes['show_excerpt'], + 'show_image' => $attributes['show_image'], + ) + ), + $post_types + ); + + $result = ( new SearchQueryResolver() )->resolve( + array( + 'post_types' => $post_types, + 'posts_per_page' => (int) $attributes['posts_per_page'], + 'search_term' => (string) $attributes['search'], + 'source' => (string) $attributes['source'], + ) + ); + + return ( new SearchResultsRenderer() )->render( + $result, + new RuleCollection( $rules ), + array( + 'columns' => (int) $attributes['columns'], + 'show_search_form' => $attributes['show_search_form'], + 'show_summary' => $attributes['show_summary'], + ) + ); + } +} diff --git a/src/components/search-result-type/edit.tsx b/src/components/search-result-type/edit.tsx new file mode 100644 index 0000000..6689d6f --- /dev/null +++ b/src/components/search-result-type/edit.tsx @@ -0,0 +1,19 @@ +import React, { ReactElement } from 'react'; +import { ModuleContainer } from '@divi/module'; + +import { SearchResultTypeEditProps } from './types'; + +export const SearchResultTypeEdit = (props: SearchResultTypeEditProps): ReactElement => { + const { attrs, elements, id, name } = props; + const rule = attrs.rule?.innerContent?.desktop?.value; + const postType = rule?.postType || 'post'; + + return ( + +
+ {rule?.badgeLabel || postType} + {postType} +
+
+ ); +}; diff --git a/src/components/search-result-type/index.ts b/src/components/search-result-type/index.ts new file mode 100644 index 0000000..01ac3c9 --- /dev/null +++ b/src/components/search-result-type/index.ts @@ -0,0 +1,14 @@ +import { type Metadata, type ModuleLibrary } from '@divi/types'; + +import metadata from './module.json'; +import { SearchResultTypeEdit } from './edit'; +import { SearchResultTypeAttrs } from './types'; + +import './module.scss'; + +export const searchResultTypeModule: ModuleLibrary.Module.RegisterDefinition = { + metadata: metadata as Metadata.Values, + renderers: { + edit: SearchResultTypeEdit, + }, +}; diff --git a/src/components/search-result-type/module.json b/src/components/search-result-type/module.json new file mode 100644 index 0000000..660cc0c --- /dev/null +++ b/src/components/search-result-type/module.json @@ -0,0 +1,221 @@ +{ + "name": "codecorn/search-result-type", + "d4Shortcode": "", + "title": "Result Type Rule", + "titles": "Result Type Rules", + "moduleIcon": "divi/module-toggle", + "moduleClassName": "cc-d5sr-rule", + "moduleOrderClassName": "cc-d5sr-rule", + "category": "child-module", + "childrenName": [], + "attributes": { + "module": { + "type": "object", + "selector": "{{selector}}", + "settings": { + "meta": { + "meta": {} + }, + "advanced": { + "html": {} + }, + "decoration": { + "disabledOn": {} + } + } + }, + "rule": { + "type": "object", + "default": { + "innerContent": { + "desktop": { + "value": { + "postType": "post", + "singularLabel": "", + "pluralLabel": "", + "badgeLabel": "", + "accentColor": "#2b2f36", + "priority": "10", + "showImage": "on", + "showExcerpt": "on", + "showDate": "on", + "excerptLength": "28", + "ctaLabel": "View result" + } + } + } + }, + "settings": { + "innerContent": { + "groupType": "group-items", + "items": { + "postType": { + "groupSlug": "contentRule", + "priority": 10, + "render": true, + "subName": "postType", + "label": "Post type slug", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "singularLabel": { + "groupSlug": "contentLabels", + "priority": 10, + "render": true, + "subName": "singularLabel", + "label": "Singular label", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "pluralLabel": { + "groupSlug": "contentLabels", + "priority": 20, + "render": true, + "subName": "pluralLabel", + "label": "Plural label", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "badgeLabel": { + "groupSlug": "contentLabels", + "priority": 30, + "render": true, + "subName": "badgeLabel", + "label": "Badge label", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "priority": { + "groupSlug": "contentRule", + "priority": 20, + "render": true, + "subName": "priority", + "label": "Rule priority", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "accentColor": { + "groupSlug": "contentCard", + "priority": 10, + "render": true, + "subName": "accentColor", + "label": "Accent color", + "component": { + "type": "field", + "name": "divi/color-picker" + } + }, + "showImage": { + "groupSlug": "contentCard", + "priority": 20, + "render": true, + "subName": "showImage", + "label": "Show image", + "component": { + "type": "field", + "name": "divi/toggle" + } + }, + "showExcerpt": { + "groupSlug": "contentCard", + "priority": 30, + "render": true, + "subName": "showExcerpt", + "label": "Show excerpt", + "component": { + "type": "field", + "name": "divi/toggle" + } + }, + "showDate": { + "groupSlug": "contentCard", + "priority": 40, + "render": true, + "subName": "showDate", + "label": "Show date", + "component": { + "type": "field", + "name": "divi/toggle" + } + }, + "excerptLength": { + "groupSlug": "contentCard", + "priority": 50, + "render": true, + "subName": "excerptLength", + "label": "Excerpt words", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "ctaLabel": { + "groupSlug": "contentCard", + "priority": 60, + "render": true, + "subName": "ctaLabel", + "label": "CTA label", + "component": { + "type": "field", + "name": "divi/text" + } + } + } + } + } + } + }, + "settings": { + "content": "auto", + "design": "auto", + "advanced": "auto", + "groups": { + "contentRule": { + "panel": "content", + "priority": 10, + "groupName": "contentRule", + "multiElements": true, + "component": { + "name": "divi/composite", + "props": { + "groupLabel": "Rule" + } + } + }, + "contentLabels": { + "panel": "content", + "priority": 20, + "groupName": "contentLabels", + "multiElements": true, + "component": { + "name": "divi/composite", + "props": { + "groupLabel": "Labels" + } + } + }, + "contentCard": { + "panel": "content", + "priority": 30, + "groupName": "contentCard", + "multiElements": true, + "component": { + "name": "divi/composite", + "props": { + "groupLabel": "Card" + } + } + } + } + } +} diff --git a/src/components/search-result-type/module.scss b/src/components/search-result-type/module.scss new file mode 100644 index 0000000..adb6d8f --- /dev/null +++ b/src/components/search-result-type/module.scss @@ -0,0 +1,10 @@ +.cc-d5sr-rule-vb { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 8px; + padding: 10px 12px; + border: 1px solid; + border-radius: 6px; +} diff --git a/src/components/search-result-type/types.ts b/src/components/search-result-type/types.ts new file mode 100644 index 0000000..f96874e --- /dev/null +++ b/src/components/search-result-type/types.ts @@ -0,0 +1,20 @@ +import { ModuleEditProps } from '@divi/module-library'; +import { FormatBreakpointStateAttr, InternalAttrs, type Element } from '@divi/types'; + +export interface ResultTypeRuleValue { + postType?: string; + badgeLabel?: string; + accentColor?: string; + priority?: string; +} + +export interface SearchResultTypeAttrs extends InternalAttrs { + module?: { + meta?: Element.Meta.Attributes; + advanced?: Record; + decoration?: Record; + }; + rule?: { innerContent?: FormatBreakpointStateAttr }; +} + +export type SearchResultTypeEditProps = ModuleEditProps; diff --git a/src/components/search-results/edit.tsx b/src/components/search-results/edit.tsx new file mode 100644 index 0000000..0b4eb65 --- /dev/null +++ b/src/components/search-results/edit.tsx @@ -0,0 +1,35 @@ +import React, { ReactElement } from 'react'; +import { ChildModulesContainer, ModuleContainer } from '@divi/module'; + +import { moduleClassnames } from './module-classnames'; +import { ModuleStyles } from './styles'; +import { SearchResultsEditProps } from './types'; + +export const SearchResultsEdit = (props: SearchResultsEditProps): ReactElement => { + const { attrs, childrenIds, elements, id, name } = props; + const query = attrs.query?.innerContent?.desktop?.value; + + return ( + + {elements.styleComponents({ attrName: 'module' })} +
+ Search Results + + {query?.source === 'isolated' + ? `Isolated query: ${query.searchTerm || 'no search term'}` + : 'Current WordPress search query'} + + Result Type Rule children configure the frontend cards. +
+ +
+ ); +}; diff --git a/src/components/search-results/index.ts b/src/components/search-results/index.ts new file mode 100644 index 0000000..d18d063 --- /dev/null +++ b/src/components/search-results/index.ts @@ -0,0 +1,19 @@ +import { type Metadata, type ModuleLibrary } from '@divi/types'; + +import metadata from './module.json'; +import { SearchResultsEdit } from './edit'; +import { SearchResultsAttrs } from './types'; + +import './module.scss'; + +export const searchResultsModule: ModuleLibrary.Module.RegisterDefinition = { + metadata: metadata as Metadata.Values, + childrenName: ['codecorn/search-result-type'], + template: [ + ['codecorn/search-result-type', { rule: { innerContent: { desktop: { value: { postType: 'post' } } } } }], + ['codecorn/search-result-type', { rule: { innerContent: { desktop: { value: { postType: 'page' } } } } }], + ], + renderers: { + edit: SearchResultsEdit, + }, +}; diff --git a/src/components/search-results/module-classnames.ts b/src/components/search-results/module-classnames.ts new file mode 100644 index 0000000..2dbab09 --- /dev/null +++ b/src/components/search-results/module-classnames.ts @@ -0,0 +1,9 @@ +import { ModuleClassnamesParams } from '@divi/module'; + +import { SearchResultsAttrs } from './types'; + +export const moduleClassnames = ({ + classnamesInstance, +}: ModuleClassnamesParams): void => { + classnamesInstance.add('cc-d5sr'); +}; diff --git a/src/components/search-results/module.json b/src/components/search-results/module.json new file mode 100644 index 0000000..b203180 --- /dev/null +++ b/src/components/search-results/module.json @@ -0,0 +1,264 @@ +{ + "name": "codecorn/search-results", + "d4Shortcode": "", + "title": "Search Results", + "titles": "Search Results", + "moduleIcon": "divi/module-search", + "moduleClassName": "cc-d5sr", + "moduleOrderClassName": "cc-d5sr", + "childModuleName": "codecorn/search-result-type", + "childModuleTitle": "Result Type Rule", + "category": "module", + "childrenName": [ + "codecorn/search-result-type" + ], + "attributes": { + "module": { + "type": "object", + "selector": "{{selector}}", + "settings": { + "meta": { + "meta": {} + }, + "advanced": { + "html": {}, + "link": {}, + "text": {} + }, + "decoration": { + "animation": {}, + "attributes": {}, + "background": {}, + "border": {}, + "boxShadow": {}, + "conditions": {}, + "disabledOn": {}, + "filters": {}, + "overflow": {}, + "position": {}, + "scroll": {}, + "sizing": {}, + "spacing": {}, + "sticky": {}, + "transform": {}, + "transition": {}, + "zIndex": {} + } + } + }, + "query": { + "type": "object", + "default": { + "innerContent": { + "desktop": { + "value": { + "source": "current", + "searchTerm": "", + "postsPerPage": "10" + } + } + } + }, + "settings": { + "innerContent": { + "groupType": "group-items", + "items": { + "source": { + "groupSlug": "contentQuery", + "priority": 10, + "render": true, + "subName": "source", + "label": "Query source", + "component": { + "type": "field", + "name": "divi/select", + "props": { + "options": { + "current": { + "label": "Current search query" + }, + "isolated": { + "label": "Isolated query" + } + } + } + } + }, + "searchTerm": { + "groupSlug": "contentQuery", + "priority": 20, + "render": true, + "subName": "searchTerm", + "label": "Search term", + "description": "Used by the isolated query and by Visual Builder previews.", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "postsPerPage": { + "groupSlug": "contentQuery", + "priority": 30, + "render": true, + "subName": "postsPerPage", + "label": "Results per page", + "component": { + "type": "field", + "name": "divi/text" + } + } + } + } + } + }, + "display": { + "type": "object", + "default": { + "innerContent": { + "desktop": { + "value": { + "showSummary": "on", + "showSearchForm": "on", + "columns": "3" + } + } + } + }, + "settings": { + "innerContent": { + "groupType": "group-items", + "items": { + "showSummary": { + "groupSlug": "contentDisplay", + "priority": 10, + "render": true, + "subName": "showSummary", + "label": "Show result count", + "component": { + "type": "field", + "name": "divi/toggle" + } + }, + "showSearchForm": { + "groupSlug": "contentDisplay", + "priority": 20, + "render": true, + "subName": "showSearchForm", + "label": "Show search form", + "component": { + "type": "field", + "name": "divi/toggle" + } + }, + "columns": { + "groupSlug": "contentDisplay", + "priority": 30, + "render": true, + "subName": "columns", + "label": "Desktop columns", + "component": { + "type": "field", + "name": "divi/select", + "props": { + "options": { + "1": { "label": "1" }, + "2": { "label": "2" }, + "3": { "label": "3" }, + "4": { "label": "4" }, + "5": { "label": "5" }, + "6": { "label": "6" } + } + } + } + } + } + } + } + }, + "emptyState": { + "type": "object", + "default": { + "innerContent": { + "desktop": { + "value": { + "title": "No results found", + "body": "Try a different search term or browse another section of the site." + } + } + } + }, + "settings": { + "innerContent": { + "groupType": "group-items", + "items": { + "title": { + "groupSlug": "contentEmpty", + "priority": 10, + "render": true, + "subName": "title", + "label": "Empty-state title", + "component": { + "type": "field", + "name": "divi/text" + } + }, + "body": { + "groupSlug": "contentEmpty", + "priority": 20, + "render": true, + "subName": "body", + "label": "Empty-state message", + "component": { + "type": "field", + "name": "divi/textarea" + } + } + } + } + } + } + }, + "settings": { + "content": "auto", + "design": "auto", + "advanced": "auto", + "groups": { + "contentQuery": { + "panel": "content", + "priority": 10, + "groupName": "contentQuery", + "multiElements": true, + "component": { + "name": "divi/composite", + "props": { + "groupLabel": "Query" + } + } + }, + "contentDisplay": { + "panel": "content", + "priority": 20, + "groupName": "contentDisplay", + "multiElements": true, + "component": { + "name": "divi/composite", + "props": { + "groupLabel": "Display" + } + } + }, + "contentEmpty": { + "panel": "content", + "priority": 30, + "groupName": "contentEmpty", + "multiElements": true, + "component": { + "name": "divi/composite", + "props": { + "groupLabel": "Empty state" + } + } + } + } + } +} diff --git a/src/components/search-results/module.scss b/src/components/search-results/module.scss new file mode 100644 index 0000000..0d134ad --- /dev/null +++ b/src/components/search-results/module.scss @@ -0,0 +1,11 @@ +.cc-d5sr-vb-preview { + display: grid; + gap: 6px; + padding: 18px; + border: 1px dashed currentColor; + border-radius: 8px; +} + +.cc-d5sr-vb-preview small { + opacity: 0.7; +} diff --git a/src/components/search-results/styles.tsx b/src/components/search-results/styles.tsx new file mode 100644 index 0000000..13833dd --- /dev/null +++ b/src/components/search-results/styles.tsx @@ -0,0 +1,23 @@ +import React, { ReactElement } from 'react'; +import { StyleContainer, StylesProps } from '@divi/module'; + +import { SearchResultsAttrs } from './types'; + +export const ModuleStyles = ({ + elements, + mode, + noStyleTag, + settings, + state, +}: StylesProps): ReactElement => ( + + {elements.style({ + attrName: 'module', + styleProps: { + disabledOn: { + disabledModuleVisibility: settings?.disabledModuleVisibility, + }, + }, + })} + +); diff --git a/src/components/search-results/types.ts b/src/components/search-results/types.ts new file mode 100644 index 0000000..78d5a8e --- /dev/null +++ b/src/components/search-results/types.ts @@ -0,0 +1,32 @@ +import { ModuleEditProps } from '@divi/module-library'; +import { FormatBreakpointStateAttr, InternalAttrs, type Element } from '@divi/types'; + +export interface SearchResultsQueryValue { + source?: string; + searchTerm?: string; + postsPerPage?: string; +} + +export interface SearchResultsDisplayValue { + showSummary?: string; + showSearchForm?: string; + columns?: string; +} + +export interface SearchResultsEmptyValue { + title?: string; + body?: string; +} + +export interface SearchResultsAttrs extends InternalAttrs { + module?: { + meta?: Element.Meta.Attributes; + advanced?: Record; + decoration?: Record; + }; + query?: { innerContent?: FormatBreakpointStateAttr }; + display?: { innerContent?: FormatBreakpointStateAttr }; + emptyState?: { innerContent?: FormatBreakpointStateAttr }; +} + +export type SearchResultsEditProps = ModuleEditProps; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..0368436 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,13 @@ +import { addAction } from '@wordpress/hooks'; +import { registerModule } from '@divi/module-library'; + +import { searchResultTypeModule } from './components/search-result-type'; +import { searchResultsModule } from './components/search-results'; + +addAction('divi.moduleLibrary.registerModuleLibraryStore.after', 'codecorn/search-results', () => { + const { metadata: resultTypeMetadata, ...resultTypeDefinition } = searchResultTypeModule; + const { metadata: searchResultsMetadata, ...searchResultsDefinition } = searchResultsModule; + + registerModule(resultTypeMetadata, resultTypeDefinition); + registerModule(searchResultsMetadata, searchResultsDefinition); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..febcb0a --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "module": "esnext", + "moduleResolution": "node", + "noEmit": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "es2019" + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..c2cb97c --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,53 @@ +const path = require('path'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); + +module.exports = { + entry: { + bundle: './src/index.ts', + }, + externals: { + react: ['vendor', 'React'], + 'react-dom': ['vendor', 'ReactDOM'], + '@wordpress/hooks': ['vendor', 'wp', 'hooks'], + '@divi/module': ['divi', 'module'], + '@divi/module-library': ['divi', 'moduleLibrary'], + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: { + loader: 'ts-loader', + options: { + transpileOnly: false, + }, + }, + exclude: /node_modules/, + }, + { + test: /\.s?css$/i, + use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'], + }, + ], + }, + plugins: [ + new MiniCssExtractPlugin({ filename: '../styles/vb-[name].css' }), + new CopyWebpackPlugin({ + patterns: [ + { + from: '**/module.json', + context: 'src/components', + to: path.resolve(__dirname, 'modules-json'), + }, + ], + }), + ], + resolve: { + extensions: ['.js', '.jsx', '.tsx', '.ts', '.json'], + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, 'scripts'), + }, +}; From 0ad029fbaf614de9c2cd96eacd2aa20136b7f525 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:17:28 +0200 Subject: [PATCH 02/78] fix: align Divi TypeScript dependencies --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index e7b5af0..8dd3be1 100644 --- a/package.json +++ b/package.json @@ -11,14 +11,19 @@ "scripts": { "start": "NODE_ENV=development webpack -w --config webpack.config.js --progress", "build": "NODE_ENV=production webpack --config webpack.config.js --progress", + "check": "npm run check:types && npm run check:json", + "check:types": "tsc --noEmit", "check:json": "node scripts/check-json.cjs" }, "devDependencies": { "@divi/types": "npm:divi-types@^1.0.10", + "@tinymce/tinymce-react": "^5.0.1", "@types/divi__module": "npm:divi-types-module@^1.0.10", "@types/divi__module-library": "npm:divi-types-module-library@^1.0.10", "@types/react": "18.3.1", "@types/react-dom": "18.3.0", + "@types/seamless-immutable": "^7.1.19", + "@types/wordpress__blocks": "^12.5.14", "@wordpress/hooks": "^3.57.0", "copy-webpack-plugin": "^12.0.2", "css-loader": "^7.1.1", @@ -26,6 +31,7 @@ "react": "^18.2.0", "sass": "^1.77.0", "sass-loader": "^14.2.1", + "seamless-immutable": "^7.1.4", "ts-loader": "^9.5.1", "typescript": "^5.4.5", "webpack": "^5.91.0", From 969757e26220014c83ad7ba038cf866fed7e79c2 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:17:37 +0200 Subject: [PATCH 03/78] fix: make the Divi bundle emit compatible JavaScript --- tsconfig.json | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index febcb0a..562888f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,16 +1,17 @@ { "compilerOptions": { + "allowJs": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, - "jsx": "react-jsx", - "module": "esnext", + "jsx": "react", + "module": "es6", "moduleResolution": "node", - "noEmit": true, + "noImplicitAny": true, + "outDir": "./scripts/", "resolveJsonModule": true, "skipLibCheck": true, - "strict": true, - "target": "es2019" + "target": "es5" }, "include": ["src/**/*.ts", "src/**/*.tsx"] } From 2ed5fbac6c2105a915c5ab58851e6fa7a6a942a4 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:17:50 +0200 Subject: [PATCH 04/78] fix: use Divi-native parent attribute types --- src/components/search-results/types.ts | 30 +++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/search-results/types.ts b/src/components/search-results/types.ts index 78d5a8e..12d54cd 100644 --- a/src/components/search-results/types.ts +++ b/src/components/search-results/types.ts @@ -1,5 +1,9 @@ import { ModuleEditProps } from '@divi/module-library'; -import { FormatBreakpointStateAttr, InternalAttrs, type Element } from '@divi/types'; +import { + FormatBreakpointStateAttr, + InternalAttrs, + type Element, +} from '@divi/types'; export interface SearchResultsQueryValue { source?: string; @@ -21,8 +25,28 @@ export interface SearchResultsEmptyValue { export interface SearchResultsAttrs extends InternalAttrs { module?: { meta?: Element.Meta.Attributes; - advanced?: Record; - decoration?: Record; + advanced?: { + link?: Element.Advanced.Link.Attributes; + htmlAttributes?: Element.Advanced.IdClasses.Attributes; + text?: Element.Advanced.Text.Attributes; + }; + decoration?: Element.Decoration.PickedAttributes< + 'animation' | + 'background' | + 'border' | + 'boxShadow' | + 'disabledOn' | + 'filters' | + 'overflow' | + 'position' | + 'scroll' | + 'sizing' | + 'spacing' | + 'sticky' | + 'transform' | + 'transition' | + 'zIndex' + >; }; query?: { innerContent?: FormatBreakpointStateAttr }; display?: { innerContent?: FormatBreakpointStateAttr }; From df7076519d52d98171f1325e22d49cb3910bb1a6 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:18:07 +0200 Subject: [PATCH 05/78] fix: type child rules against the native parent --- src/components/search-result-type/types.ts | 26 ++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/components/search-result-type/types.ts b/src/components/search-result-type/types.ts index f96874e..efd8efc 100644 --- a/src/components/search-result-type/types.ts +++ b/src/components/search-result-type/types.ts @@ -1,20 +1,38 @@ import { ModuleEditProps } from '@divi/module-library'; -import { FormatBreakpointStateAttr, InternalAttrs, type Element } from '@divi/types'; +import { + FormatBreakpointStateAttr, + InternalAttrs, + type Element, +} from '@divi/types'; + +import { SearchResultsAttrs } from '../search-results/types'; export interface ResultTypeRuleValue { postType?: string; + singularLabel?: string; + pluralLabel?: string; badgeLabel?: string; accentColor?: string; priority?: string; + showImage?: string; + showExcerpt?: string; + showDate?: string; + excerptLength?: string; + ctaLabel?: string; } export interface SearchResultTypeAttrs extends InternalAttrs { module?: { meta?: Element.Meta.Attributes; - advanced?: Record; - decoration?: Record; + advanced?: { + htmlAttributes?: Element.Advanced.IdClasses.Attributes; + }; + decoration?: Element.Decoration.PickedAttributes<'disabledOn'>; }; rule?: { innerContent?: FormatBreakpointStateAttr }; } -export type SearchResultTypeEditProps = ModuleEditProps; +export type SearchResultTypeEditProps = ModuleEditProps< + SearchResultTypeAttrs, + SearchResultsAttrs +>; From a046d7dca57cd4d65ffa23025370579a51b6a382 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:18:22 +0200 Subject: [PATCH 06/78] fix: guard Visual Builder edit props --- src/components/search-results/edit.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/search-results/edit.tsx b/src/components/search-results/edit.tsx index 0b4eb65..c77451a 100644 --- a/src/components/search-results/edit.tsx +++ b/src/components/search-results/edit.tsx @@ -6,7 +6,18 @@ import { ModuleStyles } from './styles'; import { SearchResultsEditProps } from './types'; export const SearchResultsEdit = (props: SearchResultsEditProps): ReactElement => { - const { attrs, childrenIds, elements, id, name } = props; + const { + attrs, + childrenIds = [], + elements, + id, + name, + } = props; + + if (! elements) { + return <>; + } + const query = attrs.query?.innerContent?.desktop?.value; return ( From d92bdb5823d34103ac413d320796d9d4d4e99cfd Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:18:32 +0200 Subject: [PATCH 07/78] fix: narrow Divi style renderer props --- src/components/search-results/styles.tsx | 42 ++++++++++++++---------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/src/components/search-results/styles.tsx b/src/components/search-results/styles.tsx index 13833dd..0afe5c9 100644 --- a/src/components/search-results/styles.tsx +++ b/src/components/search-results/styles.tsx @@ -3,21 +3,29 @@ import { StyleContainer, StylesProps } from '@divi/module'; import { SearchResultsAttrs } from './types'; -export const ModuleStyles = ({ - elements, - mode, - noStyleTag, - settings, - state, -}: StylesProps): ReactElement => ( - - {elements.style({ - attrName: 'module', - styleProps: { - disabledOn: { - disabledModuleVisibility: settings?.disabledModuleVisibility, +export const ModuleStyles = (props: StylesProps): ReactElement => { + const { + elements, + mode, + noStyleTag, + settings, + state, + } = props; + + if (! elements || ! mode || ! state) { + return <>; + } + + return ( + + {elements.style({ + attrName: 'module', + styleProps: { + disabledOn: { + disabledModuleVisibility: settings?.disabledModuleVisibility, + }, }, - }, - })} - -); + })} + + ); +}; From a70cb3f917e15e390de6cc580b787a7de99c09f5 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:19:53 +0200 Subject: [PATCH 08/78] docs: align build instructions with the actual toolchain --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 12b1afd..21a0dca 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The `0.1.0` development branch currently includes: - repeatable post-type rules for labels, badge, accent, image, excerpt, date and CTA; - accessible result count, search form, result cards, pagination and empty state; - shared rendering used by both the native module and `[cc_divi5_search_results]`; -- Visual Builder TypeScript sources and build configuration; +- Visual Builder TypeScript sources, Divi-compatible compiler configuration and webpack build; - frontend CSS with responsive grid behavior. The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. @@ -117,6 +117,7 @@ Install and build: ```bash composer install npm install +npm run check npm run build ``` @@ -124,9 +125,14 @@ Validation: ```bash composer check:syntax +npm run check:types npm run check:json ``` +`ts-loader` performs type checking during `npm run build`; it is not configured with `transpileOnly`. The compiler configuration intentionally follows the compatibility surface used by the official Divi 5 example modules: emitted ES5 JavaScript, classic React JSX and no strict-null checking inside the published Divi type sources. + +The npm installation can report peer-resolution and deprecation warnings from the `divi-types*` compatibility aliases used by Elegant Themes. Those warnings are not treated as a successful build: the authoritative result is the exit status of `npm run check` and `npm run build`. Do not run `npm audit fix --force`, because it can replace Divi-compatible development dependencies with breaking versions. + After `npm run build`, the generated files are: ```text @@ -154,7 +160,7 @@ Those capabilities will be added in later reviewable increments without changing ## Documentation rule -Every pull request that changes behavior, controls, requirements, generated paths or public APIs must update this README in the same pull request. Documentation may describe merged or included code only; planned behavior belongs exclusively in **Not implemented yet**. +Every pull request that changes behavior, controls, requirements, generated paths, build commands, dependency requirements or public APIs must update this README in the same pull request. Documentation may describe merged or included code only; planned behavior belongs exclusively in **Not implemented yet**. ## License From 66e59a5cc6709bb010bc4d196a758cb8efcb4d81 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 20:20:06 +0200 Subject: [PATCH 09/78] docs: record the Divi build compatibility fixes --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63f04a5..61623c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,12 @@ - Optional `[cc_divi5_search_results]` adapter backed by the shared resolver and renderer. - Visual Builder TypeScript source, webpack build and responsive frontend styles. - README documentation contract requiring code and documentation to remain synchronized in every PR. +- Explicit TypeScript validation through `npm run check:types` and aggregate validation through `npm run check`. ### Changed - Plugin bootstrap now supports Composer autoloading and a source-checkout fallback autoloader. +- TypeScript compiler settings now emit the Divi Visual Builder bundle and follow the compatibility settings used by the official Divi 5 example modules. +- Visual Builder attribute interfaces now use native Divi element types instead of generic unknown records. +- Visual Builder edit and style renderers now guard optional props exposed by the published Divi types. +- Development dependencies now include the transitive declarations required by the Divi 5.9.0 type packages. From b464ce00663f821cd2c3f173eb92367fb454b0dd Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:27:49 +0200 Subject: [PATCH 10/78] fix: make Divi dependency installation reproducible --- .npmrc | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..d5831dd --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +engine-strict=true +legacy-peer-deps=true From 97dd18dd54423a84aa8b2cccc2cf331eef1ee8b4 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:28:40 +0200 Subject: [PATCH 11/78] docs: document Divi peer dependency policy --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 21a0dca..a17a73e 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ The `0.1.0` development branch currently includes: - accessible result count, search form, result cards, pagination and empty state; - shared rendering used by both the native module and `[cc_divi5_search_results]`; - Visual Builder TypeScript sources, Divi-compatible compiler configuration and webpack build; +- repository-level npm configuration for the incompatible peer ranges published by the Divi 5 type aliases; - frontend CSS with responsive grid behavior. The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. @@ -121,6 +122,13 @@ npm run check npm run build ``` +After any change to `package.json` or `.npmrc`, reset the local dependency tree before validating: + +```bash +rm -rf node_modules package-lock.json +npm install +``` + Validation: ```bash @@ -131,7 +139,9 @@ npm run check:json `ts-loader` performs type checking during `npm run build`; it is not configured with `transpileOnly`. The compiler configuration intentionally follows the compatibility surface used by the official Divi 5 example modules: emitted ES5 JavaScript, classic React JSX and no strict-null checking inside the published Divi type sources. -The npm installation can report peer-resolution and deprecation warnings from the `divi-types*` compatibility aliases used by Elegant Themes. Those warnings are not treated as a successful build: the authoritative result is the exit status of `npm run check` and `npm run build`. Do not run `npm audit fix --force`, because it can replace Divi-compatible development dependencies with breaking versions. +The published Divi 5 type aliases contain mutually incompatible development-only peer ranges: `react-dates` requests React/ReactDOM 16 while current WordPress packages request React 18. The repository therefore commits `.npmrc` with `legacy-peer-deps=true`; this prevents npm 10 from attempting an impossible peer-resolution graph. React remains externalized from the Visual Builder bundle, so this setting does not select or ship a second runtime React version. The same file keeps `engine-strict=true`. + +The npm installation can still report deprecation warnings from the `divi-types*` compatibility aliases used by Elegant Themes. Those warnings are not treated as a successful build: the authoritative result is the exit status of `npm run check` and `npm run build`. Do not run `npm audit fix --force`, because it can replace Divi-compatible development dependencies with breaking versions. After `npm run build`, the generated files are: From 07ac92c8e7e966f4a6079b600e653f26639972d4 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:28:52 +0200 Subject: [PATCH 12/78] docs: record npm peer dependency policy --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61623c5..4a39833 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Visual Builder TypeScript source, webpack build and responsive frontend styles. - README documentation contract requiring code and documentation to remain synchronized in every PR. - Explicit TypeScript validation through `npm run check:types` and aggregate validation through `npm run check`. +- Repository `.npmrc` with strict engine enforcement and deterministic handling of incompatible Divi peer ranges. ### Changed @@ -20,3 +21,4 @@ - Visual Builder attribute interfaces now use native Divi element types instead of generic unknown records. - Visual Builder edit and style renderers now guard optional props exposed by the published Divi types. - Development dependencies now include the transitive declarations required by the Divi 5.9.0 type packages. +- Development documentation now requires a clean dependency-tree reset after changes to `package.json` or `.npmrc`. From 157ce1356f60f694af63d833cc9fb8fa946ef8ac Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:29:08 +0200 Subject: [PATCH 13/78] chore: add clean dependency reset command --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8dd3be1..cf0fadf 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "build": "NODE_ENV=production webpack --config webpack.config.js --progress", "check": "npm run check:types && npm run check:json", "check:types": "tsc --noEmit", - "check:json": "node scripts/check-json.cjs" + "check:json": "node scripts/check-json.cjs", + "reset-install": "rm -rf node_modules package-lock.json && npm install" }, "devDependencies": { "@divi/types": "npm:divi-types@^1.0.10", From f3df6fe41565edbfe76bb4abb49b85fdeecf4da3 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:29:54 +0200 Subject: [PATCH 14/78] docs: use the committed dependency reset command --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a17a73e..a942eb2 100644 --- a/README.md +++ b/README.md @@ -125,10 +125,11 @@ npm run build After any change to `package.json` or `.npmrc`, reset the local dependency tree before validating: ```bash -rm -rf node_modules package-lock.json -npm install +npm run reset-install ``` +`reset-install` removes `node_modules` and `package-lock.json`, then performs a fresh install using the repository `.npmrc` policy. + Validation: ```bash From 1caeac0897061b4acb4b1ba3bc397d641bca1a1e Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:30:13 +0200 Subject: [PATCH 15/78] docs: record clean dependency reset command --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a39833..83821df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - README documentation contract requiring code and documentation to remain synchronized in every PR. - Explicit TypeScript validation through `npm run check:types` and aggregate validation through `npm run check`. - Repository `.npmrc` with strict engine enforcement and deterministic handling of incompatible Divi peer ranges. +- `npm run reset-install` for a clean dependency-tree rebuild after manifest or npm-policy changes. ### Changed From b2e0494dfeed1f80433cb4c8b97a554a2b988989 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:30:48 +0200 Subject: [PATCH 16/78] chore: normalize dependency reset command From ce95e41cfdfdec5825402c4b6672b01003d32318 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:31:18 +0200 Subject: [PATCH 17/78] docs: clarify clean install command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a942eb2..c8dce32 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ After any change to `package.json` or `.npmrc`, reset the local dependency tree npm run reset-install ``` -`reset-install` removes `node_modules` and `package-lock.json`, then performs a fresh install using the repository `.npmrc` policy. +`reset-install` removes `node_modules` and `package-lock.json`, then performs a fresh install using the repository `.npmrc` policy. Run it only after pulling the commit that defines the script. Validation: From efc52b135340bd73ad80342f24a400d471e78a0f Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:31:32 +0200 Subject: [PATCH 18/78] docs: align reset-install wording --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 83821df..da7f230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,4 +22,4 @@ - Visual Builder attribute interfaces now use native Divi element types instead of generic unknown records. - Visual Builder edit and style renderers now guard optional props exposed by the published Divi types. - Development dependencies now include the transitive declarations required by the Divi 5.9.0 type packages. -- Development documentation now requires a clean dependency-tree reset after changes to `package.json` or `.npmrc`. +- Development documentation now requires the committed reset command after changes to `package.json` or `.npmrc`. From 6aa89dc4ff1bf9fb533b39de4f40e50e86b7ecf3 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:32:11 +0200 Subject: [PATCH 19/78] docs: keep install workflow exact From 9d5afb8978566b6f646fa3333f637049c61e0e7c Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:32:27 +0200 Subject: [PATCH 20/78] docs: preserve dependency reset record From 31f08af994b49d1b41712aabf83fd21e07d66171 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:32:52 +0200 Subject: [PATCH 21/78] chore: keep reset-install script From f31052291ecc53d1852e4d3b82f8d875c5eef315 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:33:13 +0200 Subject: [PATCH 22/78] chore: preserve dependency reset command From 0372424492654a4b1c3004e24b6ff20343b475cb Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 21:33:47 +0200 Subject: [PATCH 23/78] docs: retain npm peer policy From 383ead70b03faf9cb7f0799ff655ddf1f47ea630 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:16:26 +0200 Subject: [PATCH 24/78] build: exclude local Divi references --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9d8fddd..1e881ce 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .env.* .idea/ .vscode/ +.reference/ node_modules/ vendor/ build/ From 0779ec7224e41d5517b149013a90938dad32a6dc Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:16:56 +0200 Subject: [PATCH 25/78] build: make dependency reset lockfile-safe --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cf0fadf..a8e55dd 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "check": "npm run check:types && npm run check:json", "check:types": "tsc --noEmit", "check:json": "node scripts/check-json.cjs", - "reset-install": "rm -rf node_modules package-lock.json && npm install" + "reset-install": "rm -rf node_modules && npm ci" }, "devDependencies": { "@divi/types": "npm:divi-types@^1.0.10", From d61e34004cdd17f499b01c5f9ad8226c050b8e77 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:17:55 +0200 Subject: [PATCH 26/78] docs: align dependency and release workflow --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c8dce32..0ca93fd 100644 --- a/README.md +++ b/README.md @@ -113,22 +113,22 @@ Requirements: - Node.js 18+ and npm 10+; - Composer. -Install and build: +Install from the committed dependency locks and build: ```bash composer install -npm install +npm ci npm run check npm run build ``` -After any change to `package.json` or `.npmrc`, reset the local dependency tree before validating: +To rebuild the installed npm tree without changing the committed dependency graph: ```bash npm run reset-install ``` -`reset-install` removes `node_modules` and `package-lock.json`, then performs a fresh install using the repository `.npmrc` policy. Run it only after pulling the commit that defines the script. +`reset-install` removes only `node_modules`, then runs `npm ci`. It deliberately preserves `package-lock.json`. Changes to `package.json` must be followed by an intentional `npm install`, review of the resulting lockfile diff and inclusion of both files in the same pull request. The same rule applies to `composer.json` and `composer.lock`. Validation: @@ -142,7 +142,7 @@ npm run check:json The published Divi 5 type aliases contain mutually incompatible development-only peer ranges: `react-dates` requests React/ReactDOM 16 while current WordPress packages request React 18. The repository therefore commits `.npmrc` with `legacy-peer-deps=true`; this prevents npm 10 from attempting an impossible peer-resolution graph. React remains externalized from the Visual Builder bundle, so this setting does not select or ship a second runtime React version. The same file keeps `engine-strict=true`. -The npm installation can still report deprecation warnings from the `divi-types*` compatibility aliases used by Elegant Themes. Those warnings are not treated as a successful build: the authoritative result is the exit status of `npm run check` and `npm run build`. Do not run `npm audit fix --force`, because it can replace Divi-compatible development dependencies with breaking versions. +The npm installation can still report deprecation and audit warnings from the `divi-types*` compatibility aliases used by Elegant Themes. Those warnings are not treated as a successful build: the authoritative result is the exit status of `npm run check` and `npm run build`. Do not run `npm audit fix --force`, because it can replace Divi-compatible development dependencies with breaking versions. After `npm run build`, the generated files are: @@ -153,6 +153,8 @@ modules-json/search-results/module.json modules-json/search-result-type/module.json ``` +Local proprietary references, including an extracted Divi theme under `.reference/`, are ignored by Git and must never be committed. A source checkout is therefore not a distributable plugin archive by itself: release packaging must run the build and include the generated Visual Builder assets and module metadata. + ## Not implemented yet The README deliberately does not present the following as available: @@ -165,7 +167,8 @@ The README deliberately does not present the following as available: - per-breakpoint column controls; - image fallback and ratio controls; - card presets; -- AJAX navigation. +- AJAX navigation; +- automated release archive generation. Those capabilities will be added in later reviewable increments without changing the shared renderer contract. From 2d4d3b681edbe8d3adf3d3e9754a7c0948d5ece8 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:18:14 +0200 Subject: [PATCH 27/78] docs: record lockfile-safe build workflow --- CHANGELOG.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da7f230..fc20c1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ - README documentation contract requiring code and documentation to remain synchronized in every PR. - Explicit TypeScript validation through `npm run check:types` and aggregate validation through `npm run check`. - Repository `.npmrc` with strict engine enforcement and deterministic handling of incompatible Divi peer ranges. -- `npm run reset-install` for a clean dependency-tree rebuild after manifest or npm-policy changes. +- Lockfile-safe `npm run reset-install` for rebuilding `node_modules` through `npm ci`. +- Git exclusion for local proprietary references under `.reference/`. ### Changed @@ -22,4 +23,5 @@ - Visual Builder attribute interfaces now use native Divi element types instead of generic unknown records. - Visual Builder edit and style renderers now guard optional props exposed by the published Divi types. - Development dependencies now include the transitive declarations required by the Divi 5.9.0 type packages. -- Development documentation now requires the committed reset command after changes to `package.json` or `.npmrc`. +- Development documentation now requires committed npm and Composer lockfiles to remain synchronized with their manifests. +- Release documentation now distinguishes ignored source-build outputs from files required in a distributable plugin archive. From d6e334bd21fe4c0ec1e1452a874bdb083cde0f60 Mon Sep 17 00:00:00 2001 From: Federico Girolami Date: Wed, 29 Jul 2026 23:09:08 +0200 Subject: [PATCH 28/78] build: lock validated dependency graph --- composer.lock | 20 + package-lock.json | 7235 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 7255 insertions(+) create mode 100644 composer.lock create mode 100644 package-lock.json diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..6f84889 --- /dev/null +++ b/composer.lock @@ -0,0 +1,20 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "f8f07812cefa5ecffd666cc60d725575", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=8.1" + }, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5026a50 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7235 @@ +{ + "name": "cc-divi5-search-results", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "cc-divi5-search-results", + "version": "0.1.0", + "license": "MIT", + "devDependencies": { + "@divi/types": "npm:divi-types@^1.0.10", + "@tinymce/tinymce-react": "^5.0.1", + "@types/divi__module": "npm:divi-types-module@^1.0.10", + "@types/divi__module-library": "npm:divi-types-module-library@^1.0.10", + "@types/react": "18.3.1", + "@types/react-dom": "18.3.0", + "@types/seamless-immutable": "^7.1.19", + "@types/wordpress__blocks": "^12.5.14", + "@wordpress/hooks": "^3.57.0", + "copy-webpack-plugin": "^12.0.2", + "css-loader": "^7.1.1", + "mini-css-extract-plugin": "^2.9.0", + "react": "^18.2.0", + "sass": "^1.77.0", + "sass-loader": "^14.2.1", + "seamless-immutable": "^7.1.4", + "ts-loader": "^9.5.1", + "typescript": "^5.4.5", + "webpack": "^5.91.0", + "webpack-cli": "^5.1.4" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=10.0.0" + } + }, + "node_modules/@ariakit/core": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.11.tgz", + "integrity": "sha512-+MnOeqnA4FLI/7vqsZLbZQHHN4ofd9kvkNjz44fNi0gqmD+ZbMWiDkFAvZII75dYnxYw5ZPpWjA4waK22VBWig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ariakit/react": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.3.14.tgz", + "integrity": "sha512-h71BPMZ2eW+E2ESbdYxSAEMR1DozYzd5eHE5IOzGd9Egi5u7EZxqmuW4CXVXZ1Y6vbaDMV3SudgPh7iHS/ArFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ariakit/react-core": "0.3.14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ariakit" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@ariakit/react-core": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.3.14.tgz", + "integrity": "sha512-16Qj6kDPglpdWtU5roY9q+G66naOjauTY5HvUIaL2aLY0187ATaRrABIKoMMzTtJyhvsud4jFlzivz+/zCQ8yw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ariakit/core": "0.3.11", + "@floating-ui/dom": "^1.0.0", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@divi/conversion": { + "name": "divi-types-conversion", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-conversion/-/divi-types-conversion-1.0.10.tgz", + "integrity": "sha512-Txtmn+XnwqA8oan+hyaVANK404qS7IBNWpt+rXjPHt5+bzVqZMFrWygp5x7umGvtwn5y5wAxt1KbTA0M0WlPBA==", + "deprecated": "Deprecated: use @divi/conversion instead.", + "dev": true, + "license": "GPL-2.0-or-later" + }, + "node_modules/@divi/types": { + "name": "divi-types", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types/-/divi-types-1.0.10.tgz", + "integrity": "sha512-bjukhmVjaNJsu1izY/sigCQabcuktw2FQ4JCFvW3qKHPu07vs65s0qHvRD0GVfTAXQwbfpcQkhpIOXYytBxfxw==", + "deprecated": "Deprecated: use @divi/types instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/blocks": "12.19.13", + "react": "18.2.0", + "seamless-immutable": "^7.1.4" + } + }, + "node_modules/@divi/types-external": { + "name": "divi-types-external", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-external/-/divi-types-external-1.0.10.tgz", + "integrity": "sha512-xwEddgZnsi65qJ9z4ricfxtF0iAugnJifkgLHddFc1FHHfkTOvT5GgTc0feqyL4Uvp6vKna9HUgFmNd7U9c9Mw==", + "deprecated": "Deprecated: use @divi/types-external instead.", + "dev": true, + "license": "GPL-2.0-or-later" + }, + "node_modules/@divi/types/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/css": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz", + "integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@floating-ui/core": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.8.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz", + "integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.6.0", + "@parcel/watcher-darwin-arm64": "2.6.0", + "@parcel/watcher-darwin-x64": "2.6.0", + "@parcel/watcher-freebsd-x64": "2.6.0", + "@parcel/watcher-linux-arm-glibc": "2.6.0", + "@parcel/watcher-linux-arm-musl": "2.6.0", + "@parcel/watcher-linux-arm64-glibc": "2.6.0", + "@parcel/watcher-linux-arm64-musl": "2.6.0", + "@parcel/watcher-linux-x64-glibc": "2.6.0", + "@parcel/watcher-linux-x64-musl": "2.6.0", + "@parcel/watcher-win32-arm64": "2.6.0", + "@parcel/watcher-win32-x64": "2.6.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz", + "integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz", + "integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz", + "integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz", + "integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz", + "integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz", + "integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz", + "integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz", + "integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz", + "integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz", + "integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz", + "integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz", + "integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@tannin/compile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.1.0.tgz", + "integrity": "sha512-n8m9eNDfoNZoxdvWiTfW/hSPhehzLJ3zW7f8E7oT6mCROoMNWCB4TYtv041+2FMAxweiE0j7i1jubQU4MEC/Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tannin/evaluate": "^1.2.0", + "@tannin/postfix": "^1.1.0" + } + }, + "node_modules/@tannin/evaluate": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.2.0.tgz", + "integrity": "sha512-3ioXvNowbO/wSrxsDG5DKIMxC81P0QrQTYai8zFNY+umuoHWRPbQ/TuuDEOju9E+jQDXmj6yI5GyejNuh8I+eg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tannin/plural-forms": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.1.0.tgz", + "integrity": "sha512-xl9R2mDZO/qiHam1AgMnAES6IKIg7OBhcXqy6eDsRCdXuxAFPcjrej9HMjyCLE0DJ/8cHf0i5OQTstuBRhpbHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tannin/compile": "^1.1.0" + } + }, + "node_modules/@tannin/postfix": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.1.0.tgz", + "integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tinymce/tinymce-react": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@tinymce/tinymce-react/-/tinymce-react-5.1.1.tgz", + "integrity": "sha512-DQ0wpvnf/9z8RsOEAmrWZ1DN1PKqcQHfU+DpM3llLze7FHmxVtzuN8O+FYh0oAAF4stzAXwiCIVacfqjMwRieQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prop-types": "^15.6.2", + "tinymce": "^7.0.0 || ^6.0.0 || ^5.5.1" + }, + "peerDependencies": { + "react": "^18.0.0 || ^17.0.1 || ^16.7.0", + "react-dom": "^18.0.0 || ^17.0.1 || ^16.7.0" + } + }, + "node_modules/@types/divi__conversion": { + "name": "divi-types-conversion", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-conversion/-/divi-types-conversion-1.0.10.tgz", + "integrity": "sha512-Txtmn+XnwqA8oan+hyaVANK404qS7IBNWpt+rXjPHt5+bzVqZMFrWygp5x7umGvtwn5y5wAxt1KbTA0M0WlPBA==", + "deprecated": "Deprecated: use @divi/conversion instead.", + "dev": true, + "license": "GPL-2.0-or-later" + }, + "node_modules/@types/divi__draggable": { + "name": "divi-types-draggable", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-draggable/-/divi-types-draggable-1.0.10.tgz", + "integrity": "sha512-MXWOj2qxl1aRNVuer6RR/+dypFZ4Zu//eBm60VQ3Pfmk/t38DQCNiHv3YZ4N1H+X1wTRBHIsMJ6qQ6479fu6tQ==", + "deprecated": "Deprecated: use @divi/draggable instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "react": "18.2.0" + } + }, + "node_modules/@types/divi__draggable/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__field-library": { + "name": "divi-types-field-library", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-field-library/-/divi-types-field-library-1.0.10.tgz", + "integrity": "sha512-aCO7JeAiKvwQCLeP+nFClciGcUO3ZhJPl1cExs8kMS2h8hOTZ/qUpFxAzhE4vbBv++jteXEVR+8SEw6MYA5HAw==", + "deprecated": "Deprecated: use @divi/field-library instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@divi/types-external": "npm:divi-types-external@^1.0.0", + "@types/divi__icon-library": "npm:divi-types-icon-library@^1.0.0", + "@types/divi__style-library": "npm:divi-types-style-library@^1.0.0", + "codemirror": "5.65.16", + "codemirror-colorpicker": "1.9.80", + "react": "18.2.0", + "react-dates": "^21.8.0", + "tinymce": "^5.10.7" + } + }, + "node_modules/@types/divi__field-library/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__field-library/node_modules/tinymce": { + "version": "5.10.9", + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.9.tgz", + "integrity": "sha512-5bkrors87X9LhYX2xq8GgPHrIgJYHl87YNs+kBcjQ5I3CiUgzo/vFcGvT3MZQ9QHsEeYMhYO6a5CLGGffR8hMg==", + "dev": true, + "license": "LGPL-2.1" + }, + "node_modules/@types/divi__icon-library": { + "name": "divi-types-icon-library", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-icon-library/-/divi-types-icon-library-1.0.10.tgz", + "integrity": "sha512-D33kjPNv74qpmKqcRH08lhukQkO5/P/uOlxa7YW45GARvJReTWWxgbUSiK6aeX6dvMb4UZnUr0tUS07s/i+biQ==", + "deprecated": "Deprecated: use @divi/icon-library instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "react": "18.2.0" + } + }, + "node_modules/@types/divi__icon-library/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__modal": { + "name": "divi-types-modal", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-modal/-/divi-types-modal-1.0.10.tgz", + "integrity": "sha512-2sCIc1fIwHD1rce4Xkwm3XZXdaf8ZaIAuL4xesXbktj4PAGcNkysuC7a4SYycd6oN74r/K6qCKipZ0dx2jy41g==", + "deprecated": "Deprecated: use @divi/modal instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@divi/types": "npm:divi-types@^1.0.0", + "@types/divi__draggable": "npm:divi-types-draggable@^1.0.0", + "react": "18.2.0" + } + }, + "node_modules/@types/divi__modal/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__module": { + "name": "divi-types-module", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-module/-/divi-types-module-1.0.10.tgz", + "integrity": "sha512-zvlLwTPBHtZReb8S8rfXslPloGZkJ2aTqtEGEsFEENbGVPDRigIvn0doCTGBJopEvl5mu5Im0+lqOm4/3GxSNA==", + "deprecated": "Deprecated: use @divi/module instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@divi/conversion": "npm:divi-types-conversion@^1.0.0", + "@divi/types-external": "npm:divi-types-external@^1.0.0", + "@types/divi__conversion": "npm:divi-types-conversion@^1.0.0", + "@types/divi__field-library": "npm:divi-types-field-library@^1.0.0", + "@types/divi__modal": "npm:divi-types-modal@^1.0.0", + "@types/divi__right-click-options": "npm:divi-types-right-click-options@^1.0.0", + "@types/divi__style-library": "npm:divi-types-style-library@^1.0.0", + "lodash": "4.17.21", + "react": "18.2.0", + "seamless-immutable": "^7.1.4" + } + }, + "node_modules/@types/divi__module-library": { + "name": "divi-types-module-library", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-module-library/-/divi-types-module-library-1.0.10.tgz", + "integrity": "sha512-66XtEhJWivcPvMNbgLwJgQgKyC5OsheLTHhOa71kw02x81JTNSBsMZ8athVVwmavxKLT8N6w1sFjtT7hAOOFJQ==", + "deprecated": "Deprecated: use @divi/module-library instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@divi/types": "npm:divi-types@^1.0.0", + "@types/divi__module": "npm:divi-types-module@^1.0.0", + "@types/divi__style-library": "npm:divi-types-style-library@^1.0.0", + "@wordpress/blocks": "12.19.13", + "react": "18.2.0", + "seamless-immutable": "^7.1.4" + } + }, + "node_modules/@types/divi__module-library/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__module/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__right-click-options": { + "name": "divi-types-right-click-options", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-right-click-options/-/divi-types-right-click-options-1.0.10.tgz", + "integrity": "sha512-HsfxS7XlMz7Pd30xX0iOIXFx1V+meBm+Iajq1+7yr2Mi2Edx3T8tqM+uL54BZcKBmaJRVRZ46Ioy7j2AOiElaQ==", + "deprecated": "Deprecated: use @divi/right-click-options instead.", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "react": "18.2.0", + "seamless-immutable": "^7.1.4" + } + }, + "node_modules/@types/divi__right-click-options/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/divi__style-library": { + "name": "divi-types-style-library", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/divi-types-style-library/-/divi-types-style-library-1.0.10.tgz", + "integrity": "sha512-439L3LMi1TFBCx+Xwfdhpnk8TMCbCmn3KOr5YTTEXmCpqioStsFJ4MzaesmJwSxk0cQUlSY+ZkRVdmc+h90hrQ==", + "deprecated": "Deprecated: use @divi/style-library instead.", + "dev": true, + "license": "GPL-2.0-or-later" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/gradient-parser": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@types/gradient-parser/-/gradient-parser-0.1.3.tgz", + "integrity": "sha512-XDbrTSBlQV9nxE1GiDL3FaOPy4G/KaJkhDutBX48Kg8CYZMBARyyDFGCWfWJn4pobmInmwud1xxH7VJMAr0CKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/highlight-words-core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/highlight-words-core/-/highlight-words-core-1.2.1.tgz", + "integrity": "sha512-9VZUA5omXBfn+hDxFjUDu1FOJTBM3LmvqfDey+Z6Aa8B8/JmF5SMj6FBrjfgJ/Q3YXOZd3qyTDfJyMZSs/wCUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mousetrap": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/@types/mousetrap/-/mousetrap-1.6.15.tgz", + "integrity": "sha512-qL0hyIMNPow317QWW/63RvL1x5MVMV+Ru3NaY9f/CuEpCqrmb7WeuK2071ZY5hczOnm38qExWM2i2WtkXLSqFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "26.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz", + "integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.1.tgz", + "integrity": "sha512-V0kuGBX3+prX+DQ/7r2qsv1NsdfnCLnTgnRJ1pYnxykBhGMz+qj+box5lq7XsO5mtZsBqpjwwTu/7wszPfMBcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", + "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/seamless-immutable": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/seamless-immutable/-/seamless-immutable-7.1.19.tgz", + "integrity": "sha512-EBUncfvAjFqmOTlhp095M9DruNViePvR6bUJzIymEOdyu33/ats/G3cLcqTzGRQceUWbLuJrXm9H73XYimLb/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/wordpress__blocks": { + "version": "12.5.18", + "resolved": "https://registry.npmjs.org/@types/wordpress__blocks/-/wordpress__blocks-12.5.18.tgz", + "integrity": "sha512-KDugvZn2fEd1mIyYSE4j0QS4vkXOyz1r4akFrnUyJBoIBVQNqDopqXW2qX7kIrTXk9MydWZpdReNDg2Me02s4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "^18", + "@wordpress/components": "^27.2.0", + "@wordpress/data": "^9.13.0", + "@wordpress/element": "^5.0.0", + "@wordpress/shortcode": "^4.14.0" + } + }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@wordpress/a11y": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.58.0.tgz", + "integrity": "sha512-7NnJKl4+pxP6kV/jvXaJcZZCGzW7zaj6YeMnyjUd96cH4ta1ykBIveWgejerFOGsbK+88FnStcxSFj+dbDXs/w==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/dom-ready": "^3.58.0", + "@wordpress/i18n": "^4.58.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/autop": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.58.0.tgz", + "integrity": "sha512-RsdUV57A+DTJGU3slq/S9vTOtVkatnT1YyGIK3UDKaEhXkvBPtLTWwd3WR13GCfjFZ5XupH9FAGUQFkOve0eKQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/blob": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.58.0.tgz", + "integrity": "sha512-6L3WqbOWEGFOSs3vLMwJ83YScggCiJ9NvZj1kC7mgeiP302UP2Fxkt4KlfjeTsD350XcvakkD/57wRkHXd819Q==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/block-serialization-default-parser": { + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.58.0.tgz", + "integrity": "sha512-++fowmFEJC+1SwiCGuLPO9k+g3rgI2SCAA/p8/Bc1rNgnKB+rowzmQvSIIlRpcUkmOxHOrH5uruOEX27Ksg6uw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/blocks": { + "version": "12.19.13", + "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.13.tgz", + "integrity": "sha512-KdNcYb5Cr4sgzOkJM+KpPZeLLFr8e06CkRDp0EQk7VGSsoScXpqIcMEtMcKNQp1XPuJ6npMr/BacC5qNjyHA1A==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/autop": "^3.42.13", + "@wordpress/blob": "^3.42.13", + "@wordpress/block-serialization-default-parser": "^4.42.13", + "@wordpress/compose": "^6.19.13", + "@wordpress/data": "^9.12.13", + "@wordpress/deprecated": "^3.42.13", + "@wordpress/dom": "^3.42.13", + "@wordpress/element": "^5.19.13", + "@wordpress/hooks": "^3.42.13", + "@wordpress/html-entities": "^3.42.13", + "@wordpress/i18n": "^4.42.13", + "@wordpress/is-shallow-equal": "^4.42.13", + "@wordpress/private-apis": "^0.24.13", + "@wordpress/shortcode": "^3.42.13", + "change-case": "^4.1.2", + "colord": "^2.7.0", + "deepmerge": "^4.3.0", + "fast-deep-equal": "^3.1.3", + "hpq": "^1.3.0", + "is-plain-object": "^5.0.0", + "memize": "^2.1.0", + "rememo": "^4.0.2", + "remove-accents": "^0.5.0", + "showdown": "^1.9.1", + "simple-html-tokenizer": "^0.5.7", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/blocks/node_modules/@wordpress/shortcode": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.58.0.tgz", + "integrity": "sha512-yM3Y25XqLfz/X6xXowXbrTvk+tslKeALNNESI5nGt1X7wWPsYQDOqyBb1HT9TglSLFgWYlQlNtgEbz07dEiDgQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "memize": "^2.0.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/components": { + "version": "27.6.0", + "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-27.6.0.tgz", + "integrity": "sha512-f+fXENkgrPs5GLo2yu9fEAdVX0KriEatRcjDUyw0+DbNbJR62sCdDtGdhJRW4jPUUoUowxaGO0y4+jvQWxnbyg==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@ariakit/react": "^0.3.12", + "@babel/runtime": "^7.16.0", + "@emotion/cache": "^11.7.1", + "@emotion/css": "^11.7.1", + "@emotion/react": "^11.7.1", + "@emotion/serialize": "^1.0.2", + "@emotion/styled": "^11.6.0", + "@emotion/utils": "^1.0.0", + "@floating-ui/react-dom": "^2.0.8", + "@types/gradient-parser": "0.1.3", + "@types/highlight-words-core": "1.2.1", + "@use-gesture/react": "^10.3.1", + "@wordpress/a11y": "^3.58.0", + "@wordpress/compose": "^6.35.0", + "@wordpress/date": "^4.58.0", + "@wordpress/deprecated": "^3.58.0", + "@wordpress/dom": "^3.58.0", + "@wordpress/element": "^5.35.0", + "@wordpress/escape-html": "^2.58.0", + "@wordpress/hooks": "^3.58.0", + "@wordpress/html-entities": "^3.58.0", + "@wordpress/i18n": "^4.58.0", + "@wordpress/icons": "^9.49.0", + "@wordpress/is-shallow-equal": "^4.58.0", + "@wordpress/keycodes": "^3.58.0", + "@wordpress/primitives": "^3.56.0", + "@wordpress/private-apis": "^0.40.0", + "@wordpress/rich-text": "^6.35.0", + "@wordpress/warning": "^2.58.0", + "change-case": "^4.1.2", + "clsx": "^2.1.1", + "colord": "^2.7.0", + "date-fns": "^3.6.0", + "deepmerge": "^4.3.0", + "downshift": "^6.0.15", + "fast-deep-equal": "^3.1.3", + "framer-motion": "^11.1.9", + "gradient-parser": "^0.1.5", + "highlight-words-core": "^1.2.2", + "is-plain-object": "^5.0.0", + "memize": "^2.1.0", + "path-to-regexp": "^6.2.1", + "re-resizable": "^6.4.0", + "react-colorful": "^5.3.1", + "remove-accents": "^0.5.0", + "use-lilius": "^2.0.5", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@wordpress/components/node_modules/@wordpress/private-apis": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.40.0.tgz", + "integrity": "sha512-ZX/9Y8eA3C3K6LOj32bHFj+9tNV819CBd8+chqMmmlvQRcTngiuXbMbnSdZnnAr1gLQgNpH9PJ60dIwJnGSEtQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/compose": { + "version": "6.35.0", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.35.0.tgz", + "integrity": "sha512-PfruhCxxxJokDQHc2YBgerEiHV7BIxQk9g5vU4/f9X/0PBQWUTuxOzSFcAba03vnjfAgtPTSMp50T50hcJwXfA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@types/mousetrap": "^1.6.8", + "@wordpress/deprecated": "^3.58.0", + "@wordpress/dom": "^3.58.0", + "@wordpress/element": "^5.35.0", + "@wordpress/is-shallow-equal": "^4.58.0", + "@wordpress/keycodes": "^3.58.0", + "@wordpress/priority-queue": "^2.58.0", + "@wordpress/undo-manager": "^0.18.0", + "change-case": "^4.1.2", + "clipboard": "^2.0.11", + "mousetrap": "^1.6.5", + "use-memo-one": "^1.1.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/data": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.28.0.tgz", + "integrity": "sha512-EDPpZdkngdoW7EMzPpGj0BmNcr7syJO67pgTODtN/4XFIdYL2RKzFyn3nlLBKhX17UsE/ALq9WdijacH4QJ9qw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/compose": "^6.35.0", + "@wordpress/deprecated": "^3.58.0", + "@wordpress/element": "^5.35.0", + "@wordpress/is-shallow-equal": "^4.58.0", + "@wordpress/priority-queue": "^2.58.0", + "@wordpress/private-apis": "^0.40.0", + "@wordpress/redux-routine": "^4.58.0", + "deepmerge": "^4.3.0", + "equivalent-key-map": "^0.2.2", + "is-plain-object": "^5.0.0", + "is-promise": "^4.0.0", + "redux": "^4.1.2", + "rememo": "^4.0.2", + "use-memo-one": "^1.1.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/data/node_modules/@wordpress/private-apis": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.40.0.tgz", + "integrity": "sha512-ZX/9Y8eA3C3K6LOj32bHFj+9tNV819CBd8+chqMmmlvQRcTngiuXbMbnSdZnnAr1gLQgNpH9PJ60dIwJnGSEtQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/date": { + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.58.0.tgz", + "integrity": "sha512-yFT7DU0H9W0lsDytMaVMmjho08X1LeBMIQMppxdtKB04Ujx58hVh7gtunOsstUQ7pVg23nE2eLaVfx5JOdjzAw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/deprecated": "^3.58.0", + "moment": "^2.29.4", + "moment-timezone": "^0.5.40" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/deprecated": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.58.0.tgz", + "integrity": "sha512-knweE2lLEUxWRr6A48sHiO0ww5pPybGe2NVIZVq/y7EaYCMdpy6gYA0ZdVqMKZvtxKKqicJfwigcn+hinsTvUQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/hooks": "^3.58.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/dom": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.58.0.tgz", + "integrity": "sha512-t3xSr/nqekj2qwUGRAqSeGx6116JOBxzI+VBiUfZrjGEnuyKdLelXDEeYtcwbb7etMkj/6F60/NB7GTl5IwizQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/deprecated": "^3.58.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/dom-ready": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.58.0.tgz", + "integrity": "sha512-sDgRPjNBToRKgYrpwvMRv2Yc7/17+sp8hm/rRnbubwb+d/DbGkK4Tc/r4sNLSZCqUAtcBXq9uk1lzvhge3QUSg==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/element": { + "version": "5.35.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.35.0.tgz", + "integrity": "sha512-puswpGcIdS+0A2g28uHriMkZqqRCmzFczue5Tk99VNtzBdehyk7Ae+DZ4xw5yT6GqYai8NTqv6MRwCB78uh5Mw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@types/react": "^18.2.79", + "@types/react-dom": "^18.2.25", + "@wordpress/escape-html": "^2.58.0", + "change-case": "^4.1.2", + "is-plain-object": "^5.0.0", + "react": "^18.3.0", + "react-dom": "^18.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/escape-html": { + "version": "2.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.58.0.tgz", + "integrity": "sha512-9YJXMNfzkrhHEVP1jFEhgijbZqW8Mt3NHIMZjIQoWtBf7QE86umpYpGGBXzYC0YlpGTRGzZTBwYaqFKxjeaSgA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/hooks": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.58.0.tgz", + "integrity": "sha512-9LB0ZHnZRQlORttux9t/xbAskF+dk2ujqzPGsVzc92mSKpQP3K2a5Wy74fUnInguB1vLUNHT6nrNdkVom5qX1Q==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/html-entities": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.58.0.tgz", + "integrity": "sha512-FU7b6QZdwTCuLKq6wCl0IZqqOMcMRxMcekVVytzTse7hYk9dvL1qQL/U4eQ/CNyKqiT9u7fb5NKTQILOzoolVQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/i18n": { + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.58.0.tgz", + "integrity": "sha512-VfvS3BWv/RDjRKD6PscIcvYfWKnGJcI/DEqyDgUMhxCM6NRwoL478CsUKTiGJIymeyRodNRfprdcF086DpGKYw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/hooks": "^3.58.0", + "gettext-parser": "^1.3.1", + "memize": "^2.1.0", + "sprintf-js": "^1.1.1", + "tannin": "^1.2.0" + }, + "bin": { + "pot-to-php": "tools/pot-to-php.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/icons": { + "version": "9.49.0", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.49.0.tgz", + "integrity": "sha512-Z8F+ledkfkcKDuS1c/RkM0dEWdfv2AXs6bCgey89p0atJSscf7qYbMJR9zE5rZ5aqXyFfV0DAFKJEgayNqneNQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/element": "^5.35.0", + "@wordpress/primitives": "^3.56.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/is-shallow-equal": { + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.58.0.tgz", + "integrity": "sha512-NH2lbXo/6ix1t4Zu9UBXpXNtoLwSaYmIRSyDH34XNb0ic8a7yjEOhYWVW3LTfSCv9dJVyxlM5TJPtL85q7LdeQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/keycodes": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.58.0.tgz", + "integrity": "sha512-Q/LRKpx8ndzuHlkxSQ2BD+NTYYKQPIneNNMng8hTAfyU7RFwXpqj06HpeOFGh4XIdPKCs/8hmucoLJRmmLmZJA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/i18n": "^4.58.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/primitives": { + "version": "3.56.0", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.56.0.tgz", + "integrity": "sha512-NXBq1ODjl6inMWx/l7KCbATcjdoeIOqYeL9i9alqdAfWeKx1EH9PIvKWylIkqZk7erXxCxldiRkuyjTtwjNBxw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/element": "^5.35.0", + "clsx": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/priority-queue": { + "version": "2.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.58.0.tgz", + "integrity": "sha512-W+qCS8HJWsXG8gE6yK/H/IObowcghPrQMM3cQHtfd/U05yFNU1Bd/fbj3AO1fVRztktS47lIpi9m3ll1evPEHA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "requestidlecallback": "^0.3.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/private-apis": { + "version": "0.24.13", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.13.tgz", + "integrity": "sha512-RgvGB6VQpPnEGU8Y61tzpgPFYDRAW28+2gcdOXYiqSVdZfGBL6+hBs5bMbLSJYRU9G5pl5q4Eb0lHlkMgHW5FA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/redux-routine": { + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.58.0.tgz", + "integrity": "sha512-r0mMWFeJr93yPy2uY/M5+gdUUYj0Zu8+21OFFb5hyQ0z7UHIa3IdgQxzCaTbV1LDA1ZYJrjHeCnA6s4gNHjA2Q==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "is-plain-object": "^5.0.0", + "is-promise": "^4.0.0", + "rungen": "^0.3.2" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "redux": ">=4" + } + }, + "node_modules/@wordpress/rich-text": { + "version": "6.35.0", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.35.0.tgz", + "integrity": "sha512-h6/XftSqo9UQZebuNZyLfOVu+ButBLITW/BILsKeJhSpmM19VNdz8UhVGLp+xQPE+/GPCIMJrhhqipISDfc2Ig==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/a11y": "^3.58.0", + "@wordpress/compose": "^6.35.0", + "@wordpress/data": "^9.28.0", + "@wordpress/deprecated": "^3.58.0", + "@wordpress/element": "^5.35.0", + "@wordpress/escape-html": "^2.58.0", + "@wordpress/i18n": "^4.58.0", + "@wordpress/keycodes": "^3.58.0", + "memize": "^2.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/shortcode": { + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-4.52.0.tgz", + "integrity": "sha512-6vTLq3WxPMaE6pvxvvUzbcSeNzvqcghF4ngX1bXlSVIwMXVDgwsTFA4yc6LoI9BFBDZt9UZ+KN22wcdqnDr9Ug==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "memize": "^2.1.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/undo-manager": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.18.0.tgz", + "integrity": "sha512-upbzPEToa095XG+2JXLHaolF1LfXEMFS0lNMYV37myoUS+eZ7/tl9Gx+yU2+OqWy57TMwx33NlWUX/n+ynzPRw==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/is-shallow-equal": "^4.58.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/warning": { + "version": "2.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.58.0.tgz", + "integrity": "sha512-9bZlORhyMY2nbWozeyC5kqJsFzEPP4DCLhGmjtbv+YWGHttUrxUZEfrKdqO+rUODA8rP5zeIly1nCQOUnkw4Lg==", + "dev": true, + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=12" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/airbnb-prop-types": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/airbnb-prop-types/-/airbnb-prop-types-2.16.0.tgz", + "integrity": "sha512-7WHOFolP/6cS96PhKNrslCLMYAI8yB1Pp6u6XmxozQOiZbsI5ycglZr5cHhBFfuRcQQjzCMith5ZPZdYiJCxUg==", + "deprecated": "This package has been renamed to 'prop-types-tools'", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.find": "^2.1.1", + "function.prototype.name": "^1.1.2", + "is-regex": "^1.1.0", + "object-is": "^1.1.2", + "object.assign": "^4.1.0", + "object.entries": "^1.1.2", + "prop-types": "^15.7.2", + "prop-types-exact": "^1.2.0", + "react-is": "^16.13.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "peerDependencies": { + "react": "^0.14 || ^15.0.0 || ^16.0.0-alpha" + } + }, + "node_modules/airbnb-prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.find": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.3.tgz", + "integrity": "sha512-fO/ORdOELvjbbeIfZfzrXFMhYHGofRGqd+am9zm3tZ4GlJINj/pA2eITyfd65Vg6+ZbHd/Cys7stpoRSWtQFdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.7", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.7.tgz", + "integrity": "sha512-APw5YuIQAg6L9w4sHDI6j26DGFJI6RpYOhnkMPdC9lWbkKvsyPHzDsve1yd73lk21yz7Y09Kci8B2Pp9FonzWA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brcast": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brcast/-/brcast-2.0.2.tgz", + "integrity": "sha512-Tfn5JSE7hrUlFcOoaLzVvkbgIemIorMIyoMr3TgvszWW7jFt2C9PdeMLtysYD9RU0MmU17b69+XJG1eRY2OBRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "dev": true, + "license": "MIT", + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/codemirror": { + "version": "5.65.16", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.16.tgz", + "integrity": "sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==", + "dev": true, + "license": "MIT" + }, + "node_modules/codemirror-colorpicker": { + "version": "1.9.80", + "resolved": "https://registry.npmjs.org/codemirror-colorpicker/-/codemirror-colorpicker-1.9.80.tgz", + "integrity": "sha512-7lGqNxf5haBJXLnVR1ynPiPkN2d1Whm0jdy8Z9QsSOhRWVyK2C2ihgm1dX4DCks57ht/jKMdpL9lYv+zAphxWQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "codemirror": "^5.48.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/compute-scroll-into-view": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz", + "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==", + "dev": true, + "license": "MIT" + }, + "node_modules/consolidated-events": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/consolidated-events/-/consolidated-events-2.0.2.tgz", + "integrity": "sha512-2/uRVMdRypf5z/TW/ncD/66l75P5hH2vM/GR8Jf8HLc2xnfJtmina6F6du8+v4Z2vTrMo7jC+W1tmEEuuELgkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", + "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-loader": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.4.tgz", + "integrity": "sha512-vv3J9tlOl04WjiMvHQI/9tmIrCxVrj6PFbHemBB1iihpeRbi/I4h033eoFIhwxBBqLhI0KYFS7yvynBFhIZfTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.40", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.6.3" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "webpack": "^5.27.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/direction": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz", + "integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==", + "dev": true, + "license": "MIT", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/document.contains": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/document.contains/-/document.contains-1.0.2.tgz", + "integrity": "sha512-YcvYFs15mX8m3AO1QNQy3BlIpSMfNRj3Ujk2BEJxsZG+HZf7/hZ6jr7mDpXrF8q+ff95Vef5yjhiZxm8CGJr6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/downshift": { + "version": "6.1.12", + "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.12.tgz", + "integrity": "sha512-7XB/iaSJVS4T8wGFT3WRXmSF1UlBHAA40DshZtkrIscIN+VC+Lh363skLxFTvJwtNgHxAMDGEHT4xsyQFWL+UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.14.8", + "compute-scroll-into-view": "^1.0.17", + "prop-types": "^15.7.2", + "react-is": "^17.0.2", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "react": ">=16.12.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.398", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.398.tgz", + "integrity": "sha512-AsvhAxopJGh6museTDMIjn6JpDYOfgu4RLlygomt87MUwBUqTfd/1EiPtx10/LZE8xpTvkP2E9Gafq7lkLtodQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.24.4", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.4.tgz", + "integrity": "sha512-GVoi+ICHocoOIU7qVVM48wOJziRsqrsyqlI0Ce0LdowRn6v3bcH2zUa9kp85ncx0nwIb9/HOCOLS3fdThDG/XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/enzyme-shallow-equal": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/enzyme-shallow-equal/-/enzyme-shallow-equal-1.0.7.tgz", + "integrity": "sha512-/um0GFqUXnpM9SvKtje+9Tjoz3f1fpBC3eXRFrNs8kpYn69JljciYP7KZTqM/YQbUY9KUjvKB4jo/q+L6WGGvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0", + "object-is": "^1.1.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/equivalent-key-map": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/equivalent-key-map/-/equivalent-key-map-0.2.2.tgz", + "integrity": "sha512-xvHeyCDbZzkpN4VHQj/n+j2lOwL0VWszG30X4cOrc9Y7Tuo2qCdZK/0AMod23Z5dCtNUbaju6p0rwOhHUk05ew==", + "dev": true, + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-abstract-get": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", + "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.2", + "is-callable": "^1.2.7", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", + "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-abstract-get": "^1.0.0", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "is-callable": "^1.2.7", + "is-date-object": "^1.1.0", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true, + "license": "MIT" + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", + "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2", + "hasown": "^2.0.4", + "is-callable": "^1.2.7", + "is-document.all": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gettext-parser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", + "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "encoding": "^0.1.12", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-cache": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/global-cache/-/global-cache-1.2.1.tgz", + "integrity": "sha512-EOeUaup5DgWKlCMhA9YFqNRIlZwoxt731jCh47WBV9fQqHgXhr3Fa55hfgIUqilIcPsfdNKN7LHjrNY+Km40KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.2", + "is-symbol": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", + "dev": true, + "license": "MIT", + "dependencies": { + "delegate": "^3.1.2" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/gradient-parser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/gradient-parser/-/gradient-parser-0.1.5.tgz", + "integrity": "sha512-+uPlcVbjrKOnTzvz0MjTj7BfACj8OmxIa1moIjJV7btvhUMSJk0D47RfDCgDrZE3dYMz9Cf5xKJwnrKLjUq0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/highlight-words-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/highlight-words-core/-/highlight-words-core-1.2.3.tgz", + "integrity": "sha512-m1O9HW3/GNHxzSIXWw1wCNXXsgLlxrP0OI6+ycGUhiUHkikqW3OrwVHz+lxeNBe5yqLESdIcj8PowHQ2zLvUvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpq": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/hpq/-/hpq-1.4.0.tgz", + "integrity": "sha512-ycJQMRaRPBcfnoT1gS5I1XCvbbw9KO94Y0vkwksuOjcJMqNZtb03MF2tCItLI2mQbkZWSSeFinoRDPmjzv4tKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ignore": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-document.all": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", + "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-touch-device": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-touch-device/-/is-touch-device-1.0.1.tgz", + "integrity": "sha512-LAYzo9kMT1b2p19L/1ATGt2XcSilnzNlyvq6c0pbPRVisLbAPpLqr53tIJS00kvrTkj0HtR8U7+u8X0yR8lPSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memize": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/memize/-/memize-2.1.1.tgz", + "integrity": "sha512-8Nl+i9S5D6KXnruM03Jgjb+LwSupvR13WBr4hJegaaEyobvowCVupi79y2WSiWvO1mzBWxPwEYE5feCe8vyA5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimizer-webpack-plugin": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.6.1.tgz", + "integrity": "sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mousetrap": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.5.tgz", + "integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==", + "dev": true, + "license": "Apache-2.0 WITH LLVM-exception" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/own-keys": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", + "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.4.tgz", + "integrity": "sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types-exact": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/prop-types-exact/-/prop-types-exact-1.2.7.tgz", + "integrity": "sha512-A4RaV6mg3jocQqBYmqi2ojJ2VnV4AKTEHhl3xHsud08/u87gcVJc8DUOtgnPegoOCQv/shUqEk4eZGYibjnHzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "isarray": "^2.0.5", + "object.assign": "^4.1.7", + "own-keys": "^1.0.0" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/re-resizable": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.11.2.tgz", + "integrity": "sha512-2xI2P3OHs5qw7K0Ud1aLILK6MQxW50TcO+DetD9eIV58j84TqYeHoZcL9H4GXFXXIh7afhH8mv5iUCXII7OW7A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-colorful": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.8.0.tgz", + "integrity": "sha512-Wy9OzPfjSN9bF12OB8N7UQvlsZ0I+7wHxpN+bV5BjNQGxOj6IiwkRjevJK9yOBjJWGQvAaf1OXtn8rUeEatAng==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-dates": { + "version": "21.8.0", + "resolved": "https://registry.npmjs.org/react-dates/-/react-dates-21.8.0.tgz", + "integrity": "sha512-PPriGqi30CtzZmoHiGdhlA++YPYPYGCZrhydYmXXQ6RAvAsaONcPtYgXRTLozIOrsQ5mSo40+DiA5eOFHnZ6xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "airbnb-prop-types": "^2.15.0", + "consolidated-events": "^1.1.1 || ^2.0.0", + "enzyme-shallow-equal": "^1.0.0", + "is-touch-device": "^1.0.1", + "lodash": "^4.1.1", + "object.assign": "^4.1.0", + "object.values": "^1.1.0", + "prop-types": "^15.7.2", + "raf": "^3.4.1", + "react-moment-proptypes": "^1.6.0", + "react-outside-click-handler": "^1.2.4", + "react-portal": "^4.2.0", + "react-with-direction": "^1.3.1", + "react-with-styles": "^4.1.0", + "react-with-styles-interface-css": "^6.0.0" + }, + "peerDependencies": { + "@babel/runtime": "^7.0.0", + "moment": "^2.18.1", + "react": "^0.14 || ^15.5.4 || ^16.1.1", + "react-dom": "^0.14 || ^15.5.4 || ^16.1.1", + "react-with-direction": "^1.3.1" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-moment-proptypes": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/react-moment-proptypes/-/react-moment-proptypes-1.8.1.tgz", + "integrity": "sha512-Er940DxWoObfIqPrZNfwXKugjxMIuk1LAuEzn23gytzV6hKS/sw108wibi9QubfMN4h+nrlje8eUCSbQRJo2fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "moment": ">=1.6.0" + }, + "peerDependencies": { + "moment": ">=1.6.0" + } + }, + "node_modules/react-outside-click-handler": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz", + "integrity": "sha512-Te/7zFU0oHpAnctl//pP3hEAeobfeHMyygHB8MnjP6sX5OR8KHT1G3jmLsV3U9RnIYo+Yn+peJYWu+D5tUS8qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "airbnb-prop-types": "^2.15.0", + "consolidated-events": "^1.1.1 || ^2.0.0", + "document.contains": "^1.0.1", + "object.values": "^1.1.0", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^0.14 || >=15", + "react-dom": "^0.14 || >=15" + } + }, + "node_modules/react-portal": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/react-portal/-/react-portal-4.3.0.tgz", + "integrity": "sha512-qs/2uKq1ifB3J1+K8ExfgUvCDZqlqCkfOEhqTELEDTfosloKiuzOzc7hl7IQ/7nohiFZD41BUYU0boAsIsGYHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0", + "react-dom": "^16.0.0-0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0" + } + }, + "node_modules/react-with-direction": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/react-with-direction/-/react-with-direction-1.4.0.tgz", + "integrity": "sha512-ybHNPiAmaJpoWwugwqry9Hd1Irl2hnNXlo/2SXQBwbLn/jGMauMS2y9jw+ydyX5V9ICryCqObNSthNt5R94xpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "airbnb-prop-types": "^2.16.0", + "brcast": "^2.0.2", + "deepmerge": "^1.5.2", + "direction": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "object.assign": "^4.1.2", + "object.values": "^1.1.5", + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "react": "^0.14 || ^15 || ^16", + "react-dom": "^0.14 || ^15 || ^16" + } + }, + "node_modules/react-with-direction/node_modules/deepmerge": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", + "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-with-styles": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/react-with-styles/-/react-with-styles-4.2.0.tgz", + "integrity": "sha512-tZCTY27KriRNhwHIbg1NkSdTTOSfXDg6Z7s+Q37mtz0Ym7Sc7IOr3PzVt4qJhJMW6Nkvfi3g34FuhtiGAJCBQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "airbnb-prop-types": "^2.14.0", + "hoist-non-react-statics": "^3.2.1", + "object.assign": "^4.1.0", + "prop-types": "^15.7.2", + "react-with-direction": "^1.3.1" + }, + "peerDependencies": { + "@babel/runtime": "^7.0.0", + "react": ">=0.14", + "react-with-direction": "^1.3.1" + } + }, + "node_modules/react-with-styles-interface-css": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/react-with-styles-interface-css/-/react-with-styles-interface-css-6.0.0.tgz", + "integrity": "sha512-6khSG1Trf4L/uXOge/ZAlBnq2O2PEXlQEqAhCRbvzaQU4sksIkdwpCPEl6d+DtP3+IdhyffTWuHDO9lhe1iYvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array.prototype.flat": "^1.2.1", + "global-cache": "^1.2.1" + }, + "peerDependencies": { + "@babel/runtime": "^7.0.0", + "react-with-styles": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rememo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rememo/-/rememo-4.0.2.tgz", + "integrity": "sha512-NVfSP9NstE3QPNs/TnegQY0vnJnstKQSpcrsI2kBTB3dB2PkdfKdTa+abbjMIDqpc63fE5LfjLgfMst0ULMFxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/requestidlecallback": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/requestidlecallback/-/requestidlecallback-0.3.0.tgz", + "integrity": "sha512-TWHFkT7S9p7IxLC5A1hYmAYQx2Eb9w1skrXmQ+dS1URyvR8tenMLl4lHbqEOUnpEYxNKpkVMXUgknVpBZWXXfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rungen": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/rungen/-/rungen-0.3.2.tgz", + "integrity": "sha512-zWl10xu2D7zoR8zSC2U6bg5bYF6T/Wk7rxwp8IPaJH7f0Ge21G03kNHVgHR7tyVkSSfAOG0Rqf/Cl38JftSmtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.102.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz", + "integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-loader": { + "version": "14.2.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.2.1.tgz", + "integrity": "sha512-G0VcnMYU18a4N7VoNDegg2OuMjYtxnqzQWARVWCIVSZwJeiL9kg8QMsuIZOplsJgTzZLF6jGxI3AClj8I9nRdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/seamless-immutable": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/seamless-immutable/-/seamless-immutable-7.1.4.tgz", + "integrity": "sha512-XiUO1QP4ki4E2PHegiGAlu6r82o5A+6tRh7IkGGTVg/h+UoeX4nFBeCGPOhb4CYjvkqsfm/TUtvOMYC1xmV30A==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/showdown": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-1.9.1.tgz", + "integrity": "sha512-9cGuS382HcvExtf5AHk7Cb4pAeQQ+h0eTr33V1mu+crYWV4KvWAw6el92bDrqGEk5d46Ai/fhbEUwqJ/mTCNEA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "yargs": "^14.2" + }, + "bin": { + "showdown": "bin/showdown.js" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-html-tokenizer": { + "version": "0.5.11", + "resolved": "https://registry.npmjs.org/simple-html-tokenizer/-/simple-html-tokenizer-0.5.11.tgz", + "integrity": "sha512-C2WEK/Z3HoSFbYq8tI7ni3eOo/NneSPRoPpcM7WdLjFOArFuyXEjAoCdOC3DgMfRyziZQ1hCNR4mrNdWEvD0og==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", + "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-object-atoms": "^1.1.2", + "has-property-descriptors": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", + "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tannin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.2.0.tgz", + "integrity": "sha512-U7GgX/RcSeUETbV7gYgoz8PD7Ni4y95pgIP/Z6ayI3CfhSujwKEBlGFTCRN+Aqnuyf4AN2yHL+L8x+TCGjb9uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tannin/plural-forms": "^1.1.0" + } + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.49.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz", + "integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinymce": { + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-7.9.3.tgz", + "integrity": "sha512-Mtm54U5YJ6Pyo/GaAx+JSHXTGEuxrg2AowVWCD9zy1eBolp5Ub7S1rTtsyQdxhPegfhLuR3VLiTKGw1tacv09g==", + "dev": true, + "license": "GPL-2.0-or-later" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-loader": { + "version": "9.6.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.6.2.tgz", + "integrity": "sha512-R4iuczmtgxvtuI556s+hTZ6/7Ee03VCAk/l/M8LY1OAsUgB7YydsCxkgq9D9pKRaD7GJqUi2u8fp9zZP/ufjKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "picomatch": "^4.0.0", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "loader-utils": "*", + "typescript": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "loader-utils": { + "optional": true + } + } + }, + "node_modules/ts-loader/node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", + "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.9", + "for-each": "^0.3.5", + "gopd": "^1.2.0", + "is-typed-array": "^1.1.15", + "possible-typed-array-names": "^1.1.0", + "reflect.getprototypeof": "^1.0.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/use-lilius": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/use-lilius/-/use-lilius-2.0.5.tgz", + "integrity": "sha512-IbPjJe4T6B0zQV6ahftVtHvCAxi6RAuDpEcO8TmnHh4nBtx7JbGdpbgXWOUj/9YjrzEbdT/lW7JWcBVbX3MbrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "date-fns": "^3.6.0" + }, + "peerDependencies": { + "react": "*", + "react-dom": "*" + } + }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/watchpack": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", + "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.109.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", + "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.24.4", + "es-module-lexer": "^2.1.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "graceful-fs": "^4.2.11", + "mime-db": "^1.54.0", + "minimizer-webpack-plugin": "^5.6.1", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "watchpack": "^2.5.2", + "webpack-sources": "^3.5.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", + "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^5.0.0", + "decamelize": "^1.2.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^15.0.1" + } + }, + "node_modules/yargs-parser": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", + "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + } + } +} From a0e651da2bbbe0a24ef95ce42a30d01adad3329d Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:20:50 +0200 Subject: [PATCH 29/78] build: add verified VM deployment workflow --- bin/cc-deploy-vm | 761 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 761 insertions(+) create mode 100644 bin/cc-deploy-vm diff --git a/bin/cc-deploy-vm b/bin/cc-deploy-vm new file mode 100644 index 0000000..ad1dfaa --- /dev/null +++ b/bin/cc-deploy-vm @@ -0,0 +1,761 @@ +#!/usr/bin/env bash + +cc_d5sr_usage() { + cat <<'USAGE' +Uso: + bin/cc-deploy-vm --dry-run + bin/cc-deploy-vm --package-only + bin/cc-deploy-vm --apply + +Variabili richieste per --apply: + CC_D5SR_DEPLOY_TARGET Destinazione SSH, ad esempio user@example-host + +Variabili opzionali: + CC_D5SR_DEPLOY_MODE auto, host o docker. Default: auto + CC_D5SR_DEPLOY_CONTAINER Container WordPress per la modalità docker + CC_D5SR_REMOTE_WP_ROOT Root WordPress remoto. Default: /var/www/html + CC_D5SR_REMOTE_STATE_DIR Stato, backup e staging remoti. + Default: .local/state/cc-divi5-search-results + CC_D5SR_SSH_PORT Porta SSH. Default: 22 + CC_D5SR_ACTIVATE 1 per attivare/verificare il plugin via WP-CLI. Default: 1 + CC_D5SR_BACKUP_KEEP Numero massimo di backup remoti. Default: 10 + CC_D5SR_REQUIRE_CLEAN 1 per richiedere una working tree pulita. Default: 1 + CC_D5SR_COLOR auto, always o never. Default: auto + NO_COLOR Disabilita i colori ANSI +USAGE +} + +cc_d5sr_error() { + printf '%bERRORE:%b %s\n' "$CC_D5SR_RED" "$CC_D5SR_RESET" "$*" >&2 +} + +cc_d5sr_info() { + printf '%b==>%b %s\n' "$CC_D5SR_CYAN" "$CC_D5SR_RESET" "$*" +} + +cc_d5sr_ok() { + printf '%bOK:%b %s\n' "$CC_D5SR_GREEN" "$CC_D5SR_RESET" "$*" +} + +cc_d5sr_warn() { + printf '%bATTENZIONE:%b %s\n' "$CC_D5SR_YELLOW" "$CC_D5SR_RESET" "$*" >&2 +} + +cc_d5sr_command_exists() { + command -v "$1" >/dev/null 2>&1 +} + +cc_d5sr_init_colors() { + local mode="${CC_D5SR_COLOR:-auto}" + + if [[ -n "${NO_COLOR:-}" ]]; then + mode="never" + fi + + case "$mode" in + always) + ;; + never) + CC_D5SR_RED='' + CC_D5SR_GREEN='' + CC_D5SR_YELLOW='' + CC_D5SR_CYAN='' + CC_D5SR_RESET='' + return 0 + ;; + auto) + if [[ ! -t 1 ]]; then + CC_D5SR_RED='' + CC_D5SR_GREEN='' + CC_D5SR_YELLOW='' + CC_D5SR_CYAN='' + CC_D5SR_RESET='' + return 0 + fi + ;; + *) + printf 'ERRORE: CC_D5SR_COLOR deve essere auto, always o never.\n' >&2 + return 1 + ;; + esac + + CC_D5SR_RED=$'\033[31m' + CC_D5SR_GREEN=$'\033[32m' + CC_D5SR_YELLOW=$'\033[33m' + CC_D5SR_CYAN=$'\033[36m' + CC_D5SR_RESET=$'\033[0m' +} + +cc_d5sr_require_command() { + local command_name="$1" + + if ! cc_d5sr_command_exists "$command_name"; then + cc_d5sr_error "comando richiesto non disponibile: $command_name" + return 1 + fi +} + +cc_d5sr_sha256() { + local file="$1" + + if cc_d5sr_command_exists sha256sum; then + sha256sum "$file" | awk '{print $1}' + return ${PIPESTATUS[0]} + fi + + if cc_d5sr_command_exists shasum; then + shasum -a 256 "$file" | awk '{print $1}' + return ${PIPESTATUS[0]} + fi + + cc_d5sr_error 'sha256sum o shasum non disponibile' + return 1 +} + +cc_d5sr_copy_path() { + local source="$1" + local destination="$2" + + if [[ ! -e "$source" ]]; then + cc_d5sr_error "percorso runtime mancante: $source" + return 1 + fi + + cp -R "$source" "$destination" || return 1 +} + +cc_d5sr_validate_integer() { + local value="$1" + local name="$2" + + if [[ ! "$value" =~ ^[0-9]+$ ]]; then + cc_d5sr_error "$name deve essere un intero non negativo" + return 1 + fi +} + +cc_d5sr_validate_mode() { + case "$1" in + auto|host|docker) + return 0 + ;; + *) + cc_d5sr_error 'CC_D5SR_DEPLOY_MODE deve essere auto, host o docker' + return 1 + ;; + esac +} + +cc_d5sr_validate_remote_value() { + local value="$1" + local name="$2" + + if [[ ! "$value" =~ ^[A-Za-z0-9_./@:-]+$ ]]; then + cc_d5sr_error "$name contiene caratteri non ammessi" + return 1 + fi +} + +cc_d5sr_build_package() { + local repo_root="$1" + local dist_dir="$2" + local plugin_slug="$3" + local stage_parent stage_dir version commit branch built_at archive archive_sha + + cc_d5sr_info 'Verifica lockfile' + + [[ -f "$repo_root/package-lock.json" ]] || { + cc_d5sr_error 'package-lock.json mancante: il deploy richiede il grafo npm bloccato' + return 1 + } + + [[ -f "$repo_root/composer.lock" ]] || { + cc_d5sr_error 'composer.lock mancante: il deploy richiede il grafo Composer bloccato' + return 1 + } + + if [[ "${CC_D5SR_REQUIRE_CLEAN:-1}" == '1' ]]; then + if [[ -n "$(git -C "$repo_root" status --porcelain --untracked-files=all)" ]]; then + cc_d5sr_error 'working tree non pulita; commit o rimuovi le modifiche prima del deploy' + git -C "$repo_root" status --short >&2 + return 1 + fi + fi + + cc_d5sr_info 'Installazione dipendenze bloccate' + ( + cd "$repo_root" || return 1 + composer install --no-interaction --prefer-dist --no-dev --optimize-autoloader || return 1 + npm ci || return 1 + ) || return 1 + + cc_d5sr_info 'Validazione e build' + ( + cd "$repo_root" || return 1 + npm run check || return 1 + npm run build || return 1 + composer check:syntax || return 1 + ) || return 1 + + version="$(php -r '$data = file_get_contents($argv[1]); if (preg_match("/^[[:space:]]*\\*[[:space:]]*Version:[[:space:]]*([^[:space:]]+)/m", $data, $m)) { echo $m[1]; }' "$repo_root/cc-divi5-search-results.php")" + [[ -n "$version" ]] || { + cc_d5sr_error 'impossibile rilevare la versione dal plugin header' + return 1 + } + + commit="$(git -C "$repo_root" rev-parse HEAD)" || return 1 + branch="$(git -C "$repo_root" branch --show-current)" || return 1 + built_at="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" + + mkdir -p "$dist_dir" || return 1 + stage_parent="$(mktemp -d "${TMPDIR:-/tmp}/cc-d5sr-package.XXXXXX")" || return 1 + stage_dir="$stage_parent/$plugin_slug" + mkdir -p "$stage_dir/scripts" "$stage_dir/styles" || { + rm -rf "$stage_parent" + return 1 + } + + cc_d5sr_copy_path "$repo_root/cc-divi5-search-results.php" "$stage_dir/" || { + rm -rf "$stage_parent" + return 1 + } + + local path + for path in assets includes modules shortcodes languages vendor modules-json; do + cc_d5sr_copy_path "$repo_root/$path" "$stage_dir/" || { + rm -rf "$stage_parent" + return 1 + } + done + + for path in LICENSE README.md CHANGELOG.md; do + cc_d5sr_copy_path "$repo_root/$path" "$stage_dir/" || { + rm -rf "$stage_parent" + return 1 + } + done + + cc_d5sr_copy_path "$repo_root/scripts/bundle.js" "$stage_dir/scripts/" || { + rm -rf "$stage_parent" + return 1 + } + + cc_d5sr_copy_path "$repo_root/styles/vb-bundle.css" "$stage_dir/styles/" || { + rm -rf "$stage_parent" + return 1 + } + + [[ -n "$branch" ]] || branch='detached' + + CC_D5SR_MANIFEST_PLUGIN="$plugin_slug" \ + CC_D5SR_MANIFEST_VERSION="$version" \ + CC_D5SR_MANIFEST_COMMIT="$commit" \ + CC_D5SR_MANIFEST_BRANCH="$branch" \ + CC_D5SR_MANIFEST_BUILT_AT="$built_at" \ + php -r ' + $manifest = array( + "plugin" => getenv("CC_D5SR_MANIFEST_PLUGIN"), + "version" => getenv("CC_D5SR_MANIFEST_VERSION"), + "git_commit" => getenv("CC_D5SR_MANIFEST_COMMIT"), + "git_branch" => getenv("CC_D5SR_MANIFEST_BRANCH"), + "built_at_utc" => getenv("CC_D5SR_MANIFEST_BUILT_AT"), + ); + file_put_contents($argv[1], json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL); + ' "$stage_dir/build-manifest.json" || { + rm -rf "$stage_parent" + return 1 + } + + archive="$dist_dir/${plugin_slug}-${version}-${commit:0:12}.tar.gz" + tar -C "$stage_parent" -czf "$archive" "$plugin_slug" || { + rm -rf "$stage_parent" + return 1 + } + + archive_sha="$(cc_d5sr_sha256 "$archive")" || { + rm -rf "$stage_parent" + return 1 + } + + printf '%s %s\n' "$archive_sha" "$(basename "$archive")" > "$archive.sha256" || { + rm -rf "$stage_parent" + return 1 + } + + rm -rf "$stage_parent" + + CC_D5SR_PACKAGE_PATH="$archive" + CC_D5SR_PACKAGE_SHA256="$archive_sha" + CC_D5SR_PACKAGE_VERSION="$version" + CC_D5SR_PACKAGE_COMMIT="$commit" + + cc_d5sr_ok "pacchetto creato: $archive" + cc_d5sr_ok "SHA-256: $archive_sha" +} + +cc_d5sr_deploy_remote() { + local target="$1" + local ssh_port="$2" + local deploy_mode="$3" + local container="$4" + local wp_root="$5" + local remote_state="$6" + local plugin_slug="$7" + local activate="$8" + local backup_keep="$9" + local remote_archive + + remote_archive="$remote_state/incoming/$(basename "$CC_D5SR_PACKAGE_PATH")" + + cc_d5sr_info "Preparazione destinazione remota: $target" + ssh -p "$ssh_port" "$target" \ + "mkdir -p '$remote_state/incoming' '$remote_state/backups' '$remote_state/stage'" || return 1 + + cc_d5sr_info 'Upload pacchetto' + cat "$CC_D5SR_PACKAGE_PATH" | ssh -p "$ssh_port" "$target" "cat > '$remote_archive'" || return 1 + + cc_d5sr_info 'Verifica checksum remoto' + ssh -p "$ssh_port" "$target" bash -s -- "$remote_archive" "$CC_D5SR_PACKAGE_SHA256" <<'REMOTE_SHA' || return 1 +remote_sha_main() { +archive="$1" +expected="$2" + +if command -v sha256sum >/dev/null 2>&1; then + actual="$(sha256sum "$archive" | awk '{print $1}')" || return 1 +elif command -v shasum >/dev/null 2>&1; then + actual="$(shasum -a 256 "$archive" | awk '{print $1}')" || return 1 +else + printf 'ERRORE: sha256sum o shasum non disponibile sulla VM.\n' >&2 + return 1 +fi + +if [[ "$actual" != "$expected" ]]; then + printf 'ERRORE: checksum remoto non corrispondente.\n' >&2 + return 1 +fi +} + +remote_sha_main "$@" +REMOTE_SHA + + cc_d5sr_info 'Backup e deploy atomico' + ssh -p "$ssh_port" "$target" bash -s -- \ + "$deploy_mode" \ + "$container" \ + "$wp_root" \ + "$plugin_slug" \ + "$remote_archive" \ + "$remote_state" \ + "$activate" \ + "$backup_keep" <<'REMOTE_DEPLOY' +remote_deploy_main() { +mode="$1" +container="$2" +wp_root="$3" +plugin_slug="$4" +archive="$5" +state_dir="$6" +activate="$7" +backup_keep="$8" + +timestamp="$(date '+%Y%m%d-%H%M%S')" +stage_parent="$state_dir/stage/$timestamp" +package_dir="$stage_parent/$plugin_slug" +backup_file="$state_dir/backups/${plugin_slug}-${timestamp}.tar.gz" +plugin_parent="$wp_root/wp-content/plugins" +target="$plugin_parent/$plugin_slug" +new_target="$plugin_parent/.${plugin_slug}.new-${timestamp}" +old_target="$plugin_parent/.${plugin_slug}.old-${timestamp}" +had_previous=0 + +remote_error() { + printf 'ERRORE: %s\n' "$*" >&2 +} + +remote_cleanup() { + rm -rf "$stage_parent" + rm -f "$archive" +} + +remote_prune_backups() { + local keep="$1" + + [[ "$keep" =~ ^[0-9]+$ ]] || return 1 + (( keep > 0 )) || return 0 + + find "$state_dir/backups" -maxdepth 1 -type f -name "${plugin_slug}-*.tar.gz" -print \ + | sort -r \ + | awk -v keep="$keep" 'NR > keep' \ + | while IFS= read -r old_backup; do + [[ -n "$old_backup" ]] && rm -f "$old_backup" + done +} + +remote_rollback_host() { + rm -rf "$target" + + if [[ -d "$old_target" ]]; then + mv "$old_target" "$target" || return 1 + elif (( had_previous == 1 )) && [[ -f "$backup_file" ]]; then + tar -C "$plugin_parent" -xzf "$backup_file" || return 1 + fi +} + +remote_rollback_docker() { + docker exec "$container" sh -lc "rm -rf '$target'" || return 1 + + if docker exec "$container" sh -lc "test -d '$old_target'"; then + docker exec "$container" sh -lc "mv '$old_target' '$target'" || return 1 + elif (( had_previous == 1 )) && [[ -f "$backup_file" ]]; then + cat "$backup_file" | docker exec -i "$container" tar -C "$plugin_parent" -xzf - || return 1 + fi +} + +remote_activate_host() { + (( activate == 1 )) || return 0 + + command -v wp >/dev/null 2>&1 || { + remote_error 'WP-CLI non disponibile sulla VM host' + return 1 + } + + wp --allow-root --path="$wp_root" plugin activate "$plugin_slug" || return 1 + wp --allow-root --path="$wp_root" plugin status "$plugin_slug" || return 1 +} + +remote_activate_docker() { + (( activate == 1 )) || return 0 + + docker exec "$container" sh -lc "command -v wp >/dev/null 2>&1" || { + remote_error 'WP-CLI non disponibile nel container WordPress' + return 1 + } + + docker exec "$container" wp --allow-root --path="$wp_root" plugin activate "$plugin_slug" || return 1 + docker exec "$container" wp --allow-root --path="$wp_root" plugin status "$plugin_slug" || return 1 +} + +mkdir -p "$stage_parent" "$state_dir/backups" || { + remote_error 'impossibile creare staging e backup remoti' + return 1 +} + +tar -C "$stage_parent" -xzf "$archive" || { + remote_error 'estrazione pacchetto fallita' + remote_cleanup + return 1 +} + +[[ -f "$package_dir/cc-divi5-search-results.php" ]] || { + remote_error 'entrypoint plugin assente nel pacchetto' + remote_cleanup + return 1 +} + +if [[ "$mode" == 'auto' ]]; then + if [[ -n "$container" ]]; then + mode='docker' + else + mode='host' + fi +fi + +case "$mode" in + host) + command -v php >/dev/null 2>&1 || { + remote_error 'PHP CLI non disponibile sulla VM host' + remote_cleanup + return 1 + } + + mkdir -p "$plugin_parent" || { + remote_error 'directory plugin host non disponibile' + remote_cleanup + return 1 + } + + if [[ -d "$target" ]]; then + tar -C "$plugin_parent" -czf "$backup_file" "$plugin_slug" || { + remote_error 'backup host fallito' + remote_cleanup + return 1 + } + had_previous=1 + fi + + rm -rf "$new_target" "$old_target" + cp -R "$package_dir" "$new_target" || { + remote_error 'copia staging host fallita' + remote_cleanup + return 1 + } + + php -l "$new_target/cc-divi5-search-results.php" >/dev/null || { + remote_error 'PHP lint remoto fallito sul nuovo pacchetto' + rm -rf "$new_target" + remote_cleanup + return 1 + } + + if (( had_previous == 1 )); then + mv "$target" "$old_target" || { + remote_error 'impossibile spostare la versione precedente' + rm -rf "$new_target" + remote_cleanup + return 1 + } + fi + + mv "$new_target" "$target" || { + remote_error 'switch atomico host fallito' + remote_rollback_host + remote_cleanup + return 1 + } + + remote_activate_host || { + remote_error 'attivazione/verifica host fallita; rollback in corso' + remote_rollback_host + remote_cleanup + return 1 + } + + rm -rf "$old_target" + ;; + + docker) + [[ -n "$container" ]] || { + remote_error 'CC_D5SR_DEPLOY_CONTAINER richiesto in modalità docker' + remote_cleanup + return 1 + } + + command -v docker >/dev/null 2>&1 || { + remote_error 'Docker non disponibile sulla VM' + remote_cleanup + return 1 + } + + docker inspect "$container" >/dev/null 2>&1 || { + remote_error "container non trovato: $container" + remote_cleanup + return 1 + } + + docker exec "$container" sh -lc "command -v php >/dev/null 2>&1 && command -v tar >/dev/null 2>&1" || { + remote_error 'PHP CLI o tar non disponibile nel container WordPress' + remote_cleanup + return 1 + } + + docker exec "$container" sh -lc "mkdir -p '$plugin_parent'" || { + remote_error 'directory plugin container non disponibile' + remote_cleanup + return 1 + } + + if docker exec "$container" sh -lc "test -d '$target'"; then + docker exec "$container" tar -C "$plugin_parent" -czf - "$plugin_slug" > "$backup_file" || { + remote_error 'backup container fallito' + remote_cleanup + return 1 + } + had_previous=1 + fi + + docker exec "$container" sh -lc "rm -rf '$new_target' '$old_target' && mkdir -p '$new_target'" || { + remote_error 'staging container fallito' + remote_cleanup + return 1 + } + + docker cp "$package_dir/." "$container:$new_target/" || { + remote_error 'docker cp fallito' + docker exec "$container" sh -lc "rm -rf '$new_target'" >/dev/null 2>&1 + remote_cleanup + return 1 + } + + docker exec "$container" php -l "$new_target/cc-divi5-search-results.php" >/dev/null || { + remote_error 'PHP lint nel container fallito' + docker exec "$container" sh -lc "rm -rf '$new_target'" >/dev/null 2>&1 + remote_cleanup + return 1 + } + + if (( had_previous == 1 )); then + docker exec "$container" sh -lc "mv '$target' '$old_target'" || { + remote_error 'impossibile spostare la versione precedente nel container' + docker exec "$container" sh -lc "rm -rf '$new_target'" >/dev/null 2>&1 + remote_cleanup + return 1 + } + fi + + docker exec "$container" sh -lc "mv '$new_target' '$target'" || { + remote_error 'switch atomico container fallito' + remote_rollback_docker + remote_cleanup + return 1 + } + + remote_activate_docker || { + remote_error 'attivazione/verifica container fallita; rollback in corso' + remote_rollback_docker + remote_cleanup + return 1 + } + + docker exec "$container" sh -lc "rm -rf '$old_target'" + ;; + + *) + remote_error "modalità deploy non valida: $mode" + remote_cleanup + return 1 + ;; +esac + +remote_prune_backups "$backup_keep" || { + remote_error 'deploy riuscito, ma pulizia backup fallita' + remote_cleanup + return 1 +} + +remote_cleanup + +printf 'OK: deploy completato\n' +if (( had_previous == 1 )); then + printf 'Backup: %s\n' "$backup_file" +else + printf 'Backup: nessuna versione precedente\n' +fi +} + +remote_deploy_main "$@" +REMOTE_DEPLOY +} + +cc_d5sr_main() { + local action='' + local repo_root dist_dir plugin_slug + local deploy_target deploy_mode deploy_container remote_wp_root remote_state + local ssh_port activate backup_keep + + cc_d5sr_init_colors || return 1 + + while (($#)); do + case "$1" in + --dry-run) + action='dry-run' + ;; + --package-only) + action='package-only' + ;; + --apply) + action='apply' + ;; + -h|--help) + cc_d5sr_usage + return 0 + ;; + *) + cc_d5sr_error "argomento non riconosciuto: $1" + cc_d5sr_usage >&2 + return 1 + ;; + esac + shift + done + + [[ -n "$action" ]] || { + cc_d5sr_error 'specificare --dry-run, --package-only o --apply' + cc_d5sr_usage >&2 + return 1 + } + + for command_name in git php composer npm tar awk find sort; do + cc_d5sr_require_command "$command_name" || return 1 + done + + if [[ "$action" == 'apply' ]]; then + cc_d5sr_require_command ssh || return 1 + fi + + repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || { + cc_d5sr_error 'eseguire lo script dentro il repository Git' + return 1 + } + + plugin_slug='cc-divi5-search-results' + dist_dir="$repo_root/dist" + deploy_target="${CC_D5SR_DEPLOY_TARGET:-}" + deploy_mode="${CC_D5SR_DEPLOY_MODE:-auto}" + deploy_container="${CC_D5SR_DEPLOY_CONTAINER:-}" + remote_wp_root="${CC_D5SR_REMOTE_WP_ROOT:-/var/www/html}" + remote_state="${CC_D5SR_REMOTE_STATE_DIR:-.local/state/cc-divi5-search-results}" + ssh_port="${CC_D5SR_SSH_PORT:-22}" + activate="${CC_D5SR_ACTIVATE:-1}" + backup_keep="${CC_D5SR_BACKUP_KEEP:-10}" + + cc_d5sr_validate_mode "$deploy_mode" || return 1 + cc_d5sr_validate_integer "$ssh_port" CC_D5SR_SSH_PORT || return 1 + cc_d5sr_validate_integer "$activate" CC_D5SR_ACTIVATE || return 1 + cc_d5sr_validate_integer "$backup_keep" CC_D5SR_BACKUP_KEEP || return 1 + cc_d5sr_validate_integer "${CC_D5SR_REQUIRE_CLEAN:-1}" CC_D5SR_REQUIRE_CLEAN || return 1 + cc_d5sr_validate_remote_value "$remote_wp_root" CC_D5SR_REMOTE_WP_ROOT || return 1 + cc_d5sr_validate_remote_value "$remote_state" CC_D5SR_REMOTE_STATE_DIR || return 1 + + if [[ -n "$deploy_target" ]]; then + cc_d5sr_validate_remote_value "$deploy_target" CC_D5SR_DEPLOY_TARGET || return 1 + fi + + if [[ -n "$deploy_container" ]]; then + cc_d5sr_validate_remote_value "$deploy_container" CC_D5SR_DEPLOY_CONTAINER || return 1 + fi + + if [[ "$activate" != '0' && "$activate" != '1' ]]; then + cc_d5sr_error 'CC_D5SR_ACTIVATE deve essere 0 o 1' + return 1 + fi + + cc_d5sr_build_package "$repo_root" "$dist_dir" "$plugin_slug" || return 1 + + case "$action" in + package-only) + printf '%s\n' "$CC_D5SR_PACKAGE_PATH" + return 0 + ;; + dry-run) + cc_d5sr_info 'Dry-run completato: nessun collegamento SSH e nessuna modifica remota' + printf 'Pacchetto: %s\n' "$CC_D5SR_PACKAGE_PATH" + printf 'SHA-256: %s\n' "$CC_D5SR_PACKAGE_SHA256" + printf 'Target: %s\n' "${deploy_target:-}" + printf 'Modalità: %s\n' "$deploy_mode" + printf 'Container:%s\n' " ${deploy_container:-}" + printf 'WP root: %s\n' "$remote_wp_root" + return 0 + ;; + apply) + [[ -n "$deploy_target" ]] || { + cc_d5sr_error 'CC_D5SR_DEPLOY_TARGET è obbligatorio per --apply' + return 1 + } + + cc_d5sr_deploy_remote \ + "$deploy_target" \ + "$ssh_port" \ + "$deploy_mode" \ + "$deploy_container" \ + "$remote_wp_root" \ + "$remote_state" \ + "$plugin_slug" \ + "$activate" \ + "$backup_keep" || return 1 + + cc_d5sr_ok "deploy completato su $deploy_target" + ;; + esac +} + +cc_d5sr_main "$@" From 66210213931575c93f9cb8351ce4c23f97193979 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:21:04 +0200 Subject: [PATCH 30/78] build: expose package and VM deploy commands --- composer.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 12c5ebd..4b024ff 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,9 @@ "sort-packages": true }, "scripts": { - "check:syntax": "find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print0 | xargs -0 -n1 php -l" + "check:syntax": "find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print0 | xargs -0 -n1 php -l", + "package": "bash bin/cc-deploy-vm --package-only", + "deploy:check": "bash bin/cc-deploy-vm --dry-run", + "deploy": "bash bin/cc-deploy-vm --apply" } } From 43e6318f54cf8bf9bc6ca1463792d54d5fe6d524 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:22:04 +0200 Subject: [PATCH 31/78] docs: document reproducible VM deployment --- README.md | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0ca93fd..b54ccd1 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ The `0.1.0` development branch currently includes: - shared rendering used by both the native module and `[cc_divi5_search_results]`; - Visual Builder TypeScript sources, Divi-compatible compiler configuration and webpack build; - repository-level npm configuration for the incompatible peer ranges published by the Divi 5 type aliases; +- deterministic runtime packaging with build manifest and SHA-256 checksum; +- verified VM deployment for host and Docker WordPress installations, including backup and automatic rollback; - frontend CSS with responsive grid behavior. The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. @@ -153,7 +155,118 @@ modules-json/search-results/module.json modules-json/search-result-type/module.json ``` -Local proprietary references, including an extracted Divi theme under `.reference/`, are ignored by Git and must never be committed. A source checkout is therefore not a distributable plugin archive by itself: release packaging must run the build and include the generated Visual Builder assets and module metadata. +Local proprietary references, including an extracted Divi theme under `.reference/`, are ignored by Git and must never be committed. + +## Runtime package + +A source checkout is not a distributable plugin archive by itself. The package command performs a clean dependency install from both committed lockfiles, runs all TypeScript/JSON/PHP checks, builds the Visual Builder assets and creates a runtime-only archive under `dist/`: + +```bash +composer package +``` + +The generated archive contains: + +```text +cc-divi5-search-results.php +assets/ +includes/ +modules/ +shortcodes/ +languages/ +vendor/ +modules-json/ +scripts/bundle.js +styles/vb-bundle.css +README.md +CHANGELOG.md +LICENSE +build-manifest.json +``` + +It deliberately excludes `src/`, `node_modules/`, development manifests, local references and repository metadata. A sibling `.sha256` file records the archive checksum. The build manifest records plugin version, exact Git commit, branch and UTC build time. + +Packaging requires: + +- committed `composer.lock` and `package-lock.json`; +- a clean working tree unless `CC_D5SR_REQUIRE_CLEAN=0` is set explicitly; +- successful `composer install --no-dev`, `npm ci`, `npm run check`, `npm run build` and `composer check:syntax`. + +## VM deployment + +The same workflow deploys the generated runtime archive to a WordPress installation reachable over SSH: + +```bash +composer deploy:check +composer deploy +``` + +`deploy:check` performs the full local package and validation sequence but never opens an SSH connection and never modifies the VM. + +`deploy` performs: + +1. local clean-tree and lockfile checks; +2. reproducible package generation; +3. SSH upload without `scp`; +4. SHA-256 verification on the VM; +5. timestamped backup of the installed plugin when present; +6. staged copy into the WordPress plugins directory; +7. remote PHP lint before switching versions; +8. same-filesystem atomic directory switch; +9. optional activation and status verification through WP-CLI; +10. automatic rollback when the remote lint, switch, activation or status check fails; +11. retention pruning for old backups. + +### Required deployment variable + +```bash +export CC_D5SR_DEPLOY_TARGET="user@example-host" +``` + +### Docker WordPress example + +```bash +export CC_D5SR_DEPLOY_TARGET="user@example-host" +export CC_D5SR_DEPLOY_MODE="docker" +export CC_D5SR_DEPLOY_CONTAINER="wordpress" +export CC_D5SR_REMOTE_WP_ROOT="/var/www/html" + +composer deploy:check +composer deploy +``` + +The VM must provide Docker. The selected container must provide `php`, `tar` and, when activation is enabled, `wp`. + +### Host WordPress example + +```bash +export CC_D5SR_DEPLOY_TARGET="user@example-host" +export CC_D5SR_DEPLOY_MODE="host" +export CC_D5SR_REMOTE_WP_ROOT="/var/www/html" + +composer deploy:check +composer deploy +``` + +The host must provide `php` and, when activation is enabled, `wp`. + +### Deployment variables + +```text +CC_D5SR_DEPLOY_TARGET required for deploy; SSH user/host +CC_D5SR_DEPLOY_MODE auto, host or docker; default auto +CC_D5SR_DEPLOY_CONTAINER required by docker mode +CC_D5SR_REMOTE_WP_ROOT default /var/www/html +CC_D5SR_REMOTE_STATE_DIR default .local/state/cc-divi5-search-results +CC_D5SR_SSH_PORT default 22 +CC_D5SR_ACTIVATE 1 or 0; default 1 +CC_D5SR_BACKUP_KEEP default 10; 0 disables pruning +CC_D5SR_REQUIRE_CLEAN 1 or 0; default 1 +CC_D5SR_COLOR auto, always or never +NO_COLOR disables ANSI colors +``` + +The default remote state path is relative to the SSH user's home directory. It contains incoming archives, temporary extraction directories and timestamped backups. No credentials or VM-specific values belong in the repository. ## Not implemented yet @@ -168,13 +281,13 @@ The README deliberately does not present the following as available: - image fallback and ratio controls; - card presets; - AJAX navigation; -- automated release archive generation. +- automated GitHub release publication. Those capabilities will be added in later reviewable increments without changing the shared renderer contract. ## Documentation rule -Every pull request that changes behavior, controls, requirements, generated paths, build commands, dependency requirements or public APIs must update this README in the same pull request. Documentation may describe merged or included code only; planned behavior belongs exclusively in **Not implemented yet**. +Every pull request that changes behavior, controls, requirements, generated paths, build commands, dependency requirements, deployment behavior or public APIs must update this README in the same pull request. Documentation may describe merged or included code only; planned behavior belongs exclusively in **Not implemented yet**. ## License From 9915bb2a7ca0a5b3bec8cde161cd77131cb54203 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:22:20 +0200 Subject: [PATCH 32/78] docs: record runtime packaging and VM deploy --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc20c1f..eb0ddac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ - Repository `.npmrc` with strict engine enforcement and deterministic handling of incompatible Divi peer ranges. - Lockfile-safe `npm run reset-install` for rebuilding `node_modules` through `npm ci`. - Git exclusion for local proprietary references under `.reference/`. +- Runtime-only package generation with build manifest and SHA-256 checksum. +- VM deployment workflow supporting host and Docker WordPress installations. +- Timestamped remote backups, retention pruning and automatic rollback on failed remote validation or activation. +- Composer commands `package`, `deploy:check` and `deploy`. ### Changed @@ -25,3 +29,4 @@ - Development dependencies now include the transitive declarations required by the Divi 5.9.0 type packages. - Development documentation now requires committed npm and Composer lockfiles to remain synchronized with their manifests. - Release documentation now distinguishes ignored source-build outputs from files required in a distributable plugin archive. +- Deployment documentation now defines reproducible packaging, dry-run behavior, remote requirements, backup location and rollback guarantees. From 698b4ae556cca442113ce9c32e0754ffa9a617be Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:23:34 +0200 Subject: [PATCH 33/78] docs: clarify deploy validation scope --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b54ccd1..7564358 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ The `0.1.0` development branch currently includes: - Visual Builder TypeScript sources, Divi-compatible compiler configuration and webpack build; - repository-level npm configuration for the incompatible peer ranges published by the Divi 5 type aliases; - deterministic runtime packaging with build manifest and SHA-256 checksum; -- verified VM deployment for host and Docker WordPress installations, including backup and automatic rollback; +- VM deployment workflow for host and Docker WordPress installations, including backup and automatic rollback; - frontend CSS with responsive grid behavior. The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. @@ -192,6 +192,8 @@ Packaging requires: - a clean working tree unless `CC_D5SR_REQUIRE_CLEAN=0` is set explicitly; - successful `composer install --no-dev`, `npm ci`, `npm run check`, `npm run build` and `composer check:syntax`. +The package path, archive contents and checksum flow have been exercised against a disposable mock repository. The first real VM deployment remains a required integration test before this PR can leave draft state. + ## VM deployment The same workflow deploys the generated runtime archive to a WordPress installation reachable over SSH: From d04d1bdb2cfd5392edf4d99af2695aec2e81bff6 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:23:49 +0200 Subject: [PATCH 34/78] docs: record deploy verification boundary --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb0ddac..ad90a72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,3 +30,4 @@ - Development documentation now requires committed npm and Composer lockfiles to remain synchronized with their manifests. - Release documentation now distinguishes ignored source-build outputs from files required in a distributable plugin archive. - Deployment documentation now defines reproducible packaging, dry-run behavior, remote requirements, backup location and rollback guarantees. +- Documentation now records that runtime packaging passed a disposable mock-repository test while the first real VM deployment remains an integration gate. From 767d1219c764a749645b756f5e4853fc317506cd Mon Sep 17 00:00:00 2001 From: Federico Girolami Date: Wed, 29 Jul 2026 23:33:10 +0200 Subject: [PATCH 35/78] build: lock dependencies and enable VM deploy --- bin/cc-deploy-vm | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/cc-deploy-vm diff --git a/bin/cc-deploy-vm b/bin/cc-deploy-vm old mode 100644 new mode 100755 From 5e6d97f8e29ddbf16bb733f014237994764fbbeb Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:40:31 +0200 Subject: [PATCH 36/78] fix: resolve Barbagia container from explicit Compose stack --- bin/cc-deploy-barbagia-vm | 210 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 bin/cc-deploy-barbagia-vm diff --git a/bin/cc-deploy-barbagia-vm b/bin/cc-deploy-barbagia-vm new file mode 100644 index 0000000..f308f86 --- /dev/null +++ b/bin/cc-deploy-barbagia-vm @@ -0,0 +1,210 @@ +#!/usr/bin/env bash + +cc_d5sr_barbagia_usage() { + cat <<'USAGE' +Uso: + bin/cc-deploy-barbagia-vm --dry-run + bin/cc-deploy-barbagia-vm --package-only + bin/cc-deploy-barbagia-vm --apply + +Default Barbagia Musei: + SSH target: docker02 + Compose file: /home/fgirolami/docker/barbagiamusei/compose.yaml + Compose service: wp_cron + WordPress root: /var/www/html + +Variabili opzionali: + CC_D5SR_DEPLOY_TARGET + CC_D5SR_COMPOSE_FILE + CC_D5SR_COMPOSE_SERVICE + CC_D5SR_REMOTE_WP_ROOT + CC_D5SR_REMOTE_STATE_DIR + CC_D5SR_SSH_PORT + CC_D5SR_ACTIVATE + CC_D5SR_BACKUP_KEEP + CC_D5SR_REQUIRE_CLEAN + CC_D5SR_COLOR +USAGE +} + +cc_d5sr_barbagia_error() { + printf 'ERRORE: %s\n' "$*" >&2 +} + +cc_d5sr_barbagia_info() { + printf '==> %s\n' "$*" +} + +cc_d5sr_barbagia_validate_value() { + local value="$1" + local name="$2" + + if [[ ! "$value" =~ ^[A-Za-z0-9_./@:-]+$ ]]; then + cc_d5sr_barbagia_error "$name contiene caratteri non ammessi" + return 1 + fi +} + +cc_d5sr_barbagia_resolve_container() { + local target="$1" + local ssh_port="$2" + local compose_file="$3" + local compose_service="$4" + local wp_root="$5" + local result + + result="$( + ssh -p "$ssh_port" "$target" bash -s -- \ + "$compose_file" \ + "$compose_service" \ + "$wp_root" <<'REMOTE_RESOLVE' +resolve_container_main() { + compose_file="$1" + compose_service="$2" + wp_root="$3" + + command -v docker >/dev/null 2>&1 || { + printf 'ERRORE: Docker non disponibile sulla VM.\n' >&2 + return 1 + } + + [[ -f "$compose_file" ]] || { + printf 'ERRORE: Compose file non trovato: %s\n' "$compose_file" >&2 + return 1 + } + + docker compose -f "$compose_file" config --services \ + | grep -Fx "$compose_service" >/dev/null 2>&1 || { + printf 'ERRORE: service Compose non trovato: %s\n' "$compose_service" >&2 + return 1 + } + + container_ids="$(docker compose -f "$compose_file" ps -q "$compose_service")" || return 1 + container_count="$(printf '%s\n' "$container_ids" | awk 'NF { count++ } END { print count + 0 }')" + + [[ "$container_count" == '1' ]] || { + printf 'ERRORE: atteso un solo container per %s, trovati %s.\n' \ + "$compose_service" \ + "$container_count" >&2 + return 1 + } + + container_id="$(printf '%s\n' "$container_ids" | awk 'NF { print; exit }')" + + docker inspect "$container_id" >/dev/null 2>&1 || { + printf 'ERRORE: container Compose non disponibile: %s\n' "$container_id" >&2 + return 1 + } + + docker exec "$container_id" sh -lc \ + "test -f '$wp_root/wp-load.php' && command -v php >/dev/null 2>&1 && command -v tar >/dev/null 2>&1 && command -v wp >/dev/null 2>&1" || { + printf 'ERRORE: il container %s non espone WordPress, PHP, tar e WP-CLI nel path %s.\n' \ + "$container_id" \ + "$wp_root" >&2 + return 1 + } + + container_name="$(docker inspect --format '{{.Name}}' "$container_id" | sed 's#^/##')" || return 1 + + printf '%s|%s\n' "$container_id" "$container_name" +} + +resolve_container_main "$@" +REMOTE_RESOLVE + )" || return 1 + + [[ "$result" == *'|'* ]] || { + cc_d5sr_barbagia_error 'risposta non valida durante la risoluzione del container Compose' + return 1 + } + + CC_D5SR_BARBAGIA_CONTAINER_ID="${result%%|*}" + CC_D5SR_BARBAGIA_CONTAINER_NAME="${result#*|}" + + [[ "$CC_D5SR_BARBAGIA_CONTAINER_ID" =~ ^[a-f0-9]{12,64}$ ]] || { + cc_d5sr_barbagia_error "ID container non valido: $CC_D5SR_BARBAGIA_CONTAINER_ID" + return 1 + } +} + +cc_d5sr_barbagia_main() { + local action="${1:-}" + local repo_root deploy_script + local target compose_file compose_service wp_root ssh_port + + case "$action" in + --dry-run|--package-only|--apply) + ;; + -h|--help) + cc_d5sr_barbagia_usage + return 0 + ;; + *) + cc_d5sr_barbagia_error 'specificare --dry-run, --package-only o --apply' + cc_d5sr_barbagia_usage >&2 + return 1 + ;; + esac + + repo_root="$(git rev-parse --show-toplevel 2>/dev/null)" || { + cc_d5sr_barbagia_error 'eseguire il wrapper dentro il repository Git' + return 1 + } + + deploy_script="$repo_root/bin/cc-deploy-vm" + [[ -f "$deploy_script" ]] || { + cc_d5sr_barbagia_error "script generico non trovato: $deploy_script" + return 1 + } + + target="${CC_D5SR_DEPLOY_TARGET:-docker02}" + compose_file="${CC_D5SR_COMPOSE_FILE:-/home/fgirolami/docker/barbagiamusei/compose.yaml}" + compose_service="${CC_D5SR_COMPOSE_SERVICE:-wp_cron}" + wp_root="${CC_D5SR_REMOTE_WP_ROOT:-/var/www/html}" + ssh_port="${CC_D5SR_SSH_PORT:-22}" + + cc_d5sr_barbagia_validate_value "$target" CC_D5SR_DEPLOY_TARGET || return 1 + cc_d5sr_barbagia_validate_value "$compose_file" CC_D5SR_COMPOSE_FILE || return 1 + cc_d5sr_barbagia_validate_value "$compose_service" CC_D5SR_COMPOSE_SERVICE || return 1 + cc_d5sr_barbagia_validate_value "$wp_root" CC_D5SR_REMOTE_WP_ROOT || return 1 + + [[ "$ssh_port" =~ ^[0-9]+$ ]] || { + cc_d5sr_barbagia_error 'CC_D5SR_SSH_PORT deve essere numerica' + return 1 + } + + export CC_D5SR_DEPLOY_TARGET="$target" + export CC_D5SR_DEPLOY_MODE='docker' + export CC_D5SR_REMOTE_WP_ROOT="$wp_root" + export CC_D5SR_SSH_PORT="$ssh_port" + export CC_D5SR_ACTIVATE="${CC_D5SR_ACTIVATE:-1}" + export CC_D5SR_BACKUP_KEEP="${CC_D5SR_BACKUP_KEEP:-10}" + export CC_D5SR_COLOR="${CC_D5SR_COLOR:-always}" + + cc_d5sr_barbagia_info "repository locale: $repo_root" + cc_d5sr_barbagia_info "target SSH: $target" + cc_d5sr_barbagia_info "Compose file remoto: $compose_file" + cc_d5sr_barbagia_info "Compose service: $compose_service" + cc_d5sr_barbagia_info "WordPress root: $wp_root" + + if [[ "$action" == '--apply' ]]; then + cc_d5sr_barbagia_info 'risoluzione container dal Compose remoto' + cc_d5sr_barbagia_resolve_container \ + "$target" \ + "$ssh_port" \ + "$compose_file" \ + "$compose_service" \ + "$wp_root" || return 1 + + export CC_D5SR_DEPLOY_CONTAINER="$CC_D5SR_BARBAGIA_CONTAINER_ID" + cc_d5sr_barbagia_info \ + "container risolto: $CC_D5SR_BARBAGIA_CONTAINER_NAME ($CC_D5SR_BARBAGIA_CONTAINER_ID)" + else + unset CC_D5SR_DEPLOY_CONTAINER + cc_d5sr_barbagia_info 'container remoto: risolto dal Compose soltanto durante --apply' + fi + + bash "$deploy_script" "$action" +} + +cc_d5sr_barbagia_main "$@" From 06ebb35bf8d7ac268ec99fa1a5e963be531cf9c4 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:40:42 +0200 Subject: [PATCH 37/78] build: add explicit Barbagia deploy commands --- composer.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4b024ff..354d5ec 100644 --- a/composer.json +++ b/composer.json @@ -20,6 +20,8 @@ "check:syntax": "find . -path ./vendor -prune -o -path ./node_modules -prune -o -name '*.php' -print0 | xargs -0 -n1 php -l", "package": "bash bin/cc-deploy-vm --package-only", "deploy:check": "bash bin/cc-deploy-vm --dry-run", - "deploy": "bash bin/cc-deploy-vm --apply" + "deploy": "bash bin/cc-deploy-vm --apply", + "deploy:barbagia:check": "bash bin/cc-deploy-barbagia-vm --dry-run", + "deploy:barbagia": "bash bin/cc-deploy-barbagia-vm --apply" } } From 02942c9f131ab7b16fb04107c1eb475c71ab7a86 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:42:07 +0200 Subject: [PATCH 38/78] docs: pin the Barbagia Compose deployment contract --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7564358..65ef298 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ The `0.1.0` development branch currently includes: - repository-level npm configuration for the incompatible peer ranges published by the Divi 5 type aliases; - deterministic runtime packaging with build manifest and SHA-256 checksum; - VM deployment workflow for host and Docker WordPress installations, including backup and automatic rollback; +- a Barbagia Musei deployment wrapper pinned to the real `docker02` Compose stack and `wp_cron` service; - frontend CSS with responsive grid behavior. The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. @@ -227,10 +228,12 @@ export CC_D5SR_DEPLOY_TARGET="user@example-host" ### Docker WordPress example +`CC_D5SR_DEPLOY_CONTAINER` is a Docker container name or ID, not a Compose service name. + ```bash export CC_D5SR_DEPLOY_TARGET="user@example-host" export CC_D5SR_DEPLOY_MODE="docker" -export CC_D5SR_DEPLOY_CONTAINER="wordpress" +export CC_D5SR_DEPLOY_CONTAINER="wordpress-container-name" export CC_D5SR_REMOTE_WP_ROOT="/var/www/html" composer deploy:check @@ -239,6 +242,57 @@ composer deploy The VM must provide Docker. The selected container must provide `php`, `tar` and, when activation is enabled, `wp`. +### Barbagia Musei on `docker02` + +The dedicated wrapper removes all manual container and path discovery. Run it from the local repository root: + +```bash +cd "$GH_PATH/cc-divi5-search-results" || return 1 + +composer deploy:barbagia:check +composer deploy:barbagia +``` + +The wrapper is pinned to this deployment contract: + +```text +Local repository: $GH_PATH/cc-divi5-search-results +SSH target: docker02 +Remote Compose file:/home/fgirolami/docker/barbagiamusei/compose.yaml +Compose service: wp_cron +WordPress root: /var/www/html +Activation: enabled +Backup retention: 10 +``` + +`composer deploy:barbagia:check` runs the complete local package validation without SSH or remote changes. + +`composer deploy:barbagia` connects to `docker02` and resolves the running container dynamically with: + +```bash +docker compose \ + -f /home/fgirolami/docker/barbagiamusei/compose.yaml \ + ps -q wp_cron +``` + +The resolved container is currently named `cron_barbagiamusei`, but that name is not hardcoded because it can change after a Compose recreate. Before deployment, the wrapper requires exactly one running container for `wp_cron` and verifies inside it: + +- `/var/www/html/wp-load.php`; +- PHP CLI; +- `tar`; +- WP-CLI. + +The remote Compose command uses the absolute `-f` path. It does not depend on the SSH login directory or on the repository path shown by the remote shell prompt. + +Optional Barbagia overrides are available only when the stack changes intentionally: + +```text +CC_D5SR_DEPLOY_TARGET default docker02 +CC_D5SR_COMPOSE_FILE default /home/fgirolami/docker/barbagiamusei/compose.yaml +CC_D5SR_COMPOSE_SERVICE default wp_cron +CC_D5SR_REMOTE_WP_ROOT default /var/www/html +``` + ### Host WordPress example ```bash @@ -255,9 +309,9 @@ The host must provide `php` and, when activation is enabled, `wp`. ### Deployment variables ```text -CC_D5SR_DEPLOY_TARGET required for deploy; SSH user/host +CC_D5SR_DEPLOY_TARGET required for generic deploy; SSH user/host CC_D5SR_DEPLOY_MODE auto, host or docker; default auto -CC_D5SR_DEPLOY_CONTAINER required by docker mode +CC_D5SR_DEPLOY_CONTAINER Docker container name or ID; never a Compose service CC_D5SR_REMOTE_WP_ROOT default /var/www/html CC_D5SR_REMOTE_STATE_DIR default .local/state/cc-divi5-search-results CC_D5SR_SSH_PORT default 22 @@ -268,7 +322,7 @@ CC_D5SR_COLOR auto, always or never NO_COLOR disables ANSI colors ``` -The default remote state path is relative to the SSH user's home directory. It contains incoming archives, temporary extraction directories and timestamped backups. No credentials or VM-specific values belong in the repository. +The default remote state path is relative to the SSH user's home directory. It contains incoming archives, temporary extraction directories and timestamped backups. No credentials belong in the repository. The Barbagia wrapper intentionally contains the non-secret stack path and service contract so deployment does not rely on operator memory. ## Not implemented yet From e6ec304457592345fce83aa4697108b00cc59597 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Wed, 29 Jul 2026 23:42:25 +0200 Subject: [PATCH 39/78] docs: record explicit Compose service resolution --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad90a72..c804f24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ - VM deployment workflow supporting host and Docker WordPress installations. - Timestamped remote backups, retention pruning and automatic rollback on failed remote validation or activation. - Composer commands `package`, `deploy:check` and `deploy`. +- Barbagia-specific Composer commands `deploy:barbagia:check` and `deploy:barbagia`. +- Dedicated Barbagia wrapper pinned to `/home/fgirolami/docker/barbagiamusei/compose.yaml` and the `wp_cron` Compose service. +- Dynamic resolution and validation of the real `wp_cron` container before remote deployment. ### Changed @@ -30,4 +33,6 @@ - Development documentation now requires committed npm and Composer lockfiles to remain synchronized with their manifests. - Release documentation now distinguishes ignored source-build outputs from files required in a distributable plugin archive. - Deployment documentation now defines reproducible packaging, dry-run behavior, remote requirements, backup location and rollback guarantees. +- Generic Docker deployment documentation now distinguishes Docker container names or IDs from Compose service names. +- Barbagia deployment no longer depends on the current SSH directory or a hardcoded container name. - Documentation now records that runtime packaging passed a disposable mock-repository test while the first real VM deployment remains an integration gate. From 5851e8cbb8d5b56ae742c11c1c9e727e453e3f6f Mon Sep 17 00:00:00 2001 From: Federico Girolami Date: Wed, 29 Jul 2026 23:59:05 +0200 Subject: [PATCH 40/78] modified: bin/cc-deploy-barbagia-vm modified: bin/cc-deploy-vm --- bin/cc-deploy-barbagia-vm | 0 bin/cc-deploy-vm | 179 ++++++++++++++++++++------------------ 2 files changed, 92 insertions(+), 87 deletions(-) mode change 100644 => 100755 bin/cc-deploy-barbagia-vm diff --git a/bin/cc-deploy-barbagia-vm b/bin/cc-deploy-barbagia-vm old mode 100644 new mode 100755 diff --git a/bin/cc-deploy-vm b/bin/cc-deploy-vm index ad1dfaa..df56202 100755 --- a/bin/cc-deploy-vm +++ b/bin/cc-deploy-vm @@ -53,30 +53,29 @@ cc_d5sr_init_colors() { fi case "$mode" in - always) - ;; - never) + always) ;; + never) + CC_D5SR_RED='' + CC_D5SR_GREEN='' + CC_D5SR_YELLOW='' + CC_D5SR_CYAN='' + CC_D5SR_RESET='' + return 0 + ;; + auto) + if [[ ! -t 1 ]]; then CC_D5SR_RED='' CC_D5SR_GREEN='' CC_D5SR_YELLOW='' CC_D5SR_CYAN='' CC_D5SR_RESET='' return 0 - ;; - auto) - if [[ ! -t 1 ]]; then - CC_D5SR_RED='' - CC_D5SR_GREEN='' - CC_D5SR_YELLOW='' - CC_D5SR_CYAN='' - CC_D5SR_RESET='' - return 0 - fi - ;; - *) - printf 'ERRORE: CC_D5SR_COLOR deve essere auto, always o never.\n' >&2 - return 1 - ;; + fi + ;; + *) + printf 'ERRORE: CC_D5SR_COLOR deve essere auto, always o never.\n' >&2 + return 1 + ;; esac CC_D5SR_RED=$'\033[31m' @@ -100,12 +99,12 @@ cc_d5sr_sha256() { if cc_d5sr_command_exists sha256sum; then sha256sum "$file" | awk '{print $1}' - return ${PIPESTATUS[0]} + return "${PIPESTATUS[0]}" fi if cc_d5sr_command_exists shasum; then shasum -a 256 "$file" | awk '{print $1}' - return ${PIPESTATUS[0]} + return "${PIPESTATUS[0]}" fi cc_d5sr_error 'sha256sum o shasum non disponibile' @@ -136,13 +135,13 @@ cc_d5sr_validate_integer() { cc_d5sr_validate_mode() { case "$1" in - auto|host|docker) - return 0 - ;; - *) - cc_d5sr_error 'CC_D5SR_DEPLOY_MODE deve essere auto, host o docker' - return 1 - ;; + auto | host | docker) + return 0 + ;; + *) + cc_d5sr_error 'CC_D5SR_DEPLOY_MODE deve essere auto, host o docker' + return 1 + ;; esac } @@ -197,6 +196,7 @@ cc_d5sr_build_package() { composer check:syntax || return 1 ) || return 1 + # shellcheck disable=SC2016 version="$(php -r '$data = file_get_contents($argv[1]); if (preg_match("/^[[:space:]]*\\*[[:space:]]*Version:[[:space:]]*([^[:space:]]+)/m", $data, $m)) { echo $m[1]; }' "$repo_root/cc-divi5-search-results.php")" [[ -n "$version" ]] || { cc_d5sr_error 'impossibile rilevare la versione dal plugin header' @@ -247,11 +247,12 @@ cc_d5sr_build_package() { [[ -n "$branch" ]] || branch='detached' + # shellcheck disable=SC2016 CC_D5SR_MANIFEST_PLUGIN="$plugin_slug" \ - CC_D5SR_MANIFEST_VERSION="$version" \ - CC_D5SR_MANIFEST_COMMIT="$commit" \ - CC_D5SR_MANIFEST_BRANCH="$branch" \ - CC_D5SR_MANIFEST_BUILT_AT="$built_at" \ + CC_D5SR_MANIFEST_VERSION="$version" \ + CC_D5SR_MANIFEST_COMMIT="$commit" \ + CC_D5SR_MANIFEST_BRANCH="$branch" \ + CC_D5SR_MANIFEST_BUILT_AT="$built_at" \ php -r ' $manifest = array( "plugin" => getenv("CC_D5SR_MANIFEST_PLUGIN"), @@ -262,9 +263,9 @@ cc_d5sr_build_package() { ); file_put_contents($argv[1], json_encode($manifest, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL); ' "$stage_dir/build-manifest.json" || { - rm -rf "$stage_parent" - return 1 - } + rm -rf "$stage_parent" + return 1 + } archive="$dist_dir/${plugin_slug}-${version}-${commit:0:12}.tar.gz" tar -C "$stage_parent" -czf "$archive" "$plugin_slug" || { @@ -277,7 +278,7 @@ cc_d5sr_build_package() { return 1 } - printf '%s %s\n' "$archive_sha" "$(basename "$archive")" > "$archive.sha256" || { + printf '%s %s\n' "$archive_sha" "$(basename "$archive")" >"$archive.sha256" || { rm -rf "$stage_parent" return 1 } @@ -286,8 +287,8 @@ cc_d5sr_build_package() { CC_D5SR_PACKAGE_PATH="$archive" CC_D5SR_PACKAGE_SHA256="$archive_sha" - CC_D5SR_PACKAGE_VERSION="$version" - CC_D5SR_PACKAGE_COMMIT="$commit" + export CC_D5SR_PACKAGE_VERSION="$version" + export CC_D5SR_PACKAGE_COMMIT="$commit" cc_d5sr_ok "pacchetto creato: $archive" cc_d5sr_ok "SHA-256: $archive_sha" @@ -646,24 +647,24 @@ cc_d5sr_main() { while (($#)); do case "$1" in - --dry-run) - action='dry-run' - ;; - --package-only) - action='package-only' - ;; - --apply) - action='apply' - ;; - -h|--help) - cc_d5sr_usage - return 0 - ;; - *) - cc_d5sr_error "argomento non riconosciuto: $1" - cc_d5sr_usage >&2 - return 1 - ;; + --dry-run) + action='dry-run' + ;; + --package-only) + action='package-only' + ;; + --apply) + action='apply' + ;; + -h | --help) + cc_d5sr_usage + return 0 + ;; + *) + cc_d5sr_error "argomento non riconosciuto: $1" + cc_d5sr_usage >&2 + return 1 + ;; esac shift done @@ -722,40 +723,44 @@ cc_d5sr_main() { cc_d5sr_build_package "$repo_root" "$dist_dir" "$plugin_slug" || return 1 case "$action" in - package-only) - printf '%s\n' "$CC_D5SR_PACKAGE_PATH" - return 0 - ;; - dry-run) - cc_d5sr_info 'Dry-run completato: nessun collegamento SSH e nessuna modifica remota' - printf 'Pacchetto: %s\n' "$CC_D5SR_PACKAGE_PATH" - printf 'SHA-256: %s\n' "$CC_D5SR_PACKAGE_SHA256" - printf 'Target: %s\n' "${deploy_target:-}" - printf 'Modalità: %s\n' "$deploy_mode" - printf 'Container:%s\n' " ${deploy_container:-}" - printf 'WP root: %s\n' "$remote_wp_root" - return 0 - ;; - apply) - [[ -n "$deploy_target" ]] || { - cc_d5sr_error 'CC_D5SR_DEPLOY_TARGET è obbligatorio per --apply' - return 1 - } + package-only) + printf '%s\n' "$CC_D5SR_PACKAGE_PATH" + return 0 + ;; + dry-run) + cc_d5sr_info 'Dry-run completato: nessun collegamento SSH e nessuna modifica remota' + printf 'Pacchetto: %s\n' "$CC_D5SR_PACKAGE_PATH" + printf 'SHA-256: %s\n' "$CC_D5SR_PACKAGE_SHA256" + printf 'Target: %s\n' "${deploy_target:-}" + printf 'Modalità: %s\n' "$deploy_mode" + printf 'Container:%s\n' " ${deploy_container:-}" + printf 'WP root: %s\n' "$remote_wp_root" + return 0 + ;; + apply) + [[ -n "$deploy_target" ]] || { + cc_d5sr_error 'CC_D5SR_DEPLOY_TARGET è obbligatorio per --apply' + return 1 + } - cc_d5sr_deploy_remote \ - "$deploy_target" \ - "$ssh_port" \ - "$deploy_mode" \ - "$deploy_container" \ - "$remote_wp_root" \ - "$remote_state" \ - "$plugin_slug" \ - "$activate" \ - "$backup_keep" || return 1 - - cc_d5sr_ok "deploy completato su $deploy_target" - ;; + cc_d5sr_deploy_remote \ + "$deploy_target" \ + "$ssh_port" \ + "$deploy_mode" \ + "$deploy_container" \ + "$remote_wp_root" \ + "$remote_state" \ + "$plugin_slug" \ + "$activate" \ + "$backup_keep" || return 1 + + cc_d5sr_ok "deploy completato su $deploy_target" + ;; esac } cc_d5sr_main "$@" + +unset \ + CC_D5SR_PACKAGE_COMMIT \ + CC_D5SR_PACKAGE_VERSION From 35d368b67bd1e3df1cee1e9a974ddfb2a5df37b6 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:27:26 +0200 Subject: [PATCH 41/78] fix: require key SSH and remote Docker access --- bin/cc-deploy-barbagia-vm | 62 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/bin/cc-deploy-barbagia-vm b/bin/cc-deploy-barbagia-vm index f308f86..06f64e9 100644 --- a/bin/cc-deploy-barbagia-vm +++ b/bin/cc-deploy-barbagia-vm @@ -8,10 +8,15 @@ Uso: bin/cc-deploy-barbagia-vm --apply Default Barbagia Musei: - SSH target: docker02 - Compose file: /home/fgirolami/docker/barbagiamusei/compose.yaml + SSH target: docker02 + Compose file: /home/fgirolami/docker/barbagiamusei/compose.yaml Compose service: wp_cron - WordPress root: /var/www/html + WordPress root: /var/www/html + +Prerequisiti remoti per --apply: + - autenticazione SSH a chiave, senza fallback password; + - utente SSH autorizzato ad accedere al socket Docker; + - Docker Compose v2 disponibile sulla VM. Variabili opzionali: CC_D5SR_DEPLOY_TARGET @@ -45,6 +50,26 @@ cc_d5sr_barbagia_validate_value() { fi } +cc_d5sr_barbagia_check_ssh_key() { + local target="$1" + local ssh_port="$2" + + ssh \ + -o BatchMode=yes \ + -o ConnectTimeout=10 \ + -p "$ssh_port" \ + "$target" \ + true >/dev/null 2>&1 || { + cc_d5sr_barbagia_error \ + "autenticazione SSH a chiave non disponibile per $target; il deploy non usa password interattive" + printf '%s\n' \ + 'Verifica locale:' \ + " ssh-add --apple-use-keychain ~/.ssh/id_ed25519" \ + " ssh -o BatchMode=yes $target true" >&2 + return 1 + } +} + cc_d5sr_barbagia_resolve_container() { local target="$1" local ssh_port="$2" @@ -54,7 +79,12 @@ cc_d5sr_barbagia_resolve_container() { local result result="$( - ssh -p "$ssh_port" "$target" bash -s -- \ + ssh \ + -o BatchMode=yes \ + -o ConnectTimeout=10 \ + -p "$ssh_port" \ + "$target" \ + bash -s -- \ "$compose_file" \ "$compose_service" \ "$wp_root" <<'REMOTE_RESOLVE' @@ -68,6 +98,27 @@ resolve_container_main() { return 1 } + docker info >/dev/null 2>&1 || { + printf 'ERRORE: utente remoto %s senza accesso al Docker API.\n' "$(id -un)" >&2 + printf 'Gruppi: %s\n' "$(id -Gn)" >&2 + + if [[ -S /var/run/docker.sock ]]; then + if command -v stat >/dev/null 2>&1; then + stat -c 'Socket: %U:%G %a %n' /var/run/docker.sock >&2 2>/dev/null || true + else + ls -l /var/run/docker.sock >&2 + fi + fi + + printf 'Aggiungere una volta l utente al gruppo docker e riaprire la sessione SSH.\n' >&2 + return 1 + } + + docker compose version >/dev/null 2>&1 || { + printf 'ERRORE: Docker Compose v2 non disponibile sulla VM.\n' >&2 + return 1 + } + [[ -f "$compose_file" ]] || { printf 'ERRORE: Compose file non trovato: %s\n' "$compose_file" >&2 return 1 @@ -188,6 +239,9 @@ cc_d5sr_barbagia_main() { cc_d5sr_barbagia_info "WordPress root: $wp_root" if [[ "$action" == '--apply' ]]; then + cc_d5sr_barbagia_info 'preflight autenticazione SSH a chiave' + cc_d5sr_barbagia_check_ssh_key "$target" "$ssh_port" || return 1 + cc_d5sr_barbagia_info 'risoluzione container dal Compose remoto' cc_d5sr_barbagia_resolve_container \ "$target" \ From b2e7e1b7e3b4c1d8497939032f8d73faa49d8b97 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:28:34 +0200 Subject: [PATCH 42/78] docs: record SSH and Docker deploy preflight --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c804f24..eea13bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - Barbagia-specific Composer commands `deploy:barbagia:check` and `deploy:barbagia`. - Dedicated Barbagia wrapper pinned to `/home/fgirolami/docker/barbagiamusei/compose.yaml` and the `wp_cron` Compose service. - Dynamic resolution and validation of the real `wp_cron` container before remote deployment. +- Barbagia deployment preflight requiring SSH public-key authentication and direct remote Docker API access. ### Changed @@ -35,4 +36,5 @@ - Deployment documentation now defines reproducible packaging, dry-run behavior, remote requirements, backup location and rollback guarantees. - Generic Docker deployment documentation now distinguishes Docker container names or IDs from Compose service names. - Barbagia deployment no longer depends on the current SSH directory or a hardcoded container name. +- Barbagia deployment now refuses password fallback and reports the remote Docker socket user, groups and permissions before any package upload. - Documentation now records that runtime packaging passed a disposable mock-repository test while the first real VM deployment remains an integration gate. From b1d962b81a648106615f2ae2cb6bc9cb10ebff73 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:29:51 +0200 Subject: [PATCH 43/78] docs: define non-interactive Barbagia deploy prerequisites --- README.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 65ef298..710b8b3 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ The `0.1.0` development branch currently includes: - deterministic runtime packaging with build manifest and SHA-256 checksum; - VM deployment workflow for host and Docker WordPress installations, including backup and automatic rollback; - a Barbagia Musei deployment wrapper pinned to the real `docker02` Compose stack and `wp_cron` service; +- non-interactive Barbagia preflight for SSH public-key authentication and remote Docker API access; - frontend CSS with responsive grid behavior. The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. @@ -282,7 +283,58 @@ The resolved container is currently named `cron_barbagiamusei`, but that name is - `tar`; - WP-CLI. -The remote Compose command uses the absolute `-f` path. It does not depend on the SSH login directory or on the repository path shown by the remote shell prompt. +The remote Compose command uses the absolute `-f` path. It does not depend on the SSH login directory or on the repository path shown by the remote shell prompt. Docker is executed on `docker02`; a stopped Docker Desktop installation on the local Mac has no effect on this workflow. + +The Barbagia apply command is intentionally non-interactive. Before packaging or upload it requires both of these checks to pass: + +```bash +ssh -o BatchMode=yes docker02 true +ssh -o BatchMode=yes docker02 docker info +``` + +The first check proves that the Mac can authenticate with the configured SSH key without falling back to the account password. The second proves that the remote `fgirolami` session can access `/var/run/docker.sock` without `sudo`. The deploy script never stores, pipes or retries SSH or sudo passwords. + +One-time SSH-key bootstrap, only when the first check fails: + +```bash +ssh-add --apple-use-keychain ~/.ssh/id_ed25519 + +cat ~/.ssh/id_ed25519.pub | ssh docker02 ' + umask 077 + mkdir -p ~/.ssh + touch ~/.ssh/authorized_keys + IFS= read -r key + grep -qxF "$key" ~/.ssh/authorized_keys || printf "%s\n" "$key" >> ~/.ssh/authorized_keys + chmod 700 ~/.ssh + chmod 600 ~/.ssh/authorized_keys +' + +ssh -o BatchMode=yes docker02 true +``` + +The `ssh` command used to install the public key may request the normal account password once. The final `BatchMode=yes` verification must not request any password. + +One-time Docker-access bootstrap, only when the second check fails: + +```bash +ssh -tt docker02 'sudo usermod -aG docker fgirolami' +``` + +After changing group membership, terminate the old SSH session and open a new one. If SSH connection multiplexing is configured globally, close the existing master connection before verification: + +```bash +ssh -O exit docker02 2>/dev/null || true + +ssh -o BatchMode=yes docker02 ' + id + docker info >/dev/null + docker compose \ + -f /home/fgirolami/docker/barbagiamusei/compose.yaml \ + ps -q wp_cron +' +``` + +Membership in the `docker` group grants root-equivalent control of the Docker host. This stack already requires Docker administration for deployment, so the requirement is explicit rather than hidden behind an interactive sudo prompt. Optional Barbagia overrides are available only when the stack changes intentionally: From 3743cfe8dd565019a95d240cfda5a4b4b9f83433 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:51:28 +0200 Subject: [PATCH 44/78] feat: populate builder post type options --- src/builder-data.ts | 96 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/builder-data.ts diff --git a/src/builder-data.ts b/src/builder-data.ts new file mode 100644 index 0000000..a7f5d00 --- /dev/null +++ b/src/builder-data.ts @@ -0,0 +1,96 @@ +export interface PostTypeOption { + label: string; +} + +export type PostTypeOptions = Record; + +interface BuilderData { + postTypes?: PostTypeOptions; +} + +declare global { + interface Window { + ccD5srBuilderData?: BuilderData; + } +} + +interface MutableFieldComponent { + name?: string; + props?: { + options?: PostTypeOptions; + [key: string]: unknown; + }; +} + +interface MutableModuleMetadata { + title?: string; + titles?: string; + childModuleTitle?: string; + attributes?: { + rule?: { + settings?: { + innerContent?: { + items?: { + postType?: { + component?: MutableFieldComponent; + }; + }; + }; + }; + }; + }; +} + +const fallbackPostTypes: PostTypeOptions = { + post: { + label: 'Posts (post)', + }, + page: { + label: 'Pages (page)', + }, +}; + +export const getPostTypeOptions = (): PostTypeOptions => { + const options = window.ccD5srBuilderData?.postTypes; + + if (! options || Object.keys(options).length === 0) { + return fallbackPostTypes; + } + + return options; +}; + +export const getPostTypeLabel = (postType: string): string => { + return getPostTypeOptions()[postType]?.label || postType; +}; + +export const prepareSearchResultTypeMetadata = (metadata: T): T => { + const mutableMetadata = metadata as T & MutableModuleMetadata; + const postTypeField = mutableMetadata.attributes?.rule?.settings?.innerContent?.items?.postType; + + mutableMetadata.title = 'CC Result Type'; + mutableMetadata.titles = 'CC Result Types'; + + if (postTypeField) { + postTypeField.component = { + ...postTypeField.component, + name: 'divi/select', + props: { + ...postTypeField.component?.props, + options: getPostTypeOptions(), + }, + }; + } + + return metadata; +}; + +export const prepareSearchResultsMetadata = (metadata: T): T => { + const mutableMetadata = metadata as T & MutableModuleMetadata; + + mutableMetadata.title = 'CC Search Results'; + mutableMetadata.titles = 'CC Search Results'; + mutableMetadata.childModuleTitle = 'CC Result Type'; + + return metadata; +}; From 9852f5488aba29f67666a78d604a914a1d3adba9 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:51:58 +0200 Subject: [PATCH 45/78] feat: expose public post types to Divi builder --- includes/Plugin.php | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/includes/Plugin.php b/includes/Plugin.php index 430eb7d..78ef12e 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -66,6 +66,26 @@ public static function registerVisualBuilderAssets(): void { return; } + $builder_data_handle = 'cc-divi5-search-results-vb-data'; + + wp_register_script( + $builder_data_handle, + false, + array(), + CC_D5SR_VERSION, + true + ); + + wp_add_inline_script( + $builder_data_handle, + 'window.ccD5srBuilderData = ' . wp_json_encode( + array( + 'postTypes' => self::getBuilderPostTypeOptions(), + ) + ) . ';', + 'before' + ); + \ET\Builder\VisualBuilder\Assets\PackageBuildManager::register_package_build( array( 'name' => 'cc-divi5-search-results-vb', @@ -73,6 +93,7 @@ public static function registerVisualBuilderAssets(): void { 'script' => array( 'src' => CC_D5SR_URL . 'scripts/bundle.js', 'deps' => array( + $builder_data_handle, 'divi-module-library', 'divi-vendor-wp-hooks', ), @@ -99,4 +120,61 @@ public static function registerVisualBuilderAssets(): void { ); } } + + /** + * Return public WordPress post types as Divi select options. + * + * @return array + */ + private static function getBuilderPostTypeOptions(): array { + $post_type_objects = get_post_types( + array( + 'public' => true, + ), + 'objects' + ); + + unset( $post_type_objects['attachment'] ); + + $options = array(); + + foreach ( $post_type_objects as $post_type_slug => $post_type_object ) { + if ( ! $post_type_object instanceof \WP_Post_Type ) { + continue; + } + + $label = $post_type_object->labels->name ?: $post_type_object->label; + $label = $label ?: $post_type_slug; + + $options[ $post_type_slug ] = array( + 'label' => sprintf( + /* translators: 1: post type label, 2: post type slug. */ + __( '%1$s (%2$s)', 'cc-divi5-search-results' ), + $label, + $post_type_slug + ), + ); + } + + uasort( + $options, + static function ( array $left, array $right ): int { + return strnatcasecmp( $left['label'], $right['label'] ); + } + ); + + /** + * Filter post types exposed by the CC Result Type selector. + * + * @param array $options Divi select options keyed by post type slug. + * @param array $post_type_objects Public post type objects, excluding attachments. + */ + $options = apply_filters( + 'cc_d5sr_builder_post_type_options', + $options, + $post_type_objects + ); + + return is_array( $options ) ? $options : array(); + } } From 8889e5efcb018c1bc42a12226a26e047135841e5 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:52:10 +0200 Subject: [PATCH 46/78] feat: brand modules and inject post type options --- src/index.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 0368436..dbd2674 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,19 @@ -import { addAction } from '@wordpress/hooks'; import { registerModule } from '@divi/module-library'; +import { addAction } from '@wordpress/hooks'; +import { + prepareSearchResultTypeMetadata, + prepareSearchResultsMetadata, +} from './builder-data'; import { searchResultTypeModule } from './components/search-result-type'; import { searchResultsModule } from './components/search-results'; addAction('divi.moduleLibrary.registerModuleLibraryStore.after', 'codecorn/search-results', () => { - const { metadata: resultTypeMetadata, ...resultTypeDefinition } = searchResultTypeModule; - const { metadata: searchResultsMetadata, ...searchResultsDefinition } = searchResultsModule; + const { metadata: rawResultTypeMetadata, ...resultTypeDefinition } = searchResultTypeModule; + const { metadata: rawSearchResultsMetadata, ...searchResultsDefinition } = searchResultsModule; + + const resultTypeMetadata = prepareSearchResultTypeMetadata(rawResultTypeMetadata); + const searchResultsMetadata = prepareSearchResultsMetadata(rawSearchResultsMetadata); registerModule(resultTypeMetadata, resultTypeDefinition); registerModule(searchResultsMetadata, searchResultsDefinition); From 47b2c565541236d48695896d0314cd003306ba5b Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:52:23 +0200 Subject: [PATCH 47/78] ui: brand parent module preview --- src/components/search-results/edit.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/search-results/edit.tsx b/src/components/search-results/edit.tsx index c77451a..437e46a 100644 --- a/src/components/search-results/edit.tsx +++ b/src/components/search-results/edit.tsx @@ -32,13 +32,13 @@ export const SearchResultsEdit = (props: SearchResultsEditProps): ReactElement = > {elements.styleComponents({ attrName: 'module' })}
- Search Results + CC Search Results {query?.source === 'isolated' ? `Isolated query: ${query.searchTerm || 'no search term'}` : 'Current WordPress search query'} - Result Type Rule children configure the frontend cards. + CC Result Type children configure the frontend cards.
From 0439e9394f0405d72cc3ad971c6411c6ebbdff57 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:52:32 +0200 Subject: [PATCH 48/78] ui: show branded post type rule labels --- src/components/search-result-type/edit.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/search-result-type/edit.tsx b/src/components/search-result-type/edit.tsx index 6689d6f..653cd28 100644 --- a/src/components/search-result-type/edit.tsx +++ b/src/components/search-result-type/edit.tsx @@ -1,17 +1,19 @@ import React, { ReactElement } from 'react'; import { ModuleContainer } from '@divi/module'; +import { getPostTypeLabel } from '../../builder-data'; import { SearchResultTypeEditProps } from './types'; export const SearchResultTypeEdit = (props: SearchResultTypeEditProps): ReactElement => { const { attrs, elements, id, name } = props; const rule = attrs.rule?.innerContent?.desktop?.value; const postType = rule?.postType || 'post'; + const postTypeLabel = getPostTypeLabel(postType); return (
- {rule?.badgeLabel || postType} + CC Result Type — {postTypeLabel} {postType}
From 43a3e59a85d2cbe8e83b9911d733956aede9f44a Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:53:20 +0200 Subject: [PATCH 49/78] ui: label dynamic post type selector --- src/builder-data.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/builder-data.ts b/src/builder-data.ts index a7f5d00..17f712c 100644 --- a/src/builder-data.ts +++ b/src/builder-data.ts @@ -22,6 +22,12 @@ interface MutableFieldComponent { }; } +interface MutableFieldMetadata { + label?: string; + description?: string; + component?: MutableFieldComponent; +} + interface MutableModuleMetadata { title?: string; titles?: string; @@ -31,9 +37,7 @@ interface MutableModuleMetadata { settings?: { innerContent?: { items?: { - postType?: { - component?: MutableFieldComponent; - }; + postType?: MutableFieldMetadata; }; }; }; @@ -72,6 +76,8 @@ export const prepareSearchResultTypeMetadata = (metadata: T): T => { mutableMetadata.titles = 'CC Result Types'; if (postTypeField) { + postTypeField.label = 'Post type'; + postTypeField.description = 'Choose one of the public post types registered by WordPress.'; postTypeField.component = { ...postTypeField.component, name: 'divi/select', From 6f29359ff506c100b4cdf7394c6326a15ccf3adb Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:53:49 +0200 Subject: [PATCH 50/78] docs: record dynamic post type selector --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eea13bf..6782aab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,8 @@ - Dedicated Barbagia wrapper pinned to `/home/fgirolami/docker/barbagiamusei/compose.yaml` and the `wp_cron` Compose service. - Dynamic resolution and validation of the real `wp_cron` container before remote deployment. - Barbagia deployment preflight requiring SSH public-key authentication and direct remote Docker API access. +- Dynamic Visual Builder post-type selector populated from public WordPress post types, with labels and slugs. +- `cc_d5sr_builder_post_type_options` filter for adjusting the post types exposed by the builder selector. ### Changed @@ -38,3 +40,5 @@ - Barbagia deployment no longer depends on the current SSH directory or a hardcoded container name. - Barbagia deployment now refuses password fallback and reports the remote Docker socket user, groups and permissions before any package upload. - Documentation now records that runtime packaging passed a disposable mock-repository test while the first real VM deployment remains an integration gate. +- Visual Builder display names are now `CC Search Results` and `CC Result Type` while the saved technical module slugs remain unchanged. +- The result-type post-type control is now a select instead of a free-text slug field. From 018423e17918b280f8dbbd4c60a6b05cc17160c8 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:54:40 +0200 Subject: [PATCH 51/78] fix: read builder data across Divi windows --- src/builder-data.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/builder-data.ts b/src/builder-data.ts index 17f712c..b54e9ba 100644 --- a/src/builder-data.ts +++ b/src/builder-data.ts @@ -54,8 +54,20 @@ const fallbackPostTypes: PostTypeOptions = { }, }; +const getBuilderData = (): BuilderData | undefined => { + if (window.ccD5srBuilderData) { + return window.ccD5srBuilderData; + } + + try { + return window.top?.ccD5srBuilderData; + } catch { + return undefined; + } +}; + export const getPostTypeOptions = (): PostTypeOptions => { - const options = window.ccD5srBuilderData?.postTypes; + const options = getBuilderData()?.postTypes; if (! options || Object.keys(options).length === 0) { return fallbackPostTypes; From a4771d138cfd981dafb038ef6c5798144e720b9c Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 01:56:00 +0200 Subject: [PATCH 52/78] docs: document branded dynamic post type selector --- README.md | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 710b8b3..3756884 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,10 @@ The `0.1.0` development branch currently includes: - isolated search-query resolution that never calls `query_posts()` and never replaces the global `$wp_query`; - reuse of the real current WordPress search query when the module runs on a search-results request; - an isolated `WP_Query` fallback for Visual Builder previews, non-search pages and shortcode use; -- the native Divi 5 parent module `codecorn/search-results`; -- the native configuration child module `codecorn/search-result-type`; +- the native Divi 5 parent module `codecorn/search-results`, displayed in the Builder as `CC Search Results`; +- the native configuration child module `codecorn/search-result-type`, displayed as `CC Result Type`; - repeatable post-type rules for labels, badge, accent, image, excerpt, date and CTA; +- a dynamic result-type selector populated from the public post types registered by WordPress; - accessible result count, search form, result cards, pagination and empty state; - shared rendering used by both the native module and `[cc_divi5_search_results]`; - Visual Builder TypeScript sources, Divi-compatible compiler configuration and webpack build; @@ -30,14 +31,14 @@ The Visual Builder bundle and `modules-json/` metadata are generated locally and ## Native module structure ```text -codecorn/search-results -└── codecorn/search-result-type +CC Search Results (codecorn/search-results) +└── CC Result Type (codecorn/search-result-type) ├── post ├── page - └── any registered custom post type + └── any registered public custom post type ``` -`Result Type Rule` children are configuration objects. They do not render independent frontend cards. The parent reads their saved Divi block attributes and applies them to posts returned by the search query. +`CC Result Type` children are configuration objects. They do not render independent frontend cards. The parent reads their saved Divi block attributes and applies them to posts returned by the search query. ## Available parent controls @@ -60,7 +61,7 @@ codecorn/search-results ## Available result-type controls -- post type slug; +- public WordPress post type selected from the list registered by the current site; - singular, plural and badge labels; - rule priority; - accent color; @@ -68,6 +69,21 @@ codecorn/search-results - excerpt word count; - CTA label. +The post-type selector is populated when the Visual Builder assets are registered. It lists the translated WordPress label followed by the technical slug, for example `Articoli (post)`, `Pagine (page)` or `Eventi (eventi)`. Attachments are excluded. If Builder data is unavailable, the control falls back to `post` and `page` instead of becoming a free-text field. + +Integrations can adjust the available options without changing module code: + +```php +add_filter( + 'cc_d5sr_builder_post_type_options', + function ( array $options, array $post_type_objects ): array { + return $options; + }, + 10, + 2 +); +``` + Missing labels fall back to the registered WordPress post-type labels. Missing rules fall back to a generic rule derived from the result's post type. ## Query contract @@ -381,7 +397,6 @@ The default remote state path is relative to the SSH user's home directory. It c The README deliberately does not present the following as available: - live query results inside the Visual Builder canvas; -- dynamic post-type selector options populated from WordPress REST data; - per-type custom-field and taxonomy mappings; - type filters with counts; - query-term highlighting; From 6625bade10b95ab9ccf548adc50deda392723d27 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:29:58 +0200 Subject: [PATCH 53/78] feat: read responsive Divi field values --- includes/Support/AttributeValue.php | 59 ++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/includes/Support/AttributeValue.php b/includes/Support/AttributeValue.php index a08af5c..58ba438 100644 --- a/includes/Support/AttributeValue.php +++ b/includes/Support/AttributeValue.php @@ -4,7 +4,7 @@ final class AttributeValue { /** - * Read a Divi responsive attribute value from a nested module attribute array. + * Read a value from a nested module attribute array. * * @param array $attrs * @param list $path @@ -30,10 +30,10 @@ public static function get( array $attrs, array $path, $default = null ) { * @param array $attrs * @param list $path */ - public static function desktop( array $attrs, array $path, string $default = '' ): string { + public static function breakpoint( array $attrs, array $path, string $breakpoint, string $default = '' ): string { $value = self::get( $attrs, - array_merge( $path, array( 'desktop', 'value' ) ), + array_merge( $path, array( $breakpoint, 'value' ) ), $default ); @@ -44,21 +44,70 @@ public static function desktop( array $attrs, array $path, string $default = '' * @param array $attrs * @param list $path */ - public static function desktopField( + public static function desktop( array $attrs, array $path, string $default = '' ): string { + return self::breakpoint( $attrs, $path, 'desktop', $default ); + } + + /** + * @param array $attrs + * @param list $path + */ + public static function breakpointField( array $attrs, array $path, + string $breakpoint, string $field, string $default = '' ): string { $value = self::get( $attrs, - array_merge( $path, array( 'desktop', 'value', $field ) ), + array_merge( $path, array( $breakpoint, 'value', $field ) ), $default ); return is_scalar( $value ) ? (string) $value : $default; } + /** + * @param array $attrs + * @param list $path + */ + public static function desktopField( + array $attrs, + array $path, + string $field, + string $default = '' + ): string { + return self::breakpointField( $attrs, $path, 'desktop', $field, $default ); + } + + /** + * Read one responsive field with desktop -> tablet -> phone fallback. + * + * @param array $attrs + * @param list $path + * + * @return array{desktop:string,tablet:string,phone:string} + */ + public static function responsiveField( + array $attrs, + array $path, + string $field, + string $desktop_default = '', + string $tablet_default = '', + string $phone_default = '' + ): array { + $desktop = self::breakpointField( $attrs, $path, 'desktop', $field, $desktop_default ); + $tablet = self::breakpointField( $attrs, $path, 'tablet', $field, $tablet_default ?: $desktop ); + $phone = self::breakpointField( $attrs, $path, 'phone', $field, $phone_default ?: $tablet ); + + return array( + 'desktop' => $desktop, + 'tablet' => $tablet, + 'phone' => $phone, + ); + } + public static function isOn( string $value ): bool { return 'on' === $value || '1' === $value || 'true' === strtolower( $value ); } From 2145868e7e14af21e41c7d89a987e2b71632e633 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:30:52 +0200 Subject: [PATCH 54/78] feat: add presets and localized search UI --- includes/Rendering/SearchResultsRenderer.php | 89 +++++++++++++++----- 1 file changed, 68 insertions(+), 21 deletions(-) diff --git a/includes/Rendering/SearchResultsRenderer.php b/includes/Rendering/SearchResultsRenderer.php index af45f17..e3d52aa 100644 --- a/includes/Rendering/SearchResultsRenderer.php +++ b/includes/Rendering/SearchResultsRenderer.php @@ -12,16 +12,22 @@ final class SearchResultsRenderer { public function render( QueryResult $result, RuleCollection $rules, array $options = array() ): string { $show_summary = $this->flag( $options['show_summary'] ?? true ); $show_search_form = $this->flag( $options['show_search_form'] ?? true ); - $columns = max( 1, min( 6, (int) ( $options['columns'] ?? 3 ) ) ); + $ajax_pagination = $this->flag( $options['ajax_pagination'] ?? true ); + $preset = $this->preset( (string) ( $options['preset'] ?? 'grid' ) ); + $columns = $this->columns( $options['columns'] ?? array() ); + $instance_id = sanitize_html_class( (string) ( $options['instance_id'] ?? '' ) ); $summary = $show_summary ? $this->summary( $result ) : ''; $form = $show_search_form ? $this->searchForm( $result->searchTerm ) : ''; $body = $result->posts - ? $this->resultsGrid( $result, $rules, $columns ) + ? $this->results( $result, $rules, $preset, $columns ) : $this->emptyState( $result, $options ); return sprintf( - '
%s%s%s
', + '
%4$s%5$s%6$s
', + esc_attr( $preset ), + esc_attr( $instance_id ), + $ajax_pagination && '' !== $instance_id ? 'on' : 'off', $summary, $form, $body @@ -29,14 +35,18 @@ public function render( QueryResult $result, RuleCollection $rules, array $optio } private function summary( QueryResult $result ): string { + $count = sprintf( + _n( '%d risultato', '%d risultati', $result->foundPosts, 'cc-divi5-search-results' ), + $result->foundPosts + ); $term = '' !== $result->searchTerm - ? esc_html( sprintf( __( ' for “%s”', 'cc-divi5-search-results' ), $result->searchTerm ) ) + ? sprintf( __( ' per “%s”', 'cc-divi5-search-results' ), $result->searchTerm ) : ''; return sprintf( - '
%s%s
', - esc_html( sprintf( _n( '%d result', '%d results', $result->foundPosts, 'cc-divi5-search-results' ), $result->foundPosts ) ), - $term + '
%1$s%2$s
', + esc_html( $count ), + esc_html( $term ) ); } @@ -44,17 +54,20 @@ private function searchForm( string $search_term ): string { $input_id = wp_unique_id( 'cc-d5sr-search-' ); return sprintf( - '', + '', esc_url( home_url( '/' ) ), esc_attr( $input_id ), - esc_html__( 'Search for:', 'cc-divi5-search-results' ), + esc_html__( 'Cerca nel sito:', 'cc-divi5-search-results' ), esc_attr( $search_term ), - esc_attr__( 'Search the site', 'cc-divi5-search-results' ), - esc_html__( 'Search', 'cc-divi5-search-results' ) + esc_attr__( 'Cerca nel sito', 'cc-divi5-search-results' ), + esc_html__( 'Cerca', 'cc-divi5-search-results' ) ); } - private function resultsGrid( QueryResult $result, RuleCollection $rules, int $columns ): string { + /** + * @param array{desktop:int,tablet:int,phone:int} $columns + */ + private function results( QueryResult $result, RuleCollection $rules, string $preset, array $columns ): string { $cards = ''; foreach ( $result->posts as $post ) { @@ -62,8 +75,11 @@ private function resultsGrid( QueryResult $result, RuleCollection $rules, int $c } return sprintf( - '
%s
%s', - $columns, + '
%5$s
%6$s', + $columns['desktop'], + $columns['tablet'], + $columns['phone'], + esc_attr( $preset ), $cards, $this->pagination( $result ) ); @@ -99,8 +115,14 @@ private function card( WP_Post $post, ResultTypeRule $rule ): string { $excerpt = '' !== $excerpt_text ? sprintf( '

%s

', esc_html( $excerpt_text ) ) : ''; } + $card_classes = array( 'cc-d5sr__card' ); + if ( '' === $image ) { + $card_classes[] = 'cc-d5sr__card--no-image'; + } + return sprintf( - '', + '', + esc_attr( implode( ' ', $card_classes ) ), esc_attr( $rule->postType ), esc_attr( $rule->accentColor ), $image, @@ -117,11 +139,11 @@ private function card( WP_Post $post, ResultTypeRule $rule ): string { * @param array $options */ private function emptyState( QueryResult $result, array $options ): string { - $title = sanitize_text_field( (string) ( $options['empty_title'] ?? __( 'No results found', 'cc-divi5-search-results' ) ) ); - $body = sanitize_text_field( (string) ( $options['empty_body'] ?? __( 'Try a different search term or browse another section of the site.', 'cc-divi5-search-results' ) ) ); + $title = sanitize_text_field( (string) ( $options['empty_title'] ?? __( 'Nessun risultato trovato', 'cc-divi5-search-results' ) ) ); + $body = sanitize_text_field( (string) ( $options['empty_body'] ?? __( 'Prova con un termine diverso oppure visita un’altra sezione del sito.', 'cc-divi5-search-results' ) ) ); return sprintf( - '

%1$s

%2$s

%3$s
', + '

%1$s

%2$s

%3$s
', esc_html( $title ), esc_html( $body ), '' !== $result->searchTerm @@ -139,8 +161,8 @@ private function pagination( QueryResult $result ): string { array( 'current' => $result->currentPage, 'mid_size' => 2, - 'prev_text' => __( 'Previous', 'cc-divi5-search-results' ), - 'next_text' => __( 'Next', 'cc-divi5-search-results' ), + 'prev_text' => __( 'Precedente', 'cc-divi5-search-results' ), + 'next_text' => __( 'Successiva', 'cc-divi5-search-results' ), 'total' => $result->maxPages, 'type' => 'list', ) @@ -152,11 +174,14 @@ private function pagination( QueryResult $result ): string { return sprintf( '', - esc_attr__( 'Search results pages', 'cc-divi5-search-results' ), + esc_attr__( 'Pagine dei risultati di ricerca', 'cc-divi5-search-results' ), wp_kses_post( $links ) ); } + /** + * @param mixed $value + */ private function flag( $value ): bool { if ( is_bool( $value ) ) { return $value; @@ -164,4 +189,26 @@ private function flag( $value ): bool { return in_array( strtolower( (string) $value ), array( '1', 'on', 'true', 'yes' ), true ); } + + private function preset( string $preset ): string { + $preset = sanitize_key( $preset ); + + return in_array( $preset, array( 'grid', 'compact-list', 'classic-card' ), true ) + ? $preset + : 'grid'; + } + + /** + * @param mixed $columns + * + * @return array{desktop:int,tablet:int,phone:int} + */ + private function columns( $columns ): array { + $columns = is_array( $columns ) ? $columns : array( 'desktop' => $columns ); + $desktop = max( 1, min( 6, (int) ( $columns['desktop'] ?? 3 ) ) ); + $tablet = max( 1, min( 4, (int) ( $columns['tablet'] ?? min( 2, $desktop ) ) ) ); + $phone = max( 1, min( 2, (int) ( $columns['phone'] ?? 1 ) ) ); + + return compact( 'desktop', 'tablet', 'phone' ); + } } From 75c7a8cc84f6bed3a873ae3dfc3bbbcac4f5dab2 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:31:35 +0200 Subject: [PATCH 55/78] feat: expose responsive layout and AJAX options --- modules/SearchResults/SearchResultsModule.php | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/modules/SearchResults/SearchResultsModule.php b/modules/SearchResults/SearchResultsModule.php index bdfe7c6..cf96545 100644 --- a/modules/SearchResults/SearchResultsModule.php +++ b/modules/SearchResults/SearchResultsModule.php @@ -60,7 +60,9 @@ public static function renderCallback( 'source' => $options['source'], ) ); - $content = ( new SearchResultsRenderer() )->render( $result, $rules, $options ); + + $options['instance_id'] = (string) ( $block->parsed_block['id'] ?? '' ); + $content = ( new SearchResultsRenderer() )->render( $result, $rules, $options ); return Module::render( array( @@ -136,11 +138,22 @@ public static function moduleStyles( array $args ): void { * @return array */ private static function optionsFromAttrs( array $attrs ): array { + $columns = AttributeValue::responsiveField( + $attrs, + array( 'display', 'innerContent' ), + 'columns', + '3', + '2', + '1' + ); + return array( - 'columns' => (int) AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'columns', '3' ), - 'empty_body' => AttributeValue::desktopField( $attrs, array( 'emptyState', 'innerContent' ), 'body', __( 'Try a different search term or browse another section of the site.', 'cc-divi5-search-results' ) ), - 'empty_title' => AttributeValue::desktopField( $attrs, array( 'emptyState', 'innerContent' ), 'title', __( 'No results found', 'cc-divi5-search-results' ) ), + 'ajax_pagination' => AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'ajaxPagination', 'on' ), + 'columns' => array_map( 'intval', $columns ), + 'empty_body' => AttributeValue::desktopField( $attrs, array( 'emptyState', 'innerContent' ), 'body', __( 'Prova con un termine diverso oppure visita un’altra sezione del sito.', 'cc-divi5-search-results' ) ), + 'empty_title' => AttributeValue::desktopField( $attrs, array( 'emptyState', 'innerContent' ), 'title', __( 'Nessun risultato trovato', 'cc-divi5-search-results' ) ), 'posts_per_page' => (int) AttributeValue::desktopField( $attrs, array( 'query', 'innerContent' ), 'postsPerPage', '10' ), + 'preset' => AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'preset', 'grid' ), 'search_term' => AttributeValue::desktopField( $attrs, array( 'query', 'innerContent' ), 'searchTerm', '' ), 'show_search_form' => AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'showSearchForm', 'on' ), 'show_summary' => AttributeValue::desktopField( $attrs, array( 'display', 'innerContent' ), 'showSummary', 'on' ), From a4d40134b920a2f941339b085dcf2d83f399d6ab Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:32:00 +0200 Subject: [PATCH 56/78] fix: localize default result CTA --- includes/Rendering/ResultTypeRule.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/includes/Rendering/ResultTypeRule.php b/includes/Rendering/ResultTypeRule.php index 156861a..d0aab30 100644 --- a/includes/Rendering/ResultTypeRule.php +++ b/includes/Rendering/ResultTypeRule.php @@ -58,7 +58,7 @@ public static function fromFlatArray( array $values ): self { self::flag( $values['showExcerpt'] ?? $values['show_excerpt'] ?? 'on' ), self::flag( $values['showDate'] ?? $values['show_date'] ?? 'on' ), max( 0, min( 200, (int) ( $values['excerptLength'] ?? $values['excerpt_length'] ?? 28 ) ) ), - sanitize_text_field( (string) ( $values['ctaLabel'] ?? $values['cta_label'] ?? __( 'View result', 'cc-divi5-search-results' ) ) ) + sanitize_text_field( (string) ( $values['ctaLabel'] ?? $values['cta_label'] ?? __( 'Vedi risultato', 'cc-divi5-search-results' ) ) ) ); } @@ -66,6 +66,9 @@ public static function fallback( string $post_type ): self { return self::fromFlatArray( array( 'postType' => $post_type ) ); } + /** + * @param mixed $value + */ private static function flag( $value ): bool { if ( is_bool( $value ) ) { return $value; @@ -74,6 +77,9 @@ private static function flag( $value ): bool { return AttributeValue::isOn( (string) $value ); } + /** + * @param mixed $candidate + */ private static function label( $candidate, ?WP_Post_Type $object, bool $plural, string $fallback ): string { $candidate = sanitize_text_field( (string) $candidate ); From 5acc659bf9b1b237224352acf88afb77bd4f8127 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:32:27 +0200 Subject: [PATCH 57/78] feat: extend shortcode layout and pagination options --- shortcodes/SearchResultsShortcode.php | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/shortcodes/SearchResultsShortcode.php b/shortcodes/SearchResultsShortcode.php index 57f5085..682f4a3 100644 --- a/shortcodes/SearchResultsShortcode.php +++ b/shortcodes/SearchResultsShortcode.php @@ -8,6 +8,8 @@ use CodeCorn\Divi5SearchResults\Rendering\SearchResultsRenderer; final class SearchResultsShortcode { + private static int $instance = 0; + public static function register(): void { add_shortcode( 'cc_divi5_search_results', array( self::class, 'render' ) ); } @@ -18,11 +20,15 @@ public static function register(): void { public static function render( $attributes = array() ): string { $attributes = shortcode_atts( array( + 'ajax_pagination' => 'on', 'columns' => '3', - 'cta_label' => __( 'View result', 'cc-divi5-search-results' ), + 'columns_phone' => '1', + 'columns_tablet' => '2', + 'cta_label' => __( 'Vedi risultato', 'cc-divi5-search-results' ), 'excerpt_length' => '28', 'post_types' => '', 'posts_per_page' => '10', + 'preset' => 'grid', 'search' => '', 'show_date' => 'on', 'show_excerpt' => 'on', @@ -64,11 +70,20 @@ public static function render( $attributes = array() ): string { ) ); + ++self::$instance; + return ( new SearchResultsRenderer() )->render( $result, new RuleCollection( $rules ), array( - 'columns' => (int) $attributes['columns'], + 'ajax_pagination' => $attributes['ajax_pagination'], + 'columns' => array( + 'desktop' => (int) $attributes['columns'], + 'tablet' => (int) $attributes['columns_tablet'], + 'phone' => (int) $attributes['columns_phone'], + ), + 'instance_id' => 'shortcode-' . self::$instance, + 'preset' => $attributes['preset'], 'show_search_form' => $attributes['show_search_form'], 'show_summary' => $attributes['show_summary'], ) From 72be9e521eb9f9b6c77f00b711693569eb23b7b3 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:33:03 +0200 Subject: [PATCH 58/78] feat: enqueue frontend pagination runtime --- includes/Plugin.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/includes/Plugin.php b/includes/Plugin.php index 78ef12e..d089966 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -38,6 +38,14 @@ public static function enqueueFrontendAssets(): void { array(), CC_D5SR_VERSION ); + + wp_enqueue_script( + 'cc-divi5-search-results', + CC_D5SR_URL . 'assets/js/search-results.js', + array(), + CC_D5SR_VERSION, + true + ); } /** @@ -167,7 +175,7 @@ static function ( array $left, array $right ): int { * Filter post types exposed by the CC Result Type selector. * * @param array $options Divi select options keyed by post type slug. - * @param array $post_type_objects Public post type objects, excluding attachments. + * @param array $post_type_objects Public post type objects, excluding attachments. */ $options = apply_filters( 'cc_d5sr_builder_post_type_options', From 498d8147b5df8fa36de714e66aaff5018373b720 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:33:33 +0200 Subject: [PATCH 59/78] feat: add progressive AJAX pagination --- assets/js/search-results.js | 137 ++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 assets/js/search-results.js diff --git a/assets/js/search-results.js b/assets/js/search-results.js new file mode 100644 index 0000000..14596a9 --- /dev/null +++ b/assets/js/search-results.js @@ -0,0 +1,137 @@ +(() => { + 'use strict'; + + const controllers = new WeakMap(); + const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); + + const findModule = (scope, instanceId) => { + const modules = scope.querySelectorAll('.cc-d5sr__inner[data-cc-d5sr-instance]'); + + return Array.from(modules).find((module) => module.dataset.ccD5srInstance === instanceId) || null; + }; + + const focusResults = (module) => { + const results = module.querySelector('.cc-d5sr__results, .cc-d5sr__empty'); + + module.scrollIntoView({ + behavior: reducedMotion.matches ? 'auto' : 'smooth', + block: 'start', + }); + + if (results instanceof HTMLElement) { + results.focus({ preventScroll: true }); + } + }; + + const loadPage = async (module, url) => { + const instanceId = module.dataset.ccD5srInstance || ''; + + if (!instanceId) { + window.location.assign(url); + return; + } + + const previousController = controllers.get(module); + if (previousController) { + previousController.abort(); + } + + const controller = new AbortController(); + controllers.set(module, controller); + + module.classList.add('cc-d5sr--loading'); + module.setAttribute('aria-busy', 'true'); + + try { + const response = await fetch(url, { + credentials: 'same-origin', + headers: { + 'X-Requested-With': 'XMLHttpRequest', + 'X-CC-D5SR': 'pagination', + }, + signal: controller.signal, + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}`); + } + + const html = await response.text(); + const parsed = new DOMParser().parseFromString(html, 'text/html'); + const replacement = findModule(parsed, instanceId); + + if (!(replacement instanceof HTMLElement)) { + throw new Error('CC Search Results module not found in response'); + } + + const imported = document.importNode(replacement, true); + module.replaceWith(imported); + window.history.pushState({ ccD5srPagination: true }, '', url); + focusResults(imported); + + document.dispatchEvent(new CustomEvent('cc-d5sr:page-loaded', { + detail: { + instanceId, + url, + }, + })); + } catch (error) { + if (error instanceof DOMException && error.name === 'AbortError') { + return; + } + + window.location.assign(url); + } finally { + module.classList.remove('cc-d5sr--loading'); + module.removeAttribute('aria-busy'); + controllers.delete(module); + } + }; + + document.addEventListener('click', (event) => { + const target = event.target; + + if (!(target instanceof Element)) { + return; + } + + const link = target.closest('.cc-d5sr__pagination a'); + if (!(link instanceof HTMLAnchorElement)) { + return; + } + + const module = link.closest('.cc-d5sr__inner[data-cc-d5sr-ajax="on"]'); + if (!(module instanceof HTMLElement)) { + return; + } + + if ( + event.defaultPrevented + || event.button !== 0 + || event.metaKey + || event.ctrlKey + || event.shiftKey + || event.altKey + || link.target === '_blank' + || link.origin !== window.location.origin + ) { + return; + } + + event.preventDefault(); + loadPage(module, link.href); + }); + + if (document.querySelector('.cc-d5sr__inner[data-cc-d5sr-ajax="on"]')) { + window.history.replaceState({ + ...window.history.state, + ccD5srPagination: true, + }, '', window.location.href); + } + + window.addEventListener('popstate', () => { + if (document.querySelector('.cc-d5sr__inner[data-cc-d5sr-ajax="on"]')) { + window.location.reload(); + } + }); +})(); From b453d5abb9d92410d4a6f28cb70d2fc5183a8266 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:34:56 +0200 Subject: [PATCH 60/78] feat: add responsive result presets and polished controls --- assets/css/search-results.css | 401 +++++++++++++++++++++++++++++++--- 1 file changed, 375 insertions(+), 26 deletions(-) diff --git a/assets/css/search-results.css b/assets/css/search-results.css index a80baa6..5acb3d0 100644 --- a/assets/css/search-results.css +++ b/assets/css/search-results.css @@ -1,8 +1,23 @@ .cc-d5sr { --cc-d5sr-gap: clamp(16px, 2vw, 28px); + --cc-d5sr-ui-accent: #02797e; + --cc-d5sr-ui-accent-strong: #016368; + --cc-d5sr-text: #243536; + --cc-d5sr-muted: #687477; + --cc-d5sr-surface: #fff; + --cc-d5sr-border: #dce3e3; + --cc-d5sr-radius: 14px; + color: var(--cc-d5sr-text); +} + +.cc-d5sr *, +.cc-d5sr *::before, +.cc-d5sr *::after { + box-sizing: border-box; } .cc-d5sr__inner { + position: relative; display: grid; gap: var(--cc-d5sr-gap); } @@ -12,81 +27,281 @@ flex-wrap: wrap; gap: 0.35em; align-items: baseline; + color: var(--cc-d5sr-muted); + font-size: 0.95rem; +} + +.cc-d5sr__summary strong { + color: var(--cc-d5sr-text); + font-weight: 750; } .cc-d5sr__search { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; + width: 100%; } .cc-d5sr__search input, .cc-d5sr__search button { - min-height: 46px; - padding: 10px 14px; + min-height: 50px; + margin: 0; + border-radius: 10px; font: inherit; } -.cc-d5sr__grid { +.cc-d5sr__search input { + width: 100%; + padding: 11px 16px; + border: 1px solid var(--cc-d5sr-border); + outline: 0; + color: var(--cc-d5sr-text); + background: var(--cc-d5sr-surface); + box-shadow: 0 1px 2px rgb(20 38 39 / 4%); + transition: border-color 160ms ease, box-shadow 160ms ease; +} + +.cc-d5sr__search input:focus { + border-color: var(--cc-d5sr-ui-accent); + box-shadow: 0 0 0 3px rgb(2 121 126 / 16%); +} + +.cc-d5sr__search button { + padding: 11px 22px; + border: 1px solid var(--cc-d5sr-ui-accent); + color: #fff; + background: var(--cc-d5sr-ui-accent); + font-weight: 750; + line-height: 1; + cursor: pointer; + transition: transform 160ms ease, border-color 160ms ease, background 160ms ease; +} + +.cc-d5sr__search button:hover, +.cc-d5sr__search button:focus-visible { + border-color: var(--cc-d5sr-ui-accent-strong); + background: var(--cc-d5sr-ui-accent-strong); + transform: translateY(-1px); +} + +.cc-d5sr__results { display: grid; - grid-template-columns: repeat(var(--cc-d5sr-columns, 3), minmax(0, 1fr)); + grid-template-columns: repeat(var(--cc-d5sr-columns-desktop, 3), minmax(0, 1fr)); gap: var(--cc-d5sr-gap); + outline: 0; } .cc-d5sr__card { + position: relative; + display: flex; + min-width: 0; + height: 100%; overflow: hidden; - border: 1px solid #d7d9dc; - border-color: color-mix(in srgb, var(--cc-d5sr-accent) 28%, transparent); - border-radius: 12px; - background: #fff; + flex-direction: column; + border: 1px solid var(--cc-d5sr-border); + border-top: 3px solid var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)); + border-radius: var(--cc-d5sr-radius); + background: var(--cc-d5sr-surface); + box-shadow: 0 8px 24px rgb(26 47 48 / 6%); + transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease; +} + +.cc-d5sr__card:hover { + border-color: color-mix(in srgb, var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)) 42%, var(--cc-d5sr-border)); + box-shadow: 0 16px 36px rgb(26 47 48 / 12%); + transform: translateY(-3px); } .cc-d5sr__image { display: block; aspect-ratio: 16 / 10; overflow: hidden; + background: #eef2f2; } .cc-d5sr__image img { + display: block; width: 100%; height: 100%; object-fit: cover; + transition: transform 320ms ease; +} + +.cc-d5sr__card:hover .cc-d5sr__image img { + transform: scale(1.025); } .cc-d5sr__content { - display: grid; + display: flex; + min-width: 0; + flex: 1; + flex-direction: column; gap: 12px; - padding: 20px; + padding: clamp(16px, 2vw, 22px); } .cc-d5sr__meta { display: flex; flex-wrap: wrap; - gap: 10px; + gap: 8px 10px; align-items: center; - font-size: 0.85em; + color: var(--cc-d5sr-muted); + font-size: 0.78rem; + line-height: 1.25; } .cc-d5sr__badge { display: inline-flex; - padding: 0.25em 0.65em; + max-width: 100%; + padding: 0.35em 0.75em; + overflow: hidden; + align-items: center; border-radius: 999px; color: #fff; - background: var(--cc-d5sr-accent); + background: var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)); + font-weight: 700; + text-overflow: ellipsis; + white-space: nowrap; } .cc-d5sr__title { margin: 0; - font-size: clamp(1.1rem, 1.8vw, 1.45rem); + color: var(--cc-d5sr-text); + font-size: clamp(1.15rem, 1.65vw, 1.5rem); + line-height: 1.12; +} + +.cc-d5sr__title a { + color: inherit; + text-decoration: none; +} + +.cc-d5sr__title a:hover, +.cc-d5sr__title a:focus-visible { + color: var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)); } .cc-d5sr__excerpt { margin: 0; + color: var(--cc-d5sr-muted); + line-height: 1.65; } .cc-d5sr__cta { - justify-self: start; - font-weight: 700; + margin-top: auto; + align-self: flex-start; + color: var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)); + font-weight: 750; + text-decoration: none; +} + +.cc-d5sr__cta:hover, +.cc-d5sr__cta:focus-visible { + text-decoration: underline; + text-underline-offset: 0.2em; +} + +.cc-d5sr--preset-grid .cc-d5sr__meta { + order: 1; +} + +.cc-d5sr--preset-grid .cc-d5sr__title { + order: 2; +} + +.cc-d5sr--preset-grid .cc-d5sr__excerpt { + order: 3; +} + +.cc-d5sr--preset-grid .cc-d5sr__cta { + order: 4; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__card { + border-top-width: 1px; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__image { + aspect-ratio: 4 / 3; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__title { + order: 1; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__meta { + order: 2; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__excerpt { + order: 3; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__cta { + order: 4; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__results { + grid-template-columns: 1fr; + gap: 14px; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__card { + display: grid; + min-height: 138px; + grid-template-columns: clamp(140px, 19vw, 220px) minmax(0, 1fr); + border-top-width: 1px; + transform: none; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__card--no-image { + grid-template-columns: 1fr; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__image { + height: 100%; + min-height: 138px; + aspect-ratio: auto; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__content { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px 18px; + align-content: center; + padding: 16px 20px; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__meta, +.cc-d5sr--preset-compact-list .cc-d5sr__title, +.cc-d5sr--preset-compact-list .cc-d5sr__excerpt { + grid-column: 1; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__meta { + grid-row: 1; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__title { + grid-row: 2; + font-size: clamp(1.05rem, 1.4vw, 1.35rem); +} + +.cc-d5sr--preset-compact-list .cc-d5sr__excerpt { + display: -webkit-box; + overflow: hidden; + grid-row: 3; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + line-height: 1.45; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__cta { + grid-column: 2; + grid-row: 1 / span 3; + align-self: center; + white-space: nowrap; } .cc-d5sr__pagination .page-numbers { @@ -98,31 +313,165 @@ list-style: none; } +.cc-d5sr__pagination li { + margin: 0; +} + .cc-d5sr__pagination a, .cc-d5sr__pagination span { display: inline-flex; - min-width: 40px; - min-height: 40px; + min-width: 42px; + min-height: 42px; + padding: 8px 12px; align-items: center; justify-content: center; + border: 1px solid var(--cc-d5sr-border); + border-radius: 999px; + color: var(--cc-d5sr-text); + background: var(--cc-d5sr-surface); + font-weight: 700; + line-height: 1; + text-decoration: none; +} + +.cc-d5sr__pagination a:hover, +.cc-d5sr__pagination a:focus-visible, +.cc-d5sr__pagination .current { + border-color: var(--cc-d5sr-ui-accent); + color: #fff; + background: var(--cc-d5sr-ui-accent); } .cc-d5sr__empty { - padding: clamp(24px, 4vw, 48px); - border: 1px dashed currentColor; - border-radius: 12px; + padding: clamp(28px, 5vw, 56px); + border: 1px dashed var(--cc-d5sr-border); + border-radius: var(--cc-d5sr-radius); + background: color-mix(in srgb, var(--cc-d5sr-ui-accent) 4%, #fff); text-align: center; + outline: 0; +} + +.cc-d5sr__empty h2, +.cc-d5sr__empty p { + margin-top: 0; +} + +.cc-d5sr__empty p:last-child { + margin-bottom: 0; +} + +.cc-d5sr--loading { + min-height: 180px; + pointer-events: none; +} + +.cc-d5sr--loading::before { + position: absolute; + z-index: 20; + inset: -4px; + border-radius: var(--cc-d5sr-radius); + background: rgb(255 255 255 / 78%); + content: ''; +} + +.cc-d5sr--loading::after { + position: absolute; + z-index: 21; + top: 50%; + left: 50%; + width: 38px; + height: 38px; + margin: -19px 0 0 -19px; + border: 3px solid rgb(2 121 126 / 20%); + border-top-color: var(--cc-d5sr-ui-accent); + border-radius: 50%; + content: ''; + animation: cc-d5sr-spin 700ms linear infinite; +} + +@keyframes cc-d5sr-spin { + to { + transform: rotate(360deg); + } } @media (max-width: 980px) { - .cc-d5sr__grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); + .cc-d5sr__results { + grid-template-columns: repeat(var(--cc-d5sr-columns-tablet, 2), minmax(0, 1fr)); + } + + .cc-d5sr--preset-compact-list .cc-d5sr__results { + grid-template-columns: 1fr; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__card { + grid-template-columns: clamp(126px, 24vw, 190px) minmax(0, 1fr); } } @media (max-width: 600px) { - .cc-d5sr__search, - .cc-d5sr__grid { + .cc-d5sr__search { grid-template-columns: 1fr; } + + .cc-d5sr__search button { + width: 100%; + } + + .cc-d5sr__results { + grid-template-columns: repeat(var(--cc-d5sr-columns-phone, 1), minmax(0, 1fr)); + } + + .cc-d5sr--preset-compact-list .cc-d5sr__results { + grid-template-columns: 1fr; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__card { + min-height: 108px; + grid-template-columns: 104px minmax(0, 1fr); + border-radius: 11px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__image { + min-height: 108px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__content { + display: flex; + gap: 6px; + justify-content: center; + padding: 11px 12px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__meta { + font-size: 0.7rem; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__title { + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + font-size: 1rem; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__excerpt { + display: none; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__cta { + margin-top: 2px; + font-size: 0.82rem; + } +} + +@media (prefers-reduced-motion: reduce) { + .cc-d5sr *, + .cc-d5sr *::before, + .cc-d5sr *::after { + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + } } From e8ff30ccf9adb213a52bcafdcd2927322fe8bb46 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:36:02 +0200 Subject: [PATCH 61/78] feat: add responsive preset and pagination controls --- src/components/search-results/module.json | 207 +++++++++++++++++++--- 1 file changed, 186 insertions(+), 21 deletions(-) diff --git a/src/components/search-results/module.json b/src/components/search-results/module.json index b203180..ef9024f 100644 --- a/src/components/search-results/module.json +++ b/src/components/search-results/module.json @@ -1,13 +1,13 @@ { "name": "codecorn/search-results", "d4Shortcode": "", - "title": "Search Results", - "titles": "Search Results", + "title": "CC Search Results", + "titles": "CC Search Results", "moduleIcon": "divi/module-search", "moduleClassName": "cc-d5sr", "moduleOrderClassName": "cc-d5sr", "childModuleName": "codecorn/search-result-type", - "childModuleTitle": "Result Type Rule", + "childModuleTitle": "CC Result Type", "category": "module", "childrenName": [ "codecorn/search-result-type" @@ -16,22 +16,29 @@ "module": { "type": "object", "selector": "{{selector}}", + "default": { + "meta": { + "adminLabel": { + "desktop": { + "value": "CC Search Results" + } + } + } + }, "settings": { "meta": { - "meta": {} + "adminLabel": {} }, "advanced": { - "html": {}, + "htmlAttributes": {}, "link": {}, "text": {} }, "decoration": { "animation": {}, - "attributes": {}, "background": {}, "border": {}, "boxShadow": {}, - "conditions": {}, "disabledOn": {}, "filters": {}, "overflow": {}, @@ -69,6 +76,12 @@ "render": true, "subName": "source", "label": "Query source", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/select", @@ -90,7 +103,13 @@ "render": true, "subName": "searchTerm", "label": "Search term", - "description": "Used by the isolated query and by Visual Builder previews.", + "description": "Used by the isolated query and Visual Builder previews.", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -102,6 +121,12 @@ "render": true, "subName": "postsPerPage", "label": "Results per page", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -119,7 +144,19 @@ "value": { "showSummary": "on", "showSearchForm": "on", - "columns": "3" + "preset": "grid", + "columns": "3", + "ajaxPagination": "on" + } + }, + "tablet": { + "value": { + "columns": "2" + } + }, + "phone": { + "value": { + "columns": "1" } } } @@ -134,6 +171,12 @@ "render": true, "subName": "showSummary", "label": "Show result count", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/toggle" @@ -144,32 +187,105 @@ "priority": 20, "render": true, "subName": "showSearchForm", - "label": "Show search form", + "label": "Show search form above results", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/toggle" } }, - "columns": { + "preset": { "groupSlug": "contentDisplay", "priority": 30, "render": true, + "subName": "preset", + "label": "Output preset", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, + "component": { + "type": "field", + "name": "divi/select", + "props": { + "options": { + "grid": { + "label": "Editorial grid" + }, + "compact-list": { + "label": "Compact vertical list" + }, + "classic-card": { + "label": "Classic image card" + } + } + } + } + }, + "columns": { + "groupSlug": "contentDisplay", + "priority": 40, + "render": true, "subName": "columns", - "label": "Desktop columns", + "label": "Columns", + "description": "Responsive column count for grid and classic-card presets.", + "features": { + "sticky": false, + "responsive": true, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/select", "props": { "options": { - "1": { "label": "1" }, - "2": { "label": "2" }, - "3": { "label": "3" }, - "4": { "label": "4" }, - "5": { "label": "5" }, - "6": { "label": "6" } + "1": { + "label": "1" + }, + "2": { + "label": "2" + }, + "3": { + "label": "3" + }, + "4": { + "label": "4" + }, + "5": { + "label": "5" + }, + "6": { + "label": "6" + } } } } + }, + "ajaxPagination": { + "groupSlug": "contentDisplay", + "priority": 50, + "render": true, + "subName": "ajaxPagination", + "label": "AJAX pagination", + "description": "Loads the next result page without a full-page refresh and falls back to normal links on failure.", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, + "component": { + "type": "field", + "name": "divi/toggle" + } } } } @@ -181,8 +297,8 @@ "innerContent": { "desktop": { "value": { - "title": "No results found", - "body": "Try a different search term or browse another section of the site." + "title": "Nessun risultato trovato", + "body": "Prova con un termine diverso oppure visita un’altra sezione del sito." } } } @@ -197,6 +313,12 @@ "render": true, "subName": "title", "label": "Empty-state title", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -208,6 +330,12 @@ "render": true, "subName": "body", "label": "Empty-state message", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/textarea" @@ -218,6 +346,43 @@ } } }, + "customCssFields": { + "summary": { + "subName": "summary", + "label": "Result summary", + "selectorSuffix": " .cc-d5sr__summary" + }, + "searchForm": { + "subName": "searchForm", + "label": "Search form", + "selectorSuffix": " .cc-d5sr__search" + }, + "results": { + "subName": "results", + "label": "Results wrapper", + "selectorSuffix": " .cc-d5sr__results" + }, + "card": { + "subName": "card", + "label": "Result card", + "selectorSuffix": " .cc-d5sr__card" + }, + "cardImage": { + "subName": "cardImage", + "label": "Card image", + "selectorSuffix": " .cc-d5sr__image" + }, + "cardTitle": { + "subName": "cardTitle", + "label": "Card title", + "selectorSuffix": " .cc-d5sr__title" + }, + "pagination": { + "subName": "pagination", + "label": "Pagination", + "selectorSuffix": " .cc-d5sr__pagination" + } + }, "settings": { "content": "auto", "design": "auto", @@ -243,7 +408,7 @@ "component": { "name": "divi/composite", "props": { - "groupLabel": "Display" + "groupLabel": "Layout and navigation" } } }, From c9bfda67c8cc5ab4137274fe4808ca692edb0ad0 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:36:54 +0200 Subject: [PATCH 62/78] fix: align child metadata and localized defaults --- src/components/search-result-type/module.json | 120 +++++++++++++++--- 1 file changed, 103 insertions(+), 17 deletions(-) diff --git a/src/components/search-result-type/module.json b/src/components/search-result-type/module.json index 660cc0c..4896c18 100644 --- a/src/components/search-result-type/module.json +++ b/src/components/search-result-type/module.json @@ -1,8 +1,8 @@ { "name": "codecorn/search-result-type", "d4Shortcode": "", - "title": "Result Type Rule", - "titles": "Result Type Rules", + "title": "CC Result Type", + "titles": "CC Result Types", "moduleIcon": "divi/module-toggle", "moduleClassName": "cc-d5sr-rule", "moduleOrderClassName": "cc-d5sr-rule", @@ -12,12 +12,21 @@ "module": { "type": "object", "selector": "{{selector}}", + "default": { + "meta": { + "adminLabel": { + "desktop": { + "value": "CC Result Type" + } + } + } + }, "settings": { "meta": { - "meta": {} + "adminLabel": {} }, "advanced": { - "html": {} + "htmlAttributes": {} }, "decoration": { "disabledOn": {} @@ -40,7 +49,7 @@ "showExcerpt": "on", "showDate": "on", "excerptLength": "28", - "ctaLabel": "View result" + "ctaLabel": "Vedi risultato" } } } @@ -54,7 +63,41 @@ "priority": 10, "render": true, "subName": "postType", - "label": "Post type slug", + "label": "Post type", + "description": "Choose one of the public post types registered by WordPress.", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, + "component": { + "type": "field", + "name": "divi/select", + "props": { + "options": { + "post": { + "label": "Posts (post)" + }, + "page": { + "label": "Pages (page)" + } + } + } + } + }, + "priority": { + "groupSlug": "contentRule", + "priority": 20, + "render": true, + "subName": "priority", + "label": "Rule priority", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -66,6 +109,12 @@ "render": true, "subName": "singularLabel", "label": "Singular label", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -77,6 +126,12 @@ "render": true, "subName": "pluralLabel", "label": "Plural label", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -88,17 +143,12 @@ "render": true, "subName": "badgeLabel", "label": "Badge label", - "component": { - "type": "field", - "name": "divi/text" - } - }, - "priority": { - "groupSlug": "contentRule", - "priority": 20, - "render": true, - "subName": "priority", - "label": "Rule priority", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -110,6 +160,12 @@ "render": true, "subName": "accentColor", "label": "Accent color", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/color-picker" @@ -121,6 +177,12 @@ "render": true, "subName": "showImage", "label": "Show image", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/toggle" @@ -132,6 +194,12 @@ "render": true, "subName": "showExcerpt", "label": "Show excerpt", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/toggle" @@ -143,6 +211,12 @@ "render": true, "subName": "showDate", "label": "Show date", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/toggle" @@ -154,6 +228,12 @@ "render": true, "subName": "excerptLength", "label": "Excerpt words", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" @@ -165,6 +245,12 @@ "render": true, "subName": "ctaLabel", "label": "CTA label", + "features": { + "sticky": false, + "responsive": false, + "hover": false, + "dynamicContent": false + }, "component": { "type": "field", "name": "divi/text" From c5c990e2f655079b1fab1ed58d05cc5c7b96c443 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:37:10 +0200 Subject: [PATCH 63/78] feat: type responsive preset controls --- src/components/search-results/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/search-results/types.ts b/src/components/search-results/types.ts index 12d54cd..56e24ee 100644 --- a/src/components/search-results/types.ts +++ b/src/components/search-results/types.ts @@ -14,7 +14,9 @@ export interface SearchResultsQueryValue { export interface SearchResultsDisplayValue { showSummary?: string; showSearchForm?: string; + preset?: string; columns?: string; + ajaxPagination?: string; } export interface SearchResultsEmptyValue { From 0d553b78a14ff7aec1a808865fedeca83dabe57d Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:37:54 +0200 Subject: [PATCH 64/78] feat: preview selected output configuration --- src/components/search-results/edit.tsx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/search-results/edit.tsx b/src/components/search-results/edit.tsx index 437e46a..2e85354 100644 --- a/src/components/search-results/edit.tsx +++ b/src/components/search-results/edit.tsx @@ -5,6 +5,12 @@ import { moduleClassnames } from './module-classnames'; import { ModuleStyles } from './styles'; import { SearchResultsEditProps } from './types'; +const presetLabels: Record = { + grid: 'Editorial grid', + 'compact-list': 'Compact vertical list', + 'classic-card': 'Classic image card', +}; + export const SearchResultsEdit = (props: SearchResultsEditProps): ReactElement => { const { attrs, @@ -19,6 +25,13 @@ export const SearchResultsEdit = (props: SearchResultsEditProps): ReactElement = } const query = attrs.query?.innerContent?.desktop?.value; + const displayDesktop = attrs.display?.innerContent?.desktop?.value; + const displayTablet = attrs.display?.innerContent?.tablet?.value; + const displayPhone = attrs.display?.innerContent?.phone?.value; + const preset = displayDesktop?.preset || 'grid'; + const columnsDesktop = displayDesktop?.columns || '3'; + const columnsTablet = displayTablet?.columns || '2'; + const columnsPhone = displayPhone?.columns || '1'; return ( - CC Result Type children configure the frontend cards. + + {presetLabels[preset] || preset} + {preset !== 'compact-list' ? ` · columns ${columnsDesktop}/${columnsTablet}/${columnsPhone}` : ''} + {displayDesktop?.showSearchForm === 'off' ? ' · search form off' : ' · search form on'} + {displayDesktop?.ajaxPagination === 'off' ? ' · classic pagination' : ' · AJAX pagination'} + From ebfb39430391d4202c55b808239b7d34bceca7b1 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:41:48 +0200 Subject: [PATCH 65/78] docs: document presets and progressive pagination --- README.md | 292 ++++++++++++++++++++---------------------------------- 1 file changed, 110 insertions(+), 182 deletions(-) diff --git a/README.md b/README.md index 3756884..46feba2 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,32 @@ > Native Divi 5 search results. The Blog Module workaround ends here. -A public Divi 5 extension for type-aware WordPress search results. The native parent module owns the query and result layout; native child modules act as repeatable rules for individual post types. The optional shortcode calls the same PHP query and rendering services. +A public Divi 5 extension for type-aware WordPress search results. The native parent module owns the query, layout and navigation; native child modules are repeatable post-type rules. The optional shortcode calls the same PHP resolver and renderer. ## Current implementation The `0.1.0` development branch currently includes: - safe plugin bootstrap with Composer PSR-4 autoloading and a source-checkout fallback autoloader; -- isolated search-query resolution that never calls `query_posts()` and never replaces the global `$wp_query`; -- reuse of the real current WordPress search query when the module runs on a search-results request; -- an isolated `WP_Query` fallback for Visual Builder previews, non-search pages and shortcode use; -- the native Divi 5 parent module `codecorn/search-results`, displayed in the Builder as `CC Search Results`; -- the native configuration child module `codecorn/search-result-type`, displayed as `CC Result Type`; +- reuse of the real current WordPress search query without calling `query_posts()` or replacing global `$wp_query`; +- isolated `WP_Query` resolution for Visual Builder previews, normal pages and shortcode use; +- parent module `codecorn/search-results`, displayed as **CC Search Results**; +- child module `codecorn/search-result-type`, displayed as **CC Result Type**; +- a dynamic post-type selector populated from the public post types registered by the current WordPress site; - repeatable post-type rules for labels, badge, accent, image, excerpt, date and CTA; -- a dynamic result-type selector populated from the public post types registered by WordPress; -- accessible result count, search form, result cards, pagination and empty state; -- shared rendering used by both the native module and `[cc_divi5_search_results]`; -- Visual Builder TypeScript sources, Divi-compatible compiler configuration and webpack build; -- repository-level npm configuration for the incompatible peer ranges published by the Divi 5 type aliases; +- optional result summary and optional search form above the first result; +- three output presets: editorial grid, compact vertical list and classic image card; +- responsive grid columns controlled independently for desktop, tablet and phone; +- progressive AJAX pagination with loading state, URL history, focus restoration and classic-link fallback; +- Italian frontend defaults for search, count, empty state, pagination and CTA labels; +- shared rendering used by the native module and `[cc_divi5_search_results]`; +- responsive frontend styling for form, cards, metadata, pagination, empty state and reduced motion; +- Visual Builder TypeScript sources and webpack build; - deterministic runtime packaging with build manifest and SHA-256 checksum; -- VM deployment workflow for host and Docker WordPress installations, including backup and automatic rollback; -- a Barbagia Musei deployment wrapper pinned to the real `docker02` Compose stack and `wp_cron` service; -- non-interactive Barbagia preflight for SSH public-key authentication and remote Docker API access; -- frontend CSS with responsive grid behavior. +- VM deployment for host and Docker WordPress installations with backup and rollback; +- a Barbagia Musei wrapper pinned to the real `docker02` Compose stack and `wp_cron` service. -The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Server registration consumes the generated `modules-json/` files, so run the build before testing module insertion and editing. +The Visual Builder bundle and `modules-json/` metadata are generated locally and are not committed. Run the build before module insertion, Visual Builder testing or packaging. ## Native module structure @@ -38,30 +39,48 @@ CC Search Results (codecorn/search-results) └── any registered public custom post type ``` -`CC Result Type` children are configuration objects. They do not render independent frontend cards. The parent reads their saved Divi block attributes and applies them to posts returned by the search query. +`CC Result Type` children are configuration objects. They do not render independent frontend cards. The parent reads their saved Divi attributes and applies them to posts returned by the search query. -## Available parent controls +## Parent controls ### Query - current WordPress search query or isolated query; -- explicit search term for the isolated query and Visual Builder preview; +- explicit search term for isolated queries and Builder previews; - results per page. -### Display +### Layout and navigation -- result count; -- search form; -- one to six desktop columns. +- show or hide the result count; +- show or hide the complete search form above the results; +- output preset; +- responsive columns for desktop, tablet and phone; +- AJAX pagination on or off. ### Empty state - title; - message. -## Available result-type controls +## Output presets -- public WordPress post type selected from the list registered by the current site; +### Editorial grid — `grid` + +Metadata and badge appear before the title. Cards have equal-height content, optional image, excerpt and CTA. The responsive column control is applied at each Divi breakpoint. + +### Compact vertical list — `compact-list` + +One low horizontal item per row, designed for podcast/archive-like sections. The image sits on the left, content remains compact, the excerpt is clamped and the mobile item reduces to a small thumbnail with a two-line title. + +The columns control is ignored by this preset because it is intentionally a one-column vertical list. + +### Classic image card — `classic-card` + +The image appears above the content. The title is the first element immediately below the image, followed by metadata, description and CTA. The responsive column control is applied at each Divi breakpoint. + +## Result-type controls + +- public WordPress post type selected from the current site's registered list; - singular, plural and badge labels; - rule priority; - accent color; @@ -69,9 +88,9 @@ CC Search Results (codecorn/search-results) - excerpt word count; - CTA label. -The post-type selector is populated when the Visual Builder assets are registered. It lists the translated WordPress label followed by the technical slug, for example `Articoli (post)`, `Pagine (page)` or `Eventi (eventi)`. Attachments are excluded. If Builder data is unavailable, the control falls back to `post` and `page` instead of becoming a free-text field. +The post-type selector lists the translated WordPress label and technical slug, for example `Articoli (post)`, `Pagine (page)` or `Eventi (eventi)`. Attachments are excluded. If Builder data is unavailable, the selector falls back to `post` and `page`; it never becomes a comma-separated free-text field. -Integrations can adjust the available options without changing module code: +Integrations can change the exposed post types: ```php add_filter( @@ -84,13 +103,13 @@ add_filter( ); ``` -Missing labels fall back to the registered WordPress post-type labels. Missing rules fall back to a generic rule derived from the result's post type. +Missing labels fall back to the registered post-type labels. Missing rules fall back to a generic rule derived from the result's post type. ## Query contract -For `source=current`, the module reads the already-resolved main WordPress search query. It does not alter it. +For `source=current`, the module reads the already-resolved main WordPress search query. It does not mutate it. -For `source=isolated`, the plugin creates its own `WP_Query` using the search term, configured result types, result limit and current page. Integrations can adjust only that isolated query through: +For `source=isolated`, the plugin creates its own query using the search term, configured result types, result limit and current page. Integrations can adjust only that isolated query: ```php add_filter( 'cc_d5sr_query_args', function ( array $query_args, array $options ): array { @@ -98,27 +117,44 @@ add_filter( 'cc_d5sr_query_args', function ( array $query_args, array $options ) }, 10, 2 ); ``` +## AJAX pagination contract + +AJAX pagination is progressive enhancement rather than a second query endpoint: + +1. pagination still renders normal WordPress links; +2. the frontend runtime fetches the real target page; +3. it locates the same module instance in the returned document; +4. it replaces only that module's inner result output; +5. it updates browser history, scrolls to the module and restores keyboard focus; +6. a failed request or missing module instance falls back to the normal page navigation. + +This preserves the current WordPress search query, Theme Builder layout, third-party query filters and canonical paginated URLs. Disabling **AJAX pagination** leaves the normal links untouched. + ## Optional shortcode ```text [cc_divi5_search_results] ``` -Supported attributes in this increment: +Supported attributes: ```text source="current|isolated" search="museum" post_types="post,page,event" posts_per_page="10" +preset="grid|compact-list|classic-card" columns="3" -show_summary="on" -show_search_form="on" -show_image="on" -show_excerpt="on" -show_date="on" +columns_tablet="2" +columns_phone="1" +ajax_pagination="on|off" +show_summary="on|off" +show_search_form="on|off" +show_image="on|off" +show_excerpt="on|off" +show_date="on|off" excerpt_length="28" -cta_label="View result" +cta_label="Vedi risultato" ``` The shortcode is an adapter, not the primary implementation. @@ -128,12 +164,12 @@ The shortcode is an adapter, not the primary implementation. Requirements: - WordPress 6.6+; -- Divi 5.9.0 reference target for this development increment; +- Divi 5.9.0 reference target for this increment; - PHP 8.1+; - Node.js 18+ and npm 10+; - Composer. -Install from the committed dependency locks and build: +Install from the committed locks and build: ```bash composer install @@ -142,13 +178,13 @@ npm run check npm run build ``` -To rebuild the installed npm tree without changing the committed dependency graph: +Rebuild the installed npm tree without changing the committed graph: ```bash npm run reset-install ``` -`reset-install` removes only `node_modules`, then runs `npm ci`. It deliberately preserves `package-lock.json`. Changes to `package.json` must be followed by an intentional `npm install`, review of the resulting lockfile diff and inclusion of both files in the same pull request. The same rule applies to `composer.json` and `composer.lock`. +`reset-install` removes only `node_modules`, then runs `npm ci`. Changes to `package.json` require an intentional `npm install`, review of `package-lock.json` and inclusion of both files in the same PR. The same rule applies to `composer.json` and `composer.lock`. Validation: @@ -156,15 +192,14 @@ Validation: composer check:syntax npm run check:types npm run check:json +node --check assets/js/search-results.js ``` -`ts-loader` performs type checking during `npm run build`; it is not configured with `transpileOnly`. The compiler configuration intentionally follows the compatibility surface used by the official Divi 5 example modules: emitted ES5 JavaScript, classic React JSX and no strict-null checking inside the published Divi type sources. - -The published Divi 5 type aliases contain mutually incompatible development-only peer ranges: `react-dates` requests React/ReactDOM 16 while current WordPress packages request React 18. The repository therefore commits `.npmrc` with `legacy-peer-deps=true`; this prevents npm 10 from attempting an impossible peer-resolution graph. React remains externalized from the Visual Builder bundle, so this setting does not select or ship a second runtime React version. The same file keeps `engine-strict=true`. +`ts-loader` performs type checking during `npm run build`; it is not configured with `transpileOnly`. The TypeScript configuration follows the compatibility surface used by the official Divi 5 example modules. -The npm installation can still report deprecation and audit warnings from the `divi-types*` compatibility aliases used by Elegant Themes. Those warnings are not treated as a successful build: the authoritative result is the exit status of `npm run check` and `npm run build`. Do not run `npm audit fix --force`, because it can replace Divi-compatible development dependencies with breaking versions. +The published Divi compatibility aliases contain incompatible development-only React peer ranges. `.npmrc` therefore commits `legacy-peer-deps=true` and `engine-strict=true`. Do not run `npm audit fix --force` because it can replace Divi-compatible development dependencies with breaking versions. -After `npm run build`, the generated files are: +Generated build files: ```text scripts/bundle.js @@ -173,21 +208,20 @@ modules-json/search-results/module.json modules-json/search-result-type/module.json ``` -Local proprietary references, including an extracted Divi theme under `.reference/`, are ignored by Git and must never be committed. +Local proprietary references under `.reference/` are ignored and must never be committed. ## Runtime package -A source checkout is not a distributable plugin archive by itself. The package command performs a clean dependency install from both committed lockfiles, runs all TypeScript/JSON/PHP checks, builds the Visual Builder assets and creates a runtime-only archive under `dist/`: - ```bash composer package ``` -The generated archive contains: +The runtime archive contains: ```text cc-divi5-search-results.php -assets/ +assets/css/search-results.css +assets/js/search-results.js includes/ modules/ shortcodes/ @@ -202,50 +236,24 @@ LICENSE build-manifest.json ``` -It deliberately excludes `src/`, `node_modules/`, development manifests, local references and repository metadata. A sibling `.sha256` file records the archive checksum. The build manifest records plugin version, exact Git commit, branch and UTC build time. +It excludes `src/`, `node_modules/`, development manifests, local references and Git metadata. A sibling `.sha256` file records the archive checksum. -Packaging requires: - -- committed `composer.lock` and `package-lock.json`; -- a clean working tree unless `CC_D5SR_REQUIRE_CLEAN=0` is set explicitly; -- successful `composer install --no-dev`, `npm ci`, `npm run check`, `npm run build` and `composer check:syntax`. - -The package path, archive contents and checksum flow have been exercised against a disposable mock repository. The first real VM deployment remains a required integration test before this PR can leave draft state. +Packaging requires committed lockfiles, a clean working tree unless explicitly overridden, and successful Composer, npm, TypeScript, JSON, JavaScript and PHP validation. ## VM deployment -The same workflow deploys the generated runtime archive to a WordPress installation reachable over SSH: +Generic commands: ```bash composer deploy:check composer deploy ``` -`deploy:check` performs the full local package and validation sequence but never opens an SSH connection and never modifies the VM. - -`deploy` performs: - -1. local clean-tree and lockfile checks; -2. reproducible package generation; -3. SSH upload without `scp`; -4. SHA-256 verification on the VM; -5. timestamped backup of the installed plugin when present; -6. staged copy into the WordPress plugins directory; -7. remote PHP lint before switching versions; -8. same-filesystem atomic directory switch; -9. optional activation and status verification through WP-CLI; -10. automatic rollback when the remote lint, switch, activation or status check fails; -11. retention pruning for old backups. - -### Required deployment variable - -```bash -export CC_D5SR_DEPLOY_TARGET="user@example-host" -``` +`deploy:check` performs local packaging and validation without SSH or remote changes. `deploy` uploads the runtime archive, verifies SHA-256, creates a timestamped backup, stages and lints the plugin, switches directories, activates through WP-CLI when enabled and rolls back on failure. -### Docker WordPress example +### Generic Docker example -`CC_D5SR_DEPLOY_CONTAINER` is a Docker container name or ID, not a Compose service name. +`CC_D5SR_DEPLOY_CONTAINER` is a container name or ID, never a Compose service name. ```bash export CC_D5SR_DEPLOY_TARGET="user@example-host" @@ -257,11 +265,9 @@ composer deploy:check composer deploy ``` -The VM must provide Docker. The selected container must provide `php`, `tar` and, when activation is enabled, `wp`. - ### Barbagia Musei on `docker02` -The dedicated wrapper removes all manual container and path discovery. Run it from the local repository root: +Run from the local repository: ```bash cd "$GH_PATH/cc-divi5-search-results" || return 1 @@ -270,21 +276,19 @@ composer deploy:barbagia:check composer deploy:barbagia ``` -The wrapper is pinned to this deployment contract: +Pinned deployment contract: ```text -Local repository: $GH_PATH/cc-divi5-search-results -SSH target: docker02 -Remote Compose file:/home/fgirolami/docker/barbagiamusei/compose.yaml -Compose service: wp_cron -WordPress root: /var/www/html -Activation: enabled -Backup retention: 10 +Local repository: $GH_PATH/cc-divi5-search-results +SSH target: docker02 +Remote Compose file: /home/fgirolami/docker/barbagiamusei/compose.yaml +Compose service: wp_cron +WordPress root: /var/www/html +Activation: enabled +Backup retention: 10 ``` -`composer deploy:barbagia:check` runs the complete local package validation without SSH or remote changes. - -`composer deploy:barbagia` connects to `docker02` and resolves the running container dynamically with: +The wrapper resolves the running container with the absolute Compose path: ```bash docker compose \ @@ -292,67 +296,27 @@ docker compose \ ps -q wp_cron ``` -The resolved container is currently named `cron_barbagiamusei`, but that name is not hardcoded because it can change after a Compose recreate. Before deployment, the wrapper requires exactly one running container for `wp_cron` and verifies inside it: +The current container name is `cron_barbagiamusei`, but it is not hardcoded. Docker runs on `docker02`; local Docker Desktop is irrelevant. -- `/var/www/html/wp-load.php`; -- PHP CLI; -- `tar`; -- WP-CLI. - -The remote Compose command uses the absolute `-f` path. It does not depend on the SSH login directory or on the repository path shown by the remote shell prompt. Docker is executed on `docker02`; a stopped Docker Desktop installation on the local Mac has no effect on this workflow. - -The Barbagia apply command is intentionally non-interactive. Before packaging or upload it requires both of these checks to pass: +The apply command is non-interactive and requires: ```bash ssh -o BatchMode=yes docker02 true ssh -o BatchMode=yes docker02 docker info ``` -The first check proves that the Mac can authenticate with the configured SSH key without falling back to the account password. The second proves that the remote `fgirolami` session can access `/var/run/docker.sock` without `sudo`. The deploy script never stores, pipes or retries SSH or sudo passwords. - -One-time SSH-key bootstrap, only when the first check fails: - -```bash -ssh-add --apple-use-keychain ~/.ssh/id_ed25519 - -cat ~/.ssh/id_ed25519.pub | ssh docker02 ' - umask 077 - mkdir -p ~/.ssh - touch ~/.ssh/authorized_keys - IFS= read -r key - grep -qxF "$key" ~/.ssh/authorized_keys || printf "%s\n" "$key" >> ~/.ssh/authorized_keys - chmod 700 ~/.ssh - chmod 600 ~/.ssh/authorized_keys -' - -ssh -o BatchMode=yes docker02 true -``` - -The `ssh` command used to install the public key may request the normal account password once. The final `BatchMode=yes` verification must not request any password. +The first check verifies SSH public-key authentication. The second verifies that remote user `fgirolami` can access `/var/run/docker.sock` without sudo. The deploy script never stores or pipes SSH or sudo passwords. -One-time Docker-access bootstrap, only when the second check fails: +One-time Docker group bootstrap when required: ```bash ssh -tt docker02 'sudo usermod -aG docker fgirolami' -``` - -After changing group membership, terminate the old SSH session and open a new one. If SSH connection multiplexing is configured globally, close the existing master connection before verification: - -```bash ssh -O exit docker02 2>/dev/null || true - -ssh -o BatchMode=yes docker02 ' - id - docker info >/dev/null - docker compose \ - -f /home/fgirolami/docker/barbagiamusei/compose.yaml \ - ps -q wp_cron -' ``` -Membership in the `docker` group grants root-equivalent control of the Docker host. This stack already requires Docker administration for deployment, so the requirement is explicit rather than hidden behind an interactive sudo prompt. +Open a new SSH session after changing group membership. Membership in the Docker group grants root-equivalent Docker-host control; this requirement is explicit because the deployment manages containers. -Optional Barbagia overrides are available only when the stack changes intentionally: +Optional Barbagia overrides: ```text CC_D5SR_DEPLOY_TARGET default docker02 @@ -361,56 +325,20 @@ CC_D5SR_COMPOSE_SERVICE default wp_cron CC_D5SR_REMOTE_WP_ROOT default /var/www/html ``` -### Host WordPress example - -```bash -export CC_D5SR_DEPLOY_TARGET="user@example-host" -export CC_D5SR_DEPLOY_MODE="host" -export CC_D5SR_REMOTE_WP_ROOT="/var/www/html" - -composer deploy:check -composer deploy -``` - -The host must provide `php` and, when activation is enabled, `wp`. - -### Deployment variables - -```text -CC_D5SR_DEPLOY_TARGET required for generic deploy; SSH user/host -CC_D5SR_DEPLOY_MODE auto, host or docker; default auto -CC_D5SR_DEPLOY_CONTAINER Docker container name or ID; never a Compose service -CC_D5SR_REMOTE_WP_ROOT default /var/www/html -CC_D5SR_REMOTE_STATE_DIR default .local/state/cc-divi5-search-results -CC_D5SR_SSH_PORT default 22 -CC_D5SR_ACTIVATE 1 or 0; default 1 -CC_D5SR_BACKUP_KEEP default 10; 0 disables pruning -CC_D5SR_REQUIRE_CLEAN 1 or 0; default 1 -CC_D5SR_COLOR auto, always or never -NO_COLOR disables ANSI colors -``` - -The default remote state path is relative to the SSH user's home directory. It contains incoming archives, temporary extraction directories and timestamped backups. No credentials belong in the repository. The Barbagia wrapper intentionally contains the non-secret stack path and service contract so deployment does not rely on operator memory. - ## Not implemented yet -The README deliberately does not present the following as available: +The README does not present these as available: - live query results inside the Visual Builder canvas; - per-type custom-field and taxonomy mappings; - type filters with counts; - query-term highlighting; -- per-breakpoint column controls; -- image fallback and ratio controls; -- card presets; -- AJAX navigation; +- per-rule image fallback and configurable image ratios; - automated GitHub release publication. -Those capabilities will be added in later reviewable increments without changing the shared renderer contract. - ## Documentation rule -Every pull request that changes behavior, controls, requirements, generated paths, build commands, dependency requirements, deployment behavior or public APIs must update this README in the same pull request. Documentation may describe merged or included code only; planned behavior belongs exclusively in **Not implemented yet**. +Every PR that changes behavior, controls, requirements, generated paths, build commands, dependency requirements, deployment behavior or public APIs must update this README in the same PR. Documentation may describe included code only; planned behavior belongs under **Not implemented yet**. ## License From 4033e5929bbfb603bd22a118e57e7f61e7425d02 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:42:44 +0200 Subject: [PATCH 66/78] build: validate frontend pagination runtime --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index a8e55dd..e3b766d 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,10 @@ "scripts": { "start": "NODE_ENV=development webpack -w --config webpack.config.js --progress", "build": "NODE_ENV=production webpack --config webpack.config.js --progress", - "check": "npm run check:types && npm run check:json", + "check": "npm run check:types && npm run check:json && npm run check:frontend", "check:types": "tsc --noEmit", "check:json": "node scripts/check-json.cjs", + "check:frontend": "node --check assets/js/search-results.js", "reset-install": "rm -rf node_modules && npm ci" }, "devDependencies": { From 91f100dcf2066657a29a26783931c928eea17397 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:43:19 +0200 Subject: [PATCH 67/78] docs: record result presentation increment --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6782aab..a512585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,11 @@ - Barbagia deployment preflight requiring SSH public-key authentication and direct remote Docker API access. - Dynamic Visual Builder post-type selector populated from public WordPress post types, with labels and slugs. - `cc_d5sr_builder_post_type_options` filter for adjusting the post types exposed by the builder selector. +- Three frontend output presets: editorial grid, compact vertical list and classic image card. +- Independent desktop, tablet and phone column controls for grid-based presets. +- Optional progressive AJAX pagination with loading state, browser history, focus restoration and classic navigation fallback. +- Frontend JavaScript syntax validation through `npm run check:frontend`. +- Custom CSS selector targets for summary, search form, results, cards, images, titles and pagination. ### Changed @@ -42,3 +47,7 @@ - Documentation now records that runtime packaging passed a disposable mock-repository test while the first real VM deployment remains an integration gate. - Visual Builder display names are now `CC Search Results` and `CC Result Type` while the saved technical module slugs remain unchanged. - The result-type post-type control is now a select instead of a free-text slug field. +- The complete search form can be shown or hidden above the result output. +- Default frontend copy is now Italian: `Cerca`, result counts, empty state, pagination labels and `Vedi risultato`. +- Frontend presentation now styles the search form, cards, metadata, pagination, loading state, focus states and reduced-motion behavior. +- Parent and child module metadata now use the native Divi 5 `adminLabel` and `htmlAttributes` schema. From dce3476d4bda1a570439105867d7fed06d6c40ff Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:44:23 +0200 Subject: [PATCH 68/78] fix: migrate legacy default CTA label --- includes/Rendering/ResultTypeRule.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/includes/Rendering/ResultTypeRule.php b/includes/Rendering/ResultTypeRule.php index d0aab30..fcfe61e 100644 --- a/includes/Rendering/ResultTypeRule.php +++ b/includes/Rendering/ResultTypeRule.php @@ -46,6 +46,11 @@ public static function fromFlatArray( array $values ): self { $plural = self::label( $values['pluralLabel'] ?? $values['plural_label'] ?? '', $object, true, $singular ); $badge = sanitize_text_field( (string) ( $values['badgeLabel'] ?? $values['badge_label'] ?? $singular ) ); $accent = sanitize_hex_color( (string) ( $values['accentColor'] ?? $values['accent_color'] ?? '#2b2f36' ) ); + $cta = sanitize_text_field( (string) ( $values['ctaLabel'] ?? $values['cta_label'] ?? '' ) ); + + if ( '' === $cta || 'View result' === $cta ) { + $cta = __( 'Vedi risultato', 'cc-divi5-search-results' ); + } return new self( $post_type, @@ -58,7 +63,7 @@ public static function fromFlatArray( array $values ): self { self::flag( $values['showExcerpt'] ?? $values['show_excerpt'] ?? 'on' ), self::flag( $values['showDate'] ?? $values['show_date'] ?? 'on' ), max( 0, min( 200, (int) ( $values['excerptLength'] ?? $values['excerpt_length'] ?? 28 ) ) ), - sanitize_text_field( (string) ( $values['ctaLabel'] ?? $values['cta_label'] ?? __( 'Vedi risultato', 'cc-divi5-search-results' ) ) ) + $cta ); } From 4252a0160fbc5a46fbf91d7d7915c0a2f0e124e7 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:45:41 +0200 Subject: [PATCH 69/78] docs: record legacy CTA compatibility --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a512585..3847345 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,5 +49,6 @@ - The result-type post-type control is now a select instead of a free-text slug field. - The complete search form can be shown or hidden above the result output. - Default frontend copy is now Italian: `Cerca`, result counts, empty state, pagination labels and `Vedi risultato`. +- Existing child modules that still contain the old exact default CTA `View result` are rendered as `Vedi risultato`; custom CTA labels are left untouched. - Frontend presentation now styles the search form, cards, metadata, pagination, loading state, focus states and reduced-motion behavior. - Parent and child module metadata now use the native Divi 5 `adminLabel` and `htmlAttributes` schema. From 3c1ea8c97adcc57cbd4ad0d7d4b9a6ff7650a542 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 03:47:04 +0200 Subject: [PATCH 70/78] docs: clarify legacy saved CTA migration --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46feba2..c7ab569 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ add_filter( ); ``` -Missing labels fall back to the registered post-type labels. Missing rules fall back to a generic rule derived from the result's post type. +Missing labels fall back to the registered post-type labels. Missing rules fall back to a generic rule derived from the result's post type. Existing child modules that still store the old exact default CTA `View result` render as `Vedi risultato`; any custom CTA text remains unchanged. ## Query contract From ea001f7cba754fae7df1e1efec38281e81a44382 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:36:20 +0200 Subject: [PATCH 71/78] fix: honor module pagination on current searches --- includes/Query/SearchQueryResolver.php | 78 +++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/includes/Query/SearchQueryResolver.php b/includes/Query/SearchQueryResolver.php index 745e315..3709002 100644 --- a/includes/Query/SearchQueryResolver.php +++ b/includes/Query/SearchQueryResolver.php @@ -9,24 +9,50 @@ final class SearchQueryResolver { * @param array $options */ public function resolve( array $options ): QueryResult { - $source = sanitize_key( (string) ( $options['source'] ?? 'current' ) ); + $source = sanitize_key( (string) ( $options['source'] ?? 'current' ) ); + $posts_per_page = max( 1, min( 100, (int) ( $options['posts_per_page'] ?? 10 ) ) ); + $current_page = max( 1, (int) ( $options['current_page'] ?? $this->currentPage() ) ); + $post_types = $this->sanitizePostTypes( $options['post_types'] ?? array() ); + $requested_term = sanitize_text_field( (string) ( $options['search_term'] ?? '' ) ); if ( 'current' === $source ) { $current = $this->currentSearchQuery(); if ( $current instanceof WP_Query ) { - return $this->fromQuery( $current, get_search_query( false ) ); + $search_term = sanitize_text_field( + (string) $current->get( 's', get_search_query( false ) ) + ); + $query_args = $this->currentQueryArgs( + $current, + $search_term, + $post_types, + $posts_per_page, + $current_page + ); + + /** + * Filter the isolated query derived from the current WordPress search request. + * + * The main global query is never mutated. + * + * @param array $query_args + * @param array $options + * @param WP_Query $current + */ + $query_args = apply_filters( 'cc_d5sr_current_query_args', $query_args, $options, $current ); + $query = new WP_Query( $query_args ); + + return $this->fromQuery( $query, $search_term ); } } - $search_term = sanitize_text_field( (string) ( $options['search_term'] ?? get_search_query( false ) ) ); - $posts_per_page = max( 1, min( 100, (int) ( $options['posts_per_page'] ?? 10 ) ) ); - $current_page = max( 1, (int) ( $options['current_page'] ?? $this->currentPage() ) ); - $post_types = $this->sanitizePostTypes( $options['post_types'] ?? array() ); - - $query_args = array( + $search_term = '' !== $requested_term + ? $requested_term + : sanitize_text_field( get_search_query( false ) ); + $query_args = array( 'ignore_sticky_posts' => true, 'no_found_rows' => false, + 'nopaging' => false, 'paged' => $current_page, 'post_status' => 'publish', 'post_type' => $post_types ?: 'any', @@ -56,6 +82,42 @@ private function currentSearchQuery(): ?WP_Query { return $wp_query; } + /** + * Build a private query from the resolved search request while allowing the module + * to own result types, page size and pagination. + * + * @param list $post_types + * + * @return array + */ + private function currentQueryArgs( + WP_Query $current, + string $search_term, + array $post_types, + int $posts_per_page, + int $current_page + ): array { + $query_args = is_array( $current->query_vars ) ? $current->query_vars : array(); + + unset( + $query_args['offset'], + $query_args['posts_per_archive_page'], + $query_args['fields'] + ); + + $query_args['ignore_sticky_posts'] = true; + $query_args['no_found_rows'] = false; + $query_args['nopaging'] = false; + $query_args['paged'] = $current_page; + $query_args['page'] = 0; + $query_args['post_status'] = 'publish'; + $query_args['post_type'] = $post_types ?: 'any'; + $query_args['posts_per_page'] = $posts_per_page; + $query_args['s'] = $search_term; + + return $query_args; + } + private function currentPage(): int { return max( 1, (int) get_query_var( 'paged' ), (int) get_query_var( 'page' ) ); } From 92e8d23be0c20514853a47d78fa9b053818e0b04 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:38:06 +0200 Subject: [PATCH 72/78] style: add polished search result presets --- assets/css/search-results-theme.css | 320 ++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 assets/css/search-results-theme.css diff --git a/assets/css/search-results-theme.css b/assets/css/search-results-theme.css new file mode 100644 index 0000000..c8cb33a --- /dev/null +++ b/assets/css/search-results-theme.css @@ -0,0 +1,320 @@ +.cc-d5sr { + --cc-d5sr-gap: clamp(14px, 1.6vw, 22px); + --cc-d5sr-ui-accent: #02797e; + --cc-d5sr-ui-accent-strong: #015d61; + --cc-d5sr-text: #243536; + --cc-d5sr-muted: #687477; + --cc-d5sr-surface: #fff; + --cc-d5sr-surface-soft: #f7faf9; + --cc-d5sr-border: #d8e1df; + --cc-d5sr-radius: 18px; + container-type: inline-size; +} + +.cc-d5sr__inner { + gap: clamp(14px, 2vw, 24px); + padding: clamp(16px, 2.3vw, 28px); + border: 1px solid rgb(2 121 126 / 14%); + border-radius: calc(var(--cc-d5sr-radius) + 4px); + background: + radial-gradient(circle at 100% 0, rgb(2 121 126 / 8%), transparent 36%), + linear-gradient(145deg, rgb(255 255 255 / 96%), rgb(247 250 249 / 94%)); + box-shadow: 0 20px 55px rgb(30 54 54 / 10%); +} + +.cc-d5sr__summary { + position: relative; + gap: 0.45em; + padding-left: 17px; + font-size: 0.92rem; + letter-spacing: 0.01em; +} + +.cc-d5sr__summary::before { + position: absolute; + top: 50%; + left: 0; + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--cc-d5sr-ui-accent); + box-shadow: 0 0 0 5px rgb(2 121 126 / 11%); + content: ''; + transform: translateY(-50%); +} + +.cc-d5sr__summary strong { + font-weight: 800; +} + +.cc-d5sr__search { + gap: 6px; + padding: 6px; + border: 1px solid var(--cc-d5sr-border); + border-radius: 15px; + background: rgb(255 255 255 / 92%); + box-shadow: 0 8px 24px rgb(30 54 54 / 7%); +} + +.cc-d5sr__search input, +.cc-d5sr__search button { + min-height: 46px; + border-radius: 10px; +} + +.cc-d5sr__search input { + padding-inline: 14px; + border-color: transparent; + background: transparent; + box-shadow: none; +} + +.cc-d5sr__search input:focus { + border-color: rgb(2 121 126 / 24%); + background: #fff; + box-shadow: 0 0 0 3px rgb(2 121 126 / 10%); +} + +.cc-d5sr__search button { + min-width: 92px; + padding-inline: 20px; + border: 0; + box-shadow: 0 8px 18px rgb(2 121 126 / 20%); +} + +.cc-d5sr__results { + align-items: stretch; +} + +.cc-d5sr__card { + isolation: isolate; + border: 1px solid rgb(36 53 54 / 10%); + border-top: 0; + border-radius: 16px; + box-shadow: 0 10px 28px rgb(31 49 49 / 8%); +} + +.cc-d5sr__card::before { + position: absolute; + z-index: 3; + top: 0; + right: 0; + left: 0; + height: 3px; + background: var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)); + content: ''; +} + +.cc-d5sr__card:hover { + border-color: rgb(2 121 126 / 24%); + box-shadow: 0 18px 42px rgb(31 49 49 / 14%); + transform: translateY(-4px); +} + +.cc-d5sr__image { + background: + linear-gradient(135deg, rgb(2 121 126 / 10%), rgb(217 164 65 / 12%)), + #edf3f2; +} + +.cc-d5sr__content { + gap: 11px; + padding: clamp(15px, 1.7vw, 21px); +} + +.cc-d5sr__meta { + gap: 7px 10px; + font-size: 0.73rem; + letter-spacing: 0.015em; +} + +.cc-d5sr__badge { + padding: 0.38em 0.72em; + border: 1px solid color-mix(in srgb, var(--cc-d5sr-accent) 34%, transparent); + color: color-mix(in srgb, var(--cc-d5sr-accent) 82%, #162a2b); + background: color-mix(in srgb, var(--cc-d5sr-accent) 11%, #fff); + font-size: 0.72rem; + font-weight: 800; + letter-spacing: 0.02em; +} + +.cc-d5sr__title { + font-size: clamp(1.05rem, 1.35vw, 1.36rem); + line-height: 1.16; +} + +.cc-d5sr__excerpt { + font-size: 0.92rem; + line-height: 1.55; +} + +.cc-d5sr__cta { + display: inline-flex; + gap: 0.25em; + align-items: center; + padding-top: 2px; + font-size: 0.82rem; + font-weight: 800; + letter-spacing: 0.01em; +} + +.cc-d5sr--preset-grid .cc-d5sr__card--no-image .cc-d5sr__content { + padding-top: clamp(20px, 2.2vw, 28px); +} + +.cc-d5sr--preset-grid .cc-d5sr__image { + aspect-ratio: 16 / 9; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__card::before { + display: none; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__image { + aspect-ratio: 4 / 3; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__content { + padding-top: 15px; +} + +.cc-d5sr--preset-classic-card .cc-d5sr__title { + margin-top: -2px; + font-size: clamp(1.12rem, 1.5vw, 1.48rem); +} + +.cc-d5sr--preset-compact-list .cc-d5sr__results { + gap: 12px; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__card { + min-height: 118px; + grid-template-columns: clamp(132px, 18vw, 196px) minmax(0, 1fr); + border-left: 3px solid var(--cc-d5sr-accent, var(--cc-d5sr-ui-accent)); + border-radius: 14px; + box-shadow: 0 8px 22px rgb(31 49 49 / 7%); +} + +.cc-d5sr--preset-compact-list .cc-d5sr__card::before { + display: none; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__card:hover { + box-shadow: 0 13px 30px rgb(31 49 49 / 12%); + transform: translateX(3px); +} + +.cc-d5sr--preset-compact-list .cc-d5sr__image { + min-height: 118px; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__content { + gap: 6px 18px; + padding: 14px 18px; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__title { + font-size: clamp(1rem, 1.25vw, 1.24rem); +} + +.cc-d5sr--preset-compact-list .cc-d5sr__excerpt { + font-size: 0.86rem; + line-height: 1.42; +} + +.cc-d5sr--preset-compact-list .cc-d5sr__cta { + padding: 8px 12px; + border: 1px solid color-mix(in srgb, var(--cc-d5sr-accent) 26%, transparent); + border-radius: 999px; + background: color-mix(in srgb, var(--cc-d5sr-accent) 7%, #fff); +} + +.cc-d5sr__pagination { + display: flex; + justify-content: center; + padding-top: 4px; +} + +.cc-d5sr__pagination .page-numbers { + justify-content: center; + padding: 5px; + border: 1px solid var(--cc-d5sr-border); + border-radius: 999px; + background: rgb(255 255 255 / 86%); + box-shadow: 0 8px 24px rgb(31 49 49 / 7%); +} + +.cc-d5sr__pagination a, +.cc-d5sr__pagination span { + min-width: 38px; + min-height: 38px; + border: 0; + background: transparent; + font-size: 0.82rem; +} + +.cc-d5sr__pagination a:hover, +.cc-d5sr__pagination a:focus-visible, +.cc-d5sr__pagination .current { + box-shadow: 0 6px 14px rgb(2 121 126 / 18%); +} + +@container (max-width: 760px) { + .cc-d5sr__inner { + padding: 15px; + border-radius: 17px; + } + + .cc-d5sr__content { + padding: 15px; + } +} + +@media (max-width: 980px) { + .cc-d5sr__inner { + padding: clamp(15px, 2.5vw, 22px); + } +} + +@media (max-width: 767px) { + .cc-d5sr__search { + grid-template-columns: 1fr; + padding: 5px; + border-radius: 13px; + } + + .cc-d5sr__search button { + width: 100%; + } + + .cc-d5sr__results { + grid-template-columns: repeat(var(--cc-d5sr-columns-phone, 1), minmax(0, 1fr)); + } + + .cc-d5sr--preset-compact-list .cc-d5sr__card { + min-height: 104px; + grid-template-columns: 96px minmax(0, 1fr); + } + + .cc-d5sr--preset-compact-list .cc-d5sr__image { + min-height: 104px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__content { + padding: 10px 11px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__meta { + gap: 5px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__badge { + max-width: 120px; + } + + .cc-d5sr--preset-compact-list .cc-d5sr__cta { + padding: 0; + border: 0; + background: transparent; + } +} From 93a606163f90a0e517d2acc35de9b1fa157c62d4 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:38:46 +0200 Subject: [PATCH 73/78] style: enqueue polished preset theme --- includes/Plugin.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/includes/Plugin.php b/includes/Plugin.php index d089966..d36a85e 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -39,6 +39,13 @@ public static function enqueueFrontendAssets(): void { CC_D5SR_VERSION ); + wp_enqueue_style( + 'cc-divi5-search-results-theme', + CC_D5SR_URL . 'assets/css/search-results-theme.css', + array( 'cc-divi5-search-results' ), + CC_D5SR_VERSION + ); + wp_enqueue_script( 'cc-divi5-search-results', CC_D5SR_URL . 'assets/js/search-results.js', From 9310493a4645aee84b7a81c58c9a1e9af5dea5c7 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:40:35 +0200 Subject: [PATCH 74/78] fix: default invalid page sizes to ten results --- includes/Query/SearchQueryResolver.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/includes/Query/SearchQueryResolver.php b/includes/Query/SearchQueryResolver.php index 3709002..de15439 100644 --- a/includes/Query/SearchQueryResolver.php +++ b/includes/Query/SearchQueryResolver.php @@ -9,11 +9,12 @@ final class SearchQueryResolver { * @param array $options */ public function resolve( array $options ): QueryResult { - $source = sanitize_key( (string) ( $options['source'] ?? 'current' ) ); - $posts_per_page = max( 1, min( 100, (int) ( $options['posts_per_page'] ?? 10 ) ) ); - $current_page = max( 1, (int) ( $options['current_page'] ?? $this->currentPage() ) ); - $post_types = $this->sanitizePostTypes( $options['post_types'] ?? array() ); - $requested_term = sanitize_text_field( (string) ( $options['search_term'] ?? '' ) ); + $source = sanitize_key( (string) ( $options['source'] ?? 'current' ) ); + $requested_page_size = (int) ( $options['posts_per_page'] ?? 10 ); + $posts_per_page = 0 < $requested_page_size ? min( 100, $requested_page_size ) : 10; + $current_page = max( 1, (int) ( $options['current_page'] ?? $this->currentPage() ) ); + $post_types = $this->sanitizePostTypes( $options['post_types'] ?? array() ); + $requested_term = sanitize_text_field( (string) ( $options['search_term'] ?? '' ) ); if ( 'current' === $source ) { $current = $this->currentSearchQuery(); From 98208d6a0f3b158992a6e28ce25e6a1c502bd751 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:41:23 +0200 Subject: [PATCH 75/78] docs: record page-size and preset polish fixes --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3847345..b577446 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,8 @@ - Optional progressive AJAX pagination with loading state, browser history, focus restoration and classic navigation fallback. - Frontend JavaScript syntax validation through `npm run check:frontend`. - Custom CSS selector targets for summary, search form, results, cards, images, titles and pagination. +- A second frontend theme layer with polished panel, form, card, list and pagination presentation. +- `cc_d5sr_current_query_args` filter for the private query derived from the current search request. ### Changed @@ -52,3 +54,10 @@ - Existing child modules that still contain the old exact default CTA `View result` are rendered as `Vedi risultato`; custom CTA labels are left untouched. - Frontend presentation now styles the search form, cards, metadata, pagination, loading state, focus states and reduced-motion behavior. - Parent and child module metadata now use the native Divi 5 `adminLabel` and `htmlAttributes` schema. +- `source=current` now derives a private query from the current WordPress search context so module post types, page size and pagination are honored without mutating `$wp_query`. + +### Fixed + +- The **Results per page** control is no longer ignored on real WordPress search pages or AJAX pagination requests. +- Empty or invalid page-size values now fall back to 10 instead of collapsing to one result. +- Grid column counts and result page sizes now operate independently, so a five-column layout can render the configured number of posts per page. From de4aef86a2ac1560b5558668f37792f7b9619a90 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:42:52 +0200 Subject: [PATCH 76/78] docs: define module-owned pagination and polished presets --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c7ab569..558133e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ A public Divi 5 extension for type-aware WordPress search results. The native pa The `0.1.0` development branch currently includes: - safe plugin bootstrap with Composer PSR-4 autoloading and a source-checkout fallback autoloader; -- reuse of the real current WordPress search query without calling `query_posts()` or replacing global `$wp_query`; +- a private query derived from the real current WordPress search context without calling `query_posts()` or replacing global `$wp_query`; +- module-owned post types, results per page and pagination for both current and isolated query sources; - isolated `WP_Query` resolution for Visual Builder previews, normal pages and shortcode use; - parent module `codecorn/search-results`, displayed as **CC Search Results**; - child module `codecorn/search-result-type`, displayed as **CC Result Type**; @@ -21,7 +22,7 @@ The `0.1.0` development branch currently includes: - progressive AJAX pagination with loading state, URL history, focus restoration and classic-link fallback; - Italian frontend defaults for search, count, empty state, pagination and CTA labels; - shared rendering used by the native module and `[cc_divi5_search_results]`; -- responsive frontend styling for form, cards, metadata, pagination, empty state and reduced motion; +- responsive frontend styling plus a polished theme layer for form, cards, metadata, pagination, empty state and reduced motion; - Visual Builder TypeScript sources and webpack build; - deterministic runtime packaging with build manifest and SHA-256 checksum; - VM deployment for host and Docker WordPress installations with backup and rollback; @@ -45,9 +46,9 @@ CC Search Results (codecorn/search-results) ### Query -- current WordPress search query or isolated query; +- current WordPress search context or isolated query; - explicit search term for isolated queries and Builder previews; -- results per page. +- results per page from 1 to 100; empty or invalid values fall back to 10. ### Layout and navigation @@ -57,6 +58,8 @@ CC Search Results (codecorn/search-results) - responsive columns for desktop, tablet and phone; - AJAX pagination on or off. +The column count and results-per-page value are independent. A five-column grid can therefore render 5, 10, 15 or any other configured page size rather than inheriting the site's global search limit. + ### Empty state - title; @@ -78,6 +81,23 @@ The columns control is ignored by this preset because it is intentionally a one- The image appears above the content. The title is the first element immediately below the image, followed by metadata, description and CTA. The responsive column control is applied at each Divi breakpoint. +The default presentation is split into a structural stylesheet and a theme stylesheet: + +```text +assets/css/search-results.css +assets/css/search-results-theme.css +``` + +The theme layer provides the panel, search form, card depth, rule accents, compact-list treatment and pill pagination while retaining CSS custom properties for site-level overrides. + +Divi breakpoints used by the responsive layout are: + +```text +desktop: above 980px +tablet: 768px–980px +phone: 767px and below +``` + ## Result-type controls - public WordPress post type selected from the current site's registered list; @@ -107,9 +127,22 @@ Missing labels fall back to the registered post-type labels. Missing rules fall ## Query contract -For `source=current`, the module reads the already-resolved main WordPress search query. It does not mutate it. +For `source=current`, the module reads the resolved main WordPress search query variables and creates a separate `WP_Query`. It preserves the current search term and compatible query context, then explicitly applies the module's selected post types, results-per-page value and current page. The global `$wp_query` and its posts are never changed. + +Integrations can adjust this private query: + +```php +add_filter( + 'cc_d5sr_current_query_args', + function ( array $query_args, array $options, WP_Query $current_query ): array { + return $query_args; + }, + 10, + 3 +); +``` -For `source=isolated`, the plugin creates its own query using the search term, configured result types, result limit and current page. Integrations can adjust only that isolated query: +For `source=isolated`, the plugin creates its own query using the search term, configured result types, result limit and current page: ```php add_filter( 'cc_d5sr_query_args', function ( array $query_args, array $options ): array { @@ -123,12 +156,13 @@ AJAX pagination is progressive enhancement rather than a second query endpoint: 1. pagination still renders normal WordPress links; 2. the frontend runtime fetches the real target page; -3. it locates the same module instance in the returned document; -4. it replaces only that module's inner result output; -5. it updates browser history, scrolls to the module and restores keyboard focus; -6. a failed request or missing module instance falls back to the normal page navigation. +3. the server derives the module query again with the saved page size and result-type rules; +4. the runtime locates the same module instance in the returned document; +5. it replaces only that module's inner result output; +6. it updates browser history, scrolls to the module and restores keyboard focus; +7. a failed request or missing module instance falls back to the normal page navigation. -This preserves the current WordPress search query, Theme Builder layout, third-party query filters and canonical paginated URLs. Disabling **AJAX pagination** leaves the normal links untouched. +This preserves the search request context, Theme Builder layout, compatible third-party query filters and canonical paginated URLs while keeping page size under module control. Disabling **AJAX pagination** leaves the normal links untouched and produces the same result count per page. ## Optional shortcode @@ -221,6 +255,7 @@ The runtime archive contains: ```text cc-divi5-search-results.php assets/css/search-results.css +assets/css/search-results-theme.css assets/js/search-results.js includes/ modules/ From 5aa6febe3878f5f9e61fb2d37638dd626957d5f2 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:44:33 +0200 Subject: [PATCH 77/78] fix: bust caches for rebuilt frontend assets --- includes/Plugin.php | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/includes/Plugin.php b/includes/Plugin.php index d36a85e..632d820 100644 --- a/includes/Plugin.php +++ b/includes/Plugin.php @@ -36,21 +36,21 @@ public static function enqueueFrontendAssets(): void { 'cc-divi5-search-results', CC_D5SR_URL . 'assets/css/search-results.css', array(), - CC_D5SR_VERSION + self::assetVersion( 'assets/css/search-results.css' ) ); wp_enqueue_style( 'cc-divi5-search-results-theme', CC_D5SR_URL . 'assets/css/search-results-theme.css', array( 'cc-divi5-search-results' ), - CC_D5SR_VERSION + self::assetVersion( 'assets/css/search-results-theme.css' ) ); wp_enqueue_script( 'cc-divi5-search-results', CC_D5SR_URL . 'assets/js/search-results.js', array(), - CC_D5SR_VERSION, + self::assetVersion( 'assets/js/search-results.js' ), true ); } @@ -104,7 +104,7 @@ public static function registerVisualBuilderAssets(): void { \ET\Builder\VisualBuilder\Assets\PackageBuildManager::register_package_build( array( 'name' => 'cc-divi5-search-results-vb', - 'version' => CC_D5SR_VERSION, + 'version' => self::assetVersion( 'scripts/bundle.js' ), 'script' => array( 'src' => CC_D5SR_URL . 'scripts/bundle.js', 'deps' => array( @@ -124,7 +124,7 @@ public static function registerVisualBuilderAssets(): void { \ET\Builder\VisualBuilder\Assets\PackageBuildManager::register_package_build( array( 'name' => 'cc-divi5-search-results-vb-style', - 'version' => CC_D5SR_VERSION, + 'version' => self::assetVersion( 'styles/vb-bundle.css' ), 'style' => array( 'src' => CC_D5SR_URL . 'styles/vb-bundle.css', 'deps' => array(), @@ -136,6 +136,15 @@ public static function registerVisualBuilderAssets(): void { } } + private static function assetVersion( string $relative_path ): string { + $path = CC_D5SR_DIR . ltrim( $relative_path, '/' ); + $time = is_readable( $path ) ? filemtime( $path ) : false; + + return false !== $time + ? CC_D5SR_VERSION . '.' . (string) $time + : CC_D5SR_VERSION; + } + /** * Return public WordPress post types as Divi select options. * From 56d22a470b6c1262bae09484981258ba3c13bd16 Mon Sep 17 00:00:00 2001 From: Federico Girolami <68548715+fgirolami29@users.noreply.github.com> Date: Thu, 30 Jul 2026 05:45:55 +0200 Subject: [PATCH 78/78] docs: record asset cache busting --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b577446..3346cda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ - Frontend presentation now styles the search form, cards, metadata, pagination, loading state, focus states and reduced-motion behavior. - Parent and child module metadata now use the native Divi 5 `adminLabel` and `htmlAttributes` schema. - `source=current` now derives a private query from the current WordPress search context so module post types, page size and pagination are honored without mutating `$wp_query`. +- Frontend CSS, JavaScript and Visual Builder bundles now use version-plus-filemtime cache keys during iterative deployments. ### Fixed