@sikka/hawa 0.0.235 → 0.0.237
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/styles.css +15 -0
- package/docs/documentation/iframe.html +1 -1
- package/docs/documentation/main.53a90744.iframe.bundle.js +1 -0
- package/docs/documentation/project.json +1 -1
- package/es/elements/FloatingComment.d.ts +27 -1
- package/es/index.es.js +1 -1
- package/lib/elements/FloatingComment.d.ts +27 -1
- package/lib/index.js +2 -2
- package/package.json +1 -1
- package/src/elements/FloatingComment.tsx +407 -142
- package/src/styles.css +15 -0
- package/docs/documentation/main.fb64f936.iframe.bundle.js +0 -1
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ import clsx from "clsx"
|
|
|
4
4
|
const Property = (props) => {
|
|
5
5
|
return (
|
|
6
6
|
<div
|
|
7
|
-
className="border-box mr-[
|
|
7
|
+
className="border-box mr-[10px] flex h-[32px] w-[32px] items-center justify-center rounded bg-gray-300 p-2"
|
|
8
8
|
onMouseDown={props.onMouseDown}
|
|
9
9
|
>
|
|
10
10
|
{props.name}
|
|
@@ -13,21 +13,33 @@ const Property = (props) => {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
type ComponentTypes = {
|
|
16
|
-
|
|
16
|
+
rtl?: "enabled" | "disabled" | "auto"
|
|
17
|
+
onSubmit?: (
|
|
18
|
+
content: string,
|
|
19
|
+
stylings: { type: keyof typeof stylers; start: number; finish: number }[]
|
|
20
|
+
) => void
|
|
17
21
|
}
|
|
18
22
|
|
|
19
|
-
const
|
|
20
|
-
bold: "font-bold",
|
|
21
|
-
italic: "italic",
|
|
22
|
-
under: "underline",
|
|
23
|
-
strike: "line-through",
|
|
23
|
+
const stylers = {
|
|
24
|
+
bold: { css: "font-bold", content: "B" },
|
|
25
|
+
italic: { id: "italic", css: "italic", content: "I" },
|
|
26
|
+
under: { id: "under", css: "underline", content: "U" },
|
|
27
|
+
strike: { id: "strike", css: "line-through", content: "S" },
|
|
24
28
|
}
|
|
25
29
|
|
|
26
|
-
// FIXME: Highlighting a part of styled text with a bit on the left with an overall length not equal to clipboard copied text will result in paste issues
|
|
30
|
+
// FIXME: ? Highlighting a part of styled text with a bit on the left with an overall length not equal to clipboard copied text will result in paste issues
|
|
27
31
|
|
|
28
32
|
// FIXME: Highlighting the beginning characters of styled text and then pasting text sometimes doesn't register as right intersecting
|
|
29
33
|
// This expecially happens when the selection is for example, [0, 2] and the styling is [0, 3], this might be failure of addition which doesn't offset the styling
|
|
30
34
|
|
|
35
|
+
// TODO: Refactor styling splicing into one method
|
|
36
|
+
// TODO: Refactor function that simplifies a list of stylings
|
|
37
|
+
// TODO: Turn stylings into a class, this should also change .finish to .end
|
|
38
|
+
|
|
39
|
+
// Possible logic changes:
|
|
40
|
+
// Paste = Removal + Addition -> Styling Removal + Styling Addition
|
|
41
|
+
// Drag & Drop = Removal + Addition -> Styling Removal + Styling Addition
|
|
42
|
+
|
|
31
43
|
export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
32
44
|
props
|
|
33
45
|
) => {
|
|
@@ -37,6 +49,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
37
49
|
revert: [0, 0],
|
|
38
50
|
lastCopy: [],
|
|
39
51
|
pasted: { status: false, length: 0 },
|
|
52
|
+
dropped: { status: false, text: "", previous: [0, 0] },
|
|
40
53
|
})
|
|
41
54
|
|
|
42
55
|
const field = useRef(null)
|
|
@@ -51,42 +64,101 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
51
64
|
return i
|
|
52
65
|
}
|
|
53
66
|
|
|
54
|
-
|
|
55
|
-
const getFieldSelection = () => {
|
|
56
|
-
if (document.activeElement != field.current) return [0, 0]
|
|
57
|
-
|
|
67
|
+
const getSelectionPrecedingSum = (name) => {
|
|
58
68
|
let selection = window.getSelection()
|
|
59
69
|
let nodes = Array.from(field.current.childNodes)
|
|
60
70
|
|
|
71
|
+
// All current occurences for text or br:
|
|
72
|
+
// Pasting on empty text (text)
|
|
73
|
+
// Cutting/removing all text (br)
|
|
74
|
+
// Typing the first character in empty text (text)
|
|
75
|
+
// Dragging text to the end of the text (text)
|
|
76
|
+
|
|
61
77
|
nodes = nodes.filter(
|
|
62
78
|
(item: any) => !["#text", "BR"].includes(item.nodeName)
|
|
63
79
|
)
|
|
64
80
|
|
|
65
|
-
let
|
|
81
|
+
let parent: any = selection[name].parentNode
|
|
82
|
+
let special = 0
|
|
83
|
+
|
|
84
|
+
// Special case for empty text
|
|
85
|
+
// if (parent == field.current) {
|
|
86
|
+
// console.log("hi")
|
|
87
|
+
// }
|
|
88
|
+
|
|
89
|
+
// Special case for dropping text near or inside styled text
|
|
90
|
+
if (!Array.from(parent.parentNode.classList).includes("selection-ignore")) {
|
|
91
|
+
parent = parent.parentNode
|
|
66
92
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
:
|
|
71
|
-
|
|
93
|
+
let index = getChildIndex(selection[name].parentNode)
|
|
94
|
+
special = Array.from(parent.childNodes)
|
|
95
|
+
.slice(0, index)
|
|
96
|
+
.map((e: any) => e.textContent.length)
|
|
97
|
+
.reduce((a, b) => a + b, 0)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
let index = parent == field.current ? nodes.length : getChildIndex(parent)
|
|
101
|
+
|
|
102
|
+
let sum =
|
|
103
|
+
nodes
|
|
104
|
+
.slice(0, index)
|
|
105
|
+
.map((span: any) => span.textContent.length)
|
|
106
|
+
.reduce((a, b) => a + b, 0) + special
|
|
107
|
+
|
|
108
|
+
return sum
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const getFieldSelection = () => {
|
|
112
|
+
if (document.activeElement != field.current) return [0, 0]
|
|
72
113
|
|
|
73
|
-
let
|
|
74
|
-
|
|
75
|
-
.map((span: any) => span.textContent.length)
|
|
76
|
-
.reduce((a, b) => a + b, 0)
|
|
114
|
+
let selection = window.getSelection()
|
|
115
|
+
// let nodes = Array.from(field.current.childNodes)
|
|
77
116
|
|
|
78
|
-
|
|
79
|
-
let endNodeIndex =
|
|
80
|
-
endParent == field.current
|
|
81
|
-
? nodes.length
|
|
82
|
-
: // : parseInt(endParent.dataset.childIndex)
|
|
83
|
-
getChildIndex(endParent)
|
|
117
|
+
// console.log(nodes)
|
|
84
118
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.reduce((a, b) => a + b, 0)
|
|
119
|
+
// nodes = nodes.filter(
|
|
120
|
+
// (item: any) => !["#text", "BR"].includes(item.nodeName)
|
|
121
|
+
// )
|
|
89
122
|
|
|
123
|
+
// console.log(selection.anchorNode)
|
|
124
|
+
// console.log(selection.focusNode)
|
|
125
|
+
// console.log(selection.anchorNode.parentNode)
|
|
126
|
+
// console.log(selection.focusNode.parentNode)
|
|
127
|
+
// console.log(selection.anchorNode.parentNode.parentNode)
|
|
128
|
+
// console.log(selection.focusNode.parentNode.parentNode)
|
|
129
|
+
// console.log(selection.anchorOffset)
|
|
130
|
+
// console.log(selection.focusOffset)
|
|
131
|
+
|
|
132
|
+
// let startParent: any = selection.anchorNode.parentNode
|
|
133
|
+
|
|
134
|
+
// let startNodeIndex =
|
|
135
|
+
// startParent == field.current
|
|
136
|
+
// ? nodes.length
|
|
137
|
+
// : // : parseInt(startParent.dataset.childIndex)
|
|
138
|
+
// getChildIndex(startParent)
|
|
139
|
+
|
|
140
|
+
// let startPrecedingSum = nodes
|
|
141
|
+
// .slice(0, startNodeIndex)
|
|
142
|
+
// .map((span: any) => span.textContent.length)
|
|
143
|
+
// .reduce((a, b) => a + b, 0)
|
|
144
|
+
|
|
145
|
+
let startPrecedingSum = getSelectionPrecedingSum("anchorNode")
|
|
146
|
+
|
|
147
|
+
// let endParent: any = selection.focusNode.parentNode
|
|
148
|
+
// let endNodeIndex =
|
|
149
|
+
// endParent == field.current
|
|
150
|
+
// ? nodes.length
|
|
151
|
+
// : // : parseInt(endParent.dataset.childIndex)
|
|
152
|
+
// getChildIndex(endParent)
|
|
153
|
+
|
|
154
|
+
// let endPrecedingSum = nodes
|
|
155
|
+
// .slice(0, endNodeIndex)
|
|
156
|
+
// .map((span: any) => span.textContent.length)
|
|
157
|
+
// .reduce((a, b) => a + b, 0)
|
|
158
|
+
|
|
159
|
+
let endPrecedingSum = getSelectionPrecedingSum("focusNode")
|
|
160
|
+
|
|
161
|
+
console.log([startPrecedingSum, endPrecedingSum])
|
|
90
162
|
let result = [
|
|
91
163
|
startPrecedingSum + selection.anchorOffset,
|
|
92
164
|
endPrecedingSum + selection.focusOffset,
|
|
@@ -524,11 +596,11 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
524
596
|
})
|
|
525
597
|
changes.push(succeeding)
|
|
526
598
|
|
|
527
|
-
console.log(`Addition (${length})`)
|
|
528
|
-
console.log([start, end])
|
|
529
|
-
if (stylings.length > 0) {
|
|
530
|
-
|
|
531
|
-
}
|
|
599
|
+
// console.log(`Addition (${length})`)
|
|
600
|
+
// console.log([start, end])
|
|
601
|
+
// if (stylings.length > 0) {
|
|
602
|
+
// console.log([stylings[0].start, stylings[0].finish])
|
|
603
|
+
// }
|
|
532
604
|
|
|
533
605
|
// console.log(succeeding)
|
|
534
606
|
|
|
@@ -557,12 +629,12 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
557
629
|
|
|
558
630
|
changes.push(encapsulated)
|
|
559
631
|
|
|
560
|
-
console.log(length)
|
|
632
|
+
// console.log(length)
|
|
561
633
|
|
|
562
|
-
console.log(`Encapsulated: ${encapsulated.length}`)
|
|
634
|
+
// console.log(`Encapsulated: ${encapsulated.length}`)
|
|
563
635
|
|
|
564
|
-
console.log(`Succeeding: ${succeeding.length}`)
|
|
565
|
-
console.log(`Preceding: ${preceding.length}`)
|
|
636
|
+
// console.log(`Succeeding: ${succeeding.length}`)
|
|
637
|
+
// console.log(`Preceding: ${preceding.length}`)
|
|
566
638
|
// console.log(preceding)
|
|
567
639
|
|
|
568
640
|
changes.flat().map(({ index, start, finish }) => {
|
|
@@ -577,13 +649,12 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
577
649
|
}
|
|
578
650
|
|
|
579
651
|
const handlePaste = (stylings, difference, start, end) => {
|
|
580
|
-
console.log(`Paste:`)
|
|
581
|
-
console.log([start, end])
|
|
582
|
-
console.log(stylings)
|
|
652
|
+
// console.log(`Paste:`)
|
|
653
|
+
// console.log([start, end])
|
|
654
|
+
// console.log(stylings)
|
|
583
655
|
let changes = []
|
|
584
656
|
|
|
585
657
|
// Get stylings being encapsulated by pasting range
|
|
586
|
-
|
|
587
658
|
let encapsulating = handleScenario(
|
|
588
659
|
stylings,
|
|
589
660
|
(_start, _end) => start <= _start && end >= _end // This is needed because of conflict with addition/deletion
|
|
@@ -655,10 +726,10 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
655
726
|
|
|
656
727
|
changes.push(right)
|
|
657
728
|
|
|
658
|
-
console.log(`Encapsulating: ${encapsulating.length}`)
|
|
659
|
-
console.log(`Encapsulated: ${encapsulated.length}`)
|
|
660
|
-
console.log(`Left Intersecting: ${left.length}`)
|
|
661
|
-
console.log(`Right Intersecting: ${right.length}`)
|
|
729
|
+
// console.log(`Encapsulating: ${encapsulating.length}`)
|
|
730
|
+
// console.log(`Encapsulated: ${encapsulated.length}`)
|
|
731
|
+
// console.log(`Left Intersecting: ${left.length}`)
|
|
732
|
+
// console.log(`Right Intersecting: ${right.length}`)
|
|
662
733
|
|
|
663
734
|
changes = changes.flat()
|
|
664
735
|
changes.map((styling) => {
|
|
@@ -679,15 +750,225 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
679
750
|
}
|
|
680
751
|
})
|
|
681
752
|
|
|
682
|
-
console.log(stylings)
|
|
753
|
+
// console.log(stylings)
|
|
683
754
|
|
|
684
755
|
return stylings
|
|
685
756
|
}
|
|
686
757
|
|
|
758
|
+
const handleDrop = (value) => {
|
|
759
|
+
let [dropStart, dropEnd] = getFieldSelection()
|
|
760
|
+
|
|
761
|
+
let stylings = _text.current.stylings.slice()
|
|
762
|
+
let dropped = _text.current.dropped.text
|
|
763
|
+
|
|
764
|
+
let changes = []
|
|
765
|
+
|
|
766
|
+
let [dragStart, dragEnd] = _text.current.dropped.previous
|
|
767
|
+
|
|
768
|
+
console.log(`Drag: ${[dragStart, dragEnd]}`)
|
|
769
|
+
console.log(`Drop: ${[dropStart, dropEnd]}`)
|
|
770
|
+
console.log(stylings)
|
|
771
|
+
|
|
772
|
+
// negative - right, positive - left
|
|
773
|
+
// let direction = dragStart - dropStart < 0 ? -1 : 1
|
|
774
|
+
|
|
775
|
+
// Possible refactorization:
|
|
776
|
+
// Since the drop invokes the onInput event twice, the first is the removal of dragged text, and the second is the addition of dropped text
|
|
777
|
+
// If the handling occurs at the second occurence of onInput, the first could be handled naturally by the handleDeletion function
|
|
778
|
+
|
|
779
|
+
// offset: length * direction
|
|
780
|
+
|
|
781
|
+
// To be offset in right conditions:
|
|
782
|
+
// (_start >= dg.end && _end > dg.end)
|
|
783
|
+
// (_end <= dp.start && _start < dp.start)
|
|
784
|
+
|
|
785
|
+
// To be offset in left conditions:
|
|
786
|
+
// (_end <= dg.start && _start < dg.start)
|
|
787
|
+
// (_start >= dp.end && _end > dp.end)
|
|
788
|
+
|
|
789
|
+
// Get all intersecting stylings
|
|
790
|
+
let dragStylings = stylings.filter(
|
|
791
|
+
({ start, finish }) =>
|
|
792
|
+
!(
|
|
793
|
+
(start < dragStart && finish <= dragStart) ||
|
|
794
|
+
(start >= dragEnd && finish > dragEnd)
|
|
795
|
+
)
|
|
796
|
+
)
|
|
797
|
+
|
|
798
|
+
// Offset stylings between drag and drop locations
|
|
799
|
+
stylings
|
|
800
|
+
.filter(({ start, finish }) => start >= dragEnd && finish > dragEnd)
|
|
801
|
+
.map((styling) => {
|
|
802
|
+
changes.push({
|
|
803
|
+
original: styling,
|
|
804
|
+
changed: {
|
|
805
|
+
...styling,
|
|
806
|
+
start: styling.start - dropped.length,
|
|
807
|
+
finish: styling.finish - dropped.length,
|
|
808
|
+
},
|
|
809
|
+
})
|
|
810
|
+
})
|
|
811
|
+
|
|
812
|
+
// Handle complete encapsulation over styling
|
|
813
|
+
stylings
|
|
814
|
+
.filter(({ start, finish }) => dragStart <= start && dragEnd >= finish)
|
|
815
|
+
.map((styling) => {
|
|
816
|
+
changes.push({
|
|
817
|
+
original: styling,
|
|
818
|
+
changed: { ...styling, start: styling.start, finish: styling.start },
|
|
819
|
+
})
|
|
820
|
+
})
|
|
821
|
+
|
|
822
|
+
// Handle drag range being encapsulated by styling
|
|
823
|
+
stylings
|
|
824
|
+
.filter(
|
|
825
|
+
({ start, finish }) =>
|
|
826
|
+
(dragStart > start && dragEnd <= finish) ||
|
|
827
|
+
(dragStart >= start && dragEnd < finish)
|
|
828
|
+
)
|
|
829
|
+
.map((styling) => {
|
|
830
|
+
changes.push({
|
|
831
|
+
original: styling,
|
|
832
|
+
changed: {
|
|
833
|
+
...styling,
|
|
834
|
+
start: styling.start,
|
|
835
|
+
finish: styling.finish - dropped.length,
|
|
836
|
+
},
|
|
837
|
+
})
|
|
838
|
+
})
|
|
839
|
+
|
|
840
|
+
// Handle resumptions
|
|
841
|
+
let resumptions = stylings.filter(
|
|
842
|
+
({ start, finish }) =>
|
|
843
|
+
(finish > dragStart &&
|
|
844
|
+
start > dragStart &&
|
|
845
|
+
start < dragEnd &&
|
|
846
|
+
finish > dragEnd) ||
|
|
847
|
+
(start < dragEnd &&
|
|
848
|
+
finish < dragEnd &&
|
|
849
|
+
finish > dragStart &&
|
|
850
|
+
start < dragStart)
|
|
851
|
+
)
|
|
852
|
+
|
|
853
|
+
resumptions.map((styling) => {
|
|
854
|
+
let right =
|
|
855
|
+
styling.start < dragEnd &&
|
|
856
|
+
styling.finish < dragEnd &&
|
|
857
|
+
styling.finish > dragStart &&
|
|
858
|
+
styling.start < dragStart
|
|
859
|
+
|
|
860
|
+
changes.push({
|
|
861
|
+
original: styling,
|
|
862
|
+
changed: {
|
|
863
|
+
...styling,
|
|
864
|
+
start: !right
|
|
865
|
+
? getMaximum([dragEnd, styling.start]) - dropped.length // Only decrease if the drag
|
|
866
|
+
: styling.start,
|
|
867
|
+
finish: right
|
|
868
|
+
? getMinimum([dragStart, styling.finish])
|
|
869
|
+
: styling.finish - dropped.length,
|
|
870
|
+
},
|
|
871
|
+
})
|
|
872
|
+
})
|
|
873
|
+
|
|
874
|
+
// Apply drag changes
|
|
875
|
+
changes.map(({ original, changed }) => {
|
|
876
|
+
let index = stylings.findIndex((styling) =>
|
|
877
|
+
compareStylings(original, styling)
|
|
878
|
+
)
|
|
879
|
+
|
|
880
|
+
stylings[index] = changed
|
|
881
|
+
})
|
|
882
|
+
|
|
883
|
+
changes = []
|
|
884
|
+
|
|
885
|
+
// Positive offset succeeding stylings
|
|
886
|
+
stylings
|
|
887
|
+
.filter(({ start, finish }) => start >= dropStart && finish > dropStart)
|
|
888
|
+
.map((styling) => {
|
|
889
|
+
changes.push({
|
|
890
|
+
original: styling,
|
|
891
|
+
changed: {
|
|
892
|
+
...styling,
|
|
893
|
+
start: styling.start + dropped.length,
|
|
894
|
+
finish: styling.finish + dropped.length,
|
|
895
|
+
},
|
|
896
|
+
})
|
|
897
|
+
})
|
|
898
|
+
|
|
899
|
+
// Splice intersecting stylings
|
|
900
|
+
stylings
|
|
901
|
+
.filter(({ start, finish }) => start < dropStart && finish > dropStart)
|
|
902
|
+
.map((styling) => {
|
|
903
|
+
changes.push({
|
|
904
|
+
original: styling,
|
|
905
|
+
changed: {
|
|
906
|
+
...styling,
|
|
907
|
+
start: styling.start,
|
|
908
|
+
finish: dropStart,
|
|
909
|
+
},
|
|
910
|
+
})
|
|
911
|
+
|
|
912
|
+
changes.push({
|
|
913
|
+
original: null,
|
|
914
|
+
changed: {
|
|
915
|
+
...styling,
|
|
916
|
+
start: dropEnd,
|
|
917
|
+
finish: styling.finish + dropped.length,
|
|
918
|
+
},
|
|
919
|
+
})
|
|
920
|
+
})
|
|
921
|
+
|
|
922
|
+
// Apply drop changes
|
|
923
|
+
changes.map(({ original, changed }) => {
|
|
924
|
+
if (original == null) {
|
|
925
|
+
stylings.push(changed)
|
|
926
|
+
return
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
let index = stylings.findIndex((styling) =>
|
|
930
|
+
compareStylings(original, styling)
|
|
931
|
+
)
|
|
932
|
+
|
|
933
|
+
stylings[index] = changed
|
|
934
|
+
})
|
|
935
|
+
|
|
936
|
+
// Remove empty stylings
|
|
937
|
+
stylings = stylings.filter((styling) => styling.start != styling.finish)
|
|
938
|
+
|
|
939
|
+
// Clamp start and end values, negative offset by dragStart, and positive offset by dropStart
|
|
940
|
+
dragStylings = dragStylings.map((styling) => {
|
|
941
|
+
return {
|
|
942
|
+
...styling,
|
|
943
|
+
start: getMaximum([styling.start, dragStart]) - dragStart + dropStart,
|
|
944
|
+
finish: getMinimum([styling.finish, dragEnd]) - dragStart + dropStart,
|
|
945
|
+
}
|
|
946
|
+
})
|
|
947
|
+
|
|
948
|
+
// Push to current stylings
|
|
949
|
+
stylings = stylings.concat(dragStylings)
|
|
950
|
+
|
|
951
|
+
setText({
|
|
952
|
+
..._text.current,
|
|
953
|
+
content: value,
|
|
954
|
+
stylings: stylings,
|
|
955
|
+
revert: [dropStart, dropEnd],
|
|
956
|
+
pasted: { status: false, length: 0 },
|
|
957
|
+
dropped: { status: false, text: "", previous: [0, 0] },
|
|
958
|
+
})
|
|
959
|
+
}
|
|
960
|
+
|
|
687
961
|
const onChange = (value) => {
|
|
688
962
|
setTimeout(function () {
|
|
689
|
-
|
|
963
|
+
if (_text.current.dropped.status) {
|
|
964
|
+
// Drops from text in the content editable invoke the onChange function twice
|
|
965
|
+
if (value.length == _text.current.content.length) {
|
|
966
|
+
handleDrop(value)
|
|
967
|
+
}
|
|
968
|
+
return
|
|
969
|
+
}
|
|
690
970
|
|
|
971
|
+
let [selectionStart, selectionEnd] = getFieldSelection()
|
|
691
972
|
let difference = value.length - _text.current.content.length
|
|
692
973
|
|
|
693
974
|
let start = selectionStart - difference
|
|
@@ -769,6 +1050,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
769
1050
|
stylings: stylings,
|
|
770
1051
|
revert: [selectionStart, selectionEnd],
|
|
771
1052
|
pasted: { status: false, length: 0 },
|
|
1053
|
+
dropped: { status: false, text: "", previous: [0, 0] },
|
|
772
1054
|
})
|
|
773
1055
|
}, 0)
|
|
774
1056
|
}
|
|
@@ -847,7 +1129,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
847
1129
|
// console.log(data)
|
|
848
1130
|
// console.log(stylings)
|
|
849
1131
|
return `<span class="${stylings
|
|
850
|
-
.map((styling) =>
|
|
1132
|
+
.map((styling) => stylers[styling.type].css)
|
|
851
1133
|
.join(" ")}" data-child-index="${index}">${data}</span>`
|
|
852
1134
|
})
|
|
853
1135
|
.join("")
|
|
@@ -855,44 +1137,60 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
855
1137
|
field.current.innerHTML = html
|
|
856
1138
|
}, [text.content, text.stylings, text.revert])
|
|
857
1139
|
|
|
1140
|
+
const getTextDirection = () => {
|
|
1141
|
+
let value = props.rtl || "disabled"
|
|
1142
|
+
|
|
1143
|
+
switch (value) {
|
|
1144
|
+
case "enabled":
|
|
1145
|
+
return "rtl"
|
|
1146
|
+
case "disabled":
|
|
1147
|
+
return "ltr"
|
|
1148
|
+
case "auto":
|
|
1149
|
+
return "ltr"
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
const calculateTextWidth = (
|
|
1154
|
+
text: string,
|
|
1155
|
+
font: { size: number; family: string }
|
|
1156
|
+
) => {
|
|
1157
|
+
let element = document.createElement("div")
|
|
1158
|
+
let { size, family } = font
|
|
1159
|
+
|
|
1160
|
+
element.className = `text-[${size}px] font-['${family}'] absolute float-left whitespace-nowrap invisible`
|
|
1161
|
+
element.innerHTML = text
|
|
1162
|
+
|
|
1163
|
+
document.body.appendChild(element)
|
|
1164
|
+
|
|
1165
|
+
let rect = element.getBoundingClientRect()
|
|
1166
|
+
return rect.width
|
|
1167
|
+
}
|
|
1168
|
+
|
|
858
1169
|
return (
|
|
859
|
-
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded
|
|
1170
|
+
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded shadow-md">
|
|
860
1171
|
<div className={clsx("flex w-full flex-row justify-start p-2")}>
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
}}
|
|
874
|
-
/>
|
|
875
|
-
<Property
|
|
876
|
-
name="U"
|
|
877
|
-
onMouseDown={(event) => {
|
|
878
|
-
event.preventDefault()
|
|
879
|
-
perform("under")
|
|
880
|
-
}}
|
|
881
|
-
/>
|
|
882
|
-
<Property
|
|
883
|
-
name="S"
|
|
884
|
-
onMouseDown={(event) => {
|
|
885
|
-
event.preventDefault()
|
|
886
|
-
perform("strike")
|
|
887
|
-
}}
|
|
888
|
-
/>
|
|
1172
|
+
{Object.entries(stylers).map(([id, data]) => {
|
|
1173
|
+
return (
|
|
1174
|
+
<Property
|
|
1175
|
+
name={data.content}
|
|
1176
|
+
key={`property-${id}`}
|
|
1177
|
+
onMouseDown={(event) => {
|
|
1178
|
+
event.preventDefault()
|
|
1179
|
+
perform(id)
|
|
1180
|
+
}}
|
|
1181
|
+
/>
|
|
1182
|
+
)
|
|
1183
|
+
})}
|
|
889
1184
|
</div>
|
|
890
1185
|
<div className="h-[1px] w-full bg-slate-600"> </div>
|
|
891
|
-
<div className="w-full">
|
|
1186
|
+
<div className="selection-ignore box-border w-full p-2">
|
|
892
1187
|
<div
|
|
893
1188
|
ref={field}
|
|
894
1189
|
contentEditable="true"
|
|
895
|
-
className="h-[150px] w-full resize-none overflow-auto overflow-x-hidden border-none
|
|
1190
|
+
className="selection-ignore rtl h-[150px] w-full resize-none overflow-auto overflow-x-hidden border-none font-['Arial'] text-[16px] outline-none"
|
|
1191
|
+
style={{
|
|
1192
|
+
direction: getTextDirection(),
|
|
1193
|
+
}}
|
|
896
1194
|
onPaste={(event) => {
|
|
897
1195
|
// pastes all copied text from the content editable as plain text
|
|
898
1196
|
event.preventDefault()
|
|
@@ -905,60 +1203,6 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
905
1203
|
..._text.current,
|
|
906
1204
|
pasted: { status: true, length: data.length },
|
|
907
1205
|
})
|
|
908
|
-
|
|
909
|
-
// let [start, end] = getFieldSelection()
|
|
910
|
-
|
|
911
|
-
// console.log(index)
|
|
912
|
-
// console.log(start)
|
|
913
|
-
|
|
914
|
-
// let index = start - data.length
|
|
915
|
-
// let stylings = text.stylings.slice()
|
|
916
|
-
|
|
917
|
-
// FIXME:
|
|
918
|
-
// stylings.push({
|
|
919
|
-
// type: "bold",
|
|
920
|
-
// start: 5,
|
|
921
|
-
// finish: 7,
|
|
922
|
-
// })
|
|
923
|
-
|
|
924
|
-
// let copy = text.lastCopy
|
|
925
|
-
// if (copy.length != 0) {
|
|
926
|
-
// for (let styling of copy) {
|
|
927
|
-
// stylings.push({
|
|
928
|
-
// type: styling.type,
|
|
929
|
-
// start: styling.start + start,
|
|
930
|
-
// finish: styling.finish + start,
|
|
931
|
-
// })
|
|
932
|
-
// }
|
|
933
|
-
// }
|
|
934
|
-
|
|
935
|
-
// let content: any = text.content
|
|
936
|
-
// let original = content.length
|
|
937
|
-
|
|
938
|
-
// // If not collapsed, insert text
|
|
939
|
-
// if (start == end) {
|
|
940
|
-
// content = content.split("")
|
|
941
|
-
// content.splice(start, 0, data)
|
|
942
|
-
// content = content.join("")
|
|
943
|
-
// } else {
|
|
944
|
-
// console.log(content)
|
|
945
|
-
// // Otherwise, replace substring
|
|
946
|
-
// content =
|
|
947
|
-
// content.substring(0, start) +
|
|
948
|
-
// data +
|
|
949
|
-
// content.substring(end, content.length)
|
|
950
|
-
// }
|
|
951
|
-
|
|
952
|
-
// let difference = content.length - original
|
|
953
|
-
|
|
954
|
-
// stylings = handleDeletion()
|
|
955
|
-
|
|
956
|
-
// setText({
|
|
957
|
-
// ...text,
|
|
958
|
-
// content: content,
|
|
959
|
-
// stylings: stylings,
|
|
960
|
-
// revert: [start + data.length, start + data.length],
|
|
961
|
-
// })
|
|
962
1206
|
}}
|
|
963
1207
|
onInput={(event: any) => {
|
|
964
1208
|
onChange(event.target.textContent)
|
|
@@ -973,14 +1217,35 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
973
1217
|
lastCopy: data,
|
|
974
1218
|
})
|
|
975
1219
|
}}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1220
|
+
onDrop={(event) => {
|
|
1221
|
+
let text = event.dataTransfer.getData("text")
|
|
1222
|
+
|
|
1223
|
+
if (text.trim() == "") return
|
|
1224
|
+
|
|
1225
|
+
// console.log(getSelectionPrecedingSum("anchorNode"))
|
|
1226
|
+
// console.log(getSelectionPrecedingSum("focusNode"))
|
|
1227
|
+
// console.log(window.getSelection())
|
|
1228
|
+
|
|
1229
|
+
setText({
|
|
1230
|
+
..._text.current,
|
|
1231
|
+
dropped: {
|
|
1232
|
+
status: true,
|
|
1233
|
+
text: text,
|
|
1234
|
+
previous: getFieldSelection(),
|
|
1235
|
+
},
|
|
1236
|
+
})
|
|
1237
|
+
}}
|
|
980
1238
|
></div>
|
|
981
1239
|
</div>
|
|
982
1240
|
<div className="h-[1px] w-full bg-slate-600"> </div>
|
|
983
|
-
<button
|
|
1241
|
+
<button
|
|
1242
|
+
className="my-1 rounded bg-cyan-800 p-2 py-1 text-white"
|
|
1243
|
+
onClick={() => {
|
|
1244
|
+
let onSubmit = props.onSubmit || (() => {})
|
|
1245
|
+
|
|
1246
|
+
onSubmit(text.content, text.stylings)
|
|
1247
|
+
}}
|
|
1248
|
+
>
|
|
984
1249
|
Submit
|
|
985
1250
|
</button>
|
|
986
1251
|
</div>
|