@meenainwal/rich-text-editor 1.0.8 → 1.1.0
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 +37 -54
- 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 +25 -13
- package/images/Screenshot from 2026-03-07 12-13-13.png +0 -0
- package/images/editor-preview.png +0 -0
package/ReadME.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
# @meenainwal/rich-text-editor 🚀
|
|
1
|
+
# @meenainwal/rich-text-editor 🚀 | Premium WYSIWYG Editor
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@meenainwal/rich-text-editor)
|
|
4
4
|
[](https://www.npmjs.com/package/@meenainwal/rich-text-editor)
|
|
5
5
|
|
|
6
|
-
A premium, ultra-lightweight, framework-agnostic rich text editor built entirely with Vanilla TypeScript. Featuring a sophisticated **Slate & Indigo** design system, it provides a flawless writing experience
|
|
6
|
+
A premium, ultra-lightweight, and framework-agnostic **WYSIWYG rich text editor** built entirely with Vanilla TypeScript. Featuring a sophisticated **Slate & Indigo** design system, it provides a flawless writing experience for React, Next.js, and modern web applications.
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|
|
|
10
|
-
## ✨ Why Choose This Editor?
|
|
10
|
+
## ✨ Premium Features & Why Choose This Editor?
|
|
11
11
|
|
|
12
|
-
### 👍 Pros
|
|
12
|
+
### 👍 Key Pros & Capabilities
|
|
13
13
|
- **Zero Dependencies**: Pure Vanilla JS/TypeScript. No bloated third-party libraries.
|
|
14
|
-
- **Microscopic Footprint**: Only **~25kB**
|
|
15
|
-
- **Framework Agnostic**:
|
|
16
|
-
- **Auto-Formatting Magic**: Intelligently parses pasted HTML strings
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
- **
|
|
14
|
+
- **Microscopic Footprint**: Only **~25kB** gzipped, making it one of the most lightweight editors available.
|
|
15
|
+
- **Framework Agnostic**: Native support for **React**, **Next.js**, **Vue**, **Angular**, and **Svelte**.
|
|
16
|
+
- **Auto-Formatting Magic**: Intelligently parses pasted HTML strings into clean, formatted rich text.
|
|
17
|
+
- **Professional UI/UX**: Modern aesthetics curated with a polished Slate & Indigo color palette.
|
|
18
|
+
- **Table Support**: Natively insert and style interactive HTML tables.
|
|
19
|
+
- **Emoji Picker**: Integrated searchable emoji library for expressive content.
|
|
20
|
+
- **Dark Mode**: Sophisticated dark theme for premium developer experiences.
|
|
21
|
+
- **Customizable Toolbar**: Granular control over tool visibility and layout.
|
|
20
22
|
|
|
21
23
|
### 👎 Cons (Current Limitations)
|
|
22
24
|
- 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
25
|
- Markdown shortcut typing (e.g., typing `#` for H1) is not natively supported yet.
|
|
25
26
|
|
|
26
27
|
---
|
|
@@ -36,82 +37,64 @@ npm install @meenainwal/rich-text-editor
|
|
|
36
37
|
### Basic Usage (Vanilla JS)
|
|
37
38
|
|
|
38
39
|
```javascript
|
|
39
|
-
import {
|
|
40
|
-
import '@meenainwal/rich-text-editor/
|
|
40
|
+
import { TestEditor } from '@meenainwal/rich-text-editor';
|
|
41
|
+
import '@meenainwal/rich-text-editor/style'; // Simple style import
|
|
41
42
|
|
|
42
43
|
const container = document.getElementById('editor');
|
|
43
|
-
const editor = new
|
|
44
|
+
const editor = new TestEditor(container, {
|
|
44
45
|
placeholder: 'Type something beautiful...',
|
|
45
|
-
autofocus: true
|
|
46
|
+
autofocus: true,
|
|
47
|
+
showStatus: true,
|
|
48
|
+
toolbarItems: ['bold', 'italic', 'heading', 'table', 'link'] // Customize tools
|
|
46
49
|
});
|
|
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
50
|
```
|
|
68
51
|
|
|
69
|
-
### In React
|
|
52
|
+
### In React / Next.js (SSR Safe)
|
|
70
53
|
|
|
71
54
|
```tsx
|
|
55
|
+
"use client";
|
|
72
56
|
import { useEffect, useRef } from 'react';
|
|
73
|
-
import {
|
|
74
|
-
import '@meenainwal/rich-text-editor/
|
|
57
|
+
import { TestEditor } from '@meenainwal/rich-text-editor';
|
|
58
|
+
import '@meenainwal/rich-text-editor/style';
|
|
75
59
|
|
|
76
|
-
export
|
|
60
|
+
export default function Editor() {
|
|
77
61
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
78
62
|
|
|
79
63
|
useEffect(() => {
|
|
80
64
|
if (containerRef.current) {
|
|
81
|
-
|
|
65
|
+
new TestEditor(containerRef.current, {
|
|
66
|
+
onSave: (html) => console.log("Saved:", html)
|
|
67
|
+
});
|
|
82
68
|
}
|
|
83
69
|
}, []);
|
|
84
70
|
|
|
85
71
|
return <div ref={containerRef} />;
|
|
86
|
-
}
|
|
72
|
+
}
|
|
87
73
|
```
|
|
88
74
|
|
|
89
75
|
---
|
|
90
76
|
|
|
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
77
|
## ⚙️ Configuration Options
|
|
103
78
|
|
|
104
79
|
| Option | Type | Default | Description |
|
|
105
80
|
| :--- | :--- | :--- | :--- |
|
|
106
81
|
| `placeholder` | `string` | `undefined` | The placeholder text when the editor is empty. |
|
|
107
|
-
| `autofocus` | `boolean` | `false` |
|
|
82
|
+
| `autofocus` | `boolean` | `false` | Focus the editor automatically on initialization. |
|
|
83
|
+
| `dark` | `boolean` | `false` | Enable sophisticated Dark Mode theme. |
|
|
84
|
+
| `showStatus` | `boolean` | `true` | Show/hide the "Saved at..." status in the toolbar. |
|
|
85
|
+
| `toolbarItems` | `string[]` | `all` | Array of tool IDs to display (e.g., `['bold', 'table']`). |
|
|
86
|
+
| `onSave` | `function` | `undefined` | Callback triggered when content is saved. |
|
|
87
|
+
| `autoSaveInterval` | `number` | `1000` | Delay in ms before auto-save triggers after typing. |
|
|
108
88
|
|
|
109
89
|
## 🛠 API Methods
|
|
110
90
|
|
|
111
91
|
- `getHTML()`: Returns the content as a sanitized HTML string.
|
|
112
92
|
- `setHTML(html)`: Programmatically sets the editor content.
|
|
113
93
|
- `focus()`: Forces focus onto the editor.
|
|
114
|
-
- `
|
|
94
|
+
- `setDarkMode(boolean)`: Dynamically toggle dark mode.
|
|
95
|
+
- `insertTable(rows, cols)`: Programmatically insert a table.
|
|
96
|
+
|
|
97
|
+
---
|
|
115
98
|
|
|
116
99
|
## 📄 License
|
|
117
100
|
|
|
@@ -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