@sikka/hawa 0.0.234 → 0.0.235

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 (49) hide show
  1. package/_config.yml +1 -0
  2. package/dist/styles.css +0 -3
  3. package/docs/CNAME +1 -0
  4. package/docs/README.md +60 -0
  5. package/docs/_layouts/default.html +47 -0
  6. package/docs/assets/css/style.css +366 -0
  7. package/docs/documentation/229.1b36ccba973b04d66b4c.manager.bundle.js +1 -0
  8. package/docs/documentation/229.f7a1c971.iframe.bundle.js +1 -0
  9. package/docs/documentation/295.67c251ec00675ab59b60.manager.bundle.js +1 -0
  10. package/docs/documentation/51.07b491d3.iframe.bundle.js +2 -0
  11. package/docs/documentation/51.07b491d3.iframe.bundle.js.LICENSE.txt +8 -0
  12. package/docs/documentation/51.e44cb3212565a342a42d.manager.bundle.js +2 -0
  13. package/docs/documentation/51.e44cb3212565a342a42d.manager.bundle.js.LICENSE.txt +8 -0
  14. package/docs/documentation/551.67cd309b0648b0a52636.manager.bundle.js +1 -0
  15. package/docs/documentation/551.c82ea8f1.iframe.bundle.js +1 -0
  16. package/docs/documentation/701.07623c34.iframe.bundle.js +1 -0
  17. package/docs/documentation/767.e90d0d608aa8557f855d.manager.bundle.js +2 -0
  18. package/docs/documentation/767.e90d0d608aa8557f855d.manager.bundle.js.LICENSE.txt +94 -0
  19. package/docs/documentation/807.1424ceed.iframe.bundle.js +2 -0
  20. package/docs/documentation/807.1424ceed.iframe.bundle.js.LICENSE.txt +31 -0
  21. package/docs/documentation/807.4e87168c6f719304d458.manager.bundle.js +2 -0
  22. package/docs/documentation/807.4e87168c6f719304d458.manager.bundle.js.LICENSE.txt +31 -0
  23. package/docs/documentation/897.386c170cbd1467abc7ca.manager.bundle.js +2 -0
  24. package/docs/documentation/897.386c170cbd1467abc7ca.manager.bundle.js.LICENSE.txt +12 -0
  25. package/docs/documentation/897.d9a35fd0.iframe.bundle.js +2 -0
  26. package/docs/documentation/897.d9a35fd0.iframe.bundle.js.LICENSE.txt +12 -0
  27. package/docs/documentation/901.ae81c179.iframe.bundle.js +2 -0
  28. package/docs/documentation/901.ae81c179.iframe.bundle.js.LICENSE.txt +105 -0
  29. package/docs/documentation/935.3a33e233.iframe.bundle.js +1 -0
  30. package/docs/documentation/935.df0c782bef63c348b9da.manager.bundle.js +1 -0
  31. package/docs/documentation/favicon.ico +0 -0
  32. package/docs/documentation/iframe.html +364 -0
  33. package/docs/documentation/index.html +59 -0
  34. package/docs/documentation/main.051275cac7b0dc69501c.manager.bundle.js +1 -0
  35. package/docs/documentation/main.fb64f936.iframe.bundle.js +1 -0
  36. package/docs/documentation/project.json +1 -0
  37. package/docs/documentation/runtime~main.a832da8f0c3235fa0d36.manager.bundle.js +1 -0
  38. package/docs/documentation/runtime~main.d6831407.iframe.bundle.js +1 -0
  39. package/es/elements/index.d.ts +0 -1
  40. package/es/index.es.js +2 -2
  41. package/lib/elements/index.d.ts +0 -1
  42. package/lib/index.js +2 -2
  43. package/package.json +2 -3
  44. package/src/elements/FloatingComment.tsx +711 -92
  45. package/src/elements/index.ts +0 -1
  46. package/src/styles.css +0 -3
  47. package/es/elements/FloatingCommentCE.d.ts +0 -6
  48. package/lib/elements/FloatingCommentCE.d.ts +0 -6
  49. package/src/elements/FloatingCommentCE.tsx +0 -852
@@ -1,852 +0,0 @@
1
- import React, { useRef, useState, useEffect } from "react"
2
- import { RichTextarea } from "rich-textarea"
3
- import clsx from "clsx"
4
-
5
- const Property = (props) => {
6
- return (
7
- <div
8
- className="border-box mr-[5px] flex h-[32px] w-[32px] items-center justify-center rounded bg-gray-400 p-2"
9
- onMouseDown={props.onMouseDown}
10
- >
11
- {props.name}
12
- </div>
13
- )
14
- }
15
-
16
- type ComponentTypes = {
17
- foo?: string
18
- }
19
-
20
- const styleClasses = {
21
- bold: "font-bold",
22
- italic: "italic",
23
- under: "underline",
24
- strike: "line-through",
25
- }
26
-
27
- // FIXME: Deleting a styled part of text while selecting characters on the borders or more
28
- // FIXME: Deleting more than one character of a styled part of text
29
- // FIXME: Pasting styled text doesn't offset succeeding stylings
30
- // FIXME: Pasting styled text inside other stylings
31
- // FIXME: Typing characters behind and after stylings
32
-
33
- // FIXME: Pasting behind the second character in styled text
34
- // FIXME: Pasting over styled text with resumptions and/or highlighted text exceeding pasted text length
35
-
36
- export const FloatingCommentCE: React.FunctionComponent<ComponentTypes> = (
37
- props
38
- ) => {
39
- const [text, _setText] = useState({
40
- content: "",
41
- stylings: [], // A styling is an object with 2 indices specifying a substring of text, and the applied effect
42
- revert: [0, 0],
43
- lastCopy: [],
44
- pasted: { status: false, length: 0 },
45
- })
46
-
47
- const field = useRef(null)
48
- const _text = useRef(text)
49
- const setText = (data) => {
50
- _text.current = data
51
- _setText(data)
52
- }
53
-
54
- const getChildIndex = (child) => {
55
- for (var i = 0; (child = child.previousSibling); i++);
56
- return i
57
- }
58
-
59
- // Full reversion achieved !
60
- const getFieldSelection = () => {
61
- if (document.activeElement != field.current) return [0, 0]
62
-
63
- let selection = window.getSelection()
64
- let nodes = Array.from(field.current.childNodes)
65
-
66
- nodes = nodes.filter(
67
- (item: any) => !["#text", "BR"].includes(item.nodeName)
68
- )
69
-
70
- let startParent: any = selection.anchorNode.parentNode
71
-
72
- let startNodeIndex =
73
- startParent == field.current
74
- ? nodes.length
75
- : // : parseInt(startParent.dataset.childIndex)
76
- getChildIndex(startParent)
77
-
78
- let startPrecedingSum = nodes
79
- .slice(0, startNodeIndex)
80
- .map((span: any) => span.textContent.length)
81
- .reduce((a, b) => a + b, 0)
82
-
83
- let endParent: any = selection.focusNode.parentNode
84
- let endNodeIndex =
85
- endParent == field.current
86
- ? nodes.length
87
- : // : parseInt(endParent.dataset.childIndex)
88
- getChildIndex(endParent)
89
-
90
- let endPrecedingSum = nodes
91
- .slice(0, endNodeIndex)
92
- .map((span: any) => span.textContent.length)
93
- .reduce((a, b) => a + b, 0)
94
-
95
- let result = [
96
- startPrecedingSum + selection.anchorOffset,
97
- endPrecedingSum + selection.focusOffset,
98
- ]
99
-
100
- // Sort to make the minimum selection the start selection
101
- return result.sort((a, b) => a - b)
102
- }
103
-
104
- useEffect(() => {
105
- setTimeout(function () {
106
- let [start, end] = _text.current.revert
107
-
108
- if (start == 0 && end == 0) return
109
-
110
- let startNode = null
111
- let endNode = null
112
-
113
- let total = 0
114
- let nodes = Array.from(field.current.childNodes)
115
-
116
- for (let i = 0; i < nodes.length; i++) {
117
- let node: any = nodes[i]
118
- let sum = node.textContent.length + total
119
-
120
- if (startNode == null && start >= total && start <= sum) {
121
- startNode = nodes[i]
122
- start -= total
123
- }
124
-
125
- if (endNode == null && end > total && end <= sum) {
126
- endNode = nodes[i]
127
- end -= total
128
- }
129
-
130
- total += node.textContent.length
131
- }
132
-
133
- var range = document.createRange()
134
- var sel = window.getSelection()
135
-
136
- range.setStart(startNode.firstChild, start)
137
- range.setEnd(endNode.firstChild, end)
138
-
139
- sel.removeAllRanges()
140
- sel.addRange(range)
141
- }, 1)
142
- }, [text.revert])
143
-
144
- // utility functions
145
- const getRange = (start, end) => {
146
- let result = []
147
- for (let i = start; i <= end; i++) {
148
- result.push(i)
149
- }
150
- return result
151
- }
152
-
153
- const intersection = (setA, setB) => {
154
- const _intersection = new Set()
155
- for (const elem of setB) {
156
- if (setA.has(elem)) {
157
- _intersection.add(elem)
158
- }
159
- }
160
- return _intersection
161
- }
162
-
163
- const getMinimum = (array) => {
164
- return array.sort((a, b) => a - b)[0]
165
- }
166
-
167
- const getMaximum = (array) => {
168
- return array.sort((a, b) => b - a)[0]
169
- }
170
-
171
- // -1 - types dont match
172
- // 0 - s1 is surrounded or on the edge of the s2
173
- // 1 - s1 intersects with s2
174
- // 2 - s1 does not intersect with s2
175
- const getCorrelation = (styling1, styling2) => {
176
- if (styling1.type != styling2.type) return -1
177
-
178
- if (
179
- styling2.start <= styling1.start &&
180
- styling2.finish >= styling1.finish
181
- ) {
182
- return 0
183
- }
184
-
185
- let indices1 = new Set(getRange(styling1.start - 1, styling1.finish - 1))
186
- let indices2 = new Set(getRange(styling2.start - 1, styling2.finish - 1))
187
-
188
- let result = intersection(indices1, indices2)
189
-
190
- return result.size == 0 ? 2 : 1
191
- }
192
-
193
- // Correlation handler
194
- const stylingSplice = (correlations, stylings, current, type) => {
195
- // Only one surround correlation is possible at one time, so use .find to fetch it
196
-
197
- let [_, index, styling] = correlations.find(([c, _, __]) => c == 0)
198
-
199
- // Remove correlated styling
200
- stylings = stylings.filter((_, _index) => _index != index)
201
-
202
- // Get splices
203
- let added = [
204
- {
205
- type: type,
206
- start: getMinimum([styling.start, current.start]),
207
- finish: getMaximum([styling.start, current.start]),
208
- },
209
- {
210
- type: type,
211
- start: getMinimum([styling.finish, current.finish]),
212
- finish: getMaximum([styling.finish, current.finish]),
213
- },
214
- ]
215
-
216
- // Remove empty splices (edge cases)
217
- added = added.filter((item) => item.start != item.finish)
218
-
219
- // Add to current stylings
220
- stylings = [...stylings, ...added]
221
-
222
- return stylings
223
- }
224
-
225
- // Correlation handler
226
- const stylingIntersect = (correlations, stylings, current, type) => {
227
- // Filter out all intersected stylings
228
- let intersections = correlations
229
- .filter(([c, _, __]) => c == 1)
230
- .map(([_, index, styling]) => {
231
- return [index, styling]
232
- })
233
-
234
- // Add current styling with no index for the sake for endpoint indices
235
- intersections.push([-1, current])
236
-
237
- // Get minimum intersection start index
238
- let start = intersections
239
- .map(([_, styling]) => styling.start)
240
- .sort((a, b) => a - b)[0]
241
-
242
- // Get maximum intersection start index
243
- let finish = intersections
244
- .map(([_, styling]) => styling.finish)
245
- .sort((a, b) => b - a)[0]
246
-
247
- // Get indices of all intersection
248
- let indices = intersections.map((e) => e[0])
249
-
250
- // Remove all from resulting styling array
251
- stylings = stylings.filter((_, index) => !indices.includes(index))
252
-
253
- // Add widest styling which encompasses all intersections
254
- stylings.push({
255
- type: type,
256
- start: start,
257
- finish: finish,
258
- })
259
-
260
- return stylings
261
- }
262
-
263
- const perform = (id) => {
264
- let stylings = _text.current.stylings.slice()
265
- let [selectionStart, selectionEnd] = getFieldSelection()
266
-
267
- if (selectionStart == selectionEnd) return
268
-
269
- let current = {
270
- type: id,
271
- start: selectionStart,
272
- finish: selectionEnd,
273
- }
274
-
275
- let correlations = []
276
-
277
- // Check the correlation between this requested styling and all other stylings
278
- for (let i = 0; i < stylings.length; i++) {
279
- let styling = stylings[i]
280
- let correlation = getCorrelation(current, styling)
281
-
282
- if (correlation != -1) correlations.push([correlation, i, styling])
283
- }
284
-
285
- let result
286
-
287
- if (correlations.find(([c, _, __]) => c == 1)) {
288
- result = stylingIntersect(correlations, stylings, current, id)
289
- } else if (correlations.find(([c, _, __]) => c == 0)) {
290
- result = stylingSplice(correlations, stylings, current, id)
291
- } else if (
292
- correlations.find(([c, _, __]) => c == 2) ||
293
- correlations.length == 0
294
- ) {
295
- result = [...stylings, current]
296
- }
297
-
298
- setText({
299
- ...text,
300
- stylings: result,
301
- revert: [selectionStart, selectionEnd],
302
- })
303
- }
304
-
305
- const getRangeIntersectStylings = (start, end, startOffset, finishOffset) => {
306
- // Get all stylings intersecting
307
- let stylings = []
308
- for (let i = start; i < end; i++) {
309
- stylings.push(getIntersectStylings(i, startOffset, finishOffset))
310
- }
311
-
312
- // Remove duplicates
313
- stylings = stylings.flat().filter((item) => item)
314
- stylings = stylings.filter(
315
- (item, index) =>
316
- stylings.findIndex(
317
- (_item) =>
318
- _item.start == item.start &&
319
- _item.finish == item.finish &&
320
- _item.type == item.type
321
- ) == index
322
- )
323
-
324
- return stylings
325
- }
326
-
327
- const compareStylings = (styling1, styling2) => {
328
- return (
329
- styling1.type == styling2.type &&
330
- styling1.start == styling2.start &&
331
- styling1.finish == styling2.finish
332
- )
333
- }
334
-
335
- // Get stylings encompassing an index within it's range
336
- const getIntersectStylings = (index, startOffset = 0, finishOffset = 0) => {
337
- // Find all stylings with encompassing range
338
- let matches = text.stylings.filter(
339
- ({ start, finish }) =>
340
- index >= start + startOffset && index < finish + finishOffset
341
- )
342
-
343
- return matches
344
- }
345
-
346
- // Get stylings after an index
347
- const getSucceedStylings = (index) => {
348
- // Find all stylings after the index
349
- let matches = text.stylings.filter(({ start, finish }) => start >= index)
350
-
351
- return matches
352
- }
353
-
354
- const getStylingIndex = (styling) => {
355
- return text.stylings.findIndex(
356
- (item) =>
357
- item.start == styling.start &&
358
- item.finish == styling.finish &&
359
- item.type == styling.type
360
- )
361
- }
362
-
363
- const handleScenario = (stylings, predicate) => {
364
- let matches = stylings.filter(({ start: _start, finish: _finish }) =>
365
- predicate(_start, _finish)
366
- )
367
-
368
- let indices = []
369
-
370
- stylings.map((styling, index) => {
371
- let result = matches.find((item) => compareStylings(styling, item))
372
- if (!result) return
373
- indices.push({
374
- index: index,
375
- start: styling.start,
376
- finish: styling.finish,
377
- })
378
- })
379
-
380
- return indices
381
- }
382
-
383
- const handleDeletion = (length, start, end) => {
384
- let stylings = _text.current.stylings.slice()
385
- let changes = []
386
-
387
- console.log(`Deletion`)
388
- console.log([start, end])
389
-
390
- // TODO: Refactor
391
-
392
- // Offset all succeeding stylings by length
393
- // changes.push(
394
- // handleScenario(
395
- // stylings,
396
- // (_start, _finish) => start < _start && end <= start
397
- // ).map((styling) => {
398
- // return {
399
- // ...styling,
400
- // start: styling.start - length,
401
- // finish: styling.finish - length,
402
- // }
403
- // })
404
- // )
405
-
406
- let succeeding = stylings.filter(
407
- ({ start: _start }) => start < _start && end <= _start
408
- )
409
- stylings.map((styling, index) => {
410
- let result = succeeding.find((item) => compareStylings(styling, item))
411
- if (!result) return
412
-
413
- changes.push({
414
- index: index,
415
- start: styling.start - length,
416
- finish: styling.finish - length,
417
- })
418
- })
419
-
420
- // Handle complete encapsulation over styling
421
- let encapsulating = stylings.filter(
422
- ({ start: _start, finish: _finish }) => start <= _start && end >= _finish
423
- )
424
- stylings.map((styling, index) => {
425
- let result = encapsulating.find((item) => compareStylings(styling, item))
426
- if (!result) return
427
-
428
- // This will effectively remove the styling, since collapsed ranges are automatically removed
429
- changes.push({
430
- index: index,
431
- start: styling.start,
432
- finish: styling.start,
433
- })
434
- })
435
-
436
- // Handle deletion being encapsulated by styling
437
- let encapsulated = stylings.filter(
438
- ({ start: _start, finish: _finish }) =>
439
- (start > _start && end <= _finish) || (start >= _start && end < _finish)
440
- )
441
- stylings.map((styling, index) => {
442
- let result = encapsulated.find((item) => compareStylings(styling, item))
443
- if (!result) return
444
-
445
- changes.push({
446
- index: index,
447
- start: styling.start,
448
- finish: styling.finish - length,
449
- })
450
- })
451
-
452
- // Handle deletion being encapsulated by styling with left resumption
453
- let leftResumption = stylings.filter(
454
- ({ start: _start, finish: _finish }) =>
455
- end < _finish && end > _start && start < _start
456
- )
457
- stylings.map((styling, index) => {
458
- let result = leftResumption.find((item) => compareStylings(styling, item))
459
- if (!result) return
460
-
461
- changes.push({
462
- index: index,
463
- start: getMaximum([end, styling.start]) - length,
464
- finish: styling.finish - length,
465
- })
466
- })
467
-
468
- let rightResumption = stylings.filter(
469
- ({ start: _start, finish: _finish }) =>
470
- start > _start && start < _finish && end > _finish
471
- )
472
- stylings.map((styling, index) => {
473
- let result = rightResumption.find((item) =>
474
- compareStylings(styling, item)
475
- )
476
- if (!result) return
477
-
478
- changes.push({
479
- index: index,
480
- start: styling.start,
481
- finish: getMinimum([start, styling.finish]),
482
- })
483
- })
484
-
485
- // Apply changes
486
- changes.map(({ index, start, finish }) => {
487
- stylings[index] = {
488
- ...stylings[index],
489
- start: start,
490
- finish: finish,
491
- }
492
- })
493
-
494
- // Handle complete encapsulation by styling
495
- // stylings = stylings.map((styling) => {
496
- // if (start >= styling.start && end <= styling.finish) {
497
- // console.log("hi")
498
- // }
499
-
500
- // return styling
501
- // })
502
-
503
- // If deletion is surrounded by styling, decrease finish by length (this might not include first character, but try first)
504
- // If deletion is intersecting with a styling behind it, get maximum between deletion finish and styling start, and set the start to it, then offset styling by length
505
- // If deletion is intersecting wit ha styling after it, get minimum between deletion start and styling finish, and set the finish to it
506
-
507
- // console.log(succeeding)
508
-
509
- // If the start and finish of any styling is greater than the new length, remove it
510
-
511
- return stylings
512
- }
513
-
514
- const handleAddition = (length, start, end) => {
515
- start -= length
516
- end -= length
517
-
518
- let stylings = _text.current.stylings.slice()
519
-
520
- let changes = []
521
-
522
- let succeeding = handleScenario(
523
- stylings,
524
- (_start, _finish) => _start + 1 >= start && _start + 1 >= end
525
- ).map((styling) => {
526
- return {
527
- ...styling,
528
- start: styling.start + length,
529
- finish: styling.finish + length,
530
- }
531
- })
532
- changes.push(succeeding)
533
-
534
- console.log(`Addition (${length})`)
535
- console.log([start, end])
536
- console.log(`Succeeding:`)
537
- console.log(succeeding)
538
-
539
- let preceding = handleScenario(
540
- stylings,
541
- (_start, _finish) => start <= _finish && start >= _start + 2
542
- ).map((styling) => {
543
- return {
544
- ...styling,
545
- start: styling.start,
546
- finish: styling.finish + length,
547
- }
548
- })
549
- changes.push(preceding)
550
-
551
- console.log(`Preceding:`)
552
- console.log(preceding)
553
-
554
- changes.flat().map(({ index, start, finish }) => {
555
- stylings[index] = {
556
- ...stylings[index],
557
- start: start,
558
- finish: finish,
559
- }
560
- })
561
-
562
- return stylings
563
- }
564
-
565
- const handlePaste = (stylings, start, end) => {
566
- console.log([start, end])
567
- console.log(stylings)
568
-
569
- return stylings
570
- }
571
-
572
- const onChange = (value) => {
573
- setTimeout(function () {
574
- let [selectionStart, selectionEnd] = getFieldSelection()
575
-
576
- let difference = value.length - _text.current.content.length
577
-
578
- let start = selectionStart - difference
579
- let end = selectionEnd - difference
580
-
581
- let stylings = _text.current.stylings.slice()
582
-
583
- let succeeding = getSucceedStylings(start)
584
- let changes = []
585
-
586
- for (let succeed of succeeding) {
587
- let index = getStylingIndex(succeed)
588
- let styling = stylings[index]
589
-
590
- changes.push([
591
- index,
592
- styling.start + difference,
593
- styling.finish + difference,
594
- ])
595
- }
596
-
597
- if (difference < 0) {
598
- stylings = handleDeletion(
599
- Math.abs(difference),
600
- selectionStart,
601
- selectionEnd + Math.abs(difference)
602
- )
603
- }
604
-
605
- if (difference > 0) {
606
- stylings = handleAddition(
607
- Math.abs(difference),
608
- selectionStart,
609
- selectionEnd
610
- )
611
- }
612
-
613
- // Remove empty stylings and invisible stylings
614
- stylings = stylings.filter(
615
- (styling) =>
616
- !(
617
- styling.start == styling.finish ||
618
- (styling.start >= value.length && styling.finish >= value.length)
619
- )
620
- )
621
-
622
- if (_text.current.pasted.status) {
623
- stylings = handlePaste(
624
- stylings,
625
- selectionStart - _text.current.pasted.length,
626
- selectionStart
627
- )
628
- }
629
-
630
- setText({
631
- ..._text.current,
632
- content: value,
633
- stylings: stylings,
634
- revert: [selectionStart, selectionEnd],
635
- pasted: { status: false, length: 0 },
636
- })
637
- }, 0)
638
- }
639
-
640
- const getContent = () => {
641
- let content = _text.current.content
642
-
643
- // Get all styling indices
644
- let indices = _text.current.stylings
645
- .map(({ start, finish }) => [start, finish])
646
- .flat()
647
-
648
- // Sort ascendingly
649
- indices = indices.sort((a, b) => a - b)
650
-
651
- // Remove duplicates
652
- indices = indices.filter(
653
- (element, index) => indices.indexOf(element) == index
654
- )
655
-
656
- // Add first index if not present
657
- if (indices[0] != 0) indices.unshift(0)
658
-
659
- // Add last index if not present
660
- let last = content.length
661
- if (indices[indices.length - 1] != last) indices.push(last)
662
-
663
- let result = []
664
-
665
- for (let i = 0; i < indices.length - 1; i++) {
666
- result.push([indices[i], content.substring(indices[i], indices[i + 1])])
667
- }
668
-
669
- return result
670
- }
671
-
672
- const serializeStyleInRange = (start, end) => {
673
- // Get all stylings intersecting
674
- let stylings = []
675
- for (let i = start; i < end; i++) {
676
- stylings.push(getIntersectStylings(i))
677
- }
678
-
679
- // Remove duplicates
680
- stylings = stylings.flat().filter((item) => item)
681
- stylings = stylings.filter(
682
- (item, index) =>
683
- stylings.findIndex(
684
- (_item) =>
685
- _item.start == item.start &&
686
- _item.finish == item.finish &&
687
- _item.type == item.type
688
- ) == index
689
- )
690
-
691
- // Clamp start and finish values and offset by start index
692
- stylings = stylings.map((styling) => {
693
- return {
694
- ...styling,
695
- start: getMaximum([styling.start, start]) - start,
696
- finish: getMinimum([styling.finish, end]) - start,
697
- }
698
- })
699
-
700
- return stylings
701
- }
702
-
703
- // dangerouslySetInnerHTML incorrectly renders when the entire text is highlighted, copied, and then pasted in succession
704
- useEffect(() => {
705
- let html = getContent()
706
- .map((_data, index) => {
707
- let [start, data] = _data
708
-
709
- // Get stylings encompassing an index within it's range
710
- let stylings = getIntersectStylings(start)
711
- // console.log(data)
712
- // console.log(stylings)
713
- return `<span class="${stylings
714
- .map((styling) => styleClasses[styling.type])
715
- .join(" ")}" data-child-index="${index}">${data}</span>`
716
- })
717
- .join("")
718
-
719
- field.current.innerHTML = html
720
- }, [text.content, text.stylings, text.revert])
721
-
722
- return (
723
- <div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded bg-blue-300 shadow-md">
724
- <div className={clsx("flex w-full flex-row justify-start p-2")}>
725
- <Property
726
- name="B"
727
- onMouseDown={(event) => {
728
- event.preventDefault() // This does not take focus away from field which allows the function to retrieve the current selection data
729
- perform("bold")
730
- }}
731
- />
732
- <Property
733
- name="I"
734
- onMouseDown={(event) => {
735
- event.preventDefault()
736
- perform("italic")
737
- }}
738
- />
739
- <Property
740
- name="U"
741
- onMouseDown={(event) => {
742
- event.preventDefault()
743
- perform("under")
744
- }}
745
- />
746
- <Property
747
- name="S"
748
- onMouseDown={(event) => {
749
- event.preventDefault()
750
- perform("strike")
751
- }}
752
- />
753
- </div>
754
- <div className="h-[1px] w-full bg-slate-600">&nbsp;</div>
755
- <div className="w-full">
756
- <div
757
- ref={field}
758
- contentEditable="true"
759
- className="h-[150px] w-full resize-none overflow-auto overflow-x-hidden border-none p-2 outline-none"
760
- onPaste={(event) => {
761
- // pastes all copied text from the content editable as plain text
762
- event.preventDefault()
763
- const data = event.clipboardData.getData("text/plain")
764
- document.execCommand("insertHTML", false, data)
765
-
766
- console.log(data)
767
-
768
- setText({
769
- ..._text.current,
770
- pasted: { status: true, length: data.length },
771
- })
772
-
773
- // let [start, end] = getFieldSelection()
774
-
775
- // console.log(index)
776
- // console.log(start)
777
-
778
- // let index = start - data.length
779
- // let stylings = text.stylings.slice()
780
-
781
- // FIXME:
782
- // stylings.push({
783
- // type: "bold",
784
- // start: 5,
785
- // finish: 7,
786
- // })
787
-
788
- // let copy = text.lastCopy
789
- // if (copy.length != 0) {
790
- // for (let styling of copy) {
791
- // stylings.push({
792
- // type: styling.type,
793
- // start: styling.start + start,
794
- // finish: styling.finish + start,
795
- // })
796
- // }
797
- // }
798
-
799
- // let content: any = text.content
800
- // let original = content.length
801
-
802
- // // If not collapsed, insert text
803
- // if (start == end) {
804
- // content = content.split("")
805
- // content.splice(start, 0, data)
806
- // content = content.join("")
807
- // } else {
808
- // console.log(content)
809
- // // Otherwise, replace substring
810
- // content =
811
- // content.substring(0, start) +
812
- // data +
813
- // content.substring(end, content.length)
814
- // }
815
-
816
- // let difference = content.length - original
817
-
818
- // stylings = handleDeletion()
819
-
820
- // setText({
821
- // ...text,
822
- // content: content,
823
- // stylings: stylings,
824
- // revert: [start + data.length, start + data.length],
825
- // })
826
- }}
827
- onInput={(event: any) => {
828
- onChange(event.target.textContent)
829
- }}
830
- onCopy={(event) => {
831
- let [start, end] = getFieldSelection()
832
-
833
- let data = serializeStyleInRange(start, end)
834
-
835
- setText({
836
- ...text,
837
- lastCopy: data,
838
- })
839
- }}
840
- // onKeyDown={(event: any) => {
841
- // event.preventDefault()
842
- // console.log(event)
843
- // }}
844
- ></div>
845
- </div>
846
- <div className="h-[1px] w-full bg-slate-600">&nbsp;</div>
847
- <button className="my-1 rounded bg-cyan-800 p-2 py-1 text-white">
848
- Submit
849
- </button>
850
- </div>
851
- )
852
- }