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.
@@ -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 _k = (0, react_1.useState)(false), focused = _k[0], setFocused = _k[1];
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,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
- export declare const sanitizeHtml: (html: string) => string;
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
- var ALLOWED_TAGS = [
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|&nbsp;|<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: 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
- var sanitized = (0, exports.sanitizeHtml)(html);
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
- var sanitized = (0, exports.sanitizeHtml)(html);
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';
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ require("@testing-library/jest-dom");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "krl-alfred",
3
- "version": "2.23.13",
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%",