pixel-react 1.22.4 → 1.22.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 (44) hide show
  1. package/lib/components/Icon/iconList.js +4 -0
  2. package/lib/components/Icon/iconList.js.map +1 -1
  3. package/lib/components/RichTextEditor/DynamicValue.d.ts +8 -0
  4. package/lib/components/RichTextEditor/DynamicValue.js +73 -0
  5. package/lib/components/RichTextEditor/DynamicValue.js.map +1 -0
  6. package/lib/components/RichTextEditor/DynamicValueList.d.ts +11 -0
  7. package/lib/components/RichTextEditor/DynamicValueList.js +49 -0
  8. package/lib/components/RichTextEditor/DynamicValueList.js.map +1 -0
  9. package/lib/components/RichTextEditor/ImagePopover.d.ts +10 -0
  10. package/lib/components/RichTextEditor/ImagePopover.js +99 -0
  11. package/lib/components/RichTextEditor/ImagePopover.js.map +1 -0
  12. package/lib/components/RichTextEditor/LinkPopover.d.ts +8 -0
  13. package/lib/components/RichTextEditor/LinkPopover.js +98 -0
  14. package/lib/components/RichTextEditor/LinkPopover.js.map +1 -0
  15. package/lib/components/RichTextEditor/RichTextEditor.d.ts +5 -0
  16. package/lib/components/RichTextEditor/RichTextEditor.js +216 -0
  17. package/lib/components/RichTextEditor/RichTextEditor.js.map +1 -0
  18. package/lib/components/RichTextEditor/Toolbar.d.ts +12 -0
  19. package/lib/components/RichTextEditor/Toolbar.js +186 -0
  20. package/lib/components/RichTextEditor/Toolbar.js.map +1 -0
  21. package/lib/components/RichTextEditor/constants.d.ts +4 -0
  22. package/lib/components/RichTextEditor/constants.js +33 -0
  23. package/lib/components/RichTextEditor/constants.js.map +1 -0
  24. package/lib/components/RichTextEditor/fileAttachment.d.ts +23 -0
  25. package/lib/components/RichTextEditor/fileAttachment.js +143 -0
  26. package/lib/components/RichTextEditor/fileAttachment.js.map +1 -0
  27. package/lib/components/RichTextEditor/imageUpload.d.ts +6 -0
  28. package/lib/components/RichTextEditor/imageUpload.js +29 -0
  29. package/lib/components/RichTextEditor/imageUpload.js.map +1 -0
  30. package/lib/components/RichTextEditor/index.d.ts +1 -0
  31. package/lib/components/RichTextEditor/index.js +2 -0
  32. package/lib/components/RichTextEditor/index.js.map +1 -0
  33. package/lib/components/RichTextEditor/pasteFormatting.d.ts +18 -0
  34. package/lib/components/RichTextEditor/pasteFormatting.js +167 -0
  35. package/lib/components/RichTextEditor/pasteFormatting.js.map +1 -0
  36. package/lib/components/RichTextEditor/types.d.ts +167 -0
  37. package/lib/components/RichTextEditor/types.js +2 -0
  38. package/lib/components/RichTextEditor/types.js.map +1 -0
  39. package/lib/index.d.ts +174 -4
  40. package/lib/index.js +27 -9
  41. package/lib/index.js.map +1 -1
  42. package/lib/styles.css +1 -1
  43. package/lib/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +129 -119
@@ -0,0 +1,143 @@
1
+ import { mergeAttributes, Node } from '@tiptap/react';
2
+ import { SAFE_IMAGE_URL_REGEX } from './imageUpload';
3
+ // Same rule as images: data URLs are limited to images so a pasted
4
+ // `data:text/html` link can't run script when opened
5
+ export const SAFE_ATTACHMENT_URL_REGEX = SAFE_IMAGE_URL_REGEX;
6
+ export const formatFileSize = (bytes) => {
7
+ if (bytes < 1024)
8
+ return `${bytes} B`;
9
+ const units = ['KB', 'MB', 'GB'];
10
+ let size = bytes / 1024;
11
+ let unit = 0;
12
+ while (size >= 1024 && unit < units.length - 1) {
13
+ size /= 1024;
14
+ unit += 1;
15
+ }
16
+ return `${size < 10 ? size.toFixed(1) : Math.round(size)} ${units[unit]}`;
17
+ };
18
+ // Same syntax as the `accept` attribute: `.pdf`, `image/*`, `application/pdf`
19
+ export const matchesAccept = (file, accept) => {
20
+ const rules = accept
21
+ .split(',')
22
+ .map((rule) => rule.trim().toLowerCase())
23
+ .filter(Boolean);
24
+ if (!rules.length)
25
+ return true;
26
+ const name = file.name.toLowerCase();
27
+ const type = file.type.toLowerCase();
28
+ return rules.some((rule) => {
29
+ if (rule.startsWith('.'))
30
+ return name.endsWith(rule);
31
+ if (rule.endsWith('/*'))
32
+ return type.startsWith(rule.slice(0, -1));
33
+ return type === rule;
34
+ });
35
+ };
36
+ /**
37
+ * Inline, non-editable chip linking to an uploaded file. Serialised as
38
+ * `<a data-type="fileAttachment" href="{url}" data-name="{name}" data-size="{bytes}" download="{name}">{name} ({size})</a>`
39
+ */
40
+ export const FileAttachment = Node.create({
41
+ name: 'fileAttachment',
42
+ group: 'inline',
43
+ inline: true,
44
+ atom: true,
45
+ selectable: true,
46
+ draggable: true,
47
+ addAttributes() {
48
+ return {
49
+ href: {
50
+ default: null,
51
+ parseHTML: (element) => {
52
+ const href = element.getAttribute('href') ?? '';
53
+ return SAFE_ATTACHMENT_URL_REGEX.test(href) ? href : null;
54
+ },
55
+ renderHTML: () => ({}),
56
+ },
57
+ name: {
58
+ default: '',
59
+ parseHTML: (element) => element.getAttribute('data-name') ?? element.textContent ?? '',
60
+ renderHTML: () => ({}),
61
+ },
62
+ size: {
63
+ default: null,
64
+ parseHTML: (element) => {
65
+ const size = Number(element.getAttribute('data-size'));
66
+ return Number.isFinite(size) && size > 0 ? size : null;
67
+ },
68
+ renderHTML: () => ({}),
69
+ },
70
+ };
71
+ },
72
+ parseHTML() {
73
+ // Above the link mark's `a[href]` rule
74
+ return [{ tag: 'a[data-type="fileAttachment"]', priority: 60 }];
75
+ },
76
+ renderHTML({ node, HTMLAttributes }) {
77
+ const { href, name, size } = node.attrs;
78
+ return [
79
+ 'a',
80
+ mergeAttributes(HTMLAttributes, {
81
+ 'data-type': this.name,
82
+ class: 'ff-rich-text-editor__attachment',
83
+ href,
84
+ 'data-name': name,
85
+ 'data-size': size ?? undefined,
86
+ download: name,
87
+ target: '_blank',
88
+ rel: 'noopener noreferrer',
89
+ }),
90
+ size ? `${name} (${formatFileSize(size)})` : name,
91
+ ];
92
+ },
93
+ renderText({ node }) {
94
+ return node.attrs.name;
95
+ },
96
+ });
97
+ /**
98
+ * Uploads files and inserts them as attachment chips at `pos`, or over the
99
+ * selection when omitted. Resolves with the position after the last chip
100
+ */
101
+ export const insertAttachmentFiles = async (view, files, { upload, accept, maxFileSize, onError }, pos) => {
102
+ for (const file of files) {
103
+ if (!matchesAccept(file, accept)) {
104
+ onError?.(file, 'type');
105
+ continue;
106
+ }
107
+ if (maxFileSize && file.size > maxFileSize) {
108
+ onError?.(file, 'size');
109
+ continue;
110
+ }
111
+ let href;
112
+ try {
113
+ href = await upload(file);
114
+ }
115
+ catch {
116
+ onError?.(file, 'upload');
117
+ continue;
118
+ }
119
+ // The editor may have been unmounted while uploading
120
+ const attachmentType = view.isDestroyed
121
+ ? null
122
+ : view.state.schema.nodes.fileAttachment;
123
+ if (!attachmentType)
124
+ return pos;
125
+ if (!SAFE_ATTACHMENT_URL_REGEX.test(href)) {
126
+ onError?.(file, 'upload');
127
+ continue;
128
+ }
129
+ const node = attachmentType.create({
130
+ href,
131
+ name: file.name,
132
+ size: file.size,
133
+ });
134
+ const tr = pos === undefined
135
+ ? view.state.tr.replaceSelectionWith(node, false)
136
+ : view.state.tr.insert(Math.min(pos, view.state.doc.content.size), node);
137
+ view.dispatch(tr);
138
+ if (pos !== undefined)
139
+ pos += node.nodeSize;
140
+ }
141
+ return pos;
142
+ };
143
+ //# sourceMappingURL=fileAttachment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileAttachment.js","sourceRoot":"","sources":["../../../src/components/RichTextEditor/fileAttachment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { EditorView } from '@tiptap/pm/view';
2
+ import { RichTextImageUpload } from './types';
3
+ export declare const SAFE_IMAGE_URL_REGEX: RegExp;
4
+ export declare const readAsDataUrl: RichTextImageUpload;
5
+ export declare const getImageFiles: (files?: FileList | File[] | null) => File[];
6
+ export declare const insertImageFiles: (view: EditorView, files: File[], upload: RichTextImageUpload, pos?: number) => Promise<number | undefined>;
@@ -0,0 +1,29 @@
1
+ export const SAFE_IMAGE_URL_REGEX = /^(https?:\/\/|data:image\/)/i;
2
+ // Used when no `onImageUpload` is given: embeds the file in the HTML
3
+ export const readAsDataUrl = (file) => new Promise((resolve, reject) => {
4
+ const reader = new FileReader();
5
+ reader.onload = () => resolve(reader.result);
6
+ reader.onerror = () => reject(reader.error);
7
+ reader.readAsDataURL(file);
8
+ });
9
+ export const getImageFiles = (files) => Array.from(files ?? []).filter((file) => file.type.startsWith('image/'));
10
+ // Inserts pasted/dropped images at `pos`, or over the selection when omitted.
11
+ // Resolves with the position after the last image
12
+ export const insertImageFiles = async (view, files, upload, pos) => {
13
+ for (const file of files) {
14
+ const src = await upload(file);
15
+ // The editor may have been unmounted while uploading
16
+ const imageType = view.isDestroyed ? null : view.state.schema.nodes.image;
17
+ if (!imageType || !SAFE_IMAGE_URL_REGEX.test(src))
18
+ continue;
19
+ const node = imageType.create({ src, alt: file.name });
20
+ const tr = pos === undefined
21
+ ? view.state.tr.replaceSelectionWith(node)
22
+ : view.state.tr.insert(Math.min(pos, view.state.doc.content.size), node);
23
+ view.dispatch(tr);
24
+ if (pos !== undefined)
25
+ pos += node.nodeSize;
26
+ }
27
+ return pos;
28
+ };
29
+ //# sourceMappingURL=imageUpload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"imageUpload.js","sourceRoot":"","sources":["../../../src/components/RichTextEditor/imageUpload.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,oBAAoB,GAAG,8BAA8B,CAAC;AAEnE,qEAAqE;AACrE,MAAM,CAAC,MAAM,aAAa,GAAwB,CAAC,IAAI,EAAE,EAAE,CACzD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC9B,MAAM,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;IAChC,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAgB,CAAC,CAAC;IACvD,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAgC,EAAE,EAAE,CAChE,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE3E,8EAA8E;AAC9E,kDAAkD;AAClD,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EACnC,IAAgB,EAChB,KAAa,EACb,MAA2B,EAC3B,GAAY,EACZ,EAAE;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,qDAAqD;QACrD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC;QAC1E,IAAI,CAAC,SAAS,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5D,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACvD,MAAM,EAAE,GACN,GAAG,KAAK,SAAS;YACf,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC;YAC1C,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAClB,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAC1C,IAAI,CACL,CAAC;QACR,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClB,IAAI,GAAG,KAAK,SAAS;YAAE,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC9C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
@@ -0,0 +1 @@
1
+ export { default } from './RichTextEditor';
@@ -0,0 +1,2 @@
1
+ export { default } from './RichTextEditor';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/RichTextEditor/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { Extension } from '@tiptap/core';
2
+ /**
3
+ * Keeps inline styles and legacy layout attributes (common in email signatures)
4
+ * on blocks and tables, which the default schema drops
5
+ */
6
+ export declare const PreservedHtmlAttributes: Extension<any, any>;
7
+ /**
8
+ * Inline image (so it can sit in a line of text or inside a link) that keeps its inline style
9
+ */
10
+ export declare const InlineImage: import("@tiptap/core").Node<import("@tiptap/extension-image").ImageOptions, any>;
11
+ /**
12
+ * Prepares pasted HTML (e.g. a copied email signature) so it keeps its look:
13
+ * converts `<font>` tags and line divs, copies inherited text styles onto the
14
+ * text, and drops images the browser can't load (`file:`, `cid:`, `blob:`).
15
+ * All images are dropped when `keepImages` is false
16
+ */
17
+ export declare const normalizePastedHtml: (html: string, keepImages: boolean) => string;
18
+ export declare const hasHtmlText: (html: string) => boolean;
@@ -0,0 +1,167 @@
1
+ import { Extension } from '@tiptap/core';
2
+ import Image from '@tiptap/extension-image';
3
+ import { SAFE_IMAGE_URL_REGEX } from './imageUpload';
4
+ // Text styles a parent passes down to its text. Pasted wrappers (divs, cells)
5
+ // aren't kept as nodes, so these are copied onto the text itself
6
+ const INHERITED_STYLES = [
7
+ 'color',
8
+ 'font-family',
9
+ 'font-size',
10
+ 'font-weight',
11
+ 'font-style',
12
+ 'line-height',
13
+ 'text-decoration',
14
+ ];
15
+ const BLOCK_SELECTOR = 'address, article, aside, blockquote, dd, div, dl, dt, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hr, li, main, nav, ol, p, pre, section, table, ul';
16
+ // <font size="1-7"> to the sizes browsers render them at
17
+ const FONT_TAG_SIZES = ['', '10px', '13px', '16px', '18px', '24px', '32px', '48px'];
18
+ const preserveAttribute = (key, htmlName) => ({
19
+ [key]: {
20
+ default: null,
21
+ parseHTML: (element) => element.getAttribute(htmlName),
22
+ renderHTML: (attributes) => attributes[key] ? { [htmlName]: attributes[key] } : {},
23
+ },
24
+ });
25
+ /**
26
+ * Keeps inline styles and legacy layout attributes (common in email signatures)
27
+ * on blocks and tables, which the default schema drops
28
+ */
29
+ export const PreservedHtmlAttributes = Extension.create({
30
+ name: 'preservedHtmlAttributes',
31
+ addGlobalAttributes() {
32
+ return [
33
+ {
34
+ types: [
35
+ 'paragraph',
36
+ 'heading',
37
+ 'blockquote',
38
+ 'bulletList',
39
+ 'orderedList',
40
+ 'listItem',
41
+ 'table',
42
+ 'tableRow',
43
+ 'tableCell',
44
+ 'tableHeader',
45
+ ],
46
+ attributes: preserveAttribute('htmlStyle', 'style'),
47
+ },
48
+ {
49
+ types: ['table'],
50
+ attributes: {
51
+ ...preserveAttribute('htmlWidth', 'width'),
52
+ ...preserveAttribute('htmlAlign', 'align'),
53
+ ...preserveAttribute('htmlBorder', 'border'),
54
+ ...preserveAttribute('htmlCellPadding', 'cellpadding'),
55
+ ...preserveAttribute('htmlCellSpacing', 'cellspacing'),
56
+ ...preserveAttribute('htmlBgColor', 'bgcolor'),
57
+ },
58
+ },
59
+ {
60
+ // `align` is already handled by the table cell extensions
61
+ types: ['tableCell', 'tableHeader'],
62
+ attributes: {
63
+ ...preserveAttribute('htmlWidth', 'width'),
64
+ ...preserveAttribute('htmlVAlign', 'valign'),
65
+ ...preserveAttribute('htmlBgColor', 'bgcolor'),
66
+ },
67
+ },
68
+ ];
69
+ },
70
+ });
71
+ /**
72
+ * Inline image (so it can sit in a line of text or inside a link) that keeps its inline style
73
+ */
74
+ export const InlineImage = Image.extend({
75
+ addAttributes() {
76
+ return {
77
+ ...this.parent?.(),
78
+ ...preserveAttribute('style', 'style'),
79
+ };
80
+ },
81
+ });
82
+ const convertFontTags = (doc) => {
83
+ doc.querySelectorAll('font').forEach((font) => {
84
+ const span = doc.createElement('span');
85
+ const color = font.getAttribute('color');
86
+ const face = font.getAttribute('face');
87
+ const size = FONT_TAG_SIZES[Number(font.getAttribute('size'))];
88
+ if (color)
89
+ span.style.color = color;
90
+ if (face)
91
+ span.style.fontFamily = face;
92
+ if (size)
93
+ span.style.fontSize = size;
94
+ if (font.getAttribute('style')) {
95
+ span.style.cssText += font.getAttribute('style');
96
+ }
97
+ span.append(...Array.from(font.childNodes));
98
+ font.replaceWith(span);
99
+ });
100
+ };
101
+ // Divs holding only inline content are lines (Gmail writes one per line):
102
+ // keep them as paragraphs without the editor's paragraph spacing
103
+ const convertLineDivs = (doc) => {
104
+ Array.from(doc.querySelectorAll('div'))
105
+ .reverse()
106
+ .forEach((div) => {
107
+ if (Array.from(div.children).some((child) => child.matches(BLOCK_SELECTOR))) {
108
+ return;
109
+ }
110
+ const paragraph = doc.createElement('p');
111
+ Array.from(div.attributes).forEach(({ name, value }) => paragraph.setAttribute(name, value));
112
+ paragraph.style.cssText = `margin: 0; ${div.style.cssText}`;
113
+ paragraph.append(...Array.from(div.childNodes));
114
+ div.replaceWith(paragraph);
115
+ });
116
+ };
117
+ const inlineInheritedStyles = (doc) => {
118
+ const walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT);
119
+ const textNodes = [];
120
+ while (walker.nextNode()) {
121
+ const node = walker.currentNode;
122
+ if (node.data.trim())
123
+ textNodes.push(node);
124
+ }
125
+ textNodes.forEach((text) => {
126
+ const styles = [];
127
+ const found = new Set();
128
+ // Nearest ancestor wins, as in CSS inheritance
129
+ for (let element = text.parentElement; element && element !== doc.body; element = element.parentElement) {
130
+ INHERITED_STYLES.forEach((property) => {
131
+ const value = element.style.getPropertyValue(property);
132
+ if (value && !found.has(property)) {
133
+ found.add(property);
134
+ styles.push(`${property}: ${value}`);
135
+ }
136
+ });
137
+ }
138
+ if (!styles.length)
139
+ return;
140
+ const span = doc.createElement('span');
141
+ span.setAttribute('style', styles.join('; '));
142
+ text.replaceWith(span);
143
+ span.append(text);
144
+ });
145
+ };
146
+ /**
147
+ * Prepares pasted HTML (e.g. a copied email signature) so it keeps its look:
148
+ * converts `<font>` tags and line divs, copies inherited text styles onto the
149
+ * text, and drops images the browser can't load (`file:`, `cid:`, `blob:`).
150
+ * All images are dropped when `keepImages` is false
151
+ */
152
+ export const normalizePastedHtml = (html, keepImages) => {
153
+ const doc = new DOMParser().parseFromString(html, 'text/html');
154
+ doc.querySelectorAll('img').forEach((image) => {
155
+ if (!keepImages || !SAFE_IMAGE_URL_REGEX.test(image.getAttribute('src') ?? '')) {
156
+ image.remove();
157
+ }
158
+ });
159
+ if (!keepImages)
160
+ doc.querySelectorAll('picture').forEach((node) => node.remove());
161
+ convertFontTags(doc);
162
+ convertLineDivs(doc);
163
+ inlineInheritedStyles(doc);
164
+ return doc.body.innerHTML;
165
+ };
166
+ export const hasHtmlText = (html) => !!new DOMParser().parseFromString(html, 'text/html').body.textContent?.trim();
167
+ //# sourceMappingURL=pasteFormatting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pasteFormatting.js","sourceRoot":"","sources":["../../../src/components/RichTextEditor/pasteFormatting.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,167 @@
1
+ export type RichTextToolbarOption = 'bold' | 'italic' | 'underline' | 'strike' | 'heading1' | 'heading2' | 'heading3' | 'bulletList' | 'orderedList' | 'blockquote' | 'code' | 'codeBlock' | 'link' | 'image' | 'attachment' | 'undo' | 'redo' | 'clear';
2
+ /**
3
+ * Uploads an image and resolves with its http(s) URL
4
+ */
5
+ export type RichTextImageUpload = (file: File) => Promise<string>;
6
+ /**
7
+ * Uploads an attached file and resolves with its http(s) URL
8
+ */
9
+ export type RichTextFileUpload = (file: File) => Promise<string>;
10
+ /**
11
+ * Why an attached file was not inserted:
12
+ * - `'type'`: it doesn't match `fileAttachmentAccept`
13
+ * - `'size'`: it is larger than `maxFileSize`
14
+ * - `'upload'`: the upload failed or resolved with an unsafe URL
15
+ */
16
+ export type RichTextFileAttachmentError = 'type' | 'size' | 'upload';
17
+ /**
18
+ * Format of the editor `value` and of the content passed to `onChange`, `onFocus` and `onBlur`
19
+ */
20
+ export type RichTextOutputFormat = 'html' | 'text';
21
+ export interface RichTextDynamicValue {
22
+ /**
23
+ * Text shown in the suggestion list
24
+ */
25
+ label: string;
26
+ /**
27
+ * Identifier stored on the token as `data-id` and shown as `{{value}}`
28
+ */
29
+ value: string;
30
+ }
31
+ export interface RichTextEditorProps {
32
+ /**
33
+ * Content of the editor, in the format set by `outputFormat`
34
+ */
35
+ value?: string;
36
+ /**
37
+ * Format of `value` and of the content passed to `onChange`, `onFocus` and `onBlur`.
38
+ * - `'html'`: the editor HTML, with formatting
39
+ * - `'text'`: plain text, one line per block. Formatting, links and images are
40
+ * dropped and dynamic values are written as `{{value}}`
41
+ * @default 'html'
42
+ */
43
+ outputFormat?: RichTextOutputFormat;
44
+ /**
45
+ * Called with the editor content (see `outputFormat`) and its text character count
46
+ * whenever the content changes
47
+ */
48
+ onChange?: (value: string, charCount: number) => void;
49
+ /**
50
+ * Called with the text character count on mount and whenever it changes
51
+ * (including external `value` updates). Use it to run min/max length
52
+ * validation in the parent form and pass the result back via `error`/`helperText`
53
+ */
54
+ onCharCountChange?: (charCount: number) => void;
55
+ /**
56
+ * Label shown above the editor
57
+ */
58
+ label?: string;
59
+ /**
60
+ * Shows a required asterisk next to the label
61
+ */
62
+ required?: boolean;
63
+ /**
64
+ * Placeholder shown when the editor is empty
65
+ */
66
+ placeholder?: string;
67
+ /**
68
+ * Makes the editor non-editable and hides the toolbar
69
+ */
70
+ readOnly?: boolean;
71
+ /**
72
+ * Hides the toolbar while keeping the editor editable
73
+ */
74
+ toolbarHidden?: boolean;
75
+ /**
76
+ * Toolbar buttons to show, in order. Defaults to all options
77
+ */
78
+ toolbarOptions?: RichTextToolbarOption[];
79
+ /**
80
+ * Values offered when the user types `dynamicValueTrigger`. Picking one inserts it
81
+ * as a token: `<span data-type="dynamicValue" data-id="{value}" data-label="{label}">`.
82
+ * The feature is disabled (typing the trigger does nothing) when this is empty or omitted
83
+ */
84
+ dynamicValues?: RichTextDynamicValue[];
85
+ /**
86
+ * Called with the dynamic values present in the content (document order, no duplicates)
87
+ * on mount and whenever they change, including external `value` updates
88
+ */
89
+ onDynamicValuesChange?: (dynamicValues: RichTextDynamicValue[]) => void;
90
+ /**
91
+ * Character that opens the dynamic value list
92
+ * @default '<'
93
+ */
94
+ dynamicValueTrigger?: string;
95
+ /**
96
+ * Enables inserting images via the toolbar `image` button, paste and drop.
97
+ * When false, the `image` toolbar option is hidden and pasted/dropped images are ignored
98
+ * @default false
99
+ */
100
+ allowImageUpload?: boolean;
101
+ /**
102
+ * Uploads images picked, pasted or dropped into the editor and resolves with their URL.
103
+ * When omitted, images are embedded in the HTML as base64 data URLs
104
+ */
105
+ onImageUpload?: RichTextImageUpload;
106
+ /**
107
+ * Enables attaching local files via the toolbar `attachment` button, and via
108
+ * paste and drop for files that aren't inserted as images. Each file is inserted
109
+ * as a download chip:
110
+ * `<a data-type="fileAttachment" href="{url}" data-name="{name}" data-size="{bytes}" download>`.
111
+ * When false, the `attachment` toolbar option is hidden
112
+ * @default false
113
+ */
114
+ allowFileAttachment?: boolean;
115
+ /**
116
+ * Uploads attached files and resolves with their URL. When omitted, files are
117
+ * embedded in the HTML as base64 data URLs, which only works for images
118
+ */
119
+ onFileUpload?: RichTextFileUpload;
120
+ /**
121
+ * File types that can be attached, in `accept` attribute syntax
122
+ * (e.g. `'image/*'`, `'.pdf,.docx'`)
123
+ * @default 'image/*'
124
+ */
125
+ fileAttachmentAccept?: string;
126
+ /**
127
+ * Maximum size of an attached file, in bytes
128
+ */
129
+ maxFileSize?: number;
130
+ /**
131
+ * Called for each attached file that was not inserted, with the reason
132
+ */
133
+ onFileAttachmentError?: (file: File, reason: RichTextFileAttachmentError) => void;
134
+ /**
135
+ * Applies error styling
136
+ */
137
+ error?: boolean;
138
+ /**
139
+ * Text shown below the editor (error message when `error` is true)
140
+ */
141
+ helperText?: string;
142
+ /**
143
+ * Minimum height of the editable area
144
+ */
145
+ minHeight?: number | string;
146
+ /**
147
+ * Maximum height of the editable area, scrolls beyond this
148
+ */
149
+ maxHeight?: number | string;
150
+ /**
151
+ * Minimum number of text characters. Shows an error after blur when the
152
+ * content is non-empty but shorter than this
153
+ */
154
+ minLength?: number;
155
+ /**
156
+ * Maximum number of text characters. Input beyond this is blocked and a
157
+ * `count/maxLength` counter is shown below the editor
158
+ */
159
+ maxLength?: number;
160
+ /**
161
+ * Focuses the editor on mount
162
+ */
163
+ autoFocus?: boolean;
164
+ onFocus?: (value: string) => void;
165
+ onBlur?: (value: string) => void;
166
+ className?: string;
167
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/components/RichTextEditor/types.ts"],"names":[],"mappings":""}