256 lines
8.3 KiB
Markdown
256 lines
8.3 KiB
Markdown
# SbRichTextEditor
|
|
|
|
A rich text editor component for creating and editing formatted content.
|
|
|
|
## Parameters
|
|
|
|
| Parameter | Type | Default | Description |
|
|
|-----------|------|---------|-------------|
|
|
| Value | string? | null | The HTML content (two-way bindable) |
|
|
| ValueChanged | EventCallback\<string?\> | - | Callback when content changes |
|
|
| Mode | SbEditorMode | SbEditorMode.Html | Editor mode (e.g. Html) |
|
|
| ToolbarItems | IReadOnlyList\<SbEditorToolbarItem\>? | null | Custom toolbar items (when null, default toolbar is used) |
|
|
| Placeholder | string? | null | Placeholder text when empty |
|
|
| ReadOnly | bool | false | Whether the editor is read-only |
|
|
| Disabled | bool | false | Whether the editor is disabled |
|
|
| RightToLeft | bool | false | Whether the editor is RTL |
|
|
| Height | string? | "300px" | Editor content area height |
|
|
| HideToolbar | bool | false | When true, hides the toolbar |
|
|
| ShowCharacterCount | bool | false | Whether to show character count in footer |
|
|
| ShowWordCount | bool | false | Whether to show word count in footer |
|
|
| UseToolbarContributors | bool | false | Enable toolbar items from registered contributor services |
|
|
| IncludeDefaultToolbarItems | bool | true | Whether to include default toolbar items |
|
|
| Class | string? | null | Additional CSS classes |
|
|
|
|
Additional parameters for dialogs and accessibility (e.g. ToolbarAriaLabel, EditorAriaLabel, LinkDialogTitle, ImageDialogTitle, WordCountFormat, CharacterCountFormat, and various link/image dialog labels) are available; when null or not set, defaults are used.
|
|
|
|
## Events
|
|
|
|
| Event | Type | Description |
|
|
|-------|------|-------------|
|
|
| ValueChanged | EventCallback\<string?\> | Fired when the content changes |
|
|
| OnChange | EventCallback\<string?\> | Fired when content changes (receives current HTML) |
|
|
| OnFocus | EventCallback | Fired when editor gains focus |
|
|
| OnBlur | EventCallback | Fired when editor loses focus |
|
|
|
|
## CSS Classes
|
|
|
|
- `sb-editor` - Base class
|
|
- `sb-editor__toolbar` - Toolbar container
|
|
- `sb-editor__toolbar-separator` - Toolbar separator
|
|
- `sb-editor__toolbar-select` - Toolbar dropdown (e.g. headings)
|
|
- `sb-editor__toolbar-btn` - Toolbar button
|
|
- `sb-editor__toolbar-btn--active` - Active format button
|
|
- `sb-editor__toolbar-icon` - Toolbar icon
|
|
- `sb-editor__content` - Editable content area
|
|
- `sb-editor__footer` - Footer (word/character count)
|
|
- `sb-editor__count` - Count display
|
|
- `sb-editor__link-dialog` - Link/Image dialog container
|
|
- `sb-editor__link-dialog-field` - Dialog field
|
|
- `sb-editor__link-input` - Dialog input
|
|
- `sb-editor--disabled` - Disabled state
|
|
- `sb-editor--readonly` - Read-only state
|
|
- `sb-editor--rtl` - Right-to-left state
|
|
|
|
## Examples
|
|
|
|
### Basic Usage
|
|
|
|
```razor
|
|
<SbRichTextEditor @bind-Value="content" />
|
|
```
|
|
|
|
### With Placeholder
|
|
|
|
```razor
|
|
<SbRichTextEditor @bind-Value="description"
|
|
Placeholder="Enter description..." />
|
|
```
|
|
|
|
### Custom Height
|
|
|
|
```razor
|
|
<SbRichTextEditor @bind-Value="articleContent"
|
|
Height="400px" />
|
|
```
|
|
|
|
### Without Toolbar
|
|
|
|
```razor
|
|
<SbRichTextEditor @bind-Value="note"
|
|
HideToolbar="true"
|
|
Height="200px" />
|
|
```
|
|
|
|
### Read-Only Display
|
|
|
|
```razor
|
|
<SbRichTextEditor Value="@displayContent" ReadOnly="true" />
|
|
```
|
|
|
|
### With Form Field
|
|
|
|
```razor
|
|
<SbFormField Label="Description" Required="true">
|
|
<SbRichTextEditor @bind-Value="model.Description"
|
|
Placeholder="Enter a detailed description..." />
|
|
<SbFieldError For="() => model.Description" />
|
|
</SbFormField>
|
|
```
|
|
|
|
## Toolbar Extensibility
|
|
|
|
The `SbRichTextEditor` supports extending the toolbar with custom buttons from external modules using the contributor pattern.
|
|
|
|
### Enabling Toolbar Contributors
|
|
|
|
To use toolbar contributors, set `UseToolbarContributors="true"` on the component:
|
|
|
|
```razor
|
|
<SbRichTextEditor @bind-Value="content"
|
|
UseToolbarContributors="true" />
|
|
```
|
|
|
|
### Implementing a Toolbar Contributor
|
|
|
|
Create a class that implements `IRteToolbarContributor`:
|
|
|
|
```csharp
|
|
using SufiChain.SufiBlazor.Contracts.Editors;
|
|
|
|
public class MediaToolbarContributor : IRteToolbarContributor
|
|
{
|
|
// Items with lower Order appear first. Default items use 0-100.
|
|
// Use > 100 to add after defaults, negative values to add before.
|
|
public int Order => 150;
|
|
|
|
public Task ConfigureToolbarAsync(RteToolbarContext context)
|
|
{
|
|
// Add an "Insert Media" button
|
|
context.Items.Add(new RteToolbarContributedItem
|
|
{
|
|
Id = "insert-media",
|
|
Label = "Insert Media",
|
|
Icon = "image",
|
|
Tooltip = "Insert media from library",
|
|
Group = "insert", // Groups: history, heading, formatting, list, alignment, insert, blocks, custom, actions
|
|
Order = 10,
|
|
OnClickAsync = async (actionContext) =>
|
|
{
|
|
// Access services via DI
|
|
var mediaService = actionContext.ServiceProvider.GetService<IMediaService>();
|
|
|
|
// Get current selection if needed
|
|
var selection = await actionContext.GetSelectionAsync?.Invoke()!;
|
|
|
|
// Insert HTML at cursor position
|
|
var html = "<img src=\"/media/example.jpg\" alt=\"Example\" />";
|
|
await actionContext.InsertHtmlAsync?.Invoke(html)!;
|
|
},
|
|
// Conditionally show/hide
|
|
IsVisible = () => true,
|
|
// Conditionally enable/disable
|
|
IsEnabled = () => true
|
|
});
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Registering Toolbar Contributors
|
|
|
|
Register your contributor in `Program.cs` or your module's service configuration:
|
|
|
|
```csharp
|
|
// Method 1: Using the generic extension method
|
|
services.AddSufiBlazor();
|
|
services.AddRteToolbarContributor<MediaToolbarContributor>();
|
|
|
|
// Method 2: Multiple contributors
|
|
services.AddSufiBlazor();
|
|
services.AddRteToolbarContributor<MediaToolbarContributor>();
|
|
services.AddRteToolbarContributor<EmojiToolbarContributor>();
|
|
|
|
// Method 3: Using RteToolbarOptions configuration
|
|
services.AddSufiBlazor(options =>
|
|
{
|
|
options.AddContributor<MediaToolbarContributor>();
|
|
options.AddContributor<EmojiToolbarContributor>();
|
|
|
|
// Optionally disable default toolbar items
|
|
options.IncludeDefaultItems = false;
|
|
|
|
// Customize group order
|
|
options.GroupOrder = new List<string>
|
|
{
|
|
"formatting",
|
|
"insert",
|
|
"custom",
|
|
"actions"
|
|
};
|
|
});
|
|
```
|
|
|
|
### RteToolbarActionContext
|
|
|
|
The `OnClickAsync` callback receives an `RteToolbarActionContext` with useful actions:
|
|
|
|
| Property | Type | Description |
|
|
|----------|------|-------------|
|
|
| EditorId | string | The unique editor instance ID |
|
|
| ServiceProvider | IServiceProvider | DI service provider |
|
|
| InsertHtmlAsync | Func\<string, Task\> | Insert HTML at cursor |
|
|
| InsertImageAsync | Func\<string, string?, Task\> | Insert image (src, alt) |
|
|
| InsertLinkAsync | Func\<string, string?, Task\> | Insert link (url, text) |
|
|
| GetSelectionAsync | Func\<Task\<string?\>\> | Get selected text |
|
|
| GetHtmlAsync | Func\<Task\<string?\>\> | Get editor HTML content |
|
|
|
|
### Toolbar Groups
|
|
|
|
Items are organized into groups. Use the `Group` property to place your item:
|
|
|
|
| Group | Description |
|
|
|-------|-------------|
|
|
| history | Undo/Redo buttons |
|
|
| heading | Header formatting (H1-H6) |
|
|
| formatting | Bold, Italic, Underline, etc. |
|
|
| list | Ordered/Unordered lists |
|
|
| alignment | Text alignment |
|
|
| insert | Links, Images, Files |
|
|
| blocks | Blockquote, Code blocks |
|
|
| custom | Default group for contributed items |
|
|
| actions | Clear formatting, etc. |
|
|
|
|
### Complete Example: Emoji Picker Contributor
|
|
|
|
```csharp
|
|
public class EmojiToolbarContributor : IRteToolbarContributor
|
|
{
|
|
public int Order => 200;
|
|
|
|
public Task ConfigureToolbarAsync(RteToolbarContext context)
|
|
{
|
|
var emojis = new[] { "😀", "😊", "👍", "❤️", "🎉" };
|
|
|
|
foreach (var (emoji, index) in emojis.Select((e, i) => (e, i)))
|
|
{
|
|
context.Items.Add(new RteToolbarContributedItem
|
|
{
|
|
Id = $"emoji-{index}",
|
|
Label = emoji,
|
|
Tooltip = $"Insert {emoji}",
|
|
Group = "insert",
|
|
Order = 100 + index,
|
|
OnClickAsync = async (actionContext) =>
|
|
{
|
|
await actionContext.InsertHtmlAsync?.Invoke(emoji)!;
|
|
}
|
|
});
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
}
|
|
```
|