@meenainwal/rich-text-editor 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ReadME.md +28 -44
- package/dist/core/Editor.d.ts +133 -0
- package/dist/core/HistoryManager.d.ts +30 -0
- package/dist/core/ImageManager.d.ts +19 -0
- package/dist/core/SelectionManager.d.ts +31 -0
- package/dist/index.d.ts +11 -0
- package/dist/rich-text-editor.css +1 -1
- package/dist/style.d.ts +4 -0
- package/dist/test-editor.cjs +2 -2
- package/dist/test-editor.mjs +535 -232
- package/dist/ui/Toolbar.d.ts +19 -0
- package/dist/ui/toolbar/EmojiList.d.ts +6 -0
- package/dist/ui/toolbar/EmojiPicker.d.ts +19 -0
- package/dist/ui/toolbar/ToolbarItem.d.ts +16 -0
- package/dist/ui/toolbar/items/AlignCenter.d.ts +2 -0
- package/dist/ui/toolbar/items/AlignJustify.d.ts +2 -0
- package/dist/ui/toolbar/items/AlignLeft.d.ts +2 -0
- package/dist/ui/toolbar/items/AlignRight.d.ts +2 -0
- package/dist/ui/toolbar/items/Bold.d.ts +2 -0
- package/dist/ui/toolbar/items/BulletList.d.ts +2 -0
- package/dist/ui/toolbar/items/ClearFormatting.d.ts +2 -0
- package/dist/ui/toolbar/items/Emoji.d.ts +2 -0
- package/dist/ui/toolbar/items/FontFamily.d.ts +2 -0
- package/dist/ui/toolbar/items/FontSize.d.ts +2 -0
- package/dist/ui/toolbar/items/Heading.d.ts +2 -0
- package/dist/ui/toolbar/items/HighlightColor.d.ts +2 -0
- package/dist/ui/toolbar/items/HorizontalRule.d.ts +2 -0
- package/dist/ui/toolbar/items/Image.d.ts +2 -0
- package/dist/ui/toolbar/items/Indent.d.ts +2 -0
- package/dist/ui/toolbar/items/Italic.d.ts +2 -0
- package/dist/ui/toolbar/items/LineHeight.d.ts +2 -0
- package/dist/ui/toolbar/items/Link.d.ts +2 -0
- package/dist/ui/toolbar/items/OrderedList.d.ts +2 -0
- package/dist/ui/toolbar/items/Outdent.d.ts +2 -0
- package/dist/ui/toolbar/items/Redo.d.ts +2 -0
- package/dist/ui/toolbar/items/Strikethrough.d.ts +2 -0
- package/dist/ui/toolbar/items/Table.d.ts +2 -0
- package/dist/ui/toolbar/items/TableActions.d.ts +5 -0
- package/dist/ui/toolbar/items/TextColor.d.ts +2 -0
- package/dist/ui/toolbar/items/Underline.d.ts +2 -0
- package/dist/ui/toolbar/items/Undo.d.ts +2 -0
- package/dist/ui/toolbar/registry.d.ts +2 -0
- package/package.json +15 -10
- package/images/Screenshot from 2026-03-07 12-13-13.png +0 -0
- package/images/editor-preview.png +0 -0
package/ReadME.md
CHANGED
|
@@ -15,12 +15,14 @@ A premium, ultra-lightweight, framework-agnostic rich text editor built entirely
|
|
|
15
15
|
- **Framework Agnostic**: Drop it into React, Vue, Angular, Svelte, or plain HTML projects seamlessly.
|
|
16
16
|
- **Auto-Formatting Magic**: Intelligently parses pasted HTML strings automatically into perfectly formatted rich text.
|
|
17
17
|
- **Beautiful UI**: Modern aesthetics curated with a polished Slate & Indigo color palette, smooth transitions, and dynamic SVG icons.
|
|
18
|
+
- **Table Support**: Natively insert and style interactive HTML tables with ease.
|
|
19
|
+
- **Micro-Animations**: Subtle, premium transitions for tooltips, pickers, and status updates.
|
|
18
20
|
- **Local Image Uploads**: Natively integrates with the OS file picker for rapid inline base64 image insertions.
|
|
19
21
|
- **Flexible Styling**: Full control over font families, complex line heights, text colors, and highlighting.
|
|
22
|
+
- **Customizable Toolbar**: Full control over which tools are visible to the user.
|
|
20
23
|
|
|
21
24
|
### 👎 Cons (Current Limitations)
|
|
22
25
|
- Base64 image storage can increase the raw output string size for very large images (Backend S3 uploading adapter coming soon).
|
|
23
|
-
- Lacks advanced table grid manipulations in the current version.
|
|
24
26
|
- Markdown shortcut typing (e.g., typing `#` for H1) is not natively supported yet.
|
|
25
27
|
|
|
26
28
|
---
|
|
@@ -36,82 +38,64 @@ npm install @meenainwal/rich-text-editor
|
|
|
36
38
|
### Basic Usage (Vanilla JS)
|
|
37
39
|
|
|
38
40
|
```javascript
|
|
39
|
-
import {
|
|
40
|
-
import '@meenainwal/rich-text-editor/
|
|
41
|
+
import { TestEditor } from '@meenainwal/rich-text-editor';
|
|
42
|
+
import '@meenainwal/rich-text-editor/style'; // Simple style import
|
|
41
43
|
|
|
42
44
|
const container = document.getElementById('editor');
|
|
43
|
-
const editor = new
|
|
45
|
+
const editor = new TestEditor(container, {
|
|
44
46
|
placeholder: 'Type something beautiful...',
|
|
45
|
-
autofocus: true
|
|
47
|
+
autofocus: true,
|
|
48
|
+
showStatus: true,
|
|
49
|
+
toolbarItems: ['bold', 'italic', 'heading', 'table', 'link'] // Customize tools
|
|
46
50
|
});
|
|
47
|
-
|
|
48
|
-
// To extract the customized HTML:
|
|
49
|
-
const htmlOutput = editor.getHTML();
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Via CDN (Direct Download, No NPM Required)
|
|
53
|
-
|
|
54
|
-
You can instantly drop the editor into any standard HTML page without installing tools or bundlers. Simply use standard CDN links (like `unpkg.com` or `jsdelivr.net`):
|
|
55
|
-
|
|
56
|
-
```html
|
|
57
|
-
<!-- Load the beautifully styled CSS -->
|
|
58
|
-
<link rel="stylesheet" href="https://unpkg.com/@meenainwal/rich-text-editor/dist/rich-text-editor.css">
|
|
59
|
-
|
|
60
|
-
<!-- Load the Logic Script as an ES Module -->
|
|
61
|
-
<script type="module">
|
|
62
|
-
import { CoreEditor } from 'https://unpkg.com/@meenainwal/rich-text-editor/dist/test-editor.mjs';
|
|
63
|
-
|
|
64
|
-
const container = document.getElementById('editor');
|
|
65
|
-
const editor = new CoreEditor(container);
|
|
66
|
-
</script>
|
|
67
51
|
```
|
|
68
52
|
|
|
69
|
-
### In React
|
|
53
|
+
### In React / Next.js (SSR Safe)
|
|
70
54
|
|
|
71
55
|
```tsx
|
|
56
|
+
"use client";
|
|
72
57
|
import { useEffect, useRef } from 'react';
|
|
73
|
-
import {
|
|
74
|
-
import '@meenainwal/rich-text-editor/
|
|
58
|
+
import { TestEditor } from '@meenainwal/rich-text-editor';
|
|
59
|
+
import '@meenainwal/rich-text-editor/style';
|
|
75
60
|
|
|
76
|
-
export
|
|
61
|
+
export default function Editor() {
|
|
77
62
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
78
63
|
|
|
79
64
|
useEffect(() => {
|
|
80
65
|
if (containerRef.current) {
|
|
81
|
-
|
|
66
|
+
new TestEditor(containerRef.current, {
|
|
67
|
+
onSave: (html) => console.log("Saved:", html)
|
|
68
|
+
});
|
|
82
69
|
}
|
|
83
70
|
}, []);
|
|
84
71
|
|
|
85
72
|
return <div ref={containerRef} />;
|
|
86
|
-
}
|
|
73
|
+
}
|
|
87
74
|
```
|
|
88
75
|
|
|
89
76
|
---
|
|
90
77
|
|
|
91
|
-
## 🗺️ Future Roadmap & Upcoming Updates
|
|
92
|
-
|
|
93
|
-
As the project manager, we are aggressively expanding this editor. Next releases will feature:
|
|
94
|
-
|
|
95
|
-
1. **Phase 2.1 - Markdown Power:** Seamless markdown shortcuts (typing `**bold**`, `## Header`) that auto-convert to rich text instantly.
|
|
96
|
-
2. **Phase 2.2 - Table Support:** An interactive grid UI to insert, resize, and style complex HTML tables.
|
|
97
|
-
3. **Phase 2.3 - Framework Wrappers:** Official, first-party wrapper components for `<ReactEditor />` and `<VueEditor />` for even faster plug-and-play.
|
|
98
|
-
4. **Phase 2.4 - Advanced Image Handlers:** Providing hooks to intercept image uploads and pipe them to external buckets (AWS S3, Cloudinary) to return URLs instead of raw base64.
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
78
|
## ⚙️ Configuration Options
|
|
103
79
|
|
|
104
80
|
| Option | Type | Default | Description |
|
|
105
81
|
| :--- | :--- | :--- | :--- |
|
|
106
82
|
| `placeholder` | `string` | `undefined` | The placeholder text when the editor is empty. |
|
|
107
|
-
| `autofocus` | `boolean` | `false` |
|
|
83
|
+
| `autofocus` | `boolean` | `false` | Focus the editor automatically on initialization. |
|
|
84
|
+
| `dark` | `boolean` | `false` | Enable sophisticated Dark Mode theme. |
|
|
85
|
+
| `showStatus` | `boolean` | `true` | Show/hide the "Saved at..." status in the toolbar. |
|
|
86
|
+
| `toolbarItems` | `string[]` | `all` | Array of tool IDs to display (e.g., `['bold', 'table']`). |
|
|
87
|
+
| `onSave` | `function` | `undefined` | Callback triggered when content is saved. |
|
|
88
|
+
| `autoSaveInterval` | `number` | `1000` | Delay in ms before auto-save triggers after typing. |
|
|
108
89
|
|
|
109
90
|
## 🛠 API Methods
|
|
110
91
|
|
|
111
92
|
- `getHTML()`: Returns the content as a sanitized HTML string.
|
|
112
93
|
- `setHTML(html)`: Programmatically sets the editor content.
|
|
113
94
|
- `focus()`: Forces focus onto the editor.
|
|
114
|
-
- `
|
|
95
|
+
- `setDarkMode(boolean)`: Dynamically toggle dark mode.
|
|
96
|
+
- `insertTable(rows, cols)`: Programmatically insert a table.
|
|
97
|
+
|
|
98
|
+
---
|
|
115
99
|
|
|
116
100
|
## 📄 License
|
|
117
101
|
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { SelectionManager } from './SelectionManager';
|
|
2
|
+
import { ImageManager } from './ImageManager';
|
|
3
|
+
export interface ThemeConfig {
|
|
4
|
+
primaryColor?: string;
|
|
5
|
+
primaryHover?: string;
|
|
6
|
+
bgApp?: string;
|
|
7
|
+
bgEditor?: string;
|
|
8
|
+
toolbarBg?: string;
|
|
9
|
+
borderColor?: string;
|
|
10
|
+
borderFocus?: string;
|
|
11
|
+
textMain?: string;
|
|
12
|
+
textMuted?: string;
|
|
13
|
+
placeholder?: string;
|
|
14
|
+
btnHover?: string;
|
|
15
|
+
btnActive?: string;
|
|
16
|
+
radiusLg?: string;
|
|
17
|
+
radiusMd?: string;
|
|
18
|
+
radiusSm?: string;
|
|
19
|
+
shadowSm?: string;
|
|
20
|
+
shadowMd?: string;
|
|
21
|
+
shadowLg?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface EditorOptions {
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
autofocus?: boolean;
|
|
26
|
+
theme?: ThemeConfig;
|
|
27
|
+
dark?: boolean;
|
|
28
|
+
onSave?: (html: string) => void;
|
|
29
|
+
onSaving?: () => void;
|
|
30
|
+
onChange?: (html: string) => void;
|
|
31
|
+
autoSaveInterval?: number;
|
|
32
|
+
showStatus?: boolean;
|
|
33
|
+
toolbarItems?: string[];
|
|
34
|
+
}
|
|
35
|
+
export declare class CoreEditor {
|
|
36
|
+
protected container: HTMLElement;
|
|
37
|
+
protected editableElement: HTMLElement;
|
|
38
|
+
selection: SelectionManager;
|
|
39
|
+
protected imageManager: ImageManager;
|
|
40
|
+
private history;
|
|
41
|
+
protected options: EditorOptions;
|
|
42
|
+
private saveTimeout;
|
|
43
|
+
private historyTimeout;
|
|
44
|
+
private pendingStyles;
|
|
45
|
+
constructor(container: HTMLElement, options?: EditorOptions);
|
|
46
|
+
/**
|
|
47
|
+
* Applies custom theme variables to the editor container.
|
|
48
|
+
*/
|
|
49
|
+
private applyTheme;
|
|
50
|
+
/**
|
|
51
|
+
* Toggles dark mode on the editor.
|
|
52
|
+
*/
|
|
53
|
+
setDarkMode(enabled: boolean): void;
|
|
54
|
+
protected setupImageObserver(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Wraps a raw <img> element in the interactive container
|
|
57
|
+
*/
|
|
58
|
+
private wrapImage;
|
|
59
|
+
protected setupInputHandlers(): void;
|
|
60
|
+
private handleInput;
|
|
61
|
+
private scheduleHistoryRecord;
|
|
62
|
+
private scheduleAutoSave;
|
|
63
|
+
save(): void;
|
|
64
|
+
undo(): void;
|
|
65
|
+
redo(): void;
|
|
66
|
+
private triggerChange;
|
|
67
|
+
protected createEditableElement(): HTMLElement;
|
|
68
|
+
/**
|
|
69
|
+
* Focuses the editor.
|
|
70
|
+
*/
|
|
71
|
+
focus(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Executes a command on the current selection.
|
|
74
|
+
*/
|
|
75
|
+
execute(command: string, value?: string | null): void;
|
|
76
|
+
/**
|
|
77
|
+
* Inserts a table at the current selection.
|
|
78
|
+
*/
|
|
79
|
+
insertTable(rows?: number, cols?: number): void;
|
|
80
|
+
/**
|
|
81
|
+
* Adds a row to the currently selected table.
|
|
82
|
+
*/
|
|
83
|
+
addRow(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Deletes the currently selected row.
|
|
86
|
+
*/
|
|
87
|
+
deleteRow(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Adds a column to the currently selected table.
|
|
90
|
+
*/
|
|
91
|
+
addColumn(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Deletes the currently selected column.
|
|
94
|
+
*/
|
|
95
|
+
deleteColumn(): void;
|
|
96
|
+
private getSelectedTd;
|
|
97
|
+
private getSelectedTable;
|
|
98
|
+
/**
|
|
99
|
+
* Recursively removes a style property from all elements in a fragment.
|
|
100
|
+
*/
|
|
101
|
+
private clearStyleRecursive;
|
|
102
|
+
/**
|
|
103
|
+
* Applies an inline style to the selection.
|
|
104
|
+
* This is used for properties like font-size (px) and font-family
|
|
105
|
+
* where execCommand is outdated or limited.
|
|
106
|
+
*/
|
|
107
|
+
setStyle(property: string, value: string, range?: Range): Range | null;
|
|
108
|
+
/**
|
|
109
|
+
* Creates a link at the current selection.
|
|
110
|
+
* Ensures the link opens in a new tab with proper security attributes.
|
|
111
|
+
*/
|
|
112
|
+
createLink(url: string): void;
|
|
113
|
+
/**
|
|
114
|
+
* Inserts an image at the current selection.
|
|
115
|
+
*/
|
|
116
|
+
insertImage(url: string): void;
|
|
117
|
+
/**
|
|
118
|
+
* Returns the clean HTML content of the editor.
|
|
119
|
+
*/
|
|
120
|
+
getHTML(): string;
|
|
121
|
+
/**
|
|
122
|
+
* Sets the HTML content of the editor.
|
|
123
|
+
*/
|
|
124
|
+
setHTML(html: string): void;
|
|
125
|
+
/**
|
|
126
|
+
* Internal access to the editable element.
|
|
127
|
+
*/
|
|
128
|
+
get el(): HTMLElement;
|
|
129
|
+
/**
|
|
130
|
+
* Returns the editor options.
|
|
131
|
+
*/
|
|
132
|
+
getOptions(): EditorOptions;
|
|
133
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface HistoryState {
|
|
2
|
+
html: string;
|
|
3
|
+
}
|
|
4
|
+
export declare class HistoryManager {
|
|
5
|
+
private stack;
|
|
6
|
+
private index;
|
|
7
|
+
private maxDepth;
|
|
8
|
+
constructor(initialState?: string);
|
|
9
|
+
/**
|
|
10
|
+
* Records a new state in the history stack.
|
|
11
|
+
* Clears any "redo" states if we record a new action.
|
|
12
|
+
*/
|
|
13
|
+
record(html: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the previous state if available.
|
|
16
|
+
*/
|
|
17
|
+
undo(): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Returns the next state if available.
|
|
20
|
+
*/
|
|
21
|
+
redo(): string | null;
|
|
22
|
+
/**
|
|
23
|
+
* Checks if undo is possible.
|
|
24
|
+
*/
|
|
25
|
+
canUndo(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if redo is possible.
|
|
28
|
+
*/
|
|
29
|
+
canRedo(): boolean;
|
|
30
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CoreEditor } from './Editor';
|
|
2
|
+
export declare class ImageManager {
|
|
3
|
+
private editor;
|
|
4
|
+
private activeContainer;
|
|
5
|
+
private isResizing;
|
|
6
|
+
private startX;
|
|
7
|
+
private startY;
|
|
8
|
+
private startWidth;
|
|
9
|
+
private startHeight;
|
|
10
|
+
private currentHandle;
|
|
11
|
+
private aspectRatio;
|
|
12
|
+
constructor(editor: CoreEditor);
|
|
13
|
+
private setupListeners;
|
|
14
|
+
private selectImage;
|
|
15
|
+
private deselectImage;
|
|
16
|
+
private startResize;
|
|
17
|
+
private handleResize;
|
|
18
|
+
private stopResize;
|
|
19
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SelectionManager handles wrapping the native browser Selection and Range APIs.
|
|
3
|
+
* This ensures consistent behavior across different environments and simplifies
|
|
4
|
+
* interaction with the editor's cursor and selected text.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SelectionManager {
|
|
7
|
+
/**
|
|
8
|
+
* Returns the current selection object.
|
|
9
|
+
*/
|
|
10
|
+
getSelection(): Selection | null;
|
|
11
|
+
/**
|
|
12
|
+
* Returns the first range of the current selection.
|
|
13
|
+
*/
|
|
14
|
+
getRange(): Range | null;
|
|
15
|
+
/**
|
|
16
|
+
* Saves the current selection range.
|
|
17
|
+
*/
|
|
18
|
+
saveSelection(): Range | null;
|
|
19
|
+
/**
|
|
20
|
+
* Restores a previously saved range.
|
|
21
|
+
*/
|
|
22
|
+
restoreSelection(range: Range | null): void;
|
|
23
|
+
/**
|
|
24
|
+
* Checks if the selection is within a specific element.
|
|
25
|
+
*/
|
|
26
|
+
isSelectionInElement(element: HTMLElement): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Clears the current selection.
|
|
29
|
+
*/
|
|
30
|
+
clearSelection(): void;
|
|
31
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CoreEditor, EditorOptions } from './core/Editor';
|
|
2
|
+
import { Toolbar } from './ui/Toolbar';
|
|
3
|
+
export declare class TestEditor extends CoreEditor {
|
|
4
|
+
private toolbar;
|
|
5
|
+
constructor(container: HTMLElement, options?: EditorOptions);
|
|
6
|
+
getToolbar(): Toolbar;
|
|
7
|
+
}
|
|
8
|
+
export { CoreEditor, type EditorOptions } from './core/Editor';
|
|
9
|
+
export { SelectionManager } from './core/SelectionManager';
|
|
10
|
+
export { Toolbar } from './ui/Toolbar';
|
|
11
|
+
export { HistoryManager } from './core/HistoryManager';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
.te-container,.te-emoji-picker{--te-primary-color: #6366f1;--te-primary-hover: #4f46e5;--te-bg-app: #f8fafc;--te-bg-editor: #ffffff;--te-toolbar-bg: #ffffff;--te-border-color: #e2e8f0;--te-border-focus: #cbd5e1;--te-text-main: #1e293b;--te-text-muted: #64748b;--te-placeholder: #94a3b8;--te-btn-hover: #f1f5f9;--te-btn-active: #e2e8f0;--te-radius-lg: 12px;--te-radius-md: 8px;--te-radius-sm: 6px;--te-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .05);--te-shadow-md: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--te-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--te-transition: all .2s cubic-bezier(.4, 0, .2, 1)}.te-container.te-dark,.te-emoji-picker.te-dark{--te-primary-color: #818cf8 !important;--te-primary-hover: #6366f1 !important;--te-bg-app: #0f172a !important;--te-bg-editor: #1e293b !important;--te-toolbar-bg: #1e293b !important;--te-border-color: #334155 !important;--te-border-focus: #475569 !important;--te-text-main: #f8fafc !important;--te-text-muted: #94a3b8 !important;--te-placeholder: #64748b !important;--te-btn-hover: #334155 !important;--te-btn-active: #475569 !important;--te-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / .3) !important;--te-shadow-md: 0 4px 6px -1px rgb(0 0 0 / .5), 0 2px 4px -2px rgb(0 0 0 / .5) !important;--te-shadow-lg: 0 10px 15px -3px rgb(0 0 0 / .5), 0 4px 6px -4px rgb(0 0 0 / .5) !important}.te-container,.te-container *,.te-emoji-picker,.te-emoji-picker *{box-sizing:border-box}.te-container{display:flex;flex-direction:column;height:500px;border:1px solid var(--te-border-color);border-radius:var(--te-radius-lg);background:var(--te-bg-editor);box-shadow:var(--te-shadow-sm);overflow:hidden;font-family:Inter,-apple-system,system-ui,sans-serif;color:var(--te-text-main)!important;transition:var(--te-transition);max-width:100%}.te-container:focus-within{border-color:var(--te-primary-color);box-shadow:0 0 0 4px #6366f11a,var(--te-shadow-md)}.te-toolbar{display:flex;flex-wrap:wrap;gap:6px;padding:10px 12px;border-bottom:1px solid var(--te-border-color);background:var(--te-toolbar-bg);align-items:center;-webkit-user-select:none;user-select:none;position:sticky;top:0;z-index:10}.te-divider{width:1px;height:20px;background-color:var(--te-border-color);margin:0 6px}.te-button,.te-select,.te-input{display:flex;align-items:center;justify-content:center;height:32px;border:1px solid transparent;background:transparent;border-radius:var(--te-radius-sm);cursor:pointer;color:var(--te-text-muted);font-size:13px;font-weight:500;transition:var(--te-transition);box-sizing:border-box}.te-button{width:32px;padding:0}.te-button svg{width:16px;height:16px;stroke:currentColor;stroke-width:2.2;fill:none}.te-select{padding:0 24px 0 8px;min-width:120px;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%2364748b'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2.5' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 6px center;background-size:12px;border:1px solid var(--te-border-color);background-color:var(--te-bg-editor)!important;color:var(--te-text-main)!important}.te-input{width:56px;padding:0 4px;text-align:center;cursor:text;border:1px solid var(--te-border-color);background-color:var(--te-bg-editor)!important;color:var(--te-text-main)!important}.te-color-picker{width:32px;height:32px;padding:4px;border:1px solid var(--te-border-color);border-radius:var(--te-radius-sm);background:var(--te-bg-editor);cursor:pointer;box-sizing:border-box}.te-color-picker:hover{border-color:var(--te-border-focus)}.te-color-picker-wrapper{position:relative;display:inline-flex;width:32px;height:32px;border-radius:var(--te-radius-sm);transition:var(--te-transition)}.te-color-picker-wrapper:hover{background:var(--te-btn-hover)}.te-color-picker-input{position:absolute;top:0;left:0;width:100%;height:100%;opacity:0;cursor:pointer;z-index:2}.te-color-icon{position:relative;width:100%;height:100%;display:flex;align-items:center;justify-content:center;z-index:1}.te-color-indicator{position:absolute;bottom:4px;left:6px;right:6px;height:3px;border-radius:2px;box-shadow:0 1px 1px var(--te-shadow-sm)}.te-emoji-picker{position:absolute;width:280px;height:320px;background:var(--te-bg-editor);border:1px solid var(--te-border-color);border-radius:var(--te-radius-md);box-shadow:var(--te-shadow-lg);display:flex;flex-direction:column;z-index:1000;animation:te-fade-in .2s ease-out}@keyframes te-fade-in{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.te-emoji-header{padding:12px;border-bottom:1px solid var(--te-border-color)}.te-emoji-search{width:100%;padding:8px 12px;border:1px solid var(--te-border-color);border-radius:var(--te-radius-sm);background-color:var(--te-bg-editor)!important;color:var(--te-text-main)!important;font-size:13px;outline:none;transition:var(--te-transition)}.te-emoji-search:focus{border-color:var(--te-primary-color);box-shadow:0 0 0 2px #6366f11a}.te-emoji-body{flex:1;overflow-y:auto;overflow-x:hidden;padding:8px}.te-emoji-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:4px}.te-emoji-category-title{grid-column:span 7;padding:8px 4px 4px;font-size:11px;font-weight:600;color:var(--te-text-muted);text-transform:uppercase;letter-spacing:.05em}.te-emoji-item{width:32px;height:32px;display:flex;align-items:center;justify-content:center;font-size:20px;border:none;background:transparent;cursor:pointer;border-radius:var(--te-radius-sm);transition:var(--te-transition)}.te-emoji-item:hover{background:var(--te-btn-hover);transform:scale(1.1)}.te-emoji-empty{grid-column:span 7;text-align:center;padding:20px;color:var(--te-text-muted);font-size:13px}.te-button:hover{background:var(--te-btn-hover);color:var(--te-text-main)!important}.te-select:hover,.te-input:hover{border-color:var(--te-border-focus)}.te-button.active{background:var(--te-btn-active);color:var(--te-primary-color);border-color:#6366f133}.te-select:focus,.te-input:focus{border-color:var(--te-primary-color);box-shadow:0 0 0 2px #6366f11a;outline:none;background:var(--te-bg-editor);color:var(--te-text-main)!important}.te-content{flex:1;overflow-y:auto;min-height:240px;padding:24px;line-height:1.25;outline:none;font-size:16px}.te-content p{margin:0 0 1.25em}.te-content h1,.te-content h2,.te-content h3,.te-content h4,.te-content h5,.te-content h6{color:var(--te-text-main)!important;font-weight:700;margin:1.5em 0 .5em;line-height:1.25}.te-content h1:first-child,.te-content p:first-child{margin-top:0}.te-content h1{font-size:2.25em}.te-content h2{font-size:1.875em}.te-content h3{font-size:1.5em}.te-content h4{font-size:1.25em}.te-content[data-placeholder]:empty:before{content:attr(data-placeholder);color:var(--te-placeholder);pointer-events:none}.te-image-container{position:relative;display:inline-block;margin:1.5rem 0;max-width:100%;border-radius:var(--te-radius-lg);overflow:visible;transition:box-shadow var(--te-transition-fast);line-height:0}.te-image-container:hover{box-shadow:0 0 0 2px var(--te-primary-color)}.te-image-container.active{box-shadow:0 0 0 2px var(--te-primary-color),var(--te-shadow-lg)}.te-image{display:block;max-width:100%;height:auto;-webkit-user-select:none;user-select:none}.te-image-caption{font-size:.875rem;color:var(--te-text-muted);text-align:center;padding:.75rem;background:var(--te-bg-app);line-height:normal;border-bottom-left-radius:var(--te-radius-lg);border-bottom-right-radius:var(--te-radius-lg)}.te-image-caption:empty:before{content:attr(data-placeholder);color:var(--te-placeholder)}.te-image-resizer{position:absolute;width:10px;height:10px;background:var(--te-primary-color);border:1px solid var(--te-bg-editor);z-index:10;display:none}.te-image-container:hover .te-image-resizer,.te-image-container.active .te-image-resizer{display:block}.te-resizer-top-left{top:-5px;left:-5px;cursor:nwse-resize}.te-resizer-top-right{top:-5px;right:-5px;cursor:nesw-resize}.te-resizer-bottom-left{bottom:-5px;left:-5px;cursor:nesw-resize}.te-resizer-bottom-right{bottom:-5px;right:-5px;cursor:nwse-resize}.te-content.dragover{background:var(--te-btn-hover);outline:2px dashed var(--te-primary-color);outline-offset:-4px}.te-table{width:100%;border-collapse:collapse;margin:1.5rem 0;border:1px solid var(--te-border-color);border-radius:var(--te-radius-md);table-layout:fixed}.te-table td,.te-table th{border:1px solid var(--te-border-color);padding:12px;min-height:44px;vertical-align:top;position:relative;transition:background-color .2s ease;color:var(--te-text-main)}.te-table tr{border-bottom:1px solid var(--te-border-color)}.te-table tr:last-child{border-bottom:none}.te-table td:hover{background-color:var(--te-btn-hover)}.te-table td:focus-within{background-color:var(--te-btn-active);outline:none}.te-dark .te-table,.te-dark .te-table td,.te-dark .te-table th{border-color:#334155}.te-dark .te-table td:hover{background-color:#1e293b}
|
package/dist/style.d.ts
ADDED