smartrte-react 0.3.4 → 0.3.5

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +14 -83
  3. package/dist/adapters/canonicalInlineCommandBridge.d.ts +15 -0
  4. package/dist/adapters/canonicalInlineCommandBridge.js +269 -0
  5. package/dist/adapters/canonicalListCommandBridge.d.ts +26 -0
  6. package/dist/adapters/canonicalListCommandBridge.js +430 -0
  7. package/dist/adapters/documentFormats.d.ts +26 -0
  8. package/dist/adapters/documentFormats.js +49 -0
  9. package/dist/adapters/docxFormat.d.ts +5 -0
  10. package/dist/adapters/docxFormat.js +272 -0
  11. package/dist/adapters/domBlockCommandBridge.d.ts +19 -0
  12. package/dist/adapters/domBlockCommandBridge.js +79 -0
  13. package/dist/adapters/domChecklistCommandBridge.d.ts +6 -0
  14. package/dist/adapters/domChecklistCommandBridge.js +33 -0
  15. package/dist/adapters/domCommandBridge.d.ts +19 -0
  16. package/dist/adapters/domCommandBridge.js +33 -0
  17. package/dist/adapters/domInlineAtomCommandBridge.d.ts +14 -0
  18. package/dist/adapters/domInlineAtomCommandBridge.js +101 -0
  19. package/dist/adapters/domInlineImageCommandBridge.d.ts +14 -0
  20. package/dist/adapters/domInlineImageCommandBridge.js +72 -0
  21. package/dist/adapters/domMoveCommandBridge.d.ts +7 -0
  22. package/dist/adapters/domMoveCommandBridge.js +54 -0
  23. package/dist/adapters/domSelectionBridge.d.ts +3 -1
  24. package/dist/adapters/domSelectionBridge.js +96 -44
  25. package/dist/adapters/domSmartDocument.js +158 -16
  26. package/dist/adapters/domTableCommandBridge.d.ts +35 -0
  27. package/dist/adapters/domTableCommandBridge.js +201 -0
  28. package/dist/adapters/legacyListShadowComparator.d.ts +26 -0
  29. package/dist/adapters/legacyListShadowComparator.js +316 -0
  30. package/dist/adapters/pdfFormat.d.ts +23 -0
  31. package/dist/adapters/pdfFormat.js +204 -0
  32. package/dist/adapters/portableDocxAtoms.d.ts +4 -0
  33. package/dist/adapters/portableDocxAtoms.js +58 -0
  34. package/dist/adapters/styledDocxFormat.d.ts +8 -0
  35. package/dist/adapters/styledDocxFormat.js +190 -0
  36. package/dist/builtInFormatDefinitions.d.ts +5 -0
  37. package/dist/builtInFormatDefinitions.js +82 -0
  38. package/dist/canonicalAuthorityFlag.d.ts +32 -0
  39. package/dist/canonicalAuthorityFlag.js +49 -0
  40. package/dist/canonicalClipboardRuntime.d.ts +15 -0
  41. package/dist/canonicalClipboardRuntime.js +76 -0
  42. package/dist/canonicalEditorRuntime.d.ts +77 -0
  43. package/dist/canonicalEditorRuntime.js +274 -0
  44. package/dist/components/CanonicalAuthorityEditor.d.ts +25 -0
  45. package/dist/components/CanonicalAuthorityEditor.js +518 -0
  46. package/dist/components/ClassicEditor.d.ts +13 -3
  47. package/dist/components/ClassicEditor.js +1226 -1114
  48. package/dist/components/ClassicEditorAuthority.d.ts +38 -0
  49. package/dist/components/ClassicEditorAuthority.js +49 -0
  50. package/dist/components/MediaPicker.d.ts +10 -0
  51. package/dist/components/MediaPicker.js +16 -0
  52. package/dist/editorController.d.ts +78 -0
  53. package/dist/editorController.js +298 -0
  54. package/dist/formatFidelity.d.ts +14 -0
  55. package/dist/formatFidelity.js +107 -0
  56. package/dist/formatRuntime.d.ts +50 -0
  57. package/dist/formatRuntime.js +20 -0
  58. package/dist/index.d.ts +24 -0
  59. package/dist/index.js +10 -0
  60. package/dist/mediaProvider.d.ts +39 -0
  61. package/dist/mediaProvider.js +1 -0
  62. package/dist/pluginRuntime.d.ts +68 -0
  63. package/dist/pluginRuntime.js +78 -0
  64. package/dist/standalone/editor.js +722 -495
  65. package/dist/test-harness/atomShadowComparator.d.ts +14 -0
  66. package/dist/test-harness/atomShadowComparator.js +63 -0
  67. package/dist/test-harness/blockShadowComparator.d.ts +30 -0
  68. package/dist/test-harness/blockShadowComparator.js +140 -0
  69. package/dist/test-harness/clipboardShadowComparator.d.ts +12 -0
  70. package/dist/test-harness/clipboardShadowComparator.js +46 -0
  71. package/dist/test-harness/inlineShadowComparator.d.ts +32 -0
  72. package/dist/test-harness/inlineShadowComparator.js +152 -0
  73. package/dist/test-harness/legacyAtomEngine.d.ts +10 -0
  74. package/dist/test-harness/legacyAtomEngine.js +15 -0
  75. package/dist/test-harness/legacyBlockEngine.d.ts +31 -0
  76. package/dist/test-harness/legacyBlockEngine.js +31 -0
  77. package/dist/test-harness/legacyClipboardEngine.d.ts +14 -0
  78. package/dist/test-harness/legacyClipboardEngine.js +67 -0
  79. package/dist/test-harness/legacyInlineEngine.d.ts +19 -0
  80. package/dist/test-harness/legacyInlineEngine.js +49 -0
  81. package/dist/test-harness/legacyTableEngine.d.ts +12 -0
  82. package/dist/test-harness/legacyTableEngine.js +25 -0
  83. package/dist/test-harness/tableShadowComparator.d.ts +29 -0
  84. package/dist/test-harness/tableShadowComparator.js +101 -0
  85. package/dist/theme.d.ts +1 -1
  86. package/dist/theme.js +28 -0
  87. package/package.json +1 -1
@@ -0,0 +1,20 @@
1
+ import { createBuiltInFormatDefinitions } from "./builtInFormatDefinitions.js";
2
+ export const createEditorFormatRuntime = (config = {}, replacements = createBuiltInFormatDefinitions()) => {
3
+ const seen = new Set();
4
+ replacements.forEach((format) => {
5
+ if (seen.has(format.id))
6
+ throw new Error(`Duplicate editor format "${format.id}".`);
7
+ seen.add(format.id);
8
+ });
9
+ const formats = replacements.filter((format) => config[format.id] !== false);
10
+ const byId = new Map(formats.map((format) => [format.id, format]));
11
+ return {
12
+ formats,
13
+ imports: formats.filter((format) => format.canImport),
14
+ exports: formats.filter((format) => format.canExport),
15
+ has: (format) => byId.has(format),
16
+ get: (format) => byId.get(format),
17
+ canImport: (format) => Boolean(byId.get(format)?.canImport),
18
+ canExport: (format) => Boolean(byId.get(format)?.canExport),
19
+ };
20
+ };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,28 @@
1
1
  export { ClassicEditor } from './components/ClassicEditor.js';
2
+ export type { ClassicEditorProps } from './components/ClassicEditor.js';
2
3
  export type { MediaManagerAdapter, MediaItem, MediaSearchQuery } from './components/MediaManager.js';
3
4
  export type { SrteTheme } from './theme.js';
4
5
  export { SRTE_DEFAULT_CSS, ensureStyleSheet } from './theme.js';
6
+ export { createReactEditorPluginRuntime } from './pluginRuntime.js';
7
+ export type { ReactEditorFeatureConfig, ReactEditorPluginRuntime } from './pluginRuntime.js';
8
+ export type { ReactEditorPlugin, ReactPluginUi, ReactToolbarContribution } from './pluginRuntime.js';
9
+ export type { ReactContextMenuContext, ReactContextMenuContribution, ReactKeyboardShortcutContribution } from './pluginRuntime.js';
10
+ export type { ReactCommandContribution, ReactCommandContributionContext } from './pluginRuntime.js';
11
+ export { matchesPluginShortcut } from './pluginRuntime.js';
12
+ export { createDocumentFormatRegistry, defaultDocumentFormatRegistry, DocumentFormatRegistry, exportTextDocument, getDocumentFormatAdapter, importTextDocument, roundTripTextDocument } from './adapters/documentFormats.js';
13
+ export type { DocumentFormatAdapter, DocumentImportContext, TextDocumentFormat } from './adapters/documentFormats.js';
14
+ export { DOCX_MEDIA_TYPE, exportDocxDocument, importDocxDocumentWithMammoth, smartDocumentToDocxXml } from './adapters/docxFormat.js';
15
+ export { enhanceDocxTables, importStyledDocxDocument } from './adapters/styledDocxFormat.js';
16
+ export type { StyledDocxImportResult } from './adapters/styledDocxFormat.js';
17
+ export { buildPdfPrintDocument, importPdfDocument, PDF_MEDIA_TYPE, printSmartDocumentAsPdf, reconstructPdfPages } from './adapters/pdfFormat.js';
18
+ export type { PdfImportResult, PdfPageSnapshot, PdfTextItemSnapshot } from './adapters/pdfFormat.js';
19
+ export { createEditorFormatRuntime } from './formatRuntime.js';
20
+ export type { BuiltInDocumentFormat, EditorDocumentFormat, EditorFormatConfig, EditorFormatDefinition, EditorFormatExportContext, EditorFormatExportResult, EditorFormatImportContext, EditorFormatImportResult, EditorFormatRuntime } from './formatRuntime.js';
21
+ export { builtInFormatFidelity, getFormatFidelity } from './formatFidelity.js';
22
+ export type { FeatureFidelityContract, FidelityFeature, FidelityFormat, FidelityLevel, FormatFidelityCapability } from './formatFidelity.js';
23
+ export { createBuiltInFormatDefinitions } from './builtInFormatDefinitions.js';
24
+ export type { BuiltInFormatDefinitionOptions } from './builtInFormatDefinitions.js';
25
+ export { createDomEditorController, DomEditorController } from './editorController.js';
26
+ export type { DomEditorControllerChange, DomEditorControllerListener, DomEditorControllerSnapshot } from './editorController.js';
27
+ export type { DomBlockCommand } from './adapters/domBlockCommandBridge.js';
28
+ export type { DomTableCommand } from './adapters/domTableCommandBridge.js';
package/dist/index.js CHANGED
@@ -1,2 +1,12 @@
1
1
  export { ClassicEditor } from './components/ClassicEditor.js';
2
2
  export { SRTE_DEFAULT_CSS, ensureStyleSheet } from './theme.js';
3
+ export { createReactEditorPluginRuntime } from './pluginRuntime.js';
4
+ export { matchesPluginShortcut } from './pluginRuntime.js';
5
+ export { createDocumentFormatRegistry, defaultDocumentFormatRegistry, DocumentFormatRegistry, exportTextDocument, getDocumentFormatAdapter, importTextDocument, roundTripTextDocument } from './adapters/documentFormats.js';
6
+ export { DOCX_MEDIA_TYPE, exportDocxDocument, importDocxDocumentWithMammoth, smartDocumentToDocxXml } from './adapters/docxFormat.js';
7
+ export { enhanceDocxTables, importStyledDocxDocument } from './adapters/styledDocxFormat.js';
8
+ export { buildPdfPrintDocument, importPdfDocument, PDF_MEDIA_TYPE, printSmartDocumentAsPdf, reconstructPdfPages } from './adapters/pdfFormat.js';
9
+ export { createEditorFormatRuntime } from './formatRuntime.js';
10
+ export { builtInFormatFidelity, getFormatFidelity } from './formatFidelity.js';
11
+ export { createBuiltInFormatDefinitions } from './builtInFormatDefinitions.js';
12
+ export { createDomEditorController, DomEditorController } from './editorController.js';
@@ -0,0 +1,39 @@
1
+ export type MediaKind = "image" | "video" | "audio";
2
+ export interface UploadOptions {
3
+ readonly signal?: AbortSignal;
4
+ }
5
+ export interface MediaFilters {
6
+ readonly mimePrefix?: string;
7
+ readonly tags?: readonly string[];
8
+ readonly hashHex?: string;
9
+ readonly pageSize?: number;
10
+ }
11
+ export interface MediaItem {
12
+ readonly id: string;
13
+ readonly url: string;
14
+ readonly width?: number;
15
+ readonly height?: number;
16
+ readonly sizeBytes?: number;
17
+ readonly mimeType?: string;
18
+ readonly hashHex?: string;
19
+ readonly createdAt?: string;
20
+ readonly title?: string;
21
+ readonly alt?: string;
22
+ readonly tags?: readonly string[];
23
+ readonly license?: {
24
+ readonly author?: string;
25
+ readonly licenseType?: string;
26
+ readonly licenseText?: string;
27
+ readonly sourceUrl?: string;
28
+ readonly workName?: string;
29
+ };
30
+ }
31
+ /** Host-owned media boundary. The editor never receives storage credentials. */
32
+ export interface MediaProvider {
33
+ upload(file: File, opts?: UploadOptions): Promise<{
34
+ url: string;
35
+ id: string;
36
+ }>;
37
+ search(query: string, filters?: MediaFilters, page?: number): Promise<MediaItem[]>;
38
+ remove(id: string): Promise<void>;
39
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,68 @@
1
+ import { type CoreFeatureConfig, type CoreFeatureId, type SmartRtePlugin } from "smartrte-core";
2
+ import type { ReactNode } from "react";
3
+ import type { EditorFormatDefinition } from "./formatRuntime.js";
4
+ export type ReactEditorFeatureConfig = CoreFeatureConfig;
5
+ export interface ReactCommandContributionContext {
6
+ root: HTMLElement | null;
7
+ selection: Selection | null;
8
+ readOnly: boolean;
9
+ canExecute: (commandId: string, input?: unknown) => boolean;
10
+ }
11
+ export interface ReactCommandContribution {
12
+ id: string;
13
+ commandId: string;
14
+ input?: unknown;
15
+ order?: number;
16
+ isVisible?: (context: ReactCommandContributionContext) => boolean;
17
+ isEnabled?: (context: ReactCommandContributionContext) => boolean;
18
+ isActive?: (context: ReactCommandContributionContext) => boolean;
19
+ }
20
+ export interface ReactToolbarContribution extends ReactCommandContribution {
21
+ label: string;
22
+ title?: string;
23
+ placement?: "main" | "insert" | "more";
24
+ icon?: ReactNode;
25
+ }
26
+ export interface ReactKeyboardShortcutContribution extends ReactCommandContribution {
27
+ key: string;
28
+ primary?: boolean;
29
+ alt?: boolean;
30
+ shift?: boolean;
31
+ }
32
+ export interface ReactContextMenuContext {
33
+ root: HTMLElement;
34
+ target: HTMLElement;
35
+ selection: Selection | null;
36
+ }
37
+ export interface ReactContextMenuContribution extends ReactCommandContribution {
38
+ label: string;
39
+ when?: (context: ReactContextMenuContext) => boolean;
40
+ }
41
+ export interface ReactPluginUi {
42
+ toolbar?: readonly ReactToolbarContribution[];
43
+ shortcuts?: readonly ReactKeyboardShortcutContribution[];
44
+ contextMenu?: readonly ReactContextMenuContribution[];
45
+ formats?: readonly EditorFormatDefinition[];
46
+ }
47
+ export type ReactEditorPlugin = SmartRtePlugin & {
48
+ react?: ReactPluginUi;
49
+ };
50
+ export interface ReactEditorPluginRuntime {
51
+ plugins: readonly SmartRtePlugin[];
52
+ featureIds: ReadonlySet<CoreFeatureId>;
53
+ toolbar: readonly ReactToolbarContribution[];
54
+ shortcuts: readonly ReactKeyboardShortcutContribution[];
55
+ contextMenu: readonly ReactContextMenuContribution[];
56
+ formats: readonly EditorFormatDefinition[];
57
+ hasFeature: (feature: CoreFeatureId) => boolean;
58
+ }
59
+ /**
60
+ * Resolves one authoritative plugin set for both React UI availability and
61
+ * core command execution. Passing `plugins` creates an exact custom runtime;
62
+ * otherwise the standard plugin preset is filtered by `features`.
63
+ */
64
+ export declare const createReactEditorPluginRuntime: (options?: {
65
+ features?: ReactEditorFeatureConfig;
66
+ plugins?: readonly ReactEditorPlugin[];
67
+ }) => ReactEditorPluginRuntime;
68
+ export declare const matchesPluginShortcut: (event: Pick<KeyboardEvent, "key" | "metaKey" | "ctrlKey" | "altKey" | "shiftKey">, shortcut: ReactKeyboardShortcutContribution) => boolean;
@@ -0,0 +1,78 @@
1
+ import { createCorePlugins, orderPlugins, } from "smartrte-core";
2
+ const pluginIdByFeature = {
3
+ basicFormatting: "basic-formatting",
4
+ blockType: "block-type",
5
+ alignment: "alignment",
6
+ list: "list",
7
+ checklist: "checklist",
8
+ blockquote: "blockquote",
9
+ codeBlock: "code-block",
10
+ table: "table",
11
+ media: "media",
12
+ formula: "formula",
13
+ move: "move",
14
+ };
15
+ /**
16
+ * Resolves one authoritative plugin set for both React UI availability and
17
+ * core command execution. Passing `plugins` creates an exact custom runtime;
18
+ * otherwise the standard plugin preset is filtered by `features`.
19
+ */
20
+ export const createReactEditorPluginRuntime = (options = {}) => {
21
+ const plugins = orderPlugins(options.plugins ? [...options.plugins] : createCorePlugins(options.features));
22
+ const pluginIds = new Set(plugins.map((plugin) => plugin.id));
23
+ const featureIds = new Set(Object.keys(pluginIdByFeature)
24
+ .filter((feature) => pluginIds.has(pluginIdByFeature[feature])));
25
+ const commandIds = new Set(plugins.flatMap((plugin) => Object.keys(plugin.commands || {})));
26
+ const contributionIds = new Set();
27
+ const ordered = (items) => items.map((item, index) => ({ item, index }))
28
+ .sort((left, right) => (left.item.order ?? 0) - (right.item.order ?? 0) || left.index - right.index)
29
+ .map(({ item }) => item);
30
+ const validateContribution = (pluginId, contribution, kind) => {
31
+ if (!contribution.id.trim())
32
+ throw new Error(`Plugin "${pluginId}" has a ${kind} contribution with an empty id.`);
33
+ if (contributionIds.has(contribution.id)) {
34
+ throw new Error(`Duplicate UI contribution id "${contribution.id}".`);
35
+ }
36
+ if (!commandIds.has(contribution.commandId)) {
37
+ throw new Error(`${kind} contribution "${contribution.id}" references missing command "${contribution.commandId}".`);
38
+ }
39
+ contributionIds.add(contribution.id);
40
+ };
41
+ const toolbar = ordered(plugins.flatMap((plugin) => (plugin.react?.toolbar || []).map((contribution) => {
42
+ validateContribution(plugin.id, contribution, "Toolbar");
43
+ return { ...contribution };
44
+ })));
45
+ const shortcuts = ordered(plugins.flatMap((plugin) => (plugin.react?.shortcuts || []).map((contribution) => {
46
+ validateContribution(plugin.id, contribution, "Shortcut");
47
+ if (!contribution.key.trim()) {
48
+ throw new Error(`Shortcut contribution "${contribution.id}" requires a key.`);
49
+ }
50
+ return { ...contribution, key: contribution.key.toLowerCase() };
51
+ })));
52
+ const contextMenu = ordered(plugins.flatMap((plugin) => (plugin.react?.contextMenu || []).map((contribution) => {
53
+ validateContribution(plugin.id, contribution, "Context menu");
54
+ return { ...contribution };
55
+ })));
56
+ const formatIds = new Set();
57
+ const formats = plugins.flatMap((plugin) => (plugin.react?.formats || []).map((format) => {
58
+ if (!format.id.trim())
59
+ throw new Error(`Plugin "${plugin.id}" has a format with an empty id.`);
60
+ if (formatIds.has(format.id))
61
+ throw new Error(`Duplicate plugin format "${format.id}".`);
62
+ formatIds.add(format.id);
63
+ return format;
64
+ }));
65
+ return {
66
+ plugins,
67
+ featureIds,
68
+ toolbar,
69
+ shortcuts,
70
+ contextMenu,
71
+ formats,
72
+ hasFeature: (feature) => featureIds.has(feature),
73
+ };
74
+ };
75
+ export const matchesPluginShortcut = (event, shortcut) => event.key.toLowerCase() === shortcut.key.toLowerCase() &&
76
+ (shortcut.primary ? event.metaKey || event.ctrlKey : !event.metaKey && !event.ctrlKey) &&
77
+ event.altKey === Boolean(shortcut.alt) &&
78
+ event.shiftKey === Boolean(shortcut.shift);