@truedat/core 8.5.3 → 8.5.4
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/package.json +3 -9
- package/src/components/Markdown.js +0 -2
- package/src/components/TemplateSelector.js +3 -3
- package/src/components/UploadJobParser.js +0 -4
- package/src/components/index.js +0 -2
- package/src/services/__tests__/i18nContent.spec.js +2 -3
- package/src/services/format.js +0 -22
- package/src/services/i18nContent.js +6 -10
- package/src/components/RichTextEditor.js +0 -365
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/core",
|
|
3
|
-
"version": "8.5.
|
|
3
|
+
"version": "8.5.4",
|
|
4
4
|
"description": "Truedat Web Core",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@testing-library/jest-dom": "^6.6.3",
|
|
55
55
|
"@testing-library/react": "^16.3.0",
|
|
56
56
|
"@testing-library/user-event": "^14.6.1",
|
|
57
|
-
"@truedat/test": "8.5.
|
|
57
|
+
"@truedat/test": "8.5.4",
|
|
58
58
|
"identity-obj-proxy": "^3.0.0",
|
|
59
59
|
"jest": "^29.7.0",
|
|
60
60
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -64,7 +64,6 @@
|
|
|
64
64
|
"@tiptap/core": "^3.20.0",
|
|
65
65
|
"@tiptap/extension-heading": "^3.20.0",
|
|
66
66
|
"@tiptap/extension-link": "^3.20.0",
|
|
67
|
-
"@tiptap/extension-underline": "^3.22.4",
|
|
68
67
|
"@tiptap/pm": "^3.20.0",
|
|
69
68
|
"@tiptap/react": "^3.20.0",
|
|
70
69
|
"@tiptap/starter-kit": "^3.20.0",
|
|
@@ -73,9 +72,6 @@
|
|
|
73
72
|
"dompurify": "^3.3.3",
|
|
74
73
|
"elkjs": "^0.10.0",
|
|
75
74
|
"graphql": "^16.11.0",
|
|
76
|
-
"immutable": "^4.3.7",
|
|
77
|
-
"is-hotkey": "^0.2.0",
|
|
78
|
-
"is-url": "^1.2.4",
|
|
79
75
|
"lodash": "^4.17.21",
|
|
80
76
|
"marked": "^17.0.3",
|
|
81
77
|
"moment": "^2.30.1",
|
|
@@ -96,10 +92,8 @@
|
|
|
96
92
|
"redux-saga-routines": "^3.2.3",
|
|
97
93
|
"reselect": "^5.1.1",
|
|
98
94
|
"semantic-ui-react": "^3.0.0-beta.2",
|
|
99
|
-
"slate": "^0.47.9",
|
|
100
|
-
"slate-react": "^0.22.10",
|
|
101
95
|
"swr": "^2.3.3",
|
|
102
96
|
"turndown": "^7.2.2"
|
|
103
97
|
},
|
|
104
|
-
"gitHead": "
|
|
98
|
+
"gitHead": "75272567eb3ec948a5cdeb8346ef9cacac58267f"
|
|
105
99
|
}
|
|
@@ -5,7 +5,6 @@ import { useEditor, EditorContent } from "@tiptap/react";
|
|
|
5
5
|
import StarterKit from "@tiptap/starter-kit";
|
|
6
6
|
import Link from "@tiptap/extension-link";
|
|
7
7
|
import Heading from "@tiptap/extension-heading";
|
|
8
|
-
import Underline from "@tiptap/extension-underline";
|
|
9
8
|
import { Menu, Icon } from "semantic-ui-react";
|
|
10
9
|
import { FormattedMessage } from "react-intl";
|
|
11
10
|
import { marked } from "marked";
|
|
@@ -34,7 +33,6 @@ const extensions = [
|
|
|
34
33
|
target: "_blank",
|
|
35
34
|
},
|
|
36
35
|
}),
|
|
37
|
-
Underline,
|
|
38
36
|
];
|
|
39
37
|
|
|
40
38
|
const validateUrl = (value, allowEmpty = false) => {
|
|
@@ -13,7 +13,7 @@ const makeOptions = (formatMessage) =>
|
|
|
13
13
|
value,
|
|
14
14
|
text: formatMessage({ id: `templates.${label}`, defaultMessage: label }),
|
|
15
15
|
})),
|
|
16
|
-
_.sortBy(accentInsensitivePathOrder("text"))
|
|
16
|
+
_.sortBy(accentInsensitivePathOrder("text")),
|
|
17
17
|
);
|
|
18
18
|
|
|
19
19
|
export const TemplateSelector = ({
|
|
@@ -65,8 +65,8 @@ export const TemplateSelector = ({
|
|
|
65
65
|
placeholder
|
|
66
66
|
? placeholder
|
|
67
67
|
: formatMessage({
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
id: loading ? "loading" : "template.selector.placeholder",
|
|
69
|
+
})
|
|
70
70
|
}
|
|
71
71
|
search
|
|
72
72
|
selection
|
|
@@ -2,8 +2,6 @@ import _ from "lodash/fp";
|
|
|
2
2
|
import { useState } from "react";
|
|
3
3
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
4
4
|
import { Label } from "semantic-ui-react";
|
|
5
|
-
import { RichTextEditor } from "@truedat/core/components";
|
|
6
|
-
|
|
7
5
|
import RuleImplementationLink from "@truedat/dq/components/RuleImplementationLink";
|
|
8
6
|
import StructureNoteLink from "@truedat/dd/components/StructureNoteLink";
|
|
9
7
|
|
|
@@ -395,8 +393,6 @@ const formatValue = (value, key) => {
|
|
|
395
393
|
)(value);
|
|
396
394
|
}
|
|
397
395
|
if (_.isObject(value)) {
|
|
398
|
-
if (_.has("document")(value))
|
|
399
|
-
return <RichTextEditor readOnly value={value} />;
|
|
400
396
|
if (_.has("url_value")(value))
|
|
401
397
|
return `[${value.url_name}] (${value.url_value})`;
|
|
402
398
|
if (_.has("name")(value)) return value.name;
|
package/src/components/index.js
CHANGED
|
@@ -42,7 +42,6 @@ import OriginLabel from "./OriginLabel";
|
|
|
42
42
|
import Pagination from "./Pagination";
|
|
43
43
|
import QualityMenu from "./QualityMenu";
|
|
44
44
|
import Redirector from "./Redirector";
|
|
45
|
-
import RichTextEditor from "./RichTextEditor";
|
|
46
45
|
import RouteListener from "./RouteListener";
|
|
47
46
|
import SafeLink from "./SafeLink";
|
|
48
47
|
import ScrollToTop from "./ScrollToTop";
|
|
@@ -107,7 +106,6 @@ export {
|
|
|
107
106
|
Pagination,
|
|
108
107
|
QualityMenu,
|
|
109
108
|
Redirector,
|
|
110
|
-
RichTextEditor,
|
|
111
109
|
RouteListener,
|
|
112
110
|
SafeLink,
|
|
113
111
|
ScrollToTop,
|
|
@@ -13,7 +13,7 @@ describe("services: i18nContent", () => {
|
|
|
13
13
|
{
|
|
14
14
|
fields: [
|
|
15
15
|
{ name: "title", widget: "string" },
|
|
16
|
-
{ name: "description", widget: "
|
|
16
|
+
{ name: "description", widget: "markdown" },
|
|
17
17
|
{ name: "date", widget: "date" },
|
|
18
18
|
{ name: "notes", widget: "textarea" },
|
|
19
19
|
],
|
|
@@ -26,7 +26,7 @@ describe("services: i18nContent", () => {
|
|
|
26
26
|
expect(result).toEqual({
|
|
27
27
|
translatable: {
|
|
28
28
|
title: { value: "", origin: "user" },
|
|
29
|
-
description: { value:
|
|
29
|
+
description: { value: "", origin: "user" },
|
|
30
30
|
notes: { value: null, origin: "user" },
|
|
31
31
|
},
|
|
32
32
|
noTranslatable: {
|
|
@@ -151,7 +151,6 @@ describe("services: i18nContent", () => {
|
|
|
151
151
|
describe("isTranslatableField", () => {
|
|
152
152
|
it("should identify translatable fields", () => {
|
|
153
153
|
expect(isTranslatableField({ widget: "string" })).toBe(true);
|
|
154
|
-
expect(isTranslatableField({ widget: "enriched_text" })).toBe(true);
|
|
155
154
|
expect(isTranslatableField({ widget: "markdown" })).toBe(true);
|
|
156
155
|
expect(isTranslatableField({ widget: "textarea" })).toBe(true);
|
|
157
156
|
});
|
package/src/services/format.js
CHANGED
|
@@ -1,23 +1 @@
|
|
|
1
1
|
export const formatNumber = (value) => value?.toLocaleString();
|
|
2
|
-
|
|
3
|
-
export const toEnrichedTextFormat = (value) => ({
|
|
4
|
-
object: "value",
|
|
5
|
-
document: {
|
|
6
|
-
object: "document",
|
|
7
|
-
data: {},
|
|
8
|
-
nodes: [
|
|
9
|
-
{
|
|
10
|
-
object: "block",
|
|
11
|
-
type: "paragraph",
|
|
12
|
-
data: {},
|
|
13
|
-
nodes: [
|
|
14
|
-
{
|
|
15
|
-
object: "text",
|
|
16
|
-
text: value,
|
|
17
|
-
marks: [],
|
|
18
|
-
},
|
|
19
|
-
],
|
|
20
|
-
},
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
|
|
3
|
-
const translatableFieldWidgets = ["
|
|
3
|
+
const translatableFieldWidgets = ["markdown", "string", "textarea"];
|
|
4
4
|
|
|
5
5
|
export const splitTranslatableFields = (template) =>
|
|
6
6
|
_.flow(
|
|
@@ -17,10 +17,6 @@ export const splitTranslatableFields = (template) =>
|
|
|
17
17
|
[translatableKey]: {
|
|
18
18
|
...acc[translatableKey],
|
|
19
19
|
[name]: _.cond([
|
|
20
|
-
[
|
|
21
|
-
(w) => w == "enriched_text",
|
|
22
|
-
_.constant({ value: {}, origin: "user" }),
|
|
23
|
-
],
|
|
24
20
|
[
|
|
25
21
|
(w) => w == "markdown",
|
|
26
22
|
_.constant({ value: "", origin: "user" }),
|
|
@@ -34,8 +30,8 @@ export const splitTranslatableFields = (template) =>
|
|
|
34
30
|
},
|
|
35
31
|
};
|
|
36
32
|
},
|
|
37
|
-
{ translatable: {}, noTranslatable: {} }
|
|
38
|
-
)(group.fields)
|
|
33
|
+
{ translatable: {}, noTranslatable: {} },
|
|
34
|
+
)(group.fields),
|
|
39
35
|
),
|
|
40
36
|
_.reduce(
|
|
41
37
|
(acc, { translatable, noTranslatable }) => {
|
|
@@ -44,8 +40,8 @@ export const splitTranslatableFields = (template) =>
|
|
|
44
40
|
noTranslatable: { ...acc.noTranslatable, ...noTranslatable },
|
|
45
41
|
};
|
|
46
42
|
},
|
|
47
|
-
{ translatable: {}, noTranslatable: {} }
|
|
48
|
-
)
|
|
43
|
+
{ translatable: {}, noTranslatable: {} },
|
|
44
|
+
),
|
|
49
45
|
)(template);
|
|
50
46
|
|
|
51
47
|
export const formatLocales = (locales) =>
|
|
@@ -69,7 +65,7 @@ export const formatLocales = (locales) =>
|
|
|
69
65
|
|
|
70
66
|
export const hasTranslatableFields = (fields) => {
|
|
71
67
|
return _.some((field) => translatableFieldWidgets.includes(field.widget))(
|
|
72
|
-
fields
|
|
68
|
+
fields,
|
|
73
69
|
);
|
|
74
70
|
};
|
|
75
71
|
|
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
import _ from "lodash/fp";
|
|
2
|
-
import { useState, useEffect } from "react";
|
|
3
|
-
import PropTypes from "prop-types";
|
|
4
|
-
import { isKeyHotkey } from "is-hotkey";
|
|
5
|
-
import isUrl from "is-url";
|
|
6
|
-
import { Editor, getEventTransfer } from "slate-react";
|
|
7
|
-
import { Value } from "slate";
|
|
8
|
-
import { Menu, Icon } from "semantic-ui-react";
|
|
9
|
-
import { validUrl } from "../services/validation";
|
|
10
|
-
import SafeLink from "./SafeLink";
|
|
11
|
-
|
|
12
|
-
const DEFAULT_NODE = "paragraph";
|
|
13
|
-
|
|
14
|
-
function wrapLink(change, value) {
|
|
15
|
-
const href = validUrl(value);
|
|
16
|
-
if (href) {
|
|
17
|
-
change.wrapInline({
|
|
18
|
-
type: "link",
|
|
19
|
-
data: { href },
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
change.moveToEnd();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function unwrapLink(change) {
|
|
27
|
-
change.unwrapInline("link");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function renderBlock(props, _editor, next) {
|
|
31
|
-
const { attributes, children, node } = props;
|
|
32
|
-
|
|
33
|
-
switch (node.type) {
|
|
34
|
-
// case 'block-quote':
|
|
35
|
-
// return <blockquote {...attributes}>{children}</blockquote>
|
|
36
|
-
case "bulleted-list":
|
|
37
|
-
return <ul {...attributes}>{children}</ul>;
|
|
38
|
-
case "heading-one":
|
|
39
|
-
return (
|
|
40
|
-
<h1 style={{ fontSize: "18px" }} {...attributes}>
|
|
41
|
-
{children}
|
|
42
|
-
</h1>
|
|
43
|
-
);
|
|
44
|
-
case "heading-two":
|
|
45
|
-
return (
|
|
46
|
-
<h2 style={{ fontSize: "15px" }} {...attributes}>
|
|
47
|
-
{children}
|
|
48
|
-
</h2>
|
|
49
|
-
);
|
|
50
|
-
case "list-item":
|
|
51
|
-
return <li {...attributes}>{children}</li>;
|
|
52
|
-
case "numbered-list":
|
|
53
|
-
return <ol {...attributes}>{children}</ol>;
|
|
54
|
-
case "link":
|
|
55
|
-
return (
|
|
56
|
-
<SafeLink href={node.data?.get("href")} {...attributes}>
|
|
57
|
-
{children}
|
|
58
|
-
</SafeLink>
|
|
59
|
-
);
|
|
60
|
-
default:
|
|
61
|
-
return next();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function renderMark(props, _editor, next) {
|
|
66
|
-
const { children, mark, attributes } = props;
|
|
67
|
-
|
|
68
|
-
switch (mark.type) {
|
|
69
|
-
case "bold":
|
|
70
|
-
return <strong {...attributes}>{children}</strong>;
|
|
71
|
-
// case 'code':
|
|
72
|
-
// return <code {...attributes}>{children}</code>
|
|
73
|
-
case "italic":
|
|
74
|
-
return <em {...attributes}>{children}</em>;
|
|
75
|
-
case "underlined":
|
|
76
|
-
return <u {...attributes}>{children}</u>;
|
|
77
|
-
default:
|
|
78
|
-
return next();
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function renderInline(props, _editor, next) {
|
|
83
|
-
const { attributes, children, node } = props;
|
|
84
|
-
|
|
85
|
-
switch (node.type) {
|
|
86
|
-
case "link": {
|
|
87
|
-
const props = _.omit(["ref"])(attributes);
|
|
88
|
-
return (
|
|
89
|
-
<SafeLink href={node.data?.get("href")} {...props}>
|
|
90
|
-
{children}
|
|
91
|
-
</SafeLink>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
default:
|
|
96
|
-
return next();
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function onKeyDown(event, editor, next) {
|
|
101
|
-
const isBoldHotkey = isKeyHotkey("mod+b");
|
|
102
|
-
const isItalicHotkey = isKeyHotkey("mod+i");
|
|
103
|
-
const isUnderlinedHotkey = isKeyHotkey("mod+u");
|
|
104
|
-
const mark = isBoldHotkey(event)
|
|
105
|
-
? "bold"
|
|
106
|
-
: isItalicHotkey(event)
|
|
107
|
-
? "italic"
|
|
108
|
-
: isUnderlinedHotkey(event)
|
|
109
|
-
? "underlined"
|
|
110
|
-
: undefined;
|
|
111
|
-
if (!_.isNil(mark)) {
|
|
112
|
-
event.preventDefault();
|
|
113
|
-
editor.toggleMark(mark);
|
|
114
|
-
return true;
|
|
115
|
-
} else {
|
|
116
|
-
next();
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const EMPTY_VALUE = {
|
|
121
|
-
document: {
|
|
122
|
-
nodes: [
|
|
123
|
-
{
|
|
124
|
-
object: "block",
|
|
125
|
-
type: "paragraph",
|
|
126
|
-
nodes: [],
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export const RichTextEditor = ({
|
|
133
|
-
readOnly,
|
|
134
|
-
value: propValue,
|
|
135
|
-
label,
|
|
136
|
-
required,
|
|
137
|
-
onChange,
|
|
138
|
-
name,
|
|
139
|
-
}) => {
|
|
140
|
-
const [jsonValue, setJsonValue] = useState(
|
|
141
|
-
_.isEmpty(propValue) ? EMPTY_VALUE : propValue
|
|
142
|
-
);
|
|
143
|
-
const [value, setValue] = useState(Value.fromJSON(jsonValue));
|
|
144
|
-
const [editor, setEditor] = useState();
|
|
145
|
-
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
if (
|
|
148
|
-
(!_.isEmpty(propValue) && !_.equals(propValue)(jsonValue)) ||
|
|
149
|
-
(readOnly && !_.equals(value)(Value.fromJSON(propValue)))
|
|
150
|
-
) {
|
|
151
|
-
setValue(Value.fromJSON(propValue));
|
|
152
|
-
}
|
|
153
|
-
}, [propValue]);
|
|
154
|
-
|
|
155
|
-
const renderMarkButton = (type, icon) => {
|
|
156
|
-
const isActive = value?.activeMarks.some((mark) => mark.type == type);
|
|
157
|
-
|
|
158
|
-
return (
|
|
159
|
-
<Menu.Item
|
|
160
|
-
icon
|
|
161
|
-
active={isActive}
|
|
162
|
-
onMouseDown={(e) => {
|
|
163
|
-
e.preventDefault();
|
|
164
|
-
editor?.toggleMark(type);
|
|
165
|
-
}}
|
|
166
|
-
onClick={() => {}}
|
|
167
|
-
>
|
|
168
|
-
<Icon name={icon} />
|
|
169
|
-
</Menu.Item>
|
|
170
|
-
);
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
const hasBlock = (type) => value?.blocks.some((node) => node.type == type);
|
|
174
|
-
|
|
175
|
-
const onClickBlock = (type) => {
|
|
176
|
-
const { value } = editor || {};
|
|
177
|
-
const { document } = value || {};
|
|
178
|
-
|
|
179
|
-
if (type != "bulleted-list" && type != "numbered-list") {
|
|
180
|
-
const isActive = hasBlock(type);
|
|
181
|
-
const isList = hasBlock("list-item");
|
|
182
|
-
|
|
183
|
-
if (isList) {
|
|
184
|
-
editor
|
|
185
|
-
.setBlocks(isActive ? DEFAULT_NODE : type)
|
|
186
|
-
.unwrapBlock("bulleted-list")
|
|
187
|
-
.unwrapBlock("numbered-list");
|
|
188
|
-
} else {
|
|
189
|
-
editor.setBlocks(isActive ? DEFAULT_NODE : type);
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
const isList = hasBlock("list-item");
|
|
193
|
-
const isType = value?.blocks.some((block) => {
|
|
194
|
-
return !!document?.getClosest(
|
|
195
|
-
block.key,
|
|
196
|
-
(parent) => parent.type == type
|
|
197
|
-
);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
if (isList && isType) {
|
|
201
|
-
editor
|
|
202
|
-
.setBlocks(DEFAULT_NODE)
|
|
203
|
-
.unwrapBlock("bulleted-list")
|
|
204
|
-
.unwrapBlock("numbered-list");
|
|
205
|
-
} else if (isList) {
|
|
206
|
-
editor
|
|
207
|
-
.unwrapBlock(
|
|
208
|
-
type == "bulleted-list" ? "numbered-list" : "bulleted-list"
|
|
209
|
-
)
|
|
210
|
-
.wrapBlock(type);
|
|
211
|
-
} else {
|
|
212
|
-
editor.setBlocks("list-item").wrapBlock(type);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
const renderBlockButton = (type, icon) => {
|
|
218
|
-
const { document, blocks } = value || {};
|
|
219
|
-
const parent =
|
|
220
|
-
blocks?.size != 0 ? document?.getParent(blocks?.first().key) : null;
|
|
221
|
-
const isActive = _.includes(type)(["numbered-list", "bulleted-list"])
|
|
222
|
-
? hasBlock("list-item") && parent && parent?.type === type
|
|
223
|
-
: hasBlock(type);
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<Menu.Item
|
|
227
|
-
icon
|
|
228
|
-
active={isActive}
|
|
229
|
-
onMouseDown={(e) => {
|
|
230
|
-
e.preventDefault();
|
|
231
|
-
onClickBlock(type);
|
|
232
|
-
}}
|
|
233
|
-
onClick={() => {}}
|
|
234
|
-
>
|
|
235
|
-
<Icon name={icon} />
|
|
236
|
-
</Menu.Item>
|
|
237
|
-
);
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
const hasLinks = () => value?.inlines.some((inline) => inline.type == "link");
|
|
241
|
-
|
|
242
|
-
const onClickLink = () => {
|
|
243
|
-
const { value } = editor || {};
|
|
244
|
-
|
|
245
|
-
if (hasLinks()) {
|
|
246
|
-
editor.command(unwrapLink);
|
|
247
|
-
} else if (value?.selection.isExpanded) {
|
|
248
|
-
const href = window.prompt("Introduzca la URL del Link:");
|
|
249
|
-
editor.command(wrapLink, href);
|
|
250
|
-
} else {
|
|
251
|
-
const href = window.prompt("Introduzca la URL del Link:");
|
|
252
|
-
const text = window.prompt("Introduzca el Texto del Link:");
|
|
253
|
-
editor
|
|
254
|
-
.insertText(text)
|
|
255
|
-
.moveFocusForward(0 - text.length)
|
|
256
|
-
.command(wrapLink, href);
|
|
257
|
-
}
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
const renderLinkButton = (icon) => {
|
|
261
|
-
const isActive = hasLinks();
|
|
262
|
-
|
|
263
|
-
return (
|
|
264
|
-
<Menu.Item
|
|
265
|
-
icon
|
|
266
|
-
active={isActive}
|
|
267
|
-
onMouseDown={(e) => {
|
|
268
|
-
e.preventDefault();
|
|
269
|
-
onClickLink();
|
|
270
|
-
}}
|
|
271
|
-
onClick={() => {}}
|
|
272
|
-
>
|
|
273
|
-
<Icon name={icon} />
|
|
274
|
-
</Menu.Item>
|
|
275
|
-
);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
const handleChange = ({ value }) => {
|
|
279
|
-
const { text } = value?.document || {};
|
|
280
|
-
const json = text ? value?.toJSON() : {};
|
|
281
|
-
setJsonValue(json);
|
|
282
|
-
setValue(value);
|
|
283
|
-
if (onChange) {
|
|
284
|
-
onChange(undefined, { name, value: json });
|
|
285
|
-
}
|
|
286
|
-
};
|
|
287
|
-
|
|
288
|
-
const onPaste = (event, editor, next) => {
|
|
289
|
-
if (editor?.value?.selection?.isCollapsed) return next();
|
|
290
|
-
|
|
291
|
-
const transfer = getEventTransfer(event);
|
|
292
|
-
const { type, text } = transfer;
|
|
293
|
-
if (type !== "text" && type !== "html") return next();
|
|
294
|
-
if (!isUrl(text)) return next();
|
|
295
|
-
|
|
296
|
-
if (hasLinks()) {
|
|
297
|
-
editor.command(unwrapLink);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
editor.command(wrapLink, text);
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
return readOnly ? (
|
|
304
|
-
<Editor
|
|
305
|
-
readOnly
|
|
306
|
-
value={value}
|
|
307
|
-
renderBlock={renderBlock}
|
|
308
|
-
renderMark={renderMark}
|
|
309
|
-
renderInline={renderInline}
|
|
310
|
-
/>
|
|
311
|
-
) : (
|
|
312
|
-
<div>
|
|
313
|
-
{label ? (
|
|
314
|
-
<div className={required ? "required field" : "field"}>
|
|
315
|
-
<label>{label}</label>
|
|
316
|
-
</div>
|
|
317
|
-
) : null}
|
|
318
|
-
<div
|
|
319
|
-
style={{
|
|
320
|
-
border: "1px solid rgba(34, 36, 38, 0.15)",
|
|
321
|
-
borderRadius: "0.28571429rem",
|
|
322
|
-
}}
|
|
323
|
-
>
|
|
324
|
-
<Menu>
|
|
325
|
-
{renderMarkButton("bold", "bold")}
|
|
326
|
-
{renderMarkButton("italic", "italic")}
|
|
327
|
-
{renderMarkButton("underlined", "underline")}
|
|
328
|
-
{/* {renderMarkButton('code', 'file code')} */}
|
|
329
|
-
{renderBlockButton("heading-one", "header")}
|
|
330
|
-
{renderBlockButton("heading-two", "h")}
|
|
331
|
-
{/* {renderBlockButton('block-quote', 'quote right')} */}
|
|
332
|
-
{renderBlockButton("numbered-list", "list ol")}
|
|
333
|
-
{renderBlockButton("bulleted-list", "list ul")}
|
|
334
|
-
{renderLinkButton("linkify")}
|
|
335
|
-
</Menu>
|
|
336
|
-
<div style={{ padding: "10px" }}>
|
|
337
|
-
<Editor
|
|
338
|
-
style={{ WebkitUserModify: "read-write !important" }}
|
|
339
|
-
spellCheck
|
|
340
|
-
autoFocus
|
|
341
|
-
value={value}
|
|
342
|
-
onChange={handleChange}
|
|
343
|
-
onPaste={onPaste}
|
|
344
|
-
onKeyDown={onKeyDown}
|
|
345
|
-
renderBlock={renderBlock}
|
|
346
|
-
renderMark={renderMark}
|
|
347
|
-
renderInline={renderInline}
|
|
348
|
-
ref={setEditor}
|
|
349
|
-
/>
|
|
350
|
-
</div>
|
|
351
|
-
</div>
|
|
352
|
-
</div>
|
|
353
|
-
);
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
RichTextEditor.propTypes = {
|
|
357
|
-
label: PropTypes.string,
|
|
358
|
-
name: PropTypes.string,
|
|
359
|
-
onChange: PropTypes.func,
|
|
360
|
-
readOnly: PropTypes.bool,
|
|
361
|
-
required: PropTypes.bool,
|
|
362
|
-
value: PropTypes.object,
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
export default RichTextEditor;
|