@commercetools-uikit/rich-text-utils 19.24.0 → 19.25.0
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/commercetools-uikit-rich-text-utils.cjs.dev.js +162 -19
- package/dist/commercetools-uikit-rich-text-utils.cjs.prod.js +162 -19
- package/dist/commercetools-uikit-rich-text-utils.esm.js +160 -21
- package/dist/declarations/src/html/html.d.ts +2 -0
- package/dist/declarations/src/index.d.ts +1 -1
- package/dist/declarations/src/slate-helpers.d.ts +6 -1
- package/dist/declarations/src/tags.d.ts +1 -0
- package/package.json +8 -7
|
@@ -12,9 +12,11 @@ var utils = require('@commercetools-uikit/utils');
|
|
|
12
12
|
var uniq = require('lodash/uniq');
|
|
13
13
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
14
14
|
var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
|
|
15
|
+
var _trimInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/trim');
|
|
16
|
+
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
15
17
|
var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-array');
|
|
18
|
+
var _Array$from = require('@babel/runtime-corejs3/core-js-stable/array/from');
|
|
16
19
|
var _flatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/flat');
|
|
17
|
-
var _Array$from3 = require('@babel/runtime-corejs3/core-js-stable/array/from');
|
|
18
20
|
var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
|
|
19
21
|
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
20
22
|
var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
|
|
@@ -28,11 +30,12 @@ var slateHyperscript = require('slate-hyperscript');
|
|
|
28
30
|
var parse = require('style-to-object');
|
|
29
31
|
var isEmpty$2 = require('lodash/isEmpty');
|
|
30
32
|
var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
|
|
33
|
+
var react = require('react');
|
|
31
34
|
var slateReact = require('slate-react');
|
|
35
|
+
var isUrl = require('is-url');
|
|
32
36
|
var jsxRuntime = require('@emotion/react/jsx-runtime');
|
|
33
37
|
var _someInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/some');
|
|
34
38
|
var _pt = require('prop-types');
|
|
35
|
-
var react = require('react');
|
|
36
39
|
var inputUtils = require('@commercetools-uikit/input-utils');
|
|
37
40
|
var _objectWithoutProperties = require('@babel/runtime-corejs3/helpers/objectWithoutProperties');
|
|
38
41
|
var _styled = require('@emotion/styled/base');
|
|
@@ -55,9 +58,11 @@ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
|
55
58
|
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
56
59
|
var uniq__default = /*#__PURE__*/_interopDefault(uniq);
|
|
57
60
|
var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
|
|
61
|
+
var _trimInstanceProperty__default = /*#__PURE__*/_interopDefault(_trimInstanceProperty);
|
|
62
|
+
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
58
63
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
64
|
+
var _Array$from__default = /*#__PURE__*/_interopDefault(_Array$from);
|
|
59
65
|
var _flatInstanceProperty__default = /*#__PURE__*/_interopDefault(_flatInstanceProperty);
|
|
60
|
-
var _Array$from3__default = /*#__PURE__*/_interopDefault(_Array$from3);
|
|
61
66
|
var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
|
|
62
67
|
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
63
68
|
var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
|
|
@@ -69,6 +74,7 @@ var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
|
|
|
69
74
|
var parse__default = /*#__PURE__*/_interopDefault(parse);
|
|
70
75
|
var isEmpty__default = /*#__PURE__*/_interopDefault(isEmpty$2);
|
|
71
76
|
var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
|
|
77
|
+
var isUrl__default = /*#__PURE__*/_interopDefault(isUrl);
|
|
72
78
|
var _someInstanceProperty__default = /*#__PURE__*/_interopDefault(_someInstanceProperty);
|
|
73
79
|
var _pt__default = /*#__PURE__*/_interopDefault(_pt);
|
|
74
80
|
var _styled__default = /*#__PURE__*/_interopDefault(_styled);
|
|
@@ -89,7 +95,8 @@ const BLOCK_TAGS = {
|
|
|
89
95
|
pre: 'code',
|
|
90
96
|
li: 'list-item',
|
|
91
97
|
ol: 'numbered-list',
|
|
92
|
-
ul: 'bulleted-list'
|
|
98
|
+
ul: 'bulleted-list',
|
|
99
|
+
a: 'link'
|
|
93
100
|
};
|
|
94
101
|
|
|
95
102
|
// Add a dictionary of mark tags.
|
|
@@ -173,6 +180,13 @@ const Element = _ref => {
|
|
|
173
180
|
}, attributes), {}, {
|
|
174
181
|
children: children
|
|
175
182
|
}));
|
|
183
|
+
case BLOCK_TAGS.a:
|
|
184
|
+
return jsxRuntime.jsx("a", _objectSpread$g(_objectSpread$g({
|
|
185
|
+
style: style
|
|
186
|
+
}, attributes), {}, {
|
|
187
|
+
rel: "noopener noreferrer",
|
|
188
|
+
children: children
|
|
189
|
+
}));
|
|
176
190
|
default:
|
|
177
191
|
return jsxRuntime.jsx("p", _objectSpread$g(_objectSpread$g({
|
|
178
192
|
style: style
|
|
@@ -259,7 +273,7 @@ const toggleMark = (editor, format) => {
|
|
|
259
273
|
const isBlockActive = (editor, format) => {
|
|
260
274
|
const selection = editor.selection;
|
|
261
275
|
if (!selection) return false;
|
|
262
|
-
const _Array$from = _Array$
|
|
276
|
+
const _Array$from = _Array$from__default["default"](slate.Editor.nodes(editor, {
|
|
263
277
|
at: slate.Editor.unhangRange(editor, selection),
|
|
264
278
|
match: n => !slate.Editor.isEditor(n) && slate.Element.isElement(n) && n.type === format
|
|
265
279
|
})),
|
|
@@ -362,9 +376,74 @@ const Softbreaker = {
|
|
|
362
376
|
return html.split(this.placeholderCharacter).join('');
|
|
363
377
|
}
|
|
364
378
|
};
|
|
379
|
+
const isLinkActive = editor => {
|
|
380
|
+
const _Editor$nodes = slate.Editor.nodes(editor, {
|
|
381
|
+
match: n => !slate.Editor.isEditor(n) && slate.Element.isElement(n) && n.type === 'link'
|
|
382
|
+
}),
|
|
383
|
+
_Editor$nodes2 = _slicedToArray(_Editor$nodes, 1),
|
|
384
|
+
link = _Editor$nodes2[0];
|
|
385
|
+
return !!link;
|
|
386
|
+
};
|
|
387
|
+
const unwrapLink = editor => {
|
|
388
|
+
slate.Transforms.unwrapNodes(editor, {
|
|
389
|
+
match: n => !slate.Editor.isEditor(n) && slate.Element.isElement(n) && n.type === 'link'
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
const wrapLink = (editor, url) => {
|
|
393
|
+
if (isLinkActive(editor)) {
|
|
394
|
+
unwrapLink(editor);
|
|
395
|
+
}
|
|
396
|
+
const selection = editor.selection;
|
|
397
|
+
const isCollapsed = selection && slate.Range.isCollapsed(selection);
|
|
398
|
+
const linkNode = {
|
|
399
|
+
type: 'link',
|
|
400
|
+
url,
|
|
401
|
+
children: isCollapsed ? [{
|
|
402
|
+
text: url
|
|
403
|
+
}] : []
|
|
404
|
+
};
|
|
405
|
+
if (isCollapsed) {
|
|
406
|
+
slate.Transforms.insertNodes(editor, linkNode);
|
|
407
|
+
} else {
|
|
408
|
+
slate.Transforms.wrapNodes(editor, linkNode, {
|
|
409
|
+
split: true
|
|
410
|
+
});
|
|
411
|
+
slate.Transforms.collapse(editor, {
|
|
412
|
+
edge: 'end'
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
};
|
|
416
|
+
const withLinks = editor => {
|
|
417
|
+
const insertText = editor.insertText,
|
|
418
|
+
insertData = editor.insertData,
|
|
419
|
+
isInline = editor.isInline;
|
|
420
|
+
|
|
421
|
+
// Mark link elements as inline (from example)
|
|
422
|
+
editor.isInline = element => {
|
|
423
|
+
return element.type === 'link' || isInline(element);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
// Handle URL pasting/typing to automatically create links (from example)
|
|
427
|
+
editor.insertText = text => {
|
|
428
|
+
if (text && isUrl__default["default"](text)) {
|
|
429
|
+
wrapLink(editor, text);
|
|
430
|
+
} else {
|
|
431
|
+
insertText(text);
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
editor.insertData = data => {
|
|
435
|
+
const text = data.getData('text/plain');
|
|
436
|
+
if (text && isUrl__default["default"](text)) {
|
|
437
|
+
wrapLink(editor, text);
|
|
438
|
+
} else {
|
|
439
|
+
insertData(data);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
return editor;
|
|
443
|
+
};
|
|
365
444
|
|
|
366
445
|
function ownKeys$f(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
367
|
-
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
446
|
+
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var _context8, _context9; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context8 = ownKeys$f(Object(t), !0)).call(_context8, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context9 = ownKeys$f(Object(t))).call(_context9, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
368
447
|
|
|
369
448
|
// Slate's way of providing custom type annotations comes down to extending `CustomTypes` interface
|
|
370
449
|
// more: https://docs.slatejs.org/concepts/12-typescript
|
|
@@ -401,15 +480,16 @@ const serializeNode = node => {
|
|
|
401
480
|
return string;
|
|
402
481
|
}
|
|
403
482
|
const children = _mapInstanceProperty__default["default"](_context = node.children).call(_context, serializeNode).join('');
|
|
404
|
-
|
|
483
|
+
const element = node; // Use updated CustomElement
|
|
484
|
+
|
|
485
|
+
switch (element.type) {
|
|
405
486
|
case 'block-quote':
|
|
406
487
|
return `<blockquote>${children}</blockquote>`;
|
|
407
488
|
case 'paragraph':
|
|
408
489
|
return `<p>${children}</p>`;
|
|
409
490
|
case 'code':
|
|
410
491
|
return `<pre>
|
|
411
|
-
<code>${children}</code
|
|
412
|
-
</pre>`;
|
|
492
|
+
<code>${children}</code>`;
|
|
413
493
|
case 'span':
|
|
414
494
|
return `<span>${children}</span>`;
|
|
415
495
|
case 'bulleted-list':
|
|
@@ -418,6 +498,36 @@ const serializeNode = node => {
|
|
|
418
498
|
return `<ol>${children}</ol>`;
|
|
419
499
|
case 'list-item':
|
|
420
500
|
return `<li>${children}</li>`;
|
|
501
|
+
case BLOCK_TAGS.a:
|
|
502
|
+
// Handle link serialization
|
|
503
|
+
// eslint-disable-next-line no-case-declarations
|
|
504
|
+
let hrefAttr = '';
|
|
505
|
+
if (element.url) {
|
|
506
|
+
// Sanitize href to prevent javascript: URLs during serialization as well
|
|
507
|
+
const sanitizedUrl = (_context2 => {
|
|
508
|
+
const url = _trimInstanceProperty__default["default"](_context2 = String(element.url)).call(_context2).toLowerCase();
|
|
509
|
+
if (_startsWithInstanceProperty__default["default"](url).call(url, 'javascript:') || _startsWithInstanceProperty__default["default"](url).call(url, 'data:') || _startsWithInstanceProperty__default["default"](url).call(url, 'vbscript:')) {
|
|
510
|
+
return '#';
|
|
511
|
+
}
|
|
512
|
+
return String(element.url);
|
|
513
|
+
})();
|
|
514
|
+
hrefAttr = ` href="${escapeHtml__default["default"](sanitizedUrl)}"`;
|
|
515
|
+
}
|
|
516
|
+
// eslint-disable-next-line no-case-declarations
|
|
517
|
+
let otherAttrsString = '';
|
|
518
|
+
if (element.htmlAttributes && typeof element.htmlAttributes === 'object') {
|
|
519
|
+
for (const _ref of _Object$entries__default["default"](element.htmlAttributes)) {
|
|
520
|
+
var _context3;
|
|
521
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
522
|
+
const key = _ref2[0];
|
|
523
|
+
const value = _ref2[1];
|
|
524
|
+
// Strip event handlers during serialization too
|
|
525
|
+
if (!_startsWithInstanceProperty__default["default"](_context3 = key.toLowerCase()).call(_context3, 'on')) {
|
|
526
|
+
otherAttrsString += ` ${escapeHtml__default["default"](key)}="${escapeHtml__default["default"](String(value))}"`;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return `<a${hrefAttr}${otherAttrsString}>${children}</a>`;
|
|
421
531
|
case 'heading-one':
|
|
422
532
|
return `<h1>${children}</h1>`;
|
|
423
533
|
case 'heading-two':
|
|
@@ -425,7 +535,7 @@ const serializeNode = node => {
|
|
|
425
535
|
case 'heading-three':
|
|
426
536
|
return `<h3>${children}</h3>`;
|
|
427
537
|
case 'heading-four':
|
|
428
|
-
return `<h4
|
|
538
|
+
return `<h4>${children}</h4>`;
|
|
429
539
|
case 'heading-five':
|
|
430
540
|
return `<h5>${children}</h5>`;
|
|
431
541
|
default:
|
|
@@ -447,6 +557,35 @@ const serialize = value => {
|
|
|
447
557
|
return outputHtml;
|
|
448
558
|
};
|
|
449
559
|
const ELEMENT_TAGS = {
|
|
560
|
+
A: el => {
|
|
561
|
+
const props = {
|
|
562
|
+
type: BLOCK_TAGS.a
|
|
563
|
+
};
|
|
564
|
+
const htmlAttributes = {};
|
|
565
|
+
for (const attr of _Array$from__default["default"](el.attributes)) {
|
|
566
|
+
const attrName = attr.name.toLowerCase();
|
|
567
|
+
const attrValue = attr.value;
|
|
568
|
+
if (attrName === 'href') {
|
|
569
|
+
var _context4;
|
|
570
|
+
// Sanitize href to prevent javascript: URLs
|
|
571
|
+
const sanitizedValue = _trimInstanceProperty__default["default"](_context4 = decodeURI(attrValue)).call(_context4).toLowerCase();
|
|
572
|
+
if (
|
|
573
|
+
// eslint-disable-next-line no-script-url
|
|
574
|
+
_startsWithInstanceProperty__default["default"](sanitizedValue).call(sanitizedValue, 'javascript:') || _startsWithInstanceProperty__default["default"](sanitizedValue).call(sanitizedValue, 'data:') || _startsWithInstanceProperty__default["default"](sanitizedValue).call(sanitizedValue, 'vbscript:')) {
|
|
575
|
+
props.url = '#'; // Replace with a safe value
|
|
576
|
+
} else {
|
|
577
|
+
props.url = attrValue;
|
|
578
|
+
}
|
|
579
|
+
} else if (!_startsWithInstanceProperty__default["default"](attrName).call(attrName, 'on')) {
|
|
580
|
+
// Strip event handlers
|
|
581
|
+
htmlAttributes[attrName] = attrValue;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
if (_Object$keys__default["default"](htmlAttributes).length > 0) {
|
|
585
|
+
props.htmlAttributes = htmlAttributes;
|
|
586
|
+
}
|
|
587
|
+
return props;
|
|
588
|
+
},
|
|
450
589
|
BLOCKQUOTE: () => ({
|
|
451
590
|
type: 'quote'
|
|
452
591
|
}),
|
|
@@ -552,7 +691,7 @@ const wrapWithParagraph = textContent => slateHyperscript.jsx('element', {
|
|
|
552
691
|
const wrapWithParagraphIfRootElement = (el, textContent) => el.parentNode?.nodeName === 'BODY' // root element, because body is eventually turned to React fragment
|
|
553
692
|
? wrapWithParagraph(textContent) : textContent;
|
|
554
693
|
const deserializeElement = el => {
|
|
555
|
-
var
|
|
694
|
+
var _context5, _context6;
|
|
556
695
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#value
|
|
557
696
|
if (el.nodeType === 3) {
|
|
558
697
|
return wrapWithParagraphIfRootElement(el, {
|
|
@@ -569,7 +708,7 @@ const deserializeElement = el => {
|
|
|
569
708
|
if (nodeName === 'PRE' && el.childNodes[0] && el.childNodes[0].nodeName === 'CODE') {
|
|
570
709
|
parent = el.childNodes[0];
|
|
571
710
|
}
|
|
572
|
-
let children = _flatInstanceProperty__default["default"](
|
|
711
|
+
let children = _flatInstanceProperty__default["default"](_context5 = _mapInstanceProperty__default["default"](_context6 = _Array$from__default["default"](parent.childNodes)).call(_context6, deserializeElement)).call(_context5);
|
|
573
712
|
if (children.length === 0) {
|
|
574
713
|
children = [{
|
|
575
714
|
text: ''
|
|
@@ -588,11 +727,11 @@ const deserializeElement = el => {
|
|
|
588
727
|
type: 'span'
|
|
589
728
|
}, children));
|
|
590
729
|
} else {
|
|
591
|
-
var
|
|
592
|
-
attrs = _reduceInstanceProperty__default["default"](
|
|
593
|
-
let
|
|
594
|
-
key =
|
|
595
|
-
value =
|
|
730
|
+
var _context7;
|
|
731
|
+
attrs = _reduceInstanceProperty__default["default"](_context7 = _Object$entries__default["default"](styleObj || {})).call(_context7, (mappedAttrObj, _ref3) => {
|
|
732
|
+
let _ref4 = _slicedToArray(_ref3, 2),
|
|
733
|
+
key = _ref4[0],
|
|
734
|
+
value = _ref4[1];
|
|
596
735
|
const values = value.split(' '); // to cover the case of space-separated values e.g. `text-decoration-line: "underline line-through"`
|
|
597
736
|
|
|
598
737
|
_forEachInstanceProperty__default["default"](values).call(values, splittedValue => {
|
|
@@ -614,8 +753,11 @@ const deserializeElement = el => {
|
|
|
614
753
|
_mapInstanceProperty__default["default"](children).call(children, child => slate.Text.isText(child) ? slateHyperscript.jsx('text', attrs, child) : slateHyperscript.jsx('element', attrs, child)));
|
|
615
754
|
}
|
|
616
755
|
}
|
|
756
|
+
|
|
757
|
+
// Modified to use the updated ELEMENT_TAGS for 'A'
|
|
617
758
|
if (ELEMENT_TAGS[nodeName]) {
|
|
618
|
-
const attrs = ELEMENT_TAGS[nodeName](
|
|
759
|
+
const attrs = ELEMENT_TAGS[nodeName](el // Pass element to access its attributes
|
|
760
|
+
);
|
|
619
761
|
return slateHyperscript.jsx('element', attrs, children);
|
|
620
762
|
}
|
|
621
763
|
if (TEXT_TAGS[nodeName]) {
|
|
@@ -1838,7 +1980,7 @@ RichTextEditorBody.displayName = 'RichTextEditorBody';
|
|
|
1838
1980
|
var RichTextEditorBody$1 = RichTextEditorBody;
|
|
1839
1981
|
|
|
1840
1982
|
// NOTE: This string will be replaced on build time with the package version.
|
|
1841
|
-
var version = "19.
|
|
1983
|
+
var version = "19.25.0";
|
|
1842
1984
|
|
|
1843
1985
|
exports.Element = Element;
|
|
1844
1986
|
exports.HiddenInput = HiddenInput$1;
|
|
@@ -1856,3 +1998,4 @@ exports.toggleBlock = toggleBlock;
|
|
|
1856
1998
|
exports.toggleMark = toggleMark;
|
|
1857
1999
|
exports.validSlateStateAdapter = validSlateStateAdapter;
|
|
1858
2000
|
exports.version = version;
|
|
2001
|
+
exports.withLinks = withLinks;
|
|
@@ -12,9 +12,11 @@ require('@commercetools-uikit/utils');
|
|
|
12
12
|
var uniq = require('lodash/uniq');
|
|
13
13
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
14
14
|
var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
|
|
15
|
+
var _trimInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/trim');
|
|
16
|
+
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
15
17
|
var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-array');
|
|
18
|
+
var _Array$from = require('@babel/runtime-corejs3/core-js-stable/array/from');
|
|
16
19
|
var _flatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/flat');
|
|
17
|
-
var _Array$from3 = require('@babel/runtime-corejs3/core-js-stable/array/from');
|
|
18
20
|
var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/for-each');
|
|
19
21
|
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
20
22
|
var _filterInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/filter');
|
|
@@ -28,11 +30,12 @@ var slateHyperscript = require('slate-hyperscript');
|
|
|
28
30
|
var parse = require('style-to-object');
|
|
29
31
|
var isEmpty$2 = require('lodash/isEmpty');
|
|
30
32
|
var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
|
|
33
|
+
var react = require('react');
|
|
31
34
|
var slateReact = require('slate-react');
|
|
35
|
+
var isUrl = require('is-url');
|
|
32
36
|
var jsxRuntime = require('@emotion/react/jsx-runtime');
|
|
33
37
|
var _someInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/some');
|
|
34
38
|
require('prop-types');
|
|
35
|
-
var react = require('react');
|
|
36
39
|
var inputUtils = require('@commercetools-uikit/input-utils');
|
|
37
40
|
var _objectWithoutProperties = require('@babel/runtime-corejs3/helpers/objectWithoutProperties');
|
|
38
41
|
var _styled = require('@emotion/styled/base');
|
|
@@ -55,9 +58,11 @@ var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
|
55
58
|
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
56
59
|
var uniq__default = /*#__PURE__*/_interopDefault(uniq);
|
|
57
60
|
var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
|
|
61
|
+
var _trimInstanceProperty__default = /*#__PURE__*/_interopDefault(_trimInstanceProperty);
|
|
62
|
+
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
58
63
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
64
|
+
var _Array$from__default = /*#__PURE__*/_interopDefault(_Array$from);
|
|
59
65
|
var _flatInstanceProperty__default = /*#__PURE__*/_interopDefault(_flatInstanceProperty);
|
|
60
|
-
var _Array$from3__default = /*#__PURE__*/_interopDefault(_Array$from3);
|
|
61
66
|
var _forEachInstanceProperty__default = /*#__PURE__*/_interopDefault(_forEachInstanceProperty);
|
|
62
67
|
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
63
68
|
var _filterInstanceProperty__default = /*#__PURE__*/_interopDefault(_filterInstanceProperty);
|
|
@@ -69,6 +74,7 @@ var escapeHtml__default = /*#__PURE__*/_interopDefault(escapeHtml);
|
|
|
69
74
|
var parse__default = /*#__PURE__*/_interopDefault(parse);
|
|
70
75
|
var isEmpty__default = /*#__PURE__*/_interopDefault(isEmpty$2);
|
|
71
76
|
var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
|
|
77
|
+
var isUrl__default = /*#__PURE__*/_interopDefault(isUrl);
|
|
72
78
|
var _someInstanceProperty__default = /*#__PURE__*/_interopDefault(_someInstanceProperty);
|
|
73
79
|
var _styled__default = /*#__PURE__*/_interopDefault(_styled);
|
|
74
80
|
var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
|
|
@@ -88,7 +94,8 @@ const BLOCK_TAGS = {
|
|
|
88
94
|
pre: 'code',
|
|
89
95
|
li: 'list-item',
|
|
90
96
|
ol: 'numbered-list',
|
|
91
|
-
ul: 'bulleted-list'
|
|
97
|
+
ul: 'bulleted-list',
|
|
98
|
+
a: 'link'
|
|
92
99
|
};
|
|
93
100
|
|
|
94
101
|
// Add a dictionary of mark tags.
|
|
@@ -172,6 +179,13 @@ const Element = _ref => {
|
|
|
172
179
|
}, attributes), {}, {
|
|
173
180
|
children: children
|
|
174
181
|
}));
|
|
182
|
+
case BLOCK_TAGS.a:
|
|
183
|
+
return jsxRuntime.jsx("a", _objectSpread$g(_objectSpread$g({
|
|
184
|
+
style: style
|
|
185
|
+
}, attributes), {}, {
|
|
186
|
+
rel: "noopener noreferrer",
|
|
187
|
+
children: children
|
|
188
|
+
}));
|
|
175
189
|
default:
|
|
176
190
|
return jsxRuntime.jsx("p", _objectSpread$g(_objectSpread$g({
|
|
177
191
|
style: style
|
|
@@ -258,7 +272,7 @@ const toggleMark = (editor, format) => {
|
|
|
258
272
|
const isBlockActive = (editor, format) => {
|
|
259
273
|
const selection = editor.selection;
|
|
260
274
|
if (!selection) return false;
|
|
261
|
-
const _Array$from = _Array$
|
|
275
|
+
const _Array$from = _Array$from__default["default"](slate.Editor.nodes(editor, {
|
|
262
276
|
at: slate.Editor.unhangRange(editor, selection),
|
|
263
277
|
match: n => !slate.Editor.isEditor(n) && slate.Element.isElement(n) && n.type === format
|
|
264
278
|
})),
|
|
@@ -361,9 +375,74 @@ const Softbreaker = {
|
|
|
361
375
|
return html.split(this.placeholderCharacter).join('');
|
|
362
376
|
}
|
|
363
377
|
};
|
|
378
|
+
const isLinkActive = editor => {
|
|
379
|
+
const _Editor$nodes = slate.Editor.nodes(editor, {
|
|
380
|
+
match: n => !slate.Editor.isEditor(n) && slate.Element.isElement(n) && n.type === 'link'
|
|
381
|
+
}),
|
|
382
|
+
_Editor$nodes2 = _slicedToArray(_Editor$nodes, 1),
|
|
383
|
+
link = _Editor$nodes2[0];
|
|
384
|
+
return !!link;
|
|
385
|
+
};
|
|
386
|
+
const unwrapLink = editor => {
|
|
387
|
+
slate.Transforms.unwrapNodes(editor, {
|
|
388
|
+
match: n => !slate.Editor.isEditor(n) && slate.Element.isElement(n) && n.type === 'link'
|
|
389
|
+
});
|
|
390
|
+
};
|
|
391
|
+
const wrapLink = (editor, url) => {
|
|
392
|
+
if (isLinkActive(editor)) {
|
|
393
|
+
unwrapLink(editor);
|
|
394
|
+
}
|
|
395
|
+
const selection = editor.selection;
|
|
396
|
+
const isCollapsed = selection && slate.Range.isCollapsed(selection);
|
|
397
|
+
const linkNode = {
|
|
398
|
+
type: 'link',
|
|
399
|
+
url,
|
|
400
|
+
children: isCollapsed ? [{
|
|
401
|
+
text: url
|
|
402
|
+
}] : []
|
|
403
|
+
};
|
|
404
|
+
if (isCollapsed) {
|
|
405
|
+
slate.Transforms.insertNodes(editor, linkNode);
|
|
406
|
+
} else {
|
|
407
|
+
slate.Transforms.wrapNodes(editor, linkNode, {
|
|
408
|
+
split: true
|
|
409
|
+
});
|
|
410
|
+
slate.Transforms.collapse(editor, {
|
|
411
|
+
edge: 'end'
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
const withLinks = editor => {
|
|
416
|
+
const insertText = editor.insertText,
|
|
417
|
+
insertData = editor.insertData,
|
|
418
|
+
isInline = editor.isInline;
|
|
419
|
+
|
|
420
|
+
// Mark link elements as inline (from example)
|
|
421
|
+
editor.isInline = element => {
|
|
422
|
+
return element.type === 'link' || isInline(element);
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
// Handle URL pasting/typing to automatically create links (from example)
|
|
426
|
+
editor.insertText = text => {
|
|
427
|
+
if (text && isUrl__default["default"](text)) {
|
|
428
|
+
wrapLink(editor, text);
|
|
429
|
+
} else {
|
|
430
|
+
insertText(text);
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
editor.insertData = data => {
|
|
434
|
+
const text = data.getData('text/plain');
|
|
435
|
+
if (text && isUrl__default["default"](text)) {
|
|
436
|
+
wrapLink(editor, text);
|
|
437
|
+
} else {
|
|
438
|
+
insertData(data);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
return editor;
|
|
442
|
+
};
|
|
364
443
|
|
|
365
444
|
function ownKeys$f(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
366
|
-
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
445
|
+
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var _context8, _context9; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context8 = ownKeys$f(Object(t), !0)).call(_context8, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context9 = ownKeys$f(Object(t))).call(_context9, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
367
446
|
|
|
368
447
|
// Slate's way of providing custom type annotations comes down to extending `CustomTypes` interface
|
|
369
448
|
// more: https://docs.slatejs.org/concepts/12-typescript
|
|
@@ -400,15 +479,16 @@ const serializeNode = node => {
|
|
|
400
479
|
return string;
|
|
401
480
|
}
|
|
402
481
|
const children = _mapInstanceProperty__default["default"](_context = node.children).call(_context, serializeNode).join('');
|
|
403
|
-
|
|
482
|
+
const element = node; // Use updated CustomElement
|
|
483
|
+
|
|
484
|
+
switch (element.type) {
|
|
404
485
|
case 'block-quote':
|
|
405
486
|
return `<blockquote>${children}</blockquote>`;
|
|
406
487
|
case 'paragraph':
|
|
407
488
|
return `<p>${children}</p>`;
|
|
408
489
|
case 'code':
|
|
409
490
|
return `<pre>
|
|
410
|
-
<code>${children}</code
|
|
411
|
-
</pre>`;
|
|
491
|
+
<code>${children}</code>`;
|
|
412
492
|
case 'span':
|
|
413
493
|
return `<span>${children}</span>`;
|
|
414
494
|
case 'bulleted-list':
|
|
@@ -417,6 +497,36 @@ const serializeNode = node => {
|
|
|
417
497
|
return `<ol>${children}</ol>`;
|
|
418
498
|
case 'list-item':
|
|
419
499
|
return `<li>${children}</li>`;
|
|
500
|
+
case BLOCK_TAGS.a:
|
|
501
|
+
// Handle link serialization
|
|
502
|
+
// eslint-disable-next-line no-case-declarations
|
|
503
|
+
let hrefAttr = '';
|
|
504
|
+
if (element.url) {
|
|
505
|
+
// Sanitize href to prevent javascript: URLs during serialization as well
|
|
506
|
+
const sanitizedUrl = (_context2 => {
|
|
507
|
+
const url = _trimInstanceProperty__default["default"](_context2 = String(element.url)).call(_context2).toLowerCase();
|
|
508
|
+
if (_startsWithInstanceProperty__default["default"](url).call(url, 'javascript:') || _startsWithInstanceProperty__default["default"](url).call(url, 'data:') || _startsWithInstanceProperty__default["default"](url).call(url, 'vbscript:')) {
|
|
509
|
+
return '#';
|
|
510
|
+
}
|
|
511
|
+
return String(element.url);
|
|
512
|
+
})();
|
|
513
|
+
hrefAttr = ` href="${escapeHtml__default["default"](sanitizedUrl)}"`;
|
|
514
|
+
}
|
|
515
|
+
// eslint-disable-next-line no-case-declarations
|
|
516
|
+
let otherAttrsString = '';
|
|
517
|
+
if (element.htmlAttributes && typeof element.htmlAttributes === 'object') {
|
|
518
|
+
for (const _ref of _Object$entries__default["default"](element.htmlAttributes)) {
|
|
519
|
+
var _context3;
|
|
520
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
521
|
+
const key = _ref2[0];
|
|
522
|
+
const value = _ref2[1];
|
|
523
|
+
// Strip event handlers during serialization too
|
|
524
|
+
if (!_startsWithInstanceProperty__default["default"](_context3 = key.toLowerCase()).call(_context3, 'on')) {
|
|
525
|
+
otherAttrsString += ` ${escapeHtml__default["default"](key)}="${escapeHtml__default["default"](String(value))}"`;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
return `<a${hrefAttr}${otherAttrsString}>${children}</a>`;
|
|
420
530
|
case 'heading-one':
|
|
421
531
|
return `<h1>${children}</h1>`;
|
|
422
532
|
case 'heading-two':
|
|
@@ -424,7 +534,7 @@ const serializeNode = node => {
|
|
|
424
534
|
case 'heading-three':
|
|
425
535
|
return `<h3>${children}</h3>`;
|
|
426
536
|
case 'heading-four':
|
|
427
|
-
return `<h4
|
|
537
|
+
return `<h4>${children}</h4>`;
|
|
428
538
|
case 'heading-five':
|
|
429
539
|
return `<h5>${children}</h5>`;
|
|
430
540
|
default:
|
|
@@ -446,6 +556,35 @@ const serialize = value => {
|
|
|
446
556
|
return outputHtml;
|
|
447
557
|
};
|
|
448
558
|
const ELEMENT_TAGS = {
|
|
559
|
+
A: el => {
|
|
560
|
+
const props = {
|
|
561
|
+
type: BLOCK_TAGS.a
|
|
562
|
+
};
|
|
563
|
+
const htmlAttributes = {};
|
|
564
|
+
for (const attr of _Array$from__default["default"](el.attributes)) {
|
|
565
|
+
const attrName = attr.name.toLowerCase();
|
|
566
|
+
const attrValue = attr.value;
|
|
567
|
+
if (attrName === 'href') {
|
|
568
|
+
var _context4;
|
|
569
|
+
// Sanitize href to prevent javascript: URLs
|
|
570
|
+
const sanitizedValue = _trimInstanceProperty__default["default"](_context4 = decodeURI(attrValue)).call(_context4).toLowerCase();
|
|
571
|
+
if (
|
|
572
|
+
// eslint-disable-next-line no-script-url
|
|
573
|
+
_startsWithInstanceProperty__default["default"](sanitizedValue).call(sanitizedValue, 'javascript:') || _startsWithInstanceProperty__default["default"](sanitizedValue).call(sanitizedValue, 'data:') || _startsWithInstanceProperty__default["default"](sanitizedValue).call(sanitizedValue, 'vbscript:')) {
|
|
574
|
+
props.url = '#'; // Replace with a safe value
|
|
575
|
+
} else {
|
|
576
|
+
props.url = attrValue;
|
|
577
|
+
}
|
|
578
|
+
} else if (!_startsWithInstanceProperty__default["default"](attrName).call(attrName, 'on')) {
|
|
579
|
+
// Strip event handlers
|
|
580
|
+
htmlAttributes[attrName] = attrValue;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
if (_Object$keys__default["default"](htmlAttributes).length > 0) {
|
|
584
|
+
props.htmlAttributes = htmlAttributes;
|
|
585
|
+
}
|
|
586
|
+
return props;
|
|
587
|
+
},
|
|
449
588
|
BLOCKQUOTE: () => ({
|
|
450
589
|
type: 'quote'
|
|
451
590
|
}),
|
|
@@ -551,7 +690,7 @@ const wrapWithParagraph = textContent => slateHyperscript.jsx('element', {
|
|
|
551
690
|
const wrapWithParagraphIfRootElement = (el, textContent) => el.parentNode?.nodeName === 'BODY' // root element, because body is eventually turned to React fragment
|
|
552
691
|
? wrapWithParagraph(textContent) : textContent;
|
|
553
692
|
const deserializeElement = el => {
|
|
554
|
-
var
|
|
693
|
+
var _context5, _context6;
|
|
555
694
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#value
|
|
556
695
|
if (el.nodeType === 3) {
|
|
557
696
|
return wrapWithParagraphIfRootElement(el, {
|
|
@@ -568,7 +707,7 @@ const deserializeElement = el => {
|
|
|
568
707
|
if (nodeName === 'PRE' && el.childNodes[0] && el.childNodes[0].nodeName === 'CODE') {
|
|
569
708
|
parent = el.childNodes[0];
|
|
570
709
|
}
|
|
571
|
-
let children = _flatInstanceProperty__default["default"](
|
|
710
|
+
let children = _flatInstanceProperty__default["default"](_context5 = _mapInstanceProperty__default["default"](_context6 = _Array$from__default["default"](parent.childNodes)).call(_context6, deserializeElement)).call(_context5);
|
|
572
711
|
if (children.length === 0) {
|
|
573
712
|
children = [{
|
|
574
713
|
text: ''
|
|
@@ -587,11 +726,11 @@ const deserializeElement = el => {
|
|
|
587
726
|
type: 'span'
|
|
588
727
|
}, children));
|
|
589
728
|
} else {
|
|
590
|
-
var
|
|
591
|
-
attrs = _reduceInstanceProperty__default["default"](
|
|
592
|
-
let
|
|
593
|
-
key =
|
|
594
|
-
value =
|
|
729
|
+
var _context7;
|
|
730
|
+
attrs = _reduceInstanceProperty__default["default"](_context7 = _Object$entries__default["default"](styleObj || {})).call(_context7, (mappedAttrObj, _ref3) => {
|
|
731
|
+
let _ref4 = _slicedToArray(_ref3, 2),
|
|
732
|
+
key = _ref4[0],
|
|
733
|
+
value = _ref4[1];
|
|
595
734
|
const values = value.split(' '); // to cover the case of space-separated values e.g. `text-decoration-line: "underline line-through"`
|
|
596
735
|
|
|
597
736
|
_forEachInstanceProperty__default["default"](values).call(values, splittedValue => {
|
|
@@ -613,8 +752,11 @@ const deserializeElement = el => {
|
|
|
613
752
|
_mapInstanceProperty__default["default"](children).call(children, child => slate.Text.isText(child) ? slateHyperscript.jsx('text', attrs, child) : slateHyperscript.jsx('element', attrs, child)));
|
|
614
753
|
}
|
|
615
754
|
}
|
|
755
|
+
|
|
756
|
+
// Modified to use the updated ELEMENT_TAGS for 'A'
|
|
616
757
|
if (ELEMENT_TAGS[nodeName]) {
|
|
617
|
-
const attrs = ELEMENT_TAGS[nodeName](
|
|
758
|
+
const attrs = ELEMENT_TAGS[nodeName](el // Pass element to access its attributes
|
|
759
|
+
);
|
|
618
760
|
return slateHyperscript.jsx('element', attrs, children);
|
|
619
761
|
}
|
|
620
762
|
if (TEXT_TAGS[nodeName]) {
|
|
@@ -1731,7 +1873,7 @@ RichTextEditorBody.displayName = 'RichTextEditorBody';
|
|
|
1731
1873
|
var RichTextEditorBody$1 = RichTextEditorBody;
|
|
1732
1874
|
|
|
1733
1875
|
// NOTE: This string will be replaced on build time with the package version.
|
|
1734
|
-
var version = "19.
|
|
1876
|
+
var version = "19.25.0";
|
|
1735
1877
|
|
|
1736
1878
|
exports.Element = Element;
|
|
1737
1879
|
exports.HiddenInput = HiddenInput$1;
|
|
@@ -1749,3 +1891,4 @@ exports.toggleBlock = toggleBlock;
|
|
|
1749
1891
|
exports.toggleMark = toggleMark;
|
|
1750
1892
|
exports.validSlateStateAdapter = validSlateStateAdapter;
|
|
1751
1893
|
exports.version = version;
|
|
1894
|
+
exports.withLinks = withLinks;
|
|
@@ -8,9 +8,11 @@ import { warning } from '@commercetools-uikit/utils';
|
|
|
8
8
|
import uniq from 'lodash/uniq';
|
|
9
9
|
import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
|
|
10
10
|
import _mapInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/map';
|
|
11
|
+
import _trimInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/trim';
|
|
12
|
+
import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
|
|
11
13
|
import _Array$isArray from '@babel/runtime-corejs3/core-js-stable/array/is-array';
|
|
14
|
+
import _Array$from from '@babel/runtime-corejs3/core-js-stable/array/from';
|
|
12
15
|
import _flatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/flat';
|
|
13
|
-
import _Array$from3 from '@babel/runtime-corejs3/core-js-stable/array/from';
|
|
14
16
|
import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/for-each';
|
|
15
17
|
import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols';
|
|
16
18
|
import _filterInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/filter';
|
|
@@ -19,16 +21,17 @@ import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-st
|
|
|
19
21
|
import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
|
|
20
22
|
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
|
|
21
23
|
import escapeHtml from 'escape-html';
|
|
22
|
-
import { Editor, Element as Element$1, Transforms, Text } from 'slate';
|
|
24
|
+
import { Editor, Element as Element$1, Transforms, Text, Range } from 'slate';
|
|
23
25
|
import { jsx as jsx$1 } from 'slate-hyperscript';
|
|
24
26
|
import parse from 'style-to-object';
|
|
25
27
|
import isEmpty$2 from 'lodash/isEmpty';
|
|
26
28
|
import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
|
|
29
|
+
import { useCallback, forwardRef } from 'react';
|
|
27
30
|
import { ReactEditor, useSlate } from 'slate-react';
|
|
31
|
+
import isUrl from 'is-url';
|
|
28
32
|
import { jsx, jsxs, Fragment } from '@emotion/react/jsx-runtime';
|
|
29
33
|
import _someInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/some';
|
|
30
34
|
import _pt from 'prop-types';
|
|
31
|
-
import { useCallback, forwardRef } from 'react';
|
|
32
35
|
import { accessibleHiddenInputStyles } from '@commercetools-uikit/input-utils';
|
|
33
36
|
import _objectWithoutProperties from '@babel/runtime-corejs3/helpers/esm/objectWithoutProperties';
|
|
34
37
|
import _styled from '@emotion/styled/base';
|
|
@@ -53,7 +56,8 @@ const BLOCK_TAGS = {
|
|
|
53
56
|
pre: 'code',
|
|
54
57
|
li: 'list-item',
|
|
55
58
|
ol: 'numbered-list',
|
|
56
|
-
ul: 'bulleted-list'
|
|
59
|
+
ul: 'bulleted-list',
|
|
60
|
+
a: 'link'
|
|
57
61
|
};
|
|
58
62
|
|
|
59
63
|
// Add a dictionary of mark tags.
|
|
@@ -137,6 +141,13 @@ const Element = _ref => {
|
|
|
137
141
|
}, attributes), {}, {
|
|
138
142
|
children: children
|
|
139
143
|
}));
|
|
144
|
+
case BLOCK_TAGS.a:
|
|
145
|
+
return jsx("a", _objectSpread$g(_objectSpread$g({
|
|
146
|
+
style: style
|
|
147
|
+
}, attributes), {}, {
|
|
148
|
+
rel: "noopener noreferrer",
|
|
149
|
+
children: children
|
|
150
|
+
}));
|
|
140
151
|
default:
|
|
141
152
|
return jsx("p", _objectSpread$g(_objectSpread$g({
|
|
142
153
|
style: style
|
|
@@ -223,11 +234,11 @@ const toggleMark = (editor, format) => {
|
|
|
223
234
|
const isBlockActive = (editor, format) => {
|
|
224
235
|
const selection = editor.selection;
|
|
225
236
|
if (!selection) return false;
|
|
226
|
-
const _Array$from = _Array$
|
|
237
|
+
const _Array$from$1 = _Array$from(Editor.nodes(editor, {
|
|
227
238
|
at: Editor.unhangRange(editor, selection),
|
|
228
239
|
match: n => !Editor.isEditor(n) && Element$1.isElement(n) && n.type === format
|
|
229
240
|
})),
|
|
230
|
-
_Array$from2 = _slicedToArray(_Array$from, 1),
|
|
241
|
+
_Array$from2 = _slicedToArray(_Array$from$1, 1),
|
|
231
242
|
match = _Array$from2[0];
|
|
232
243
|
return Boolean(match);
|
|
233
244
|
};
|
|
@@ -326,9 +337,74 @@ const Softbreaker = {
|
|
|
326
337
|
return html.split(this.placeholderCharacter).join('');
|
|
327
338
|
}
|
|
328
339
|
};
|
|
340
|
+
const isLinkActive = editor => {
|
|
341
|
+
const _Editor$nodes = Editor.nodes(editor, {
|
|
342
|
+
match: n => !Editor.isEditor(n) && Element$1.isElement(n) && n.type === 'link'
|
|
343
|
+
}),
|
|
344
|
+
_Editor$nodes2 = _slicedToArray(_Editor$nodes, 1),
|
|
345
|
+
link = _Editor$nodes2[0];
|
|
346
|
+
return !!link;
|
|
347
|
+
};
|
|
348
|
+
const unwrapLink = editor => {
|
|
349
|
+
Transforms.unwrapNodes(editor, {
|
|
350
|
+
match: n => !Editor.isEditor(n) && Element$1.isElement(n) && n.type === 'link'
|
|
351
|
+
});
|
|
352
|
+
};
|
|
353
|
+
const wrapLink = (editor, url) => {
|
|
354
|
+
if (isLinkActive(editor)) {
|
|
355
|
+
unwrapLink(editor);
|
|
356
|
+
}
|
|
357
|
+
const selection = editor.selection;
|
|
358
|
+
const isCollapsed = selection && Range.isCollapsed(selection);
|
|
359
|
+
const linkNode = {
|
|
360
|
+
type: 'link',
|
|
361
|
+
url,
|
|
362
|
+
children: isCollapsed ? [{
|
|
363
|
+
text: url
|
|
364
|
+
}] : []
|
|
365
|
+
};
|
|
366
|
+
if (isCollapsed) {
|
|
367
|
+
Transforms.insertNodes(editor, linkNode);
|
|
368
|
+
} else {
|
|
369
|
+
Transforms.wrapNodes(editor, linkNode, {
|
|
370
|
+
split: true
|
|
371
|
+
});
|
|
372
|
+
Transforms.collapse(editor, {
|
|
373
|
+
edge: 'end'
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
const withLinks = editor => {
|
|
378
|
+
const insertText = editor.insertText,
|
|
379
|
+
insertData = editor.insertData,
|
|
380
|
+
isInline = editor.isInline;
|
|
381
|
+
|
|
382
|
+
// Mark link elements as inline (from example)
|
|
383
|
+
editor.isInline = element => {
|
|
384
|
+
return element.type === 'link' || isInline(element);
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// Handle URL pasting/typing to automatically create links (from example)
|
|
388
|
+
editor.insertText = text => {
|
|
389
|
+
if (text && isUrl(text)) {
|
|
390
|
+
wrapLink(editor, text);
|
|
391
|
+
} else {
|
|
392
|
+
insertText(text);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
editor.insertData = data => {
|
|
396
|
+
const text = data.getData('text/plain');
|
|
397
|
+
if (text && isUrl(text)) {
|
|
398
|
+
wrapLink(editor, text);
|
|
399
|
+
} else {
|
|
400
|
+
insertData(data);
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
return editor;
|
|
404
|
+
};
|
|
329
405
|
|
|
330
406
|
function ownKeys$f(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
331
|
-
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
407
|
+
function _objectSpread$f(e) { for (var r = 1; r < arguments.length; r++) { var _context8, _context9; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context8 = ownKeys$f(Object(t), !0)).call(_context8, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context9 = ownKeys$f(Object(t))).call(_context9, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
332
408
|
|
|
333
409
|
// Slate's way of providing custom type annotations comes down to extending `CustomTypes` interface
|
|
334
410
|
// more: https://docs.slatejs.org/concepts/12-typescript
|
|
@@ -365,15 +441,16 @@ const serializeNode = node => {
|
|
|
365
441
|
return string;
|
|
366
442
|
}
|
|
367
443
|
const children = _mapInstanceProperty(_context = node.children).call(_context, serializeNode).join('');
|
|
368
|
-
|
|
444
|
+
const element = node; // Use updated CustomElement
|
|
445
|
+
|
|
446
|
+
switch (element.type) {
|
|
369
447
|
case 'block-quote':
|
|
370
448
|
return `<blockquote>${children}</blockquote>`;
|
|
371
449
|
case 'paragraph':
|
|
372
450
|
return `<p>${children}</p>`;
|
|
373
451
|
case 'code':
|
|
374
452
|
return `<pre>
|
|
375
|
-
<code>${children}</code
|
|
376
|
-
</pre>`;
|
|
453
|
+
<code>${children}</code>`;
|
|
377
454
|
case 'span':
|
|
378
455
|
return `<span>${children}</span>`;
|
|
379
456
|
case 'bulleted-list':
|
|
@@ -382,6 +459,36 @@ const serializeNode = node => {
|
|
|
382
459
|
return `<ol>${children}</ol>`;
|
|
383
460
|
case 'list-item':
|
|
384
461
|
return `<li>${children}</li>`;
|
|
462
|
+
case BLOCK_TAGS.a:
|
|
463
|
+
// Handle link serialization
|
|
464
|
+
// eslint-disable-next-line no-case-declarations
|
|
465
|
+
let hrefAttr = '';
|
|
466
|
+
if (element.url) {
|
|
467
|
+
// Sanitize href to prevent javascript: URLs during serialization as well
|
|
468
|
+
const sanitizedUrl = (_context2 => {
|
|
469
|
+
const url = _trimInstanceProperty(_context2 = String(element.url)).call(_context2).toLowerCase();
|
|
470
|
+
if (_startsWithInstanceProperty(url).call(url, 'javascript:') || _startsWithInstanceProperty(url).call(url, 'data:') || _startsWithInstanceProperty(url).call(url, 'vbscript:')) {
|
|
471
|
+
return '#';
|
|
472
|
+
}
|
|
473
|
+
return String(element.url);
|
|
474
|
+
})();
|
|
475
|
+
hrefAttr = ` href="${escapeHtml(sanitizedUrl)}"`;
|
|
476
|
+
}
|
|
477
|
+
// eslint-disable-next-line no-case-declarations
|
|
478
|
+
let otherAttrsString = '';
|
|
479
|
+
if (element.htmlAttributes && typeof element.htmlAttributes === 'object') {
|
|
480
|
+
for (const _ref of _Object$entries(element.htmlAttributes)) {
|
|
481
|
+
var _context3;
|
|
482
|
+
var _ref2 = _slicedToArray(_ref, 2);
|
|
483
|
+
const key = _ref2[0];
|
|
484
|
+
const value = _ref2[1];
|
|
485
|
+
// Strip event handlers during serialization too
|
|
486
|
+
if (!_startsWithInstanceProperty(_context3 = key.toLowerCase()).call(_context3, 'on')) {
|
|
487
|
+
otherAttrsString += ` ${escapeHtml(key)}="${escapeHtml(String(value))}"`;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return `<a${hrefAttr}${otherAttrsString}>${children}</a>`;
|
|
385
492
|
case 'heading-one':
|
|
386
493
|
return `<h1>${children}</h1>`;
|
|
387
494
|
case 'heading-two':
|
|
@@ -389,7 +496,7 @@ const serializeNode = node => {
|
|
|
389
496
|
case 'heading-three':
|
|
390
497
|
return `<h3>${children}</h3>`;
|
|
391
498
|
case 'heading-four':
|
|
392
|
-
return `<h4
|
|
499
|
+
return `<h4>${children}</h4>`;
|
|
393
500
|
case 'heading-five':
|
|
394
501
|
return `<h5>${children}</h5>`;
|
|
395
502
|
default:
|
|
@@ -411,6 +518,35 @@ const serialize = value => {
|
|
|
411
518
|
return outputHtml;
|
|
412
519
|
};
|
|
413
520
|
const ELEMENT_TAGS = {
|
|
521
|
+
A: el => {
|
|
522
|
+
const props = {
|
|
523
|
+
type: BLOCK_TAGS.a
|
|
524
|
+
};
|
|
525
|
+
const htmlAttributes = {};
|
|
526
|
+
for (const attr of _Array$from(el.attributes)) {
|
|
527
|
+
const attrName = attr.name.toLowerCase();
|
|
528
|
+
const attrValue = attr.value;
|
|
529
|
+
if (attrName === 'href') {
|
|
530
|
+
var _context4;
|
|
531
|
+
// Sanitize href to prevent javascript: URLs
|
|
532
|
+
const sanitizedValue = _trimInstanceProperty(_context4 = decodeURI(attrValue)).call(_context4).toLowerCase();
|
|
533
|
+
if (
|
|
534
|
+
// eslint-disable-next-line no-script-url
|
|
535
|
+
_startsWithInstanceProperty(sanitizedValue).call(sanitizedValue, 'javascript:') || _startsWithInstanceProperty(sanitizedValue).call(sanitizedValue, 'data:') || _startsWithInstanceProperty(sanitizedValue).call(sanitizedValue, 'vbscript:')) {
|
|
536
|
+
props.url = '#'; // Replace with a safe value
|
|
537
|
+
} else {
|
|
538
|
+
props.url = attrValue;
|
|
539
|
+
}
|
|
540
|
+
} else if (!_startsWithInstanceProperty(attrName).call(attrName, 'on')) {
|
|
541
|
+
// Strip event handlers
|
|
542
|
+
htmlAttributes[attrName] = attrValue;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
if (_Object$keys(htmlAttributes).length > 0) {
|
|
546
|
+
props.htmlAttributes = htmlAttributes;
|
|
547
|
+
}
|
|
548
|
+
return props;
|
|
549
|
+
},
|
|
414
550
|
BLOCKQUOTE: () => ({
|
|
415
551
|
type: 'quote'
|
|
416
552
|
}),
|
|
@@ -516,7 +652,7 @@ const wrapWithParagraph = textContent => jsx$1('element', {
|
|
|
516
652
|
const wrapWithParagraphIfRootElement = (el, textContent) => el.parentNode?.nodeName === 'BODY' // root element, because body is eventually turned to React fragment
|
|
517
653
|
? wrapWithParagraph(textContent) : textContent;
|
|
518
654
|
const deserializeElement = el => {
|
|
519
|
-
var
|
|
655
|
+
var _context5, _context6;
|
|
520
656
|
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#value
|
|
521
657
|
if (el.nodeType === 3) {
|
|
522
658
|
return wrapWithParagraphIfRootElement(el, {
|
|
@@ -533,7 +669,7 @@ const deserializeElement = el => {
|
|
|
533
669
|
if (nodeName === 'PRE' && el.childNodes[0] && el.childNodes[0].nodeName === 'CODE') {
|
|
534
670
|
parent = el.childNodes[0];
|
|
535
671
|
}
|
|
536
|
-
let children = _flatInstanceProperty(
|
|
672
|
+
let children = _flatInstanceProperty(_context5 = _mapInstanceProperty(_context6 = _Array$from(parent.childNodes)).call(_context6, deserializeElement)).call(_context5);
|
|
537
673
|
if (children.length === 0) {
|
|
538
674
|
children = [{
|
|
539
675
|
text: ''
|
|
@@ -552,11 +688,11 @@ const deserializeElement = el => {
|
|
|
552
688
|
type: 'span'
|
|
553
689
|
}, children));
|
|
554
690
|
} else {
|
|
555
|
-
var
|
|
556
|
-
attrs = _reduceInstanceProperty(
|
|
557
|
-
let
|
|
558
|
-
key =
|
|
559
|
-
value =
|
|
691
|
+
var _context7;
|
|
692
|
+
attrs = _reduceInstanceProperty(_context7 = _Object$entries(styleObj || {})).call(_context7, (mappedAttrObj, _ref3) => {
|
|
693
|
+
let _ref4 = _slicedToArray(_ref3, 2),
|
|
694
|
+
key = _ref4[0],
|
|
695
|
+
value = _ref4[1];
|
|
560
696
|
const values = value.split(' '); // to cover the case of space-separated values e.g. `text-decoration-line: "underline line-through"`
|
|
561
697
|
|
|
562
698
|
_forEachInstanceProperty(values).call(values, splittedValue => {
|
|
@@ -578,8 +714,11 @@ const deserializeElement = el => {
|
|
|
578
714
|
_mapInstanceProperty(children).call(children, child => Text.isText(child) ? jsx$1('text', attrs, child) : jsx$1('element', attrs, child)));
|
|
579
715
|
}
|
|
580
716
|
}
|
|
717
|
+
|
|
718
|
+
// Modified to use the updated ELEMENT_TAGS for 'A'
|
|
581
719
|
if (ELEMENT_TAGS[nodeName]) {
|
|
582
|
-
const attrs = ELEMENT_TAGS[nodeName](
|
|
720
|
+
const attrs = ELEMENT_TAGS[nodeName](el // Pass element to access its attributes
|
|
721
|
+
);
|
|
583
722
|
return jsx$1('element', attrs, children);
|
|
584
723
|
}
|
|
585
724
|
if (TEXT_TAGS[nodeName]) {
|
|
@@ -1802,6 +1941,6 @@ RichTextEditorBody.displayName = 'RichTextEditorBody';
|
|
|
1802
1941
|
var RichTextEditorBody$1 = RichTextEditorBody;
|
|
1803
1942
|
|
|
1804
1943
|
// NOTE: This string will be replaced on build time with the package version.
|
|
1805
|
-
var version = "19.
|
|
1944
|
+
var version = "19.25.0";
|
|
1806
1945
|
|
|
1807
|
-
export { Element, HiddenInput$1 as HiddenInput, Leaf, RichTextEditorBody$1 as RichTextBody, Softbreaker, focusEditor, html$1 as html, isBlockActive, isRichTextEmpty as isEmpty, isMarkActive, index as localized, resetEditor, toggleBlock, toggleMark, validSlateStateAdapter, version };
|
|
1946
|
+
export { Element, HiddenInput$1 as HiddenInput, Leaf, RichTextEditorBody$1 as RichTextBody, Softbreaker, focusEditor, html$1 as html, isBlockActive, isRichTextEmpty as isEmpty, isMarkActive, index as localized, resetEditor, toggleBlock, toggleMark, validSlateStateAdapter, version, withLinks };
|
|
@@ -3,4 +3,4 @@ export { default as html } from "./html/index.js";
|
|
|
3
3
|
export { default as isEmpty } from "./is-empty/index.js";
|
|
4
4
|
export { HiddenInput, RichTextBody } from "./rich-text-body/index.js";
|
|
5
5
|
export { default as version } from "./version.js";
|
|
6
|
-
export { Element, Leaf, Softbreaker, isMarkActive, isBlockActive, toggleMark, toggleBlock, validSlateStateAdapter, resetEditor, focusEditor, } from "./slate-helpers.js";
|
|
6
|
+
export { Element, Leaf, Softbreaker, isMarkActive, isBlockActive, toggleMark, toggleBlock, validSlateStateAdapter, resetEditor, focusEditor, withLinks, } from "./slate-helpers.js";
|
|
@@ -37,4 +37,9 @@ declare const Softbreaker: {
|
|
|
37
37
|
*/
|
|
38
38
|
cleanHtml(html: string): string;
|
|
39
39
|
};
|
|
40
|
-
export
|
|
40
|
+
export declare const isLinkActive: (editor: Editor) => boolean;
|
|
41
|
+
export declare const unwrapLink: (editor: Editor) => void;
|
|
42
|
+
export declare const wrapLink: (editor: Editor, url: string) => void;
|
|
43
|
+
export declare const insertLink: (editor: Editor, url: string) => void;
|
|
44
|
+
declare const withLinks: (editor: Editor) => Editor;
|
|
45
|
+
export { Element, Leaf, Softbreaker, isMarkActive, isBlockActive, toggleMark, toggleBlock, validSlateStateAdapter, resetEditor, focusEditor, withLinks, };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools-uikit/rich-text-utils",
|
|
3
3
|
"description": "Utilities for working with rich-text components.",
|
|
4
|
-
"version": "19.
|
|
4
|
+
"version": "19.25.0",
|
|
5
5
|
"bugs": "https://github.com/commercetools/ui-kit/issues",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -24,18 +24,19 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@babel/runtime": "^7.20.13",
|
|
26
26
|
"@babel/runtime-corejs3": "^7.20.13",
|
|
27
|
-
"@commercetools-uikit/design-system": "19.
|
|
28
|
-
"@commercetools-uikit/icons": "19.
|
|
29
|
-
"@commercetools-uikit/input-utils": "19.
|
|
30
|
-
"@commercetools-uikit/spacings-inline": "19.
|
|
31
|
-
"@commercetools-uikit/tooltip": "19.
|
|
32
|
-
"@commercetools-uikit/utils": "19.
|
|
27
|
+
"@commercetools-uikit/design-system": "19.25.0",
|
|
28
|
+
"@commercetools-uikit/icons": "19.25.0",
|
|
29
|
+
"@commercetools-uikit/input-utils": "19.25.0",
|
|
30
|
+
"@commercetools-uikit/spacings-inline": "19.25.0",
|
|
31
|
+
"@commercetools-uikit/tooltip": "19.25.0",
|
|
32
|
+
"@commercetools-uikit/utils": "19.25.0",
|
|
33
33
|
"@emotion/react": "^11.10.5",
|
|
34
34
|
"@emotion/styled": "^11.10.5",
|
|
35
35
|
"@types/escape-html": "1.0.4",
|
|
36
36
|
"downshift": "6.1.12",
|
|
37
37
|
"escape-html": "1.0.3",
|
|
38
38
|
"is-hotkey": "0.2.0",
|
|
39
|
+
"is-url": "^1.2.4",
|
|
39
40
|
"lodash": "4.17.21",
|
|
40
41
|
"prop-types": "15.8.1",
|
|
41
42
|
"slate": "0.75.0",
|