@yoopta/link 1.9.10-rc → 1.9.12-rc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +302 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1 +1,302 @@
1
- import{jsx as e}from"react/jsx-runtime";import{Transforms as t,Editor as n,Element as r,Range as i,Node as o}from"slate";import{isElementActive as a,generateId as s,cx as l,HOTKEYS as d,createYooptaPlugin as c,getElementByPath as u,getElementClassname as m}from"@yoopta/editor";import{useState as p,useEffect as f}from"react";var h=function(e){if("string"!=typeof e)return!1;var t=e.match(v);if(!t)return!1;var n=t[1];if(!n)return!1;if(g.test(n)||y.test(n))return!0;return!1},v=/^(?:\w+:)?\/\/(\S+)$/,g=/^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/,y=/^[^\s\.]+\.\S{2,}$/;const k=(e,o)=>{a(e,"link")&&(e=>{console.log("removeLinkNode editor selection",e.selection),t.unwrapNodes(e,{match:e=>!n.isEditor(e)&&r.isElement(e)&&"link"===e.type})})(e);const{selection:l}=e,d=l&&i.isCollapsed(l),c={id:s(),type:"link",data:{url:o,skipDrag:!0},children:d?[{text:o}]:[],nodeType:"inline"};d?t.insertNodes(e,c):(t.wrapNodes(e,c,{split:!0}),t.collapse(e,{edge:"end"}))};function w(e,t){void 0===t&&(t={});var n=t.insertAt;if(e&&"undefined"!=typeof document){var r=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===n&&r.firstChild?r.insertBefore(i,r.firstChild):r.appendChild(i),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(document.createTextNode(e))}}var N="RvZCjRoG",E="BcbwmZV8";w(".RvZCjRoG{color:#007aff;cursor:text;font-style:normal;font-weight:400;position:relative;text-decoration-line:underline}.BcbwmZV8{cursor:pointer}");const b=({attributes:t,element:n,children:r,HTMLAttributes:i})=>{const[o,a]=p(!1),[s,c]=p(!1);return f((()=>{const e=e=>{d.isCmd(e)&&c(!0)};return o&&(null===document||void 0===document||document.addEventListener("keydown",e)),()=>{null===document||void 0===document||document.removeEventListener("keydown",e)}}),[o,s]),e("a",Object.assign({draggable:!1,href:n.data.url||"",rel:"noreferrer",target:"_blank",className:l(N,{[E]:s&&o}),onClick:e=>{var t;if(!(s&&"string"==typeof n.data.url&&(null===(t=n.data.url)||void 0===t?void 0:t.length)>0))return e.preventDefault();window.open(n.data.url,"_blank")},onMouseEnter:()=>a(!0),onMouseLeave:()=>{c(!1),a(!1)}},i,t,{children:r}))};var x="WX97Rghx";w(".WX97Rghx{color:#007aff;cursor:pointer;font-style:normal;font-weight:400;position:relative;text-decoration-line:underline}");const D=({attributes:t,element:n,children:r,HTMLAttributes:i})=>e("a",Object.assign({draggable:!1,href:n.data.url||"",rel:"noreferrer",target:"_blank",onClick:e=>{if(e.preventDefault(),!n.data.url)return;new URL(n.data.url).host===window.location.host?window.open(n.data.url,"_self"):window.open(n.data.url,"_blank")}},i,{className:m({element:n,HTMLAttributes:i,className:x})},t,{children:r}));D.displayName="Link";const C="link",T=c({type:C,renderer:{editor:()=>b,render:D},defineElement:()=>({id:s(),type:"link",children:[{text:""}],nodeType:"inline",data:{url:null,skipDrag:!0}}),extendEditor(e){const{insertData:n,insertText:i,isInline:a,normalizeNode:s}=e;return e.isInline=e=>e.type===C||a(e),e.normalizeNode=n=>{var i,a;const[l,d]=n;r.isElement(l)&&l.type===C&&l.children.length>0&&0===(null===(a=null===(i=o.child(l,0))||void 0===i?void 0:i.text)||void 0===a?void 0:a.length)&&t.removeNodes(e,{at:n[1],match:e=>r.isElement(e)&&e.type===C}),s(n)},e.insertText=t=>{t&&h(t)?k(e,t):i(t)},e.insertData=t=>{const r=t.getData("text/plain");r&&h(r)?k(e,r):n(t)},e},events:{onKeyDown:(e,{hotkeys:i})=>o=>{if(!e.selection)return;if(u(e,e.selection.anchor.path).type!==C)return;const{anchor:a}=e.selection;if(i.isEnter(o)){const i=n.isEnd(e,a,a.path),l=n.isStart(e,a,a.path);if(console.log({isStart:l}),l){o.preventDefault();const i=n.above(e,{match:e=>r.isElement(e)&&e.type===C});if(!i)return;const[,a]=i,l=n.parent(e,a),[,d]=l;return t.splitNodes(e,{match:e=>r.isElement(e),mode:"highest",always:!0}),void t.setNodes(e,{id:s()},{at:d,match:e=>r.isElement(e),mode:"highest"})}return i?(o.preventDefault(),n.insertBreak(e),t.setNodes(e,{id:s()}),void t.removeNodes(e,{match:t=>r.isElement(t)&&n.isInline(e,t)&&t.type===C})):void(i||l||(o.preventDefault(),t.splitNodes(e),t.setNodes(e,{id:s()}),t.setNodes(e,{id:s()},{match:t=>r.isElement(t)&&n.isInline(e,t)&&t.type===C})))}if(i.isSpace(o)){const i=n.above(e,{match:t=>r.isElement(t)&&n.isInline(e,t)&&t.type===C,mode:"highest"});if(i){const[,r]=i;if(n.isEnd(e,a,r)){const i=n.after(e,r);t.setSelection(e,{anchor:i,focus:i})}}}else;}},exports:{markdown:{serialize:(e,t)=>`[${t}](${e.data.url})`},html:{serialize:(e,t)=>`<a target="_blank" rel="noopener noreferrer" href="${e.data.url}">${t}</a>`,deserialize:{nodeName:"A",parse:e=>({url:e.getAttribute("href"),skipDrag:!0})}}}});export{T as default};
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Transforms, Editor, Element, Range, Node } from 'slate';
3
+ import { isElementActive, generateId, cx, HOTKEYS, createYooptaPlugin, getElementByPath, getElementClassname } from '@yoopta/editor';
4
+ import { useState, useEffect } from 'react';
5
+
6
+ /**
7
+ * Expose `isUrl`.
8
+ */
9
+
10
+ var isUrl_1 = isUrl;
11
+
12
+ /**
13
+ * RegExps.
14
+ * A URL must match #1 and then at least one of #2/#3.
15
+ * Use two levels of REs to avoid REDOS.
16
+ */
17
+
18
+ var protocolAndDomainRE = /^(?:\w+:)?\/\/(\S+)$/;
19
+
20
+ var localhostDomainRE = /^localhost[\:?\d]*(?:[^\:?\d]\S*)?$/;
21
+ var nonLocalhostDomainRE = /^[^\s\.]+\.\S{2,}$/;
22
+
23
+ /**
24
+ * Loosely validate a URL `string`.
25
+ *
26
+ * @param {String} string
27
+ * @return {Boolean}
28
+ */
29
+
30
+ function isUrl(string){
31
+ if (typeof string !== 'string') {
32
+ return false;
33
+ }
34
+
35
+ var match = string.match(protocolAndDomainRE);
36
+ if (!match) {
37
+ return false;
38
+ }
39
+
40
+ var everythingAfterProtocol = match[1];
41
+ if (!everythingAfterProtocol) {
42
+ return false;
43
+ }
44
+
45
+ if (localhostDomainRE.test(everythingAfterProtocol) ||
46
+ nonLocalhostDomainRE.test(everythingAfterProtocol)) {
47
+ return true;
48
+ }
49
+
50
+ return false;
51
+ }
52
+
53
+ const removeLinkNode = (editor) => {
54
+ console.log('removeLinkNode editor selection', editor.selection);
55
+ Transforms.unwrapNodes(editor, {
56
+ match: (n) => !Editor.isEditor(n) && Element.isElement(n) && n.type === 'link',
57
+ });
58
+ };
59
+
60
+ const addLinkNode = (editor, url) => {
61
+ if (isElementActive(editor, 'link')) {
62
+ removeLinkNode(editor);
63
+ }
64
+ const { selection } = editor;
65
+ const isCollapsed = selection && Range.isCollapsed(selection);
66
+ const link = {
67
+ id: generateId(),
68
+ type: 'link',
69
+ data: { url, skipDrag: true },
70
+ children: isCollapsed ? [{ text: url }] : [],
71
+ nodeType: 'inline',
72
+ };
73
+ if (isCollapsed) {
74
+ Transforms.insertNodes(editor, link);
75
+ }
76
+ else {
77
+ Transforms.wrapNodes(editor, link, { split: true });
78
+ Transforms.collapse(editor, { edge: 'end' });
79
+ }
80
+ };
81
+
82
+ function styleInject(css, ref) {
83
+ if ( ref === void 0 ) ref = {};
84
+ var insertAt = ref.insertAt;
85
+
86
+ if (!css || typeof document === 'undefined') { return; }
87
+
88
+ var head = document.head || document.getElementsByTagName('head')[0];
89
+ var style = document.createElement('style');
90
+ style.type = 'text/css';
91
+
92
+ if (insertAt === 'top') {
93
+ if (head.firstChild) {
94
+ head.insertBefore(style, head.firstChild);
95
+ } else {
96
+ head.appendChild(style);
97
+ }
98
+ } else {
99
+ head.appendChild(style);
100
+ }
101
+
102
+ if (style.styleSheet) {
103
+ style.styleSheet.cssText = css;
104
+ } else {
105
+ style.appendChild(document.createTextNode(css));
106
+ }
107
+ }
108
+
109
+ var css_248z$1 = ".LinkEditor-module_link{color:#007aff;cursor:text;font-style:normal;font-weight:400;position:relative;text-decoration-line:underline}.LinkEditor-module_clickable{cursor:pointer}";
110
+ var s$1 = {"link":"LinkEditor-module_link","clickable":"LinkEditor-module_clickable"};
111
+ styleInject(css_248z$1);
112
+
113
+ const LinkEditor = ({ attributes, element, children, HTMLAttributes }) => {
114
+ const [hovered, setHovered] = useState(false);
115
+ const [clickable, setClickable] = useState(false);
116
+ const handleClick = (e) => {
117
+ var _a;
118
+ if (clickable && typeof element.data.url === 'string' && ((_a = element.data.url) === null || _a === void 0 ? void 0 : _a.length) > 0) {
119
+ window.open(element.data.url, '_blank');
120
+ return;
121
+ }
122
+ return e.preventDefault();
123
+ };
124
+ const reset = () => {
125
+ setClickable(false);
126
+ setHovered(false);
127
+ };
128
+ useEffect(() => {
129
+ const makeClickable = (event) => {
130
+ if (HOTKEYS.isCmd(event)) {
131
+ setClickable(true);
132
+ }
133
+ };
134
+ if (hovered) {
135
+ document === null || document === void 0 ? void 0 : document.addEventListener('keydown', makeClickable);
136
+ }
137
+ return () => {
138
+ document === null || document === void 0 ? void 0 : document.removeEventListener('keydown', makeClickable);
139
+ };
140
+ }, [hovered, clickable]);
141
+ return (jsx("a", Object.assign({ draggable: false, href: element.data.url || '', rel: "noreferrer", target: "_blank", className: cx(s$1.link, { [s$1.clickable]: clickable && hovered }), onClick: handleClick, onMouseEnter: () => setHovered(true), onMouseLeave: reset }, HTMLAttributes, attributes, { children: children })));
142
+ };
143
+
144
+ var css_248z = ".Link-module_link{color:#007aff;cursor:pointer;font-style:normal;font-weight:400;position:relative;text-decoration-line:underline}";
145
+ var s = {"link":"Link-module_link"};
146
+ styleInject(css_248z);
147
+
148
+ const LinkRender = ({ attributes, element, children, HTMLAttributes }) => {
149
+ const handleClick = (e) => {
150
+ e.preventDefault();
151
+ if (!element.data.url)
152
+ return;
153
+ const url = new URL(element.data.url);
154
+ if (url.host === window.location.host) {
155
+ window.open(element.data.url, '_self');
156
+ }
157
+ else {
158
+ window.open(element.data.url, '_blank');
159
+ }
160
+ };
161
+ return (jsx("a", Object.assign({ draggable: false, href: element.data.url || '', rel: "noreferrer", target: "_blank", onClick: handleClick }, HTMLAttributes, { className: getElementClassname({ element, HTMLAttributes, className: s.link }) }, attributes, { children: children })));
162
+ };
163
+ LinkRender.displayName = 'Link';
164
+ const LINK_NODE_TYPE = 'link';
165
+ const Link = createYooptaPlugin({
166
+ type: LINK_NODE_TYPE,
167
+ renderer: {
168
+ editor: () => LinkEditor,
169
+ render: LinkRender,
170
+ },
171
+ defineElement: () => ({
172
+ id: generateId(),
173
+ type: 'link',
174
+ children: [{ text: '' }],
175
+ nodeType: 'inline',
176
+ data: { url: null, skipDrag: true },
177
+ }),
178
+ extendEditor(editor) {
179
+ const { insertData, insertText, isInline, normalizeNode } = editor;
180
+ editor.isInline = (element) => (element.type === LINK_NODE_TYPE ? true : isInline(element));
181
+ editor.normalizeNode = (entry) => {
182
+ var _a, _b;
183
+ const [node, path] = entry;
184
+ if (Element.isElement(node) && node.type === LINK_NODE_TYPE) {
185
+ if (node.children.length > 0 && ((_b = (_a = Node.child(node, 0)) === null || _a === void 0 ? void 0 : _a.text) === null || _b === void 0 ? void 0 : _b.length) === 0) {
186
+ Transforms.removeNodes(editor, {
187
+ at: entry[1],
188
+ match: (n) => Element.isElement(n) && n.type === LINK_NODE_TYPE,
189
+ });
190
+ }
191
+ }
192
+ normalizeNode(entry);
193
+ };
194
+ editor.insertText = (text) => {
195
+ if (text && isUrl_1(text)) {
196
+ addLinkNode(editor, text);
197
+ }
198
+ else {
199
+ insertText(text);
200
+ }
201
+ };
202
+ editor.insertData = (data) => {
203
+ const text = data.getData('text/plain');
204
+ if (text && isUrl_1(text)) {
205
+ addLinkNode(editor, text);
206
+ }
207
+ else {
208
+ insertData(data);
209
+ }
210
+ };
211
+ return editor;
212
+ },
213
+ events: {
214
+ onKeyDown: (editor, { hotkeys }) => (event) => {
215
+ if (!editor.selection)
216
+ return;
217
+ const node = getElementByPath(editor, editor.selection.anchor.path);
218
+ if (node.type !== LINK_NODE_TYPE)
219
+ return;
220
+ const { anchor } = editor.selection;
221
+ if (hotkeys.isEnter(event)) {
222
+ const isEnd = Editor.isEnd(editor, anchor, anchor.path);
223
+ const isStart = Editor.isStart(editor, anchor, anchor.path);
224
+ console.log({ isStart });
225
+ if (isStart) {
226
+ event.preventDefault();
227
+ const linkEntry = Editor.above(editor, {
228
+ match: (n) => Element.isElement(n) && n.type === LINK_NODE_TYPE,
229
+ });
230
+ if (!linkEntry)
231
+ return;
232
+ const [, linkElementPath] = linkEntry;
233
+ const parentEntry = Editor.parent(editor, linkElementPath);
234
+ const [, parentElementPath] = parentEntry;
235
+ Transforms.splitNodes(editor, {
236
+ match: (n) => Element.isElement(n),
237
+ mode: 'highest',
238
+ always: true,
239
+ });
240
+ Transforms.setNodes(editor, { id: generateId() }, {
241
+ at: parentElementPath,
242
+ match: (n) => Element.isElement(n),
243
+ mode: 'highest',
244
+ });
245
+ return;
246
+ }
247
+ if (isEnd) {
248
+ event.preventDefault();
249
+ Editor.insertBreak(editor);
250
+ Transforms.setNodes(editor, { id: generateId() });
251
+ Transforms.removeNodes(editor, {
252
+ match: (n) => Element.isElement(n) && Editor.isInline(editor, n) && n.type === LINK_NODE_TYPE,
253
+ });
254
+ return;
255
+ }
256
+ if (!isEnd && !isStart) {
257
+ event.preventDefault();
258
+ Transforms.splitNodes(editor);
259
+ Transforms.setNodes(editor, { id: generateId() });
260
+ Transforms.setNodes(editor, { id: generateId() }, { match: (n) => Element.isElement(n) && Editor.isInline(editor, n) && n.type === LINK_NODE_TYPE });
261
+ }
262
+ return;
263
+ }
264
+ if (hotkeys.isSpace(event)) {
265
+ const inline = Editor.above(editor, {
266
+ match: (n) => Element.isElement(n) && Editor.isInline(editor, n) && n.type === LINK_NODE_TYPE,
267
+ mode: 'highest',
268
+ });
269
+ if (inline) {
270
+ const [, inlinePath] = inline;
271
+ if (Editor.isEnd(editor, anchor, inlinePath)) {
272
+ const afterPoint = Editor.after(editor, inlinePath);
273
+ Transforms.setSelection(editor, {
274
+ anchor: afterPoint,
275
+ focus: afterPoint,
276
+ });
277
+ }
278
+ }
279
+ return;
280
+ }
281
+ },
282
+ },
283
+ exports: {
284
+ markdown: {
285
+ serialize: (node, text) => `[${text}](${node.data.url})`,
286
+ },
287
+ html: {
288
+ serialize: (node, children) => `<a target="_blank" rel="noopener noreferrer" href="${node.data.url}">${children}</a>`,
289
+ deserialize: {
290
+ nodeName: 'A',
291
+ parse: (el) => {
292
+ return {
293
+ url: el.getAttribute('href'),
294
+ skipDrag: true,
295
+ };
296
+ },
297
+ },
298
+ },
299
+ },
300
+ });
301
+
302
+ export { Link as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yoopta/link",
3
- "version": "1.9.10-rc",
3
+ "version": "1.9.12-rc",
4
4
  "description": "> TODO: description",
5
5
  "author": "Darginec05 <devopsbanda@gmail.com>",
6
6
  "homepage": "https://github.com/Darginec05/Editor-Yoopta#readme",