@startlibs/form 1.0.11 → 1.1.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.
Files changed (92) hide show
  1. package/lib/AutoComplete.mjs +550 -0
  2. package/lib/AutoComplete.mjs.map +1 -0
  3. package/lib/Checkbox.mjs +76 -0
  4. package/lib/Checkbox.mjs.map +1 -0
  5. package/lib/Combobox.mjs +544 -0
  6. package/lib/Combobox.mjs.map +1 -0
  7. package/lib/ComboboxWithCustom.mjs +77 -0
  8. package/lib/ComboboxWithCustom.mjs.map +1 -0
  9. package/lib/DatePicker.mjs +625 -0
  10. package/lib/DatePicker.mjs.map +1 -0
  11. package/lib/EditableBox.mjs +496 -0
  12. package/lib/EditableBox.mjs.map +1 -0
  13. package/lib/Errors.mjs +176 -0
  14. package/lib/Errors.mjs.map +1 -0
  15. package/lib/ExpandableBox.mjs +209 -0
  16. package/lib/ExpandableBox.mjs.map +1 -0
  17. package/lib/Field.mjs +65 -0
  18. package/lib/Field.mjs.map +1 -0
  19. package/lib/FieldBox.mjs +80 -0
  20. package/lib/FieldBox.mjs.map +1 -0
  21. package/lib/Form.mjs +322 -0
  22. package/lib/Form.mjs.map +1 -0
  23. package/lib/FormValue.mjs +111 -0
  24. package/lib/FormValue.mjs.map +1 -0
  25. package/lib/InputboxGroup.mjs +104 -0
  26. package/lib/InputboxGroup.mjs.map +1 -0
  27. package/lib/Radiobox.mjs +67 -0
  28. package/lib/Radiobox.mjs.map +1 -0
  29. package/lib/RichText.mjs +634 -0
  30. package/lib/RichText.mjs.map +1 -0
  31. package/lib/TextInput.mjs +359 -0
  32. package/lib/TextInput.mjs.map +1 -0
  33. package/lib/alt/checkbox/SimpleCheckbox.mjs +82 -0
  34. package/lib/alt/checkbox/SimpleCheckbox.mjs.map +1 -0
  35. package/lib/alt/checkbox/ToggleCheckbox.mjs +68 -0
  36. package/lib/alt/checkbox/ToggleCheckbox.mjs.map +1 -0
  37. package/lib/alt/radiobox/CleanTabRadiobox.mjs +44 -0
  38. package/lib/alt/radiobox/CleanTabRadiobox.mjs.map +1 -0
  39. package/lib/alt/radiobox/IconRadioBox.mjs +52 -0
  40. package/lib/alt/radiobox/IconRadioBox.mjs.map +1 -0
  41. package/lib/alt/radiobox/SimpleRadiobox.mjs +61 -0
  42. package/lib/alt/radiobox/SimpleRadiobox.mjs.map +1 -0
  43. package/lib/alt/radiobox/TabRadiobox.mjs +54 -0
  44. package/lib/alt/radiobox/TabRadiobox.mjs.map +1 -0
  45. package/lib/enhanceInput.mjs +131 -0
  46. package/lib/enhanceInput.mjs.map +1 -0
  47. package/lib/index.cjs +5345 -0
  48. package/lib/index.cjs.map +1 -0
  49. package/lib/index.mjs +28 -0
  50. package/lib/index.mjs.map +1 -0
  51. package/lib/useConfirmDialog.mjs +117 -0
  52. package/lib/useConfirmDialog.mjs.map +1 -0
  53. package/lib/useDraftConfirmation.mjs +56 -0
  54. package/lib/useDraftConfirmation.mjs.map +1 -0
  55. package/lib/validation.mjs +91 -0
  56. package/lib/validation.mjs.map +1 -0
  57. package/lib/withFormImageInput.mjs +281 -0
  58. package/lib/withFormImageInput.mjs.map +1 -0
  59. package/package.json +44 -25
  60. package/src/AutoComplete.jsx +642 -0
  61. package/src/Checkbox.jsx +45 -0
  62. package/src/Combobox.jsx +606 -0
  63. package/src/ComboboxWithCustom.jsx +68 -0
  64. package/src/DatePicker.jsx +733 -0
  65. package/src/EditableBox.jsx +502 -0
  66. package/src/Errors.jsx +174 -0
  67. package/src/ExpandableBox.jsx +207 -0
  68. package/src/Field.jsx +76 -0
  69. package/src/FieldBox.jsx +136 -0
  70. package/src/Form.jsx +291 -0
  71. package/src/FormValue.jsx +67 -0
  72. package/src/IconRadioBoxOldHubt.jsx +93 -0
  73. package/src/InputboxGroup.jsx +121 -0
  74. package/src/Radiobox.jsx +33 -0
  75. package/src/RichText.jsx +812 -0
  76. package/src/TextInput.jsx +519 -0
  77. package/src/alt/checkbox/SimpleCheckbox.jsx +162 -0
  78. package/src/alt/checkbox/ToggleCheckbox.jsx +143 -0
  79. package/src/alt/radiobox/CleanTabRadiobox.jsx +46 -0
  80. package/src/alt/radiobox/IconRadioBox.jsx +93 -0
  81. package/src/alt/radiobox/SimpleRadiobox.jsx +153 -0
  82. package/src/alt/radiobox/TabRadiobox.jsx +73 -0
  83. package/src/enhanceInput.jsx +107 -0
  84. package/src/index.js +27 -0
  85. package/src/useConfirmDialog.jsx +105 -0
  86. package/src/useDraftConfirmation.jsx +60 -0
  87. package/src/validation.js +92 -0
  88. package/src/withFormImageInput.jsx +297 -0
  89. package/.babelrc +0 -28
  90. package/lib/index.js +0 -6255
  91. package/rollup.config.js +0 -43
  92. package/yarn-error.log +0 -1607
@@ -0,0 +1,634 @@
1
+ import _defineProperty from '@babel/runtime/helpers/defineProperty';
2
+ import _zipObject from 'lodash/fp/zipObject';
3
+ import _last from 'lodash/fp/last';
4
+ import _flatten from 'lodash/fp/flatten';
5
+ import _fromPairs from 'lodash/fp/fromPairs';
6
+ import _pick from 'lodash/fp/pick';
7
+ import _toPairs from 'lodash/fp/toPairs';
8
+ import _identity from 'lodash/fp/identity';
9
+ import React, { useRef, useEffect, useState, useContext } from 'react';
10
+ import styled, { css } from 'styled-components';
11
+ import ContentEditable from 'react-contenteditable';
12
+ import { darken } from 'polished';
13
+ import { getColor, stopPropagation, linkRegex } from '@startlibs/utils';
14
+ import { usePopupToggle, useEnsureRef, useRefState, useToggle, useLazyConstant, StartlibsContext } from '@startlibs/core';
15
+ import { Errors } from './Errors.mjs';
16
+ import { Field } from './Field.mjs';
17
+ import { WithForm } from './Form.mjs';
18
+ import { TextInput } from './TextInput.mjs';
19
+ import { useInput } from './enhanceInput.mjs';
20
+ import { Icon, Button } from '@startlibs/components';
21
+
22
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
23
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
24
+ const InputIcon = /*#__PURE__*/styled(Icon).withConfig({
25
+ displayName: "RichText__InputIcon",
26
+ componentId: "sc-x8c1ig-0"
27
+ })(["position:absolute;outline:none;bottom:0;font-size:21px;line-height:3rem;right:0;width:2rem;pointer-events:none;color:", ";"], getColor('gray150'));
28
+ const FORMAT_TOOLS = {
29
+ 'bold': ['b', 'strong'],
30
+ 'italic': 'i',
31
+ 'underline': 'u',
32
+ 'strikethrough': 'strike',
33
+ 'link': 'a',
34
+ 'insertUnorderedList': ['ul', 'li'],
35
+ 'insertOrderedList': ['ol', 'li'],
36
+ 'outdent': '',
37
+ 'indent': 'blockquote',
38
+ 'fontSizeUp': 'font',
39
+ 'fontSizeDown': 'font'
40
+ };
41
+ const TAG_TO_STYLE_PROPERTY = {
42
+ 'b': 'fontWeight',
43
+ 'strong': 'fontWeight',
44
+ 'u': 'textDecoration',
45
+ 'strike': 'textDecoration',
46
+ 'font': 'fontSize',
47
+ 'i': 'fontStyle'
48
+ };
49
+ let GET_LIMITS_FONT_SIZE_PX = () => {
50
+ const s = document.createElement('span');
51
+ s.style.fontSize = 'medium';
52
+ document.body.appendChild(s);
53
+ const fontSize = parseInt(getComputedStyle(s).fontSize);
54
+ document.body.removeChild(s);
55
+ const limits = [fontSize * 3 / 5, fontSize * 3];
56
+ GET_LIMITS_FONT_SIZE_PX = () => limits;
57
+ return limits;
58
+ };
59
+ const wrapWith = (el, wrapper) => {
60
+ el.parentNode.insertBefore(wrapper, el);
61
+ wrapper.appendChild(el);
62
+ };
63
+ const FIX_STYLE = {
64
+ 'fontWeight': (v, el) => {
65
+ const intFontWeight = parseInt(window.getComputedStyle(el).fontWeight);
66
+ return intFontWeight <= 400 ? 400 : 600;
67
+ },
68
+ 'fontSize': (v, el) => {
69
+ const [min, max] = GET_LIMITS_FONT_SIZE_PX();
70
+ const intFontSize = parseInt(window.getComputedStyle(el).fontSize);
71
+ return Math.min(max, Math.max(min, intFontSize)) + 'px';
72
+ },
73
+ 'textDecoration': (v, el) => {
74
+ const values = v.split(' ').filter(v => v === 'underline' || v === 'line-through');
75
+ if (values.indexOf('underline') >= 0) {
76
+ wrapWith(el, document.createElement('u'));
77
+ }
78
+ if (values.indexOf('line-through') >= 0) {
79
+ wrapWith(el, document.createElement('strike'));
80
+ }
81
+ return '';
82
+ }
83
+ };
84
+ const RichTextContainer = /*#__PURE__*/styled.div.withConfig({
85
+ displayName: "RichText__RichTextContainer",
86
+ componentId: "sc-x8c1ig-1"
87
+ })(["position:relative;width:100%;border:1px solid ", ";border-radius:8px;background:white;", ";", ";", " ", " ", " ul{list-style-type:disc;}ul,ol{padding-inline-start:25px;margin-block-start:0.5em;margin-block-end:0.5em;}"], getColor('gray210'), props => props.hasErrors && "border-color: ".concat(getColor(props)('alert')), props => props.showToolbar && "\n ".concat(ToolsContainer, " {\n transition: 0.5s;\n max-height: 7.5rem;\n transition: 0.6s;\n pointer-events: auto;\n }\n "), props => props.focus && "\n border-color: ".concat(getColor('gray180'), ";\n box-shadow: 0px 0px 0px 2px rgba(0,0,0,0.1);\n "), props => props.locked && css(["padding-right:2.25rem;background:rgba(0,0,0,0.075);"]), props => props.linkColor && css(["a,a:visited,a:focus,a:active{color:", ";}a:hover{color:", ";}"], props.linkColor, darken(0.05, props.linkColor)));
88
+ const RichTextInput = /*#__PURE__*/styled.div.withConfig({
89
+ displayName: "RichText__RichTextInput",
90
+ componentId: "sc-x8c1ig-2"
91
+ })(["font-size:14px;color:", ";background:white;border-radius:7px;> div{overflow:auto;width:100%;outline:none;min-height:", "px;padding:0.7rem;}b,strong{font-weight:600;}a{text-decoration:underline;}> div[contenteditable=true]:empty:before{content:attr(placeholder);color:rgba(0,0,0,0.3);}", ""], getColor('gray60'), props => props.minHeight || 60, props => props.disabled && "\n &[disabled] {\n background: rgba(0, 0, 0, 0.075) !important;\n opacity: 0.75 !important;\n }\n ");
92
+ const ToolsContainer = /*#__PURE__*/styled.div.withConfig({
93
+ displayName: "RichText__ToolsContainer",
94
+ componentId: "sc-x8c1ig-3"
95
+ })(["background:", ";padding:0 0.125rem;border-top-left-radius:7px;border-top-right-radius:7px;transition:0.225s;max-height:0;pointer-events:none;overflow:hidden;display:flex;align-items:center;"], getColor('lightBluishGray'));
96
+ const ToolButton = /*#__PURE__*/styled(Button).withConfig({
97
+ displayName: "RichText__ToolButton",
98
+ componentId: "sc-x8c1ig-4"
99
+ })(["min-height:2rem;min-width:2rem;background:transparent;box-shadow:none;margin:0.25rem 0.125rem;& ~ &{margin-left:0.125rem;}.icon{font-size:23px;color:", ";position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);}&:hover,&.activated:hover{background:rgba(0,0,0,0.11);}&.activated{background:rgba(0,0,0,0.09);}&:focus:after{content:none;}"], getColor('gray90'));
100
+ const ToolSeparator = /*#__PURE__*/styled.span.withConfig({
101
+ displayName: "RichText__ToolSeparator",
102
+ componentId: "sc-x8c1ig-5"
103
+ })(["border-left:1px solid rgba(0,0,0,0.1);margin-left:0.75rem;margin-right:0.5rem;height:1.5rem;"]);
104
+ const JS_CLASS = "EDITOR--JS";
105
+ const getNextRegularCharIndex = (text, offset, direction) => {
106
+ const regex = /[A-Za-z0-9ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏàáâãäåæçèéêëìíîïÐÑÒÓÔÕÖØÙÚÛÜÝÞßðñòóôõöøùúûüýþÿ]/g;
107
+ let cursor = offset;
108
+ while ((text[cursor + direction] || '').match(regex)) {
109
+ cursor += direction;
110
+ }
111
+ return cursor;
112
+ };
113
+ const addHttp = s => {
114
+ s = s.replace(/^\s/, '');
115
+ if (s.indexOf('http://') === 0 || s.indexOf('https://') === 0) {
116
+ return s;
117
+ } else {
118
+ return 'http://' + s;
119
+ }
120
+ };
121
+ const setSelectionRange = function (input, selectionStart) {
122
+ let selectionEnd = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
123
+ if (!input) return;
124
+ let range = document.createRange();
125
+ let sel = window.getSelection();
126
+ range.setStart(input, selectionStart);
127
+ if (selectionEnd) {
128
+ range.setEnd(input, selectionEnd);
129
+ } else {
130
+ range.collapse(true);
131
+ }
132
+ sel.removeAllRanges();
133
+ sel.addRange(range);
134
+ };
135
+ const cleanEditor = (editor, acceptedTags) => {
136
+ Array.prototype.slice.call(editor.querySelectorAll('.Apple-interchange-newline')).forEach(el => el.remove());
137
+ Array.prototype.slice.call(editor.querySelectorAll('iframe')).forEach(el => el.remove());
138
+ const acceptedStyles = acceptedTags.map(t => TAG_TO_STYLE_PROPERTY[t]).filter(_identity);
139
+ const newSpace = document.createTextNode('\u00A0');
140
+ if (window.getSelection().rangeCount) {
141
+ const container = window.getSelection().getRangeAt(0).startContainer;
142
+ if (container.nodeType === 3) {
143
+ container.parentNode.insertBefore(newSpace, container.nextSibling);
144
+ } else {
145
+ container.appendChild(newSpace);
146
+ }
147
+ if (newSpace.previousSibling && newSpace.previousSibling.textContent === '\u00A0') {
148
+ newSpace.previousSibling.remove();
149
+ }
150
+ setSelectionRange(newSpace, 0);
151
+ }
152
+ const clean = children => {
153
+ Array.prototype.slice.call(children).forEach(el => {
154
+ try {
155
+ if (el.nodeType === 3) return;
156
+ if (!el.tagName) {
157
+ el.remove();
158
+ return;
159
+ }
160
+ let tagName = el.tagName.toLowerCase();
161
+ const style = getComputedStyle(el);
162
+ const rect = el.getBoundingClientRect();
163
+ const isHidden = style.display === 'none' || rect.width === 0 || rect.height === 0;
164
+ if (isHidden && el.children && !el.children.length && tagName !== 'br') {
165
+ el.remove();
166
+ } else if (acceptedTags.indexOf(tagName) >= 0) {
167
+ clean(el.childNodes);
168
+ el.removeAttribute('class');
169
+ if (tagName === 'a') {
170
+ el.setAttribute('target', '_blank');
171
+ }
172
+ if (el.getAttribute('style')) {
173
+ const usedStyles = _toPairs(_pick(acceptedStyles, el.style)).filter(_ref => {
174
+ let [k, v] = _ref;
175
+ return v !== "";
176
+ });
177
+ const fixedStyle = _fromPairs(usedStyles.map(_ref2 => {
178
+ let [k, v] = _ref2;
179
+ return [k, (FIX_STYLE[k] || _identity)(v, el)];
180
+ }));
181
+ el.removeAttribute('style');
182
+ Object.assign(el.style, fixedStyle);
183
+ }
184
+ } else if (tagName === 'a') {
185
+ clean(el.childNodes);
186
+ if (el.textContent !== el.href || el.textContent.length < 5) el.outerHTML = el.innerHTML;
187
+ } else {
188
+ clean(el.childNodes);
189
+ if (el.hasChildNodes()) {
190
+ const newTagName = style.display === 'inline' ? 'span' : 'div';
191
+ const newEl = document.createElement(newTagName);
192
+ Array.prototype.slice.call(el.childNodes).forEach(child => newEl.appendChild(child));
193
+ el.parentNode.replaceChild(newEl, el);
194
+ } else {
195
+ el.remove();
196
+ }
197
+ }
198
+ } catch (e) {
199
+ if (el && el.remove) el.remove();
200
+ }
201
+ });
202
+ };
203
+ clean(editor.childNodes);
204
+ };
205
+ const RichText = _ref3 => {
206
+ let {
207
+ path,
208
+ inputRef,
209
+ label,
210
+ autoHideToolbar,
211
+ autoFocus,
212
+ disabled,
213
+ minHeight,
214
+ placeholder,
215
+ className,
216
+ formatTools = ['bold', 'italic', 'underline', 'strikethrough', 'separator', 'link'],
217
+ reformatText = _identity,
218
+ mandatory,
219
+ descText,
220
+ helpText,
221
+ linkColor,
222
+ tabIndex = 1,
223
+ value,
224
+ setValue,
225
+ raw,
226
+ locked
227
+ } = _ref3;
228
+ const linkPopup = usePopupToggle();
229
+ const input = useEnsureRef(inputRef);
230
+ const activeLinkNode = useRef();
231
+ const container = useRef();
232
+ useRefState();
233
+
234
+ // auto-hide needs
235
+ useRefState();
236
+ useRefState();
237
+ useRefState([]);
238
+ const containerFocused = useToggle();
239
+ const needsNormalize = useRefState();
240
+ const alreadyCancelled = useRefState();
241
+
242
+ // const [formValue, setFormValue] = useInput({path})
243
+ const [formValue, _setFormValue, {
244
+ hasErrors
245
+ }] = useInput({
246
+ path,
247
+ value,
248
+ setValue
249
+ }, raw);
250
+
251
+ // const tempValue = useConstant(formValue)
252
+ const tempValue = useRef(formValue);
253
+ const setFormValue = v => {
254
+ tempValue.current = v;
255
+ _setFormValue(v);
256
+ };
257
+ useEffect(() => {
258
+ if (value === formValue && formValue !== tempValue) {
259
+ tempValue.current = formValue;
260
+ }
261
+ }, [path]);
262
+ const [activatedTools, setActivatedTools] = useState({});
263
+ const validElements = useLazyConstant(() => ['br', 'div', 'p', 'span'].concat(_flatten(formatTools.map(tool => FORMAT_TOOLS[tool] || []))));
264
+ useEffect(() => {
265
+ cleanEditor(input.current, validElements);
266
+ }, []);
267
+ const focus = () => input.current && input.current.focus();
268
+
269
+ // Foco inicial opcional (ex.: abrir a dialog já no campo de descrição). Em
270
+ // rAF pra rodar depois que a dialog termina de montar e não perder o foco.
271
+ useEffect(() => {
272
+ if (autoFocus) {
273
+ requestAnimationFrame(focus);
274
+ }
275
+ }, []);
276
+ useEffect(() => {
277
+ if (needsNormalize.get()) {
278
+ input.current.normalize();
279
+ needsNormalize.set(false);
280
+ }
281
+ });
282
+ const triggerScrollForPanel = d => {
283
+ requestAnimationFrame(time => {
284
+ if (time > d + 250) return;
285
+ window.dispatchEvent(new Event('scroll'));
286
+ triggerScrollForPanel(d);
287
+ });
288
+ };
289
+ const containerFocus = () => {
290
+ containerFocused.openWith(2);
291
+ triggerScrollForPanel(Date.now());
292
+ };
293
+ const containerBlur = e => {
294
+ if (containerFocused.isOpen !== 1) {
295
+ containerFocused.close();
296
+ triggerScrollForPanel(Date.now());
297
+ }
298
+ };
299
+ const onBlur = e => {
300
+ const newValue = input.current.textContent.length === 0 ? '' : input.current.innerHTML;
301
+ // Só reescreve se o conteúdo mudou de fato: focar/desfocar sem editar não pode
302
+ // marcar o form como alterado (senão dispara a confirmação de descarte à toa).
303
+ // textContent vazio equivale a valor ausente/'' do form.
304
+ if (newValue !== (formValue || '')) {
305
+ setFormValue(newValue);
306
+ }
307
+ };
308
+ const keydownHandler = e => {
309
+ if (containerFocused.isOpen === 2) {
310
+ if (formatTools.indexOf('link') < 0) {
311
+ return;
312
+ }
313
+ if (e.key === "k" && e.ctrlKey || e.key === "k" && e.metaKey) {
314
+ e.preventDefault();
315
+ execCommand(null, 'link');
316
+ }
317
+ }
318
+ };
319
+ useEffect(() => {
320
+ document.addEventListener('keydown', keydownHandler);
321
+ return () => document.removeEventListener('keydown', keydownHandler);
322
+ }, [containerFocused.isOpen]);
323
+ const execCommand = (e, command) => {
324
+ if (command === 'link') {
325
+ let nodeEl;
326
+ if (!isSelectionInsideRichTextEditor()) {
327
+ let anchor = document.createElement('a');
328
+ anchor.innerHTML = '&#8203;';
329
+ input.current.appendChild(anchor);
330
+ nodeEl = anchor;
331
+ } else {
332
+ const range = window.getSelection().getRangeAt(0);
333
+ const selectedNode = range.startContainer;
334
+ if (range.collapsed) {
335
+ const start = getNextRegularCharIndex(selectedNode.textContent, range.startOffset, -1);
336
+ const end = getNextRegularCharIndex(selectedNode.textContent, range.startOffset - 1, 1);
337
+ if (start < range.startOffset && end > range.startOffset - 1) {
338
+ range.setStart(selectedNode, start);
339
+ range.setEnd(selectedNode, end + 1);
340
+ }
341
+ }
342
+ const selectedEl = selectedNode.nodeType === Node.TEXT_NODE ? selectedNode.parentNode : selectedNode;
343
+ const parent = selectedEl.closest('a,.' + JS_CLASS);
344
+ if (parent && parent.matches('a')) {
345
+ nodeEl = parent;
346
+ } else {
347
+ let anchor = document.createElement('a');
348
+ anchor.innerHTML = '&#8203;';
349
+ if (range.collapsed) {
350
+ range.insertNode(anchor);
351
+ } else {
352
+ if (range.commonAncestorContainer === input.current) {
353
+ range.setStart(range.endContainer, 0);
354
+ }
355
+ document.execCommand('createLink', false, '_');
356
+ anchor = window.getSelection().anchorNode;
357
+ }
358
+ const parent = range.commonAncestorContainer.nodeType === 3 ? range.commonAncestorContainer.parentNode : range.commonAncestorContainer;
359
+ const links = parent.querySelectorAll("a[href='_']");
360
+ Array.from(links).slice(0, -1).forEach(removeLinkFromNode);
361
+ nodeEl = _last(links);
362
+ nodeEl.setAttribute('href', ' ');
363
+ }
364
+ }
365
+ tempValue.current = input.current.innerHTML;
366
+ openDialog(nodeEl);
367
+ } else {
368
+ if (!isSelectionInsideRichTextEditor()) {
369
+ input.current.focus();
370
+ const last = document.createTreeWalker(input.current, NodeFilter.SHOW_TEXT).lastChild();
371
+ const range = document.createRange();
372
+ range.selectNodeContents(last || input.current);
373
+ range.collapse(false);
374
+ const sel = window.getSelection();
375
+ sel.removeAllRanges();
376
+ sel.addRange(range);
377
+ }
378
+ document.execCommand(command);
379
+ setFormValue(input.current.innerHTML);
380
+ toggleButtonsState();
381
+ focus();
382
+ }
383
+ };
384
+ const isSelectionInsideRichTextEditor = () => {
385
+ const range = window.getSelection().getRangeAt(0);
386
+ if (!range) return false;
387
+ const el = range.startContainer;
388
+ if (!el) return false;
389
+ const node = el.closest ? el : el.parentNode || document.body;
390
+ return node.closest('.' + JS_CLASS) === input.current;
391
+ };
392
+ const saveRichTextLink = _ref4 => {
393
+ let {
394
+ linkUrl,
395
+ linkText
396
+ } = _ref4;
397
+ const currentActiveLinkNode = activeLinkNode.current;
398
+ currentActiveLinkNode.setAttribute('href', addHttp(linkUrl));
399
+ currentActiveLinkNode.setAttribute('target', '_blank');
400
+ if (currentActiveLinkNode.textContent !== linkText) {
401
+ currentActiveLinkNode.innerText = linkText;
402
+ }
403
+ linkPopup.close();
404
+ setSelectionRange(currentActiveLinkNode.lastChild, currentActiveLinkNode.textContent.length, 0);
405
+ focus();
406
+ setFormValue(input.current.innerHTML);
407
+ };
408
+ const cancelRichTextLink = e => {
409
+ if (alreadyCancelled.get()) return;
410
+ const currentActiveLinkNode = activeLinkNode.current;
411
+ const span = document.createElement('span');
412
+ if (currentActiveLinkNode.nextSibling) currentActiveLinkNode.parentNode.insertBefore(span, currentActiveLinkNode.nextSibling);else currentActiveLinkNode.parentNode.append(span);
413
+ setSelectionRange(span, 0, 0);
414
+ focus();
415
+ if (currentActiveLinkNode.getAttribute('href') === ' ') {
416
+ removeLink(e);
417
+ }
418
+ alreadyCancelled.set(true);
419
+ span.remove();
420
+ if (input.current) {
421
+ input.current.normalize();
422
+ } else {
423
+ needsNormalize.set(true);
424
+ }
425
+ linkPopup.close();
426
+ };
427
+ const handleKeyUp = e => {
428
+ toggleButtonsState();
429
+ setFormValue(reformatText(input.current.innerHTML));
430
+ };
431
+ const handleKeyDown = e => {
432
+ /*if (linkJustCreated.current && e.which === 8) {
433
+ linkJustCreated.current.outerHTML = linkJustCreated.current.innerHTML
434
+ input.current.normalize()
435
+ return
436
+ }
437
+ commands.set([])
438
+ linkJustCreated.set(null)
439
+ const selectedRange = window.getSelection().getRangeAt(0)
440
+ if (!selectedRange) return
441
+ const possibleTextNode = selectedRange.startContainer
442
+ const node = possibleTextNode.nodeType === Node.TEXT_NODE ? possibleTextNode.parentNode : possibleTextNode
443
+ const parent = node.closest('a,.'+JS_CLASS)
444
+ if ((e.key === 'Enter' || e.which === 32) && parent && parent.matches('.'+JS_CLASS)) {
445
+ const range = document.createRange()
446
+ range.setEnd(selectedRange.startContainer, selectedRange.startOffset)
447
+ range.setStart(selectedRange.startContainer, 0)
448
+ traverseAndAddLink(range)
449
+ }*/
450
+ };
451
+ const handlePasteDrop = e => setTimeout(() => pasted(), 1);
452
+ const handleClick = e => {
453
+ toggleButtonsState();
454
+ const el = e.target.closest('a,.' + JS_CLASS);
455
+ if (el && el.matches('a') && el.getAttribute('href')) {
456
+ openDialog(el);
457
+ }
458
+ };
459
+ const openDialog = el => {
460
+ activeLinkNode.current = el;
461
+ alreadyCancelled.set(false);
462
+ linkPopup.openWith({
463
+ linkText: el.textContent,
464
+ linkUrl: (el.getAttribute('href') || '').trim()
465
+ });
466
+ };
467
+ const removeLinkFromNode = node => {
468
+ node.outerHTML = node.innerHTML === '\u200b' ? '' : node.innerHTML;
469
+ };
470
+ const removeLink = e => {
471
+ if (e) e.preventDefault();
472
+ alreadyCancelled.set(true);
473
+ removeLinkFromNode(activeLinkNode.current);
474
+ linkPopup.close();
475
+ if (input.current) {
476
+ setFormValue(input.current.innerHTML);
477
+ input.current.normalize();
478
+ }
479
+ };
480
+ const pasted = e => {
481
+ cleanEditor(input.current, validElements);
482
+ };
483
+ const toggleButtonsState = () => {
484
+ return setActivatedTools(_zipObject(formatTools, formatTools.map(t => window.document.queryCommandState(t))));
485
+ };
486
+ const toolButton = tool => /*#__PURE__*/React.createElement(ToolButton, {
487
+ key: tool,
488
+ tabIndex: -1,
489
+ onClick: e => execCommand(e, tool),
490
+ className: 'button exec-command rich-text-button only-icon ' + (activatedTools[tool] ? 'activated' : ''),
491
+ type: "button"
492
+ }, /*#__PURE__*/React.createElement("span", {
493
+ className: 'icon icon-' + tool
494
+ }));
495
+ const richTextElement = /*#__PURE__*/React.createElement(RichTextContainer, {
496
+ linkColor: linkColor,
497
+ ref: container,
498
+ onFocus: containerFocus,
499
+ onBlur: containerBlur,
500
+ focus: containerFocused.isOpen,
501
+ showToolbar: !disabled & !autoHideToolbar || containerFocused.isOpen,
502
+ className: className
503
+ }, /*#__PURE__*/React.createElement(ToolsContainer, {
504
+ className: "rich-text-tools"
505
+ }, formatTools.map((t, i) => t === 'separator' ? /*#__PURE__*/React.createElement(ToolSeparator, {
506
+ className: "separator",
507
+ key: "separator-" + i
508
+ }) : toolButton(t))), /*#__PURE__*/React.createElement(RichTextInput, null, /*#__PURE__*/React.createElement(ContentEditable, {
509
+ className: JS_CLASS,
510
+ innerRef: input,
511
+ html: tempValue.current || "",
512
+ onBlur: onBlur,
513
+ onClick: handleClick,
514
+ onKeyUp: handleKeyUp,
515
+ onKeyDown: handleKeyDown,
516
+ onPaste: handlePasteDrop,
517
+ onDrop: handlePasteDrop,
518
+ tabIndex: tabIndex,
519
+ disabled: disabled,
520
+ minHeight: minHeight,
521
+ placeholder: placeholder
522
+ })), locked && /*#__PURE__*/React.createElement(InputIcon, {
523
+ icon: "lock"
524
+ }), linkPopup.isOpen && /*#__PURE__*/React.createElement(EditLinkPopup, {
525
+ input: input,
526
+ activeLinkNode: activeLinkNode,
527
+ cancel: cancelRichTextLink,
528
+ values: linkPopup.isOpen,
529
+ removeLink: removeLink,
530
+ saveLink: saveRichTextLink
531
+ }));
532
+ return label ? /*#__PURE__*/React.createElement(Field, {
533
+ labelClick: focus,
534
+ descText: descText,
535
+ helpText: helpText,
536
+ label: label,
537
+ mandatory: mandatory
538
+ }, richTextElement) : richTextElement;
539
+ };
540
+ const EditLinkPopup = _ref5 => {
541
+ let {
542
+ cancel,
543
+ removeLink,
544
+ activeLinkNode,
545
+ input,
546
+ saveLink,
547
+ values
548
+ } = _ref5;
549
+ const linkPopup = useRef();
550
+ const formRef = useRef();
551
+ const linkTextRef = useRef();
552
+ const linkUrlRef = useRef();
553
+ const LABELS = useContext(StartlibsContext).labels.RichText;
554
+ const preValidation = formValues => {
555
+ let errors;
556
+ if (!formValues.linkText) {
557
+ errors = {
558
+ 'linkText': [LABELS.linkTextError]
559
+ };
560
+ }
561
+ if (!formValues.linkUrl || formValues.linkUrl === ' ' || !linkRegex.test(formValues.linkUrl.trim())) {
562
+ errors = _objectSpread(_objectSpread({}, errors), {}, {
563
+ 'linkUrl': [LABELS.linkUrlError]
564
+ });
565
+ }
566
+ return errors;
567
+ };
568
+ const checkEscOrEnter = e => {
569
+ if (e.keyCode === 27) {
570
+ e.stopPropagation();
571
+ cancel(e);
572
+ } else if (e.keyCode === 13) {
573
+ e.preventDefault();
574
+ e.stopPropagation();
575
+ formRef.current.submitForm();
576
+ }
577
+ };
578
+ useEffect(() => {
579
+ const currentActiveLinkNode = activeLinkNode.current;
580
+ const currentLinkPopup = linkPopup.current;
581
+ const offsetLeft = currentActiveLinkNode.getClientRects().length > 1 ? input.offsetLeft : currentActiveLinkNode.offsetLeft;
582
+ const left = currentActiveLinkNode.offsetWidth / 2 - currentLinkPopup.offsetWidth / 2 + offsetLeft;
583
+ const top = currentActiveLinkNode.offsetHeight + currentActiveLinkNode.offsetTop;
584
+ Object.assign(currentLinkPopup.style, {
585
+ 'position': 'absolute',
586
+ 'left': left + 'px',
587
+ 'top': top + 'px'
588
+ });
589
+ if (values.linkText) {
590
+ linkUrlRef.current.focus();
591
+ } else {
592
+ linkTextRef.current.focus();
593
+ }
594
+ return cancel;
595
+ }, []);
596
+ return /*#__PURE__*/React.createElement(WithForm, {
597
+ skipDom: true,
598
+ ref: formRef,
599
+ action: saveLink,
600
+ values: values,
601
+ preValidation: preValidation
602
+ }, form => /*#__PURE__*/React.createElement("div", {
603
+ onClick: stopPropagation(),
604
+ ref: linkPopup,
605
+ onKeyDown: checkEscOrEnter,
606
+ className: "popup rich-text-link-editor ignore-link",
607
+ contentEditable: false
608
+ }, /*#__PURE__*/React.createElement(TextInput, {
609
+ ref: linkTextRef,
610
+ mandatory: true,
611
+ path: "linkText",
612
+ label: LABELS.popupLinkText
613
+ }), /*#__PURE__*/React.createElement(TextInput, {
614
+ ref: linkUrlRef,
615
+ mandatory: true,
616
+ path: "linkUrl",
617
+ label: LABELS.popupLinkUrl
618
+ }), /*#__PURE__*/React.createElement("div", {
619
+ className: "popup-footer"
620
+ }, /*#__PURE__*/React.createElement(Button, {
621
+ className: "remove-link",
622
+ icon: "remove",
623
+ onClick: removeLink
624
+ }, LABELS.popupRemove), /*#__PURE__*/React.createElement(Button, {
625
+ onClick: cancel,
626
+ tabIndex: 0
627
+ }, LABELS.popupCancel), /*#__PURE__*/React.createElement(Button, {
628
+ highlight: true,
629
+ onClick: form.willSubmitForm
630
+ }, LABELS.popupConfirm)), /*#__PURE__*/React.createElement(Errors, null)));
631
+ };
632
+
633
+ export { RichText, RichTextContainer, RichTextInput };
634
+ //# sourceMappingURL=RichText.mjs.map