krl-alfred 2.23.13 → 2.23.14
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/dist/components/RichTextEditor/RichTextEditor.js +20 -12
- package/dist/components/RichTextEditor/RichTextEditor.styled.js +1 -1
- package/dist/components/RichTextEditor/RichTextEditor.test.d.ts +1 -0
- package/dist/components/RichTextEditor/RichTextEditor.test.js +250 -0
- package/dist/components/RichTextEditor/props.d.ts +6 -0
- package/dist/components/RichTextEditor/props.js +3 -0
- package/dist/components/RichTextEditor/stories/RichTextEditor.stories.d.ts +47 -0
- package/dist/components/RichTextEditor/stories/RichTextEditor.stories.js +44 -1
- package/dist/components/RichTextEditor/utils/sanitize.d.ts +5 -3
- package/dist/components/RichTextEditor/utils/sanitize.js +38 -10
- package/dist/setupTests.d.ts +1 -0
- package/dist/setupTests.js +3 -0
- package/package.json +8 -1
|
@@ -20,6 +20,8 @@ var react_2 = require("@tiptap/react");
|
|
|
20
20
|
var starter_kit_1 = __importDefault(require("@tiptap/starter-kit"));
|
|
21
21
|
var extension_underline_1 = __importDefault(require("@tiptap/extension-underline"));
|
|
22
22
|
var extension_placeholder_1 = __importDefault(require("@tiptap/extension-placeholder"));
|
|
23
|
+
var extension_table_1 = require("@tiptap/extension-table");
|
|
24
|
+
var simplebar_react_1 = __importDefault(require("simplebar-react"));
|
|
23
25
|
var props_1 = require("./props");
|
|
24
26
|
var RichTextEditor_styled_1 = require("./RichTextEditor.styled");
|
|
25
27
|
var VariableNode_1 = require("./extensions/VariableNode");
|
|
@@ -32,8 +34,8 @@ var StrikeIcon = function () { return ((0, jsx_runtime_1.jsxs)("svg", __assign({
|
|
|
32
34
|
var OrderedListIcon = function () { return ((0, jsx_runtime_1.jsxs)("svg", __assign({ viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true }, { children: [(0, jsx_runtime_1.jsx)("path", { d: "M10 6h10M10 12h10M10 18h10", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }), (0, jsx_runtime_1.jsx)("path", { d: "M4 5.5h1.5V9M4 9h3M4.5 14.5c.8 0 1.5.5 1.5 1.25S5.3 17 4.5 17H4v1.5h3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })] }))); };
|
|
33
35
|
var HeadingIcon = function () { return ((0, jsx_runtime_1.jsx)("svg", __assign({ viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true }, { children: (0, jsx_runtime_1.jsx)("path", { d: "M6 5v14M18 5v14M6 12h12", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }))); };
|
|
34
36
|
var RichTextEditor = (0, react_1.forwardRef)(function (_a, ref) {
|
|
35
|
-
var _b = _a.label, label = _b === void 0 ? props_1.RichTextEditorDefault.label : _b, _c = _a.placeholder, placeholder = _c === void 0 ? props_1.RichTextEditorDefault.placeholder : _c, _d = _a.description, description = _d === void 0 ? props_1.RichTextEditorDefault.description : _d, value = _a.value, _e = _a.defaultValue, defaultValue = _e === void 0 ? props_1.RichTextEditorDefault.defaultValue : _e, onChange = _a.onChange, onBlur = _a.onBlur, _f = _a.disabled, disabled = _f === void 0 ? props_1.RichTextEditorDefault.disabled : _f, _g = _a.hasError, hasError = _g === void 0 ? props_1.RichTextEditorDefault.hasError : _g, _h = _a.errorMessage, errorMessage = _h === void 0 ? props_1.RichTextEditorDefault.errorMessage : _h, className = _a.className, id = _a.id, _j = _a.minHeight, minHeight = _j === void 0 ? props_1.RichTextEditorDefault.minHeight : _j;
|
|
36
|
-
var
|
|
37
|
+
var _b = _a.label, label = _b === void 0 ? props_1.RichTextEditorDefault.label : _b, _c = _a.placeholder, placeholder = _c === void 0 ? props_1.RichTextEditorDefault.placeholder : _c, _d = _a.description, description = _d === void 0 ? props_1.RichTextEditorDefault.description : _d, value = _a.value, _e = _a.defaultValue, defaultValue = _e === void 0 ? props_1.RichTextEditorDefault.defaultValue : _e, onChange = _a.onChange, onBlur = _a.onBlur, _f = _a.disabled, disabled = _f === void 0 ? props_1.RichTextEditorDefault.disabled : _f, _g = _a.hasError, hasError = _g === void 0 ? props_1.RichTextEditorDefault.hasError : _g, _h = _a.errorMessage, errorMessage = _h === void 0 ? props_1.RichTextEditorDefault.errorMessage : _h, className = _a.className, id = _a.id, _j = _a.minHeight, minHeight = _j === void 0 ? props_1.RichTextEditorDefault.minHeight : _j, _k = _a.maxHeight, maxHeight = _k === void 0 ? props_1.RichTextEditorDefault.maxHeight : _k, _l = _a.allowedTags, allowedTags = _l === void 0 ? props_1.RichTextEditorDefault.allowedTags : _l;
|
|
38
|
+
var _m = (0, react_1.useState)(false), focused = _m[0], setFocused = _m[1];
|
|
37
39
|
var isControlled = value !== undefined;
|
|
38
40
|
var editor = (0, react_2.useEditor)({
|
|
39
41
|
immediatelyRender: false,
|
|
@@ -48,6 +50,7 @@ var RichTextEditor = (0, react_1.forwardRef)(function (_a, ref) {
|
|
|
48
50
|
horizontalRule: false,
|
|
49
51
|
dropcursor: false,
|
|
50
52
|
gapcursor: false,
|
|
53
|
+
underline: false,
|
|
51
54
|
hardBreak: {
|
|
52
55
|
keepMarks: true,
|
|
53
56
|
},
|
|
@@ -57,18 +60,23 @@ var RichTextEditor = (0, react_1.forwardRef)(function (_a, ref) {
|
|
|
57
60
|
placeholder: placeholder || '',
|
|
58
61
|
}),
|
|
59
62
|
VariableNode_1.VariableNode,
|
|
63
|
+
// Şema tabloyu her zaman anlar; içerikte gerçekten kalıp kalmaması `allowedTags` (sanitize) ile kontrol edilir
|
|
64
|
+
extension_table_1.Table.configure({ resizable: false }),
|
|
65
|
+
extension_table_1.TableRow,
|
|
66
|
+
extension_table_1.TableHeader,
|
|
67
|
+
extension_table_1.TableCell,
|
|
60
68
|
],
|
|
61
|
-
content: (0, sanitize_1.prepareEditorHtml)(isControlled ? (value || '') : defaultValue),
|
|
69
|
+
content: (0, sanitize_1.prepareEditorHtml)(isControlled ? (value || '') : defaultValue, allowedTags),
|
|
62
70
|
editable: !disabled,
|
|
63
71
|
editorProps: {
|
|
64
72
|
attributes: __assign(__assign({}, (id ? { id: id } : {})), { 'aria-invalid': hasError ? 'true' : 'false' }),
|
|
65
73
|
transformPastedHTML: function (html) {
|
|
66
|
-
return (0, sanitize_1.prepareEditorHtml)(html);
|
|
74
|
+
return (0, sanitize_1.prepareEditorHtml)(html, allowedTags);
|
|
67
75
|
},
|
|
68
76
|
},
|
|
69
77
|
onUpdate: function (_a) {
|
|
70
78
|
var currentEditor = _a.editor;
|
|
71
|
-
onChange === null || onChange === void 0 ? void 0 : onChange((0, sanitize_1.serializeEditorHtml)(currentEditor.getHTML()));
|
|
79
|
+
onChange === null || onChange === void 0 ? void 0 : onChange((0, sanitize_1.serializeEditorHtml)(currentEditor.getHTML(), allowedTags));
|
|
72
80
|
},
|
|
73
81
|
onFocus: function () { return setFocused(true); },
|
|
74
82
|
onBlur: function () {
|
|
@@ -84,12 +92,12 @@ var RichTextEditor = (0, react_1.forwardRef)(function (_a, ref) {
|
|
|
84
92
|
(0, react_1.useEffect)(function () {
|
|
85
93
|
if (!editor || !isControlled)
|
|
86
94
|
return;
|
|
87
|
-
var nextHtml = (0, sanitize_1.serializeEditorHtml)(value || '');
|
|
88
|
-
var currentHtml = (0, sanitize_1.serializeEditorHtml)(editor.getHTML());
|
|
95
|
+
var nextHtml = (0, sanitize_1.serializeEditorHtml)(value || '', allowedTags);
|
|
96
|
+
var currentHtml = (0, sanitize_1.serializeEditorHtml)(editor.getHTML(), allowedTags);
|
|
89
97
|
if (nextHtml !== currentHtml) {
|
|
90
|
-
editor.commands.setContent((0, sanitize_1.prepareEditorHtml)(value || ''), { emitUpdate: false });
|
|
98
|
+
editor.commands.setContent((0, sanitize_1.prepareEditorHtml)(value || '', allowedTags), { emitUpdate: false });
|
|
91
99
|
}
|
|
92
|
-
}, [value, isControlled, editor]);
|
|
100
|
+
}, [value, isControlled, editor, allowedTags]);
|
|
93
101
|
(0, react_1.useImperativeHandle)(ref, function () { return ({
|
|
94
102
|
insertVariable: function (variable) {
|
|
95
103
|
if (!editor || disabled)
|
|
@@ -99,7 +107,7 @@ var RichTextEditor = (0, react_1.forwardRef)(function (_a, ref) {
|
|
|
99
107
|
label: variable.label,
|
|
100
108
|
}).run();
|
|
101
109
|
},
|
|
102
|
-
getHTML: function () { return (0, sanitize_1.serializeEditorHtml)((editor === null || editor === void 0 ? void 0 : editor.getHTML()) || ''); },
|
|
110
|
+
getHTML: function () { return (0, sanitize_1.serializeEditorHtml)((editor === null || editor === void 0 ? void 0 : editor.getHTML()) || '', allowedTags); },
|
|
103
111
|
getEditor: function () { return editor; },
|
|
104
112
|
focus: function () {
|
|
105
113
|
editor === null || editor === void 0 ? void 0 : editor.chain().focus().run();
|
|
@@ -107,10 +115,10 @@ var RichTextEditor = (0, react_1.forwardRef)(function (_a, ref) {
|
|
|
107
115
|
clear: function () {
|
|
108
116
|
editor === null || editor === void 0 ? void 0 : editor.commands.clearContent(true);
|
|
109
117
|
},
|
|
110
|
-
}); }, [editor, disabled]);
|
|
118
|
+
}); }, [editor, disabled, allowedTags]);
|
|
111
119
|
if (!editor)
|
|
112
120
|
return null;
|
|
113
|
-
return ((0, jsx_runtime_1.jsxs)(RichTextEditor_styled_1.RichTextEditorRoot, __assign({ className: className }, { children: [label && (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.FieldLabel, __assign({ htmlFor: id }, { children: label })), (0, jsx_runtime_1.jsxs)(RichTextEditor_styled_1.EditorShell, __assign({ "$hasError": hasError, "$disabled": disabled, "$focused": focused && !hasError }, { children: [(0, jsx_runtime_1.jsxs)(RichTextEditor_styled_1.Toolbar, { children: [(0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Kal\u0131n", "$active": editor.isActive('bold'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleBold().run(); } }, { children: (0, jsx_runtime_1.jsx)(BoldIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "\u0130talik", "$active": editor.isActive('italic'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleItalic().run(); } }, { children: (0, jsx_runtime_1.jsx)(ItalicIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Alt\u0131 \u00E7izili", "$active": editor.isActive('underline'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleUnderline().run(); } }, { children: (0, jsx_runtime_1.jsx)(UnderlineIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "\u00DCst\u00FC \u00E7izili", "$active": editor.isActive('strike'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleStrike().run(); } }, { children: (0, jsx_runtime_1.jsx)(StrikeIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarDivider, {}), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Ba\u015Fl\u0131k", "$active": editor.isActive('heading', { level: 2 }), disabled: disabled, onClick: function () { return editor.chain().focus().toggleHeading({ level: 2 }).run(); } }, { children: (0, jsx_runtime_1.jsx)(HeadingIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarDivider, {}), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Numaral\u0131 liste", "$active": editor.isActive('orderedList'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleOrderedList().run(); } }, { children: (0, jsx_runtime_1.jsx)(OrderedListIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Madde i\u015Faretli liste", "$active": editor.isActive('bulletList'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleBulletList().run(); } }, { children: (0, jsx_runtime_1.jsx)(Icon_1.default, { name: "List", width: "1.25rem", height: "1.25rem", color: "currentColor" }) }))] }), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.EditorContentArea, __assign({ "$minHeight": minHeight }, { children: (0, jsx_runtime_1.jsx)(react_2.EditorContent, { editor: editor }) }))] })), description && (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.FieldDescription, { children: description }), hasError && errorMessage && ((0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ErrorMessage, { children: (0, jsx_runtime_1.jsx)("p", { children: errorMessage }) }))] })));
|
|
121
|
+
return ((0, jsx_runtime_1.jsxs)(RichTextEditor_styled_1.RichTextEditorRoot, __assign({ className: className }, { children: [label && (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.FieldLabel, __assign({ htmlFor: id }, { children: label })), (0, jsx_runtime_1.jsxs)(RichTextEditor_styled_1.EditorShell, __assign({ "$hasError": hasError, "$disabled": disabled, "$focused": focused && !hasError }, { children: [(0, jsx_runtime_1.jsxs)(RichTextEditor_styled_1.Toolbar, { children: [(0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Kal\u0131n", "$active": editor.isActive('bold'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleBold().run(); } }, { children: (0, jsx_runtime_1.jsx)(BoldIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "\u0130talik", "$active": editor.isActive('italic'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleItalic().run(); } }, { children: (0, jsx_runtime_1.jsx)(ItalicIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Alt\u0131 \u00E7izili", "$active": editor.isActive('underline'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleUnderline().run(); } }, { children: (0, jsx_runtime_1.jsx)(UnderlineIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "\u00DCst\u00FC \u00E7izili", "$active": editor.isActive('strike'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleStrike().run(); } }, { children: (0, jsx_runtime_1.jsx)(StrikeIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarDivider, {}), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Ba\u015Fl\u0131k", "$active": editor.isActive('heading', { level: 2 }), disabled: disabled, onClick: function () { return editor.chain().focus().toggleHeading({ level: 2 }).run(); } }, { children: (0, jsx_runtime_1.jsx)(HeadingIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarDivider, {}), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Numaral\u0131 liste", "$active": editor.isActive('orderedList'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleOrderedList().run(); } }, { children: (0, jsx_runtime_1.jsx)(OrderedListIcon, {}) })), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ToolbarButton, __assign({ type: "button", "aria-label": "Madde i\u015Faretli liste", "$active": editor.isActive('bulletList'), disabled: disabled, onClick: function () { return editor.chain().focus().toggleBulletList().run(); } }, { children: (0, jsx_runtime_1.jsx)(Icon_1.default, { name: "List", width: "1.25rem", height: "1.25rem", color: "currentColor" }) }))] }), (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.EditorContentArea, __assign({ "$minHeight": minHeight }, { children: maxHeight ? ((0, jsx_runtime_1.jsx)(simplebar_react_1.default, __assign({ style: { maxHeight: maxHeight } }, { children: (0, jsx_runtime_1.jsx)(react_2.EditorContent, { editor: editor }) }))) : ((0, jsx_runtime_1.jsx)(react_2.EditorContent, { editor: editor })) }))] })), description && (0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.FieldDescription, { children: description }), hasError && errorMessage && ((0, jsx_runtime_1.jsx)(RichTextEditor_styled_1.ErrorMessage, { children: (0, jsx_runtime_1.jsx)("p", { children: errorMessage }) }))] })));
|
|
114
122
|
});
|
|
115
123
|
RichTextEditor.displayName = 'RichTextEditor';
|
|
116
124
|
exports.default = RichTextEditor;
|
|
@@ -15,7 +15,7 @@ exports.EditorShell = styled_components_1.default.div(templateObject_3 || (templ
|
|
|
15
15
|
exports.Toolbar = styled_components_1.default.div(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: wrap;\n padding: 0 0 1rem;\n margin: 0 0 1rem;\n border-bottom: 1px solid var(--grey-10);\n"], ["\n display: flex;\n align-items: center;\n gap: 0.5rem;\n flex-wrap: wrap;\n padding: 0 0 1rem;\n margin: 0 0 1rem;\n border-bottom: 1px solid var(--grey-10);\n"])));
|
|
16
16
|
exports.ToolbarButton = styled_components_1.default.button(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n padding: 0;\n border: none;\n border-radius: 0.25rem;\n background: transparent;\n color: ", ";\n font: var(--body-bold-14-17);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease;\n\n &:hover:not(:disabled) {\n background: transparent;\n color: var(--dark);\n }\n\n &:disabled {\n cursor: not-allowed;\n color: var(--dark-opacity-25);\n background: transparent;\n }\n\n svg {\n width: 1.25rem;\n height: 1.25rem;\n }\n"], ["\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1.25rem;\n height: 1.25rem;\n padding: 0;\n border: none;\n border-radius: 0.25rem;\n background: transparent;\n color: ", ";\n font: var(--body-bold-14-17);\n cursor: pointer;\n transition: background-color 0.15s ease, color 0.15s ease;\n\n &:hover:not(:disabled) {\n background: transparent;\n color: var(--dark);\n }\n\n &:disabled {\n cursor: not-allowed;\n color: var(--dark-opacity-25);\n background: transparent;\n }\n\n svg {\n width: 1.25rem;\n height: 1.25rem;\n }\n"])), function (props) { return (props.$active ? 'var(--dark)' : 'var(--grey-50)'); });
|
|
17
17
|
exports.ToolbarDivider = styled_components_1.default.span(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n display: inline-block;\n width: 1px;\n height: 1.25rem;\n margin: 0;\n background: var(--dark-opacity-10);\n"], ["\n display: inline-block;\n width: 1px;\n height: 1.25rem;\n margin: 0;\n background: var(--dark-opacity-10);\n"])));
|
|
18
|
-
exports.EditorContentArea = styled_components_1.default.div(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n .ProseMirror {\n min-height: ", ";\n padding: 0;\n outline: none;\n color: var(--dark);\n font: var(--body-regular-14-17);\n box-sizing: border-box;\n\n p {\n margin: 0 0 0.75rem;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n h2 {\n margin: 0 0 0.75rem;\n color: var(--dark);\n font: var(--headline-semi-bold-18-22);\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n ul,\n ol {\n margin: 0 0 0.75rem;\n padding-left: 1.25rem;\n list-style-position: outside;\n }\n\n ul {\n list-style-type: disc;\n }\n\n ol {\n list-style-type: decimal;\n }\n\n li {\n margin-bottom: 0.25rem;\n display: list-item;\n }\n\n strong {\n font-weight: 700;\n }\n\n em {\n font-style: italic;\n }\n\n u {\n text-decoration: underline;\n }\n\n s {\n text-decoration: line-through;\n }\n\n .rte-variable-node {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n margin: 0 0.125rem;\n user-select: none;\n }\n\n /* getHTML / serialize \u00E7\u0131kt\u0131s\u0131 \u2014 Badges text/secondary ile ayn\u0131 */\n .rte-variable {\n display: inline-flex;\n align-items: center;\n margin: 0 0.125rem;\n padding: 0 8px;\n height: 17px;\n line-height: 17px;\n border-radius: 3px;\n background-color: var(--primary-opacity-10);\n color: var(--primary);\n font: var(--caption-semi-bold-10-12);\n white-space: nowrap;\n vertical-align: middle;\n user-select: none;\n }\n\n p.is-editor-empty:first-child::before {\n content: attr(data-placeholder);\n float: left;\n color: var(--dark-opacity-50);\n pointer-events: none;\n height: 0;\n font: var(--body-regular-14-17);\n }\n }\n"], ["\n .ProseMirror {\n min-height: ", ";\n padding: 0;\n outline: none;\n color: var(--dark);\n font: var(--body-regular-14-17);\n box-sizing: border-box;\n\n p {\n margin: 0 0 0.75rem;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n h2 {\n margin: 0 0 0.75rem;\n color: var(--dark);\n font: var(--headline-semi-bold-18-22);\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n ul,\n ol {\n margin: 0 0 0.75rem;\n padding-left: 1.25rem;\n list-style-position: outside;\n }\n\n ul {\n list-style-type: disc;\n }\n\n ol {\n list-style-type: decimal;\n }\n\n li {\n margin-bottom: 0.25rem;\n display: list-item;\n }\n\n strong {\n font-weight: 700;\n }\n\n em {\n font-style: italic;\n }\n\n u {\n text-decoration: underline;\n }\n\n s {\n text-decoration: line-through;\n }\n\n .rte-variable-node {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n margin: 0 0.125rem;\n user-select: none;\n }\n\n /* getHTML / serialize \u00E7\u0131kt\u0131s\u0131 \u2014 Badges text/secondary ile ayn\u0131 */\n .rte-variable {\n display: inline-flex;\n align-items: center;\n margin: 0 0.125rem;\n padding: 0 8px;\n height: 17px;\n line-height: 17px;\n border-radius: 3px;\n background-color: var(--primary-opacity-10);\n color: var(--primary);\n font: var(--caption-semi-bold-10-12);\n white-space: nowrap;\n vertical-align: middle;\n user-select: none;\n }\n\n p.is-editor-empty:first-child::before {\n content: attr(data-placeholder);\n float: left;\n color: var(--dark-opacity-50);\n pointer-events: none;\n height: 0;\n font: var(--body-regular-14-17);\n }\n }\n"])), function (props) { return props.$minHeight || '200px'; });
|
|
18
|
+
exports.EditorContentArea = styled_components_1.default.div(templateObject_7 || (templateObject_7 = __makeTemplateObject(["\n .ProseMirror {\n min-height: ", ";\n padding: 0;\n outline: none;\n color: var(--dark);\n font: var(--body-regular-14-17);\n box-sizing: border-box;\n\n p {\n margin: 0 0 0.75rem;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n h2 {\n margin: 0 0 0.75rem;\n color: var(--dark);\n font: var(--headline-semi-bold-18-22);\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n ul,\n ol {\n margin: 0 0 0.75rem;\n padding-left: 1.25rem;\n list-style-position: outside;\n }\n\n ul {\n list-style-type: disc;\n }\n\n ol {\n list-style-type: decimal;\n }\n\n li {\n margin-bottom: 0.25rem;\n display: list-item;\n }\n\n strong {\n font-weight: 700;\n }\n\n em {\n font-style: italic;\n }\n\n u {\n text-decoration: underline;\n }\n\n s {\n text-decoration: line-through;\n }\n\n .rte-variable-node {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n margin: 0 0.125rem;\n user-select: none;\n }\n\n /* getHTML / serialize \u00E7\u0131kt\u0131s\u0131 \u2014 Badges text/secondary ile ayn\u0131 */\n .rte-variable {\n display: inline-flex;\n align-items: center;\n margin: 0 0.125rem;\n padding: 0 8px;\n height: 17px;\n line-height: 17px;\n border-radius: 3px;\n background-color: var(--primary-opacity-10);\n color: var(--primary);\n font: var(--caption-semi-bold-10-12);\n white-space: nowrap;\n vertical-align: middle;\n user-select: none;\n }\n\n .tableWrapper {\n margin: 0 0 0.75rem;\n overflow-x: auto;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n th,\n td {\n border: 1px solid var(--grey-10);\n padding: 0.5rem 0.75rem;\n text-align: left;\n vertical-align: top;\n\n p {\n margin: 0;\n }\n }\n\n th {\n background: var(--dark-opacity-3);\n color: var(--dark);\n font: var(--caption-bold-12-15);\n }\n\n td {\n font: var(--body-regular-14-17);\n }\n\n p.is-editor-empty:first-child::before {\n content: attr(data-placeholder);\n float: left;\n color: var(--dark-opacity-50);\n pointer-events: none;\n height: 0;\n font: var(--body-regular-14-17);\n }\n }\n"], ["\n .ProseMirror {\n min-height: ", ";\n padding: 0;\n outline: none;\n color: var(--dark);\n font: var(--body-regular-14-17);\n box-sizing: border-box;\n\n p {\n margin: 0 0 0.75rem;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n h2 {\n margin: 0 0 0.75rem;\n color: var(--dark);\n font: var(--headline-semi-bold-18-22);\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n ul,\n ol {\n margin: 0 0 0.75rem;\n padding-left: 1.25rem;\n list-style-position: outside;\n }\n\n ul {\n list-style-type: disc;\n }\n\n ol {\n list-style-type: decimal;\n }\n\n li {\n margin-bottom: 0.25rem;\n display: list-item;\n }\n\n strong {\n font-weight: 700;\n }\n\n em {\n font-style: italic;\n }\n\n u {\n text-decoration: underline;\n }\n\n s {\n text-decoration: line-through;\n }\n\n .rte-variable-node {\n display: inline-flex;\n align-items: center;\n vertical-align: middle;\n margin: 0 0.125rem;\n user-select: none;\n }\n\n /* getHTML / serialize \u00E7\u0131kt\u0131s\u0131 \u2014 Badges text/secondary ile ayn\u0131 */\n .rte-variable {\n display: inline-flex;\n align-items: center;\n margin: 0 0.125rem;\n padding: 0 8px;\n height: 17px;\n line-height: 17px;\n border-radius: 3px;\n background-color: var(--primary-opacity-10);\n color: var(--primary);\n font: var(--caption-semi-bold-10-12);\n white-space: nowrap;\n vertical-align: middle;\n user-select: none;\n }\n\n .tableWrapper {\n margin: 0 0 0.75rem;\n overflow-x: auto;\n\n &:last-child {\n margin-bottom: 0;\n }\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n }\n\n th,\n td {\n border: 1px solid var(--grey-10);\n padding: 0.5rem 0.75rem;\n text-align: left;\n vertical-align: top;\n\n p {\n margin: 0;\n }\n }\n\n th {\n background: var(--dark-opacity-3);\n color: var(--dark);\n font: var(--caption-bold-12-15);\n }\n\n td {\n font: var(--body-regular-14-17);\n }\n\n p.is-editor-empty:first-child::before {\n content: attr(data-placeholder);\n float: left;\n color: var(--dark-opacity-50);\n pointer-events: none;\n height: 0;\n font: var(--body-regular-14-17);\n }\n }\n"])), function (props) { return props.$minHeight || '200px'; });
|
|
19
19
|
exports.FieldDescription = styled_components_1.default.p(templateObject_8 || (templateObject_8 = __makeTemplateObject(["\n margin: 0.5rem 0 0;\n color: var(--dark-opacity-50);\n font: var(--caption-semi-bold-12-15);\n"], ["\n margin: 0.5rem 0 0;\n color: var(--dark-opacity-50);\n font: var(--caption-semi-bold-12-15);\n"])));
|
|
20
20
|
exports.ErrorMessage = styled_components_1.default.div(templateObject_9 || (templateObject_9 = __makeTemplateObject(["\n display: flex;\n align-items: center;\n margin-top: 0.5rem;\n color: var(--red);\n\n p {\n margin: 0;\n font: var(--caption-semi-bold-11-13);\n }\n"], ["\n display: flex;\n align-items: center;\n margin-top: 0.5rem;\n color: var(--red);\n\n p {\n margin: 0;\n font: var(--caption-semi-bold-11-13);\n }\n"])));
|
|
21
21
|
exports.VariableActions = styled_components_1.default.div(templateObject_10 || (templateObject_10 = __makeTemplateObject(["\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n margin-top: 0.75rem;\n"], ["\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n margin-top: 0.75rem;\n"])));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
14
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
15
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
16
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
17
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
18
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
19
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
23
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
24
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
25
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
26
|
+
function step(op) {
|
|
27
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
28
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
29
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
30
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
31
|
+
switch (op[0]) {
|
|
32
|
+
case 0: case 1: t = op; break;
|
|
33
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
34
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
35
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
36
|
+
default:
|
|
37
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
38
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
39
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
40
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
41
|
+
if (t[2]) _.ops.pop();
|
|
42
|
+
_.trys.pop(); continue;
|
|
43
|
+
}
|
|
44
|
+
op = body.call(thisArg, _);
|
|
45
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
46
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
50
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
51
|
+
};
|
|
52
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
|
+
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
54
|
+
var react_1 = require("react");
|
|
55
|
+
var react_2 = require("@testing-library/react");
|
|
56
|
+
var RichTextEditor_1 = __importDefault(require("./RichTextEditor"));
|
|
57
|
+
var renderEditor = function (props) {
|
|
58
|
+
if (props === void 0) { props = {}; }
|
|
59
|
+
var ref = (0, react_1.createRef)();
|
|
60
|
+
var utils = (0, react_2.render)((0, jsx_runtime_1.jsx)(RichTextEditor_1.default, __assign({ ref: ref }, props)));
|
|
61
|
+
return __assign({ ref: ref }, utils);
|
|
62
|
+
};
|
|
63
|
+
var waitForEditor = function () {
|
|
64
|
+
return (0, react_2.waitFor)(function () { return expect(document.querySelector('.ProseMirror')).toBeInTheDocument(); });
|
|
65
|
+
};
|
|
66
|
+
describe('RichTextEditor', function () {
|
|
67
|
+
it('renders the field label', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
68
|
+
return __generator(this, function (_a) {
|
|
69
|
+
switch (_a.label) {
|
|
70
|
+
case 0:
|
|
71
|
+
renderEditor({ label: 'Mail metni' });
|
|
72
|
+
return [4 /*yield*/, waitForEditor()];
|
|
73
|
+
case 1:
|
|
74
|
+
_a.sent();
|
|
75
|
+
expect(react_2.screen.getByText('Mail metni')).toBeInTheDocument();
|
|
76
|
+
return [2 /*return*/];
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}); });
|
|
80
|
+
it('does not render a scroll container without maxHeight', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
81
|
+
return __generator(this, function (_a) {
|
|
82
|
+
switch (_a.label) {
|
|
83
|
+
case 0:
|
|
84
|
+
renderEditor();
|
|
85
|
+
return [4 /*yield*/, waitForEditor()];
|
|
86
|
+
case 1:
|
|
87
|
+
_a.sent();
|
|
88
|
+
expect(document.querySelector('[data-simplebar]')).not.toBeInTheDocument();
|
|
89
|
+
return [2 /*return*/];
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}); });
|
|
93
|
+
it('wraps the content in a SimpleBar scroll container when maxHeight is set', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
94
|
+
var scrollArea;
|
|
95
|
+
return __generator(this, function (_a) {
|
|
96
|
+
switch (_a.label) {
|
|
97
|
+
case 0:
|
|
98
|
+
renderEditor({ maxHeight: '150px' });
|
|
99
|
+
return [4 /*yield*/, waitForEditor()];
|
|
100
|
+
case 1:
|
|
101
|
+
_a.sent();
|
|
102
|
+
scrollArea = document.querySelector('[data-simplebar]');
|
|
103
|
+
expect(scrollArea).toBeInTheDocument();
|
|
104
|
+
expect(scrollArea).toHaveStyle({ maxHeight: '150px' });
|
|
105
|
+
expect(scrollArea === null || scrollArea === void 0 ? void 0 : scrollArea.querySelector('.ProseMirror')).toBeInTheDocument();
|
|
106
|
+
return [2 /*return*/];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}); });
|
|
110
|
+
it('strips <script> tags from the initial content (XSS protection)', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
111
|
+
var ref;
|
|
112
|
+
var _a;
|
|
113
|
+
return __generator(this, function (_b) {
|
|
114
|
+
switch (_b.label) {
|
|
115
|
+
case 0:
|
|
116
|
+
ref = renderEditor({ defaultValue: '<p>Merhaba</p><script>alert(1)</script>' }).ref;
|
|
117
|
+
return [4 /*yield*/, waitForEditor()];
|
|
118
|
+
case 1:
|
|
119
|
+
_b.sent();
|
|
120
|
+
expect(document.querySelector('script')).not.toBeInTheDocument();
|
|
121
|
+
expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()).not.toContain('<script>');
|
|
122
|
+
return [2 /*return*/];
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}); });
|
|
126
|
+
it('keeps the default allowed tags (e.g. heading) when allowedTags is not provided', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
127
|
+
var ref;
|
|
128
|
+
var _a;
|
|
129
|
+
return __generator(this, function (_b) {
|
|
130
|
+
switch (_b.label) {
|
|
131
|
+
case 0:
|
|
132
|
+
ref = renderEditor({ defaultValue: '<h2>Başlık</h2>' }).ref;
|
|
133
|
+
return [4 /*yield*/, waitForEditor()];
|
|
134
|
+
case 1:
|
|
135
|
+
_b.sent();
|
|
136
|
+
expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()).toContain('<h2>');
|
|
137
|
+
return [2 /*return*/];
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
}); });
|
|
141
|
+
it('strips tags outside a custom allowedTags list, keeping their text content', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
142
|
+
var ref, html;
|
|
143
|
+
var _a, _b;
|
|
144
|
+
return __generator(this, function (_c) {
|
|
145
|
+
switch (_c.label) {
|
|
146
|
+
case 0:
|
|
147
|
+
ref = renderEditor({
|
|
148
|
+
defaultValue: '<h2>Başlık</h2><p>Kalın <strong>metin</strong></p>',
|
|
149
|
+
allowedTags: ['p', 'br'],
|
|
150
|
+
}).ref;
|
|
151
|
+
return [4 /*yield*/, waitForEditor()];
|
|
152
|
+
case 1:
|
|
153
|
+
_c.sent();
|
|
154
|
+
html = (_b = (_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()) !== null && _b !== void 0 ? _b : '';
|
|
155
|
+
expect(html).not.toContain('<h2>');
|
|
156
|
+
expect(html).not.toContain('<strong>');
|
|
157
|
+
expect(html).toContain('Başlık');
|
|
158
|
+
expect(html).toContain('metin');
|
|
159
|
+
return [2 /*return*/];
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}); });
|
|
163
|
+
it('strips <table> content when "table" is not in allowedTags', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
164
|
+
var ref;
|
|
165
|
+
var _a;
|
|
166
|
+
return __generator(this, function (_b) {
|
|
167
|
+
switch (_b.label) {
|
|
168
|
+
case 0:
|
|
169
|
+
ref = renderEditor({ defaultValue: '<table><tbody><tr><td>Hücre</td></tr></tbody></table>' }).ref;
|
|
170
|
+
return [4 /*yield*/, waitForEditor()];
|
|
171
|
+
case 1:
|
|
172
|
+
_b.sent();
|
|
173
|
+
expect(document.querySelector('table')).not.toBeInTheDocument();
|
|
174
|
+
expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()).toContain('Hücre');
|
|
175
|
+
return [2 /*return*/];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}); });
|
|
179
|
+
it('renders an actual <table> once "table" is added to allowedTags', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
180
|
+
var ref;
|
|
181
|
+
var _a;
|
|
182
|
+
return __generator(this, function (_b) {
|
|
183
|
+
switch (_b.label) {
|
|
184
|
+
case 0:
|
|
185
|
+
ref = renderEditor({
|
|
186
|
+
defaultValue: '<table><tbody><tr><th>Ad</th></tr><tr><td>Ada</td></tr></tbody></table>',
|
|
187
|
+
allowedTags: ['p', 'table'],
|
|
188
|
+
}).ref;
|
|
189
|
+
return [4 /*yield*/, waitForEditor()];
|
|
190
|
+
case 1:
|
|
191
|
+
_b.sent();
|
|
192
|
+
expect(document.querySelector('table')).toBeInTheDocument();
|
|
193
|
+
expect(document.querySelector('th')).toHaveTextContent('Ad');
|
|
194
|
+
expect(document.querySelector('td')).toHaveTextContent('Ada');
|
|
195
|
+
expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()).toContain('<table');
|
|
196
|
+
return [2 /*return*/];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}); });
|
|
200
|
+
it('keeps colspan/rowspan attributes on merged table cells', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
201
|
+
var ref;
|
|
202
|
+
var _a;
|
|
203
|
+
return __generator(this, function (_b) {
|
|
204
|
+
switch (_b.label) {
|
|
205
|
+
case 0:
|
|
206
|
+
ref = renderEditor({
|
|
207
|
+
defaultValue: '<table><tbody><tr><td colspan="2" rowspan="1">Birleşik</td></tr></tbody></table>',
|
|
208
|
+
allowedTags: ['p', 'table'],
|
|
209
|
+
}).ref;
|
|
210
|
+
return [4 /*yield*/, waitForEditor()];
|
|
211
|
+
case 1:
|
|
212
|
+
_b.sent();
|
|
213
|
+
expect(document.querySelector('td')).toHaveAttribute('colspan', '2');
|
|
214
|
+
expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()).toContain('colspan="2"');
|
|
215
|
+
return [2 /*return*/];
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
}); });
|
|
219
|
+
it('marks the editor as non-editable when disabled', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
220
|
+
return __generator(this, function (_a) {
|
|
221
|
+
switch (_a.label) {
|
|
222
|
+
case 0:
|
|
223
|
+
renderEditor({ disabled: true, defaultValue: '<p>Merhaba</p>' });
|
|
224
|
+
return [4 /*yield*/, waitForEditor()];
|
|
225
|
+
case 1:
|
|
226
|
+
_a.sent();
|
|
227
|
+
expect(document.querySelector('.ProseMirror')).toHaveAttribute('contenteditable', 'false');
|
|
228
|
+
return [2 /*return*/];
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}); });
|
|
232
|
+
it('clears content through the imperative ref API', function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
233
|
+
var ref;
|
|
234
|
+
var _a;
|
|
235
|
+
return __generator(this, function (_b) {
|
|
236
|
+
switch (_b.label) {
|
|
237
|
+
case 0:
|
|
238
|
+
ref = renderEditor({ defaultValue: '<p>Merhaba</p>' }).ref;
|
|
239
|
+
return [4 /*yield*/, waitForEditor()];
|
|
240
|
+
case 1:
|
|
241
|
+
_b.sent();
|
|
242
|
+
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.clear();
|
|
243
|
+
return [4 /*yield*/, (0, react_2.waitFor)(function () { var _a; return expect((_a = ref.current) === null || _a === void 0 ? void 0 : _a.getHTML()).toBe(''); })];
|
|
244
|
+
case 2:
|
|
245
|
+
_b.sent();
|
|
246
|
+
return [2 /*return*/];
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
}); });
|
|
250
|
+
});
|
|
@@ -17,6 +17,10 @@ export interface RichTextEditorProps {
|
|
|
17
17
|
className?: string;
|
|
18
18
|
id?: string;
|
|
19
19
|
minHeight?: string;
|
|
20
|
+
/** Verildiğinde editör içeriği bu yüksekliği aşınca SimpleBar ile scroll edilebilir olur */
|
|
21
|
+
maxHeight?: string;
|
|
22
|
+
/** HTML sanitizasyonunda (DOMPurify) izin verilen etiketler. Verilmezse varsayılan güvenli liste kullanılır. */
|
|
23
|
+
allowedTags?: string[];
|
|
20
24
|
/** Story / consumer tarafında değişken listesi göstermek için opsiyonel */
|
|
21
25
|
variables?: RichTextVariable[];
|
|
22
26
|
}
|
|
@@ -36,5 +40,7 @@ export declare const RichTextEditorDefault: {
|
|
|
36
40
|
hasError: boolean;
|
|
37
41
|
errorMessage: string;
|
|
38
42
|
minHeight: string;
|
|
43
|
+
maxHeight: string;
|
|
44
|
+
allowedTags: string[];
|
|
39
45
|
variables: RichTextVariable[];
|
|
40
46
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RichTextEditorDefault = void 0;
|
|
4
|
+
var sanitize_1 = require("./utils/sanitize");
|
|
4
5
|
exports.RichTextEditorDefault = {
|
|
5
6
|
label: null,
|
|
6
7
|
placeholder: 'Metin yaz…',
|
|
@@ -10,5 +11,7 @@ exports.RichTextEditorDefault = {
|
|
|
10
11
|
hasError: false,
|
|
11
12
|
errorMessage: null,
|
|
12
13
|
minHeight: '200px',
|
|
14
|
+
maxHeight: null,
|
|
15
|
+
allowedTags: sanitize_1.DEFAULT_ALLOWED_TAGS,
|
|
13
16
|
variables: [],
|
|
14
17
|
};
|
|
@@ -26,6 +26,12 @@ declare const _default: {
|
|
|
26
26
|
minHeight: {
|
|
27
27
|
control: string;
|
|
28
28
|
};
|
|
29
|
+
maxHeight: {
|
|
30
|
+
control: string;
|
|
31
|
+
};
|
|
32
|
+
allowedTags: {
|
|
33
|
+
control: boolean;
|
|
34
|
+
};
|
|
29
35
|
onChange: {
|
|
30
36
|
control: boolean;
|
|
31
37
|
};
|
|
@@ -67,6 +73,47 @@ export declare const WithSampleContent: {
|
|
|
67
73
|
minHeight: string;
|
|
68
74
|
};
|
|
69
75
|
};
|
|
76
|
+
export declare const WithMaxHeight: {
|
|
77
|
+
name: string;
|
|
78
|
+
args: {
|
|
79
|
+
label: string;
|
|
80
|
+
defaultValue: string;
|
|
81
|
+
minHeight: string;
|
|
82
|
+
maxHeight: string;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
export declare const WithCustomAllowedTags: {
|
|
86
|
+
name: string;
|
|
87
|
+
args: {
|
|
88
|
+
label: string;
|
|
89
|
+
defaultValue: string;
|
|
90
|
+
minHeight: string;
|
|
91
|
+
allowedTags: string[];
|
|
92
|
+
};
|
|
93
|
+
parameters: {
|
|
94
|
+
docs: {
|
|
95
|
+
description: {
|
|
96
|
+
story: string;
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
export declare const WithTable: {
|
|
102
|
+
name: string;
|
|
103
|
+
args: {
|
|
104
|
+
label: string;
|
|
105
|
+
defaultValue: string;
|
|
106
|
+
minHeight: string;
|
|
107
|
+
allowedTags: string[];
|
|
108
|
+
};
|
|
109
|
+
parameters: {
|
|
110
|
+
docs: {
|
|
111
|
+
description: {
|
|
112
|
+
story: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
};
|
|
70
117
|
export declare const WithError: {
|
|
71
118
|
args: {
|
|
72
119
|
label: string;
|
|
@@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.InsertVariables = exports.Disabled = exports.WithError = exports.WithSampleContent = exports.WithDescription = exports.Default = void 0;
|
|
17
|
+
exports.InsertVariables = exports.Disabled = exports.WithError = exports.WithTable = exports.WithCustomAllowedTags = exports.WithMaxHeight = exports.WithSampleContent = exports.WithDescription = exports.Default = void 0;
|
|
18
18
|
var jsx_runtime_1 = require("react/jsx-runtime");
|
|
19
19
|
var react_1 = require("react");
|
|
20
20
|
var RichTextEditor_1 = __importDefault(require("../RichTextEditor"));
|
|
@@ -37,6 +37,8 @@ exports.default = {
|
|
|
37
37
|
hasError: { control: 'boolean' },
|
|
38
38
|
errorMessage: { control: 'text' },
|
|
39
39
|
minHeight: { control: 'text' },
|
|
40
|
+
maxHeight: { control: 'text' },
|
|
41
|
+
allowedTags: { control: false },
|
|
40
42
|
onChange: { control: false },
|
|
41
43
|
onBlur: { control: false },
|
|
42
44
|
value: { control: false },
|
|
@@ -67,6 +69,47 @@ exports.WithSampleContent = {
|
|
|
67
69
|
minHeight: '240px',
|
|
68
70
|
},
|
|
69
71
|
};
|
|
72
|
+
exports.WithMaxHeight = {
|
|
73
|
+
name: 'Sınırlı yükseklik (scroll)',
|
|
74
|
+
args: {
|
|
75
|
+
label: 'Mail metni',
|
|
76
|
+
defaultValue: SAMPLE_CONTENT.repeat(3),
|
|
77
|
+
minHeight: '220px',
|
|
78
|
+
maxHeight: '220px',
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
exports.WithCustomAllowedTags = {
|
|
82
|
+
name: 'Kısıtlı izinli etiketler',
|
|
83
|
+
args: {
|
|
84
|
+
label: 'Mail metni',
|
|
85
|
+
defaultValue: '<h2>Başlık</h2><p>Kalın <strong>metin</strong> ve normal metin.</p>',
|
|
86
|
+
minHeight: '160px',
|
|
87
|
+
allowedTags: ['p', 'br'],
|
|
88
|
+
},
|
|
89
|
+
parameters: {
|
|
90
|
+
docs: {
|
|
91
|
+
description: {
|
|
92
|
+
story: 'Sadece paragraf/satır sonuna izin verilir; `<h2>` ve `<strong>` etiketleri kaldırılır, içerikleri düz metin olarak kalır.',
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
exports.WithTable = {
|
|
98
|
+
name: 'Tablo (allowedTags: table)',
|
|
99
|
+
args: {
|
|
100
|
+
label: 'Mail metni',
|
|
101
|
+
defaultValue: "\n<p>Sipari\u015F \u00F6zeti:</p>\n<table>\n <tbody>\n <tr><th>\u00DCr\u00FCn</th><th>Adet</th><th>Tutar</th></tr>\n <tr><td>Kablosuz Kulakl\u0131k</td><td>1</td><td>\u20BA1.299</td></tr>\n <tr><td>\u015Earj Kablosu</td><td>2</td><td>\u20BA198</td></tr>\n </tbody>\n</table>",
|
|
102
|
+
minHeight: '220px',
|
|
103
|
+
allowedTags: ['p', 'table'],
|
|
104
|
+
},
|
|
105
|
+
parameters: {
|
|
106
|
+
docs: {
|
|
107
|
+
description: {
|
|
108
|
+
story: '`allowedTags` dizisine `table` eklendiğinde editör tablo şemasını (satır/hücre) destekler ve içerik render edilir. Eklenmezse `<table>` sanitize aşamasında düz metne indirilir.',
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
};
|
|
70
113
|
exports.WithError = {
|
|
71
114
|
args: {
|
|
72
115
|
label: 'Mail metni',
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
/** RichTextEditor `allowedTags` prop'u verilmediğinde kullanılan varsayılan izinli etiket listesi */
|
|
2
|
+
export declare const DEFAULT_ALLOWED_TAGS: string[];
|
|
3
|
+
export declare const sanitizeHtml: (html: string, allowedTags?: string[]) => string;
|
|
2
4
|
/**
|
|
3
5
|
* TipTap HTML → dışarı verilen HTML
|
|
4
6
|
* Boş paragraflar (Enter + yazı yok) <br> olur.
|
|
5
7
|
* İçinde metin olan paragraflar <p> olarak kalır.
|
|
6
8
|
*/
|
|
7
|
-
export declare const serializeEditorHtml: (html: string) => string;
|
|
9
|
+
export declare const serializeEditorHtml: (html: string, allowedTags?: string[]) => string;
|
|
8
10
|
/**
|
|
9
11
|
* Dışarıdan gelen HTML → TipTap'in düzenleyebileceği HTML
|
|
10
12
|
* Blok seviyesindeki <br> etiketleri boş <p> olur (Enter satırı).
|
|
11
13
|
* <p> içindeki <br> hard-break olarak kalır.
|
|
12
14
|
*/
|
|
13
|
-
export declare const prepareEditorHtml: (html: string) => string;
|
|
15
|
+
export declare const prepareEditorHtml: (html: string, allowedTags?: string[]) => string;
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
3
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
4
|
+
if (ar || !(i in from)) {
|
|
5
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
6
|
+
ar[i] = from[i];
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
10
|
+
};
|
|
2
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
13
|
};
|
|
5
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.prepareEditorHtml = exports.serializeEditorHtml = exports.sanitizeHtml = void 0;
|
|
15
|
+
exports.prepareEditorHtml = exports.serializeEditorHtml = exports.sanitizeHtml = exports.DEFAULT_ALLOWED_TAGS = void 0;
|
|
7
16
|
var dompurify_1 = __importDefault(require("dompurify"));
|
|
8
|
-
|
|
17
|
+
/** RichTextEditor `allowedTags` prop'u verilmediğinde kullanılan varsayılan izinli etiket listesi */
|
|
18
|
+
exports.DEFAULT_ALLOWED_TAGS = [
|
|
9
19
|
'p',
|
|
10
20
|
'br',
|
|
11
21
|
'h2',
|
|
@@ -26,13 +36,28 @@ var ALLOWED_ATTR = [
|
|
|
26
36
|
'data-variable',
|
|
27
37
|
'data-id',
|
|
28
38
|
'data-label',
|
|
39
|
+
// Tablo hücrelerinde birleştirme (merge/split) ve dıştan gelen sütun genişliği bilgisi için
|
|
40
|
+
'colspan',
|
|
41
|
+
'rowspan',
|
|
42
|
+
'colwidth',
|
|
29
43
|
];
|
|
44
|
+
/**
|
|
45
|
+
* `table` etiketi izinliyken düzgün render edilebilmesi için birlikte izinli olması
|
|
46
|
+
* gereken yapısal alt etiketler. Tüketici sadece "table" eklese de tablo çalışır.
|
|
47
|
+
*/
|
|
48
|
+
var TABLE_STRUCTURE_TAGS = ['table', 'tbody', 'tr', 'th', 'td', 'colgroup', 'col'];
|
|
49
|
+
var resolveAllowedTags = function (allowedTags) {
|
|
50
|
+
if (!allowedTags.includes('table'))
|
|
51
|
+
return allowedTags;
|
|
52
|
+
return Array.from(new Set(__spreadArray(__spreadArray([], allowedTags, true), TABLE_STRUCTURE_TAGS, true)));
|
|
53
|
+
};
|
|
30
54
|
var EMPTY_PARAGRAPH_REGEX = /<p>(?:\s| |<br\s*\/?>)*<\/p>/gi;
|
|
31
|
-
var sanitizeHtml = function (html) {
|
|
55
|
+
var sanitizeHtml = function (html, allowedTags) {
|
|
56
|
+
if (allowedTags === void 0) { allowedTags = exports.DEFAULT_ALLOWED_TAGS; }
|
|
32
57
|
if (!html)
|
|
33
58
|
return '';
|
|
34
59
|
return dompurify_1.default.sanitize(html, {
|
|
35
|
-
ALLOWED_TAGS:
|
|
60
|
+
ALLOWED_TAGS: resolveAllowedTags(allowedTags),
|
|
36
61
|
ALLOWED_ATTR: ALLOWED_ATTR,
|
|
37
62
|
KEEP_CONTENT: true,
|
|
38
63
|
});
|
|
@@ -43,8 +68,9 @@ exports.sanitizeHtml = sanitizeHtml;
|
|
|
43
68
|
* Boş paragraflar (Enter + yazı yok) <br> olur.
|
|
44
69
|
* İçinde metin olan paragraflar <p> olarak kalır.
|
|
45
70
|
*/
|
|
46
|
-
var serializeEditorHtml = function (html) {
|
|
47
|
-
|
|
71
|
+
var serializeEditorHtml = function (html, allowedTags) {
|
|
72
|
+
if (allowedTags === void 0) { allowedTags = exports.DEFAULT_ALLOWED_TAGS; }
|
|
73
|
+
var sanitized = (0, exports.sanitizeHtml)(html, allowedTags);
|
|
48
74
|
if (!sanitized)
|
|
49
75
|
return '';
|
|
50
76
|
var serialized = sanitized.replace(EMPTY_PARAGRAPH_REGEX, '<br>');
|
|
@@ -59,8 +85,9 @@ exports.serializeEditorHtml = serializeEditorHtml;
|
|
|
59
85
|
* Blok seviyesindeki <br> etiketleri boş <p> olur (Enter satırı).
|
|
60
86
|
* <p> içindeki <br> hard-break olarak kalır.
|
|
61
87
|
*/
|
|
62
|
-
var prepareEditorHtml = function (html) {
|
|
63
|
-
|
|
88
|
+
var prepareEditorHtml = function (html, allowedTags) {
|
|
89
|
+
if (allowedTags === void 0) { allowedTags = exports.DEFAULT_ALLOWED_TAGS; }
|
|
90
|
+
var sanitized = (0, exports.sanitizeHtml)(html, allowedTags);
|
|
64
91
|
if (!sanitized)
|
|
65
92
|
return '';
|
|
66
93
|
if (typeof DOMParser === 'undefined') {
|
|
@@ -85,12 +112,13 @@ var prepareEditorHtml = function (html) {
|
|
|
85
112
|
if (tag === 'P' || tag === 'H2' || tag === 'SPAN') {
|
|
86
113
|
return;
|
|
87
114
|
}
|
|
88
|
-
if (tag === 'LI' || tag === 'UL' || tag === 'OL' || tag === 'DIV'
|
|
115
|
+
if (tag === 'LI' || tag === 'UL' || tag === 'OL' || tag === 'DIV'
|
|
116
|
+
|| tag === 'TABLE' || tag === 'TBODY' || tag === 'TR' || tag === 'TD' || tag === 'TH') {
|
|
89
117
|
replaceBlockBreaks(element);
|
|
90
118
|
}
|
|
91
119
|
});
|
|
92
120
|
};
|
|
93
121
|
replaceBlockBreaks(root);
|
|
94
|
-
return (0, exports.sanitizeHtml)(root.innerHTML);
|
|
122
|
+
return (0, exports.sanitizeHtml)(root.innerHTML, allowedTags);
|
|
95
123
|
};
|
|
96
124
|
exports.prepareEditorHtml = prepareEditorHtml;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "krl-alfred",
|
|
3
|
-
"version": "2.23.
|
|
3
|
+
"version": "2.23.14",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist"
|
|
6
6
|
],
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"@testing-library/react": "^14.0.0",
|
|
15
15
|
"@testing-library/user-event": "^14.4.3",
|
|
16
16
|
"@tiptap/extension-placeholder": "^3.27.3",
|
|
17
|
+
"@tiptap/extension-table": "3.27.3",
|
|
17
18
|
"@tiptap/extension-underline": "^3.27.3",
|
|
18
19
|
"@tiptap/pm": "^3.27.3",
|
|
19
20
|
"@tiptap/react": "^3.27.3",
|
|
@@ -67,6 +68,12 @@
|
|
|
67
68
|
"eslintConfig": {
|
|
68
69
|
"extends": "react-app"
|
|
69
70
|
},
|
|
71
|
+
"jest": {
|
|
72
|
+
"moduleNameMapper": {
|
|
73
|
+
"^@tiptap/pm/(.*)$": "<rootDir>/node_modules/@tiptap/pm/dist/$1/index.cjs",
|
|
74
|
+
"^@tiptap/core/(jsx-runtime|jsx-dev-runtime)$": "<rootDir>/node_modules/@tiptap/core/$1/index.cjs"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
70
77
|
"browserslist": {
|
|
71
78
|
"production": [
|
|
72
79
|
">0.2%",
|