export declare const INTERACTIVITY_EDIT_TEMPLATE = "import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';\nimport { __ } from '@wordpress/i18n';\nimport {\n useBlockProps,\n InspectorControls,\n RichText,\n BlockControls,\n AlignmentToolbar,\n} from '@wordpress/block-editor';\nimport { PanelBody, RangeControl, Button, Notice } from '@wordpress/components';\nimport { useState } from '@wordpress/element';\nimport currentManifest from './manifest-document';\nimport { {{slugCamelCase}}Store } from './interactivity-store';\nimport {\n InspectorFromManifest,\n useEditorFields,\n useTypedAttributeUpdater,\n} from '@wp-typia/block-runtime/inspector';\nimport type { {{pascalCase}}Attributes } from './types';\nimport {\n sanitize{{pascalCase}}Attributes,\n validate{{pascalCase}}Attributes,\n} from './validators';\nimport { useTypiaValidation } from './hooks';\n\ntype EditProps = BlockEditProps<{{pascalCase}}Attributes>;\n\nconst actionButtonRowStyle = { display: 'flex', gap: '8px', marginTop: '16px' };\nconst validationListStyle = { margin: 0, paddingLeft: '1em' };\n\nexport default function Edit({\n attributes,\n setAttributes,\n isSelected,\n}: EditProps) {\n const [isPreviewing, setIsPreviewing] = useState(false);\n const editorFields = useEditorFields(currentManifest, {\n manual: ['content', 'clickCount', 'maxClicks'],\n labels: {\n{{interactivityEditorFieldLabels}}\n },\n });\n const { errorMessages, isValid } = useTypiaValidation(\n attributes,\n validate{{pascalCase}}Attributes,\n );\n const validateEditorUpdate = (\n nextAttributes: {{pascalCase}}Attributes,\n ) => {\n try {\n return {\n data: sanitize{{pascalCase}}Attributes(nextAttributes),\n errors: [],\n isValid: true as const,\n };\n } catch {\n return validate{{pascalCase}}Attributes(nextAttributes);\n }\n };\n const { updateField } = useTypedAttributeUpdater(\n attributes,\n setAttributes,\n validateEditorUpdate,\n );\n const alignmentValue = editorFields.getStringValue(\n attributes,\n 'alignment',\n 'left',\n ) as NonNullable<{{pascalCase}}Attributes['alignment']>;\n const clickCount = attributes.clickCount ?? 0;\n const isVisible = editorFields.getBooleanValue(attributes, 'isVisible', true);\n const isAnimating = attributes.isAnimating ?? false;\n const maxClicks = attributes.maxClicks ?? 0;\n const showCounter = editorFields.getBooleanValue(\n attributes,\n 'showCounter',\n true,\n );\n const interactiveMode = editorFields.getStringValue(\n attributes,\n 'interactiveMode',\n 'click',\n ) as NonNullable<{{pascalCase}}Attributes['interactiveMode']>;\n const animation = editorFields.getStringValue(\n attributes,\n 'animation',\n 'none',\n ) as NonNullable<{{pascalCase}}Attributes['animation']>;\n\n const blockProps = useBlockProps({\n className: `{{cssClassName}} {{cssClassName}}--${interactiveMode}`,\n 'data-wp-interactive': {{slugCamelCase}}Store.directive.interactive,\n 'data-wp-context': JSON.stringify(\n {{slugCamelCase}}Store.createContext({\n clicks: clickCount,\n isAnimating,\n isVisible,\n animation,\n maxClicks,\n }),\n ),\n });\n const previewContentStyle = { textAlign: alignmentValue };\n const progressBarStyle = { width: `${(clickCount / maxClicks) * 100}%` };\n{{interactivityClicksDirective}}\n const isAnimatingDirective =\n {{slugCamelCase}}Store.directive.state('isAnimating');\n const progressDirective =\n {{slugCamelCase}}Store.directive.state('progress') + \" + '%'\";\n\n const resetCounter = () => {\n updateField('clickCount', 0);\n updateField('isAnimating', false);\n };\n\n const testAnimation = () => {\n updateField('isAnimating', true);\n setTimeout(() => {\n updateField('isAnimating', false);\n }, 1000);\n };\n\n return (\n <>\n \n \n updateField(\n 'alignment',\n (value || alignmentValue) as NonNullable<\n {{pascalCase}}Attributes['alignment']\n >,\n )\n }\n />\n \n\n \n \n\n \n updateField('maxClicks', value ?? maxClicks)}\n min={0}\n max={100}\n help={__('Set to 0 for unlimited clicks', '{{textDomain}}')}\n />\n\n \n \n \n
\n \n\n {!isValid && (\n \n {errorMessages.map((error, index) => (\n \n {error}\n \n ))}\n \n )}\n\n {isSelected && (\n \n \n\n {clickCount > 0 && (\n \n {__('Current clicks:', '{{textDomain}}')} {clickCount}\n {maxClicks > 0 && ` / ${maxClicks}`}\n \n )}\n \n )}\n \n\n
\n
\n
updateField('content', value)}\n placeholder={__(\n {{titleTsLiteral}} + ' \u2013 click me to interact!',\n '{{textDomain}}',\n )}\n />\n\n {!isValid && (\n \n \n \n {__('Validation Errors', '{{textDomain}}')}\n \n
\n \n {errorMessages.map((error, index) => (\n - {error}
\n ))}\n
\n \n )}\n\n {showCounter && (\n \n \n {__('Clicks:', '{{textDomain}}')}\n \n \n {clickCount}\n \n
\n )}\n\n {maxClicks > 0 && (\n \n )}\n\n {animation !== 'none' && (\n \n {animation}\n
\n )}\n \n
\n >\n );\n}\n";
export declare const INTERACTIVITY_SAVE_TEMPLATE = "import { useBlockProps, RichText } from '@wordpress/block-editor';\nimport { __ } from '@wordpress/i18n';\nimport { {{slugCamelCase}}Store } from './interactivity-store';\nimport type { {{pascalCase}}Attributes } from './types';\n\nexport default function Save({\n attributes,\n}: {\n attributes: {{pascalCase}}Attributes;\n}) {\n const clickCount = attributes.clickCount ?? 0;\n const interactiveMode = attributes.interactiveMode ?? 'click';\n const animation = attributes.animation ?? 'none';\n const isAnimating = attributes.isAnimating ?? false;\n const isVisible = attributes.isVisible ?? true;\n const maxClicks = attributes.maxClicks ?? 0;\n const showCounter = attributes.showCounter ?? true;\n const contentStyle = { textAlign: attributes.alignment };\n const clickActionDirective =\n {{slugCamelCase}}Store.directive.action('handleClick');\n const visibilityHiddenDirective =\n {{slugCamelCase}}Store.directive.negate(\n {{slugCamelCase}}Store.directive.state('isVisible'),\n );\n{{interactivityClicksDirective}}\n const clampedClicksDirective =\n {{slugCamelCase}}Store.directive.state('clampedClicks');\n const isAnimatingDirective =\n {{slugCamelCase}}Store.directive.state('isAnimating');\n const completionHiddenDirective =\n {{slugCamelCase}}Store.directive.negate(\n {{slugCamelCase}}Store.directive.state('isComplete'),\n );\n const resetActionDirective =\n {{slugCamelCase}}Store.directive.action('reset');\n const blockProps = useBlockProps.save({\n className: `{{cssClassName}} {{cssClassName}}--${interactiveMode}`,\n 'data-wp-interactive': {{slugCamelCase}}Store.directive.interactive,\n 'data-wp-context': JSON.stringify(\n {{slugCamelCase}}Store.createContext({\n clicks: clickCount,\n isAnimating,\n isVisible,\n animation,\n maxClicks,\n }),\n ),\n });\n const progressDirective =\n {{slugCamelCase}}Store.directive.state('progress') + \" + '%'\";\n\n return (\n \n
\n
\n\n {showCounter && (\n
\n \n {__('Clicks:', '{{textDomain}}')}\n \n \n {clickCount}\n \n
\n )}\n\n {maxClicks > 0 && (\n
\n )}\n\n
\n\n {maxClicks > 0 && (\n
\n {__('\uD83C\uDF89 Complete!', '{{textDomain}}')}\n
\n )}\n\n
\n
\n
\n );\n}\n";
export declare const INTERACTIVITY_INDEX_TEMPLATE = "import {\n registerScaffoldBlockType,\n type BlockConfiguration,\n} from '@wp-typia/block-types/blocks/registration';\nimport type { BlockSupports } from '@wp-typia/block-types/blocks/supports';\nimport {\n buildScaffoldBlockRegistration,\n parseScaffoldBlockMetadata,\n} from '@wp-typia/block-runtime/blocks';\n\nimport Edit from './edit';\nimport Save from './save';\nimport metadata from './block-metadata';\nimport './editor.scss';\nimport './style.scss';\n\nimport type { {{pascalCase}}Attributes } from './types';\n\nconst scaffoldSupports = {\n html: false,\n align: true,\n anchor: true,\n className: true,\n interactivity: true,\n} satisfies BlockSupports;\n\nconst registration = buildScaffoldBlockRegistration(\n parseScaffoldBlockMetadata<\n BlockConfiguration<{{pascalCase}}Attributes>\n >(metadata),\n {\n supports: scaffoldSupports,\n edit: Edit,\n save: Save,\n },\n);\n\nregisterScaffoldBlockType(registration.name, registration.settings);\n";
export declare const INTERACTIVITY_STORE_TEMPLATE = "{{interactivityTypesImport}}\n\ntype InteractivityActionShape = object;\ntype InteractivityCallbackShape = object;\ntype InteractivityContextShape = object;\ntype InteractivityStateShape = object;\ntype InteractivityCallable =\n | ((...args: unknown[]) => unknown)\n | ReturnType;\ntype InteractivityKey = Extract;\ntype InteractivityMethodKey = {\n [Key in InteractivityKey]: T[Key] extends InteractivityCallable\n ? Key\n : never;\n}[InteractivityKey];\n\ntype InteractivityDirectivePath<\n Root extends string,\n Key extends string,\n> = `${Root}.${Key}`;\n\ntype NegatedInteractivityDirectivePath = `!${Path}`;\n\nexport interface TypedInteractivityDirectiveHelpers<\n State extends InteractivityStateShape,\n Context extends InteractivityContextShape,\n Actions extends InteractivityActionShape,\n Callbacks extends InteractivityCallbackShape,\n Namespace extends string,\n> {\n readonly interactive: Namespace;\n action>(\n key: Key,\n ): InteractivityDirectivePath<'actions', Key>;\n callback>(\n key: Key,\n ): InteractivityDirectivePath<'callbacks', Key>;\n state>(\n key: Key,\n ): InteractivityDirectivePath<'state', Key>;\n context>(\n key: Key,\n ): InteractivityDirectivePath<'context', Key>;\n negate(\n path: Path,\n ): NegatedInteractivityDirectivePath;\n}\n\nexport interface TypedInteractivityStore<\n Namespace extends string,\n State extends InteractivityStateShape,\n Context extends InteractivityContextShape,\n Actions extends InteractivityActionShape,\n Callbacks extends InteractivityCallbackShape,\n> {\n readonly namespace: Namespace;\n readonly state: State;\n readonly context: Context;\n readonly actions: Actions;\n readonly callbacks: Callbacks;\n readonly directive: TypedInteractivityDirectiveHelpers<\n State,\n Context,\n Actions,\n Callbacks,\n Namespace\n >;\n createContext(value: Context): Context;\n}\n\nexport function defineInteractivityStore<\n Namespace extends string,\n State extends InteractivityStateShape,\n Context extends InteractivityContextShape,\n Actions extends InteractivityActionShape,\n Callbacks extends InteractivityCallbackShape,\n>(config: {\n readonly namespace: Namespace;\n readonly state: State;\n readonly context: Context;\n readonly actions: Actions;\n readonly callbacks: Callbacks;\n}): TypedInteractivityStore {\n return {\n namespace: config.namespace,\n state: config.state,\n context: config.context,\n actions: config.actions,\n callbacks: config.callbacks,\n directive: {\n interactive: config.namespace,\n action>(key: Key) {\n return `actions.${key}` as InteractivityDirectivePath<'actions', Key>;\n },\n callback>(key: Key) {\n return `callbacks.${key}` as InteractivityDirectivePath<\n 'callbacks',\n Key\n >;\n },\n state>(key: Key) {\n return `state.${key}` as InteractivityDirectivePath<'state', Key>;\n },\n context>(key: Key) {\n return `context.${key}` as InteractivityDirectivePath<'context', Key>;\n },\n negate(path: Path) {\n return `!${path}` as NegatedInteractivityDirectivePath;\n },\n },\n createContext(value) {\n return value;\n },\n };\n}\n\ntype InteractivityActionHandler = InteractivityCallable;\n\nexport interface {{pascalCase}}StoreActions {\n handleClick: InteractivityActionHandler;\n handleMouseEnter: InteractivityActionHandler;\n handleMouseLeave: InteractivityActionHandler;\n reset: InteractivityActionHandler;\n}\n\nexport interface {{pascalCase}}StoreCallbacks {}\n\nexport const {{slugCamelCase}}Store = defineInteractivityStore({\n namespace: '{{slugKebabCase}}',\n state: {} as {{pascalCase}}State,\n context: {} as {{pascalCase}}Context,\n actions: {} as {{pascalCase}}StoreActions,\n callbacks: {} as {{pascalCase}}StoreCallbacks,\n});\n";
export declare const INTERACTIVITY_SCRIPT_TEMPLATE = "/**\n * WordPress Interactivity API implementation for {{title}} block\n */\nimport {\n store,\n getContext,\n getElement,\n withSyncEvent,\n} from '@wordpress/interactivity';\nimport {\n {{slugCamelCase}}Store,\n type {{pascalCase}}StoreActions,\n} from './interactivity-store';\n{{interactivityTypesImport}}\n\nfunction getBlockContext() {\n return getContext<{{pascalCase}}Context>();\n}\n\nconst actions: {{pascalCase}}StoreActions = {\n // Handle block click\n handleClick: () => {\n const context = getBlockContext();\n const { ref } = getElement();\n\n if (!ref) {\n return;\n }\n\n if (context.maxClicks > 0 && context.clicks >= context.maxClicks) {\n return;\n }\n\n const previousClicks = context.clicks;\n\n // Increment click counter\n context.clicks += 1;\n\n // Trigger animation\n if (context.animation !== 'none') {\n context.isAnimating = true;\n setTimeout(() => {\n context.isAnimating = false;\n }, 1000);\n }\n\n // Emit custom event\n ref.dispatchEvent(\n new CustomEvent('{{slugKebabCase}}:click', {\n detail: { clicks: context.clicks },\n }),\n );\n\n // Check if max clicks reached\n if (\n context.maxClicks > 0 &&\n previousClicks < context.maxClicks &&\n context.clicks === context.maxClicks\n ) {\n ref.dispatchEvent(\n new CustomEvent('{{slugKebabCase}}:complete', {\n detail: { totalClicks: context.clicks },\n }),\n );\n }\n },\n\n // Handle hover events\n handleMouseEnter: () => {\n const context = getBlockContext();\n if (context.animation === 'none') return;\n context.isAnimating = true;\n },\n\n handleMouseLeave: () => {\n const context = getBlockContext();\n if (context.animation === 'none') return;\n context.isAnimating = false;\n },\n\n // Reset counter\n reset: withSyncEvent((event: Event) => {\n event.stopPropagation();\n const context = getBlockContext();\n context.clicks = 0;\n context.isAnimating = false;\n }),\n};\n\nconst state = {\n get clicks() {\n return getBlockContext().clicks;\n },\n get isAnimating() {\n return getBlockContext().isAnimating;\n },\n get isVisible() {\n return getBlockContext().isVisible;\n },\n get progress() {\n const context = getBlockContext();\n const clampedClicks =\n context.maxClicks > 0\n ? Math.min(context.clicks, context.maxClicks)\n : context.clicks;\n return context.maxClicks > 0\n ? (clampedClicks / context.maxClicks) * 100\n : 0;\n },\n get clampedClicks() {\n const context = getBlockContext();\n return context.maxClicks > 0\n ? Math.min(context.clicks, context.maxClicks)\n : context.clicks;\n },\n get isComplete() {\n const context = getBlockContext();\n return context.clicks >= context.maxClicks && context.maxClicks > 0;\n },\n} satisfies {{pascalCase}}State;\n\n// Store configuration\nstore({{slugCamelCase}}Store.namespace, {\n // State - reactive data that updates the UI\n state,\n actions,\n callbacks: {{slugCamelCase}}Store.callbacks,\n});\n";
export declare const INTERACTIVITY_VALIDATORS_TEMPLATE = "import typia from 'typia';\nimport currentManifest from './manifest-defaults-document';\nimport {\n {{pascalCase}}Attributes,\n {{pascalCase}}ValidationResult,\n} from './types';\nimport { createTemplateValidatorToolkit } from './validator-toolkit';\n\nconst scaffoldValidators =\n createTemplateValidatorToolkit<{{pascalCase}}Attributes>({\n assert: typia.createAssert<{{pascalCase}}Attributes>(),\n clone: typia.plain.createClone<{{pascalCase}}Attributes>() as (\n value: {{pascalCase}}Attributes,\n ) => {{pascalCase}}Attributes,\n is: typia.createIs<{{pascalCase}}Attributes>(),\n manifest: currentManifest,\n prune: typia.plain.createPrune<{{pascalCase}}Attributes>(),\n random: typia.createRandom<{{pascalCase}}Attributes>() as (\n ...args: unknown[]\n ) => {{pascalCase}}Attributes,\n validate: typia.createValidate<{{pascalCase}}Attributes>(),\n });\n\nexport const validate{{pascalCase}}Attributes =\n scaffoldValidators.validateAttributes as (\n attributes: unknown,\n ) => {{pascalCase}}ValidationResult;\n\nexport const validators = scaffoldValidators.validators;\n\nexport const sanitize{{pascalCase}}Attributes =\n scaffoldValidators.sanitizeAttributes as (\n attributes: Partial<{{pascalCase}}Attributes>,\n ) => {{pascalCase}}Attributes;\n\n/**\n * Runtime type guard for checking if an object is {{pascalCase}}Attributes.\n */\nexport const is{{pascalCase}}Attributes = (\n obj: unknown,\n): obj is {{pascalCase}}Attributes => {\n return validators.is(obj);\n};\n\nexport const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;\n";