Find and replace feature for CKEditor 5 with comprehensive search capabilities and UI integration.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Complete type definitions for all interfaces, configuration options, and event types used throughout the find and replace system.
Configuration interface for the find and replace plugin.
/**
* Configuration options for the find and replace feature.
* Used in the editor configuration object.
*/
interface FindAndReplaceConfig {
/**
* The type of UI to display for find and replace operations.
* - 'dialog': Opens in a modal dialog (default)
* - 'dropdown': Opens in a dropdown panel
* @default 'dialog'
*/
uiType?: 'dialog' | 'dropdown';
}Usage Example:
ClassicEditor
.create(document.querySelector('#editor'), {
findAndReplace: {
uiType: 'dropdown' // Use dropdown instead of dialog
}
});Represents a single search result with optional metadata.
/**
* Represents a single find result with position and metadata information.
*/
type FindResultType = {
/** Optional unique identifier for the result */
id?: string;
/** Optional display label for the result */
label?: string;
/** Optional start position in the text */
start?: number;
/** Optional end position in the text */
end?: number;
/** Optional CKEditor marker reference for highlighting */
marker?: Marker;
};Options for controlling find operations.
/**
* Options for find operations controlling search behavior.
*/
interface FindAttributes {
/** Whether to perform case-sensitive matching */
matchCase?: boolean;
/** Whether to match whole words only */
wholeWords?: boolean;
}Usage Example:
const options: FindAttributes = {
matchCase: true,
wholeWords: false
};
editor.execute('find', 'search term', options);Function type for custom search implementations.
/**
* Custom search callback function for implementing specialized search logic.
* @param params - Object containing the model item and its text representation
* @returns Search results with metadata or legacy result array
*/
type FindCallback = ({ item, text }: {
/** The model item being searched */
item: ModelItem;
/** Text representation of the item */
text: string;
}) => FindCallbackResultObject | FindCallbackResult;Modern result object returned by find callbacks.
/**
* Result object returned by modern find callbacks.
* Preferred over the legacy FindCallbackResult array format.
*/
interface FindCallbackResultObject {
/** Array of find results */
results: Array<FindResultType>;
/** The search text that was used */
searchText: string;
}Legacy result type for backward compatibility.
/**
* Legacy result type returned by find callbacks.
* @deprecated Use FindCallbackResultObject instead
*/
type FindCallbackResult = Array<FindResultType>;Custom Search Example:
// Custom search callback that finds email addresses
const emailSearchCallback: FindCallback = ({ item, text }) => {
const emailRegex = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g;
const results: FindResultType[] = [];
let match;
while ((match = emailRegex.exec(text)) !== null) {
results.push({
id: `email-${match.index}`,
label: match[0],
start: match.index,
end: match.index + match[0].length
});
}
return {
results,
searchText: 'email addresses'
};
};
// Use the custom callback
editor.execute('find', emailSearchCallback);Event types fired by the FindAndReplaceFormView component.
/**
* Event fired when the user triggers a "find next" operation.
*/
interface FindNextEvent {
name: 'findNext';
args: [data?: FindNextEventData];
}
/**
* Event fired when the user triggers a "find previous" operation.
*/
interface FindPreviousEvent {
name: 'findPrevious';
args: [data?: FindEventBaseData];
}
/**
* Event fired when the user triggers a single replace operation.
*/
interface ReplaceEvent {
name: 'replace';
args: [data: ReplaceEventData];
}
/**
* Event fired when the user triggers a replace all operation.
*/
interface ReplaceAllEvent {
name: 'replaceAll';
args: [data: ReplaceEventData];
}/**
* Event fired when the search is reset or cleared.
*/
interface FindResetedEvent {
name: 'searchReseted';
args: [];
}Data passed with find next events, including search options.
/**
* Data object for find next events, extending base find data
* with search option flags.
*/
interface FindNextEventData extends FindEventBaseData {
/** Whether case-sensitive matching is enabled */
matchCase: boolean;
/** Whether whole word matching is enabled */
wholeWords: boolean;
}Base data object for all find-related events.
/**
* Base data object containing the search text for find operations.
*/
interface FindEventBaseData {
/** The text to search for */
searchText: string;
}Data object for replace operations, extending find data with replacement text.
/**
* Data object for replace events, containing both search and replacement text.
*/
interface ReplaceEventData extends FindEventBaseData {
/** The text to replace matches with */
replaceText: string;
}Types related to CKEditor's model system integration.
/**
* CKEditor model item type (imported from CKEditor core)
* Represents any item in the CKEditor model tree.
*/
type ModelItem = any; // From '@ckeditor/ckeditor5-engine'
/**
* CKEditor model range type (imported from CKEditor core)
* Represents a range within the CKEditor model.
*/
type ModelRange = any; // From '@ckeditor/ckeditor5-engine'
/**
* CKEditor marker type (imported from CKEditor core)
* Used for highlighting search results in the editor.
*/
type Marker = any; // From '@ckeditor/ckeditor5-engine'
/**
* CKEditor model type (imported from CKEditor core)
* The main model instance for document manipulation.
*/
type Model = any; // From '@ckeditor/ckeditor5-engine'Types related to CKEditor's UI system integration.
/**
* CKEditor locale type (imported from CKEditor core)
* Used for internationalization and localization.
*/
type Locale = any; // From '@ckeditor/ckeditor5-utils'
/**
* CKEditor view collection type (imported from CKEditor core)
* Collection of UI views for component management.
*/
type ViewCollection = any; // From '@ckeditor/ckeditor5-ui'
/**
* CKEditor focus cycler type (imported from CKEditor core)
* Manages keyboard focus cycling through UI elements.
*/
type FocusCycler = any; // From '@ckeditor/ckeditor5-ui'// Type guard for checking if a result has marker information
function hasMarker(result: FindResultType): result is FindResultType & { marker: Marker } {
return result.marker !== undefined;
}
// Type guard for checking if a result has position information
function hasPosition(result: FindResultType): result is FindResultType & { start: number; end: number } {
return result.start !== undefined && result.end !== undefined;
}
// Usage
const result: FindResultType = getSearchResult();
if (hasMarker(result)) {
// TypeScript knows result.marker is defined
console.log('Marker name:', result.marker.name);
// Can safely access marker-specific properties
const range = result.marker.getRange();
console.log('Marker range:', range);
}
if (hasPosition(result)) {
// TypeScript knows result.start and result.end are defined
console.log('Position:', result.start, 'to', result.end);
// Can safely perform position-based operations
const length = result.end - result.start;
console.log('Match length:', length);
}// Utility type for extracting callback result type
type CallbackResult<T extends FindCallback> = ReturnType<T>;
// Utility type for modern callback functions
type ModernFindCallback = (params: { item: ModelItem; text: string }) => FindCallbackResultObject;
// Type for legacy callback functions
type LegacyFindCallback = (params: { item: ModelItem; text: string }) => FindCallbackResult;interface EditorConfig {
plugins: any[];
findAndReplace: FindAndReplaceConfig;
// ... other editor options
}
const config: EditorConfig = {
plugins: [FindAndReplace, /* other plugins */],
findAndReplace: {
uiType: 'dialog'
}
};// Access configuration at runtime
const editor = await ClassicEditor.create(element, config);
const findReplaceConfig = editor.config.get('findAndReplace') as FindAndReplaceConfig;
console.log('UI Type:', findReplaceConfig.uiType); // 'dialog' or 'dropdown'
// Conditional behavior based on configuration
if (findReplaceConfig.uiType === 'dialog') {
// Handle dialog-specific setup
console.log('Using dialog UI mode');
} else {
// Handle dropdown-specific setup
console.log('Using dropdown UI mode');
}Install with Tessl CLI
npx tessl i tessl/npm-ckeditor--ckeditor5-find-and-replace