UNPKG

pp-seo

Version:

`pp-seo` is a standalone Angular library that provides a highly configurable, sectioned form for managing all SEO (Search Engine Optimization) properties in your Angular applications. It supports a wide range of SEO fields, grouped into logical sections,

928 lines 101 kB
import * as i0 from '@angular/core';
import { EventEmitter, forwardRef, Output, Input, Component } from '@angular/core';
import * as i1 from '@angular/forms';
import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';

var FieldTypes;
(function (FieldTypes) {
    FieldTypes["TEXT"] = "text";
    FieldTypes["TEXTAREA"] = "textarea";
    FieldTypes["ARRAY"] = "array";
    FieldTypes["DROPDOWN"] = "dropdown";
    FieldTypes["CHECKBOX"] = "checkbox";
    FieldTypes["MULTISELECT"] = "multiselect";
})(FieldTypes || (FieldTypes = {}));
var HINTS;
(function (HINTS) {
    HINTS["TEXT"] = "Enter text";
    HINTS["TEXTAREA"] = "Enter text";
    HINTS["ARRAY"] = "Enter text and press Enter to add";
    HINTS["DROPDOWN"] = "Select an option";
    HINTS["CHECKBOX"] = "Toggle the checkbox";
    HINTS["DEFAULT"] = "Enter value";
})(HINTS || (HINTS = {}));
class Seo {
    properties = this.getNewSeoProperties();
    propertiesChange = new EventEmitter();
    FIELD_TYPES = FieldTypes;
    HINTS = HINTS;
    onChange = (_) => { };
    onTouched = () => { };
    // Update a field value in the sectioned structure
    updateProperty(sectionKey, fieldKey, value) {
        if (this.properties.sections[sectionKey]?.fields) {
            this.properties.sections[sectionKey].fields[fieldKey].value =
                value;
        }
        this.validateAll();
        this.onChange(this.properties);
        this.propertiesChange.emit(this.properties);
    }
    // Sectioned invalid fields
    invalidFields = {};
    validateAll() {
        let valid = true;
        this.invalidFields = {};
        // Validate each section
        for (const [sectionKey, section] of Object.entries(this.properties.sections)) {
            this.invalidFields[sectionKey] = {};
            for (const [fieldKey, field] of Object.entries(section.fields)) {
                this.invalidFields[sectionKey][fieldKey] = false;
                if (field.hidden)
                    continue;
                if (field.validation?.required && !field.value) {
                    this.invalidFields[sectionKey][fieldKey] = true;
                    valid = false;
                    continue;
                }
                if (field.value &&
                    field.validation?.maxLength &&
                    typeof field.value === 'string' &&
                    field.value.length > field.validation.maxLength) {
                    this.invalidFields[sectionKey][fieldKey] = true;
                    valid = false;
                }
                if (field.value &&
                    field.validation?.pattern &&
                    typeof field.value === 'string' &&
                    !field.validation.pattern.test(field.value)) {
                    this.invalidFields[sectionKey][fieldKey] = true;
                    valid = false;
                }
            }
        }
        return valid;
    }
    // Add item to array field
    addArrayItem(sectionKey, fieldKey, event) {
        event.preventDefault();
        const section = this.properties.sections[sectionKey];
        if (!section)
            return;
        const field = section.fields[fieldKey];
        if (!field || !field._input)
            return;
        if (!Array.isArray(field.value))
            field.value = [];
        if (field._input.trim() && !field.value.includes(field._input.trim())) {
            field.value.push(field._input.trim());
        }
        field._input = '';
        this.onChange(this.properties);
        this.propertiesChange.emit(this.properties);
    }
    // Remove item from array field
    removeArrayItem(sectionKey, fieldKey, idx) {
        const section = this.properties.sections[sectionKey];
        if (!section)
            return;
        const field = section.fields[fieldKey];
        if (!field || !Array.isArray(field.value))
            return;
        field.value.splice(idx, 1);
        this.onChange(this.properties);
        this.propertiesChange.emit(this.properties);
    }
    // Helper for template type safety
    asField(entry) {
        return entry.value;
    }
    writeValue(obj) {
        if (obj) {
            this.properties = obj;
        }
    }
    registerOnChange(fn) {
        this.onChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    getNewSeoProperties() {
        return {
            sections: {
                coreMeta: {
                    label: 'Core Meta Tags',
                    fields: {
                        title: {
                            value: '',
                            label: 'Title Tag',
                            description: 'The title of the page (50-60 characters recommended)',
                            type: FieldTypes.TEXT,
                            validation: { required: true, maxLength: 60 },
                            hidden: false,
                            disabled: false,
                        },
                        description: {
                            value: '',
                            label: 'Meta Description',
                            description: 'Page description (150-160 characters recommended)',
                            type: FieldTypes.TEXTAREA,
                            validation: { maxLength: 160, required: false },
                            hidden: false,
                            disabled: false,
                        },
                        keywords: {
                            value: [],
                            label: 'Meta Keywords',
                            description: 'Comma-separated keywords (less important today)',
                            type: FieldTypes.ARRAY,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        canonicalUrl: {
                            value: '',
                            label: 'Canonical URL',
                            description: 'Preferred URL for this page to avoid duplicate content',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        robotsMeta: {
                            value: 'index, follow',
                            label: 'Robots Meta',
                            description: 'Controls how search engines index the page',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        viewport: {
                            value: 'width=device-width, initial-scale=1',
                            label: 'Viewport',
                            description: 'Controls mobile viewport behavior',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        charset: {
                            value: 'utf-8',
                            label: 'Charset',
                            description: 'Character encoding for the page',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 20 },
                            hidden: false,
                            disabled: false,
                        },
                        language: {
                            value: 'en',
                            label: 'Language',
                            description: 'Primary language of the page',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 10 },
                            hidden: false,
                            disabled: false,
                        },
                        author: {
                            value: '',
                            label: 'Author',
                            description: 'Author of the page content',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        publisher: {
                            value: '',
                            label: 'Publisher',
                            description: 'Publisher of the page content',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        rating: {
                            value: 'general',
                            label: 'Rating',
                            description: 'Content rating (general, mature, restricted, etc.)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 20 },
                            hidden: false,
                            disabled: false,
                        },
                        copyright: {
                            value: '',
                            label: 'Copyright',
                            description: 'Copyright information',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        generator: {
                            value: '',
                            label: 'Generator',
                            description: 'Software used to generate the page',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        replyTo: {
                            value: '',
                            label: 'Reply-To',
                            description: 'Contact for content questions',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        contentType: {
                            value: 'text/html',
                            label: 'Content-Type',
                            description: 'MIME type of the page content',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                crawlingAndIndex: {
                    label: 'Crawling & Indexing',
                    fields: {
                        noindex: {
                            value: false,
                            label: 'Noindex',
                            description: 'Prevent search engines from indexing this page',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        nofollow: {
                            value: false,
                            label: 'Nofollow',
                            description: 'Prevent search engines from following links on this page',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        noimageindex: {
                            value: false,
                            label: 'Noimageindex',
                            description: 'Prevent search engines from indexing images on this page',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        noarchive: {
                            value: false,
                            label: 'Noarchive',
                            description: 'Prevent search engines from showing cached version',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        nosnippet: {
                            value: false,
                            label: 'Nosnippet',
                            description: 'Prevent search engines from showing snippets',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        notranslate: {
                            value: false,
                            label: 'Notranslate',
                            description: 'Prevent search engines from offering translation',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        unavailableAfter: {
                            value: '',
                            label: 'Unavailable After',
                            description: 'Date when page should stop being indexed (YYYY-MM-DD)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, pattern: /^\d{4}-\d{2}-\d{2}$/ },
                            hidden: false,
                            disabled: false,
                        },
                        paginatedPrev: {
                            value: '',
                            label: 'Previous Page URL',
                            description: 'URL of previous page in paginated series',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        paginatedNext: {
                            value: '',
                            label: 'Next Page URL',
                            description: 'URL of next page in paginated series',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                cacheControl: {
                    label: 'Cache & Refresh Control',
                    fields: {
                        cacheControl: {
                            value: '',
                            label: 'Cache-Control',
                            description: 'Directives for caching mechanisms',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        pragma: {
                            value: '',
                            label: 'Pragma',
                            description: 'Legacy HTTP 1.0 cache control',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        expires: {
                            value: '',
                            label: 'Expires',
                            description: 'Date/time when cache expires',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        refresh: {
                            value: '',
                            label: 'Refresh',
                            description: 'Page refresh interval in seconds',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 20 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                socialMedia: {
                    label: 'Social Media & Open Graph',
                    fields: {
                        ogTitle: {
                            value: '',
                            label: 'OG Title',
                            description: 'Title for social media sharing',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        ogDescription: {
                            value: '',
                            label: 'OG Description',
                            description: 'Description for social media sharing',
                            type: FieldTypes.TEXTAREA,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        ogType: {
                            value: 'website',
                            label: 'OG Type',
                            description: 'Type of content (article, website, etc.)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        ogUrl: {
                            value: '',
                            label: 'OG URL',
                            description: 'Canonical URL for social sharing',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        ogImage: {
                            value: '',
                            label: 'OG Image',
                            description: 'Image URL for social sharing',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        ogImageAlt: {
                            value: '',
                            label: 'OG Image Alt',
                            description: 'Alt text for social sharing image',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        ogImageWidth: {
                            value: '',
                            label: 'OG Image Width',
                            description: 'Width of social sharing image in pixels',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 10 },
                            hidden: false,
                            disabled: false,
                        },
                        ogImageHeight: {
                            value: '',
                            label: 'OG Image Height',
                            description: 'Height of social sharing image in pixels',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 10 },
                            hidden: false,
                            disabled: false,
                        },
                        ogSiteName: {
                            value: '',
                            label: 'OG Site Name',
                            description: 'Name of the website',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        ogLocale: {
                            value: 'en_US',
                            label: 'OG Locale',
                            description: 'Locale of the content (en_US, etc.)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 10 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterCard: {
                            value: 'summary',
                            label: 'Twitter Card Type',
                            description: 'Type of Twitter card (summary, summary_large_image, etc.)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 30 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterTitle: {
                            value: '',
                            label: 'Twitter Title',
                            description: 'Title for Twitter sharing',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 70 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterDescription: {
                            value: '',
                            label: 'Twitter Description',
                            description: 'Description for Twitter sharing',
                            type: FieldTypes.TEXTAREA,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterImage: {
                            value: '',
                            label: 'Twitter Image',
                            description: 'Image URL for Twitter sharing',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterImageAlt: {
                            value: '',
                            label: 'Twitter Image Alt',
                            description: 'Alt text for Twitter image',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterSite: {
                            value: '',
                            label: 'Twitter Site',
                            description: '@username of website',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        twitterCreator: {
                            value: '',
                            label: 'Twitter Creator',
                            description: '@username of content creator',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        fbAppId: {
                            value: '',
                            label: 'Facebook App ID',
                            description: 'For Facebook Insights',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        pinterestDescription: {
                            value: '',
                            label: 'Pinterest Description',
                            description: 'Description for Pinterest sharing',
                            type: FieldTypes.TEXTAREA,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        pinterestMedia: {
                            value: '',
                            label: 'Pinterest Media',
                            description: 'Image URL for Pinterest sharing',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        pinterestNoPin: {
                            value: false,
                            label: 'Pinterest No Pin',
                            description: 'Disable pinning of this page',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                mobileApp: {
                    label: 'Mobile & App-Specific',
                    fields: {
                        appleTouchIcon: {
                            value: '',
                            label: 'Apple Touch Icon',
                            description: 'URL of icon for iOS home screen',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                        appleMobileWebAppCapable: {
                            value: false,
                            label: 'Apple Mobile Web App Capable',
                            description: 'Enable full-screen mode on iOS',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        appleStatusBarStyle: {
                            value: 'default',
                            label: 'Apple Status Bar Style',
                            description: 'Style of iOS status bar (default, black, black-translucent)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 20 },
                            hidden: false,
                            disabled: false,
                        },
                        mobileWebAppCapable: {
                            value: false,
                            label: 'Mobile Web App Capable',
                            description: 'Enable full-screen mode on Android',
                            type: FieldTypes.CHECKBOX,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        themeColor: {
                            value: '',
                            label: 'Theme Color',
                            description: 'Color of browser UI (hex code)',
                            type: FieldTypes.TEXT,
                            validation: {
                                required: false,
                                maxLength: 7,
                                pattern: /^#[0-9A-F]{6}$/i,
                            },
                            hidden: false,
                            disabled: false,
                        },
                        msTileColor: {
                            value: '',
                            label: 'Microsoft Tile Color',
                            description: 'Color of Windows tile (hex code)',
                            type: FieldTypes.TEXT,
                            validation: {
                                required: false,
                                maxLength: 7,
                                pattern: /^#[0-9A-F]{6}$/i,
                            },
                            hidden: false,
                            disabled: false,
                        },
                        msTileImage: {
                            value: '',
                            label: 'Microsoft Tile Image',
                            description: 'Image URL for Windows tile',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                structuredData: {
                    label: 'Structured Data',
                    fields: {
                        jsonLd: {
                            value: '',
                            label: 'JSON-LD',
                            description: 'Structured data in JSON-LD format',
                            type: FieldTypes.TEXTAREA,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                alternateTags: {
                    label: 'Alternate Tags',
                    fields: {
                        hreflang: {
                            value: [],
                            label: 'Hreflang',
                            description: 'Alternate language versions (format: language-code|url)',
                            type: FieldTypes.ARRAY,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        alternateMedia: {
                            value: '',
                            label: 'Alternate Media',
                            description: 'Media query for alternate version',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        alternateFormat: {
                            value: '',
                            label: 'Alternate Format',
                            description: 'Alternate format (e.g., PDF)',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                siteVerification: {
                    label: 'Site Verification',
                    fields: {
                        googleSiteVerification: {
                            value: '',
                            label: 'Google Verification',
                            description: 'Google Search Console verification code',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        bingSiteVerification: {
                            value: '',
                            label: 'Bing Verification',
                            description: 'Bing Webmaster Tools verification code',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        yandexVerification: {
                            value: '',
                            label: 'Yandex Verification',
                            description: 'Yandex Webmaster verification code',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        pinterestVerification: {
                            value: '',
                            label: 'Pinterest Verification',
                            description: 'Pinterest verification code',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        facebookDomainVerification: {
                            value: '',
                            label: 'Facebook Verification',
                            description: 'Facebook Domain verification code',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                        nortonSafeWeb: {
                            value: '',
                            label: 'Norton Safe Web',
                            description: 'Norton Safe Web verification code',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 100 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                securityPrivacy: {
                    label: 'Security & Privacy',
                    fields: {
                        referrerPolicy: {
                            value: 'strict-origin-when-cross-origin',
                            label: 'Referrer Policy',
                            description: 'Controls referrer information sent with requests',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        contentSecurityPolicy: {
                            value: '',
                            label: 'Content Security Policy',
                            description: 'Security policy for resources',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 500 },
                            hidden: false,
                            disabled: false,
                        },
                        permissionsPolicy: {
                            value: '',
                            label: 'Permissions Policy',
                            description: 'Controls browser features and APIs',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 500 },
                            hidden: false,
                            disabled: false,
                        },
                        xuaCompatible: {
                            value: 'IE=edge',
                            label: 'X-UA-Compatible',
                            description: 'Forces IE to use latest rendering engine',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                        xframeOptions: {
                            value: 'SAMEORIGIN',
                            label: 'X-Frame-Options',
                            description: 'Controls if page can be displayed in a frame',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 50 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
                performance: {
                    label: 'Performance',
                    fields: {
                        preconnect: {
                            value: [],
                            label: 'Preconnect',
                            description: 'Domains to preconnect to',
                            type: FieldTypes.ARRAY,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        prefetch: {
                            value: [],
                            label: 'Prefetch',
                            description: 'Resources to prefetch',
                            type: FieldTypes.ARRAY,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        preload: {
                            value: [],
                            label: 'Preload',
                            description: 'Critical resources to preload',
                            type: FieldTypes.ARRAY,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        dnsPrefetch: {
                            value: [],
                            label: 'DNS-Prefetch',
                            description: 'Domains to DNS-prefetch',
                            type: FieldTypes.ARRAY,
                            validation: { required: false },
                            hidden: false,
                            disabled: false,
                        },
                        prerender: {
                            value: '',
                            label: 'Prerender',
                            description: 'URL to prerender',
                            type: FieldTypes.TEXT,
                            validation: { required: false, maxLength: 200 },
                            hidden: false,
                            disabled: false,
                        },
                    },
                    hidden: false,
                    disabled: false,
                },
            },
            disabled: false,
        };
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Seo, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.4", type: Seo, isStandalone: true, selector: "pp-seo", inputs: { properties: "properties" }, outputs: { propertiesChange: "propertiesChange" }, host: { attributes: { "ngSkipHydration": "true" } }, providers: [
            {
                provide: NG_VALUE_ACCESSOR,
                useExisting: forwardRef(() => Seo),
                multi: true,
            },
        ], ngImport: i0, template: "<form [class.disabled]=\"properties.disabled\">\n  <!-- Core Meta Tags -->\n  @if (!properties.sections.coreMeta.hidden) {\n  <h3>{{ properties.sections.coreMeta.label }}</h3>\n  @for (field of properties.sections.coreMeta.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-coreMeta-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-coreMeta-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['coreMeta']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.TEXTAREA) {\n    <textarea\n      [id]=\"'seo-coreMeta-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['coreMeta']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    ></textarea>\n    } @case (FIELD_TYPES.ARRAY) {\n    <div class=\"custom-badge-group\">\n      <div class=\"badge-list\">\n        @for (item of field.value.value; track item) {\n        <span class=\"badge\">\n          {{ item }}\n          <button\n            type=\"button\"\n            (click)=\"removeArrayItem('coreMeta', field.key, field.value.value.indexOf(item))\"\n            [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n          >\n            &times;\n          </button>\n        </span>\n        }\n      </div>\n      <input\n        type=\"text\"\n        [placeholder]=\"field.value.description\"\n        [(ngModel)]=\"field.value._input\"\n        [ngModelOptions]=\"{standalone: true}\"\n        (keydown.enter)=\"addArrayItem('coreMeta', field.key, $event)\"\n        [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n        class=\"custom-input\"\n      />\n    </div>\n    } @case (FIELD_TYPES.DROPDOWN) {\n    <select\n      [id]=\"'seo-coreMeta-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['coreMeta']?.[field.key] }\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    >\n      @for (opt of field.value.options; track opt.value) {\n      <option [value]=\"opt.value\">{{ opt.title }}</option>\n      }\n    </select>\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-coreMeta-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['coreMeta']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (field.value.validation.pattern) { Must match required pattern. } @if\n    (!invalidFields['coreMeta']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Crawling & Indexing -->\n  @if (!properties.sections.crawlingAndIndex.hidden) {\n  <h3>{{ properties.sections.crawlingAndIndex.label }}</h3>\n  @for (field of properties.sections.crawlingAndIndex.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-crawling-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-crawling-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('crawlingAndIndex', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['crawlingAndIndex']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.crawlingAndIndex.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-crawling-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('crawlingAndIndex', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.crawlingAndIndex.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['crawlingAndIndex']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (field.value.validation.pattern) { Must match required pattern. } @if\n    (!invalidFields['crawlingAndIndex']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Cache Control -->\n  @if (!properties.sections.cacheControl.hidden) {\n  <h3>{{ properties.sections.cacheControl.label }}</h3>\n  @for (field of properties.sections.cacheControl.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-cache-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    <input\n      [id]=\"'seo-cache-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('cacheControl', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['cacheControl']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.cacheControl.disabled || properties.disabled)\"\n    />\n\n    @if (invalidFields['cacheControl']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['cacheControl']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Social Media -->\n  @if (!properties.sections.socialMedia.hidden) {\n  <h3>{{ properties.sections.socialMedia.label }}</h3>\n  @for (field of properties.sections.socialMedia.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-social-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-social-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('socialMedia', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['socialMedia']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.socialMedia.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.TEXTAREA) {\n    <textarea\n      [id]=\"'seo-social-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('socialMedia', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['socialMedia']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.socialMedia.disabled || properties.disabled)\"\n    ></textarea>\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-social-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('socialMedia', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.socialMedia.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['socialMedia']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['socialMedia']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Mobile & App-Specific -->\n  @if (!properties.sections.mobileApp.hidden) {\n  <h3>{{ properties.sections.mobileApp.label }}</h3>\n  @for (field of properties.sections.mobileApp.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-mobile-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-mobile-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('mobileApp', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['mobileApp']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.mobileApp.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-mobile-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('mobileApp', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.mobileApp.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['mobileApp']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (field.value.validation.pattern) { Must match required pattern. } @if\n    (!invalidFields['mobileApp']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Structured Data -->\n  @if (!properties.sections.structuredData.hidden) {\n  <h3>{{ properties.sections.structuredData.label }}</h3>\n  @for (field of properties.sections.structuredData.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-structured-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    <textarea\n      [id]=\"'seo-structured-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('structuredData', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['structuredData']?.[field.key] }\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.structuredData.disabled || properties.disabled)\"\n    ></textarea>\n\n    @if (invalidFields['structuredData']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. }\n    </small>\n    } @if (!invalidFields['structuredData']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Alternate Tags -->\n  @if (!properties.sections.alternateTags.hidden) {\n  <h3>{{ properties.sections.alternateTags.label }}</h3>\n  @for (field of properties.sections.alternateTags.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-alternate-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.ARRAY) {\n    <div class=\"custom-badge-group\">\n      <div class=\"badge-list\">\n        @for (item of field.value.value; track item) {\n        <span class=\"badge\">\n          {{ item }}\n          <button\n            type=\"button\"\n            (click)=\"removeArrayItem('alternateTags', field.key, field.value.value.indexOf(item))\"\n            [disabled]=\"!!(field.value.disabled || properties.sections.alternateTags.disabled || properties.disabled)\"\n          >\n            &times;\n          </button>\n        </span>\n        }\n      </div>\n      <input\n        type=\"text\"\n        [placeholder]=\"field.value.description\"\n        [(ngModel)]=\"field.value._input\"\n        [ngModelOptions]=\"{standalone: true}\"\n        (keydown.enter)=\"addArrayItem('alternateTags', field.key, $event)\"\n        [disabled]=\"!!(field.value.disabled || properties.sections.alternateTags.disabled || properties.disabled)\"\n        class=\"custom-input\"\n      />\n    </div>\n    } @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-alternate-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('alternateTags', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['alternateTags']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.alternateTags.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['alternateTags']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['alternateTags']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Site Verification -->\n  @if (!properties.sections.siteVerification.hidden) {\n  <h3>{{ properties.sections.siteVerification.label }}</h3>\n  @for (field of properties.sections.siteVerification.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-verification-' + field.key\"\n      >{{ field.value.label }}</label\n    >\n\n    <input\n      [id]=\"'seo-verification-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('siteVerification', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['siteVerification']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.siteVerification.disabled || properties.disabled)\"\n    />\n\n    @if (invalidFields['siteVerification']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['siteVerification']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Security & Privacy -->\n  @if (!properties.sections.securityPrivacy.hidden) {\n  <h3>{{ properties.sections.securityPrivacy.label }}</h3>\n  @for (field of properties.sections.securityPrivacy.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-security-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    <input\n      [id]=\"'seo-security-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('securityPrivacy', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['securityPrivacy']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.securityPrivacy.disabled || properties.disabled)\"\n    />\n\n    @if (invalidFields['securityPrivacy']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['securityPrivacy']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Performance -->\n  @if (!properties.sections.performance.hidden) {\n  <h3>{{ properties.sections.performance.label }}</h3>\n  @for (field of properties.sections.performance.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-performance-' + field.key\"\n      >{{ field.value.label }}</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.ARRAY) {\n    <div class=\"custom-badge-group\">\n      <div class=\"badge-list\">\n        @for (item of field.value.value; track item) {\n        <span class=\"badge\">\n          {{ item }}\n          <button\n            type=\"button\"\n            (click)=\"removeArrayItem('performance', field.key, field.value.value.indexOf(item))\"\n            [disabled]=\"!!(field.value.disabled || properties.sections.performance.disabled || properties.disabled)\"\n          >\n            &times;\n          </button>\n        </span>\n        }\n      </div>\n      <input\n        type=\"text\"\n        [placeholder]=\"field.value.description\"\n        [(ngModel)]=\"field.value._input\"\n        [ngModelOptions]=\"{standalone: true}\"\n        (keydown.enter)=\"addArrayItem('performance', field.key, $event)\"\n        [disabled]=\"!!(field.value.disabled || properties.sections.performance.disabled || properties.disabled)\"\n        class=\"custom-input\"\n      />\n    </div>\n    } @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-performance-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('performance', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['performance']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.performance.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['performance']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['performance']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n</form>\n", styles: [".custom-input-group,.custom-badge-group{display:flex;flex-direction:column;margin-bottom:1.5rem}.custom-input-group label,.custom-badge-group label{font-size:1rem;color:#495057;margin-bottom:.5rem;font-weight:500}.input-description{font-size:.85rem;color:#888;margin-top:.25rem}.custom-input{padding:.75rem 1rem;border:1px solid #ced4da;border-radius:4px;font-size:1rem;transition:border-color .2s,box-shadow .2s;outline:none;background:#fff;color:#495057;box-shadow:none}.custom-input:focus{border-color:#2196f3;box-shadow:0 0 0 .2rem #2196f326}.custom-input:disabled{background:#f5f5f5;color:#bdbdbd}.custom-input.invalid{border-color:#e53935;box-shadow:0 0 0 .2rem #e5393526}.badge-list{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:.5rem}.badge{display:inline-flex;align-items:center;background:#e3f2fd;color:#1976d2;border-radius:12px;padding:.25rem .75rem;font-size:.95rem;margin-right:.25rem;margin-bottom:.25rem;border:1px solid #90caf9}.badge button{background:none;border:none;color:#1976d2;font-size:1.1em;margin-left:.5em;cursor:pointer;padding:0;line-height:1}.badge button:disabled{color:#bdbdbd;cursor:not-allowed}form.disabled{pointer-events:none;opacity:.7}select.custom-input{min-width:120px}textarea.custom-input{min-height:80px;resize:vertical}.input-hint{display:inline-block;margin-left:.5rem;font-size:.92em;color:#7b8a99;background:#f4f7fa;border-radius:8px;padding:.1em .7em;font-style:italic;vertical-align:middle}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i2.KeyValuePipe, name: "keyvalue" }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.4", ngImport: i0, type: Seo, decorators: [{
            type: Component,
            args: [{ selector: 'pp-seo', standalone: true, imports: [FormsModule, CommonModule], providers: [
                        {
                            provide: NG_VALUE_ACCESSOR,
                            useExisting: forwardRef(() => Seo),
                            multi: true,
                        },
                    ], host: {
                        ngSkipHydration: 'true',
                    }, template: "<form [class.disabled]=\"properties.disabled\">\n  <!-- Core Meta Tags -->\n  @if (!properties.sections.coreMeta.hidden) {\n  <h3>{{ properties.sections.coreMeta.label }}</h3>\n  @for (field of properties.sections.coreMeta.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-coreMeta-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-coreMeta-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['coreMeta']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.TEXTAREA) {\n    <textarea\n      [id]=\"'seo-coreMeta-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['coreMeta']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    ></textarea>\n    } @case (FIELD_TYPES.ARRAY) {\n    <div class=\"custom-badge-group\">\n      <div class=\"badge-list\">\n        @for (item of field.value.value; track item) {\n        <span class=\"badge\">\n          {{ item }}\n          <button\n            type=\"button\"\n            (click)=\"removeArrayItem('coreMeta', field.key, field.value.value.indexOf(item))\"\n            [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n          >\n            &times;\n          </button>\n        </span>\n        }\n      </div>\n      <input\n        type=\"text\"\n        [placeholder]=\"field.value.description\"\n        [(ngModel)]=\"field.value._input\"\n        [ngModelOptions]=\"{standalone: true}\"\n        (keydown.enter)=\"addArrayItem('coreMeta', field.key, $event)\"\n        [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n        class=\"custom-input\"\n      />\n    </div>\n    } @case (FIELD_TYPES.DROPDOWN) {\n    <select\n      [id]=\"'seo-coreMeta-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['coreMeta']?.[field.key] }\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    >\n      @for (opt of field.value.options; track opt.value) {\n      <option [value]=\"opt.value\">{{ opt.title }}</option>\n      }\n    </select>\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-coreMeta-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('coreMeta', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.coreMeta.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['coreMeta']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (field.value.validation.pattern) { Must match required pattern. } @if\n    (!invalidFields['coreMeta']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Crawling & Indexing -->\n  @if (!properties.sections.crawlingAndIndex.hidden) {\n  <h3>{{ properties.sections.crawlingAndIndex.label }}</h3>\n  @for (field of properties.sections.crawlingAndIndex.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-crawling-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-crawling-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('crawlingAndIndex', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['crawlingAndIndex']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.crawlingAndIndex.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-crawling-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('crawlingAndIndex', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.crawlingAndIndex.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['crawlingAndIndex']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (field.value.validation.pattern) { Must match required pattern. } @if\n    (!invalidFields['crawlingAndIndex']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Cache Control -->\n  @if (!properties.sections.cacheControl.hidden) {\n  <h3>{{ properties.sections.cacheControl.label }}</h3>\n  @for (field of properties.sections.cacheControl.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-cache-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    <input\n      [id]=\"'seo-cache-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('cacheControl', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['cacheControl']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.cacheControl.disabled || properties.disabled)\"\n    />\n\n    @if (invalidFields['cacheControl']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['cacheControl']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Social Media -->\n  @if (!properties.sections.socialMedia.hidden) {\n  <h3>{{ properties.sections.socialMedia.label }}</h3>\n  @for (field of properties.sections.socialMedia.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-social-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-social-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('socialMedia', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['socialMedia']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.socialMedia.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.TEXTAREA) {\n    <textarea\n      [id]=\"'seo-social-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('socialMedia', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['socialMedia']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.socialMedia.disabled || properties.disabled)\"\n    ></textarea>\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-social-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('socialMedia', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.socialMedia.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['socialMedia']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['socialMedia']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Mobile & App-Specific -->\n  @if (!properties.sections.mobileApp.hidden) {\n  <h3>{{ properties.sections.mobileApp.label }}</h3>\n  @for (field of properties.sections.mobileApp.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-mobile-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-mobile-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('mobileApp', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['mobileApp']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.mobileApp.disabled || properties.disabled)\"\n    />\n    } @case (FIELD_TYPES.CHECKBOX) {\n    <input\n      type=\"checkbox\"\n      [id]=\"'seo-mobile-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('mobileApp', field.key, $event)\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.mobileApp.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['mobileApp']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (field.value.validation.pattern) { Must match required pattern. } @if\n    (!invalidFields['mobileApp']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Structured Data -->\n  @if (!properties.sections.structuredData.hidden) {\n  <h3>{{ properties.sections.structuredData.label }}</h3>\n  @for (field of properties.sections.structuredData.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-structured-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    <textarea\n      [id]=\"'seo-structured-' + field.key\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('structuredData', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['structuredData']?.[field.key] }\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.structuredData.disabled || properties.disabled)\"\n    ></textarea>\n\n    @if (invalidFields['structuredData']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. }\n    </small>\n    } @if (!invalidFields['structuredData']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Alternate Tags -->\n  @if (!properties.sections.alternateTags.hidden) {\n  <h3>{{ properties.sections.alternateTags.label }}</h3>\n  @for (field of properties.sections.alternateTags.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-alternate-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.ARRAY) {\n    <div class=\"custom-badge-group\">\n      <div class=\"badge-list\">\n        @for (item of field.value.value; track item) {\n        <span class=\"badge\">\n          {{ item }}\n          <button\n            type=\"button\"\n            (click)=\"removeArrayItem('alternateTags', field.key, field.value.value.indexOf(item))\"\n            [disabled]=\"!!(field.value.disabled || properties.sections.alternateTags.disabled || properties.disabled)\"\n          >\n            &times;\n          </button>\n        </span>\n        }\n      </div>\n      <input\n        type=\"text\"\n        [placeholder]=\"field.value.description\"\n        [(ngModel)]=\"field.value._input\"\n        [ngModelOptions]=\"{standalone: true}\"\n        (keydown.enter)=\"addArrayItem('alternateTags', field.key, $event)\"\n        [disabled]=\"!!(field.value.disabled || properties.sections.alternateTags.disabled || properties.disabled)\"\n        class=\"custom-input\"\n      />\n    </div>\n    } @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-alternate-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('alternateTags', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['alternateTags']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.alternateTags.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['alternateTags']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['alternateTags']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Site Verification -->\n  @if (!properties.sections.siteVerification.hidden) {\n  <h3>{{ properties.sections.siteVerification.label }}</h3>\n  @for (field of properties.sections.siteVerification.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-verification-' + field.key\"\n      >{{ field.value.label }}</label\n    >\n\n    <input\n      [id]=\"'seo-verification-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('siteVerification', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['siteVerification']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.siteVerification.disabled || properties.disabled)\"\n    />\n\n    @if (invalidFields['siteVerification']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['siteVerification']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Security & Privacy -->\n  @if (!properties.sections.securityPrivacy.hidden) {\n  <h3>{{ properties.sections.securityPrivacy.label }}</h3>\n  @for (field of properties.sections.securityPrivacy.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-security-' + field.key\"\n      >{{ field.value.label }} @if (properties.hints !== false) {\n      <span class=\"input-hint\">\n        @switch (field.value.type) { @case (FIELD_TYPES.TEXT) { {{HINTS.TEXT}} }\n        @case (FIELD_TYPES.TEXTAREA) { {{HINTS.TEXTAREA}} } @case\n        (FIELD_TYPES.ARRAY) { {{HINTS.ARRAY}} } @case (FIELD_TYPES.DROPDOWN) {\n        {{HINTS.DROPDOWN}} } @case (FIELD_TYPES.CHECKBOX) { {{HINTS.CHECKBOX}} }\n        @default { {{HINTS.DEFAULT}} } }\n      </span>\n      }</label\n    >\n\n    <input\n      [id]=\"'seo-security-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('securityPrivacy', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['securityPrivacy']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.securityPrivacy.disabled || properties.disabled)\"\n    />\n\n    @if (invalidFields['securityPrivacy']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['securityPrivacy']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n\n  <!-- Performance -->\n  @if (!properties.sections.performance.hidden) {\n  <h3>{{ properties.sections.performance.label }}</h3>\n  @for (field of properties.sections.performance.fields | keyvalue; track\n  field.key) { @if (!field.value.hidden) {\n  <div class=\"custom-input-group\">\n    <label [for]=\"'seo-performance-' + field.key\"\n      >{{ field.value.label }}</label\n    >\n\n    @switch (field.value.type) { @case (FIELD_TYPES.ARRAY) {\n    <div class=\"custom-badge-group\">\n      <div class=\"badge-list\">\n        @for (item of field.value.value; track item) {\n        <span class=\"badge\">\n          {{ item }}\n          <button\n            type=\"button\"\n            (click)=\"removeArrayItem('performance', field.key, field.value.value.indexOf(item))\"\n            [disabled]=\"!!(field.value.disabled || properties.sections.performance.disabled || properties.disabled)\"\n          >\n            &times;\n          </button>\n        </span>\n        }\n      </div>\n      <input\n        type=\"text\"\n        [placeholder]=\"field.value.description\"\n        [(ngModel)]=\"field.value._input\"\n        [ngModelOptions]=\"{standalone: true}\"\n        (keydown.enter)=\"addArrayItem('performance', field.key, $event)\"\n        [disabled]=\"!!(field.value.disabled || properties.sections.performance.disabled || properties.disabled)\"\n        class=\"custom-input\"\n      />\n    </div>\n    } @case (FIELD_TYPES.TEXT) {\n    <input\n      [id]=\"'seo-performance-' + field.key\"\n      type=\"text\"\n      [ngModel]=\"field.value.value\"\n      [ngModelOptions]=\"{standalone: true}\"\n      (ngModelChange)=\"updateProperty('performance', field.key, $event)\"\n      class=\"custom-input\"\n      [ngClass]=\"{ 'invalid': invalidFields['performance']?.[field.key] }\"\n      [attr.maxLength]=\"field.value.validation.maxLength\"\n      [attr.required]=\"field.value.validation.required ? true : null\"\n      [placeholder]=\"field.value.description\"\n      [disabled]=\"!!(field.value.disabled || properties.sections.performance.disabled || properties.disabled)\"\n    />\n    } } @if (invalidFields['performance']?.[field.key]) {\n    <small class=\"input-description\" style=\"color: #e53935\">\n      {{ field.value.label }} is invalid. @if (field.value.validation.required)\n      { It is required. } @if (field.value.validation.maxLength) { Must be at\n      most {{ field.value.validation.maxLength }} characters. }\n    </small>\n    } @if (!invalidFields['performance']?.[field.key]) {\n    <small class=\"input-description\"> {{ field.value.description }} </small>\n    }\n  </div>\n  } } }\n</form>\n", styles: [".custom-input-group,.custom-badge-group{display:flex;flex-direction:column;margin-bottom:1.5rem}.custom-input-group label,.custom-badge-group label{font-size:1rem;color:#495057;margin-bottom:.5rem;font-weight:500}.input-description{font-size:.85rem;color:#888;margin-top:.25rem}.custom-input{padding:.75rem 1rem;border:1px solid #ced4da;border-radius:4px;font-size:1rem;transition:border-color .2s,box-shadow .2s;outline:none;background:#fff;color:#495057;box-shadow:none}.custom-input:focus{border-color:#2196f3;box-shadow:0 0 0 .2rem #2196f326}.custom-input:disabled{background:#f5f5f5;color:#bdbdbd}.custom-input.invalid{border-color:#e53935;box-shadow:0 0 0 .2rem #e5393526}.badge-list{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:.5rem}.badge{display:inline-flex;align-items:center;background:#e3f2fd;color:#1976d2;border-radius:12px;padding:.25rem .75rem;font-size:.95rem;margin-right:.25rem;margin-bottom:.25rem;border:1px solid #90caf9}.badge button{background:none;border:none;color:#1976d2;font-size:1.1em;margin-left:.5em;cursor:pointer;padding:0;line-height:1}.badge button:disabled{color:#bdbdbd;cursor:not-allowed}form.disabled{pointer-events:none;opacity:.7}select.custom-input{min-width:120px}textarea.custom-input{min-height:80px;resize:vertical}.input-hint{display:inline-block;margin-left:.5rem;font-size:.92em;color:#7b8a99;background:#f4f7fa;border-radius:8px;padding:.1em .7em;font-style:italic;vertical-align:middle}\n"] }]
        }], propDecorators: { properties: [{
                type: Input
            }], propertiesChange: [{
                type: Output
            }] } });

/*
 * Public API Surface of pp-seo
 */

/**
 * Generated bundle index. Do not edit.
 */

export { FieldTypes, Seo };
//# sourceMappingURL=pp-seo.mjs.map