@sikka/hawa 0.0.231 → 0.0.232
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 +4 -0
- package/es/elements/FloatingCommentCE.d.ts +6 -0
- package/es/elements/FloatingCommentSlate.d.ts +19 -0
- package/es/elements/index.d.ts +2 -0
- package/es/index.es.js +8 -1
- package/lib/elements/FloatingCommentCE.d.ts +6 -0
- package/lib/elements/FloatingCommentSlate.d.ts +19 -0
- package/lib/elements/index.d.ts +2 -0
- package/lib/index.js +8 -1
- package/package.json +4 -1
- package/src/elements/{FloatingComment - ContentEditable.tsx → FloatingCommentCE.tsx} +47 -32
- package/src/elements/FloatingCommentSlate.tsx +149 -0
- package/src/elements/index.ts +2 -0
- package/src/styles.css +4 -0
- package/es/elements/FloatingComment - ContentEditable.d.ts +0 -6
- package/lib/elements/FloatingComment - ContentEditable.d.ts +0 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sikka/hawa",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.232",
|
|
4
4
|
"description": "SaaS Oriented UI Kit",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.es.js",
|
|
@@ -113,6 +113,9 @@
|
|
|
113
113
|
"react-select": "^5.3.2",
|
|
114
114
|
"rich-textarea": "^0.21.1",
|
|
115
115
|
"rollup-plugin-typescript2": "^0.34.1",
|
|
116
|
+
"slate": "^0.94.1",
|
|
117
|
+
"slate-history": "^0.93.0",
|
|
118
|
+
"slate-react": "^0.97.1",
|
|
116
119
|
"start": "^5.1.0"
|
|
117
120
|
}
|
|
118
121
|
}
|
|
@@ -26,7 +26,7 @@ const styleClasses = {
|
|
|
26
26
|
strike: "line-through",
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export const
|
|
29
|
+
export const FloatingCommentCE: React.FunctionComponent<ComponentTypes> = (
|
|
30
30
|
props
|
|
31
31
|
) => {
|
|
32
32
|
const [text, setText] = useState({
|
|
@@ -37,13 +37,35 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
37
37
|
|
|
38
38
|
const field = useRef(null)
|
|
39
39
|
|
|
40
|
+
const getFieldSelection = () => {
|
|
41
|
+
if (document.activeElement != field.current) return [0, 0]
|
|
42
|
+
|
|
43
|
+
let selection = window.getSelection()
|
|
44
|
+
let start
|
|
45
|
+
let end
|
|
46
|
+
|
|
47
|
+
console.log(selection)
|
|
48
|
+
console.log(document.activeElement)
|
|
49
|
+
console.log(`Range count when fetching selection: ${selection.rangeCount}`)
|
|
50
|
+
if (selection.rangeCount) {
|
|
51
|
+
let range = selection.getRangeAt(0)
|
|
52
|
+
start = range.startOffset
|
|
53
|
+
end = range.endOffset
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return [start, end]
|
|
57
|
+
}
|
|
58
|
+
|
|
40
59
|
useEffect(() => {
|
|
60
|
+
// return
|
|
41
61
|
let [start, end] = text.revert
|
|
42
62
|
|
|
43
63
|
if (start == 0 && end == 0) return
|
|
44
64
|
|
|
45
|
-
|
|
46
|
-
|
|
65
|
+
let oldStart = start
|
|
66
|
+
let oldEnd = end
|
|
67
|
+
|
|
68
|
+
let [newStart, newEnd] = getFieldSelection()
|
|
47
69
|
|
|
48
70
|
// TODO: To get the child node based on the index, get lengths of each child node
|
|
49
71
|
// add to each child node the sum of all previous child nodes
|
|
@@ -53,38 +75,45 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
53
75
|
let startNode = null
|
|
54
76
|
let endNode = null
|
|
55
77
|
|
|
78
|
+
let startNodeIndex = 0
|
|
79
|
+
let endNodeIndex = 0
|
|
80
|
+
|
|
56
81
|
let total = 0
|
|
57
82
|
let nodes = Array.from(field.current.childNodes)
|
|
83
|
+
|
|
84
|
+
console.log(
|
|
85
|
+
`Current nodes: ${nodes.map((e: any) => e.textContent.length).join(", ")}`
|
|
86
|
+
)
|
|
87
|
+
|
|
58
88
|
for (let i = 0; i < nodes.length; i++) {
|
|
59
89
|
let node: any = nodes[i]
|
|
60
90
|
let sum = node.textContent.length + total
|
|
61
91
|
|
|
62
|
-
if (start > total && start <= sum) {
|
|
92
|
+
if (startNode == null && start > total && start <= sum) {
|
|
63
93
|
startNode = nodes[i]
|
|
94
|
+
startNodeIndex = i
|
|
95
|
+
start -= total
|
|
64
96
|
}
|
|
65
97
|
|
|
66
|
-
if (end > total && end <= sum) {
|
|
98
|
+
if (endNode == null && end > total && end <= sum) {
|
|
67
99
|
endNode = nodes[i]
|
|
100
|
+
endNodeIndex = i
|
|
101
|
+
end -= total
|
|
68
102
|
}
|
|
69
103
|
|
|
70
104
|
total += node.textContent.length
|
|
71
105
|
}
|
|
72
106
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
// )
|
|
77
|
-
// )
|
|
78
|
-
|
|
79
|
-
console.log(startNode)
|
|
80
|
-
console.log(endNode)
|
|
107
|
+
console.log(
|
|
108
|
+
`Reverting (${newStart} -> ${newEnd}) to (${oldStart} - ${start} - [node ${startNodeIndex}] -> ${oldEnd} - ${end} - [node ${endNodeIndex}])`
|
|
109
|
+
)
|
|
81
110
|
|
|
82
111
|
var range = document.createRange()
|
|
83
112
|
var sel = window.getSelection()
|
|
84
113
|
|
|
85
114
|
range.setStart(startNode.firstChild, start)
|
|
86
115
|
range.setEnd(endNode.firstChild, end)
|
|
87
|
-
range.collapse(true)
|
|
116
|
+
// range.collapse(true)
|
|
88
117
|
|
|
89
118
|
sel.removeAllRanges()
|
|
90
119
|
sel.addRange(range)
|
|
@@ -247,6 +276,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
247
276
|
setText({
|
|
248
277
|
...text,
|
|
249
278
|
stylings: result,
|
|
279
|
+
revert: [selectionStart, selectionEnd],
|
|
250
280
|
})
|
|
251
281
|
}
|
|
252
282
|
|
|
@@ -355,24 +385,8 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
355
385
|
return result
|
|
356
386
|
}
|
|
357
387
|
|
|
358
|
-
const getFieldSelection = () => {
|
|
359
|
-
if (document.activeElement != field.current) return [0, 0]
|
|
360
|
-
|
|
361
|
-
let selection = window.getSelection()
|
|
362
|
-
let start
|
|
363
|
-
let end
|
|
364
|
-
|
|
365
|
-
if (selection.rangeCount) {
|
|
366
|
-
let range = selection.getRangeAt(0)
|
|
367
|
-
start = range.startOffset
|
|
368
|
-
end = range.endOffset
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
return [start, end]
|
|
372
|
-
}
|
|
373
|
-
|
|
374
388
|
return (
|
|
375
|
-
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded bg-
|
|
389
|
+
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded bg-blue-300 shadow-md">
|
|
376
390
|
<div className={clsx("flex w-full flex-row justify-start p-2")}>
|
|
377
391
|
<Property
|
|
378
392
|
name="B"
|
|
@@ -405,6 +419,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
405
419
|
<div
|
|
406
420
|
ref={field}
|
|
407
421
|
contentEditable="true"
|
|
422
|
+
role="textbox"
|
|
408
423
|
dangerouslySetInnerHTML={{
|
|
409
424
|
__html: getContent()
|
|
410
425
|
.map((_data, index) => {
|
|
@@ -425,7 +440,7 @@ export const FloatingComment: React.FunctionComponent<ComponentTypes> = (
|
|
|
425
440
|
// ${data}
|
|
426
441
|
// </span>`
|
|
427
442
|
})
|
|
428
|
-
.join("
|
|
443
|
+
.join(""),
|
|
429
444
|
}}
|
|
430
445
|
className="h-[150px] w-full resize-none border-none p-2 outline-none"
|
|
431
446
|
onInput={(event) => {
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// Import React dependencies.
|
|
2
|
+
import React, { useState, useCallback } from "react"
|
|
3
|
+
// Import the Slate editor factory.
|
|
4
|
+
import { Editor, Transforms, Element, createEditor } from "slate"
|
|
5
|
+
|
|
6
|
+
// Import the Slate components and React plugin.
|
|
7
|
+
import { Slate, Editable, withReact } from "slate-react"
|
|
8
|
+
|
|
9
|
+
// TypeScript users only add this code
|
|
10
|
+
import { BaseEditor, Descendant } from "slate"
|
|
11
|
+
import { ReactEditor } from "slate-react"
|
|
12
|
+
|
|
13
|
+
type CustomElement = { type: "paragraph"; children: CustomText[] }
|
|
14
|
+
type CustomText = { text: string }
|
|
15
|
+
|
|
16
|
+
declare module "slate" {
|
|
17
|
+
interface CustomTypes {
|
|
18
|
+
Editor: BaseEditor & ReactEditor
|
|
19
|
+
Element: CustomElement
|
|
20
|
+
Text: CustomText
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const initialValue: Descendant[] = [
|
|
25
|
+
{
|
|
26
|
+
type: "paragraph",
|
|
27
|
+
children: [{ text: "" }],
|
|
28
|
+
},
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
let styles = {
|
|
32
|
+
bold: { fontWeight: "bold" },
|
|
33
|
+
italic: { fontStyle: "italic" },
|
|
34
|
+
underline: { textDecoration: "underline" },
|
|
35
|
+
strikethrough: { textDecoration: "line-through" },
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const Leaf = (props) => {
|
|
39
|
+
let data = Object.assign({}, props.leaf)
|
|
40
|
+
delete data.text
|
|
41
|
+
|
|
42
|
+
let keys = Object.entries(data)
|
|
43
|
+
.filter(([key, value]) => value)
|
|
44
|
+
.map(([key, _]) => key)
|
|
45
|
+
|
|
46
|
+
let types = {}
|
|
47
|
+
|
|
48
|
+
if (keys.length != 0) {
|
|
49
|
+
keys.map((type) => {
|
|
50
|
+
Object.entries(styles[type]).map(([key, value]) => {
|
|
51
|
+
types[key] = value
|
|
52
|
+
})
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<span {...props.attributes} style={types}>
|
|
58
|
+
{props.children}
|
|
59
|
+
</span>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const Property = (props) => {
|
|
64
|
+
return (
|
|
65
|
+
<div
|
|
66
|
+
className="border-box mr-[5px] flex h-[32px] w-[32px] items-center justify-center rounded bg-gray-400 p-2"
|
|
67
|
+
onMouseDown={props.onMouseDown}
|
|
68
|
+
>
|
|
69
|
+
{props.name}
|
|
70
|
+
</div>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const FloatingCommentSlate = () => {
|
|
75
|
+
const [editor] = useState(() => withReact(createEditor()))
|
|
76
|
+
|
|
77
|
+
// Define a leaf rendering function that is memoized with `useCallback`.
|
|
78
|
+
const renderLeaf = useCallback((props) => {
|
|
79
|
+
return <Leaf {...props} />
|
|
80
|
+
}, [])
|
|
81
|
+
|
|
82
|
+
const perform = (event, type) => {
|
|
83
|
+
event.preventDefault() // This does not take focus away from field which allows the function to retrieve the current selection data
|
|
84
|
+
|
|
85
|
+
let current = Editor.marks(editor)[type] || false
|
|
86
|
+
console.log(Editor.marks(editor))
|
|
87
|
+
// if (!types.includes(type)) types.push(type)
|
|
88
|
+
|
|
89
|
+
Editor.addMark(editor, type, !current)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<div className="align-center box-border flex h-min w-[400px] flex-col items-center justify-center rounded bg-blue-300 shadow-md">
|
|
94
|
+
<div className={"flex w-full flex-row justify-start p-2"}>
|
|
95
|
+
<Property
|
|
96
|
+
name="B"
|
|
97
|
+
onMouseDown={(event) => {
|
|
98
|
+
perform(event, "bold")
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
<Property
|
|
102
|
+
name="I"
|
|
103
|
+
onMouseDown={(event) => {
|
|
104
|
+
perform(event, "italic")
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
<Property
|
|
108
|
+
name="U"
|
|
109
|
+
onMouseDown={(event) => {
|
|
110
|
+
perform(event, "underline")
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
<Property
|
|
114
|
+
name="S"
|
|
115
|
+
onMouseDown={(event) => {
|
|
116
|
+
perform(event, "strikethrough")
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
<div className="h-[1px] w-full bg-slate-600"> </div>
|
|
121
|
+
<div className="w-full">
|
|
122
|
+
<Slate editor={editor} initialValue={initialValue}>
|
|
123
|
+
<Editable
|
|
124
|
+
renderLeaf={renderLeaf}
|
|
125
|
+
className="h-[150px] p-2"
|
|
126
|
+
onKeyDown={(event) => {
|
|
127
|
+
if (!event.ctrlKey) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
switch (event.key) {
|
|
132
|
+
// When "B" is pressed, bold the text in the selection.
|
|
133
|
+
case "b": {
|
|
134
|
+
event.preventDefault()
|
|
135
|
+
Editor.addMark(editor, "bold", true)
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}}
|
|
140
|
+
/>
|
|
141
|
+
</Slate>
|
|
142
|
+
</div>
|
|
143
|
+
<div className="h-[1px] w-full bg-slate-600"> </div>
|
|
144
|
+
<button className="my-1 rounded bg-cyan-800 p-2 py-1 text-white">
|
|
145
|
+
Submit
|
|
146
|
+
</button>
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
}
|
package/src/elements/index.ts
CHANGED
|
@@ -33,6 +33,8 @@ export * from "./HawaDatepicker"
|
|
|
33
33
|
export * from "./UserFeedback"
|
|
34
34
|
export * from "./ArrowCarousel"
|
|
35
35
|
export * from "./FloatingComment"
|
|
36
|
+
export * from "./FloatingCommentCE"
|
|
37
|
+
export * from "./FloatingCommentSlate"
|
|
36
38
|
// Inputs
|
|
37
39
|
export * from "./HawaTextField"
|
|
38
40
|
export * from "./HawaCardInput"
|
package/src/styles.css
CHANGED
|
@@ -1503,6 +1503,10 @@ video {
|
|
|
1503
1503
|
--tw-bg-opacity: 1;
|
|
1504
1504
|
background-color: rgb(191 219 254 / var(--tw-bg-opacity));
|
|
1505
1505
|
}
|
|
1506
|
+
.bg-blue-300 {
|
|
1507
|
+
--tw-bg-opacity: 1;
|
|
1508
|
+
background-color: rgb(147 197 253 / var(--tw-bg-opacity));
|
|
1509
|
+
}
|
|
1506
1510
|
.bg-blue-50 {
|
|
1507
1511
|
--tw-bg-opacity: 1;
|
|
1508
1512
|
background-color: rgb(239 246 255 / var(--tw-bg-opacity));
|