/**
 * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
 */
/**
 * @module media-embed/mediaembedconfig
 */
import type { ToolbarConfigItem } from '@ckeditor/ckeditor5-core';
import type { ArrayOrItem } from '@ckeditor/ckeditor5-utils';
/**
 * The configuration of the media embed features.
 *
 * Read more about {@glink features/media-embed/media-embed-configuration configuring the media embed feature}.
 *
 * ```ts
 * ClassicEditor
 * 	.create( {
 * 			mediaEmbed: ... // Media embed feature options.
 * 	} )
 * 	.then( ... )
 * 	.catch( ... );
 * ```
 *
 * See {@link module:core/editor/editorconfig~EditorConfig all editor options}.
 */
export interface MediaEmbedConfig {
    /**
     * The default media providers supported by the editor.
     *
     * The names of providers with rendering functions (previews):
     *
     * * "dailymotion",
     * * "spotify",
     * * "youtube",
     * * "vimeo"
     *
     * The names of providers without rendering functions:
     *
     * * "instagram",
     * * "twitter",
     * * "googleMaps",
     * * "flickr",
     * * "facebook"
     *
     * See the {@link module:media-embed/mediaembedconfig~MediaEmbedProvider provider syntax} to learn more about
     * different kinds of media and media providers.
     *
     * **Note**: The default media provider configuration may not support all possible media URLs,
     * only the most common are included.
     *
     * Media without rendering functions are always represented in the data using the "semantic" markup. See
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`} to
     * learn more about possible data outputs.
     *
     * The priority of media providers corresponds to the order of configuration. The first provider
     * to match the URL is always used, even if there are other providers that support a particular URL.
     * The URL is never matched against the remaining providers.
     *
     * To discard **all** default media providers, simply override this configuration with your own
     * {@link module:media-embed/mediaembedconfig~MediaEmbedProvider definitions}:
     *
     * ```ts
     * ClassicEditor
     * 	.create( {
     * 		plugins: [ MediaEmbed, ... ],
     * 		mediaEmbed: {
     * 			providers: [
     * 				{
     * 					 name: 'myProvider',
     * 					 url: /^example\.com\/media\/(\w+)/,
     * 					 html: match => '...'
     * 				},
     * 				...
     * 				]
     * 		}
     * 	} )
     * 	.then( ... )
     * 	.catch( ... );
     * ```
     *
     * You can take inspiration from the default configuration of this feature which you can find in:
     * https://github.com/ckeditor/ckeditor5-media-embed/blob/master/src/mediaembedediting.js
     *
     * To **extend** the list of default providers, use
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}.
     *
     * To **remove** certain providers, use
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#removeProviders `config.mediaEmbed.removeProviders`}.
     */
    providers?: Array<MediaEmbedProvider>;
    /**
     * The additional media providers supported by the editor. This configuration helps extend the default
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#providers}.
     *
     * ```ts
     * ClassicEditor
     * 	.create( {
     * 		plugins: [ MediaEmbed, ... ],
     * 		mediaEmbed: {
     * 			extraProviders: [
     * 				{
     * 					 name: 'extraProvider',
     * 					 url: /^example\.com\/media\/(\w+)/,
     * 					 html: match => '...'
     * 				},
     * 				...
     * 				]
     * 		}
     * 	} )
     * 	.then( ... )
     * 	.catch( ... );
     * ```
     *
     * See the {@link module:media-embed/mediaembedconfig~MediaEmbedProvider provider syntax} to learn more.
     */
    extraProviders?: Array<MediaEmbedProvider>;
    /**
     * The list of media providers that should not be used despite being available in
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#providers `config.mediaEmbed.providers`} and
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}
     *
     * ```ts
     * mediaEmbed: {
     * 	removeProviders: [ 'youtube', 'twitter' ]
     * }
     * ```
     */
    removeProviders?: Array<string>;
    /**
     * Overrides the element name used for "semantic" data.
     *
     * This is not relevant if
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`} is set to `true`.
     *
     * When not set, the feature produces the `<oembed>` tag:
     *
     * ```html
     * <figure class="media">
     * 	<oembed url="https://url"></oembed>
     * </figure>
     * ```
     *
     * To override the element name with, for instance, the `o-embed` name:
     *
     * ```ts
     * mediaEmbed: {
     * 	elementName: 'o-embed'
     * }
     * ```
     *
     * This will produce semantic data with the `<o-embed>` tag:
     *
     * ```html
     * <figure class="media">
     * 	<o-embed url="https://url"></o-embed>
     * </figure>
     * ```
     *
     * @default 'oembed'
     */
    elementName?: string;
    /**
     * Controls the data format produced by the feature.
     *
     * When `false` (default), the feature produces "semantic" data, i.e. it does not include the preview of
     * the media, just the `<oembed>` tag with the `url` attribute:
     *
     * ```ts
     * <figure class="media">
     * 	<oembed url="https://url"></oembed>
     * </figure>
     * ```
     *
     * When `true`, the media is represented in the output in the same way it looks in the editor,
     * i.e. the media preview is saved to the database:
     *
     * ```ts
     * <figure class="media">
     * 	<div data-oembed-url="https://url">
     * 		<iframe src="https://preview"></iframe>
     * 	</div>
     * </figure>
     * ```
     *
     * **Note:** Media without preview are always represented in the data using the "semantic" markup
     * regardless of the value of the `previewsInData`. Learn more about different kinds of media
     * in the {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#providers `config.mediaEmbed.providers`}
     * configuration description.
     *
     * @default false
     */
    previewsInData?: boolean;
    /**
     * Items to be placed in the media embed toolbar.
     * This option requires adding {@link module:media-embed/mediaembedtoolbar~MediaEmbedToolbar} to the plugin list.
     *
     * Each entry is one of:
     *
     * * a component name (string) — including the built-in alignment buttons (e.g. `'mediaEmbed:alignCenter'`)
     *   and built-in dropdowns (`'mediaEmbed:wrapText'`, `'mediaEmbed:breakText'`),
     * * a custom split-button media style dropdown definition (object) following the
     *   {@link module:media-embed/mediaembedconfig~MediaStyleDropdownDefinition} shape — registered
     *   alongside the built-in dropdowns and inheriting the same auto-skip / fallback-defaultItem behavior,
     * * a generic nested toolbar grouping (`{ label, items }`) — same shape as in
     *   {@link module:core/editor/editorconfig~EditorConfig#toolbar `config.toolbar`}.
     *
     * ```ts
     * mediaEmbed: {
     * 	toolbar: [
     * 		'mediaEmbed:alignCenter',
     * 		{
     * 			name: 'mediaEmbed:myAlignments',
     * 			title: 'Alignment',
     * 			items: [ 'mediaEmbed:alignBlockLeft', 'mediaEmbed:alignBlockRight' ],
     * 			defaultItem: 'mediaEmbed:alignBlockLeft'
     * 		}
     * 	]
     * }
     * ```
     */
    toolbar?: Array<ToolbarConfigItem | MediaStyleDropdownDefinition>;
    /**
     * The {@link module:media-embed/mediaembedstyle~MediaEmbedStyle media embed style} feature configuration.
     *
     * Available out of the box: five built-in alignment styles — `'alignLeft'`, `'alignBlockLeft'`,
     * `'alignCenter'` (default), `'alignBlockRight'`, `'alignRight'`.
     *
     * Restrict the set to a subset of built-ins:
     *
     * ```ts
     * mediaEmbed: {
     * 	styles: {
     * 		options: [ 'alignBlockLeft', 'alignCenter', 'alignBlockRight' ]
     * 	}
     * }
     * ```
     *
     * Override fields of a built-in by re-declaring with the same `name`:
     *
     * ```ts
     * mediaEmbed: {
     * 	styles: {
     * 		options: [
     * 			{ name: 'alignCenter', title: 'Center' },
     * 			'alignLeft',
     * 			'alignRight'
     * 		]
     * 	}
     * }
     * ```
     *
     * Register a custom (e.g. semantical) style by supplying a complete definition:
     *
     * ```ts
     * import sideIcon from 'path/to/icon.svg';
     *
     * mediaEmbed: {
     * 	styles: {
     * 		options: [
     * 			'alignCenter',
     * 			{
     * 				name: 'side',
     * 				title: 'Side media',
     * 				icon: sideIcon,
     * 				className: 'media-style-side'
     * 			}
     * 		]
     * 	}
     * }
     * ```
     *
     * When omitted, all five built-in styles are available.
     */
    styles?: MediaStyleConfig;
}
/**
 * The configuration for the {@link module:media-embed/mediaembedstyle~MediaEmbedStyle} feature.
 *
 * See {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#styles `config.mediaEmbed.styles`}
 * for details and examples.
 */
export interface MediaStyleConfig {
    /**
     * A list of media style options. Each entry is either:
     *
     * * a string referencing a built-in style by name (`'alignLeft'`, `'alignBlockLeft'`,
     *   `'alignCenter'`, `'alignBlockRight'`, `'alignRight'`),
     * * an object overriding fields of a built-in (matched by `name`),
     * * an object defining a new custom style.
     *
     * Defaults to all five built-in styles when omitted.
     */
    options?: Array<string | MediaStyleOptionDefinition>;
}
/**
 * The definition of a single media style option used by the
 * {@link module:media-embed/mediaembedstyle~MediaEmbedStyle media embed style} feature.
 *
 * To customize a built-in style, re-declare it with the same `name` — only the fields
 * you set will be replaced; the rest are inherited from the built-in. To register a
 * brand-new style, provide a fresh `name` and a complete definition (`title`, `icon`,
 * and — unless `isDefault: true` — `className`).
 *
 * ```ts
 * import sideIcon from 'path/to/icon.svg';
 *
 * const sideStyle = {
 * 	name: 'side',
 * 	title: 'Side media',
 * 	icon: sideIcon,
 * 	className: 'media-style-side'
 * };
 * ```
 *
 * Each option registers a toggle button under the name `'mediaEmbed:{name}'` in the
 * {@link module:ui/componentfactory~ComponentFactory UI component factory}.
 */
export interface MediaStyleOptionDefinition {
    /**
     * The unique style name. It is used to:
     *
     * * reference a built-in style or define a custom one,
     * * store the chosen style in the model as the `mediaStyle` attribute,
     * * register the toolbar button under `'mediaEmbed:{name}'`.
     */
    name: string;
    /**
     * The button title. The title is wrapped in `editor.t()` at button creation,
     * so titles that match keys in the official translation set will be localized
     * automatically.
     *
     * Required when defining a custom style. Inherited from the built-in style with
     * the matching `name` when overriding a built-in.
     */
    title?: string;
    /**
     * The button icon. Either an SVG XML source string, or one of the keys in
     * `DEFAULT_ICONS` (`'inlineLeft'`, `'left'`, `'center'`, `'right'`, `'inlineRight'`)
     * to use one of the icons shipped with the plugin.
     *
     * Required when defining a custom style. Inherited from the built-in style with
     * the matching `name` when overriding a built-in.
     */
    icon?: string;
    /**
     * The CSS class added to the view `<figure>` when this style is applied. Required
     * for every non-default style — default styles are encoded as the absence of the
     * `mediaStyle` attribute, so they intentionally have no class.
     *
     * Inherited from the built-in style with the matching `name` when not set.
     */
    className?: string;
    /**
     * When `true`, this style is the default state — applying it removes the
     * `mediaStyle` attribute from the model element (no class is written to the view).
     * Default styles must not define a `className`.
     *
     * Inherited from the built-in style with the matching `name` when not set.
     */
    isDefault?: boolean;
}
/**
 * A media style option resolved by the normalizer — built-in inheritance has been applied
 * and {@link module:media-embed/mediaembedstyle/utils~normalizeStyles} has already verified
 * the required fields. UI and editing internals consume this shape.
 *
 * @internal
 */
export type NormalizedMediaStyleOption = Required<Pick<MediaStyleOptionDefinition, 'name' | 'title' | 'icon'>> & Pick<MediaStyleOptionDefinition, 'className' | 'isDefault'>;
/**
 * The definition of a split-button dropdown that groups several media style buttons.
 *
 * Integrators can declare custom dropdowns inline in
 * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#toolbar `config.mediaEmbed.toolbar`}
 * alongside button-name strings; `defaultItem` is the discriminator that distinguishes a
 * split-button media style dropdown from a generic toolbar grouping.
 *
 * ```ts
 * mediaEmbed: {
 * 	toolbar: [
 * 		'mediaEmbed:alignCenter',
 * 		{
 * 			name: 'mediaEmbed:myAlignments',
 * 			title: 'Alignment',
 * 			items: [ 'mediaEmbed:alignBlockLeft', 'mediaEmbed:alignBlockRight' ],
 * 			defaultItem: 'mediaEmbed:alignBlockLeft'
 * 		}
 * 	]
 * }
 * ```
 *
 * All names (`name`, `items[]`, `defaultItem`) use the full prefixed component-factory form.
 * Items referencing styles that are not in the resolved
 * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#styles `config.mediaEmbed.styles`} list
 * are filtered out at registration time. A dropdown that ends up with fewer than two items is
 * skipped. If the configured `defaultItem` was filtered out, the first surviving item is used.
 */
export interface MediaStyleDropdownDefinition {
    /**
     * The dropdown name. Registered as-is in the UI component factory, so it must use the
     * `mediaEmbed:` prefix (for example, `'mediaEmbed:myAlignments'`).
     */
    name: string;
    /**
     * The dropdown title, used both for the split-button label and the dropdown arrow tooltip.
     */
    title: string;
    /**
     * Prefixed style names included in the dropdown (for example,
     * `[ 'mediaEmbed:alignBlockLeft', 'mediaEmbed:alignBlockRight' ]`).
     */
    items: Array<string>;
    /**
     * The default child whose icon and label the split button mirrors when no child is active.
     * Must be one of the `items`.
     */
    defaultItem: string;
}
/**
 * The media embed provider descriptor. Used in
 * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#providers `config.mediaEmbed.providers`} and
 * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#extraProviders `config.mediaEmbed.extraProviders`}.
 *
 * See {@link module:media-embed/mediaembedconfig~MediaEmbedConfig} to learn more.
 *
 * ```ts
 * {
 * 	name: 'example',
 *
 * 	// The following RegExp matches https://www.example.com/media/{media id},
 * 	// (either with "http(s)://" and "www" or without), so the valid URLs are:
 * 	//
 * 	// * https://www.example.com/media/{media id},
 * 	// * http://www.example.com/media/{media id},
 * 	// * www.example.com/media/{media id},
 * 	// * example.com/media/{media id}
 * 	url: /^example\.com\/media\/(\w+)/,
 *
 * 	// The rendering function of the provider.
 * 	// Used to represent the media when editing the content (i.e. in the view)
 * 	// and also in the data output of the editor if semantic data output is disabled.
 * 	html: match => `The HTML representing the media with ID=${ match[ 1 ] }.`
 * }
 * ```
 *
 * You can allow any sort of media in the editor using the "allow–all" `RegExp`.
 * But mind that, since URLs are processed in the order of configuration, if one of the previous
 * `RegExps` matches the URL, it will have a precedence over this one.
 *
 * ```ts
 * {
 * 	name: 'allow-all',
 * 	url: /^.+/
 * }
 * ```
 *
 * To implement responsive media, set an `aspect-ratio` on the iframe. The HTML `width` and
 * `height` attributes act as the intrinsic size (useful for layout hints in containers like
 * table cells), while CSS `width: 100%` and `height: auto` make the element scale with its
 * container while preserving the declared aspect ratio. The iframe is wrapped in a plain
 * `<div>` so external styles or queries that target this wrapper continue to work:
 *
 * ```ts
 * {
 * 	...
 * 	html: match =>
 * 		'<div>' +
 * 			`<iframe src="..." width="1280" height="720" ` +
 * 				`style="width: 100%; height: auto; aspect-ratio: 16 / 9; border: 0; display: block;" ` +
 * 				'frameborder="0" allowfullscreen>' +
 * 			'</iframe>' +
 * 		'</div>'
 * }
 * ```
 */
export interface MediaEmbedProvider {
    /**
     * The name of the provider. Used e.g. when
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#removeProviders removing providers}.
     */
    name: string;
    /**
     * The `RegExp` object (or array of objects) defining the URL of the media.
     * If any URL matches the `RegExp`, it becomes the media in the editor model, as defined by the provider. The result
     * of matching (output of `String.prototype.match()`) is passed to the `html` rendering function of the media.
     *
     * **Note:** You do not need to include the protocol (`http://`, `https://`) and `www` subdomain in your `RegExps`,
     * they are stripped from the URLs before matching anyway.
     */
    url: ArrayOrItem<RegExp>;
    /**
     * The rendering function of the media. The function receives the entire matching
     * array from the corresponding `url` `RegExp` as an argument, allowing rendering a dedicated
     * preview of the media identified by a certain ID or a hash. When not defined, the media embed feature
     * will use a generic media representation in the view and output data.
     * Note that when
     * {@link module:media-embed/mediaembedconfig~MediaEmbedConfig#previewsInData `config.mediaEmbed.previewsInData`}
     * is `true`, the rendering function **will always** be used for the media in the editor data output.
     */
    html?: (match: RegExpMatchArray) => string;
}
