argous 1.2.217 → 1.2.218

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.
@@ -1,463 +0,0 @@
1
- import Cursor from './Cursor';
2
- import TextStyles from './TextStyles';
3
- import { translateKey } from './utils';
4
- import { ClickAwayListener } from '@material-ui/core';
5
- import { isEqual } from 'lodash';
6
- import React, { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
7
- import './style.css';
8
-
9
-
10
- const resizeStyle = {
11
- resize: 'both',
12
- overflow: 'auto'
13
- };
14
-
15
-
16
- export const TEXT_TO_HTML_ID = 'text-to-html';
17
- const TEXT_TO_HTML_CURSOR_ID = 'text-to-html-cursor';
18
- const TEXT_TO_HTML_TEXT_CONTAINER_ID = 'text-to-html-text-container';
19
-
20
-
21
- export const initialStateCharacter = {
22
- key: undefined,
23
- keyCode: undefined,
24
- code: undefined,
25
- string: '',
26
- dead: false,
27
- shift: false,
28
- mark: []
29
- };
30
-
31
- export const initialStateCursor = { ...initialStateCharacter, string: 'cursor' };
32
-
33
- export const textToHtmlInitialValue = { text: '', cssText: '' };
34
-
35
- const initialStateMove = {
36
- isDown: false,
37
- offset: []
38
- };
39
-
40
- const initialStateKeyboardRef = { altGraph: false };
41
-
42
- const initialStateTextStyle = {
43
- color: { r: 255, g: 255, b: 255, a: 1 },
44
- textAlign: 'center',
45
- fontSize: 2,
46
- fontFamily: 'Roboto, Helvetica, Arial, sans-serif',
47
- letterSpacing: '0.01em'
48
- };
49
-
50
- const initialState = {
51
- textStyle: initialStateTextStyle,
52
- createCursorClick: false,
53
- clickAway: undefined,
54
- tap: 0,
55
- resize: false,
56
- move: initialStateMove,
57
- characters: []
58
- };
59
-
60
-
61
- const TextToHtml = ({ initialValue = textToHtmlInitialValue, onChange, onDelete, defaultSpacing, setExternalValues }, ref) => {
62
-
63
- const keyboardRef = useRef(initialStateKeyboardRef);
64
- const [state, setState] = useState(initialState);
65
- const { createCursorClick, characters, move, resize, tap, textStyle } = state;
66
- const { color, fontSize, fontFamily, textAlign, letterSpacing } = textStyle;
67
- const propsRef = useRef({
68
- onChange
69
- });
70
-
71
- const cursor = characters.findIndex(({ string }) => (string === 'cursor'));
72
- const canWrite = (cursor > -1);
73
-
74
-
75
- const logicSetState = ({ type, field, value }) => setState(values => ({
76
- ...values,
77
- [type]: (type && field) ? { ...values[type], [field]: value } : value
78
- }));
79
-
80
-
81
- const setCharacters = useCallback(value => logicSetState({ type: 'characters', value: value }), []);
82
-
83
- const focusToWrite = () => {
84
- const element = document.getElementById(TEXT_TO_HTML_ID);
85
- if (element) element.focus();
86
- };
87
-
88
- const toggleResize = () => logicSetState({ type: 'resize', value: !resize });
89
- const toggleClickAway = () => logicSetState({ type: 'clickAway', value: (state.clickAway === undefined) ? false : undefined });
90
- const disableResize = useCallback(() => logicSetState({ type: 'resize', value: false }), []);
91
- const handleCreateCursorClick = useCallback((boolean) => logicSetState({ type: 'createCursorClick', value: boolean }), []);
92
- const deleteCursor = useCallback(() => logicSetState({ type: 'characters', value: characters.filter(({ string }) => string !== 'cursor') }), [characters]);
93
-
94
- const createCursor = useCallback((e) => {
95
- let newCharacters = [...characters];
96
- newCharacters.push(initialStateCursor);
97
- focusToWrite();
98
- logicSetState({ type: 'characters', value: newCharacters });
99
- }, [characters]);
100
-
101
- const clickAway = useCallback((e) => {
102
- if (createCursorClick) {
103
- handleCreateCursorClick(false);
104
- return;
105
- }
106
- disableResize();
107
- deleteCursor();
108
- }, [createCursorClick, deleteCursor, disableResize, handleCreateCursorClick]);
109
-
110
- const handleClickAway = (e) => {
111
- clickAway(e);
112
- };
113
-
114
- const handleContainerClick = (e) => {
115
- if (canWrite) {
116
- clickAway(e);
117
- return;
118
- }
119
- createCursor(e);
120
- handleCreateCursorClick(true);
121
- };
122
-
123
- const handleClick = (e) => {
124
- e.stopPropagation();
125
- if (canWrite) return;
126
- if (createCursorClick) handleCreateCursorClick(false);
127
- createCursor(e);
128
- };
129
-
130
- const pasteTextFromClipboard = async (e) => {
131
- const text = await navigator.clipboard?.readText();
132
- if (text?.length) {
133
- let newCharacters = [...characters];
134
-
135
- for (let index = 0; (index < text.length); index++) {
136
- const string = text[index];
137
- let newCharacter = { ...initialStateCharacter, string };
138
- newCharacters.push(newCharacter);
139
- }
140
-
141
- const cursorIndex = newCharacters.findIndex(({ string }) => (string === 'cursor'));
142
- if (cursorIndex > -1) {
143
- const [cursor] = newCharacters.splice(cursorIndex, 1);
144
- (cursor) && newCharacters.push(cursor);
145
- }
146
-
147
- (!isEqual(characters, newCharacters)) && setCharacters(newCharacters);
148
- }
149
- };
150
-
151
- const createCharactersFromInitialValue = useCallback((text) => {
152
- if (typeof text === 'string') {
153
- let newCharacters = [];
154
- for (let index = 0; (index < text.length); index++) {
155
- const string = text[index];
156
- let newCharacter = { ...initialStateCharacter, string };
157
- newCharacters.push(newCharacter);
158
- }
159
- newCharacters.push(initialStateCursor);
160
- setCharacters(newCharacters);
161
- focusToWrite();
162
- }
163
- }, [setCharacters]);
164
-
165
- const setStyleFromInitialValue = (cssText) => {
166
- const element = document.getElementById(TEXT_TO_HTML_ID);
167
- (element) && (element.style.cssText = cssText);
168
- };
169
-
170
- const loadInitialValue = useCallback((initialValue) => {
171
- (initialValue.text) && createCharactersFromInitialValue(initialValue.text);
172
- (initialValue.cssText) && setStyleFromInitialValue(initialValue.cssText);
173
- }, [createCharactersFromInitialValue]);
174
- useEffect(() => loadInitialValue(initialValue), [initialValue, loadInitialValue]);
175
-
176
- const handleKeyDown = (e) => {
177
-
178
- e.preventDefault();
179
- e.stopPropagation();
180
-
181
- if (!canWrite) return;
182
-
183
- const key = e.key;
184
- const keyCode = e.keyCode;
185
- const code = e.code;
186
- const shift = e.shiftKey;
187
- const ctrlKey = e.ctrlKey;
188
- const shiftKey = e.shiftKey;
189
- const capsLock = e.getModifierState('CapsLock');
190
-
191
- let deleted = undefined;
192
- let newCharacter = { string: null };
193
- let newCharacters = [...characters];
194
-
195
- const paste = (((key === 'v') || (key === 'V')) && (keyCode === 86) && (code === 'KeyV') && ctrlKey && !shiftKey);
196
- const characterBeforeCursorIndex = (cursor - 1);
197
- let characterBeforeCursor = newCharacters[characterBeforeCursorIndex];
198
-
199
-
200
- function moveCursor(direction) {
201
- const start = (direction === 'start');
202
- const end = (direction === 'end');
203
- const left = (direction === 'left');
204
- const right = (direction === 'right');
205
- if (!start && !end && !left && !right) return;
206
-
207
- const cursorIndex = cursor;
208
- if ((left || start) && (cursorIndex === 0)) return;
209
- const cursorObject = newCharacters.splice(cursorIndex, 1)[0];
210
- newCharacters.splice((start) ? 0 : (end) ? (newCharacters.length) : (left) ? (cursorIndex - 1) : (cursorIndex + 1), 0, cursorObject);
211
- }
212
-
213
- function deleteText(direction) {
214
- const left = (direction === 'left');
215
- const targetIndex = (left) ? (cursor === 0) ? 0 : (cursor - 1) : (cursor + 1);
216
- const nextObjectToDelete = newCharacters[targetIndex];
217
- if (nextObjectToDelete?.string === 'cursor') return;
218
- deleted = newCharacters.splice(targetIndex, 1)?.[0];
219
- }
220
-
221
- if (paste) pasteTextFromClipboard(e);
222
- else if (key === 'Home') moveCursor('start');
223
- else if (key === 'End') moveCursor('end');
224
- else if (key === 'ArrowLeft') moveCursor('left');
225
- else if (key === 'ArrowRight') moveCursor('right');
226
- else if (key === 'AltGraph') keyboardRef.current.altGraph = true;
227
- else if (key === 'Backspace') deleteText('left');
228
- else if (key === 'Delete') deleteText('right');
229
- else {
230
- const { string, before } = translateKey({ key, keyCode, code, shift, altGraph: keyboardRef.current.altGraph, capsLock, before: characterBeforeCursor });
231
- if (string) {
232
- newCharacter = {
233
- ...initialStateCharacter,
234
- key,
235
- keyCode,
236
- code,
237
- string,
238
- dead: before.dead,
239
- shift
240
- };
241
-
242
- newCharacters.splice(cursor, 0, newCharacter);
243
- if (characterBeforeCursor) {
244
- if (before.delete) newCharacters.splice(characterBeforeCursorIndex, 1);
245
- else if (characterBeforeCursor.dead) {
246
- characterBeforeCursor.dead = false;
247
- newCharacters.splice(characterBeforeCursorIndex, 1, characterBeforeCursor);
248
- }
249
- }
250
- }
251
- }
252
-
253
- (!isEqual(newCharacters, characters)) && setCharacters(newCharacters);
254
- if (deleted) onDelete && onDelete(e, deleted, newCharacters);
255
- };
256
-
257
- const handleKeyUp = (e) => {
258
- const key = e.key;
259
- if (key === 'AltGraph') keyboardRef.current.altGraph = false;
260
- };
261
-
262
- const handleDoubleClick = (e) => {
263
- toggleResize();
264
- };
265
-
266
- const handleTap = () => {
267
- let newTap = tap;
268
- newTap += 1;
269
- if (newTap > 1) toggleResize();
270
- logicSetState({ type: 'tap', value: newTap });
271
- setTimeout(() => logicSetState({ type: 'tap', value: 0 }), 300);
272
- };
273
-
274
- const handleMouseDownTouchStart = (e) => {
275
- if (e.type === 'touchstart') handleTap();
276
- if (resize) return;
277
- const element = document.getElementById(TEXT_TO_HTML_ID);
278
- if (!element) return;
279
- const clientX = (e.clientX || e.touches[0].clientX);
280
- const clientY = (e.clientY || e.touches[0].clientY);
281
- logicSetState({
282
- type: 'move',
283
- value: {
284
- ...move,
285
- isDown: true,
286
- offset: [
287
- element.offsetLeft - clientX,
288
- element.offsetTop - clientY
289
- ]
290
- }
291
- });
292
- };
293
-
294
- const handleMouseUpTouchEnd = (e) => {
295
- logicSetState({ type: 'move', field: 'isDown', value: false });
296
- const element = document.getElementById(TEXT_TO_HTML_ID);
297
- if (element) {
298
- element.style.cursor = 'pointer';
299
- }
300
- };
301
-
302
- const handleMouseTouchMove = (e) => {
303
- const { isDown, offset } = move;
304
- const containerElement = document.getElementById(TEXT_TO_HTML_TEXT_CONTAINER_ID);
305
- const textElement = document.getElementById(TEXT_TO_HTML_ID);
306
- if (containerElement && textElement && isDown) {
307
- const containerHeight = containerElement.clientHeight;
308
- const containerWidth = containerElement.clientWidth;
309
- const clientX = (e.clientX || e.touches[0].clientX);
310
- const clientY = (e.clientY || e.touches[0].clientY);
311
- const top = (clientY + offset[1]);
312
- const left = (clientX + offset[0]);
313
- const textTop = ((top / containerHeight) * 100);
314
- const textLeft = ((left / containerWidth) * 100);
315
- textElement.style.top = textTop + '%';
316
- textElement.style.left = textLeft + '%';
317
- textElement.style.cursor = 'grabbing';
318
- }
319
- };
320
-
321
- const handleFontSizeChange = (e) => {
322
- logicSetState({ type: 'clickAway', value: false });
323
- let newFontSize = fontSize;
324
- if (newFontSize > 2) newFontSize = 1;
325
- else newFontSize += 1;
326
- logicSetState({ type: 'textStyle', field: 'fontSize', value: newFontSize });
327
- focusToWrite();
328
- setTimeout(() => logicSetState({ type: 'clickAway', value: undefined }), 0);
329
- };
330
-
331
- const handleTextAlignChange = (e) => {
332
- logicSetState({ type: 'clickAway', value: false });
333
- let newTextAlign = textAlign;
334
- switch (textAlign) {
335
- case 'start':
336
- newTextAlign = 'end';
337
- break;
338
- case 'end':
339
- newTextAlign = 'center';
340
- break;
341
- case 'center':
342
- newTextAlign = 'justify';
343
- break;
344
- case 'justify':
345
- newTextAlign = 'start';
346
- break;
347
- default:
348
- return null;
349
- }
350
- logicSetState({ type: 'textStyle', field: 'textAlign', value: newTextAlign });
351
- focusToWrite();
352
- setTimeout(() => logicSetState({ type: 'clickAway', value: undefined }), 0);
353
- };
354
-
355
- const changeStyles = useCallback(({ resize }) => {
356
- const element = document.getElementById(TEXT_TO_HTML_ID);
357
- if (element) {
358
- if (resize) {
359
- element.style.resize = resizeStyle.resize;
360
- element.style.overflow = resizeStyle.overflow;
361
- } else {
362
- element.style.resize = '';
363
- element.style.overflow = '';
364
- }
365
- }
366
- }, []);
367
- useEffect(() => changeStyles({ resize }), [resize, changeStyles]);
368
-
369
- const createHtmlString = useCallback(() => {
370
- const element = document.getElementById(TEXT_TO_HTML_ID);
371
- if (element) {
372
- let htmlDataString = '';
373
- characters.forEach(({ string }) => (string === 'cursor') ? null : htmlDataString += string);
374
- element.setAttribute('data-string', htmlDataString);
375
-
376
- let newElement = element.cloneNode(true);
377
- newElement.id = `${Math.floor(Math.random() * 1000001)}-${element.id}`;
378
- newElement.style.cursor = 'inherit';
379
- const htmlString = newElement.outerHTML;
380
-
381
- (propsRef.current?.onChange) && propsRef.current.onChange(htmlString);
382
- if (ref.current) ref.current.htmlString = htmlString;
383
- return { htmlString };
384
- }
385
- }, [characters, ref]);
386
- useEffect(() => createHtmlString(), [characters, createHtmlString]);
387
-
388
-
389
- useEffect(() => ref.current = {
390
- ...ref.current,
391
- ...state,
392
- clickAway,
393
- focusToWrite,
394
- createCursor,
395
- setCharacters,
396
- createHtmlString,
397
- setExternalValues
398
- }, [ref, state, setCharacters, createCursor, createHtmlString, clickAway, setExternalValues]);
399
-
400
- const updateExternalValues = ({ state, setExternalValues }) => {
401
- setExternalValues && setExternalValues(state);
402
- };
403
- useEffect(() => updateExternalValues({ state, setExternalValues }), [state, setExternalValues]);
404
-
405
-
406
- return <div className='text-to-html-container'>
407
- {(canWrite) && (
408
- <TextStyles
409
- setColor={value => logicSetState({ type: 'textStyle', field: 'color', value })}
410
- {...{ color, defaultSpacing, toggleClickAway, handleFontSizeChange, textAlign, handleTextAlignChange }}
411
- />
412
- )}
413
- <div id={TEXT_TO_HTML_TEXT_CONTAINER_ID} onClick={handleContainerClick} className='text-to-html-text-container'>
414
- <ClickAwayListener mouseEvent={state.clickAway} touchEvent={state.clickAway} disableReactTree onClickAway={handleClickAway}>
415
- <div
416
- id={TEXT_TO_HTML_ID}
417
- tabIndex={0}
418
- onKeyDown={handleKeyDown}
419
- onKeyUp={handleKeyUp}
420
- onMouseDown={handleMouseDownTouchStart}
421
- onMouseUp={handleMouseUpTouchEnd}
422
- onMouseMove={handleMouseTouchMove}
423
- onTouchStart={handleMouseDownTouchStart}
424
- onTouchEnd={handleMouseUpTouchEnd}
425
- onTouchMove={handleMouseTouchMove}
426
- onClick={handleClick}
427
- onDoubleClick={handleDoubleClick}
428
- style={{
429
- color: (color) ? `rgba(${color.r}, ${color.g}, ${color.b}, ${color.a})` : 'inherit',
430
- textAlign: (textAlign) ? textAlign : 'inherit',
431
- fontSize: (fontSize) ? `${fontSize}rem` : '1rem',
432
- fontFamily: (fontFamily) ? fontFamily : 'inherit',
433
- letterSpacing: (letterSpacing) ? letterSpacing : 'inherit'
434
- }}
435
- className='text-to-html'
436
- >
437
- <p>
438
- {characters.map(({ code, string, dead, mark }, stringIndex) => {
439
- switch (string) {
440
- case 'cursor':
441
- return <Cursor key={`${stringIndex}-${string}`} id={TEXT_TO_HTML_CURSOR_ID} className='text-to-html-cursor' />;
442
- default:
443
- return (string) ? (
444
- <span
445
- key={`${stringIndex}-${string}`}
446
- style={{
447
- textDecoration: (dead || mark?.length) ? 'underline' : ''
448
- }}
449
- >
450
- {string}
451
- </span>
452
- ) : null;
453
- }
454
- })}
455
- </p>
456
- </div>
457
- </ClickAwayListener>
458
- </div>
459
- </div>;
460
- };
461
-
462
-
463
- export default forwardRef(TextToHtml);
@@ -1,2 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
2
- <svg width="800px" height="800px" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M22.354 9.354l-.707-.707-13 13 .707.707zm0 7l-.707-.707-6 6 .707.707z"/><path fill="none" d="M0 0h24v24H0z"/></svg>
@@ -1,2 +0,0 @@
1
- export { default } from './TextToHtml';
2
- export * from './TextToHtml';
@@ -1 +0,0 @@
1
- export { default } from './TextToHtml';
@@ -1,40 +0,0 @@
1
- .text-to-html-container {
2
- width: 100%;
3
- }
4
-
5
- .text-to-html-text-container {
6
- position: absolute;
7
- width: 100%;
8
- height: 100%;
9
- overflow: hidden;
10
- }
11
-
12
- .text-to-html {
13
- touch-action: none;
14
- position: absolute;
15
- top: 45%;
16
- left: 13%;
17
- width: 80%;
18
- display: flex;
19
- flex-wrap: wrap;
20
- align-items: center;
21
- justify-content: center;
22
- outline: 0;
23
- cursor: pointer;
24
- color: inherit;
25
- }
26
-
27
- .text-to-html > p {
28
- margin: 0;
29
- }
30
-
31
- .text-to-html::-webkit-resizer {
32
- background-color: #fff;
33
- background-image: url('./icons/resize_area.svg');
34
- background-repeat: no-repeat;
35
- background-size: cover;
36
- }
37
-
38
- .text-to-html-cursor {
39
- opacity: 0;
40
- }