const BASE_SETTINGS = { backgroundType: 'none', paddingY: 'lg' };
export const SECTION_TYPES = {
    hero: {
        id: 'hero',
        name: 'Hero Banner',
        icon: 'layout-template',
        description: 'Full-width banner with headline, body, and a primary call to action.',
        category: 'layout',
        accent: 'purple',
        scope: ['page', 'post'],
        defaultContent: {
            eyebrow: '',
            heading: 'Your headline goes here',
            body: 'A short supporting sentence that sets up the value of the page.',
            primaryButtonLabel: 'Get Started',
            primaryButtonUrl: '/contact',
            secondaryButtonLabel: '',
            secondaryButtonUrl: '',
        },
        defaultSettings: { backgroundType: 'solid', backgroundColor: 'purple', paddingY: 'xl' },
        fields: [
            { key: 'eyebrow', label: 'Eyebrow', type: 'text', placeholder: 'Optional small label' },
            { key: 'heading', label: 'Heading', type: 'textarea', required: true },
            { key: 'body', label: 'Body', type: 'textarea' },
            { key: 'primaryButtonLabel', label: 'Primary button', type: 'text' },
            { key: 'primaryButtonUrl', label: 'Primary button URL', type: 'url' },
            { key: 'secondaryButtonLabel', label: 'Secondary button', type: 'text' },
            { key: 'secondaryButtonUrl', label: 'Secondary button URL', type: 'url' },
        ],
    },
    text: {
        id: 'text',
        name: 'Text Block',
        icon: 'align-left',
        description: 'A heading and paragraph, useful for mission statements and prose.',
        category: 'content',
        accent: 'blue',
        scope: ['page', 'post'],
        defaultContent: {
            heading: 'A short, clear heading',
            body: 'Write the supporting copy for this section here.',
            alignment: 'center',
        },
        defaultSettings: { ...BASE_SETTINGS, paddingY: 'xl' },
        fields: [
            { key: 'heading', label: 'Heading', type: 'textarea', required: true },
            { key: 'body', label: 'Body', type: 'textarea' },
            {
                key: 'alignment',
                label: 'Alignment',
                type: 'select',
                options: [
                    { label: 'Left', value: 'left' },
                    { label: 'Center', value: 'center' },
                ],
            },
        ],
    },
    feature: {
        id: 'feature',
        name: 'Image + Text',
        icon: 'panels-top-left',
        description: 'Two-column feature highlight with copy on one side and media on the other.',
        category: 'media',
        accent: 'green',
        scope: ['page', 'post'],
        defaultContent: {
            label: 'Feature Highlight',
            heading: 'A standout capability',
            body: 'Describe the feature and why it matters to your audience.',
            imageUrl: '',
            imageAlt: '',
            imagePosition: 'right',
            buttonLabel: '',
            buttonUrl: '',
        },
        defaultSettings: { ...BASE_SETTINGS },
        fields: [
            {
                key: 'label',
                label: 'Section label',
                type: 'text',
                help: 'Small eyebrow above the heading',
            },
            { key: 'heading', label: 'Heading', type: 'textarea', required: true },
            { key: 'body', label: 'Body', type: 'textarea' },
            { key: 'imageUrl', label: 'Image', type: 'media' },
            {
                key: 'imageAlt',
                label: 'Image alt text',
                type: 'text',
                help: 'Required when an image is set',
            },
            {
                key: 'imagePosition',
                label: 'Image position',
                type: 'select',
                options: [
                    { label: 'Right', value: 'right' },
                    { label: 'Left', value: 'left' },
                ],
            },
            { key: 'buttonLabel', label: 'Button', type: 'text' },
            { key: 'buttonUrl', label: 'Button URL', type: 'url' },
        ],
    },
    stats: {
        id: 'stats',
        name: 'By the Numbers',
        icon: 'bar-chart-3',
        description: 'A row of key metrics with values and labels.',
        category: 'content',
        accent: 'orange',
        scope: ['page', 'post'],
        defaultContent: {
            heading: 'By the numbers',
            body: '',
            stats: [
                { value: '99.99%', label: 'Uptime', description: '' },
                { value: '124ms', label: 'Avg response time', description: '' },
                { value: '3M+', label: 'API requests served', description: '' },
            ],
        },
        defaultSettings: { ...BASE_SETTINGS },
        fields: [
            { key: 'heading', label: 'Heading', type: 'textarea' },
            { key: 'body', label: 'Body', type: 'textarea' },
            { key: 'stats', label: 'Stats', type: 'stats' },
        ],
    },
    cta: {
        id: 'cta',
        name: 'CTA Banner',
        icon: 'megaphone',
        description: 'A focused call-to-action band with heading, body, and a button.',
        category: 'conversion',
        accent: 'pink',
        scope: ['page', 'post'],
        defaultContent: {
            heading: 'Ready to get started?',
            body: 'A short nudge that motivates the next step.',
            buttonLabel: 'Start Building',
            buttonUrl: '/contact',
        },
        defaultSettings: { backgroundType: 'solid', backgroundColor: 'purple', paddingY: 'xl' },
        fields: [
            { key: 'heading', label: 'Heading', type: 'textarea', required: true },
            { key: 'body', label: 'Body', type: 'textarea' },
            { key: 'buttonLabel', label: 'Button', type: 'text' },
            { key: 'buttonUrl', label: 'Button URL', type: 'url' },
        ],
    },
    form: {
        id: 'form',
        name: 'Form',
        icon: 'mail',
        description: 'Embed a published form (e.g. contact or signup) so visitors can submit it.',
        category: 'conversion',
        accent: 'blue',
        scope: ['page', 'post'],
        defaultContent: {
            formSlug: '',
            heading: 'Get in touch',
            description: '',
        },
        defaultSettings: { ...BASE_SETTINGS, paddingY: 'xl' },
        fields: [
            {
                key: 'formSlug',
                label: 'Form',
                type: 'text',
                required: true,
                help: 'The slug of the form to embed (e.g. "contact"). Create it under Forms.',
            },
            { key: 'heading', label: 'Heading', type: 'text' },
            {
                key: 'description',
                label: 'Intro text',
                type: 'textarea',
                help: 'Optional copy shown above the form fields.',
            },
        ],
    },
    // ─── Post-oriented section types (scope: post) ─────────────────────
    'article-body': {
        id: 'article-body',
        name: 'Article Body',
        icon: 'text',
        description: "Renders the post's main body content with optional reading aids.",
        category: 'content',
        accent: 'blue',
        scope: ['post'],
        defaultContent: {
            // `source: 'field'` binds the rendered body to the post's own `body`
            // field (single source of truth). `override` lets the author type
            // body copy directly into the section instead.
            source: 'field',
            body: '',
            width: 'normal',
            showToc: false,
        },
        defaultSettings: { ...BASE_SETTINGS, paddingY: 'lg' },
        fields: [
            {
                key: 'source',
                label: 'Body source',
                type: 'select',
                help: "Use the post's Body field, or write copy here in this section.",
                options: [
                    { label: "Post's Body field", value: 'field' },
                    { label: 'Custom copy', value: 'override' },
                ],
            },
            {
                key: 'body',
                label: 'Custom body',
                type: 'richText',
                help: 'Used only when Body source is "Custom copy".',
            },
            {
                key: 'width',
                label: 'Content width',
                type: 'select',
                options: [
                    { label: 'Normal', value: 'normal' },
                    { label: 'Wide', value: 'wide' },
                ],
            },
            { key: 'showToc', label: 'Show table of contents', type: 'boolean' },
        ],
    },
    quote: {
        id: 'quote',
        name: 'Pull Quote',
        icon: 'quote',
        description: 'A highlighted quotation with optional attribution.',
        category: 'content',
        accent: 'purple',
        scope: ['post'],
        defaultContent: {
            quote: 'A memorable line worth pulling out of the body copy.',
            attribution: '',
            role: '',
        },
        defaultSettings: { ...BASE_SETTINGS, paddingY: 'lg' },
        fields: [
            { key: 'quote', label: 'Quote', type: 'textarea', required: true },
            { key: 'attribution', label: 'Attribution', type: 'text', placeholder: 'Jane Doe' },
            { key: 'role', label: 'Role / source', type: 'text', placeholder: 'CEO, Acme' },
        ],
    },
    'author-bio': {
        id: 'author-bio',
        name: 'Author Bio',
        icon: 'user',
        description: "A short biography block for the post's author.",
        category: 'content',
        accent: 'green',
        scope: ['post'],
        defaultContent: {
            heading: 'About the author',
            showAvatar: true,
            showSocial: true,
        },
        defaultSettings: { ...BASE_SETTINGS },
        fields: [
            { key: 'heading', label: 'Heading', type: 'text' },
            { key: 'showAvatar', label: 'Show avatar', type: 'boolean' },
            { key: 'showSocial', label: 'Show social links', type: 'boolean' },
        ],
    },
    'related-posts': {
        id: 'related-posts',
        name: 'Related Posts',
        icon: 'layout-grid',
        description: 'A grid of related posts, chosen automatically or hand-picked.',
        category: 'content',
        accent: 'orange',
        scope: ['post'],
        defaultContent: {
            heading: 'Related posts',
            mode: 'auto',
            count: '3',
            postSlugs: [],
        },
        defaultSettings: { ...BASE_SETTINGS },
        fields: [
            { key: 'heading', label: 'Heading', type: 'text' },
            {
                key: 'mode',
                label: 'Selection',
                type: 'select',
                options: [
                    { label: 'Automatic (newest in this type)', value: 'auto' },
                    { label: 'Hand-picked', value: 'manual' },
                ],
            },
            {
                key: 'count',
                label: 'How many',
                type: 'select',
                options: [
                    { label: '3', value: '3' },
                    { label: '4', value: '4' },
                    { label: '6', value: '6' },
                ],
            },
            {
                key: 'postSlugs',
                label: 'Posts',
                type: 'relationship',
                help: 'Used only when Selection is "Hand-picked".',
            },
        ],
    },
    gallery: {
        id: 'gallery',
        name: 'Image Gallery',
        icon: 'images',
        description: 'A grid of images with captions.',
        category: 'media',
        accent: 'pink',
        scope: ['post'],
        defaultContent: {
            heading: '',
            columns: '3',
            images: [],
        },
        defaultSettings: { ...BASE_SETTINGS },
        fields: [
            { key: 'heading', label: 'Heading', type: 'text' },
            {
                key: 'columns',
                label: 'Columns',
                type: 'select',
                options: [
                    { label: '2', value: '2' },
                    { label: '3', value: '3' },
                    { label: '4', value: '4' },
                ],
            },
            { key: 'images', label: 'Images', type: 'gallery' },
        ],
    },
};
/** Ordered list for the Add Section gallery + discovery endpoints. */
export const SECTION_TYPE_LIST = [
    SECTION_TYPES.hero,
    SECTION_TYPES.text,
    SECTION_TYPES.feature,
    SECTION_TYPES.stats,
    SECTION_TYPES.cta,
    SECTION_TYPES.form,
    SECTION_TYPES['article-body'],
    SECTION_TYPES.quote,
    SECTION_TYPES['author-bio'],
    SECTION_TYPES['related-posts'],
    SECTION_TYPES.gallery,
];
// ─── Custom (config-declared) section types ──────────────────────────
//
// A consumer declares extra section types in `actuate.config.ts` under
// `sections.types` (or the deprecated `sections.customTypes` alias). They are
// merged into the built-in registry at
// runtime so the Add Section gallery, the field-driven inspector, coerce, and
// validation all treat them as first-class, editable types. The map is a
// module-level singleton populated once at boot (server: handler-factory;
// admin: AdminRoot), mirroring how cms-core's runtime config and
// sections-react's renderer overrides are registered.
const customSectionTypes = new Map();
const CUSTOM_DEFAULT_SETTINGS = { backgroundType: 'none', paddingY: 'lg' };
/** Normalize a serializable custom-type input into a full {@link SectionTypeDef}. */
function normalizeCustomType(input) {
    return {
        id: input.id,
        name: input.name,
        icon: input.icon ?? 'puzzle',
        description: input.description ?? '',
        category: input.category ?? 'content',
        accent: input.accent ?? 'blue',
        scope: input.scope,
        defaultContent: input.defaultContent ? { ...input.defaultContent } : {},
        defaultSettings: input.defaultSettings
            ? { ...input.defaultSettings }
            : { ...CUSTOM_DEFAULT_SETTINGS },
        fields: input.fields ?? [],
    };
}
/**
 * Register (or replace) config-declared custom section types, application-wide.
 * Built-in types always win on an id collision, so a custom type can never
 * shadow a core type. Invalid entries (missing/blank id) are skipped.
 */
export function registerSectionTypes(inputs) {
    if (!Array.isArray(inputs))
        return;
    for (const input of inputs) {
        if (!input || typeof input.id !== 'string' || !input.id.trim())
            continue;
        if (input.id in SECTION_TYPES)
            continue; // never shadow a built-in
        customSectionTypes.set(input.id, normalizeCustomType(input));
    }
}
/** Remove all registered custom types. Called before re-registering at boot. */
export function resetCustomSectionTypes() {
    customSectionTypes.clear();
}
/**
 * Resolve the effective custom section types from `config.sections`, honoring
 * the canonical `sections.types` key and falling back to the deprecated
 * `sections.customTypes` alias. `types` wins outright when present so the
 * precedence is predictable. Both server boot (handler-factory) and admin boot
 * (AdminRoot) call this so the two surfaces never diverge.
 */
export function resolveCustomSectionTypes(sections) {
    if (!sections)
        return undefined;
    return sections.types ?? sections.customTypes;
}
/** All known section types (built-ins first, then customs in registration order). */
export function getAllSectionTypes() {
    return [...SECTION_TYPE_LIST, ...customSectionTypes.values()];
}
export function getSectionType(id) {
    return SECTION_TYPES[id] ?? customSectionTypes.get(id);
}
/**
 * Section types available in a given editor context, in registry order.
 *
 * The Page editor passes `'page'`, the Post editor + Post Template editor
 * pass `'post'`, so each Add Section gallery shows only the types that make
 * sense (and have a working renderer) for that surface. Config-declared custom
 * types that include the scope are included.
 */
export function getSectionTypesForScope(scope) {
    return getAllSectionTypes().filter((def) => def.scope.includes(scope));
}
/** Human label for a section type id, with a graceful fallback. */
export function sectionTypeLabel(id) {
    return getSectionType(id)?.name ?? 'Section';
}
/** True when `id` is a registered, renderable section type (built-in or custom). */
export function isKnownSectionType(id) {
    return getSectionType(id) !== undefined;
}
//# sourceMappingURL=registry.js.map