import { WatchEvent, Nuxt } from 'nuxt/schema'; import { ConsolaInstance } from 'consola'; import { FragmentDefinitionInputBase, BlockDefinitionInputBase, BlockDefinitionOptionsInputBase } from '../../dist/global/types/definitions.js'; import { ThemeName, Theme } from '../../dist/global/types/theme.js'; import { ColorOption } from '../../dist/global/types/colorOptions.js'; import { Resolver } from '@nuxt/kit'; import { FeatureDefinitionBase } from '../../dist/global/types/features.js'; type TemplateCallback = (context: ModuleContext) => string | Promise; type TemplateDependency = 'icons' | 'features' | 'block-content' | 'block-path' | 'block-global-options' | 'agent-mcp-tools' | 'agent-server' | 'agent-prompts' | 'module-css' | 'chart-types'; /** * Where the template should be available: * - 'app': Only in app context (default) * - 'server': Only in server/Nitro context (will be inlined for Nitro build) * - 'both': Available in both contexts */ type TemplateContext = 'app' | 'server' | 'both'; type TemplateOptions = { dependencies?: TemplateDependency[]; write?: boolean; /** * The context where this template should be available. * Server templates will be inlined for Nitro build. * @default 'app' */ context?: TemplateContext; }; type ModuleCodeTemplate = { type: 'code'; name: string; buildCode: TemplateCallback; buildTypes: TemplateCallback; options: Required & { context: TemplateContext; }; }; type ModuleFileTemplate = { type: 'file'; fileName: string; build: TemplateCallback; options: Required & { context: TemplateContext; }; }; type ModuleTemplate = ModuleCodeTemplate | ModuleFileTemplate; type OptionValidationError = { message: string; optionKey?: string; severity?: 'error' | 'warning'; }; type CollectedBlockType = 'main' | 'context' | 'fragment' | 'provider'; type BlockValidationError = ValidationError & OptionValidationError; declare class CollectedBlockFile extends CollectedFile { folder: string; iconPath: string | null; imagePath: string | null; iconContents: string | null; diffComponentPath: string | null; proxyComponentPath: string | null; type: CollectedBlockType | null; definition: FragmentDefinitionInputBase | BlockDefinitionInputBase | null; definitionSource: string | null; hasBlokkliField: boolean; identifier: string; chunkName: string; variations: string[]; private objectLiteralString; private validationCache; private hasSiblingFile; handleChange(helper: ModuleHelper): Promise; /** * Validate the block definition and return any errors. * Results are cached and invalidated when the file changes. */ validate(icons: IconCollector): BlockValidationError[]; } declare class BlockCollector extends Collector { protected icons: IconCollector; private patterns; constructor(helper: ModuleHelper, icons: IconCollector); init(): Promise; runHooks(): void | Promise; createCollectedFile(filePath: string, fileContents?: string): CollectedBlockFile; private findBlockForFolderFile; protected handleAdd(filePath: string): Promise; protected handleUnlink(filePath: string): Promise; protected handleChange(filePath: string): Promise; applies(filePath: string): Promise; getDependencyTypes(): TemplateDependency[]; validate(icons: IconCollector): boolean; } type GetBundlePropsTypeResult = { typeName: string; from: string; }; type GetBundlePropsType = (name: string, definition: CollectedBlockFile) => GetBundlePropsTypeResult; type BuildRelativeImports = { TYPES: string; TYPES_DEFINITIONS: string; CONSTANTS: string; ADAPTER: string; TYPES_THEME: string; TYPES_BLOKK_OPTIONS: string; }; type ModuleOptionsStorageDefaults = { /** * The default favorite block bundles. */ blockFavorites?: string[]; }; /** * Options for the module. */ type ModuleOptions = { /** * Additional blokkli/ directories provided by modules. * * These follow the same structure as /blokkli/ (tools/, skills/, * prompts/, system-prompts/) and are scanned by collectors that support it. * * Modules should push to this array during alterOptions. * * @internal */ blokkliDirs?: string[]; /** * An array of blökkli modules to use. */ modules?: BlokkliModule[]; /** * The pattern of source files to scan for blokkli components. */ pattern?: string[]; /** * Define reusable options that can be used in blokkli item components by * referencing the option name. */ globalOptions?: BlockDefinitionOptionsInputBase; /** * Custom path where the blökkli edit adapter can be found. * * Must be an absolute path and the file must exist when the module * is initialised. */ editAdapterPath?: string; /** * Define available chunk groups. * * The idea of this feature is to split rarely used components into separate * chunks, so that they are not imported on each page. * * This value should only be set if the component is actually used rarely. * Having too many chunks has the opposite effect, as rendering a page * requires multiple requests. * * If left empty, all components are bundled in a default chunk, which should * contain components that are used for most pages. */ chunkNames?: string[]; /** * Valid field list types. * * If one or more values are defined, they can be passed to the BlokkliField * component as a prop. The value is made available to all blokkli items inside * this field. */ fieldListTypes?: string[]; /** * Valid blokkli provider types. * * If one or more values are defined, they can be passed to the * BlokkliProvider component as a prop. The value is made available to all * blokkli items inside this provider. */ providerTypes?: string[]; /** * The entity type of blokkli items. * * Using the paragraphs_blokkli integration this value should be set to "paragraph". */ itemEntityType?: string; /** * The entity type of template entities. * * Using the paragraphs_blokkli integration this value should be set to "blokkli_paragraph_template". */ templateEntityType?: string; /** * The name of the 'from library' block bundle. */ fromLibraryBlockBundle?: string; /** * The name of the 'blökkli' block bundle. */ fragmentBlockBundle?: string; /** * Provide overrides for the translations. */ translations?: Record>; /** * The default/fallback language for the editor. */ defaultLanguage?: string; /** * Force the editor to always be in the default language. * * The default behaviour is that the editor is rendered in the same language * as the page entity. Setting this value to true will always render the * editor in the default language. */ forceDefaultLanguage?: boolean; /** * Add custom features by defining either a pattern or path to a feature component. */ featureImports?: string[]; /** * Theme colors for the editor. * * Accent colors are used for selections, highlights, buttons. * Mono colors are used for the UI elements in the editor. */ theme?: ThemeName | Partial; /** * Enable the theme editor feature. */ enableThemeEditor?: boolean; /** * blokkli generates a JSON file that contains all the defined block * options, keyed by block bundle. By default the file is output to * .nuxt/blokkli/options-schema.json, but the path can be overriden here. * * The path can use aliases like ~ or @ and must also contain the file * name including the extension. */ schemaOptionsPath?: string; /** * Configure automatic text replacements when editing plaintext fields. * * Set to `true` to enable all replacements, `false` to disable all. * Or pass an object to enable/disable individual replacements. * * Defaults to `true` (all replacements enabled). */ textAutoReplace?: boolean | { /** * Replace straight double quotes ("...") with guillemets («...»). * * Only active when the interface language is 'de' or 'fr'. */ quotes?: boolean; /** * Replace three consecutive dots (...) with an ellipsis character (…). */ ellipsis?: boolean; /** * Replace two consecutive hyphens (--) with an en dash (–). */ enDash?: boolean; }; /** * Override the feature settings. */ settingsOverride?: Record; /** * The default storage values for non-settings values. * * These values are not visible in the settings dialog, but are still * "settable" by the user through interactions. This option allows you to * define default values for these settings, like default favorite block * bundles. */ storageDefaults?: ModuleOptionsStorageDefaults; /** * Method that is called for each block bundle component to generate the * prop types. * * These types are used if you access a block item with the generated * FieldListItemTyped type, for example through: * const { rootBlocks } = defineBlokkli(). * * or using . * * The method receives the name of the bundle and the extracted block * definition as the second argument. * The return value should be an object with these properties: * * - typeName: The name of the type * - from: Where the type can be imported from * * For example, if the method returns this object: * ```typescript * { * typeName: 'ParagraphTextWithImageFragment', * from: '#graphql-operations' * } * ``` * * Then the module will generate this TypeScript code: * * ```typescript * import type { ParagraphTextWithImageFragment } from '#graphql-operations' * ``` * * And assign the imported type as the type for the `props` property for this bundle. * * Then, for example in a block component: * * ```typescript * const { siblings, index } = defineBlokkli() * * const previousBlock = computed(() => siblings.value[index.value - 1]) * * const previousTitle = computed(() => { * // The previous block in the list is a title. * if (previousBlock.value?.bundle === 'title') { * // The type of the props are now typed correctly. * const title = previousBlock.value.props.title * } * }) * ``` */ getBundlePropsType?: GetBundlePropsType; colorOptions?: Record; }; declare class FileCache { private cache; private existingFiles; /** * Read a file from disk. */ read(filePath: string): Promise; /** * Delete a file. */ delete(filePath: string): void; /** * Check if a file exists. */ fileExists(filePath: string): boolean; /** * Handles the builder watch event. */ handleWatchEvent(event: WatchEvent, filePath: string): Promise; } interface ValidationInterface { validate(icons: IconCollector): boolean; } type ModuleHelperResolvers = { /** * Resolver for files relative to the module src. */ module: Resolver; /** * Resolver for files relative to the blökkli build directory. */ build: Resolver; /** * Resolver for files relative to the Nuxt app source directory. */ src: Resolver; /** * Resolver for the app directory. */ app: Resolver; /** * Resolver for the Nuxt app root dir. */ root: Resolver; }; type ModuleHelperPaths = { blokkliBuildDir: string; srcDir: string; editAdapter: string; }; declare class ModuleHelper implements ValidationInterface { nuxt: Nuxt; logger: ConsolaInstance; relativePaths: BuildRelativeImports; paths: ModuleHelperPaths; resolvers: ModuleHelperResolvers; fileCache: FileCache; readonly options: ModuleOptions; readonly isDev: boolean; readonly isModuleBuild: boolean; readonly isPrepare: boolean; constructor(nuxt: Nuxt, logger: ConsolaInstance, moduleUrl: string, providedOptions: ModuleOptions); /** * Transform the path relative to the module's build directory. * * @param path - The absolute path. * * @returns The path relative to the module's build directory. */ toModuleBuildRelative(path: string): string; /** * Path to the editor's compiled tailwind config. Used by the SFC mangle * pipeline and module CSS processing to inject `@config` so consumer-side * `@apply` resolves against the editor's theme + utilities. * * In dist (npm install): `dist/modules/tailwind/index.mjs`. In source (this * repo's playground): `tailwind.config.ts` at the repo root. */ getTailwindConfigPath(): string; private findEditAdapterPath; getChunkNames(): string[]; addComponent(name: string): void; addComposable(name: string): void; addAlias(name: string, path: string): void; /** * Add a directory to the app TypeScript tsconfig includes. */ addAppTsInclude(absolutePath: string): void; /** * Add a directory to the server/Nitro TypeScript tsconfig includes. */ addServerTsInclude(absolutePath: string): void; /** * Add a path to Nitro's externals.inline for server-side usage. * @see https://github.com/nuxt/nuxt/issues/28995 */ inlineForNitro(path: string): void; getMappedBlockBundle(bundle: string): string; validate(icons: IconCollector): boolean; } type ExtractedFeatureDefinition = { id: string; componentName: string; componentPath: string; definition: FeatureDefinitionBase; definitionSource: string; }; declare class CollectedFeatureFile extends CollectedFile { private definition; private composableName; private enabled; private objectLiteral; getDefinition(): ExtractedFeatureDefinition | null; handleChange(): Promise; isEnabled(): boolean; /** * Disable the feature. */ disable(): void; } declare class FeatureCollector extends Collector { protected needsFileContents: boolean; private disabledFeatures; private srcFromModule; private srcFromBlokkliDir; constructor(helper: ModuleHelper); getEnabledFeatures(): ExtractedFeatureDefinition[]; init(): Promise; runHooks(): void | Promise; createCollectedFile(filePath: string, fileContents?: string): CollectedFeatureFile; applies(filePath: string): Promise; getDependencyTypes(): TemplateDependency[]; disableFeature(id: string): void; } type AlterHookContext = { [P in K]: T[]; }; interface ModuleHooks { 'blokkli:alter-features': (ctx: AlterHookContext<'features', CollectedFeatureFile>) => void | Promise; 'blokkli:alter-icons': (ctx: AlterHookContext<'icons', CollectedFile>) => void | Promise; 'blokkli:alter-blocks': (ctx: AlterHookContext<'blocks', CollectedBlockFile>) => void | Promise; } declare module '@nuxt/schema' { interface NuxtHooks extends ModuleHooks { } } type HandleWatchEventResult = { hasChanged: boolean; }; type ValidationSeverity = 'error' | 'warning'; type ValidationError = { message: string; severity?: ValidationSeverity; }; declare class CollectedFile { readonly filePath: string; fileContents: string; constructor(filePath: string, fileContents: string); handleChange(_helper: ModuleHelper): Promise; /** * Validate the collected file and return any errors. * Override this method in subclasses to add validation logic. */ validate(_icons: IconCollector): ValidationError[]; } declare abstract class Collector implements ValidationInterface { protected helper: ModuleHelper; files: Map; protected needsFileContents: boolean; constructor(helper: ModuleHelper); abstract init(): Promise; abstract runHooks(): Promise; abstract applies(filePath: string): Promise; abstract createCollectedFile(filePath: string, fileContents?: string): T; abstract getDependencyTypes(): TemplateDependency[]; addFile(filePath: string): Promise; protected handleAdd(filePath: string): Promise; protected handleChange(filePath: string): Promise; protected handleUnlink(filePath: string): Promise | boolean; private handleAddDir; private handleUnlinkDir; handleWatchEvent(event: WatchEvent, filePath: string): Promise; /** * Validate all collected files and log any errors/warnings to the console. * @returns true if there are validation errors (not warnings), false otherwise. */ validate(icons: IconCollector): boolean; } declare class IconCollector extends Collector { protected needsFileContents: boolean; private srcFromModule; private validMaterialIconNames; private validFileIconNames; constructor(helper: ModuleHelper); private updateValidFileIconNames; /** * Load all valid Material Symbols icon names from the package. */ private loadValidMaterialIconNames; /** * Check if a given string is a valid Material Symbols icon name. * * @param name - The icon name to check (should include `bk_mdi_` prefix). * * @returns True if the icon name is valid. */ isValidIconName(name: string): boolean; /** * Check if a given string is a valid Material Symbols icon name. * * @param name - The icon name to check (should include `bk_mdi_` prefix). * * @returns True if the icon name is valid. */ isValidMaterialIconName(name: string): boolean; /** * Get all valid Material Symbols icon names. * * @returns An array of all valid icon names (with `bk_mdi_` prefix). */ getValidMaterialIconNames(): string[]; handleWatchEvent(event: WatchEvent, filePath: string): Promise; init(): Promise; runHooks(): void | Promise; applies(filePath: string): Promise; getDependencyTypes(): TemplateDependency[]; createCollectedFile(filePath: string, fileContents?: string): CollectedFile; } declare class ThemeData { css: string; fullTheme: Record; hasCustomTheme: boolean; constructor(helper: ModuleHelper); } interface AdapterExtensionDefinition { namespace: string; path: string; } interface ComplexOptionTypeDefinition { id: string; typeName: string; typePath: string; editorComponentPath: string; editTitle: { key: string; defaultTranslation: string; }; editorIcon: string; } declare class ModuleContext { helper: ModuleHelper; icons: IconCollector; features: FeatureCollector; blocks: BlockCollector; theme: ThemeData; private templates; private templateContents; private adapterExtensions; private featureFragments; private complexOptionTypes; private cssFiles; private contentPaths; private additionalIcons; collectors: Collector[]; constructor(helper: ModuleHelper, icons: IconCollector, features: FeatureCollector, blocks: BlockCollector, theme: ThemeData); addCSS(filePath: string): void; getCSSFiles(): string[]; /** * Register a directory containing Vue files that should participate in * blökkli's CSS build pipeline. Files in these directories will: * - Have their Tailwind utility classes generated and included in the output * - Have their template class names mangled (_bk_ prefix) at build time * - Have their