smartrte-react 0.3.5 → 1.0.0-beta.10
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/CHANGELOG.md +55 -0
- package/README.md +205 -14
- package/dist/adapters/domChecklistCommandBridge.js +1 -1
- package/dist/adapters/domCommandBridge.d.ts +2 -2
- package/dist/adapters/domCommandBridge.js +2 -2
- package/dist/adapters/domInlineAtomCommandBridge.d.ts +10 -9
- package/dist/adapters/domInlineAtomCommandBridge.js +154 -50
- package/dist/adapters/domInlineImageCommandBridge.d.ts +7 -7
- package/dist/adapters/domInlineImageCommandBridge.js +6 -72
- package/dist/adapters/domMoveCommandBridge.js +1 -1
- package/dist/adapters/domSelectionBridge.d.ts +3 -3
- package/dist/adapters/domSmartDocument.d.ts +4 -4
- package/dist/adapters/domSmartDocument.js +2 -2
- package/dist/adapters/domTableCommandBridge.d.ts +42 -16
- package/dist/adapters/domTableCommandBridge.js +203 -173
- package/dist/adapters/internalFlags.d.ts +0 -8
- package/dist/adapters/internalFlags.js +0 -24
- package/dist/adapters/legacyListShadowComparator.d.ts +1 -1
- package/dist/adapters/legacyListShadowComparator.js +1 -1
- package/dist/adapters/pdfPrint.d.ts +8 -0
- package/dist/adapters/pdfPrint.js +22 -0
- package/dist/adapters/shadowMode.d.ts +3 -3
- package/dist/adapters/shadowMode.js +1 -1
- package/dist/canonicalEditorRuntime.d.ts +65 -1
- package/dist/canonicalEditorRuntime.js +63 -5
- package/dist/capabilityPresets.d.ts +27 -0
- package/dist/capabilityPresets.js +21 -0
- package/dist/collabTransport.d.ts +66 -0
- package/dist/collabTransport.js +1 -0
- package/dist/commentProvider.d.ts +24 -0
- package/dist/commentProvider.js +1 -0
- package/dist/components/CanonicalAuthorityEditor.d.ts +56 -1
- package/dist/components/CanonicalAuthorityEditor.js +1304 -116
- package/dist/components/ClassicEditorAuthority.d.ts +93 -22
- package/dist/components/ClassicEditorAuthority.js +11 -43
- package/dist/components/ColorPickerPopover.d.ts +39 -0
- package/dist/components/ColorPickerPopover.js +287 -0
- package/dist/components/CommentMarkers.d.ts +25 -0
- package/dist/components/CommentMarkers.js +105 -0
- package/dist/components/CommentThreadPanel.d.ts +26 -0
- package/dist/components/CommentThreadPanel.js +47 -0
- package/dist/components/ContextMenu.d.ts +23 -0
- package/dist/components/ContextMenu.js +141 -0
- package/dist/components/FormulaLibraryPopover.d.ts +16 -0
- package/dist/components/FormulaLibraryPopover.js +107 -0
- package/dist/components/LinkEditorPopover.d.ts +3 -1
- package/dist/components/LinkEditorPopover.js +22 -6
- package/dist/components/MediaDetailsPopover.d.ts +35 -0
- package/dist/components/MediaDetailsPopover.js +136 -0
- package/dist/components/MediaManager.d.ts +4 -20
- package/dist/components/MediaManager.js +40 -11
- package/dist/components/MediaOverlay.d.ts +27 -0
- package/dist/components/MediaOverlay.js +228 -0
- package/dist/components/SpecialCharacterPopover.d.ts +18 -0
- package/dist/components/SpecialCharacterPopover.js +99 -0
- package/dist/components/StructuralSuggestionMarkers.d.ts +20 -0
- package/dist/components/StructuralSuggestionMarkers.js +56 -0
- package/dist/components/SuggestionPanel.d.ts +26 -0
- package/dist/components/SuggestionPanel.js +33 -0
- package/dist/components/TableBorderPopover.d.ts +59 -0
- package/dist/components/TableBorderPopover.js +149 -0
- package/dist/components/TableResizeHandles.d.ts +25 -0
- package/dist/components/TableResizeHandles.js +323 -0
- package/dist/components/TableSizePickerPopover.d.ts +16 -0
- package/dist/components/TableSizePickerPopover.js +126 -0
- package/dist/components/ToolbarPrimitives.d.ts +161 -0
- package/dist/components/ToolbarPrimitives.js +237 -0
- package/dist/components/VersionHistoryPanel.d.ts +9 -0
- package/dist/components/VersionHistoryPanel.js +157 -0
- package/dist/components/fixedPositioning.d.ts +25 -0
- package/dist/components/fixedPositioning.js +42 -0
- package/dist/formulaLibrary.d.ts +31 -0
- package/dist/formulaLibrary.js +90 -0
- package/dist/index.d.ts +25 -24
- package/dist/index.js +15 -11
- package/dist/mediaManagerAdapter.d.ts +12 -0
- package/dist/mediaManagerAdapter.js +34 -0
- package/dist/mediaProvider.d.ts +21 -1
- package/dist/specialCharacters.d.ts +22 -0
- package/dist/specialCharacters.js +86 -0
- package/dist/standalone/classic-editor-embed.js +19 -12
- package/dist/suggestionProvider.d.ts +17 -0
- package/dist/suggestionProvider.js +1 -0
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +219 -30
- package/dist/toolbarTools.d.ts +95 -0
- package/dist/toolbarTools.js +17 -0
- package/dist/versionProvider.d.ts +29 -0
- package/dist/versionProvider.js +1 -0
- package/package.json +28 -14
- package/dist/adapters/canonicalInlineCommandBridge.d.ts +0 -15
- package/dist/adapters/canonicalInlineCommandBridge.js +0 -269
- package/dist/adapters/canonicalListCommandBridge.d.ts +0 -26
- package/dist/adapters/canonicalListCommandBridge.js +0 -430
- package/dist/adapters/coreBold.d.ts +0 -5
- package/dist/adapters/coreBold.js +0 -3
- package/dist/adapters/documentFormats.d.ts +0 -26
- package/dist/adapters/documentFormats.js +0 -49
- package/dist/adapters/docxFormat.d.ts +0 -5
- package/dist/adapters/docxFormat.js +0 -272
- package/dist/adapters/domBlockCommandBridge.d.ts +0 -19
- package/dist/adapters/domBlockCommandBridge.js +0 -79
- package/dist/adapters/inlineMarkCoreExecution.d.ts +0 -9
- package/dist/adapters/inlineMarkCoreExecution.js +0 -25
- package/dist/adapters/pdfFormat.d.ts +0 -23
- package/dist/adapters/pdfFormat.js +0 -204
- package/dist/adapters/portableDocxAtoms.d.ts +0 -4
- package/dist/adapters/portableDocxAtoms.js +0 -58
- package/dist/adapters/styledDocxFormat.d.ts +0 -8
- package/dist/adapters/styledDocxFormat.js +0 -190
- package/dist/builtInFormatDefinitions.d.ts +0 -5
- package/dist/builtInFormatDefinitions.js +0 -82
- package/dist/canonicalAuthorityFlag.d.ts +0 -32
- package/dist/canonicalAuthorityFlag.js +0 -49
- package/dist/canonicalClipboardRuntime.d.ts +0 -15
- package/dist/canonicalClipboardRuntime.js +0 -76
- package/dist/components/ClassicEditor.d.ts +0 -76
- package/dist/components/ClassicEditor.js +0 -6729
- package/dist/editorController.d.ts +0 -78
- package/dist/editorController.js +0 -298
- package/dist/formatFidelity.d.ts +0 -14
- package/dist/formatFidelity.js +0 -107
- package/dist/formatRuntime.d.ts +0 -50
- package/dist/formatRuntime.js +0 -20
- package/dist/pluginRuntime.d.ts +0 -68
- package/dist/pluginRuntime.js +0 -78
- package/dist/standalone/editor.js +0 -1068
- package/dist/test-harness/atomShadowComparator.d.ts +0 -14
- package/dist/test-harness/atomShadowComparator.js +0 -63
- package/dist/test-harness/blockShadowComparator.d.ts +0 -30
- package/dist/test-harness/blockShadowComparator.js +0 -140
- package/dist/test-harness/clipboardShadowComparator.d.ts +0 -12
- package/dist/test-harness/clipboardShadowComparator.js +0 -46
- package/dist/test-harness/inlineShadowComparator.d.ts +0 -32
- package/dist/test-harness/inlineShadowComparator.js +0 -152
- package/dist/test-harness/legacyAtomEngine.d.ts +0 -10
- package/dist/test-harness/legacyAtomEngine.js +0 -15
- package/dist/test-harness/legacyBlockEngine.d.ts +0 -31
- package/dist/test-harness/legacyBlockEngine.js +0 -31
- package/dist/test-harness/legacyClipboardEngine.d.ts +0 -14
- package/dist/test-harness/legacyClipboardEngine.js +0 -67
- package/dist/test-harness/legacyInlineEngine.d.ts +0 -19
- package/dist/test-harness/legacyInlineEngine.js +0 -49
- package/dist/test-harness/legacyTableEngine.d.ts +0 -12
- package/dist/test-harness/legacyTableEngine.js +0 -25
- package/dist/test-harness/tableShadowComparator.d.ts +0 -29
- package/dist/test-harness/tableShadowComparator.js +0 -101
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.10
|
|
4
|
+
|
|
5
|
+
- Fix a table row resize regression: dragging a row boundary back to where it started (after an earlier drag hit a row's natural content floor) inflated the neighboring row instead of restoring the original layout — the only way back was Undo. Reversing a boundary drag now correctly shrinks the table's total height instead of growing a neighbor that never actually had slack to give.
|
|
6
|
+
|
|
7
|
+
- Fix a horizontal line/page break appearing to be "not selectable": clicking one already set real node selection, but right-clicking showed no UI at all, unlike every other atom (image/video/audio/formula). Right-click now shows the same Delete-only action menu formula already gets (never Edit — neither atom has an editable field, and neither ever gets resize handles).
|
|
8
|
+
- Add a "Line spacing" toolbar dropdown (Paragraph group) with presets (1, 1.15, 1.5, 2, 2.5), a "Default" entry that clears the override, and a custom numeric value entry, matching Google Docs' own line-spacing picker shape. Shows a checkmark on the current value, or no checkmark at all when the selection spans blocks with differing values. New `tools.lineHeight` visibility flag (default visible). Depends on `smartrte-core@1.0.0-beta.5`.
|
|
9
|
+
- Add "Horizontal line" and "Page break" toolbar tools (in the "More to insert" group, plus wide-viewport-promoted standalone copies), and matching `tools.horizontalLine`/`tools.pageBreak` visibility flags. A page break renders as a dashed, labeled marker in the live editor — distinct from a horizontal line — and produces real pagination in both the exported HTML and this package's "Save as PDF" (a real browser print of that same HTML). Depends on `smartrte-core@1.0.0-beta.5`.
|
|
10
|
+
- Fix formulas rendering invisible in "Save as PDF" output (see `smartrte-core@1.0.0-beta.5`'s own changelog entry for the root cause).
|
|
11
|
+
- Rename the "Save as PDF" toolbar entry to "Print / Save as PDF" — it opens the browser's print dialog rather than triggering a direct file download like its "Save as ..." siblings; the new label sets the correct expectation instead of implying a one-click download.
|
|
12
|
+
|
|
13
|
+
## 1.0.0-beta.9
|
|
14
|
+
|
|
15
|
+
- Fix toolbar dropdowns, the mobile "More tools" kebab menu, and the text/background colour and table-border popovers rendering far from their own trigger when the editor is embedded inside a host container that has its own CSS `transform` on an ancestor - e.g. a Radix/shadcn `Dialog`'s own centering transform. These overlays now correctly account for the resulting change of containing block instead of assuming it's always the viewport.
|
|
16
|
+
|
|
17
|
+
## 1.0.0-beta.8
|
|
18
|
+
|
|
19
|
+
- Add a `tools` prop (`ClassicEditor`, `CanonicalAuthorityEditor`, and the standalone embed) letting a host hide any individual toolbar tool — Bold, Video, Version history, Review, and around 40 others — without wrapping or restyling the component. Every tool is visible by default; composes with existing gates (a required provider or capability must still be present). See the README's "Hiding individual toolbar tools" section for the full list and usage.
|
|
20
|
+
- Retire the never-shipped `showVersionHistory`/`showReview` props in favor of `tools.versionHistory`/`tools.comments`/`tools.suggestions`.
|
|
21
|
+
- Also export `EditorCapabilityPreset` from the package's public entry point (previously only reachable indirectly through `CanonicalAuthorityEditorProps`).
|
|
22
|
+
|
|
23
|
+
## 1.0.0-beta.7
|
|
24
|
+
|
|
25
|
+
- Fix the mobile "More tools" overflow menu getting clipped almost entirely off-screen when the editor is embedded inside a host container with `overflow: hidden` — the same fix already applied to the desktop toolbar dropdowns, now also covering this menu (the only overflow affordance on narrow viewports).
|
|
26
|
+
- Add the "List preset" control (decimal/lower-alpha/upper-alpha/roman-numeral/outline numbering styles, plus bullet-glyph presets) to the mobile "More tools" menu — previously only reachable from the desktop toolbar's "More list tools" dropdown, leaving narrow-viewport users with no way to use anything beyond plain bulleted/numbered/checklist lists.
|
|
27
|
+
|
|
28
|
+
## 1.0.0-beta.6
|
|
29
|
+
|
|
30
|
+
- Replace the media Edit overlay's plain alt-text prompt with a full "Media details" panel: link (with open-in-new-tab), corner radius, alignment, and license fields (description, source URL, type, version, attribution), matching the pre-canonical editor's own edit-panel field set. A library-picked image's existing license metadata is now carried onto the inserted atom instead of being discarded. Depends on `smartrte-core@1.0.0-beta.3`.
|
|
31
|
+
|
|
32
|
+
## 1.0.0-beta.5
|
|
33
|
+
|
|
34
|
+
- Add an opt-in `renderFormulaHtml` prop (on `ClassicEditor`/`CanonicalAuthorityEditor`) that bakes real KaTeX-rendered HTML into the formula elements of `onChange`'s exported HTML, instead of an empty placeholder — for hosts that display saved content directly (e.g. a read-only preview panel) without also running KaTeX against it. Depends on `smartrte-core@1.0.0-beta.2`.
|
|
35
|
+
|
|
36
|
+
## 1.0.0-beta.4
|
|
37
|
+
|
|
38
|
+
- Fix blockquote, table header, and dialog (media library, comments, suggestions, version history) backgrounds/text staying in their light-mode colors even when the host page is in dark mode — these now follow the host's own dark-mode CSS variables directly, the same way the rest of the editor's colors already did, instead of depending solely on the `.srte-dark` class reaching the editor correctly.
|
|
39
|
+
|
|
40
|
+
## 1.0.0-beta.3
|
|
41
|
+
|
|
42
|
+
- Fix toolbar dropdown menus (e.g. "More text styles", "More paragraph tools") getting visually clipped to unusable fragments when the editor is embedded inside a host container with `overflow: hidden` (e.g. a rounded card or a clipped split-pane panel) — the menu now positions itself relative to the viewport instead of the nearest ancestor, so it can never be clipped regardless of host layout.
|
|
43
|
+
|
|
44
|
+
## 1.0.0-beta.2
|
|
45
|
+
|
|
46
|
+
- Fix the toolbar promoting extra buttons based on the browser window's width instead of the editor's own rendered width — broke embedding the editor in a split pane or any container narrower than the window, causing overlapping/mashed toolbar labels and misdirected clicks that looked like an unresponsive toolbar.
|
|
47
|
+
|
|
48
|
+
## 1.0.0-beta.1
|
|
49
|
+
|
|
50
|
+
**BREAKING CHANGE.** `ClassicEditor` is now unconditionally the canonical, schema-driven editor (`CanonicalAuthorityEditor` underneath). The DOM-authoritative legacy editor and its rollback path have been fully removed; every published version through 0.3.4 defaulted to the DOM-authoritative implementation, so this changes real runtime behavior for every existing consumer, not just internals.
|
|
51
|
+
|
|
52
|
+
- Promote the canonical editing engine to sole production authority. Removed `LegacyClassicEditor` (the previous default), the runtime rollback flag, and all four of its DOM-authoritative command bridges.
|
|
53
|
+
- Add a documented, tested headless facade: `CanonicalEditorRuntime` / `SmartEditorHandle` (`createCanonicalEditorRuntime`) has zero React dependency and can drive a full editing session — mount, edit, checkpoint/restore, get/replace value — against a plain DOM element with no React runtime involved.
|
|
54
|
+
- Wire DOCX, PDF, and Markdown import/export to `smartrte-core`'s new format codecs, replacing the previous ad hoc, partially DOM-dependent adapters.
|
|
55
|
+
- Add live KaTeX rendering for formula content, including accessible MathML output.
|
|
56
|
+
- Depends on `smartrte-core@1.0.0-beta.1`.
|
|
57
|
+
|
|
3
58
|
## 0.3.5
|
|
4
59
|
|
|
5
60
|
- Remove the always-on drag handle that appeared next to every line, list item, and table.
|
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ pnpm add smartrte-react
|
|
|
41
41
|
## 🚀 Quick Start
|
|
42
42
|
|
|
43
43
|
### 🎮 Live Demo
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
Try the editor instantly in your browser:
|
|
46
46
|
|
|
47
47
|
- **[Live Demo](https://playground-k9l44ah7t-ayush1852017s-projects.vercel.app/)** (Deployed Version)
|
|
@@ -87,10 +87,136 @@ export default App;
|
|
|
87
87
|
| `table` | `boolean` | `true` | Enable/disable table functionality |
|
|
88
88
|
| `media` | `boolean` | `true` | Enable/disable media/image functionality |
|
|
89
89
|
| `formula` | `boolean` | `true` | Enable/disable formula/LaTeX functionality |
|
|
90
|
+
| `features` | `CoreFeatureConfig` | standard preset | Enable or disable individual core plugins |
|
|
91
|
+
| `plugins` | `ReactEditorPlugin[]` | standard preset | Use an exact custom plugin set; replaces the standard preset |
|
|
92
|
+
| `formats` | `EditorFormatConfig` | all built-ins | Enable or disable HTML, Markdown, DOCX, and PDF adapters |
|
|
93
|
+
| `formatDefinitions` | `EditorFormatDefinition[]` | built-ins | Add or replace import/export adapters |
|
|
90
94
|
| `mediaManager` | `MediaManagerAdapter` | `undefined` | Custom media manager for handling images |
|
|
95
|
+
| `fonts` | `{ name: string; value: string }[]` | Default web-safe fonts | Custom font list for the toolbar |
|
|
96
|
+
| `defaultFont` | `string` | `undefined` | Default font family for the editor content |
|
|
97
|
+
| `theme` | `"light" \| "dark"` | `"light"` | Built-in theme mode |
|
|
98
|
+
| `className` | `string` | `undefined` | Custom CSS class for theming via CSS variable overrides |
|
|
99
|
+
| `tools` | `Partial<ToolbarTools>` | every tool `true` | Hide individual toolbar tools (Bold, Video, Version history, etc.) — see [Hiding individual toolbar tools](#hiding-individual-toolbar-tools) below |
|
|
91
100
|
|
|
92
101
|
### Advanced Examples
|
|
93
102
|
|
|
103
|
+
#### Feature plugins
|
|
104
|
+
|
|
105
|
+
The editor uses the same plugin registry for core commands and React toolbar
|
|
106
|
+
state. For the architecture and custom plugin API, see
|
|
107
|
+
[`docs/PLUGIN_ARCHITECTURE.md`](../../docs/PLUGIN_ARCHITECTURE.md).
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { ClassicEditor } from 'smartrte-react';
|
|
111
|
+
|
|
112
|
+
<ClassicEditor
|
|
113
|
+
features={{
|
|
114
|
+
table: false,
|
|
115
|
+
media: false,
|
|
116
|
+
formula: false,
|
|
117
|
+
checklist: true,
|
|
118
|
+
}}
|
|
119
|
+
/>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Hiding individual toolbar tools
|
|
123
|
+
|
|
124
|
+
The `table`/`media`/`formula` props above turn off a whole *capability* — no
|
|
125
|
+
tables anywhere, or media/formulas removed from the schema entirely. If you
|
|
126
|
+
just want a **smaller toolbar** while keeping every capability intact (e.g.
|
|
127
|
+
hide Video, Audio, Version history, and Review for a specific product
|
|
128
|
+
surface, without touching what content the editor can actually store), use
|
|
129
|
+
`tools` instead. It's a plain object: name the tools you want off, everything
|
|
130
|
+
else stays on by default. No wrapping, no CSS overrides, no forking the
|
|
131
|
+
component.
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
import { ClassicEditor } from 'smartrte-react';
|
|
135
|
+
|
|
136
|
+
<ClassicEditor
|
|
137
|
+
tools={{
|
|
138
|
+
video: false,
|
|
139
|
+
audio: false,
|
|
140
|
+
versionHistory: false,
|
|
141
|
+
comments: false,
|
|
142
|
+
suggestions: false,
|
|
143
|
+
}}
|
|
144
|
+
/>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**How it composes with everything else:** a tool only ever needs *both*
|
|
148
|
+
things to be true to show up — your `tools` flag says yes, *and* whatever
|
|
149
|
+
that tool actually depends on is present. So:
|
|
150
|
+
|
|
151
|
+
- `tools.video`/`tools.audio`/`tools.image` also need a `mediaProvider` (or
|
|
152
|
+
`mediaManager`) to be configured at all — turning the flag on can't make
|
|
153
|
+
media insertion appear out of nowhere if you never wired up a provider.
|
|
154
|
+
- `tools.versionHistory` also needs a `versionProvider`; `tools.comments`
|
|
155
|
+
needs a `commentProvider`; `tools.suggestions` needs a `suggestionProvider`.
|
|
156
|
+
- `tools.insertTable` also needs the table capability to actually be enabled
|
|
157
|
+
(i.e. you haven't set `table={false}`) — you can't use `tools` to bring
|
|
158
|
+
back a capability you turned off elsewhere.
|
|
159
|
+
|
|
160
|
+
In other words: `tools` can only ever hide something, never force something
|
|
161
|
+
into existence that isn't otherwise configured. This means it's always safe
|
|
162
|
+
to leave `tools` unset — every consumer who doesn't pass it sees the exact
|
|
163
|
+
toolbar they see today.
|
|
164
|
+
|
|
165
|
+
**Every toggleable key**, grouped the way they appear in the toolbar:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
interface ToolbarTools {
|
|
169
|
+
// Text formatting
|
|
170
|
+
bold, italic, underline, strikethrough, code,
|
|
171
|
+
superscript, subscript, textColor, backgroundColor, fontSize, fontFamily,
|
|
172
|
+
|
|
173
|
+
// Paragraph
|
|
174
|
+
blockType, // the Paragraph/Heading/Code block dropdown
|
|
175
|
+
alignLeft, alignCenter, alignRight, alignJustify,
|
|
176
|
+
lineHeight, // the line-spacing dropdown (1/1.15/1.5/2/2.5 presets plus a custom value)
|
|
177
|
+
quote,
|
|
178
|
+
|
|
179
|
+
// Lists
|
|
180
|
+
bulletedList, numberedList, checklist,
|
|
181
|
+
listPreset, // the numbered-list style picker (1,2,3 / a,b,c / i,ii,iii / A,B,C / I,II,III)
|
|
182
|
+
|
|
183
|
+
// Insert
|
|
184
|
+
link, removeLink, image, video, audio, insertFormula, specialCharacters,
|
|
185
|
+
horizontalLine, // inserts a divider (<hr>)
|
|
186
|
+
pageBreak, // inserts a print/export pagination marker - distinct from horizontalLine
|
|
187
|
+
insertTable,
|
|
188
|
+
|
|
189
|
+
// Document
|
|
190
|
+
import,
|
|
191
|
+
saveAsHtml, saveAsMarkdown, saveAsWord, saveAsPdf, saveAsSmartRte,
|
|
192
|
+
versionHistory, comments, suggestions,
|
|
193
|
+
|
|
194
|
+
// History
|
|
195
|
+
undo, redo,
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
A few notes on what's *not* in this list, on purpose: actions that only ever
|
|
200
|
+
apply to something you already have selected — moving a block up/down,
|
|
201
|
+
indenting a list item, adding/removing a table row or column, resizing a
|
|
202
|
+
selected image — aren't individually toggleable. They only make sense as
|
|
203
|
+
part of using the tool that created them (a table, a list, an image), so
|
|
204
|
+
they follow that tool's own visibility rather than needing a separate flag
|
|
205
|
+
each. If you turn off `insertTable`, its row/column tools go with it
|
|
206
|
+
automatically — there's no separate flag to remember.
|
|
207
|
+
|
|
208
|
+
If you're using the exported `CanonicalAuthorityEditor` directly instead of
|
|
209
|
+
`ClassicEditor`, `tools` works exactly the same way. And if you're using the
|
|
210
|
+
standalone embed (`window.SmartRTE.ClassicEditor.init(...)`), pass `tools`
|
|
211
|
+
in the same options object you pass `target`/`value`/etc.
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
window.SmartRTE.ClassicEditor.init({
|
|
215
|
+
target: document.getElementById('editor'),
|
|
216
|
+
tools: { video: false, audio: false },
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
94
220
|
#### Complete Example with All Features
|
|
95
221
|
|
|
96
222
|
```tsx
|
|
@@ -314,23 +440,87 @@ const myMediaManager: MediaManagerAdapter = {
|
|
|
314
440
|
};
|
|
315
441
|
```
|
|
316
442
|
|
|
317
|
-
## 🎨
|
|
443
|
+
## 🎨 Theming & Dark Mode
|
|
318
444
|
|
|
319
|
-
The editor
|
|
445
|
+
The editor uses CSS custom properties (CSS variables) for all colors, making it fully customizable. No hardcoded colors — everything can be themed.
|
|
446
|
+
|
|
447
|
+
### Quick Start: Dark Mode
|
|
448
|
+
|
|
449
|
+
```tsx
|
|
450
|
+
<ClassicEditor theme="dark" onChange={handleChange} />
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Custom Themes via CSS
|
|
454
|
+
|
|
455
|
+
Apply a custom class and override any CSS variables:
|
|
320
456
|
|
|
321
457
|
```tsx
|
|
322
|
-
<
|
|
323
|
-
border: '1px solid #ddd',
|
|
324
|
-
borderRadius: '8px',
|
|
325
|
-
overflow: 'hidden',
|
|
326
|
-
}}>
|
|
327
|
-
<ClassicEditor
|
|
328
|
-
value={content}
|
|
329
|
-
onChange={setContent}
|
|
330
|
-
/>
|
|
331
|
-
</div>
|
|
458
|
+
<ClassicEditor className="my-theme" onChange={handleChange} />
|
|
332
459
|
```
|
|
333
460
|
|
|
461
|
+
```css
|
|
462
|
+
.my-theme {
|
|
463
|
+
--srte-bg: #1a1a2e;
|
|
464
|
+
--srte-text: #eaeaea;
|
|
465
|
+
--srte-border: #3a3a5c;
|
|
466
|
+
/* Override only the variables you need */
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Responding to System Preference
|
|
471
|
+
|
|
472
|
+
```tsx
|
|
473
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
474
|
+
|
|
475
|
+
<ClassicEditor theme={prefersDark ? 'dark' : 'light'} />
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Or purely via CSS (without the `theme` prop):
|
|
479
|
+
|
|
480
|
+
```css
|
|
481
|
+
@media (prefers-color-scheme: dark) {
|
|
482
|
+
.srte-editor {
|
|
483
|
+
--srte-bg: #1e1e1e;
|
|
484
|
+
--srte-text: #e0e0e0;
|
|
485
|
+
--srte-border: #3a3a3a;
|
|
486
|
+
/* ... */
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Available CSS Custom Properties
|
|
492
|
+
|
|
493
|
+
| Variable | Default (Light) | Description |
|
|
494
|
+
|---|---|---|
|
|
495
|
+
| `--srte-bg` | `#ffffff` | Editor container & content background |
|
|
496
|
+
| `--srte-text` | `#111111` | Primary UI text color |
|
|
497
|
+
| `--srte-text-muted` | `#4b5563` | Secondary/subtle text |
|
|
498
|
+
| `--srte-border` | `#dddddd` | Standard border color |
|
|
499
|
+
| `--srte-border-light` | `#eeeeee` | Light separator borders |
|
|
500
|
+
| `--srte-toolbar-bg` | `#ffffff` | Toolbar background |
|
|
501
|
+
| `--srte-input-bg` | `#ffffff` | Button, input, select backgrounds |
|
|
502
|
+
| `--srte-input-text` | `#111111` | Button, input, select text |
|
|
503
|
+
| `--srte-input-border` | `#e5e7eb` | Button, input, select borders |
|
|
504
|
+
| `--srte-modal-backdrop` | `rgba(0,0,0,0.35)` | Modal overlay background |
|
|
505
|
+
| `--srte-modal-bg` | `#ffffff` | Modal/dialog background |
|
|
506
|
+
| `--srte-modal-text` | `#000000` | Modal text color |
|
|
507
|
+
| `--srte-menu-bg` | `#ffffff` | Context menu background |
|
|
508
|
+
| `--srte-menu-text` | `#111111` | Context menu text |
|
|
509
|
+
| `--srte-menu-shadow` | `0 8px 24px rgba(0,0,0,0.18)` | Menu box-shadow |
|
|
510
|
+
| `--srte-accent` | `#1e90ff` | Accent/selection color |
|
|
511
|
+
| `--srte-accent-bg` | `rgba(30,144,255,0.15)` | Accent background (translucent) |
|
|
512
|
+
| `--srte-danger` | `#dc2626` | Destructive action color |
|
|
513
|
+
| `--srte-primary` | `#2563eb` | Primary action button color |
|
|
514
|
+
| `--srte-surface-subtle` | `#f3f4f6` | Subtle surface (dropzone, preset buttons) |
|
|
515
|
+
| `--srte-on-primary` | `#ffffff` | Text on primary/danger buttons |
|
|
516
|
+
| `--srte-cancel-bg` | `#f3f4f6` | Cancel button background |
|
|
517
|
+
|
|
518
|
+
### Important Notes
|
|
519
|
+
|
|
520
|
+
- **User content colors are preserved** — colors set via the color picker (text/background) are inline styles on content elements and are not affected by theming.
|
|
521
|
+
- **Color picker swatches are not themed** — they display actual color values regardless of theme.
|
|
522
|
+
- **The theme only affects editor chrome** — toolbar, dialogs, menus, and container. User content remains unchanged.
|
|
523
|
+
|
|
334
524
|
## 🛠️ Development
|
|
335
525
|
|
|
336
526
|
### Prerequisites
|
|
@@ -626,13 +816,14 @@ See the list of [contributors](https://github.com/ayush1852017/smart-rte/contrib
|
|
|
626
816
|
|
|
627
817
|
## 🗺️ Roadmap
|
|
628
818
|
|
|
629
|
-
### Current Version (0.
|
|
819
|
+
### Current Version (0.2.x)
|
|
630
820
|
|
|
631
821
|
- ✅ Rich text editing
|
|
632
822
|
- ✅ Table support
|
|
633
823
|
- ✅ Formula support (LaTeX/KaTeX)
|
|
634
824
|
- ✅ Media management
|
|
635
825
|
- ✅ TypeScript support
|
|
826
|
+
- ✅ Dark mode & theming (CSS custom properties)
|
|
636
827
|
|
|
637
828
|
### Upcoming Features
|
|
638
829
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { checklistPlugin, createSmartEditor, listPlugin } from "smartrte-core";
|
|
1
|
+
import { checklistPlugin, createSmartEditor, listPlugin } from "smartrte-core/legacy";
|
|
2
2
|
import { smartDocumentFromHtml } from "./domSmartDocument.js";
|
|
3
3
|
/**
|
|
4
4
|
* Validates and executes a checklist mutation through core, then projects the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type SmartRtePlugin, type
|
|
1
|
+
import { type SmartRtePlugin, type LegacySmartSelection } from "smartrte-core/legacy";
|
|
2
2
|
export interface DomCommandResult {
|
|
3
3
|
html: string;
|
|
4
|
-
selection:
|
|
4
|
+
selection: LegacySmartSelection;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
7
|
* Executes one model command against the live editor boundary.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createSmartEditor, } from "smartrte-core";
|
|
1
|
+
import { createSmartEditor, } from "smartrte-core/legacy";
|
|
2
2
|
import { restoreSelectionToDom, selectionFromDom } from "./domSelectionBridge.js";
|
|
3
3
|
import { serializeSmartDocument, smartDocumentFromEditorRoot, } from "./domSmartDocument.js";
|
|
4
4
|
/**
|
|
@@ -9,7 +9,7 @@ import { serializeSmartDocument, smartDocumentFromEditorRoot, } from "./domSmart
|
|
|
9
9
|
* the React host until the complete editor runtime is migrated.
|
|
10
10
|
*/
|
|
11
11
|
export const executeDomCommand = (args) => {
|
|
12
|
-
// These nodes are not represented by
|
|
12
|
+
// These nodes are not represented by LegacySmartDocument yet. Falling back is
|
|
13
13
|
// mandatory so a supported command can never erase unsupported content.
|
|
14
14
|
if (args.root.querySelector("img,video,audio,iframe")) {
|
|
15
15
|
return null;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
export declare const inlineAtomPathFromDom: (root: HTMLElement, atom: HTMLElement) =>
|
|
3
|
-
/**
|
|
4
|
-
* Runs deletion through the owning feature plugin and removes only the
|
|
5
|
-
* validated live atom. Caret placement remains a DOM-host responsibility.
|
|
6
|
-
*/
|
|
7
|
-
export declare const executeDomInlineAtomDelete: (root: HTMLElement, atom: HTMLElement) => boolean;
|
|
1
|
+
import { type Attrs } from "smartrte-core/foundation";
|
|
2
|
+
export declare const inlineAtomPathFromDom: (root: HTMLElement, atom: HTMLElement) => number[] | null;
|
|
8
3
|
export interface DomFormulaInput {
|
|
9
4
|
value: string;
|
|
10
5
|
displayText?: string;
|
|
11
6
|
}
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
export interface DomCanonicalAtomInput {
|
|
8
|
+
type: "image" | "formula";
|
|
9
|
+
attrs: Attrs;
|
|
10
|
+
}
|
|
11
|
+
export declare const executeDomCanonicalAtomInsert: (root: HTMLElement, input: DomCanonicalAtomInput, domSelection?: Selection | null) => HTMLElement | null;
|
|
12
|
+
export declare const executeDomFormulaInsert: (root: HTMLElement, input: DomFormulaInput, selection?: Selection | null) => HTMLElement | null;
|
|
13
|
+
export declare const executeDomInlineAtomDelete: (root: HTMLElement, atom: HTMLElement) => boolean;
|
|
14
|
+
export declare const executeDomCanonicalAtomUpdate: (root: HTMLElement, atom: HTMLElement, attrs: Attrs) => boolean;
|
|
14
15
|
export declare const adjacentInlineAtom: (range: Range, direction: "backward" | "forward") => HTMLElement | null;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isEditorOnlyElement, pathForDomElement
|
|
3
|
-
import { smartDocumentFromEditorRoot } from "./domSmartDocument.js";
|
|
1
|
+
import { applyOperations, atomDeclarations, createNodeId, createScopeIndex, deleteAtom, foundationSchema, insertAtom, parseCanonicalListHtml, renderDocumentNaively, updateAtom, } from "smartrte-core/foundation";
|
|
2
|
+
import { isEditorOnlyElement, pathForDomElement } from "./domSelectionBridge.js";
|
|
4
3
|
const atomType = (element) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
const declared = element.getAttribute("data-smart-type");
|
|
5
|
+
if (declared === "image" || element.tagName.toLowerCase() === "img")
|
|
6
|
+
return "image";
|
|
7
|
+
if (declared === "formula" || element.hasAttribute("data-formula") || element.hasAttribute("data-smart-formula"))
|
|
8
8
|
return "formula";
|
|
9
9
|
return null;
|
|
10
10
|
};
|
|
@@ -35,61 +35,165 @@ export const inlineAtomPathFromDom = (root, atom) => {
|
|
|
35
35
|
const index = inlineUnits(leaf).indexOf(atom);
|
|
36
36
|
return leafPath && index >= 0 ? [...leafPath, index] : null;
|
|
37
37
|
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
38
|
+
const ownerSelector = "p,h1,h2,h3,h4,h5,h6";
|
|
39
|
+
const prepareOwner = (owner) => {
|
|
40
|
+
var _a;
|
|
41
|
+
(_a = owner.dataset).smartId || (_a.smartId = createNodeId());
|
|
42
|
+
owner.querySelectorAll("img,[data-formula],[data-smart-formula]").forEach((atom) => {
|
|
43
|
+
var _a, _b, _c;
|
|
44
|
+
(_a = atom.dataset).smartId || (_a.smartId = createNodeId());
|
|
45
|
+
if (atomType(atom) === "formula") {
|
|
46
|
+
atom.dataset.smartType = "formula";
|
|
47
|
+
atom.dataset.smartFormula = atom.dataset.smartFormula || atom.dataset.formula || atom.textContent || "";
|
|
48
|
+
(_b = atom.dataset).smartNotation || (_b.smartNotation = "latex");
|
|
49
|
+
atom.dataset.smartAtomic = "true";
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
atom.dataset.smartType = "image";
|
|
53
|
+
(_c = atom.dataset).smartStatus || (_c.smartStatus = "ready");
|
|
54
|
+
atom.dataset.smartAtomic = "true";
|
|
55
|
+
}
|
|
52
56
|
});
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
};
|
|
58
|
+
const parseOwner = (owner) => {
|
|
59
|
+
prepareOwner(owner);
|
|
60
|
+
return parseCanonicalListHtml(owner.outerHTML);
|
|
61
|
+
};
|
|
62
|
+
const contentWidth = (node) => {
|
|
63
|
+
if (node.nodeType === node.TEXT_NODE)
|
|
64
|
+
return node.nodeValue?.length || 0;
|
|
65
|
+
if (node instanceof HTMLElement && atomType(node))
|
|
66
|
+
return 1;
|
|
67
|
+
if (node instanceof HTMLElement && isEditorOnlyElement(node))
|
|
68
|
+
return 0;
|
|
69
|
+
return [...node.childNodes].reduce((sum, child) => sum + contentWidth(child), 0);
|
|
70
|
+
};
|
|
71
|
+
const caretOffset = (owner, range) => {
|
|
72
|
+
const before = owner.ownerDocument.createRange();
|
|
73
|
+
before.selectNodeContents(owner);
|
|
74
|
+
try {
|
|
75
|
+
before.setEnd(range.startContainer, range.startOffset);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return contentWidth(before.cloneContents());
|
|
81
|
+
};
|
|
82
|
+
const renderOwner = (owner, document) => {
|
|
83
|
+
const projection = owner.ownerDocument.createElement("div");
|
|
84
|
+
renderDocumentNaively(projection, document);
|
|
85
|
+
const replacement = Array.from(projection.querySelectorAll("[data-smart-id]"))
|
|
86
|
+
.find((element) => element.dataset.smartId === owner.dataset.smartId);
|
|
87
|
+
if (!replacement)
|
|
55
88
|
return false;
|
|
56
|
-
|
|
89
|
+
owner.replaceChildren(...Array.from(replacement.childNodes));
|
|
57
90
|
return true;
|
|
58
91
|
};
|
|
59
|
-
|
|
60
|
-
export const executeDomFormulaInsert = (root, input, domSelection = root.ownerDocument.defaultView?.getSelection() || null) => {
|
|
92
|
+
export const executeDomCanonicalAtomInsert = (root, input, domSelection = root.ownerDocument.defaultView?.getSelection() || null) => {
|
|
61
93
|
if (!domSelection?.rangeCount || !domSelection.isCollapsed)
|
|
62
94
|
return null;
|
|
63
|
-
const
|
|
64
|
-
|
|
95
|
+
const range = domSelection.getRangeAt(0);
|
|
96
|
+
const element = range.startContainer instanceof Element ? range.startContainer : range.startContainer.parentElement;
|
|
97
|
+
const owner = element?.closest(ownerSelector);
|
|
98
|
+
if (!owner || !root.contains(owner))
|
|
65
99
|
return null;
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
state: { document, selection: modelSelection },
|
|
69
|
-
plugins: [formulaPlugin],
|
|
70
|
-
});
|
|
71
|
-
if (!editor.execute("formula.insert", input))
|
|
100
|
+
const offset = caretOffset(owner, range);
|
|
101
|
+
if (offset === null)
|
|
72
102
|
return null;
|
|
73
|
-
const
|
|
74
|
-
|
|
103
|
+
const document = parseOwner(owner);
|
|
104
|
+
const declaration = atomDeclarations.find((entry) => entry.type === input.type);
|
|
105
|
+
const nodeId = createNodeId();
|
|
106
|
+
const index = createScopeIndex();
|
|
107
|
+
const operations = insertAtom(document, { kind: "empty", range: { from: { path: [0], offset }, to: { path: [0], offset } }, isolatingAncestorId: null, clamped: false }, {
|
|
108
|
+
declaration, nodeId, attrs: input.attrs, ownerId: owner.dataset.smartId, offset,
|
|
109
|
+
}, { schema: foundationSchema, positions: index.positions(document, foundationSchema) });
|
|
110
|
+
if (!operations.length || !renderOwner(owner, applyOperations(document, operations)))
|
|
75
111
|
return null;
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
];
|
|
80
|
-
const atom = getNodeAtPath(editor.state.document, formulaPath);
|
|
81
|
-
if (atom?.type !== "formula")
|
|
112
|
+
const atom = Array.from(owner.querySelectorAll("[data-smart-id]"))
|
|
113
|
+
.find((element) => element.dataset.smartId === nodeId) || null;
|
|
114
|
+
if (!atom)
|
|
82
115
|
return null;
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
116
|
+
if (input.type === "formula") {
|
|
117
|
+
atom.dataset.formula = String(input.attrs.source || "");
|
|
118
|
+
atom.textContent = String(input.attrs.displayText || input.attrs.source || "");
|
|
119
|
+
}
|
|
120
|
+
else
|
|
121
|
+
atom.dataset.srteInline = "true";
|
|
122
|
+
const next = root.ownerDocument.createRange();
|
|
123
|
+
next.setStartAfter(atom);
|
|
124
|
+
next.collapse(true);
|
|
90
125
|
domSelection.removeAllRanges();
|
|
91
|
-
domSelection.addRange(
|
|
92
|
-
return
|
|
126
|
+
domSelection.addRange(next);
|
|
127
|
+
return atom;
|
|
128
|
+
};
|
|
129
|
+
export const executeDomFormulaInsert = (root, input, selection) => executeDomCanonicalAtomInsert(root, { type: "formula", attrs: { source: input.value.trim(), notation: "latex", ...(input.displayText ? { displayText: input.displayText } : {}) } }, selection);
|
|
130
|
+
export const executeDomInlineAtomDelete = (root, atom) => {
|
|
131
|
+
const owner = atom.closest(ownerSelector);
|
|
132
|
+
if (!owner || !root.contains(owner) || !atomType(atom))
|
|
133
|
+
return false;
|
|
134
|
+
prepareOwner(owner);
|
|
135
|
+
const id = atom.dataset.smartId;
|
|
136
|
+
const document = parseOwner(owner);
|
|
137
|
+
const index = createScopeIndex();
|
|
138
|
+
const positions = index.positions(document, foundationSchema);
|
|
139
|
+
const range = positions.rangeOf(id);
|
|
140
|
+
if (!range)
|
|
141
|
+
return false;
|
|
142
|
+
const scope = { kind: "atomic-node", nodeId: id, inline: true, range, isolatingAncestorId: null, clamped: false };
|
|
143
|
+
const operations = deleteAtom(document, scope, {}, { schema: foundationSchema, positions });
|
|
144
|
+
return operations.length > 0 && renderOwner(owner, applyOperations(document, operations));
|
|
145
|
+
};
|
|
146
|
+
export const executeDomCanonicalAtomUpdate = (root, atom, attrs) => {
|
|
147
|
+
const owner = atom.closest(ownerSelector);
|
|
148
|
+
if (!owner || !root.contains(owner) || !atomType(atom))
|
|
149
|
+
return false;
|
|
150
|
+
prepareOwner(owner);
|
|
151
|
+
const id = atom.dataset.smartId;
|
|
152
|
+
const document = parseOwner(owner);
|
|
153
|
+
const index = createScopeIndex();
|
|
154
|
+
const positions = index.positions(document, foundationSchema);
|
|
155
|
+
const range = positions.rangeOf(id);
|
|
156
|
+
if (!range)
|
|
157
|
+
return false;
|
|
158
|
+
const scope = { kind: "atomic-node", nodeId: id, inline: true, range, isolatingAncestorId: null, clamped: false };
|
|
159
|
+
const operations = updateAtom(document, scope, { attrs }, { schema: foundationSchema, positions });
|
|
160
|
+
if (!operations.length)
|
|
161
|
+
return false;
|
|
162
|
+
const output = applyOperations(document, operations);
|
|
163
|
+
const nextPositions = createScopeIndex().positions(output, foundationSchema);
|
|
164
|
+
const resolved = nextPositions.positionOf(id);
|
|
165
|
+
const next = resolved?.parent.children?.find((child) => child.type !== "text" && "id" in child && child.id === id);
|
|
166
|
+
if (!next || next.type === "text")
|
|
167
|
+
return false;
|
|
168
|
+
if (atom instanceof HTMLImageElement) {
|
|
169
|
+
if (typeof next.attrs?.src === "string")
|
|
170
|
+
atom.src = next.attrs.src;
|
|
171
|
+
if (typeof next.attrs?.alt === "string")
|
|
172
|
+
atom.alt = next.attrs.alt;
|
|
173
|
+
if (typeof next.attrs?.title === "string")
|
|
174
|
+
atom.title = next.attrs.title;
|
|
175
|
+
if (Number(next.attrs?.width) > 0)
|
|
176
|
+
atom.width = Number(next.attrs?.width);
|
|
177
|
+
if (Number(next.attrs?.height) > 0)
|
|
178
|
+
atom.height = Number(next.attrs?.height);
|
|
179
|
+
const align = next.attrs?.align;
|
|
180
|
+
if (align === "center") {
|
|
181
|
+
atom.style.display = "block";
|
|
182
|
+
atom.style.margin = "0 auto";
|
|
183
|
+
atom.style.float = "none";
|
|
184
|
+
}
|
|
185
|
+
else if (align === "left" || align === "right") {
|
|
186
|
+
atom.style.display = "inline";
|
|
187
|
+
atom.style.float = align;
|
|
188
|
+
atom.style.margin = align === "left" ? "0 8px 8px 0" : "0 0 8px 8px";
|
|
189
|
+
}
|
|
190
|
+
atom.dataset.smartStatus = String(next.attrs?.status || "ready");
|
|
191
|
+
if (typeof next.attrs?.error === "string")
|
|
192
|
+
atom.dataset.smartError = next.attrs.error;
|
|
193
|
+
else
|
|
194
|
+
delete atom.dataset.smartError;
|
|
195
|
+
}
|
|
196
|
+
return true;
|
|
93
197
|
};
|
|
94
198
|
export const adjacentInlineAtom = (range, direction) => {
|
|
95
199
|
if (!range.collapsed || range.startContainer.nodeType !== Node.ELEMENT_NODE)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export interface DomInlineImageInput {
|
|
2
2
|
src: string;
|
|
3
3
|
alt?: string;
|
|
4
|
+
decorative?: boolean;
|
|
4
5
|
title?: string;
|
|
5
6
|
width?: number;
|
|
6
7
|
height?: number;
|
|
8
|
+
align?: "center" | "left" | "right";
|
|
9
|
+
status?: "pending" | "ready" | "error";
|
|
10
|
+
uploadId?: string;
|
|
11
|
+
error?: string;
|
|
7
12
|
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
* atom into the existing DOM range. Unrelated DOM and metadata stay untouched.
|
|
11
|
-
*/
|
|
12
|
-
export declare const executeDomInlineImageCommand: (root: HTMLElement, input: DomInlineImageInput, domSelection?: Selection | null) => HTMLImageElement | null;
|
|
13
|
-
/** Validates an inline image attribute update through core, then mutates it in place. */
|
|
14
|
-
export declare const executeDomInlineImageUpdate: (root: HTMLElement, image: HTMLImageElement, input: Omit<DomInlineImageInput, "src">) => boolean;
|
|
13
|
+
export declare const executeDomInlineImageCommand: (root: HTMLElement, input: DomInlineImageInput, selection?: Selection | null) => HTMLImageElement | null;
|
|
14
|
+
export declare const executeDomInlineImageUpdate: (root: HTMLElement, image: HTMLImageElement, input: Partial<DomInlineImageInput>) => boolean;
|