Link plugin for Plate rich text editor providing hyperlink functionality with URL validation, keyboard shortcuts, and UI components
—
URL utility functions provide robust URL processing, validation, and encoding/decoding capabilities with error handling and security considerations.
Validates URLs according to plugin configuration, allowing internal links and configured schemes.
/**
* Validate a URL according to plugin configuration
* @param editor - Slate editor instance for accessing configuration
* @param url - URL string to validate
* @returns Whether the URL is valid
*/
function validateUrl(editor: SlateEditor, url: string): boolean;Usage Examples:
import { validateUrl } from "@udecode/plate-link";
// Basic validation
const isValid = validateUrl(editor, "https://example.com");
console.log(isValid); // true
// Internal links are allowed
const isInternalValid = validateUrl(editor, "/internal/page");
console.log(isInternalValid); // true
// Fragment links are allowed
const isFragmentValid = validateUrl(editor, "#section");
console.log(isFragmentValid); // true
// Scheme validation based on plugin config
const isMailtoValid = validateUrl(editor, "mailto:user@example.com");
// true if 'mailto' in allowedSchemesValidation Rules:
/ are always valid# are always valid['http', 'https', 'mailto', 'tel']Conditionally encodes URLs that aren't already encoded, with graceful error handling.
/**
* Encode URL if not already encoded, with error handling
* @param url - URL string to potentially encode
* @returns Encoded URL string
*/
function encodeUrlIfNeeded(url: string): string;Usage Examples:
import { encodeUrlIfNeeded } from "@udecode/plate-link";
// Encode spaces and special characters
const encoded = encodeUrlIfNeeded("https://example.com/path with spaces");
console.log(encoded); // "https://example.com/path%20with%20spaces"
// Already encoded URLs are left unchanged
const alreadyEncoded = encodeUrlIfNeeded("https://example.com/path%20encoded");
console.log(alreadyEncoded); // "https://example.com/path%20encoded"
// Handles malformed URLs gracefully
const malformed = encodeUrlIfNeeded("not-a-url");
console.log(malformed); // Returns original string if encoding failsEncoding Behavior:
Safely decodes URLs with error handling, returning the original URL if decoding fails.
/**
* Safely decode a URL with error handling
* @param url - URL string to decode
* @returns Decoded URL string, or original if decoding fails
*/
function safeDecodeUrl(url: string): string;Usage Examples:
import { safeDecodeUrl } from "@udecode/plate-link";
// Decode percent-encoded URLs
const decoded = safeDecodeUrl("https://example.com/path%20with%20spaces");
console.log(decoded); // "https://example.com/path with spaces"
// Handles malformed encoded URLs
const malformed = safeDecodeUrl("https://example.com/bad%encoding");
console.log(malformed); // Returns original string if decoding fails
// Already decoded URLs pass through
const plainUrl = safeDecodeUrl("https://example.com/plain-path");
console.log(plainUrl); // "https://example.com/plain-path"Decoding Safety:
Generates proper HTML attributes for link elements, including sanitization and default attributes.
/**
* Generate HTML attributes for link elements with sanitization
* @param editor - Slate editor instance for configuration access
* @param link - Link element to generate attributes for
* @returns React anchor element attributes
*/
function getLinkAttributes(
editor: SlateEditor,
link: TLinkElement
): React.AnchorHTMLAttributes<HTMLAnchorElement>;Usage Examples:
import { getLinkAttributes } from "@udecode/plate-link";
// Basic attribute generation
const linkElement = {
type: 'a',
url: 'https://example.com',
children: [{ text: 'Example' }]
};
const attributes = getLinkAttributes(editor, linkElement);
console.log(attributes);
// { href: 'https://example.com', target: '_blank', rel: 'noopener' }
// With custom target
const linkWithTarget = {
type: 'a',
url: 'https://example.com',
target: '_self',
children: [{ text: 'Example' }]
};
const customAttributes = getLinkAttributes(editor, linkWithTarget);
console.log(customAttributes);
// { href: 'https://example.com', target: '_self' }Attribute Processing:
dangerouslySkipSanitization optionCreates properly formatted link nodes with validation and attribute processing.
/**
* Create a properly formatted link node
* @param editor - Slate editor instance
* @param options - Link creation options
* @returns Formatted link element
*/
function createLinkNode(
editor: SlateEditor,
options: CreateLinkNodeOptions
): TLinkElement;
interface CreateLinkNodeOptions {
/** The URL for the link */
url: string;
/** Child text nodes (defaults to URL as text) */
children?: TText[];
/** Link target attribute */
target?: string;
/** Text content (alternative to children) */
text?: string;
}Usage Examples:
import { createLinkNode } from "@udecode/plate-link";
// Create basic link node
const linkNode = createLinkNode(editor, {
url: "https://example.com",
text: "Example Link"
});
// Create with custom children
const customLink = createLinkNode(editor, {
url: "https://example.com",
children: [
{ text: "Visit ", bold: true },
{ text: "Example" }
]
});
// Create with target
const externalLink = createLinkNode(editor, {
url: "https://external.com",
text: "External Link",
target: "_blank"
});import { validateUrl } from "@udecode/plate-link";
function getUrlScheme(url: string): string | null {
try {
const urlObj = new URL(url);
return urlObj.protocol.slice(0, -1); // Remove trailing colon
} catch {
return null;
}
}
function isExternalUrl(url: string): boolean {
return !url.startsWith('/') && !url.startsWith('#') && getUrlScheme(url) !== null;
}import { encodeUrlIfNeeded, safeDecodeUrl } from "@udecode/plate-link";
function normalizeUrl(url: string): string {
// Decode first to handle double-encoding
const decoded = safeDecodeUrl(url);
// Re-encode to ensure proper encoding
return encodeUrlIfNeeded(decoded);
}
function addProtocolIfNeeded(url: string): string {
if (!url.includes('://') && !url.startsWith('/') && !url.startsWith('#')) {
return `https://${url}`;
}
return url;
}import { validateUrl, encodeUrlIfNeeded } from "@udecode/plate-link";
function processUrls(editor: SlateEditor, urls: string[]): Array<{
original: string;
processed: string;
isValid: boolean;
}> {
return urls.map(url => {
const processed = encodeUrlIfNeeded(url);
const isValid = validateUrl(editor, processed);
return {
original: url,
processed,
isValid
};
});
}Install with Tessl CLI
npx tessl i tessl/npm-udecode--plate-link